I have large video files of screen recordings which I created with Camtasia Recorder. The content I am recording only updates once per minute (1/60 fps), however Camtasia appears to require at least 1 fps for recording (quite silly, really). So that's what I did, and then I tried looking in Camtasia Studio to cut out the extra frames but it seems the only way to reduce the file size without compressing to a lossy format is to manually cut by hand 1 second segments throughout the entire file, but these files are too long to do this by hand (3 files, one of which is 24 hrs and the shortest is 8 hrs).

How would I cut all but 1 frame every 60 seconds from a video file?

Note that while the file is currently in the CamRec format, I can convert it to other formats if need be.

Attempts at using mpdecimate:

I have a 479mb "test.avi" video (you can download it here) which is 35 second uncompressed avi file of me moving some windows around on my desktop.

The first command I ran was:

ffmpeg -i test.avi -vf mpdecimate test-out.mp4

The resulting file (714kb) has 5-6 seconds of black, then the rest of the input video unaltered (but it is compressed).

Then I tried:

ffmpeg -i test.avi -vf mpdecimate -vsync 2 test-out.mp4

Which output a file (716kb) with seemingly the same results.

ffmpeg version N-70358-g047fd98 Copyright (c) 2000-2015 the FFmpeg developers
  built with gcc 4.9.2 (GCC)
  configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnu
tls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-
libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-l
ibrtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-aacenc --
enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --ena
ble-libxvid --enable-lzma --enable-decklink --enable-zlib
  libavutil      54. 19.100 / 54. 19.100
  libavcodec     56. 26.100 / 56. 26.100
  libavformat    56. 23.106 / 56. 23.106
  libavdevice    56.  4.100 / 56.  4.100
  libavfilter     5. 11.102 /  5. 11.102
  libswscale      3.  1.101 /  3.  1.101
  libswresample   1.  1.100 /  1.  1.100
  libpostproc    53.  3.100 / 53.  3.100
Input #0, avi, from 'test.avi':
  Duration: 00:00:34.87, start: 0.000000, bitrate: 115403 kb/s
    Stream #0:0: Video: rawvideo, bgr24, 572x280, 115425 kb/s, 30 fps, 30 tbr, 30 tbn, 30 tbc
File 'test-out2.mp4' already exists. Overwrite ? [y/N] y
No pixel format specified, yuv444p for H.264 encoding chosen.
Use -pix_fmt yuv420p for compatibility with outdated media players.
[libx264 @ 0000000003047200] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX
[libx264 @ 0000000003047200] profile High 4:4:4 Predictive, level 2.1, 4:4:4 8-bit
[libx264 @ 0000000003047200] 264 - core 144 r2525 40bb568 - H.264/MPEG-4 AVC codec - Copyleft 2003-2014 - http://www.videolan.org/x264.html - options:
 cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 dead
zone=21,11 fast_pskip=1 chroma_qp_offset=4 threads=12 lookahead_threads=2 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_in
tra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahe
ad=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to 'test-out2.mp4':
    encoder         : Lavf56.23.106
    Stream #0:0: Video: h264 (libx264) ([33][0][0][0] / 0x0021), yuv444p, 572x280, q=-1--1, 30 fps, 10000k tbn, 30 tbc
      encoder         : Lavc56.26.100 libx264
Stream mapping:
  Stream #0:0 -> #0:0 (rawvideo (native) -> h264 (libx264))
Press [q] to stop, [?] for help
[swscaler @ 0000000003017fe0] Warning: data is not aligned! This can lead to a speedloss
frame=  406 fps= 50 q=-1.0 Lsize=     715kB time=00:00:34.06 bitrate= 171.9kbits/s
video:711kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.578083%
[libx264 @ 0000000003047200] frame I:4     Avg QP:20.40  size: 18550
[libx264 @ 0000000003047200] frame P:342   Avg QP:21.60  size:  1878
[libx264 @ 0000000003047200] frame B:60    Avg QP:19.97  size:   176
[libx264 @ 0000000003047200] consecutive B-frames: 75.9% 12.8%  1.5%  9.9%
[libx264 @ 0000000003047200] mb I  I16..4: 40.3% 25.6% 34.1%
[libx264 @ 0000000003047200] mb P  I16..4: 10.2%  4.6%  4.8%  P16..4:  7.6%  2.0%  0.6%  0.0%  0.0%    skip:70.1%
[libx264 @ 0000000003047200] mb B  I16..4:  0.6%  0.1%  0.3%  B16..8:  7.8%  0.4%  0.0%  direct: 0.1%  skip:90.7%  L0:42.8% L1:56.3% BI: 1.0%
[libx264 @ 0000000003047200] 8x8 transform intra:23.3% inter:53.3%
[libx264 @ 0000000003047200] coded y,u,v intra: 17.3% 7.5% 7.2% inter: 1.9% 0.4% 0.4%
[libx264 @ 0000000003047200] i16 v,h,dc,p: 20% 76%  3%  1%
[libx264 @ 0000000003047200] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 23% 18% 57%  0%  0%  0%  1%  0%  1%
[libx264 @ 0000000003047200] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 26% 45% 16%  1%  2%  2%  2%  2%  3%
[libx264 @ 0000000003047200] Weighted P-Frames: Y:0.0% UV:0.0%
[libx264 @ 0000000003047200] ref P L0: 62.9% 10.7% 14.1% 12.3%
[libx264 @ 0000000003047200] ref B L0: 85.2% 14.2%  0.6%
[libx264 @ 0000000003047200] ref B L1: 99.1%  0.9%
[libx264 @ 0000000003047200] kb/s:163.69

Then I tried:

ffmpeg -i test.avi -vf mpdecimate=hi=64*12:lo=64*2:frac=0.1,showinfo -vsync 2 test-out2.mp4

with the same results (in terms of how the video file appeared).

frame=  411 fps=221 q=-1.0 Lsize=     716kB time=00:00:34.06 bitrate= 172.3kbits/s
video:712kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.589478%
[libx264 @ 0000000004e66b40] frame I:4     Avg QP:20.26  size: 18595
[libx264 @ 0000000004e66b40] frame P:343   Avg QP:21.49  size:  1876
[libx264 @ 0000000004e66b40] frame B:64    Avg QP:19.52  size:   170
[libx264 @ 0000000004e66b40] consecutive B-frames: 74.7% 13.1%  1.5% 10.7%
[libx264 @ 0000000004e66b40] mb I  I16..4: 41.6% 24.6% 33.8%
[libx264 @ 0000000004e66b40] mb P  I16..4: 10.2%  4.5%  4.8%  P16..4:  7.6%  2.0%  0.6%  0.0%  0.0%    skip:70.3%
[libx264 @ 0000000004e66b40] mb B  I16..4:  0.6%  0.1%  0.3%  B16..8:  7.5%  0.4%  0.0%  direct: 0.0%  skip:91.0%  L0:43.4% L1:55.6% BI: 0.9%
[libx264 @ 0000000004e66b40] 8x8 transform intra:23.1% inter:53.7%
[libx264 @ 0000000004e66b40] coded y,u,v intra: 17.4% 7.5% 7.2% inter: 1.9% 0.4% 0.4%
[libx264 @ 0000000004e66b40] i16 v,h,dc,p: 21% 75%  3%  1%
[libx264 @ 0000000004e66b40] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 23% 17% 58%  0%  0%  0%  1%  0%  1%
[libx264 @ 0000000004e66b40] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 26% 45% 16%  1%  2%  2%  2%  2%  3%
[libx264 @ 0000000004e66b40] Weighted P-Frames: Y:0.0% UV:0.0%
[libx264 @ 0000000004e66b40] ref P L0: 62.9% 10.6% 14.2% 12.3%
[libx264 @ 0000000004e66b40] ref B L0: 86.0% 13.3%  0.6%
[libx264 @ 0000000004e66b40] ref B L1: 99.1%  0.9%
[libx264 @ 0000000004e66b40] kb/s:164.04

FFmpeg has a framestep filter to take every nth frame.

There's also mpdecimate, which outputs a frame whenever the input frame is different enough from the previous frame. (so if exactly every 60th frame isn't perfect, you could use mpdecimate instead to detect the changes, and make a potentially VFR video.)

I didn't test this command; post a comment if I screwed it up:

ffmpeg -i in.camrec -vf framestep=60 -r 1/60 -codec copy -map 0 -c:v libx264 -preset medium -crf 16 -movflags +faststart -vsync 2 out.mp4

Or use out.mkv if you like matroska better than the mp4 container.

copy (stream copy) won't work while dropping frames, I think even for an intra-only codec. So your output has to be encoded to some codec. My example uses lossy h.264, but with the quality cranked so high it should be transparent. You could use lossless h.264 (-preset ultrafast -qp 0), -c:v utvideo, or whatever else you like.

-vsync 2 turns on VFR output mode, which for some reason isn't the default in mp4. (but it is in mkv). You'll want that if you use mpdecimate, but you won't need it for framestep.

A quick google didn't tell me if camrec is already lossy or not. If it's lossy, then there's no way to get a file as small but with the same quality as just keeping every 60th CamRec frame without decoding them. (assuming there's an intra-only frame at the point you want one, if the format has any non-intra frames.)

With mjpeg, you can turn a video into a directory of images without decoding, and select whichever ones you want, and mux them up again. Since camrec frames probably aren't a stand-alone image format, it's unlikely there's something similar, so you just have to use video tools. Like I said, don't think ffmpeg can do clever things like frame dropping without decompressing, even for intra-only codecs. Other tools might exist that can do that, for some codecs.

If it's lossless, then it just takes more CPU time to decode / re-encode to a new lossless format.

edit: more about mpdecimate: As noted in the comments, I added some stats logging to mpdecimate.
git pull https://github.com/pcordes/FFmpeg.git mpdecimate
and then build ffmpeg as usual.

Then run ffmpeg -v debug ....
Or ffplav -v debug -vf mpdecimate input.avi

Testing mpdecimate threshold settings with ffplay is a lot faster than making an encode.

  • Oh btw, camrec appears to be a container format. It can hold a few different codecs. I haven't checked that ffmpeg can decode them all, but apparently you can record in xvid or h.264 in camrec, unless I misread a random forum comment. – Peter Cordes Mar 1 '15 at 18:45
  • I tried both commands but neither worked. It seems mpdecimate is really what I'm looking for, but every time I try to run the command I get either an unchanged file, or a purely black file that is slightly longer than the input file. I converted my camrec file to a lossless AVI file (since ff seems to have trouble with it) and ran this: ffmpeg -i "capture-1.avi" -vf "mpdecimate" -vsync 2 "capture-1.mp4", also without the -vsync 2 part, to no avail. Am I doing this wrong? – IDontWorkAtNASA Mar 2 '15 at 19:23
  • The difference in the frames is substantial and should be triggering the drops, but in case it isn't I tried altering the command parameters with little success. The documentation unfortunately offers no real guidance on how the parameters are entered. – IDontWorkAtNASA Mar 2 '15 at 19:45
  • That looks like the right command line. What different options did you try for mpdecimate? The options set thresholds for 8x8 SAD of blocks on all planes (luma and chroma). (en.wikipedia.org/wiki/Sum_of_absolute_differences). Is there a blinking cursor somewhere on the screen that's triggering the hi threshold? Maybe crank it really high, and depend on the lo threshold to detect when large areas of the screen change. – Peter Cordes Mar 3 '15 at 2:25
  • See my edit to my answer. Last time I used mpdecimate, I added some debug prints to it. If can and want to compile ffmpeg from source, grab my mpdecimate branch of github.com/pcordes/FFmpeg/tree/mpdecimate. (I just rebased it to current git master, so you should be able to git pull https://github.com/pcordes/FFmpeg.git mpdecimate in an existing git clone of ffmpeg.) – Peter Cordes Mar 3 '15 at 3:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.