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 fixes the scaling:
from av.video.reformatter import ColorRange
rgb = frame.to_ndarray(format='rgb24', src_color_range=ColorRange.MPEG) # works
rgb = frame.to_ndarray(format='rgb24', dst_color_range=ColorRange.MPEG) # works, too
Reproduction
To create a video with yuv444p full-range I used the following command
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
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:
https://github.com/PyAV-Org/PyAV/assets/12171321/3a934bab-5c78-4286-82fb-9b8a94edf54b
Versions
Research
I have done the following:
Additional context
Related Issue#1378