To work accurately, first convert the video to RAW YUV bitstream (if it is not already) by:
ffmpeg -i input.mp4 -an -vcodec rawvideo -pix_fmt yuv420p rawbitstream.yuv
Next step: The select
filter takes an expression, where n
is the frame number.
ffmpeg -r 2 -s WxH -i rawbitstream.yuv -filter:v select="mod(n-1\,2)" \
-c:v rawvideo -r 1 -format rawvideo -pix_fmt yuv420p -an odd.yuv
ffmpeg -r 2 -s WxH -i rawbitstream.yuv -filter:v select="not(mod(n-1\,2))" \
-c:v rawvideo -r 1 -format rawvideo -pix_fmt yuv420p -an even.yuv
To have ffmpeg
not duplicate frames, you have to force half of the framerate of your input - so you set "2" as the input and "1" to the output. Don't forget to replace the WxH with the actual dimensions of your clip because the raw bitstream doesn't have a header that carries this information.
Instead of the above, another possibility would be to add the setpts
filter to set new timestamps for the output. But be careful since it drops frames not accurately. Here, 25 is the actual output frame rate you want:
ffmpeg -i input.mp4 -filter:v select="mod(n-1\,2)",setpts="N/(25*TB)" \
-c:v rawvideo -r 12.5 -format rawvideo -pix_fmt yuv420p -an odd.yuv
ffmpeg -i input.mp4 -filter:v select="not(mod(n-1\,2))",setpts="N/(25*TB)" \
-c:v rawvideo -r 12.5 -format rawvideo -pix_fmt yuv420p -an even.yuv
You can of course choose another pixel format (any of ffmpeg -pix_fmts
). Make sure that when reading the file you know the pixel size and pixel format:
ffmpeg -f rawvideo -s:v 1280x720 -pix_fmt yuv420p input.yuv …
Can it not be done using the options
-framerate
/-r
? – Anmol Singh Jaggi – 2016-06-16T03:23:32.9131@AnmolSinghJaggi No, this just drops frames, but I wouldn't be sure that it's so deterministic (i.e., drops every odd frame). It'll be based on time codes, which may not be accurate. – slhck – 2016-06-16T08:04:14.377
Thanks, For new versions of FFMPEG it should be -vf instead of -filter:v. In addition it should be mod(n-1,2) because the n count seems to start from from 1 while frame count from 0 (otherwise the first frame is duplicated 3 time). But there is still a problem, it duplicates the frames while I want to get rid of them - e.g. the final clip will contain only half of the frames. – Mark – 2013-03-28T15:28:00.167
-vf
is an alias of-filter:v
. I can't reliably test it now, but will look into this later when I'm back on my machine. Maybe thetinterlace
filter can do the same? – slhck – 2013-03-28T15:35:00.953I've tried '-r 2 -i blah.yuv -r 1' but it shows me an error Option framerate not found. – Mark – 2013-03-28T15:36:23.357
Ah sorry.. Scratch that, this doesn't work (anymore?) and only for images. – slhck – 2013-03-28T15:38:26.777
I think I figured out why. If you use the
select
filter to drop frames,ffmpeg
will still try to create a video with the original input framerate, thus doubling the frames. Try specifying half the frame rate, or using thesetpts
filter. – slhck – 2013-03-29T16:50:45.163The ‘setpts="N/(25*TB)”’ gives me weird frame count. For instance (even): 2, 4, 6, 10, 12, 16, 20, 22 ... (no 8, 14, 18). However I’ve found another way based on the ‘mod(n-1,2)’. First, in case of compressed file, decode it to raw YUV: ‘-i input.mp4 -an -vcodec rawvideo -pix_fmt yuv420p output.yuv’. With YUVs, input frame rate required, so it also works in this case :) So the second iteration will be ‘-r 2 -s WxH -i output.yuv -vf "select=mod(n-1,2)" -r 1 -an -vcodec rawvideo -pix_fmt yuv420p outputEven.yuv’. If the file is already YUV, only the second is needed. Works like a charm :) – Mark – 2013-04-03T15:16:37.820
@Mark I'd be happy for you to suggest an [edit] to my answer and add the steps that worked for you, thereby correcting any mistakes I made. You can also post your own answer and mark it as accepted :) – slhck – 2013-04-03T15:51:42.453
Great, thanks! Very interesting the way it works, I'm new to this system of Q&A :) – Mark – 2013-04-03T17:04:52.087