The QuickTime Gamma Bug

The QuickTime player causes H.264 and MPEG-4 encoded video to look washed-out. It’s commonly referred to as the “QuickTime gamma bug,” but it’s really a reduction in contrast, which converts the full range of pixel values (0-255) to the more limited pixel value range defined in in rec.601:

rec.601
Y 16-235
U 16-240 (128 = the zero value)
V 16-240 (128 = the zero value)

The problem is not always possible to fix, so it’s important to understand what’s going on.

Problems

There are actually two different problems, which tend to be conflated with each other:

Problem #1: If you use Adobe After Effects CS5 to encode QuickTime H.264 video on a PC, After Effects will first modify the pixel values to boost the mid-tone brightness, by applying a gamma of (1/0.88). Each output_pixel is equal to (input_pixel) ^ 0.88. Here is the input/output transformation curve for RGB gray scale values: The maximum deviation occurs for an input value of 88, which is increased by 12 pixel values:

The value swatches below the graph show how input values are changed:

  • The top row shows the original RGB gray scale pixel swatch values
  • The bottom row shows how the original pixels are changed after the AE gamma shift.

The green line is a reference that shows no change in pixel values (Y = X). In the AE preview window, the image that you see does not reflect the gamma modification. AE does not apply this gamma boost when encoding using the QuickTime animation codec. You can’t turn off this gamma adjustment by fiddling with the settings in the After Effects File > Project Settings Window, or by using color-managed content. If you want to “undo” this gamma modification, then you need to add a filter to your video timeline in AE: use the Gamma/Pedestal/Gain filter, and set a value of 0.88 for the red, green, and blue gamma.

The situation for the QuickTime MPEG-4 codec is even worse: After Effects adds a gamma boost of 1/0.73, causing a maximum deviation of 30 pixel values for an input pixel value of 88.

Adobe Premier exhibits the same behavior when using the Adobe Media Encoder. I don’t know if Adobe products add the gamma boost when running on a Mac, or if Final Cut Pro adds a gamma adjustment.

If you encode using QuickTime Pro instead of After Effects, you don’t get this gamma modification.

Problem #2: The QuickTime player does not properly display decoded H.264 or MPEG-4 video: It lowers the contrast significantly, in order to convert from full range pixel values (0-255) to rec.601 pixel values. Threads on the internet talk about how the QuickTime player adds a “gamma shift”, but that’s mostly incorrect: there is indeed a tiny gamma shift, but the effect you see is dominated by a change in contrast. Here is the input/output transformation curve for some RGB gray scale values:

The green line is a reference that shows no change in pixel values (Y = X). The red line shows the transformation applied by the stand alone QuickTime player after decoding pixels from an H.264 bitstream. For example, a decoded value of 0 is transformed to a value of 22. The blue line shows the composite result of having both the After Effects gamma boost before encode, and the contrast shift of the QuickTime player after decode. The H.264 algorithm itself doesn’t significantly change the brightness/contrast/gamma of pixels: In areas of no detail / flat color, the H.264 algorithm changes pixel values by at most 2 pixel values out of 255 for a high quality encoder setting.

The value swatches below the graph show how input values are changed:

  • The middle row shows the original pixel swatch values
  • The top row shows how the original pixels are changed after the QuickTime player contrast shift, without the AE gamma shift.
  • The bottom row shows how the original pixel values are changed after the AE gamma shift, and the QuickTime player contrast shift.

In general, the result of this contrast shift is that your encoded H.264 video looks really washed out when viewed in the QuickTime player. It is particularly bad for rendered animation, which tends to rely on deep blacks and shadow detail.

Explanation

Why is After Effects adding a gamma boost? Who knows.

Why is the QuickTime player adding a contrast shift? It seems that after the decoding process, when converting from YUV values to RGB values, the QuickTime player selects from one of several possible YUV-RGB conversion methods, each of which may have a different transformation matrix.  Some of these matrices add the contrast shift, and some do not.  It’s not apparent how to coax the QuickTime player to use the matrix that doesn’t impose a contrast shift.

Other decoders offer a way for the user to specify whether to perform the contrast shift between the full range of decoded values (0-255) and the more limited range of values for rec.601.  Here are screen shots from ffdshow and VLC:

ffdshow

VLC

The QuickTime Player contrast shift does not happen when playing back video encoded with the QuickTime Animation Codec.

Solutions

There are several ways to trick the QuickTime player into not performing the contrast shift when displaying a decoded H.264 bitstream:

Straight Alpha (not recommended): In the QuickTime player, you can change the alpha setting of the video track to “straight alpha”. In this case, the QuickTime player assumes you are attempting to blend a foreground video track with a background, and QuickTime will disable the contrast adjustment, to facilitate accurate matching of a matte color. To set the alpha to straight, select Window > Show Movie Properties, then click on the Video Track line item in the top list, then in the tabbed panel on the bottom, click on the Visual Settings tab. Then for the Transparency item, chose Straight Alpha from the drop-down menu. Now close the properties window and save your .mov file using File > Save. However, this method is not a good approach. Setting the alpha in this way forces QuickTime to consume a lot more CPU cycles to play the video: Even without another video track in the background, QuickTime is probably doing an extra multiply for every single pixel. For small video dimensions, like 480×360, on a fast machine, you won’t notice a difference; but for larger video dimensions, or on a slower machine, you will get jittery playback because the QuickTime player will run out of CPU cycles and start dropping frames. So, not really a solution.  Bear in mind that this hack does not undo the gamma adjustment applied by After Effects.

X264 option on the Mac (great if you have a Mac). If you have a Mac, then you’re in luck.  People running QuickTime Pro on a Mac report that there is a definitive solution that doesn’t require hacks. Takashi Mochizuki has created an open source H.264 encoder inside a QuickTime codec wrapper.  You an use this encoder instead of the default Apple codec:

http://byteful.com/blog/2010/07/how-to-fix-the-h264-gamma-brightness-bug-in-quicktime/

When playing back an H.264 bitstream generated by this encoder, the QuickTime player will not perform the contrast shift.  This codec uses the x264 codec along with some functionality of FFmpeg, but unlike FFmpeg, it uses the ICM OS X libraries to create the .mov container.  One of the key aspects of this codec is that it allows you to set color profile tags and gamma tags in the .mov file.

X264 option on the PC (Does not exist yet) If you are on a PC, you are out of luck: the above mentioned codec wrapper is not available for Windows. But it’s not for lack of trying.  I tried using the FFmpeg utility with the libx264 codec to create .mov files, and it doesn’t solve the problem.  I also tried modifying the color profile information that is embedded in the H.264 bitstream; no luck.  Then I recompiled the FFmpeg utility, and modified the source code to add color profile tags and gamma tags to the .mov container file.  But sadly, no combination of these modifications caused the QuickTime player to display the video correctly.  I suspect that the reason the Mac-based codec works is because the OS X SDK that creates the .mov container is probably doing something different than the corresponding functionality in FFmpeg.

The TIFF hack: You can add a secondary video track, consisting of a small TIFF image, and place this new track below your main video track so that it remains invisible. Adding this new track causes QuickTime to slightly change it’s behavior: it will partially restore the original contrast: without the TIFF hack, a decoded pixel with a value of 0 will display as 22: with the TIFF hack, it gets 27% of the way to the correct value of 0, and displays with a value of 16. So the TIFF hack is a “1/3 solution” at best. Not recommended. But in case you want to try it: Create a small TIFF image, with a size of 32×32. Open the TIFF image in QuickTime. Do Edit > Copy. Then open your video file in QuickTime, and do Edit > Add to Selection and Scale. The TIFF image will appear on top of your video track. Then move the video track below your main video stream: Do Window > Show Movie Properties, then click on the Video Track containing the TIFF image in the top list, then in the tabbed panel on the bottom, click on the Visual Settings tab. Then for the Layer value, increase the value to push the TIFF track under your main video track. Now close the properties window and save your .mov file using File > Save.

Gamma tag strippers: There are various utilities on the net that claim to strip out a “gamma tag” in a QuickTime bitstream. Supposedly, when the gamma tag is removed, the QuickTime player won’t perform the gamma/contrast shift. But these gamma strippers don’t seem to work, at least when playing the video on a PC.

Result matrix

If also considering the popular MPEG-4 codec, and various players (VLC, MPC, Firefox QuickTime Plugin), then the gamma and/or contrast change that you see depends on which combination you are using:

  • Whether you encode using After Effects or QuickTime Pro
  • Whether you use the QuickTime H.264 codec or the QuickTime MPEG-4 codec
  • Which player is used to view the video: QuickTime player (with or without the straight alpha fix), MPC, VLC, or the Firefox QuickTime plugin
  • Further, how VLC is configured is important: in the preferences, under Video, you can specify the output renderer, and whether hardware acceleration is enabled.  You can specify a default or GDI renderer.

The results vary widely:

Encoding MPEG-4 using QuickTime Pro
Player Result
Firefox gamma boost: Y = X^0.88
MPC increased contrast
VLC: default + HW accel correct display
QuickTime, straight alpha fix gamma boost: Y = X^0.88
QuickTime, no straight alpha fix contrast + gamma adjustment
Encoding MPEG-4 using After Effects
Player Result
Firefox gamma boost: Y = X^0.73
MPC increased contrast
VLC gamma boost: Y = X^0.82
QuickTime, straight alpha fix gamma boost: Y = X^0.73
QuickTime, no straight alpha fix contrast + gamma adjustment
Encoding H.264 using QuickTime Pro
Player Result
Firefox correct display
MPC slightly increased contrast; very close
VLC contrast + gamma adjustment
QuickTime, straight alpha fix correct display
QuickTime, no straight alpha fix contrast + gamma adjustment
Encoding H.264 using After Effects
Player Result
Firefox gamma boost: Y = X^0.88
MPC correct display
VLC: GDI correct display
QuickTime, straight alpha fix gamma boost: Y = X^0.88
QuickTime, no straight alpha fix contrast + gamma adjustment

Summary

On the Mac, just use the open source x264 codec.  However, I have not personally verified that using this codec solves the problem 100%: it might provide only a half-solution, similar to the TIFF hack.

On the PC, depending on your needs, it might be worth it to buy a cheap Mac, for the purpose of using the Mac-based X.264 codec wrapper, to generate .mov files that don’t have the contrast shift.  You can buy a used Mac Mini from eBay for about $500.

But if you still encode on a PC, using the QuickTime MPEG-4 or H.264 encoders, there are a limited combination of authoring tools / codecs / players that allow correct playback of video, without gamma shift or contrast adjustment.

Posted in gamma | Tagged , , , | 25 Comments