Opened 4 weeks ago

Closed 7 days ago

Last modified 7 days ago

#6924 closed defect (invalid)

ffmpeg Video Levels

Reported by: chris319 Owned by:
Priority: normal Component: undetermined
Version: unspecified Keywords:
Cc: Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no


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 BT.709.
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 110.

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.

Change History (6)

comment:1 Changed 4 weeks ago by cehoyos

  • Component changed from avcodec to undetermined

Please provide the FFmpeg command line you tested together with the complete, uncut console output on stderr and the used input file to make this a valid ticket.

Last edited 4 weeks ago by cehoyos (previous) (diff)

comment:2 Changed 4 weeks ago by richardpl

  • Resolution set to invalid
  • Status changed from new to closed

If you wish to limit pixels like that use -vf scale=in_range=pc:out_range=tv
Otherwise, command will do nothing.

BTW ffmpeg have its own waveform filter.
If you just want to clamp pixels, use lut or limiter filter.

comment:3 Changed 7 days ago by chris319

  • Resolution invalid deleted
  • Status changed from closed to reopened

Here is the command line which converts the video to TV levels:

bin\ffmpeg -i "D:\Videos\KodakChart?.MP4" -y -vf "scale=in_range=pc:out_range=tv" -c:a copy output.mp4

As you can see there are still excursions above 235. The video is not being clipped to 235.

comment:4 Changed 7 days ago by kierank

So do what the previous poster says and clamp using a downstream filter. All processes might produce excursions outside TV range, that's the entire point of TV range. And modern practice is actually to leave the odd excursion in as described here:

comment:5 Changed 7 days ago by richardpl

  • Resolution set to wontfix
  • Status changed from reopened to closed

There is nothing to fix.

comment:6 Changed 7 days ago by cehoyos

  • Resolution changed from wontfix to invalid
Note: See TracTickets for help on using tickets.