1

Is it possible for FFmpeg / ffv1.3 / mkv to create a lossless video is not larger than the sum of its parts (and if so, how) and if not, what is a good alternative to come close on size? The video must be lossless.

I am attempting to use FFmpeg to create a mkv with ffv1.3 on a set of similar jpeg images (images from a web cam). I am able to create the video however, it at least 2 times the size of the collection of jpeg images. I would have expected about the same level of compression or better.

I do understand that jpeg on its own is optimized for compression. However a large set of very similar images should be able to be further compressed, or in this case similar to the original images added up.

The commands I am using to create the file are:

ffmpeg -pattern_type glob -i '*.jpg' -vcodec ffv1 -level 3 -an -pass 1 -passlogfile passlog -f matroska /dev/null

ffmpeg -pattern_type glob -i '*.jpg' -vcodec ffv1 -level 3 -an -pass 2 -passlogfile passlog -f matroska ~/foo.mkv

The input files are 24M in total but the resulting mkv is 96M (per du -h).

The results from the second pass:

ffmpeg version N-79053-g7eedad9 Copyright (c) 2000-2016 the FFmpeg developers
  built with gcc 4.6 (Debian 4.6.3-14+rpi1)
  configuration: --enable-cross-compile --cross-prefix= --arch=armel --target-os=linux --prefix=/my/path/were/i/keep/built/arm/stuff
  libavutil      55. 19.100 / 55. 19.100
  libavcodec     57. 28.103 / 57. 28.103
  libavformat    57. 28.101 / 57. 28.101
  libavdevice    57.  0.101 / 57.  0.101
  libavfilter     6. 39.102 /  6. 39.102
  libswscale      4.  0.100 /  4.  0.100
  libswresample   2.  0.101 /  2.  0.101
Input #0, image2, from '*.jpg':
  Duration: 00:00:21.32, start: 0.000000, bitrate: N/A
    Stream #0:0: Video: mjpeg, yuvj422p(pc, bt470bg/unknown/unknown), 640x480, 25 fps, 25 tbr, 25 tbn, 25 tbc
File '/home/pi/foo.mkv' already exists. Overwrite ? [y/N] y
[swscaler @ 0x3671f30] deprecated pixel format used, make sure you did set range correctly
Output #0, matroska, to '/home/pi/foo.mkv':
  Metadata:
    encoder         : Lavf57.28.101
    Stream #0:0: Video: ffv1 (FFV1 / 0x31564646), yuv422p, 640x480, q=2-31, pass 2, 200 kb/s, 25 fps, 1k tbn, 25 tbc
    Metadata:
      encoder         : Lavc57.28.103 ffv1
Stream mapping:
  Stream #0:0 -> #0:0 (mjpeg (native) -> ffv1 (native))
Press [q] to stop, [?] for help
frame=  533 fps=4.2 q=-0.0 Lsize=   97815kB time=00:00:21.32 bitrate=37584.4kbits/s speed=0.168x
video:97808kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.006607%

Each jpeg is approximately 43143 bytes (per ls -al) but running the following command the tool states each image is 614400 bytes (both in the video and the independent jpeg images). I would assume this is the uncompresses size of the image (640x480x2).

ffmpeg -pattern_type glob -i '*.jpg' -f framemd5 -

results below are for the images, same sizes are reported for the mkv.

ffmpeg version N-79053-g7eedad9 Copyright (c) 2000-2016 the FFmpeg developers
  built with gcc 4.6 (Debian 4.6.3-14+rpi1)
  configuration: --enable-cross-compile --cross-prefix= --arch=armel --target-os=linux --prefix=/my/path/were/i/keep/built/arm/stuff
  libavutil      55. 19.100 / 55. 19.100
  libavcodec     57. 28.103 / 57. 28.103
  libavformat    57. 28.101 / 57. 28.101
  libavdevice    57.  0.101 / 57.  0.101
  libavfilter     6. 39.102 /  6. 39.102
  libswscale      4.  0.100 /  4.  0.100
  libswresample   2.  0.101 /  2.  0.101
Input #0, image2, from '*.jpg':
  Duration: 00:00:21.32, start: 0.000000, bitrate: N/A
    Stream #0:0: Video: mjpeg, yuvj422p(pc, bt470bg/unknown/unknown), 640x480, 25 fps, 25 tbr, 25 tbn, 25 tbc
#format: frame checksums
#version: 1
#hash: MD5
#software: Lavf57.28.101
#tb 0: 1/25
#stream#, dts,        pts, duration,     size, hash
Output #0, framemd5, to 'pipe:':
  Metadata:
    encoder         : Lavf57.28.101
    Stream #0:0: Video: rawvideo (Y42B / 0x42323459), yuvj422p, 640x480, q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc
    Metadata:
      encoder         : Lavc57.28.103 rawvideo
Stream mapping:
  Stream #0:0 -> #0:0 (mjpeg (native) -> rawvideo (native))
Press [q] to stop, [?] for help
0,          0,          0,        1,   614400, 2148ff8b95296f4bacc1099d13235063
0,          1,          1,        1,   614400, da330e2acd2f7d7a1e79fe79fccc90cf
0,          2,          2,        1,   614400, f55563c13a9f232ce32419fa26e37214
0,          3,          3,        1,   614400, c53d994fff0a9b26529fa8763deae520

EDIT: The best compression (and good speed) came from a container of the jpeg images themself:

ffmpeg -pattern_type glob -i '*.jpg' -vcodec copy -an -f matroska ~/foo.mkv

The resulting file was just over 24M (vs. the 96M ffv1). Also the decompressed jpeg images was 312M, in both cases they compressed fairly well. If I had started with anything other than a jpeg, ffv1 would have been ideal but in my case the lossy jpeg where also the lossless initial images.

1
  • By default the image file demuxer will use a frame rate of 25. If you want to change it use the -framerate input option (and additionally the -r output option if you want to vary the input vs output frame rate). You can preprocess the JPG images with jpegtran to perform lossless optimization (see example using a bash "for loop") before muxing with ffmpeg. Your results may vary depending on the JPG files themselves.
    – llogan
    Mar 20, 2016 at 18:06

1 Answer 1

1

I've generally found that encoding lossy video with a lossless codec results in a larger file size. FFmpeg has to decompress your input before it can encode to ffv1, so it is working from the uncompressed version of your jpegs. The process is outlined here: https://ffmpeg.org/ffmpeg.html#Detailed-description

2
  • The link provided the information I needed. Because the jpeg is decompressed then re-compressed by ffv1 its not as small. Unfortunately this does not explain why individual jpeg images compress are better then multi frame compression by ffv1 but its still a fact. Mar 20, 2016 at 15:30
  • 1
    If I understand you correctly, you're wondering why -vcodec copy produced a smaller file than -vcodec ffv1? This is because it isn't re-encoding your jpegs,it's just copying the streama,. That's why it's so fast,the bottleneck is how fast your hard drive can copy/paste. Mar 20, 2016 at 16:08

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.