Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AviSynth demuxer rewrite patch #90

Closed
qyot27 opened this issue Feb 20, 2013 · 50 comments
Closed

AviSynth demuxer rewrite patch #90

qyot27 opened this issue Feb 20, 2013 · 50 comments

Comments

@qyot27
Copy link
Contributor

qyot27 commented Feb 20, 2013

Posting this here because it's sort of related.

I wanted to see about making the October 9th patch from FFmpeg-devel work against git master. The result is here:
qyot27/FFmpeg@9087175

On Linux and Windows, AvxSynth and AviSynth have issues with YV12's channel order, always assuming I420. On OS X, it's correct for some reason.

RGB24 and RGB32 are upside-down on all platforms.

The segfault on exit seems to have been caused by the combination of avs_delete_script_environment and avisynth_free_library being used in read_close. Disabling avs_delete_script_environment stops the segfault, but more than likely causes leakage.

AviSynth 2.6's colorspaces don't work when using AviSynth 2.6, failing with exception handling errors.

@avxsynth-testing
Copy link
Collaborator

Can we discuss this by email? I too would be interested in completing this, but I stopped tracking this after not seeing much response from ffmpeg-devel.

Please feel free to follow-up with me at avxsynth.testing@gmail.com

@avxsynth-testing
Copy link
Collaborator

To remark on the points you've made though:

  1. The channel order should not be special-cased. If PLANAR_U and PLANAR_V do not in fact point to the U and V planes, that is a bug that should be fixed. Avisynth uses the YVU plane order for its planar colorspaces, and it is "converted" to YUV internally by the demuxer module I wrote.

  2. RGB24 and RGB32 being vertically flipped is a consequence of the Windows DIB format and is not a bug. If ffmpeg expects the opposite line ordering, the read_video_packet function can copy using a negative stride for these formats.

  3. The segfault at exit is related to the use of exit() in ffmpeg tools. This causes C++ structures with static storage duration (i.e. global objects) to be destroyed. However, ffmpeg itself registers avformat_close with atexit, which results in avs_delete_script_environment being called to destroy structures that have already been deleted.

  4. I am interested in fixing any problems with Avisynth 2.6.

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 21, 2013

I'm really not sure how much help I can be on this. The process of getting AvxSynth support into x264 (still in x264-devel) was mostly me being directed rather than doing anything novel myself.

  1. The weird thing is that it's fine on OS X, though. Having I420 and YV12 swapped like this was also an issue years ago with x264, but I can't really remember the specifics on it.

  2. There is a commit for putting RGB rightside-up with the old AviSynth demuxer here:
    http://git.videolan.org/?p=ffmpeg.git;a=commit;h=b10ba1175d3afa28d88cf3b24b69dc4882be16f5

I wasn't really sure how or if it could be transferred over, though.

@avxsynth-testing
Copy link
Collaborator

  1. Unfortunately, I have no ability to evaluate OSX functionality. I can say with certainty that there is no system-specific code to allocate the plane pointers however. Are you sure the issue is in Avisynth? Have you checked with BlankClip()?

  2. That looks like some VfW-related trickery. There are a couple of ways to flip RGB video:

  • Call the FlipVertical function through avs_invoke if the image is RGB.
  • In avisynth_read_packet_video, special-case the loop for RGB to set src_p to the last line of the video (src_p = src_p + (planeHeight - 1) * pitch) and call avs_bit_blt with "-pitch" instead of "pitch" to copy backwards.

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 22, 2013

RGB flipping done: qyot27/FFmpeg@78f2e6e

Also has another attempt at stopping the segfault. This one doesn't seem to cause the kind of resource slogging that I saw with simply commenting out the avs_delete_script_environment in read_close, and is actually instantaneous at close. This may or may not also be a consequence of using a highly stripped-down build of FFmpeg*, but I'm leaning toward the side that the minimal build isn't the real reason for the improvement.

YV12 is still swapped, verified by using Version().ConvertToYV12() - the text appears with a blue tint on both Linux and Windows and using SwapUV() returns it to its proper appearance. The 2.6 colorspaces still silently fail on Windows...any suggestions on what can be done to get useful debug output on that? GDB seems to not want anything to do with dynamically-loaded avisynth on Windows.

*the used configure settings:
./configure --prefix=/home/qyot27/win32_build --cross-prefix=i686-w64-mingw32-
--enable-gpl --enable-version3 --disable-w32threads --enable-debug --disable-stripping
--disable-ffplay --disable-ffprobe --disable-ffserver --disable-demuxers
--enable-demuxer='avi,avisynth' --enable-avisynth --disable-decoders --enable-decoder=rawvideo
--disable-encoders --enable-encoder=rawvideo --disable-muxers --enable-muxer=avi
--disable-devices --disable-filters --disable-asm --cpu=pentium3
--extra-cflags='-mfpmath=sse -march=pentium3 -msse -mtune=pentium3 -DPTW32_STATIC_LIB'
--target-os=mingw32 --arch=x86

@avxsynth-testing
Copy link
Collaborator

To step into avisynth.dll on Windows, you may need to use Visual Studio. It is my understanding that the latest git versions of ffmpeg/libav can be compiled in MSVC 2010 or later. Your "fix" for the segfault is a NOP. Calling free/delete on NULL does nothing in C++.

Incidentally, I noticed that there was a bug in the seek routine, which I have fixed in this diff (with other changes): http://pastebin.com/vucbGbjE

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 23, 2013

Applied (although I now see I forgot to remove pthreads.h too), and now AviSynth 2.6 colorspaces are supported:
qyot27/FFmpeg@d8e275b
qyot27/FFmpeg@b15bcdf

And actually, now that I've done more testing, YV24 actually does not have an issue. The issue seems to actually be in the yuv444p rawvideo decoder, because using yuv4mpegpipe or ffv1, YV24-bearing scripts work fine too.

And finally, it seems like the segfault is now only occurring on Linux. Windows is unaffected by it.

@avxsynth-testing
Copy link
Collaborator

It is interesting that the 2.6 avisynth_c header is not a complete port of the 2.5 header.

These lines are actually unnecessary vestiges that I forgot to take out:
534 + avs->curr_frame = 0;
535 + avs->curr_sample = 0;

IIRC, the segfault occurs because of an interaction between dlclose, atexit, and C++ objects. I will look into seeing if it can be mitigated on the AvxSynth side.

Edit:
More details about the segfault on exit problem:
In ffmpeg.c, exit_program is registered with atexit. C++ static global objects are also (secretly) registered with a C++ atexit equivalent. The ScriptEnvironment destructor in Avxsynth has been modified from the Avisynth version to access some global structures, namely the (now vector instead of array) list of built-in functions and the log4cpp service. Normally, this would not be an issue because constructed static objects are guaranteed by the C++ standard to be destroyed after user atexit handlers run. However, because Avxsynth is being dynamically loaded, the global objects are actually constructed upon calling dlopen through avformat_read_header, which occurs after exit_program is registered. As a consequence, the Avxsynth global structures are destroyed before calling exit_program, and avs_delete_script_environment accesses freed memory when calling the ScriptEnvironment destructor.

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 24, 2013

I'm not entirely sure of the logistics behind the 2.6 header. It's simply the one from x264, as I figure it's advisable to keep FFmpeg and x264 in sync with each other on this aspect (namely because x264's support is probably more stable over the long term than the actual development of 2.6 itself). If/when 2.6 hits final, it'd of course be the right thing to move both of them up to the canonical 2.6 header. You'll notice that there are some differences (I can only remember some organizational stuff) when comparing avisynth_c.h from x264 to the one from AviSynth CVS.

Considering all the points on global objects, would that have anything to do with the inclusion of RTLD_GLOBAL in the dlopen call? It might explain why I never encountered a problem when adapting the x264 patch, since I only used RTLD_NOW. It certainly doesn't seem to have had any adverse effect on it there, but I'm not too sure what the consequences are for not using RTLD_GLOBAL in that case.

Edit: Yeah, RTLD_GLOBAL has nothing to do with it.

@avxsynth-testing
Copy link
Collaborator

I have sat down and thought about this for a while. Unfortunately, I can't think of a way to resolve ffmpeg's atexit usage with AvxSynth's usage of global objects. Something has to give, and unfortunately, we are not willing to give up logging to avoid this segfault. This patch to ffmpeg.c replaces the offending atexit handler and does not appear to break anything else:

http://pastebin.com/L988RtYz

There is a second atexit handler in libavcodec/bfin/dsputil_bfin.h which is not affected by this change as it does not touch any dynamically allocated structures (as far as I can tell).

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 24, 2013

The solution I went with is to spawn a new branch with the demuxer-related commits squashed into a single patch, and the atexit fix in a second patch.

https://github.com/qyot27/FFmpeg/commits/avisynth-demuxer2

I also tested the new branch on OSX (10.7 specifically), and it gives correct output (although building AvxSynth on OSX is kind of a pain due to autotools being, not right, under it; I have to resort to autoreconfing the build system in an Ubuntu VM before going native for the rest of the compilation process...).

The only tweak I can think of now is that it seems as though avs_planes_yvu and its corresponding planar case are now unnecessary, since all the planar formats point to case 1, or for Y8, case 3. Otherwise, I'd say resubmit to ffmpeg-devel or I could issue a Pull Request on it.

@avxsynth-testing
Copy link
Collaborator

avs_planes_yvu can be removed. Please feel free to submit your branch to ffmpeg-devel on my behalf. As Avxsynth is no longer my primary responsibility, I have limited time to work on it and argue with ffmpeg maintainers.

@avxsynth-testing
Copy link
Collaborator

Doh! There's a horrible memory leak in the demuxer. Apparently I should set pkt->destruct to "av_destruct_packet" in avisynth_read_packet. This also improves the performance of decoding BlankClip from 80 fps to 800 fps ;)

http://pastebin.com/PeCesZ3H

Also, I just realized that there are a bunch of exit calls in ffmpeg.c that probably should be changed to do_exit.

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 25, 2013

Applied, practically all of the exit calls have been moved over to do_exit, and new branch spawned at avisynth-demuxer3

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 25, 2013

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 26, 2013

Response to the atexit handling situtation:

On Tue, Feb 26, 2013 at 9:56 AM, Michael Niedermayer michaelni@gmx.at wrote:

ffmpeg is not the only application that uses libavformat so this
might be a much bigger problem than you think.

what you basically suggest is that no application that uses libavformat
is allowed to use atexit() anymore

also your patch replaces 6 out of 30 occurances of exit() in ffmpeg.c
this does look quite incomplete ...

an alternative solution (that may or may not work) would be to
register your own atexit handler when the avxsynth demuxer is opened
and if the callback gets called do the free / or not do the free from
it but set a global flag that prevents subsequent access from
read_close(). I dont know if that would have issues or how ugly it
would be but i guess you too would prefer if libavformat+avxsynth
could be used from applications that do use atexit in a similar way
to ffmpeg.c

@avxsynth-testing
Copy link
Collaborator

What michaelni suggests is feasible. It would involve creating a global linked list of AvisynthContexts and a global atexit_called flag. Calling avisynth_read_header will add an element to the list of contexts and a avisynth_read_close will remove it. The first call to avisynth_read_header will register with atexit a function to destroy the list of contexts.

Edit:
I just realized that using atexit in avisynth.c would also mean that the Avisynth DLL could never be unloaded (e.g. when a file is closed). It must remain until the end of the program lifetime.

@0x09
Copy link

0x09 commented Feb 27, 2013

I had been writing an AVInputFormat a few months ago, but stopped when I found out from qyot that you had already written and submitted one on the mailing list. A little late, but I guess now would be the last good time to post it if you two want to have a look:
just the avfmt
full diff

Color formats should be handled correctly* and it handles interlacing as well, also avoids that mplayer bug by using avio to read the script (which has the pointless side-effect of making things like echo "ColorBars()" | ffplay -f avx - possible.) It just links to avxsynth so there are no loader issues, and doesn't attempt to replace the avisynth support as I thought that'd be too difficult to get accepted at the time. Anyway, maybe this can still help in some way.

*Not sure about the Linux/Windows i420 issue.

@avxsynth-testing
Copy link
Collaborator

Linking to Avisynth solves a lot of problems, but it means that users would need to have Avisynth in order to run ffmpeg binaries, which would be highly unfortunate.

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 27, 2013

As an aside, support for AvxSynth in x264 is now official.

But regarding the issue of atexit in avisynth.c, does that mean neither AviSynth nor AvxSynth could be unloaded, or specifically just AviSynth? If it's just one and not the other, could it be special-cased/macro'ed around?

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 27, 2013

In looking around, it seems that the only other library FFmpeg uses dlopen for is libavfilter's frei0r support (libavfilter/vf_frei0r.c). Might there be something in there to use as a model for this? I don't know if frei0r is subject to atexit, though.

@0x09
Copy link

0x09 commented Feb 28, 2013

The frei0r ifmt doesn't do anything special, actually it looks like this sort of problem could manifest with a particularly written C++ frei0r filter.

Dynamic loading would be convenient and would make it easier to get AvxSynth support in e.g. VLC binaries, but it seems to be causing quite a few headaches. Since linking is how every other ffmpeg dependency is handled (except frei0r which would be more akin to an AviSynth plugin loader), and it's unlike the Windows AviSynth input where there are no package managers to help, it may be worth considering. Just a thought.

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 28, 2013

I guess at this point: with the situation of it not being unloaded until the program ends if avisynth.c is made to also use atexit, what is the practical consequence there? Is there really a case where the input file is unloaded and the program does not then end immediately or soon thereafter? It doesn't seem like something that would affect a program like FFmpeg very much, although I could see how it might impact media players that load a playlist if they don't free up and refresh everything between entries.

The other 'solution', i.e. disabling avs_delete_script_environment in read_close (and only read_close), what are the consequences of that? Is it pretty much the same situation as above, where it just means it doesn't get unloaded until the program exits? That can easily be special-cased with an ifdef _WIN32 since regular AviSynth has no problems with it. I ask this specifically because I know that on Windows it was probably the cause of the resources getting bogged down at the end and persisting even after ffmpeg closed. On Ubuntu 12.10, though, there weren't any issues that I could immediately feel from it - and this was on the same exact hardware: a Coppermine (PIII era) Celeron with 512 MBs of PC133. And since the issue with the segfault only exists on Linux (and possibly OSX), it would seem to be pretty cut-and-dry: allow the use of avs_delete_script_environment on Windows, disable it everywhere else unless/until a better solution is found to make atexit and dlopen play together nicely. I see this as the least acceptable option on the table, but it does 'work', so I'd only see it as a last resort unless there really are only small issues with it.

As it stands right now, the dynamic loading patch has no issues on Windows that I'm aware of, and the only remaining issue on Linux and OSX is this segfault conflict (and that only affects the ffmpeg binary itself or other programs that use atexit like it does - I'm about 99% sure the MPV test build I made was with a lavf that had a segfaulting FFmpeg, and MPV was totally cool with playing scripts without segfaulting).

Although I guess I should ask this, does the dynamic patch have support for interlacing?

@avxsynth-testing
Copy link
Collaborator

I don't think separating Avisynth and Avxsynth demuxers is a good idea.

Consequences of not unloading Avisynth DLL until program exit:
Leaks a few kB of memory. May have some consequences on Windows platforms that have a limit on the maximum number of opened DLLs. Impact on batch-type programs like ffmpeg is limited, but it may have some effect I'm not aware of on applications like video editors that open multiple files.

Consequences of not deleting script environment:
Severe memory leak if opening multiple files (cache not freed). Filters that register handlers with ScriptEnvironment->AtExit will not be finalized. Filters that write to files may not flush buffers, resulting in data loss.

Path forward:
As I mentioned before, I think holding onto the DLL is the easiest way to handle this. The first time avisynth_read_header is called, the library will be loaded and an atexit handler registered. A "constructor" and "destructor" for AvisynthContext will need to be created that maintain a list of some sort (linked list is probably easiest) of open AvisynthContext instances. The atexit handler will walk the list of AvisynthContext instances and destroy each, unload the DLL, and finally set a global flag that prevents the AvisynthContext "destructor" from running.

Interlacing:
Avisynth has no concept of interlacing.

@0x09
Copy link

0x09 commented Feb 28, 2013

Avisynth has no concept of interlacing.

It distinguishes field-based clips from frame-based, whereas ffmpeg only handles complete frames and identifies fields by a stream flag. Adding weave() was an idea from the x264 input module, otherwise the behavior is similar to using assumeframebased() all the time.

@avxsynth-testing
Copy link
Collaborator

Being field-based is still completely different from being interlaced. If the user returns a field-based clip from his script, that must be what he wants, and I don't see the value in second-guessing the user.

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 28, 2013

Another point brought up:

On Wed, Feb 27, 2013 at 9:03 AM, Michael Niedermayer michaelni@gmx.at wrote:

also the avx/avisynth code in ffmpeg will need a maintainer
are you or someone else from the avxsynth team interrested?
If so please add yourself to the MAINTAINERS file

I'd really only feel comfortable with testing patches, not so much the rest of the maintainer duties.

Also, one thing I did notice with the previous AviSynth demuxer is that it performs code page conversion (http://git.videolan.org/?p=ffmpeg.git;a=commit;h=5c742005fb7854dcfaa9f0efb65fd36a63ceaa2b). Is something like this going to be necessary, even if only for Windows?

@avxsynth-testing
Copy link
Collaborator

Yes, that looks like a valid concern. I would have to test to see if unicode is also an issue on Linux. It may not be, as Linux uses UTF-8 strings.

If the code is accepted, I will accept responsibility for maintenance.

Edit: UTF-8 filenames do not appear to be an issue on Linux.

Input #0, avisynth, from '../日本語.avs':
Duration: 00:00:00.04, start: 0.000000, bitrate: 23 kb/s

Edit2: The reason malloc/free/printf are undef'd in avisynth.c is because avisynth_c.h for some unexplained reason contains an inline function that calls malloc/free/printf, resulting in a compiler error with the ffmpeg guard macros.

@avxsynth-testing
Copy link
Collaborator

I have written a patch that implements the atexit handler I discussed above:

http://pastebin.com/ewDgwmbt

This is a fairly intrusive patch, so it should probably be tested. It also fixes a minor memory leak and a potential overflow in computing the size of video packets.

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 28, 2013

Not the filenames of the scripts, the filenames of the videos loaded into it. What FFMS2 is handling (or on Windows, AVISource, DirectShowSource, DSS2, the various DG* source filters, etc.). I'm pretty sure Windows can handle it if the scripts themselves have the Unicode names, but not if you're trying to load videos with Unicode names into the scripts.

I figured that Linux and OSX wouldn't have an issue due to UTF-8, though.

Regarding the undefs:
Ah, now that's what I get for keeping house and not keeping a working area to test cross-compilation.

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 28, 2013

Never mind, Windows does indeed have a problem with Unicode filenames. Even when the Command Prompt is switched over to UTF-8 with chcp 65001:

ffmpeg -i 永遠の瞬間に関しては.avs -vcodec rawvideo -an test.avi

ffmpeg version r50266 git-7005726 Copyright (c) 2000-2013 the FFmpeg developers
built on Feb 24 2013 11:59:26 with gcc 4.7.2 (GCC)
configuration: --prefix=/home/qyot27/win32_build --cross-prefix=i686-w64-mingw
32- --enable-gpl --enable-version3 --enable-avresample --disable-w32threads --en
able-libutvideo --enable-libxvid --enable-libx264 --enable-libtwolame --enable-l
ibmp3lame --enable-libvorbis --enable-libopus --enable-libvo-aacenc --enable-lib
vpx --enable-libtheora --enable-avisynth --cpu=pentium3 --extra-cflags='-I/home/
qyot27/win32_build/include -mfpmath=sse -march=pentium3 -msse -mtune=pentium3 -D
PTW32_STATIC_LIB' --extra-ldflags='-L/home/qyot27/win32_build/lib -lx264' --targ
et-os=mingw32 --arch=x86
libavutil 52. 17.103 / 52. 17.103
libavcodec 54. 92.100 / 54. 92.100
libavformat 54. 63.100 / 54. 63.100
libavdevice 54. 3.103 / 54. 3.103
libavfilter 3. 39.101 / 3. 39.101
libswscale 2. 2.100 / 2. 2.100
libswresample 0. 17.102 / 0. 17.102
libpostproc 52. 2.100 / 52. 2.100
[avisynth @ 021a37c0] Import: unable to locate "永遠の瞬間に関しては.avs" (try specifying
a path)
永遠の瞬間に関しては.avs: Unknown error occurred

@0x09
Copy link

0x09 commented Feb 28, 2013

That's something that could be sidestepped by using avio_read+eval.

@qyot27
Copy link
Contributor Author

qyot27 commented Feb 28, 2013

The new atexit-handling patch works for me under Windows and Linux. OSX can't decide whether it hates me or not, but the thing I was experiencing there has nothing to do with the patch, just with dependencies deciding to explode in my face and prevent AvxSynth from doing anything. But given a setup that doesn't have that problem, I have no reason to believe it wouldn't work there if it works fine on Linux.

I've posted it to ffmpeg-devel.

@avxsynth-testing
Copy link
Collaborator

Reading the script file and calling invoking Eval() is not a valid solution because the Avisynth current working directory would be different in that case. Based on what you found, it's probably necessary to explicitly convert the filename using some Win32 APIs.

@0x09
Copy link

0x09 commented Mar 1, 2013

Ah true. It is possible with

char *cwd = av_dirname(av_strdup(filename));
val = avs_invoke(avs->env, "SetWorkingDir", avs_new_value_string(cwd), NULL);
av_free(cwd);

before the eval invocation. But I'm past quota for dubious suggestions in this thread, sorry for the noise.

@qyot27
Copy link
Contributor Author

qyot27 commented Mar 2, 2013

I think I've stumbled across a very, very strange bug. I'm not sure if it affects AvxSynth, but I'm consistently getting hangs with AviSynth under Windows under the following conditions:

*Encoding audio
*Video fps denominator varies; sometimes 1000 is affected, sometimes 1001 is affected

If audio is disabled, affected scripts can output video just fine. It's like it's something particular about audio in these cases. There's no error warnings or anything (even with -v 9 -loglevel 99), ffmpeg.exe just hangs. Forcing a different framerate that's known to work using ChangeFPS suddenly makes it possible to output audio again.

12000/1000 is fine
12000/1001 is fine

15000/1000 is fine
15000/1001 hangs

23000/1000 hangs #to illustrate an arbitrary fps
23000/1001 hangs

24000/1000 is fine
24000/1001 is fine

25000/1000 is fine
25000/1001 hangs

30000/1000 is fine
30000/1001 hangs

48000/1000 is fine
48000/1001 hangs

50000/1000 is fine
50000/1001 hangs

60000/1000 is fine
60000/1001 hangs

Checking the actual script in Windows Media Player the script is completely fine. I can pipe the audio from wavi to ffmpeg and it works.

I initially found this because I was attempting to convert a 29.97fps script's audio and it just hung there for 3 minutes until I killed the Command Prompt, and the output file was empty. The rest of the scripts were 23.976 and the conversion process started instantly and finished successfully as expected. If it's a memory leak on those hanging fpses or something, the reason I notice it is probably because I have such a low amount of RAM in this computer (just 512MB).

Also, should the script's audio always be getting detected as pcm_f32le? As in that wavi example, the piped audio is detected as pcm_s16le like normal.

@qyot27
Copy link
Contributor Author

qyot27 commented Mar 3, 2013

A bit of a follow-up, it seems this is ultimately triggered by using SSRC to resample the audio rate when the video rate is one of these affected fps ratios. All the scripts had been using SSRC to go from 44.1->48, but the only one that had a problem was the one at 29.97fps. Like I said before, using ChangeFPS or ffms2's fpsnum/fpsden parameters to force an fps that didn't have the issue made it work (and obviously, so did removing/commenting out SSRC).

@qyot27
Copy link
Contributor Author

qyot27 commented Mar 6, 2013

I've isolated it to the avs_has_video block in avisynth_read_packet_audio, lines 497-504. I still have no clue why it works with some framerates but not others, though (my best guess is that AviSynth's internal representation of those fps values differs from what the demuxer is expecting, e.g., you can give it exactly as 30000/1001 in the script, but it exposes it to FFmpeg as 2997/100, and then when SSRC's treatment of the audio is added into the mix, something happens that the math doesn't like). The first samples = av_rescale_q assignment @ line 499 seems to be what's responsible for the problem.

The 'always showing up as pcm_f32le' was a mistake on my part. That only happens when SSRC is called because it converts the audio to float. And it is - obviously - a case of only happening with AviSynth because AvxSynth doesn't have a ported version of SSRC.

Strangely, the hang only wants to occur when I test on Windows. If I test the binary under Wine, it works, although it does still exhibit the sign that it has a problem: below the 1 second mark, it goes ridiculously slowly, and then after it passes that point, it speeds back up to normal (the audio output is okay). With fpses that aren't affected by this, the initial slowdown never happens. It also affects anything using the script with libavformat, as the mpv test build showed the same problem on Windows: 23.976 and SSRC, no problem. 29.97 and SSRC, hang before decoding and playback starts.

@avxsynth-testing
Copy link
Collaborator

This sounds like a math error. Could you post a script that demonstrates this problem? I was unable to reproduce it with this:

BlankClip(pixel_type="YV12", channels=2, audio_rate=44100, fps=29.970)
SSRC(48000)

I tried this with ffmpeg/mingw32 on Windows 8 with Avisynth 2.6a4. The command I ran was:

ffmpeg.exe -i test.avs -r 30000/1001 test.avi

@qyot27
Copy link
Contributor Author

qyot27 commented Mar 6, 2013

Well, with BlankClip it works (and it works with AVISource and DirectShowSource).

Okay, it seems it's a problem with a very particular build of FFMS2 (my branch of the C plugin + the extra planar-audio-related commits in Plorkyeran's dev branch so that FFMS2 can output audio when built against post-November 26th builds of FFmpeg), but it's still sparked by using SSRC and causes the demuxer to hang.

However, I did notice that the slowness-on-start issue when using those framerates does exist with this build of r739. With the affected fpses, the progress of encoding stutters below one second for a little while, and then speeds up to normal. Non-affected fpses don't do this. Example script:

no slowdown at start:

FFmpegSource2("test.mkv",atrack=-1,fpsnum=24000,fpsden=1001).SSRC(48000,fast=false)

slowdown:

FFmpegSource2("test.mkv",atrack=-1,fpsnum=30000,fpsden=1001).SSRC(48000,fast=false)

(also shows it when converting to pcm_s16le)

ffmpeg -i test.avs -vn -acodec ac3 -ab 192k test.ac3

Like I said, though, the script works fine in Windows Media Player 6.4 and wavi without that kind of slowdown or hanging, and the VFW-based demuxer didn't have issues with it either.

@avxsynth-testing
Copy link
Collaborator

That sounds like your problem and not mine.

Edit: I managed to load the first plugin you linked (http://www.mediafire.com/?w2t2cvddnxcmhc0). I still don't observe the issue.

Edit2: I managed to reproduce the issue. The problem seems to be that ffms crashes when attempting to read certain numbers of samples. This is a bug in ffms that should be fixed.

525 pkt->size = avs_bytes_per_channel_sample(avs->vi) * samples * avs->vi->nchannels;
(gdb) print samples
$6 = 1601
(gdb) n
526 pkt->data = av_malloc(pkt->size);
(gdb)
527 if (!pkt->data)
(gdb)
530 avs_library->avs_get_audio(avs->clip, pkt->data, avs->curr_sample, samples);
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x0622ab82 in ffms2!_ZNSt8_Rb_treeIiSt4pairIKi20FFMS_AudioPropertiesESt10_Select1stIS3_ESt4lessIiESaIS3_EED1Ev ()
from ffms2.dll

As for why the avisynth demuxer is attempting to read odd numbers of samples:
When both audio and video are present in the script, the demuxer tries to synchronize access to audio and video like a real demuxer would. This can be changed to only read even numbers of samples (or some other multiple), but this only pushes the issue down the road, as it is entirely possible for an audio source to have arbitrary numbers of samples in the last packet.

@qyot27
Copy link
Contributor Author

qyot27 commented Mar 8, 2013

Ok, that puts my mind at ease, although I'd have thought that whatever SSRC is doing would be external to the way FFMS2 is handling it. I'll see about generating info with an actual debug build and submit it on FFMS2's side.

Regarding the Unicode filenames issue, I did happen upon a function (ff_win32_open) in libavformat/os_support.c that seems like it deals with this sort of thing (and shares a bit of similarity with the patch that was submitted for the old AviSynth demuxer). I'd tried to see how to adapt it, but I kept getting Access Violation errors whenever I tried testing it under Wine.

@qyot27
Copy link
Contributor Author

qyot27 commented Mar 8, 2013

Reported on FFMS2's side. It's a little strange that I didn't get the same error message from the backtrace, though. Probably has to do with how I ran gdb.

@avxsynth-testing
Copy link
Collaborator

I've thought about unicode filenames for a while, and stumbled across this thread: http://forum.doom9.org/showthread.php?t=110467

The summary is that Avisynth accepts filenames encoded in the local codepage. From the point of view of the ffmpeg demuxer, this means that the string passed in avisynth_open_file to avs_invoke("Import", filename) must be encoded in the local codepage. The question is what FFmpeg does internally with strings from the console -- whether it holds them as-is, converts them to UTF-8, or converts them to UTF-16. If it is either of the latter two cases, the string should be converted to the local codepage by a Win32 call.

Note that it is still impossible to open files from other codepages than the local one, e.g. opening a BIG5 script file from a ISO-WESTERN system.

@qyot27
Copy link
Contributor Author

qyot27 commented Mar 9, 2013

Looking at what ff_win32_open does, the MultiByteToWideChar call is what handles it. It's assuming UTF-8 and then as per the documentation from Microsoft on that function, converts it to UTF-16.

In the old demuxer, this was handled by following the MultiByteToWideChar call with WideCharToMultiByte, converting UTF-16 to the local code page and handing that over to the rest of the VfW stuff. So it would appear the path was UTF-8 filename -> UTF-16 -> Local code page -> proceed. So now I'm wondering if those Access Violations I got under Wine weren't because it was working incorrectly, but because it was trying to convert back to the local code page on the larger Linux environment, i.e. UTF-8, and because the function and/or AviSynth can't handle that, it errored out (and at the same time, using it under real Windows might have worked because the local code page there isn't Unicode).

EDIT: Nope, the Access Violation is not indicative of just an issue with Wine. ffmpeg.exe crashes under real Windows, with no error message from AviSynth like on Wine. I'll push the [non-working] bit that I have done up so that it can be critiqued, though. Maybe it's not far off from being workable.

@qyot27
Copy link
Contributor Author

qyot27 commented Mar 21, 2013

So, um, it got committed. Took me by surprise since I'd been trying to get a couple of other things hashed out (aside from the UTF-8 issue, I found out that MSVC does not like it one bit, even though it compiled, the resultant build crashed when AviSynth scripts were handed to it), but I suppose that those things will get noticed by those that need them soon enough and patches to fix them will appear.

The thing that remains is how you want to be credited in MAINTAINERS.

@qyot27
Copy link
Contributor Author

qyot27 commented Mar 21, 2013

Nevermind about the MSVC thing, I rebuilt it just now and it works. Either it was fixed in git already (the previous build was a few days-a week old), or it was just some configuration issue that got resolved by my mucking about in VS2010 for a different project to try and get it to build.

@avxsynth-testing
Copy link
Collaborator

The maintainers file can credit AvxSynth team for managing avisynth.c.

Edit: In the ffmpeg push, I noticed this line in avisynth_context_create

182 av_free(avs);

This line should have been removed, and I swear it was in one of the many versions of the patch posted here.

Edit2: Actually, I don't know what I was smoking. The function should read:

static av_cold int avisynth_context_create(AVFormatContext *s) {
    AviSynthContext *avs = (AviSynthContext *)s->priv_data;
    int ret;

    if (!avs_library) {
        if (ret = avisynth_load_library())
            return ret;
    }

    avs->env = avs_library->avs_create_script_environment(3);
    if (avs_library->avs_get_error) {
        const char *error = avs_library->avs_get_error(avs->env);
        if (error) {
            av_log(s, AV_LOG_ERROR, "%s\n", error);
            return AVERROR_UNKNOWN;
        }
    }

    if (!avs_ctx_list) {
        avs_ctx_list = avs;
    } else {
        avs->next = avs_ctx_list;
        avs_ctx_list = avs;
    }

    return 0;
}

This constructor function was not correctly updated after I made the changes for the atexit handler.

I guess I/we should have used source control when writing this.

@avxsynth-testing
Copy link
Collaborator

Seeing as how this has been accepted into upstream, closing this as resolved.

@qyot27
Copy link
Contributor Author

qyot27 commented Jun 1, 2013

There is a particularly nasty issue with AviSynth 2.5.8:
http://ffmpeg.org/trac/ffmpeg/ticket/2526

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants