[FFmpeg-trac] #9407(ffmpeg:reopened): Broken Conversion: yuv444p10le to yuv444p

FFmpeg trac at avcodec.org
Mon Sep 6 02:27:44 EEST 2021


#9407: Broken Conversion: yuv444p10le to yuv444p
-------------------------------------+-------------------------------------
             Reporter:  Michael      |                    Owner:  (none)
  Witten                             |
                 Type:  defect       |                   Status:  reopened
             Priority:  normal       |                Component:  ffmpeg
              Version:  unspecified  |               Resolution:
             Keywords:  pix_fmt yuv  |               Blocked By:
  yuv444p10le yuv444p 10-bit format  |
             Blocking:               |  Reproduced by developer:  0
Analyzed by developer:  0            |
-------------------------------------+-------------------------------------
Changes (by Michael Witten):

 * status:  closed => reopened
 * resolution:  invalid =>

Comment:

 Thank you, ''pdr0'', for ''your'' explanation.

 {{{#!html
 <ul>
   <li>
     <p><b>NOT THE PROBLEM IN QUESTION:</b></p>
     <ul>
       <li><p>The issues with "<span style="font-family:monospace; font-
 size:90%">color_range</span>" are incidental, and they probably require
 their own tickets.</p></li>
       <li><p>I believe that I have been handling the "<span style="font-
 family:monospace; font-size:90%">color_range</span>" correctly (<a
 href="#color_range-0" style="font-weight:bold;
 color:#0000e0">see below</a>).</p></li>
       <li><p>Your examples, however, do not handle the "<span style="font-
 family:monospace; font-size:90%">color_range</span>" correctly (<a
 href="#color_range-1" style="font-weight:bold;
 color:#0000e0">see below</a>).</p></li>
       <li><p>I can see now that my attempt to control the color space is
 also broken, which probably requires its own ticket (<a href="#setparams-
 fail" style="font-weight:bold;
 color:#0000e0">see below</a>).</p></li>
     </ul>
   </li>
   <li>
     <p><b>THE ACTUAL PROBLEM:</b></p>
     <ul>
       <li><p>The conversion from "<b style="font-family:monospace; font-
 size:90%">yuv444p10le</b>" to "<b style="font-family:monospace; font-
 size:90%">yuv444p</b>" produces <a href="#multiple-colors" style="font-
 weight:bold; color:#0000e0">multiple</a> colors rather than just
 one.</p></li>
       <li><p>Perhaps this is some kind of forced dithering problem, as
 hinted by <i>Balling</i>'s find on issue <a class="open ticket"
 href="/ticket/3345" title="#3345: defect: Bias in planar YUV to YUV bit
 depth conversion (open)">#3345</a>, where the workaround is indeed to
 convert to something else (<i>e.g.,</i> "<b style="font-family:monospace;
 font-size:90%">rgb24</b>") as an intermediary pixel format between "<i
 style="font-family:monospace; font-size:90%">yuv444p10le</i>" and "<i
 style="font-family:monospace; font-size:90%">yuv444p</i>".</p></li>
       <li><p>My own videos brought this issue to my attention, and what I
 noticed was a change in exposure akin to applying the wrong transfer
 function; maybe this is still the result of some kind of dithering, but I
 would not be surprised if there are other issues at play as well, which is
 why I was trying to control all that metadata.</p></li>
     </ul>
   </li>
   <li><p>All of this confusion is why it is unwise to close a report or
 mark it as "invalid" when the very <em>author</em> of that report is
 <em>still</em> here to discuss it; otherwise, you are just introducing
 overhead and aggravation for all parties involved.</p></li>
 </ul>
 }}}

 = "`color_range`" [=#color_range-0] =

 My example attempted to be (and I believe it did indeed succeeded in
 being) very careful with "`color_range`"; the following sprinkles
 "`showinfo`" around, in order to prove this:

 {{{
 #!/bin/bash

 bad_output=04-rbg24-to-yuv444p10le-to-yuv444p-to-rgb24.png

 args=(
   -hide_banner
   -loglevel verbose

   -f lavfi -i '
     color=0x7FFFD4:size=480x270, format=rgb24,    showinfo,
       setparams=prog:pc:bt709:iec61966-2-1:bt709, showinfo
   '

   -vf '
     showinfo, scale=out_range=pc, showinfo, format=yuv444p10le, showinfo,
     showinfo, scale=out_range=pc, showinfo, format=yuv444p,     showinfo,
     showinfo, scale=out_range=pc, showinfo, format=rgb24,       showinfo
   '

   -frames 1

   -y "$bad_output"
 )

 ffmpeg "${args[@]}" |& grep -o 'color_range:.*' |
   grep --color=always 'color_range:[^ ]\{1,\}'
 }}}

 Here is the output: [=#setparams-fail]

 {{{#!html
 <pre class="wiki literal-block">
   <strong style="color:#f00">color_range:unknown</strong>
 color_space:unknown color_primaries:unknown color_trc:unknown
   <strong style="color:#f00">color_range:pc</strong> color_space:bt709
 color_primaries:bt709 color_trc:iec61966-2-1
   <strong style="color:#f00">color_range:unknown</strong>
 color_space:unknown color_primaries:unknown color_trc:unknown
   <strong style="color:#f00">color_range:pc</strong> color_space:unknown
 color_primaries:unknown color_trc:unknown
   <strong style="color:#f00">color_range:pc</strong> color_space:unknown
 color_primaries:unknown color_trc:unknown
   <strong style="color:#f00">color_range:pc</strong> color_space:unknown
 color_primaries:unknown color_trc:unknown
   <strong style="color:#f00">color_range:pc</strong> color_space:unknown
 color_primaries:unknown color_trc:unknown
   <strong style="color:#f00">color_range:pc</strong> color_space:unknown
 color_primaries:unknown color_trc:unknown
   <strong style="color:#f00">color_range:pc</strong> color_space:unknown
 color_primaries:unknown color_trc:unknown
   <strong style="color:#f00">color_range:pc</strong> color_space:unknown
 color_primaries:unknown color_trc:unknown
   <strong style="color:#f00">color_range:pc</strong> color_space:unknown
 color_primaries:unknown color_trc:unknown
 </pre>
 }}}

 As you can see:

 * Where it ''matters'', my "`color_range`" metadata is correct.

 * The "`setparams`" filter works correctly inside my "`lavfi`" input.

 * However, all the info from "`setparams`" is thrown out when the
 "`lavfi`" input is pumped into my filter graph; clearly this is a bug.

 * ''Nevertheless'', to state it again, the "`color_range`" metadata is
 correct where it matters.

 Please note that your own "good" example does not maintain "`color_range`"
 metadata correctly: [=#color_range-1]

 {{{
 #!/bin/bash

 your_example=(
   # 'showinfo' has been sprinkled about, and '-y' added:
   ffmpeg -f lavfi -i color=0x7FFFD4:size=480x270 -vf
 showinfo,scale=out_range=pc:out_color_matrix=bt709,format=yuv444p10le,showinfo,format=yuv444p,showinfo,scale=in_range=pc:in_color_matrix=bt709,format=rgb24,showinfo
 -frames:v 1 -y right.png
 )

 "${your_example[@]}" |& grep -o 'color_range:.*' |
   grep --color=always 'color_range:[^ ]\{1,\}'
 }}}

 Here is what your example is doing:

 {{{#!html
 <pre class="wiki literal-block">
   <strong style="color:#f00">color_range:unknown</strong>
 color_space:unknown color_primaries:unknown color_trc:unknown
   <strong style="color:#f00">color_range:pc</strong> color_space:unknown
 color_primaries:unknown color_trc:unknown
   <strong style="color:#f00">color_range:tv</strong> color_space:unknown
 color_primaries:unknown color_trc:unknown
   <strong style="color:#f00">color_range:tv</strong> color_space:unknown
 color_primaries:unknown color_trc:unknown
 </pre>
 }}}

 As you can see:

 * Your "`lavfi`" input has unknown metadata, as expected.

 * Your filter graph immediately sets "`color_range`" to "`pc`", as
 desired.

 * On the conversion from "**`yuv444p10le`**" to "**`yuv444p`**",
 "`out_range`" is set to "`tv`"! This happens because an
 **''auto_scaler''** is inserted, which by ''default'' sets
 "`out_range=tv`"; that is why I was always explicitly creating the scaler:
   {{{
   scale=out_range=pc
   }}}
   You can see this by changing the above example slightly:
   {{{
   #!/bin/bash

   your_example=(
     # Added '-loglevel verbose' and '-y':
     ffmpeg -loglevel verbose -f lavfi -i color=0x7FFFD4:size=480x270 -vf
 scale=out_range=pc:out_color_matrix=bt709,format=yuv444p10le,format=yuv444p,scale=in_range=pc:in_color_matrix=bt709,format=rgb24
 -frames:v 1 -y right.png
   )

   "${your_example[@]}" |& grep --color=always 'auto_scaler[^ ]\{1,\}'
   }}}
   Here is the output:
   {{{#!html
   <pre class="wiki literal-block">
     [<strong style="color:#f00">auto_scaler_0</strong> @ 0x7b0940] w:iw
 h:ih flags:'bicubic' interl:0
     [Parsed_format_2 @ 0x7ab5c0] auto-inserting filter '<strong
 style="color:#f00">auto_scaler_0</strong>' between the filter
 'Parsed_format_1' and the filter 'Parsed_format_2'
     [<strong style="color:#f00">auto_scaler_0</strong> @ 0x7b0940] w:480
 h:270 fmt:yuv444p10le sar:1/1 -> w:480 h:270 fmt:yuv444p sar:1/1 flags:0x4
   </pre>
   }}}

 = Color Metadata =

 {{{#!html
 <p>As shown <a href="#setparams-fail" style="font-weight:bold;
 color:#0000e0">above</a> (and as noted by <i>Balling</i>), the metadata
 specified by "<span style="font-family:monospace; font-
 size:90%">setparams</span>" in the "<span style="font-family:monospace;
 font-size:90%">lavfi</span>" input is just thrown out upon injection of
 the frames into the main filter graph; clearly, this is a bug all on its
 own.</p>
 }}}

 = **''THE ACTUAL PROBLEM''** =

 1. Here is the original data; there is one color:
   {{{
   $ f=01-rgb24.png
   $ identify -verbose "$f" | sed -n '/Colors:/,/Gamma:/s/^  //p'
   Colors: 1
   Histogram:
     129600: (127,255,212) #7FFFD4 aquamarine
   Rendering intent: Perceptual
   Gamma: 0.454545
   }}}

 2. Here is the data, after experiencing conversion to "**`yuv444p10le`**"
 (it's the same as the original):
   {{{
   $ f=03-rbg24-to-yuv444p10le-to-rgb24.png
   $ identify -verbose "$f" | sed -n '/Colors:/,/Gamma:/s/^  //p'
   Colors: 1
   Histogram:
     129600: (127,255,212) #7FFFD4 aquamarine
   Rendering intent: Perceptual
   Gamma: 0.454545
   }}}

 3. Here is the data, after experiencing conversion to "**`yuv444p`**"
 (it's imperceptibly lossy; 1 color, where the red component is 126 rather
 than 127):
   {{{
   $ f=02-rbg24-to-yuv444p-to-rgb24.png
   $ identify -verbose "$f" | sed -n '/Colors:/,/Gamma:/s/^  //p'
   Colors: 1
   Histogram:
     129600: (126,255,212) #7EFFD4 srgb(126,255,212)
   Rendering intent: Perceptual
   Gamma: 0.454545
   }}}

 4. As shown in the initial description, the conversion from
 "**`yuv444p10le`**" to "**`yuv444p`**" produces not only perceptibly bad
 results (I think a transfer function issue), but also 4 different colors
 (maybe a dithering issue): [=#multiple-colors]
   {{{
   $ f=04-rbg24-to-yuv444p10le-to-yuv444p-to-rgb24.png
   $ identify -verbose "$f" | sed -n '/Colors:/,/Gamma:/s/^  //p'
   Colors: 4
   Histogram:
     2040: (130,255,225) #82FFE1 srgb(130,255,225)
     8100: (130,255,227) #82FFE3 srgb(130,255,227)
     105240: (131,255,228) #83FFE4 srgb(131,255,228)
     14220: (133,255,228) #85FFE4 srgb(133,255,228)
   Rendering intent: Perceptual
   Gamma: 0.454545
   }}}

 5. However, using "**`rgb24`**" as an intermediate pixel format basically
 solves that problem (the results are the same as in "3." above):
   {{{
   $ f=05-rbg24-to-yuv444p10le-to-rgb24-to-yuv444p-to-rgb24.png
   $ identify -verbose "$f" | sed -n '/Colors:/,/Gamma:/s/^  //p'
   Colors: 1
   Histogram:
     129600: (126,255,212) #7EFFD4 srgb(126,255,212)
   Rendering intent: Perceptual
   Gamma: 0.454545
   }}}

 In short, the conversion from "**`yuv444p10le`**" to "**`yuv444p`**" is
 broken.
-- 
Ticket URL: <https://trac.ffmpeg.org/ticket/9407#comment:7>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker


More information about the FFmpeg-trac mailing list