我有一个yuv420p像素格式的视频。 最初,我尝试使用管道和像素格式(如rgb24)读取每个帧的字节。我用PIL制作图像。 但是,以rgb24格式读取的帧似乎失去了一点质量。
以下是读取具有rgb24像素格式的帧的命令:
ffmpeg -y -i input.mp4 -vcodec rawvideo -pix_fmt rgb24 -an -r 25 -f rawvideo pipe:1
frame_data = self.process.stdout.read(1920*1080*3)
然后我尝试以yuv420p像素格式阅读它。
ffmpeg -y -i input.mp4 -vcodec rawvideo -pix_fmt yuv420p -an -r 25 -f rawvideo pipe:1
frame_data = self.process.stdout.read(1920*1080*3/2)
一个单帧包含rgb24帧的一半字节。在1920 * 1080 yuv420p帧中为3110400字节。我把这些数据扔进了PIL:
Image.frombytes('YCbCr', (1920, 1080), frame_data)
但是PIL会引发图像数据不足的错误。 我查找了PIL支持从字节写入的模式,它们都不是12位像素。 我还尝试将yuv数据转换为rgb数据,但是要花很长的时间才能处理,所以花了比以前更多的时间。
我做错什么了吗?有什么办法可以在没有任何变换的情况下用原始的yuv数据写入图像?
答案 0 :(得分:1)
您的 YUV420p 是色度子采样和 “平面”。二次采样意味着 U 和 V 通道各是全分辨率 Y 通道宽度的一半和高度的一半。因此,它们每个都是正常大小的 1/4。所以,因为它是平面的,你实际上会收到:
这意味着。相对于 RGB 图像,您将有 1 个完整的通道和 2 个四分之一大小的通道,即 1.5 个通道,这是拥有 3 个完整 RGB 通道时的一半……这就是为什么它需要每像素 12 位而不是超过 24 位。
PIL 自然不支持子采样色度。因此,为了读取您的数据,您可以:
L
模式图像L
模式图像,并将大小调整为两倍L
模式图像,并将大小调整为两倍然后将这三个单通道图像合并为三通道图像。
我不清楚您为什么要使用 PIL
。如果您只想将未经处理的原始 YUV420p 流写入磁盘,请让 ffmpeg
自行完成。