如何使用FFmpeg将YUV420格式视频文件转换为16位?
解决12位YUV转16位的方法
一、FFmpeg正确命令
你的原命令无效的原因有三个:
-sample_fmt s16是音频采样格式参数,对视频完全不起作用;- 输入像素格式指定错误:你用了8位的
yuv420p,但实际输入是12位YUV,必须指定对应的12位格式(比如yuv420p12le小端、yuv420p12be大端); - 缺少
-f rawvideo参数,FFmpeg无法识别输入是原始无封装的YUV流。
正确命令示例
假设你的输入是小端12位YUV420(最常见的12位格式),执行:
ffmpeg -f rawvideo -video_size 352x288 -pixel_format yuv420p12le -i input.yuv -pixel_format yuv420p16le output.yuv
如果输入是大端格式,把yuv420p12le换成yuv420p12be即可;输出的16位格式也可以换成yuv422p16le等其他16位YUV格式,只要把命令里的-pixel_format对应参数替换就行。
执行后你会发现输出文件大小明显变大:原20帧12位YUV420的大小是352*288*1.5*12/8*20=4561920字节,转成16位YUV420后大小是352*288*1.5*2*20=6082560字节,以此验证转换成功。
二、Python手动转换(适合小文件)
因为你的视频只有20帧,规模很小,可以直接读取原始二进制数据,将每个12位像素值扩展为16位(左移4位填充高位0,保证数据精度),再按16位YUV格式写入。
以下是针对打包式12位YUV420(每3字节存储2个12位像素)的示例代码:
import os # 基础配置 WIDTH = 352 HEIGHT = 288 FRAME_COUNT = 20 # 计算各分量的字节数 INPUT_FRAME_SIZE = WIDTH * HEIGHT * 9 // 4 # 12位YUV420每帧总字节数 OUTPUT_FRAME_SIZE = WIDTH * HEIGHT * 3 # 16位YUV420每帧总字节数 def convert_12bit_to_16bit(raw_data): """将打包的12位像素数据转成16位小端格式""" output = bytearray() # 每3字节处理2个12位像素 for i in range(0, len(raw_data), 3): # 第一个像素:低8位+高4位,左移4位补0到16位 pix1 = (raw_data[i] | ((raw_data[i+1] & 0x0F) << 8)) << 4 # 第二个像素:低8位+高4位,左移4位补0到16位 pix2 = (raw_data[i+2] | ((raw_data[i+1] >> 4) << 8)) << 4 # 按小端写入16位数据 output.extend([pix1 & 0xFF, (pix1 >> 8) & 0xFF]) output.extend([pix2 & 0xFF, (pix2 >> 8) & 0xFF]) return output with open("input.yuv", "rb") as f_in, open("output.yuv", "wb") as f_out: for _ in range(FRAME_COUNT): frame = f_in.read(INPUT_FRAME_SIZE) if not frame: break # 拆分Y、U、V分量 y_len = WIDTH * HEIGHT * 3 // 2 # Y分量字节数 u_len = WIDTH * HEIGHT * 3 // 8 # U分量字节数 v_len = u_len y_data = frame[:y_len] u_data = frame[y_len:y_len+u_len] v_data = frame[y_len+u_len:] # 转换各分量并写入 f_out.write(convert_12bit_to_16bit(y_data)) f_out.write(convert_12bit_to_16bit(u_data)) f_out.write(convert_12bit_to_16bit(v_data))
如果你的输入是平面式12位YUV(每个分量单独存储,每个像素用2字节存12位数据),只需要修改convert_12bit_to_16bit函数,直接读取每个2字节的12位值,左移4位后写入即可。
内容的提问来源于stack exchange,提问作者IanMurphy
相关产品推荐
相关产品推荐

