如何用Python提取视频元数据中的设备及镜头信息?
我希望从视频中提取设备厂商、型号以及焦距这类信息,此前已用exifread模块从静态图片中成功提取到完整EXIF信息(示例输出如下):
image type : MPO Image ImageDescription: Shot with DxO ONE Image Make: DxO Image Model: DxO ONE Image Orientation: Horizontal (normal) Image XResolution: 300 Image YResolution: 300 Image ResolutionUnit: Pixels/Inch Image Software: V3.0.0 (2b448a1aee) APP:1.0 Image DateTime: 2022:04:05 14:53:45 Image YCbCrCoefficients: [299/1000, 587/1000, 57/500] Image YCbCrPositioning: Centered Image ExifOffset: 158 Thumbnail Compression: JPEG (old-style) Thumbnail XResolution: 300 Thumbnail YResolution: 300 Thumbnail ResolutionUnit: Pixels/Inch Thumbnail JPEGInterchangeFormat: 7156 Thumbnail JPEGInterchangeFormatLength: 24886 EXIF ExposureTime: 1/3 EXIF FNumber: 8 EXIF ExposureProgram: Aperture Priority EXIF ISOSpeedRatings: 100 EXIF SensitivityType: ISO Speed EXIF ISOSpeed: 100 EXIF ExifVersion: 0221 EXIF DateTimeOriginal: 2022:04:05 14:53:45 EXIF DateTimeDigitized: 2022:04:05 14:53:45 EXIF ComponentsConfiguration: CrCbY EXIF CompressedBitsPerPixel: 3249571/608175 EXIF ExposureBiasValue: 0 EXIF MaxApertureValue: 212/125 EXIF SubjectDistance: 39/125 EXIF MeteringMode: MultiSpot EXIF LightSource: Unknown EXIF Flash: Flash did not fire EXIF FocalLength: 1187/100 EXIF SubjectArea: [2703, 1802, 675, 450] EXIF MakerNote: [68, 88, 79, 32, 79, 78, 69, 0, 12, 0, 0, 0, 21, 0, 3, 0, 5, 0, 2, 0, ... ] EXIF SubSecTime: 046 EXIF SubSecTimeOriginal: 046 EXIF SubSecTimeDigitized: 046 EXIF FlashPixVersion: 0100 EXIF ColorSpace: sRGB EXIF ExifImageWidth: 5406 EXIF ExifImageLength: 3604 Interoperability InteroperabilityIndex: R98 Interoperability InteroperabilityVersion: [48, 49, 48, 48] EXIF InteroperabilityOffset: 596 EXIF FileSource: Digital Camera EXIF ExposureMode: Auto Exposure EXIF WhiteBalance: Auto EXIF DigitalZoomRatio: 1 EXIF FocalLengthIn35mmFilm: 32 EXIF SceneCaptureType: Standard EXIF ImageUniqueID: C01A1709306530020220405185345046 EXIF BodySerialNumber: C01A1709306530
但尝试用ffmpeg提取视频元数据时,未能找到目标信息。执行的代码如下:
import ffmpeg from pprint import pprint test_video = "my_video.mp4" pprint(ffmpeg.probe(test_video)["streams"])
输出的流信息仅包含编码、分辨率等基础内容:
[{'avg_frame_rate': '30/1', 'bit_rate': '1736871', 'bits_per_raw_sample': '8', 'chroma_location': 'left', 'codec_long_name': 'H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10', 'codec_name': 'h264', 'codec_tag': '0x31637661', 'codec_tag_string': 'avc1', 'codec_time_base': '1/60', 'codec_type': 'video', 'coded_height': 1088, 'coded_width': 1920, 'display_aspect_ratio': '16:9', 'disposition': {'attached_pic': 0, 'clean_effects': 0, 'comment': 0, 'default': 1, 'dub': 0, 'forced': 0, 'hearing_impaired': 0, 'karaoke': 0, 'lyrics': 0, 'original': 0, 'timed_thumbnails': 0, 'visual_impaired': 0}, 'duration': '20.800000', 'duration_ts': 624000, 'has_b_frames': 0, 'height': 1080, 'index': 0, 'is_avc': 'true', 'level': 40, 'nal_length_size': '4', 'nb_frames': '624', 'pix_fmt': 'yuv420p', 'profile': 'Constrained Baseline', 'r_frame_rate': '30/1', 'refs': 1, 'sample_aspect_ratio': '1:1', 'start_pts': 0, 'start_time': '0.000000', 'tags': {'creation_time': '2021-05-08T13:23:20.000000Z', 'encoder': 'AVC Coding', 'handler_name': 'VideoHandler', 'language': 'und'}, 'time_base': '1/30000', 'width': 1920}, {'avg_frame_rate': '0/0', 'bit_rate': '79858', 'bits_per_sample': 0, 'channel_layout': 'stereo', 'channels': 2, 'codec_long_name': 'AAC (Advanced Audio Coding)', 'codec_name': 'aac', 'codec_tag': '0x6134706d', 'codec_tag_string': 'mp4a', 'codec_time_base': '1/48000', 'codec_type': 'audio', 'disposition': {'attached_pic': 0, 'clean_effects': 0, 'comment': 0, 'default': 1, 'dub': 0, 'forced': 0, 'hearing_impaired': 0, 'karaoke': 0, 'lyrics': 0, 'original': 0, 'timed_thumbnails': 0, 'visual_impaired': 0}, 'duration': '20.864000', 'duration_ts': 1001472, 'index': 1, 'max_bit_rate': '128000', 'nb_frames': '978', 'profile': 'LC', 'r_frame_rate': '0/0', 'sample_fmt': 'fltp', 'sample_rate': '48000', 'start_pts': 0, 'start_time': '0.000000', 'tags': {'creation_time': '2021-05-08T13:23:20.000000Z', 'handler_name': 'SoundHandler', 'language': 'und'}, 'time_base': '1/48000'}]
执行pprint(ffmpeg.probe(test_video)["format"])的结果:
{'bit_rate': '1815244', 'duration': '20.864000', 'filename': 'my_video.mp4', 'format_long_name': 'QuickTime / MOV', 'format_name': 'mov,mp4,m4a,3gp,3g2,mj2', 'nb_programs': 0, 'nb_streams': 2, 'probe_score': 100, 'size': '4734158', 'start_time': '0.000000', 'tags': {'artist': 'Microsoft Game DVR', 'compatible_brands': 'mp41isom', 'creation_time': '2021-05-08T12:12:33.000000Z', 'major_brand': 'mp42', 'minor_version': '0', 'title': 'Snipping Tool'}}
请问视频中是否包含这类设备及镜头信息?是否需要使用其他工具来提取?
1. 当前视频的情况:无可用的设备/镜头元数据
从你提供的ffmpeg探针结果来看,这个视频已经丢失了原始设备厂商、型号、焦距这类元数据。格式标签里的Microsoft Game DVR和Snipping Tool说明这是通过Windows的游戏录制工具截取的视频,这类二次处理工具通常会清除原始视频的EXIF类元数据,仅保留录制相关的基础信息。
2. 视频是否可能包含这类信息?
只有原始直出的视频(比如相机、手机直接拍摄,未经过转码、剪辑、录制工具二次处理的)才可能携带设备、镜头相关的元数据。这些数据一般存储在MOV/MP4格式的UserData或Exif扩展块中。
如果视频经过转码、剪辑软件(如PR、剪映)或录制工具处理,大部分原始元数据会被清除或替换为处理工具的标识信息,无法再提取到原始设备相关内容。
3. 针对原始视频的提取方案
如果是未经过二次处理的原始视频,可以用以下工具提取目标元数据:
方法一:使用exiftool(推荐)
exiftool是专门处理元数据的工具,比ffmpeg更擅长识别和提取视频中的EXIF衍生信息。直接在命令行执行:
exiftool my_video.mp4
它会列出视频中所有包含的元数据,包括Make(厂商)、Model(型号)、FocalLength(焦距)等字段。
方法二:Python调用exiftool
可以使用pyexiftool库在Python中集成该功能,示例代码:
from exiftool import ExifTool with ExifTool() as et: metadata = et.get_metadata("my_video.mp4") # 提取目标字段 print("设备厂商:", metadata.get("EXIF:Make")) print("设备型号:", metadata.get("EXIF:Model")) print("焦距:", metadata.get("EXIF:FocalLength"))
方法三:使用ffmpeg的详细探针命令
如果坚持用ffmpeg,可以执行以下命令读取更完整的元数据:
ffmpeg -i my_video.mp4 -dump_segments -f null -
但这种方式输出的信息比较杂乱,不如exiftool直观。
总结
你当前的视频因为经过Microsoft Game DVR处理,已经丢失了原始设备元数据,无法提取到目标信息;如果是原始未处理的视频,优先使用exiftool来提取设备及镜头相关的元数据。
内容的提问来源于stack exchange,提问作者cat_got_my_tongue

