音视频-色域
1. 色域相关
1.1 python测试视频生成
import os
import subprocess
import argparse
import json
COLOR_PROFILES = {"bt601": {"ffmpeg": {"colorspace": "5","color_primaries": "5","color_trc": "6", },"x264-params": "colorprim=bt601:transfer=smpte170m:colormatrix=bt601","x265-params": "colorprim=bt601:transfer=smpte170m:colormatrix=bt601",},"bt709": {"ffmpeg": {"colorspace": "1","color_primaries": "1","color_trc": "1",},"x264-params": "colorprim=bt709:transfer=bt709:colormatrix=bt709","x265-params": "colorprim=bt709:transfer=bt709:colormatrix=bt709",},"bt2020": {"ffmpeg": {"colorspace": "9","color_primaries": "9","color_trc": "16", },"x265-params": "colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc",},
}
HDR_PROFILES = {"hdr10": {"x265": (":master-display=""G(13250,34500)B(7500,3000)R(34000,16000)""WP(15635,16450)L(10000000,1)"":max-cll=1000,400")},"hlg": {"x265": ":transfer=arib-std-b67" },
}def probe_video(video_path):"""使用 ffprobe 获取视频流信息"""if not os.path.exists(video_path):return {"error": "文件不存在"}cmd = ["ffprobe","-v", "quiet","-print_format", "json","-show_streams","-show_format",video_path]result = subprocess.run(cmd, capture_output=True, text=True)if result.returncode != 0:return {"error": result.stderr}info = json.loads(result.stdout)video_stream = next((s for s in info.get("streams", []) if s.get("codec_type") == "video"), None)if not video_stream:return {"error": "未找到视频流"}fps = eval(video_stream.get("r_frame_rate", "0/1"))return {"codec": video_stream.get("codec_name"),"pix_fmt": video_stream.get("pix_fmt"),"width": video_stream.get("width"),"height": video_stream.get("height"),"color_range": video_stream.get("color_range", "unknown"),"color_space": video_stream.get("color_space", "unknown"),"color_primaries": video_stream.get("color_primaries", "unknown"),"color_trc": video_stream.get("color_transfer", "unknown"),"fps": fps,}def generate_videos(profile, color_range, bit_depth, out_dir, hdr="off"):os.makedirs(out_dir, exist_ok=True)profiles = [profile] if profile != "all" else list(COLOR_PROFILES.keys())ranges = [color_range] if color_range != "all" else ["tv", "pc"]bits = [bit_depth] if bit_depth != "all" else ["8bit", "10bit"]if hdr == "all":hdrs = ["off"] + list(HDR_PROFILES.keys())else:hdrs = [hdr]results = []for p in profiles:for r in ranges:for b in bits:for h in hdrs:ffmpeg_args = []if b == "8bit":pix_fmt = "yuv420p"encoder = "libx264" if p != "bt2020" else "libx265"else: pix_fmt = "yuv420p10le"encoder = "libx265"filename = f"{p}_{r}_{b}"if h != "off":filename += f"_{h}"filename += "_1080p.mp4"filepath = os.path.join(out_dir, filename)ffmpeg_args += ["-pix_fmt", pix_fmt,"-colorspace", COLOR_PROFILES[p]["ffmpeg"]["colorspace"],"-color_primaries", COLOR_PROFILES[p]["ffmpeg"]["color_primaries"],"-color_trc", COLOR_PROFILES[p]["ffmpeg"]["color_trc"],"-color_range", "1" if r == "tv" else "2",]if encoder == "libx264":ffmpeg_args += ["-x264-params", COLOR_PROFILES[p]["x264-params"]]else:x265_params = COLOR_PROFILES[p]["x265-params"]if h in HDR_PROFILES and "x265" in HDR_PROFILES[h]:x265_params += HDR_PROFILES[h]["x265"]ffmpeg_args += ["-x265-params", x265_params]ffmpeg_cmd = ["ffmpeg","-f", "lavfi","-i", "testsrc=duration=10:size=1920x1080:rate=25","-c:v", encoder,"-crf", "23","-preset", "medium",*ffmpeg_args,filepath,]print(f"\n生成视频: {filepath}")try:subprocess.run(ffmpeg_cmd, check=True, capture_output=True)info = probe_video(filepath)results.append((True, filepath, info))print("视频流信息:", info)except subprocess.CalledProcessError as e:results.append((False, filepath, {"error": e.stderr.decode()}))print(f"生成失败: {filepath}\n", e.stderr.decode())return resultsif __name__ == "__main__":parser = argparse.ArgumentParser(description="生成不同色域/位深/HDR 的视频测试文件")parser.add_argument("--profile", default="all", choices=["all"] + list(COLOR_PROFILES.keys()),help="色域 (bt601, bt709, bt2020, all)")parser.add_argument("--range", default="all", choices=["all", "tv", "pc"],help="范围 (tv, pc, all)")parser.add_argument("--bit", default="all", choices=["all", "8bit", "10bit"],help="位深 (8bit, 10bit, all)")parser.add_argument("--hdr", default="off", choices=["off", "all"] + list(HDR_PROFILES.keys()),help="HDR 设置 (off, hdr10, hlg, all)")parser.add_argument("--out", default="output_videos", help="输出目录")args = parser.parse_args()results = generate_videos(args.profile, args.range, args.bit, args.out, args.hdr)print("\n=== 生成结果汇总 ===")for success, filepath, info in results:status = "成功" if success else "失败"print(f"{status}: {filepath}")print(f" 信息: {info}")
1.2 测试视频生成
ffmpeg -f lavfi -i testsrc=duration=10:size=1920x1080:rate=25 -pix_fmt yuv420p -colorspace 5 -color_primaries 5 -color_trc 2 -color_range 1 -c:v libx264 -x264-params colorprim=bt601:transfer=bt709:colormatrix=bt601 -crf 23 -preset medium bt601_tv_1080p.mp4
ffmpeg -f lavfi -i testsrc=duration=10:size=1920x1080:rate=25 -pix_fmt yuv420p -colorspace 5 -color_primaries 5 -color_trc 2 -color_range 2 -c:v libx264 -x264-params colorprim=bt601:transfer=bt709:colormatrix=bt601 -crf 23 -preset medium bt601_pc_1080p.mp4
ffmpeg -f lavfi -i testsrc=duration=10:size=1920x1080:rate=25 -pix_fmt yuv420p -colorspace 1 -color_primaries 1 -color_trc 1 -color_range 1 -c:v libx264 -x264-params colorprim=bt709:transfer=bt709:colormatrix=bt709 -crf 23 -preset medium bt709_tv_1080p.mp4
ffmpeg -f lavfi -i testsrc=duration=10:size=1920x1080:rate=25 -pix_fmt yuv420p -colorspace 1 -color_primaries 1 -color_trc 1 -color_range 2 -c:v libx264 -x264-params colorprim=bt709:transfer=bt709:colormatrix=bt709 -crf 23 -preset medium bt709_pc_1080p.mp4
ffmpeg -f lavfi -i testsrc=duration=10:size=1920x1080:rate=25 -pix_fmt yuv420p -colorspace 9 -color_primaries 9 -color_trc 16 -color_range 1 -c:v libx265 -x265-params colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc -crf 23 -preset medium bt2020_tv_1080p.mp4
ffmpeg -f lavfi -i testsrc=duration=10:size=1920x1080:rate=25 -pix_fmt yuv420p -colorspace 9 -color_primaries 9 -color_trc 16 -color_range 2 -c:v libx265 -x265-params colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc -crf 23 -preset medium bt2020_pc_1080p.mp4
ffmpeg -f lavfi -i testsrc=duration=10:size=1920x1080:rate=25 -pix_fmt yuv420p10le -colorspace 5 -color_primaries 5 -color_trc 2 -color_range 1 -c:v libx265 -x265-params colorprim=bt601:transfer=bt709:colormatrix=bt601 -crf 23 -preset medium bt601_tv_10bit_1080p.mp4
ffmpeg -f lavfi -i testsrc=duration=10:size=1920x1080:rate=25 -pix_fmt yuv420p10le -colorspace 5 -color_primaries 5 -color_trc 2 -color_range 2 -c:v libx265 -x265-params colorprim=bt601:transfer=bt709:colormatrix=bt601 -crf 23 -preset medium bt601_pc_10bit_1080p.mp4
ffmpeg -f lavfi -i testsrc=duration=10:size=1920x1080:rate=25 -pix_fmt yuv420p10le -colorspace 1 -color_primaries 1 -color_trc 1 -color_range 1 -c:v libx265 -x265-params colorprim=bt709:transfer=bt709:colormatrix=bt709 -crf 23 -preset medium bt709_tv_10bit_1080p.mp4
ffmpeg -f lavfi -i testsrc=duration=10:size=1920x1080:rate=25 -pix_fmt yuv420p10le -colorspace 1 -color_primaries 1 -color_trc 1 -color_range 2 -c:v libx265 -x265-params colorprim=bt709:transfer=bt709:colormatrix=bt709 -crf 23 -preset medium bt709_pc_10bit_1080p.mp4
ffmpeg -f lavfi -i testsrc=duration=10:size=1920x1080:rate=25 -pix_fmt yuv420p10le -colorspace 9 -color_primaries 9 -color_trc 16 -color_range 1 -c:v libx265 -x265-params colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc -crf 23 -preset medium bt2020_tv_10bit_1080p.mp4
ffmpeg -f lavfi -i testsrc=duration=10:size=1920x1080:rate=25 -pix_fmt yuv420p10le -colorspace 9 -color_primaries 9 -color_trc 16 -color_range 2 -c:v libx265 -x265-params colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc -crf 23 -preset medium bt2020_pc_10bit_1080p.mp4