[FFmpeg-trac] #6924(avcodec:new): ffmpeg Video Levels

FFmpeg trac at avcodec.org
Thu Dec 21 03:39:49 EET 2017

#6924: ffmpeg Video Levels
             Reporter:  chris319  |                     Type:  defect
               Status:  new       |                 Priority:  normal
            Component:  avcodec   |                  Version:  unspecified
             Keywords:            |               Blocked By:
             Blocking:            |  Reproduced by developer:  0
Analyzed by developer:  0         |
 This is a lengthy post.

 I have been doing quite a bit of work with video levels and have some
 concerns regarding ffmpeg.

 I have documented these concerns using a waveform monitor program. The x
 axis of the waveform monitor corresponds to the x axis of the image. The
 values on y axis under the "DIG" column represent all of the pixel
 intensities at a given x coordinate. The range is 0 - 255. Here is how the
 unaltered video of a Kodak Gray Card Plus appears. The video was taken
 with a Canon Vixia HF R800.


 Note that there is no chrominance information in the right-hand 2/3 of the
 chart. I use a C-language program to read a single frame of video from the
 mp4 file and place the samples into an array. The C program creates input
 and output pipes to ffmpeg which is used to read and write a frame of
 video. Here is the code used to read a frame of video into ffmpeg, showing
 the command line ffmpeg receives:

 FILE *pipein = popen("ffmpeg -i KodakChart.mp4 -f image2pipe -vcodec
 rawvideo  -pix_fmt yuv420p -", "r");

 Here is the code used to write a video frame to ffmpeg, also showing the
 ffmpeg command line:

 FILE *pipeout = popen("ffmpeg -y -f rawvideo -vcodec rawvideo -pix_fmt
 yuv420p  -s 1280x720 -r 29.97 -i - -f mp4 -q:v 5  -vf scale=out_range=tv
 cliptest.mp4", "w");

 Once the YUV samples are in the array, I use the C code below to force the
 luminance component of all pixels to a specific value. In the example
 below, 235 is chosen, as this is the maximum video level specified in ITU
 for (y=0; y<H ; y++)
 for (x=0; x<W ; x++)
 lum[y*W+x] = 235;

 Below are several waveform shots of video levels at various vales.

 In the first waveform shot, all luminance components have been forced to
 digital 255.


 Here is a waveform shot with all luminance components forced to digital


 Below, all luminance components forced to digital 180. As we can see, the
 video levels are actually slightly higher than 180.


 In the next scope display, all luminance components have been forced to
 digital 235.


  This scope display is especially noteworthy because the video levels
 reach 255 despite having been forced to 235.

 It is possible to force the luminance component to a specific value by
 reading and writing a frame of video using ffmpeg. The example which shows
 luma forced to 110 works fairly well. As we increase the video level,
 ffmpeg is applying gain to the levels. Finally, when luma is forced to
 235, ffmpeg is boosting the levels to 255. Note that the code for the
 output pipe contains the following video filter:

 -vf scale=out_range=tv

 It appears that this filter is not functioning as documented, i.e. it is
 not confining the output to the range of 16 - 235. This could be
 problematic if a user needs 16 - 235 output. For example, the U.S.
 broadcast TV station I work for would never broadcast any of the examples
 shown in this post having video levels above digital 235.

Ticket URL: <https://trac.ffmpeg.org/ticket/6924>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker

More information about the FFmpeg-trac mailing list