[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.
http://www.chrisnology.info/videos/Scope%20shot1.JPG
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.
http://www.chrisnology.info/videos/Scope%20shot2.JPG
Here is a waveform shot with all luminance components forced to digital
110.
http://www.chrisnology.info/videos/Scope%20shot3.JPG
Below, all luminance components forced to digital 180. As we can see, the
video levels are actually slightly higher than 180.
http://www.chrisnology.info/videos/Scope%20shot4.JPG
In the next scope display, all luminance components have been forced to
digital 235.
http://www.chrisnology.info/videos/Scope%20shot2.JPG
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