avs4x264mod with –seek and –frames?
When I solved the high bit depth input issue with original avs4x264 and published the first build, I had never thought that I would keep maintaining this mod as I only modified avs4x264 for my own use, and v0.1 already met all my own demands. So I didn’t test much. Recently I found another modified avs4x264 – Yet Another Avs4X264 Mod ( yaa4xm ). I was impressed by the fact that this piping tool claims not supporting x264’s –seek and –frames. I looked into avs4x264’s codes and comfirmed that –frames was not supported, by both the parameter parser and piping. –seek? Avs4x264 can handle it, although in a weird way.
There is nearly no reason for me to fix these two issues, if they had ever bothered anyone. Setting the start and the end frame for avs input is so easy — just add a Trim in avs. But if avs4x264mod has already finished many things I almost never used before and may never use in the future, why not making it more powerful?
There was two things preventing –frames from working correctly. The first stuff was in the parser that avs4x264 added –frames before user defined parameters without checking if it was already given in commandline, and x264 would get two –frames parameter. Though x264 actually use the later one, it is still not an option to leave the arbitrary problem to x264. The second stuff was that x264 finishes its work as soon as it has encoded the number of frames specified by –frames. But avs4x264 kept delivering until the end of the clip of avs. Then the frames exceeding –frames range could not be handle and avs4x264 threw error. Actually it did not matter too much as the encoding process could be finished without any error. Just leave avs4x264 away. But no one likes even error message, do we?
To solve –frames issue was quite easy and v0.6 of my mod version already support user defined –frames. However when I did it I made a mistake, and now I find out there is a bug of calculating frames delivered to x264 if both –seek and –frames are given in commandline. I prevented the parser from adding –frames if it is already defined, and made avs4x264mod only deliver the number –frames tells. This works fine if –seek is not given. But x264’s approach is to count from the first frame –seek gives until –frames gives. So if a clip has only 500 frames, for –seek 200 –frames 300, x264 will encode from the 201st frame to the 500th frame if get input from avs file directly, but will only encode from the 201st frame to the 300th frame if working with avs4x264mod.
This is still a simple thing to deal with. There are several ways to do. The simplest one is parsing –seek parameter, deleting this parameter when generating new commandline for x264 binary, and delivering from the seek+1 frame to the seek+1+frames frame. Another similar one is just adding a Trim in the end of avs after parsing and deleting –seek option. The third one is that do not touch seek parameter after parsing, but let avs4x264mod deliver from the first frame to the seek+1+frames frame, just like what it did in the past. All these three method shall give the same result in most cases, but wait, in most cases?
Yes, there is still some cases the results are different — with timecodes. x264 takes timecodes and thinks it is for the source file, not the encoded file. Say, if it takes the following timecodes for a 500 frames input file:
# timecode format v1
, and if it gets parameters like –seek 200 –frames 300, then after encoding, the timecodes of output video will be like this:
# timecode format v1
Now if we fix the way of dealing with –seek in the first or the second mothed above, as the first 200 frames will be omitted, the timecodes of output video will turn to be:
# timecode format v1
See, the result is not correct any more. This will not bother one too much as he or she can still use mkvmerge for matroska files and timelineeditor for mp4 files to fix the timecodes ( What? tc2mp4? What is that buggy stuff? -_,- ). However, begined from rev1943, x264 introduced a so-called VFR MB-tree that varies the mb-tree and therefore the quality of every frame to be encoded according to the actual frame rate of it. What if a 59.940fps frame is treated as 23.976 and a 23.976fps frame is treated as 59.970? The result file might be strangely large or the content might be somehow ugly or, at least it affects the efficiency of x264.
That is not all the issues of the first two methods. There are many things annoying avs’s seek, e.g., decoding a m2ts with ffms, or use TIVTC’s one-pass mode ( TDecimate(mode=3) ) to inverse telecine. But avs4x264mod cannot know if the avs script can be safely seeked or not. So it cannot even switch the method of doing this trimming automatically by the seekability. ( Actually avs4x264mod works in a way that it gets a frame from avs server, send it to x264, release the current frame and get the next frame. Every time it gets a frame, it calls the avs_h.func.avs_get_frame function from Avisynth library, requires a frame by its frame number. I am not familiar with how Avisynth acts in this case. Does it output frames linearly, or just seek to one frame, send and release the frame, then seek to another? If it is the first one, avs4x264mod is safe with all the avs scripts, and I personally believed it is how it works, as x264 works in nearly the same way with avs input, and should have the same problem with non-seekable avs input. That’s why I treat this breaking issue to be the second place of these two method. But if not, avs4x264mod should break all the avs that can only be linear seeked, not only with these two methods to deal with –seek. )
Now let us look at the third method again. It seems that nothing is broken in this time. Nothing. However, I called it weird before. If x264 reads input avs file directly, it acts just like the first two methods that I prepared for solving –seek issue. Although it may break non-seekbale avs, it skips all the frames until the frame number –seek indicates. The third method avs4x264mod may use to deal with –seek is somehow different. It still delivers all the frames that x264 might be interested in ( for timecodes parsing ). Now x264 acts as if with other raw piping tools ( excluding avs2pipemod if you change –seek into avs2pipemod’s -trim, in which case it does exactly in the second method ) or lavf demuxer. See both the two situation is that the source is not seekable. However the avs script is seekable, although may not be safe. It reads all the frames from the beginning, does nothing for the first to-be-discard frames except for skipping the same numbers of frame in timcodes, and starts to encode from the seek+1 frame. However, if you send a very heavy avs script to avs4x264mod working in this way, the processing time of the first *garbage* frames is just a waste of life.
Now what can I get as a conclusion? The only thing I know is that all the methods are not good enough for me. Two buggy, one wasteful. Then I got the fourth approach, i.e., a mixture the first and the third method. As x264 already breaks seekable avs with –seek, given that I aimed my avs4x264mod to be a replacement of x264.exe in the commandline, just like what I guessed the original author might do from the simple usage of avs4x264, I can just ignore that problem. Then the only problem is timecodes issue. I can make a detectection to fined if x264 gets a timecodes file or not. Actually it was already done for preventing adding –fps when –tcfile-in being used. If no tcfile is used, use the first method for fast seek, and otherwise use the third method.
This can still be improved more. If timecodes file is used, the only thing x264 cares is that the first *seek* frames being stashed. It is possible, though a little bit complicated, to replace those frames by simple BlankClip, or even easier freezed frame of the first frame after seek. Even without timecodes input we can still on this with only very litter time to be waste for the dummy frames, as long as we do not mention non-seekable avs any more. This fifth method seems to meet most demands we need. At lease I have no interest in adding a timecode parser and output a new trimmed timecodes to deal with timecodes.
And another choise is to add a –seek-mode option, to let user to decide which method to be used. “fast” uses method 1/2 if no timecodes input and 5 with timecodes, which should gives exactly the same result as inputing avs directly to x264 as well as the issue of non-seekable avs, and “safe” always uses 3 for safety of all avs scripts. This is the way I would like to accomplish in the future. Any comments are welcomed on this but for now, I will firstly fix the existing –seek & –frames bug and always use 3 as before in the next git commitment. For now, just keep tracking the git for the first solved revision, or stop using useless –seek and –frames!