ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

AI视觉检测为何要解码视频?MP4转帧原理与FFmpeg实践指南

AI视觉检测为何要解码视频?MP4转帧原理与FFmpeg实践指南 先说一个很多刚接触视觉算法的人都会问的问题我用Python调个OpenCVcv2.VideoCapture(test.mp4)直接读不是也能一帧一帧地处理吗怎么就说“AI检测程序不能直接处理MP4”这里有个关键区别OpenCV帮你把解码和帧提取的脏活累活全干了你拿到手的已经是Mat对象也就是一张张图像而不是MP4文件本身。AI检测程序真正“吃”进去的从来不是视频文件而是图像帧。MP4只是运输图像的容器视觉算法要处理的是“卸货”后的原始像素数据。把这条链路拆开看你会发现中间藏着不少坑尤其是当你自己动手写高性能检测管线、处理监控视频、或者用深度学习框架做视频推理的时候。这篇文章我尽量用大白话把整条链路讲清楚MP4文件结构、解码原理、为什么要转成帧序列、转帧时的参数怎么选、踩过的坑怎么避末尾附一份常见的视频打不开/解码失败排查表。适合刚入门视觉算法、或者工作中需要让检测程序吃视频的开发者参考。1. 视频文件的真实结构MP4只是个“集装箱”要理解为什么AI程序不能直接处理MP4第一步是要搞清楚MP4到底是个什么东西。MP4的学名叫ISO/IEC 14496-12MPEG-4 Part 12它本质上是一个容器格式Container Format。所谓容器你可以把它想象成一个国际物流集装箱里面装什么货、怎么摆放、货单怎么填都由集装箱标准来规定但“集装箱”本身不等于“货物”。MP4这个集装箱里通常装的是两类东西视频流一段经过编码压缩的视频数据常见编码是H.264AVC、H.265HEVC老一点的可能有MPEG-4 Part 2、VP9、AV1等。音频流常见编码是AAC、MP3、AC-3等。元数据包括时长、分辨率、帧率、码率、创建时间、画面旋转信息等。所以当你看到一个文件叫test.mp4时你其实看到的是一个“箱子”箱子里面放着一卷用H.264编码器压缩过的“胶卷”视频流和一段AAC压缩的“音轨”音频流外加一张写着货物说明的“运单”元数据。这里就引出一个核心概念MP4里的视频数据不是图像是编码后的二进制流。这些二进制数据长什么样举一个H.264的例子H.264编码后的数据由一系列NAL Unit组成每个NAL Unit的前几个字节是起始码00 00 00 01或00 00 01后面跟着NAL头再后面是编码数据Slice、SPS、PPS等。你把这些字节直接丢给AI模型模型什么都学不到因为这不是图像。我见过不少新手把MP4文件直接读成二进制然后想喂给卷积神经网络结果报错或者推理结果完全随机这就是没搞懂容器和编码的关系。1.1 MP4的“箱内结构”moov、mdat和编解码器MP4内部采用Box也叫Atom结构真正重要的几个Box有ftyp文件类型声明这是MP4文件。moov元数据区相当于“运单”。包含每个轨道Track的信息、编解码器配置、时间戳、关键帧索引等。mdat媒体数据区就是真正的视频音频压缩数据。这里有个非常实际的坑有些MP4文件的moovBox放在文件末尾比如录制中断、直播录制、某些相机拍出来的视频如果moov不在文件头部播放器或者解码器就不知道如何定位视频数据。这就是为什么很多视频“下载下来打不开”“数据恢复后不能播放”——要么moov丢了要么moov和mdat的索引对不上。从AI检测程序的角度看我们真正关心的是解码器Decoder。无论MP4容器里装的是H.264还是H.265都需要对应的解码器把它解成YUV原始帧再转换成RGB图像才能作为视觉算法的输入。这也是为什么“AI不能直接处理MP4”的第一层原因MP4里的数据是编码压缩状态不是可直接用于视觉推理的像素矩阵。1.2 为什么编码压缩对AI是“污染”你可能会想数据压缩只是体积变小了里面的图像信息不是还在吗确实在但编码过程不是简单的“缩小图片”而是做了一系列有损变换。以H.264为例编码过程大概经历了这些步骤把当前帧划分成16x16的宏块Macroblock。利用时域参考帧做运动估计和运动补偿算出运动矢量和残差。对残差做DCT变换离散余弦变换和量化。对量化后的系数做熵编码CABAC或CAVLC。整个流程下来解码端拿到的YUV帧和原始拍摄帧相比已经有了一定失真有损编码。但这个失真对肉眼来说可能不明显对AI来说是额外的“噪声”。更关键的是编码器输出的I帧关键帧、P帧预测帧、B帧双向预测帧里只有I帧是完整的图像P帧和B帧存储的是“参考帧运动补偿残差”的编码数据。解码器必须按顺序解码并且依赖参考帧不能任意跳帧。从编码流里直接提取P帧或B帧的压缩数据给AIAI拿到的是残差和运动矢量不是图像。这就是“压缩域处理”的研究方向虽然学术界有人做但工程上极少直接采用因为通用性太差。所以AI检测程序要处理的必须是解码后的、完整的RGB或YUV帧。MP4容器本身、H.264的宏块结构、运动矢量对目前主流的卷积神经网络或Transformer视觉模型来说统统是无效信息。2. 完整链路拆解从MP4文件到AI模型输入搞清楚了MP4的本质接下来我把“AI检测程序处理视频”的完整链路分成四段每一段都有明确的输入和输出。2.1 第一阶段解封装Demux输入test.mp4输出H.264/H.265编码的视频流 AAC编码的音频流解封装就是拆箱子。FFmpeg里的avformat_open_input和avformat_find_stream_info干的就是这个活它读取ftyp、moov、mdat等Box结构找到视频流Video Stream和音频流Audio Stream并把压缩数据包Packet从文件里提取出来。注意这一步只拆箱不解码。视频流仍然是H.264编码的二进制数据。2.2 第二阶段解码Decode输入H.264/H.265编码的视频流 输出YUV原始帧通常是YUV420P或NV12这一步是解码器的工作。FFmpeg里的avcodec_send_packet和avcodec_receive_frame就是干这个的。解码器把H.264的NAL Unit解码成一张张完整的YUV图像这个过程需要硬件或CPU算力。解码后的帧是什么格式常见的是YUV420PY平面亮度信息每像素1字节。U平面色度信息每像素0.25字节。V平面色度信息每像素0.25字节。所以一个1080p的YUV420P帧大小 1920×1080×1.5 ≈ 3MB。但YUV不是视觉算法最喜欢的输入格式绝大多数深度学习框架PyTorch、TensorFlow、OpenCV默认使用RGB或BGR顺序。2.3 第三阶段像素格式转换与尺寸调整输入YUV420P帧 输出RGB/BGR图像可能还会Resize到模型的输入尺寸如640×640、416×416这一步包括YUV转RGBOpenCV的cvtColorFFmpeg的sws_scale。缩放Resize到模型输入尺寸注意保持宽高比或者直接拉伸两种方式各有取舍。有可能还要做归一化把像素值从0-255映射到0-1或者按模型的均值和标准差做标准化。拿YOLO系列检测器举例YOLOv8的输入尺寸通常是640×640训练时会把图片Resize到640后再做Letterbox保持原始宽高比填充灰色边条这个细节后面细说。2.4 第四阶段张量化与归一化输入RGB图像numpy数组H×W×C 输出模型的输入张量NCHW或NHWCfloat32归一化后深度学习框架要求输入是张量且通常要求第0维是batch size。所以一帧1920×1080的图像经过预处理后变成(1, 3, 640, 640)的float32张量值范围是0到1或按均值方差标准化。至此MP4文件才算真正变成视觉算法能“消化”的东西。我经常用一个类比帮助新手理解MP4是快递包裹解码是拆包裹YUV是没整理的零件RGB是拼好的成品零件模型输入是标准化包装后的最终产品。AI程序要的是最终产品不是快递包裹。3. 实操环节用FFmpeg把MP4变成AI能吃的帧序列理论讲完是时候动手了。最常见的实操需求有两个一是把视频抽成帧序列保存成jpg二是实时解码喂给检测程序。我这里先把抽帧讲透实时推理放到后面结合OpenCV和PyTorch讲。3.1 前置工具FFmpeg安装与验证FFmpeg是这个链路里最核心的工具没有之一。它同时搞定解封装、解码、像素转换、缩放几乎全能。安装方式Linux Ubuntusudo apt update sudo apt install ffmpegmacOSbrew install ffmpegWindows可以直接去FFmpeg官网下载编译好的exe或者用winget install ffmpeg。安装完成后验证ffmpeg -version ffprobe -versionffprobe是FFmpeg家族的探测工具用来查看视频信息一定要装。3.2 关键参数怎么选抽帧的四种姿势抽帧看起来简单但参数选择会直接影响AI检测的效果和速度。我按需求分成四种情况情况一按固定间隔抽帧适合做数据集ffmpeg -i input.mp4 -vf fps1 frame_%04d.jpgfps1表示每秒抽1帧。如果你想每2秒抽1帧就写fps1/2。情况二抽关键帧I帧适合快速预览ffmpeg -i input.mp4 -vf selecteq(pict_type,I) -vsync vfr keyframe_%04d.jpg这个命令只提取GOP里的I帧。好处是抽出来的都是完整清晰的画面坏处是I帧间隔不固定可能两帧之间隔好几秒。情况三从指定时间开始连续抽N帧适合取视频中某一段ffmpeg -ss 00:01:30 -i input.mp4 -t 10 -vf fps10 segment_%04d.jpg-ss 00:01:30表示从第1分30秒开始-t 10表示持续10秒fps10表示每秒抽10帧。这条命令常用于从视频中截取事件片段做分析。情况四解码全部帧不丢帧适合做逐帧检测ffmpeg -i input.mp4 -vsync 0 frame_%05d.jpg注意-vsync 0这个参数它告诉FFmpeg不要丢帧。默认情况下如果视频帧率和输出帧率不匹配FFmpeg会丢帧或重复帧这在逐帧检测时是致命的比如你要统计检测到的目标数量。3.3 实时检测的Python示例保存帧到磁盘适合做离线分析但AI检测程序更多时候是实时处理的。下面给一个用OpenCV PyTorch风格的伪代码框架展示从视频到模型输入的完整链路import cv2 import numpy as np # 假设你有一个训练好的检测模型输入是640x640的RGB图像 def preprocess_frame(frame_rgb, input_size640): # 1. 保持宽高比缩放 Letterbox填充 h, w frame_rgb.shape[:2] scale min(input_size / w, input_size / h) new_w, new_h int(w * scale), int(h * scale) resized cv2.resize(frame_rgb, (new_w, new_h)) # 2. 创建画布并填充 canvas np.full((input_size, input_size, 3), 114, dtypenp.uint8) x_offset (input_size - new_w) // 2 y_offset (input_size - new_h) // 2 canvas[y_offset:y_offset new_h, x_offset:x_offset new_w] resized # 3. BGR转RGB HWC转CHW 归一化 rgb cv2.cvtColor(canvas, cv2.COLOR_BGR2RGB) chw np.transpose(rgb, (2, 0, 1)).astype(np.float32) / 255.0 # 4. 增加batch维度 [1, 3, 640, 640] return np.expand_dims(chw, axis0) cap cv2.VideoCapture(test.mp4) fps cap.get(cv2.CAP_PROP_FPS) total_frames int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) print(f视频信息: {fps:.2f} FPS, 总帧数 {total_frames}) frame_count 0 while True: ret, frame_bgr cap.read() if not ret: break # 每隔N帧处理一次根据检测速度动态调整 if frame_count % 2 0: tensor preprocess_frame(frame_bgr) # 这里调用你的模型: outputs model(tensor) # 后处理坐标变换时记得把Letterbox的偏移和缩放还原回去 frame_count 1 cap.release()这里有个细节非常容易踩坑模型输出的坐标是640×640坐标系下的要映射回原始视频分辨率必须先减去偏移量再除以缩放比例。如果你直接拿模型输出坐标画框框的位置会整体偏移。还有个容易被忽略的点OpenCV读取视频时默认是BGR顺序而模型训练时通常用RGB。顺序搞反了检测结果会明显变差尤其是颜色敏感的任务比如红绿灯检测、颜色标签识别。3.4 为什么不用循环直接拿OpenCV逐帧处理就好一个很自然的疑问是既然OpenCV能直接读视频为什么还要单独学FFmpeg我的回答是OpenCV底层就是调FFmpeg。但直接用OpenCV做视频处理时你会失去很多控制力OpenCV屏蔽了解封装格式细节遇到损坏文件、异常编码参数时报错信息极其有限。OpenCV不支持所有编码格式。比如某些H.265的视频OpenCV自带的VideoCapture可能打不开但FFmpeg的命令行早就解出来了。高性能场景下你会希望用GPU硬解NVDEC、VAAPIOpenCV的VideoCapture在这方面配置麻烦FFmpeg命令行反而更直接。生产环境中视频可能来自RTSP流、海康/大华私有协议、或者其他非MP4封装OpenCV的兼容性不够。所以我的建议是调试和快速验证用OpenCV生产级管线用FFmpeg或封装FFmpeg的Python库比如PyAV、imageio-ffmpeg。PyAV是一个很好的中间层它在Python里暴露了FFmpeg的完整能力又比直接调命令灵活得多import av container av.open(test.mp4) stream container.streams.video[0] for frame in container.decode(stream): # frame.to_image() 得到PIL图像 img frame.to_image() # 转成numpy再给模型 # ...PyAV踩坑提醒解码出来的帧可能是YUV格式frame.to_image()内部会转成RGB的PIL图像但这个过程耗时。在高帧率场景下直接用frame.to_ndarray(formatbgr24)更高效。4. 避坑手册视频打不开、解码失败、检测结果不对怎么办这条链路我踩过的坑至少能写一百条这里挑最典型、最影响效率的几类列一个速查表。4.1 视频打不开/解码失败的排查表现象可能原因解决方案FFmpeg报“moov atom not found”MP4文件未正常写入moov索引缺失或损坏用ffmpeg -i broken.mp4 -c copy repaired.mp4尝试修复或用untrunc等工具配合参考视频修复海康/大华监控导出的MP4播放不了部分监控厂商的MP4封装不规范或使用了私有编码参数先用ffprobe -show_streams xxx.mp4确认编码格式再用ffmpeg -i 源文件 -c:v libx264 -c:a aac 输出.mp4重新转码OpenCV打不开但播放器能播OpenCV编译时没带对应解码器如H.265升级OpenCV或改用PyAV或者先用FFmpeg把视频转成H.264编码抽帧出来全是绿屏/花屏解码器选了硬件解码但驱动不匹配强制软件解码ffmpeg -hwaccel none -i ...或检查是否因为丢帧导致P帧参考不完整数据恢复后的视频无法播放文件头损坏、moov丢失、mdat数据不连续尝试recover_mp4工具输入一个同设备拍的正常参考视频来重建moov重装系统后视频没权限访问NTFS权限设置问题右键文件→属性→安全→编辑权限→添加当前用户→完全控制抽帧数量不对-vsync参数设置不当导致丢帧/重复帧加-vsync 0禁止自动帧同步视频帧率显示为0容器元数据损坏用ffprobe探测实际帧率解码时手动指定-r4.2 解码性能优化的几个真实经验视频逐帧推理的性能瓶颈通常不在模型而在解码环节。我实测过一个1080p视频纯CPU软解H.264单线程解码耗时约8-15ms/帧四线程约4-6ms/帧。模型推理YOLOv8s640×640大约10-20ms/帧取决于GPU。解码预处理推理后处理全链路通常会到20-40ms/帧。如果想让检测程序跑满实时25FPS以上几个关键经验用硬件解码。FFmpeg支持NVDECNVIDIA显卡、VAAPIIntel/AMD核显、QSVIntel。加了硬解解码耗时能降到1-2ms/帧。FFmpeg命令示例ffmpeg -hwaccel cuda -i input.mp4 -vf fps30 -f null -注意硬解对输入格式有要求比如H.264/H.265不是所有编码都能硬解。别用OpenCV逐帧办法加模型推理。它的VideoCapture在解码稳定性上不如PyAV内部拷贝也更多。实测同样一段视频PyAV读帧比OpenCV快20%-40%。预处理放到模型之前的GPU上做。如果不方便用GPU预处理至少用多线程把解码和推理流水线化——解码线程只管出帧推理线程只管算模型中间用队列缓冲。4.3 一个典型的坐标映射错误示例假设你的模型输入是640×640原视频是1920×1080Letterbox后原图被缩放并居中。模型输出的目标框坐标是(x_center, y_center, w, h)纵坐标的偏移和缩放怎么还原具体步骤# 模型输出 x_center, y_center, w, h outputs[0] # 640x640坐标 # 反向计算原图坐标 input_size 640 orig_w, orig_h 1920, 1080 scale min(input_size / orig_w, input_size / orig_h) new_w, new_h int(orig_w * scale), int(orig_h * scale) x_offset (input_size - new_w) // 2 y_offset (input_size - new_h) // 2 # 减去偏移除以缩放 orig_x_center (x_center - x_offset) / scale orig_y_center (y_center - y_offset) / scale orig_w w / scale orig_h h / scale如果视频是竖屏的比如手机拍的1080×1920Letterbox时缩放比例和偏移方向跟横屏不同。很多模型在横屏视频上没问题、竖屏视频上检测框全部偏移就是这里写错了。4.4 mpkg/m3u8/m4s等非MP4格式的处理关于热词里出现的mpkg转mp4、wallpaper pkg转mp4、m3u8转mp4这里顺带说几句mpkg/ pkg通常是某些软件私有封装比如Wallpaper Engine的主题包本质上里面可能是视频JSON配置。转mp4前先把它解包再说而不是直接用FFmpeg转。解包后拿到真实的视频文件再考虑转码。m3u8是HLS直播/点播的索引文件里面是一串.ts/.m4s分片地址。转MP4的正确姿势ffmpeg -i https://example.com/playlist.m3u8 -c copy output.mp4如果分片文件是加密的有#EXT-X-KEY需要先拿到密钥再在命令里拼接解密参数这个场景比较复杂。mp4转m4sm4s是B站等平台的媒体分片格式通常是fMP4的流切片。反过来用FFmpeg也能处理。关于5.1 surround sound test files various formats aac ac3 mp4 dts这类测试文件需求其实是想验证播放器/解码器对各种音频编码的兼容性。这和AI检测链路的关系不大但从解码器调试的角度看多备几个不同编码的测试文件确实很有用。5. 检测程序内部的图像预处理为什么模型不能直接吃视频帧前面讲了从MP4到RGB帧的过程但RGB帧也不能直接被模型吃。模型训练的时候输入图像的尺寸、通道顺序、值域范围都是有讲究的。这里展开讲几个容易忽略的预处理环节。5.1 通道顺序BGR和RGB的“错位陷阱”OpenCV读图是BGR顺序而PyTorch模型训练时大多用RGB顺序这个事大家基本都知道。但坑在于如果你用的是Caffe训练的老模型或者某些用OpenCV做数据增强的工具通道顺序可能是BGR而你没注意。一个判断方法把图像转成numpy数组打印img[0, 0, :]的三个值看蓝色通道和红色通道哪个值大。如果是一张蓝天白天的照片蓝色通道值应该明显大于红色如果是BGR顺序img[..., 0]查到的就是蓝色值。在写正式检测管线时我建议统一写一个预处理函数严格注释清楚输入和输出的通道顺序这个坑能帮你省掉很多排查时间。5.2 归一化的三种“流派”不同模型对像素值的要求不一样大概有三种0-1归一化直接pixel / 255.0PyTorch官方权重很多用这个。均值-标准差标准化(pixel - mean) / stdImageNet训练常用比如mean[0.485, 0.456, 0.406]std[0.229, 0.224, 0.225]。无归一化像素保持0-255有些边缘检测或传统视觉算法不需要归一化。归一化做错了模型照样能跑但精度会掉。你要是发现“同一个模型别人跑mAP很高我跑出来怎么这么差”先检查预处理是不是和训练时一致。5.3 视频抽帧的“帧率陷阱”和“时间基准”视频文件里每帧都有一个PTSPresentation Time Stamp表示这一帧应该在哪一刻显示。用OpenCV或FFmpeg抽帧时默认是按解码顺序输出但B帧的存在会让解码顺序和显示顺序不一致。具体表现为抽出来的帧序列播放时画面跳动或者相邻两帧的时间间隔不均匀。要按时间顺序输出需要正确处理帧的PTS。FFmpeg命令行里一般自动处理了但如果你自己用libavcodec编程一定要检查pts和dts。另外视频的帧率可能不是整数。比如某监控视频帧率是29.97fps如果你按fps30抽帧实际抽出来的帧数和预期会偏差。做数据集时最好用ffprobe先确认真正的帧率。5.4 检测结果不稳定的“隐性问题”GOP结构和丢帧在线性流水线里如果解码不够快系统会丢帧。但丢帧会导致检测的目标在时间上不连贯比如车辆跟踪时ID跳变。这个问题不一定来自AI模型而是来自上游丢帧。解决办法是解码器线程和推理线程解耦解码线程不管推理有多慢先把帧都解出来放队列推理线程按自己的节奏从队列取帧。队列的深度要按实际场景调太浅会丢帧太深会引入延迟。6. 完整实战构建一个监控视频的异常事件检测流程把前面所有内容串起来我用一个真实项目来演示有一段海康摄像头导出的监控MP4需要对画面中的“人”做检测并统计每个时间段的人数变化。6.1 第一步探查视频信息拿到文件先别急着跑代码先探测ffprobe -show_streams -show_format camera_001.mp4重点看codec_name是h264还是hevc决定解码方案。width、height分辨率。avg_frame_rate平均帧率。nb_frames总帧数如果moov里有。pix_fmt像素格式常见yuv420p。如果codec_namehevc我的建议是先用FFmpeg转成H.264ffmpeg -i camera_001.mp4 -c:v libx264 -preset fast -crf 20 -c:a copy camera_001_h264.mp4为什么转因为H.265解码对CPU要求高很多老旧设备不支持硬解转成H.264后兼容性和解码速度都更好。保存到Python端后用OpenCV/PyAV直接读H.264版本省心很多。6.2 第二步按时间段抽帧做检测一天24小时的监控不可能逐帧全跑模型。合理方案是按事件触发抽帧比如定时抽1fps或者检测到画面变化才触发。我这里的示例是简单定时抽帧import av import cv2 import numpy as np container av.open(camera_001_h264.mp4) stream container.streams.video[0] stream.thread_type AUTO # 多线程解码 frames_to_process [] sample_interval 30 # 每隔30帧处理一次 for idx, frame in enumerate(container.decode(stream)): if idx % sample_interval ! 0: continue img frame.to_ndarray(formatbgr24) frames_to_process.append((idx, img))这里用PyAV而不是OpenCV主要原因是stream.thread_type AUTO能启用多线程解码在大分辨率视频上明显更快。6.3 第三步模型推理 坐标还原模型推理部分就不展开写完整YOLO代码了但坐标还原的细节值得再强调一次。def restore_coords(box, orig_shape, input_size640): # box: [x_center, y_center, w, h] in input_size坐标系 orig_h, orig_w orig_shape[:2] scale min(input_size / orig_w, input_size / orig_h) pad_x (input_size - orig_w * scale) / 2 pad_y (input_size - orig_h * scale) / 2 x_center_orig (box[0] - pad_x) / scale y_center_orig (box[1] - pad_y) / scale w_orig box[2] / scale h_orig box[3] / scale x1 int(x_center_orig - w_orig / 2) y1 int(y_center_orig - h_orig / 2) x2 int(x_center_orig w_orig / 2) y2 int(y_center_orig h_orig / 2) return x1, y1, x2, y2我踩过的坑是frame.to_ndarray()返回的数组是高×宽×通道但有些人拿到的图像方向可能是翻转的尤其是一些监控摄像头在元数据里写了旋转信息。检测前先cv2.imshow看一眼确认方向正确再批量跑。6.4 第四步结果落盘和异常统计检测结果建议直接写成结构化数据比如CSV或JSON不要只存标注后的视频。{ frame_id: 12345, timestamp_sec: 411.5, detections: [ {class: person, confidence: 0.87, bbox: [320, 150, 410, 680]}, {class: person, confidence: 0.62, bbox: [900, 200, 980, 710]} ] }时间戳的换算很重要timestamp_sec frame_id / fps前提是定帧率视频。如果视频是VFR可变帧率需要用帧的PTS换算不能简单除帧率。7. 几个更进一步的思考7.1 视频理解模型可以直接吃视频吗前面说的是“AI检测程序”主要指目标检测、分类、分割这些处理单张图像的模型。确实也有视频理解的模型比如用3D卷积C3D、SlowFast、Video TransformerTimeSformer、VideoMAE它们能同时输入多帧。但这些模型依然不能直接吃MP4。它们的输入是形状为(T, C, H, W)的张量T是时间维。你需要先把MP4解码成帧序列再按固定间隔采样T帧比如均匀抽8帧或16帧然后做和图像模型一样的预处理。所以结论没有变无论模型多高级MP4必须先解码成帧。视频理解的进步是模型层面的不是输入层面的。7.2 压缩域推理为什么难落地学术界一直有人研究“直接在压缩域上做检测/识别”即不完整解码只解析运动矢量、残差、I帧的DCT系数等。好处是省去解码开销理论上能大幅提升速度。但工程上极少用这种方案的现实原因是不同编码器H.264/H.265/VP9/AV1的压缩域特征格式完全不同模型无法跨编码器通用。编码质量影响压缩域特征的语义稳定性比如码率低时残差噪声大。运动矢量只描述块级别运动不是像素级光流精度受限。工业界有现成的GPU硬解解码开销已经很小压缩域那点性能优势不够吸引人。所以现阶段老老实实解码成帧再送给模型是最可靠、最通用的路径。7.3 边缘设备上的视频处理最后说一句边缘设备Jetson、RK3588、树莓派。在边缘设备上做视频AI检测内存和CPU都紧张需要注意优先用硬解。Jetson上有NVDECRK3588有MPP硬解用起来确实比CPU软解快好几倍。避免把每一帧都存成RGB大图再喂模型最好解码后直接在YUV上做缩放在解码器层面做scale再转格式。队列缓冲区要设上限否则连续跑几小时后内存会涨到崩。我在RK3588上做过一个8路视频并发检测最开始的方案是8个OpenCV VideoCapture各开一个线程结果内存直接爆了。后来换成统一的FFmpeg解码池每一路解码出来只保留最近一帧RGB模型按需取帧内存占用降了大约70%。所以在设计视频AI系统时解码环节和模型推理一样需要认真规划链路里的每一环都可能成为瓶颈。这条从MP4到视觉算法的完整链路说难不算难说简单也藏着不少细节。核心记住一句话AI程序吃的是图像不是视频文件。把这句话刻在脑子里再遇到解码失败、画面花屏、检测框偏移这类问题你大概就能猜到问题出在链路的哪个环节了。
返回列表