You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When decoding a full-range yuv444p video stream and converting to RGB like so
import av
from PIL import Image
with open(video_path, 'rb') as file:
with av.open(file) as container:
for pack in container.demux(0):
for frame in pack.decode():
rgb = frame.to_ndarray(format='rgb24')
Image.fromarray(rgb, mode='RGB').show()
I found that the resulting images are different than what I get when extracting images with ffmpeg:
ffmpeg -I video.mov video%06d.png
Expected behavior
The expected behaviour is that the resulting RGB is very close to what is generated by running the above ffmpeg command. For other formats (e.g. limited range yuv420p) this is the case.
Actual behavior
The actual behaviour is that the images differ significantly. It seems like the RGB created with PyAV is scaled incorrectly, using more range than the reference:
import matplotlib.pyplot as plt
plt.figure()
plt.scatter(rgb_ffmpeg[::10, ::10, :].ravel(), rgb_pyav[::10, ::10, :].ravel(), s=1, marker='.')
plt.xlabel('RGB from ffmpeg')
plt.ylabel('RGB from pyav')
Investigation
I found that specifying the src_color_range (or dst_color_range until av 12.0.0) fixes the scaling:
from av.video.reformatter import ColorRange
rgb = frame.to_ndarray(format='rgb24') # does not work in either 12.0.0 or 12.1.0
rgb = frame.to_ndarray(format='rgb24', src_color_range=ColorRange.MPEG) # works in 12.0.0 and 12.1.0
rgb = frame.to_ndarray(format='rgb24', dst_color_range=ColorRange.MPEG) # works in 12.0.0 but not in 12.1.0
Reproduction
To create a video with yuv444p full-range I used the following command
I don't think this is possible to fix in the general case because nobody has actually bothered to specify what frame.to_ndarray should actually do and which properties are most important.
Even if the behaviour isn't formally specified: the minimal assumption that PyAV users have is that the default behaviour is matching that of ffmpeg. The src_color_range and dst_color_range parameters of frame.to_ndarray behave in wrong/unexpected ways. IMHO this is an obvious bug and the reference behaviour is well defined (which is: to match ffmpeg). I propose to leave this bug open.
Overview
When decoding a full-range yuv444p video stream and converting to RGB like so
I found that the resulting images are different than what I get when extracting images with ffmpeg:
Expected behavior
The expected behaviour is that the resulting RGB is very close to what is generated by running the above ffmpeg command. For other formats (e.g. limited range yuv420p) this is the case.
Actual behavior
The actual behaviour is that the images differ significantly. It seems like the RGB created with PyAV is scaled incorrectly, using more range than the reference:
Investigation
I found that specifying the
src_color_range
(ordst_color_range
until av 12.0.0) fixes the scaling:Reproduction
To create a video with yuv444p full-range I used the following command
This is the video that I tested with:
yuv444p_full_range.mov
Versions
Research
I have done the following:
Additional context
Related Issue#1378
The text was updated successfully, but these errors were encountered: