54

Is it possible to do completely lossless encoding in h264? By lossless, I mean that if I feed it a series of frames and encode them, and then if I extract all the frames from the encoded video, I will get the exact same frames as in the input, pixel by pixel, frame by frame. Is that actually possible? Take this example:

I generate a bunch of frames, then I encode the image sequence to an uncompressed AVI (with something like virtualdub), I then apply lossless h264 (the help files claim that setting --qp 0 makes lossless compression, but I am not sure if that means that there is no loss at any point of the process or that just the quantization is lossless). I can then extract the frames from the resulting h264 video with something like mplayer.

I tried with Handbrake first, but it turns out it doesn't support lossless encoding. I tried x264 but it crashes. It may be because my source AVI file is in RGB colorspace instead of YV12. I don't know how to feed a series of YV12 bitmaps and in what format to x264 anyway, so I cannot even try.

In summary what I want to know if that is there a way to go from

Series of lossless bitmaps (in any colorspace) -> some transformation -> h264 encode -> h264 decode -> some transformation -> the original series of lossless bitmaps

If there a way to achieve this?

EDIT: There is a VERY valid point about lossless H264 not making too much sense. I am well aware that there is no way I could tell (with just my eyes) the difference between and uncompressed clip and another compressed at a high rate in H264, but I don't think it is not without uses. For example, it may be useful for storing video for editing without taking huge amounts of space and not losing quality and spending too much encoding time every time the file is saved.

UPDATE 2: Now x264 doesn't crash. I can use as sources either avisynth or lossless yv12 lagarith (to avoid the colorspace compression warning). Howerver, even with --qp 0 and a rgb or yv12 source I still get some differences, minimal but present. This is troubling, because all the information I have found on lossless predictive coding (--qp 0) claims that the whole encoding should be lossless, but I am unable to verifiy this.

cloudraven
  • 2,484
  • 1
  • 24
  • 49
  • 3
    I never even knew h.264 defined a loss-less schema... –  Jul 15 '11 at 01:47
  • 1
    I don't believe you can do h.264 in a lossless mode. Why would you want to anyway? – Brad Jul 15 '11 at 01:52
  • What's wrong with being lossy? –  Jul 15 '11 at 02:04
  • 14
    Movie CG studios often send their productions (with shipping companies) on airplanes because it's cheaper and faster than sending it on the internet. When you hear stories like this suddenly a question like this makes perfect sense. And yes, there is lossless mode for h.264. – Karoly Horvath Jul 15 '11 at 23:44
  • 1
    This question appears to be off-topic because it is about FFmpeg and would be a better fit on either [su] or [video.se]. – Cole Tobin Dec 28 '14 at 02:43

8 Answers8

34

I am going to add a late answer to this one after spending all day trying to figure out how to get YUV 4:4:4 pixels into x264. While x264 does accept raw 4:2:0 pixels in a file, it is really quite difficult getting 4:4:4 pixels passed in. With recent versions of ffmpeg, the following works for completely lossless encoding and extraction to verify the encoding.

First, write your raw yuv 4:4:4 pixels to a file in a planar format. The planes are a set of Y bytes, then the U and V bytes where U and V use 128 as the zero value. Now, invoke ffmpeg and pass in the size of the raw YUV frames as use the "yuv444p" pixel format twice, like so:

ffmpeg -y -s 480x480 -pix_fmt yuv444p -i Tree480.yuv \
-c:v libx264 -pix_fmt yuv444p -profile:v high444 -crf 0 \
-preset:v slow \
Tree480_lossless.m4v

Once the encoding to h264 and wrapping as a Quicktime file is done, one can extract the exact same bytes like so:

ffmpeg -y -i Tree480_lossless.m4v -vcodec rawvideo -pix_fmt yuv444p \
Tree480_m4v_decoded.yuv

Finally, verify the two binary files with diff:

$ diff -s Tree480.yuv Tree480_m4v_decoded.yuv
Files Tree480.yuv and Tree480_m4v_decoded.yuv are identical

Just keep in mind that you need to write the YUV bytes to a file yourself, do not let ffmpeg do any conversion of the YUV values!

MoDJ
  • 4,309
  • 2
  • 30
  • 65
  • a simpler ffmpeg command is: ffmpeg -i Frame_03d.png -vcodec rawvideo -pix_fmt yuv444p Output.y4m (change 3 to the number of digits in your file) – MarcusJ May 01 '15 at 13:15
  • at last someone verifies! – n611x007 Sep 07 '15 at 18:21
  • 2
    No, that would just dump the raw pixels to a y4m (rawvideo) file. The original question was on how to encode as lossless h.264. Your "simpler" command is not compressing the data, it just converts to raw uncompressed pixels. – MoDJ Sep 07 '15 at 19:21
  • The first command is to convert it. The second ones are to "uncompress it" for comparison purposes :) – rogerdpack Dec 20 '19 at 03:51
5

If x264 does lossless encoding but doesn't like your input format, then your best bet is to use ffmpeg to deal with the input file. Try starting with something like

ffmpeg -i input.avi -f yuv4mpegpipe -pix_fmt yuv420p -y /dev/stdout \
  | x264 $OPTIONS -o output.264 /dev/stdin

and adding options from there. YUV4MPEG is a lossless uncompressed format suitable for piping between different video tools; ffmpeg knows how to write it and x264 knows how to read it.

hobbs
  • 223,387
  • 19
  • 210
  • 288
  • 1
    Thanks! So far I haven't been able to get back to my exact original videos with x264 (now it likes my input format). There are always lingering (very very subtle) artifacts, so maybe ffmpeg can help me there. Will I lose color information from the original avi when converting to yuv420p? Even if that is the case, is there a way to extract individual frames from the yuv4mpeg uncompressed stream so that I can compare them with the frames in the x264 stream, or at least to decode the yuv4mpeg back from the x264 stream. If h264 can be truly lossless they should be identical. – cloudraven Jul 15 '11 at 22:58
  • 6
    There's probably some minor loss of precision in the conversion from RGB to YUV, but I believe that's unavoidable as YUV is H.264's native colorspace. However, I forgot that YUV420P isn't actually a fully lossless pixel format -- it reduces the chroma information it stores somewhat. Try choosing other options from `ffmpeg -pix_fmts` and seeing if x264 will accept them. `yuv444p` would be a good start; it's YUV but with full chroma information per-pixel. – hobbs Jul 16 '11 at 00:43
  • That's what I thought. I tried doing the following to discard colorspace reduction: Encode video using lagarith (lossless yv12) so that I would have my images in a colorspace suitable for h264. I extracted all the frames from that video and kept a copy. I encoded the video with x264 --qp0 (no color conversion happened this time) and then I extracted the frames of the resulting video. They didn't match my backup. There shouldn't be a loss of info going from YV12 to RGB right? Am I doing something wrong? – cloudraven Jul 16 '11 at 00:55
4

FFmpeg has a "lossless" mode for x264, see FFmpeg and x264 Encoding Guide

§ Lossless H.264

in essence it's -qp 0

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
2

I agree that sometimes the loss in data is acceptable, but it's not simply a matter of how it looks immediately after compression.

Even a visually imperceptible loss of color data can degrade footage such that color correction, greenscreen keying, tracking, and other post tasks become more difficult or impossible, which add expense to a production.

It really depends when and how you compress in the pipeline, but ultimately it makes sense to archive the original quality, as storage is usually far less expensive than reshooting.

Kijewski
  • 25,517
  • 12
  • 101
  • 143
LDaly
  • 29
  • 1
  • 1
    Good point and I agree completely, but that's more of a comment than an answer. I guess it was posted due to lack of commenting priviledge? – Camilo Martin Apr 03 '15 at 17:46
2

To generate lossless H.264 with HandBrake GUI, set Video Codec: H.264, Constant Quality, RF: 0, H.264 Profile: auto. Though this file is not supported natively by Apple, it can be re-encoded as near-lossless for playback.

HandBrake GUI's Activity Window:

H.264 Profile: auto; Encoding at constant RF 0.000000...profile High 4:4:4 Predictive, level 3.0, 4:2:0 8-bit

H.264 Profile: high; Encoding at constant RF 0.000000...lossless requires high444 profile, disabling...profile High, level 3.0

2

I don't know your requirements for compression and decompression, but a general purpose archiver (like 7-zip with LZMA2) should be able to compress about as small or, in some cases, even significantly smaller than a lossless video codec. And it is much simpler and safer than a whole video processing chain. The downside is the much slower speed, and that you have to extract before seeing it. But for images, I think you should try it.

There is also lossless image formats, like .png.

For encoding lossless RGB with x264, you should use the command line version of x264 (you can't trust GUIs in this edge case, they will probably mess-up) r2020 or newer, with something like that:

x264 --qp 0 --preset fast --input-csp rgb --output-csp rgb --colormatrix GBR --output "the_lossless_output.mkv" "someinput.avs"

Any losses/differences between the input and output should be from some colour space conversion (either before encoding, or at playback), wrong settings or some header/meta-data that was lost. x264 don't supports RGBA, but RGB is ok. YUV 4:4:4 compression is more efficient, but you will lose some data in colour space conversion as your input is RGB. YV12/i420 is much smaller, and by far the most common colour space in video, but you have less chroma resolution.

More information on x264 settings: http://mewiki.project357.com/wiki/X264_Settings

Also, avoid lagarith. It uses x87 floating point... and there are better alternatives. http://codecs.multimedia.cx/?p=303 http://mod16.org/hurfdurf/?p=142

EDIT: I don't know why I was donwvoted. Please leave a comment when you do that.

ReneSac
  • 521
  • 3
  • 9
  • 3
    General-purpose compression algorithms don't deal very well with video, audio, etc. Specialized algorithms (if they exist) are almost always better. Exceptions to this rule are some very old algorithms + maybe special crafted input data intended to fool the encoder. – Display Name Jun 03 '13 at 09:02
  • 1
    @Sarge: I disagree regarding lossless video codecs, because better is meaningless without defining the stat to compare. Many lossless video codecs are for realtime capture so only do light compression. Generic compressors often result in smaller filesize. – John Smith Aug 06 '13 at 09:04
  • @JohnSmith in that case, they are faster. – Display Name Aug 06 '13 at 10:15
  • The main advantage is not needing decompression of the whole file before viewing/using it. And yes, most lossless video codecs are designed for realtime capture and thus are fast, and usually compress natural fotage better than general purpose archivers, but not by much. But for some contents, like 2D screen capture, not even specialized codecs can match the compression of LZMA with a big dictionary. And you will aways have a bit-exact copy of your input video, with no chance to screw-up in color conversion, metadata, etc. Depending on the needs of the OP, they might be the best option. – ReneSac Nov 27 '13 at 02:45
1

If you can't get lossless compression using a h.264 encoder and decoder, perhaps you could look into two alternatives:

(1) Rather than passing all the data in h.264 format, some people are experimenting with transmitting some of the data with a residual "side channel":

  • (h.264 file) -> h264 decode -> some transformation -> a lossy approximation of the original series of bitmaps
  • (compressed residual file) --> decoder -> a series of lossless residual bitmaps
  • For each pixel in each bitmap, approximate_pixel + residual_pixel = a pixel bit-for-bit equal to the original pixel.

(2) Use Dirac video compression format in "lossless" mode.

David Cary
  • 5,250
  • 6
  • 53
  • 66
  • Yeah... actually I ended up doing something very similar to that (Option 1). I also tried using Lagarith codec, that is probably similar to option 2. My bad for not writing about it here. Thanks a lot for the answer though. – cloudraven Aug 27 '11 at 02:13
  • Does that even produce worthwhile results? I remember trying something similar with MP3 + lzma-compressed residual once but it was always worse than plain FLAC (by a very small margin) – Camilo Martin Apr 03 '15 at 17:50
0

Use FFmpeg with PowerShell. Type ffmpeg -h encoder=libx264rgb. You can see Supported pixel formats: bgr0 bgr24 rgb24 When you encoding RGB to YUV or vice versa, you always loose quality. But if you use -pix_fmt yuv444p -profile:v high444p your losses are least. But if you use libx264rgb of ffmpeg encoder libx264rgb with format of pixel rgb24 you don't have any loss of quality. A lot of application (for example Davinci Resolve) cannot read rgb 24 format of pixel. I reccomend you to use:

ffmpeg -i ["your sequence of rgb image.png"] -c:v libx264rgb -video_size [your size] -framerate [your fps] -r [your fps] -qp 0 -pix_fmt rgb24 -profile:v high444 -preset veryslow -level 6.2 "your_video.mov"

Unfortunately, I don't know how to create sequence. But it is possible in FFmpeg.

Andrew
  • 11