拓冰建站拓冰建站
首页 / 资讯中心 / 正文

AI视频检测链路详解:从MP4解码到模型推理的完整指南

前阵子公司做产线质检检测模型在单张图片上跑得飞起结果业务方扔过来一批MP4说“你直接把模型接上去就行视频也是图片组成的嘛”。我当时第一反应是直接model.predict(video_path)肯定是不行的但真要让我把“为什么不行”讲明白还是得把这条链路从头到尾捋一遍。后来我发现这个问题特别典型很多做视觉算法落地的朋友天然把“视频文件”和“图像数据”画了等号以为AI检测程序天生能读MP4。真实情况是现在几乎所有视觉算法的核心都跑在神经网络上而神经网络只认数字矩阵不认任何文件后缀。MP4里面装的是经过高度压缩的编码流别说AI了连你自己用播放器打开它中间都得先经过一层解码器把压缩流还原成成千上万张连续图片。这篇文章就想把这条隐秘链路一次性讲透从MP4的容器结构到解封装、解码、抽帧、预处理再到批量推理最后附上我用OpenCV和FFmpeg搭链路的实操代码和踩坑记录。看完你应该能明白为什么AI不能直接吃视频以及工程上到底该怎么把视频“喂”给检测程序。1. AI模型不认视频文件它只认“数字矩阵”1.1 模型底层是数学运算不是文件解析先看一个再常见不过的模型接口。无论你用的是PyTorch、TensorFlow还是ONNX Runtime一个视觉模型的前向传播本质是一连串的张量运算# 伪代码一个分类模型的 forward def forward(self, x): # x.shape [batch_size, channels, height, width] x self.conv(x) x self.pool(x) ... return x这里的输入x是一个四维浮点张量。它可以是GPU显存里的数值可以是CPU内存里的numpy数组但绝不会是一个文件路径字符串。模型内部做的卷积、池化、全连接、注意力机制都建立在“矩阵乘加”之上。你给它一个mp4的二进制流它没有任何解析手段也不知道“video”是什么意思。很多人会问那为什么不给模型加一个外部解析器呢这其实已经在做了就是我们常说的“检测程序”外面那层封装。你调用某个库它先读文件、解码、预处理最后才把张量送进模型。问题出在视频不是单张图片解码和抽帧这一层本身就要单独设计没法靠一句model(video_path)糊弄过去。1.2 图像在内存里到底长什么样一张彩色图片在内存里就是一个三维数组高、宽、通道。比如一张 1920x1080 的RGB图片shape 是(1080, 1920, 3)。每个数值代表某个像素点上某个通道的亮度通常落在0到255之间。灰度图就更简单只保留亮度通道shape 是(1080, 1920)。import numpy as np # 一个非常小的 4x4 灰度图像 gray_img np.array([ [0, 200, 30, 80], [255, 10, 90, 120], [45, 220, 180, 60], [70, 90, 55, 240] ], dtypenp.uint8)数字图像处理领域的大部分算法包括深度学习里的卷积神经网络CNN、Vision TransformerViT都是直接操作这种“像素矩阵”。模型在训练时见过的输入永远是归一化后的浮点数张量比如把0到255映射到0到1再按数据集统计的均值和方法做标准化。所以“AI检测程序”最理想的输入不是一张JPEG文件也不是一段MP4而是一份已经完成解码、预处理、排好batch顺序的数值张量。文件和路径只是外部接口的便利接口真正进模型的是张量。1.3 图片能进模型视频为什么不能一张JPEG图片虽然内部也有压缩但解码过程简单打开之后就能拿到一个二维或三维像素数组。一张图片对应一个张量一次推理就能得到结果。视频的本质是“连续的图像序列”但这里有两个额外的麻烦。第一个麻烦是数据量。一段1080p、30fps、一小时长的视频如果完整解码成RGB帧会得到 108019203303600 ≈ 671亿字节也就是600多GB的原始数据。这还只是分辨率不算高的素材。想一次性把所有帧全部变成张量塞进内存绝大多数服务器直接爆掉。第二个麻烦是时间维度。模型一次前向传播通常处理的是一个batch的静态图像。视频天然带有时序动作识别、行为分析这类的任务需要模型能理解“帧与帧之间发生了什么”这又需要另外设计3D卷积、时序Transformer或滑窗机制。即便只是做逐帧目标检测你也得考虑按什么帧率抽帧、结果怎么映射回时间轴。所以“视频不能直接进模型”不是某个框架没做好而是整个输入数据结构就不匹配。要想让AI吃视频必须在外层搭建一条流水线把视频一步步“降维”成模型能理解的张量。这就是本文接下来要讲的完整链路。2. MP4的“外皮”与“内芯”容器格式和编码压缩2.1 MP4是一个集装箱不是一种画质格式很多人会下意识觉得“MP4是一种视频格式压制一下画质就变好或变差”。这个说法不够准确。MP4本质是一个容器Container它内部可以装不同编码格式的视频流、音频流、字幕流和大量元数据。就像快递盒一样外面写着MP4里面装的是什么货还得拆开看。MP4基于 ISO BMFF 结构由许多“box”组成。常见的ftyp表示文件类型moov存放索引、时长、分辨率等元数据mdat才是真正承载媒体帧数据的地方。有些MP4文件的moov在文件头部有些在尾部这会影响网络播放时的加载速度也影响程序能不能快速定位到视频流。想验证一个MP4里到底装了什么最直接的命令是ffprobeffprobe demo.mp4输出里能看到Stream #0:0 Video: h264或hev1还能看到Stream #0:1 Audio: aac。这说明同一个文件里既有视频流也有音频流。对AI检测来说音轨几乎是无用信息第一步就得把这层外皮剥开把不属于视频流的东西全部忽略掉。2.2 视频流的核心H.264/H.265与I/P/B帧视频流本身也做过高度压缩。假设一段1小时1080p视频不压缩那就是几百GB的数据。为了塞进一个几十GB甚至几GB的文件编码器会做大量空间和时间维度的压缩。以最常见的H.264AVC为例编码后的视频流不是单纯的一帧一图而是由I帧、P帧、B帧组成I帧关键帧完整的图像数据可以独立解码。P帧预测帧只记录与前一帧的差异和运动矢量。B帧双向预测帧同时参考前后帧压缩率更高但解码时需要未来的帧先到位。这就导致一个非常反直觉的现象视频流里相邻的“字节”并不对应视觉上相邻的“画面”。你没法简单地按文件偏移量切一段就得到一张图。P帧和B帧必须依赖参考帧解码器得先把I帧解出来然后按照参考关系重建整组画面。在实际监控视频里编码器通常隔几十帧才放一个I帧这意味着如果程序从一个随机位置开始解码可能会先输出花屏或残缺画面直到下一个I帧到来才能恢复正常。很多做视频截图的同学都踩过这种坑。2.3 压缩域数据为什么不能直接送进神经网络H.264这类编码器在压缩时把图像变换到频域保存的是DCT系数、量化参数、运动矢量这类信息。这些数据对编码解码是高效的但对神经网络来说非常不友好。主流的视觉模型希望输入是“在空间上均匀采样的像素值”。卷积核做的就是在像素矩阵上滑动加权求和注意力机制也要计算像素或patch之间的相关性。你如果硬把DCT系数和运动矢量塞进卷积层模型结构、训练方式、预训练权重全都要改。学术圈确实有过“压缩域视频分析”的研究方向例如直接在DCT域做目标检测但工程实践里几乎没人这么做原因很简单通用性差、实现复杂、效果未必更好。所以把压缩视频还原成像素帧是任何AI视频处理链路都无法绕开的一步。2.4 解码器在做什么把“差异”还原成“画面”解码器做的工作和编码器完全相反从码流中提取量化系数反量化、反变换再利用运动补偿和参考帧重建出完整的图像。最终输出的通常不是RGB而是YUV格式比如YUV420P或NV12。Y是亮度分量UV是色度分量。因为人眼对亮度更敏感色度分量通常会减半采样这是视频压缩率高的另一个原因。但AI模型大多是在RGB图像上预训练的。因此在解码出YUV帧后还需要一次色彩空间转换YUV - RGB。这一步看起来很简单但往往成为颜色异常的源头尤其是当你用OpenCV读视频时读出来是BGR而非RGB模型训练和推理用的通道顺序对不上检测效果会莫名其妙地变差。这块我会在后面的踩坑部分专门展开。3. 完整拆解一条视频从MP4到张量的标准流水线3.1 第一站Demux解复用前面说过MP4容器里有视频流、音频流、可能还有字幕流。第一步就是把它们拆开只留下视频流。这一步叫解复用demuxing常见实现是FFmpeg库或OpenCV内部的VideoCapture。在命令行层面ffprobe可以快速查看流信息ffprobe -v error -select_streams v:0 -show_entries streamcodec_name,width,height,avg_frame_rate -of defaultnoprint_wrappers1 demo.mp4得到的输出会告诉你视频流是什么编码、分辨率多少、帧率多少。这些信息决定了后续解码和抽帧策略。比如编码是h264分辨率为1920x1080平均帧率30那你就可以估算原始帧大小和解码耗时。解复用阶段还要注意时间基time base的问题。MP4里的时间戳是以某个时间单位计算的比如90000或1000。如果不理解时间基在处理多路视频对齐时很容易混乱。后面写抽帧逻辑时我会强调“按时间戳”而不是“按帧序号”操作。3.2 第二站Decode解码解复用拿到的是压缩后的视频码流还需要交给解码器。CPU软解和GPU硬解都行软解通用性好硬解速度快但依赖驱动和硬件。用FFmpeg命令把一段视频抽成图片序列是最直观的例子ffmpeg -i demo.mp4 -vsync 0 frame_%04d.png默认它会输出所有帧。如果想按一定帧率抽帧比如每秒一帧ffmpeg -i demo.mp4 -vf fps1 -vsync 0 frame_%04d.png这里的fps1会让FFmpeg先均匀丢帧再输出每秒一张图。丢多少帧、怎么丢不是随便拍脑袋决定的得结合业务需求比如打比赛或监考场景可能只需要每秒两帧。3.3 第三站像素格式转换、缩放与统一尺寸解码器输出的YUV420P也好OpenCV读出的BGR也好模型通常接收固定尺寸的RGB输入。所以这一步要做三件事第一YUV到RGB的转换用FFmpeg或OpenCV自动完成。第二颜色通道顺序调整将BGR改成RGB如果用OpenCV读图。第三缩放。直接把图像resize到模型输入大小比如224x224或640x640是最简单的做法但会破坏宽高比导致目标变形。很多检测模型对此敏感。工程上更常用的是letterbox先等比缩放让较长边匹配模型尺寸然后对剩余边填充灰色像素尽量保留原始比例。代码大概是import cv2 def letterbox(img, new_shape(640, 640), color(114, 114, 114)): h, w img.shape[:2] ratio min(new_shape[0] / h, new_shape[1] / w) new_w, new_h int(w * ratio), int(h * ratio) resized cv2.resize(img, (new_w, new_h), interpolationcv2.INTER_LINEAR) canvas np.full((new_shape[0], new_shape[1], 3), color, dtypenp.uint8) dw, dh (new_shape[1] - new_w) // 2, (new_shape[0] - new_h) // 2 canvas[dh:dh new_h, dw:dw new_w] resized return canvas3.4 第四站张量化与归一化预处理完成的图像还是numpy.ndarray类型是uint8。送入模型前要转成浮点张量并且把数值范围归一化到模型训练时使用的区间。最常见的操作是除以255把0-255映射到0-1。一些模型还会使用均值和方差做标准化。PyTorch代码如下import torch from torchvision import transforms transform transforms.Compose([ transforms.ToTensor(), # HWC - CHW且 /255 transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) # frame 是 RGB 的 numpy ndarray tensor transform(frame).unsqueeze(0) # 增加 batch 维度这里有两个容易被忽略的细节。一是维度顺序PyTorch默认是NCHWHWC要调成CHW。二是batch维度即使只有一帧也要用unsqueeze(0)变成(1, C, H, W)因为模型期望四维输入。如果直接用ONNX Runtime输入名和动态轴也要提前查清楚。3.5 第五站批处理与推理单帧推理可以直接做但效率不高。GPU擅长并行一次输入多张图吞吐量远高于逐张处理。工程上会把解码抽帧出来的图像攒成一个batch再统一送进模型。batch torch.stack([preprocess(frame) for frame in frames]) with torch.no_grad(): outputs model(batch)批处理还要考虑时间戳对齐。你攒的batch可能来自不同时刻的视频帧推理完之后每一条检测结果都要能够映射回原来的时间轴。所以除了保存检测框和类别最好把每帧的pts显示时间戳也一并记录下来。3.6 为什么不建议把整段视频一次性读进内存算一笔账1080p的RGB帧单帧大小是 1920×1080×3 ≈ 6.2MB。30fps的10分钟视频解码后原始数据大约是 6.2MB × 30 × 600 ≈ 111GB。中间还要算上模型推理时产生的特征图显存占用更高。所以正常做法是流式处理打开视频流逐帧或按批读取处理完就释放。不要让all_frames这样的列表无限增长。内存溢出几乎是所有视频处理项目里出现频率最高的崩溃原因之一。4. 最小可用链路用OpenCV和FFmpeg把链路跑通4.1 方案AOpenCV VideoCapture逐帧读取OpenCV的VideoCapture是对FFmpeg的封装好处是简单原型阶段能快速验证链路。import cv2 import torch cap cv2.VideoCapture(demo.mp4) if not cap.isOpened(): raise IOError(无法打开视频文件) while True: ret, frame cap.read() if not ret: break # OpenCV读出来的是BGR需要转RGB再送模型 rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) resized cv2.resize(rgb, (224, 224)) tensor torch.from_numpy(resized).permute(2, 0, 1).float().unsqueeze(0) / 255.0 # 推理 with torch.no_grad(): output model(tensor) cap.release()这套代码能跑但有几个问题。一是cap.read()默认按视频帧率逐帧读取如果你的检测模型每秒只能处理10帧而视频是30fps就会越积越多实时性完全失控。二是OpenCV隐藏了很多细节一旦解码出错很难判断是文件编码问题还是FFmpeg配置问题。三是CAP_PROP_POS_FRAMES跳帧定位并不可靠尤其在B帧很多的视频流里。4.2 方案B用FFmpeg/PyAV抽帧更可控PyAV是FFmpeg的Python绑定比OpenCV更接近底层你能看到完整的解码上下文。import av container av.open(demo.mp4) stream container.streams.video[0] for frame in container.decode(stream): # frame是解码后的VideoFrame可以直接转PIL img frame.to_image() # 后续做RGB转换、resize、tensor化这种方式的好处是你可以精确控制读取哪一路视频流、用什么解码器、怎么处理时间戳。一些OpenCV解不了的奇奇怪怪的视频PyAV通常能解因为它直接暴露了FFmpeg能力。命令行方式也可以配合Python管道使用。比如先用FFmpeg把视频解码成rawvideo再通过管道送到Python子进程适合不想在代码里装一堆库的部署场景。ffmpeg -i demo.mp4 -f rawvideo -pix_fmt bgr24 -vf scale640:640 pipe:1Python端用subprocess.Popen读取管道按固定字节数解析帧。这种方式内存占用小但多线程和异常处理要做好否则容易死锁。4.3 一个更工程化的模板解码进程 推理进程视频解码和模型推理的速度天然不对等。1080p视频软解可能需要20ms一帧模型推理如果是30ms一帧两者差距不大但如果是高分辨率或大模型解码和推理经常互相拖慢。常见的优化模式是生产者-消费者。解码线程负责读帧和基础预处理推理线程负责从队列取帧、组batch、送模型。Python里用queue.Queue或multiprocessing.Queue都能实现。import threading import queue frame_queue queue.Queue(maxsize64) def decode_worker(video_path): cap cv2.VideoCapture(video_path) while True: ret, frame cap.read() if not ret: break frame_queue.put(frame) cap.release() frame_queue.put(None) def inference_worker(model): while True: frame frame_queue.get() if frame is None: break tensor preprocess(frame) result model(tensor) # 保存结果写入文件或数据库队列能起到消峰作用解码速度快时队列暂存推理跟不上时队列自动形成背压避免内存无限增长。4.4 什么时候选OpenCV什么时候选FFmpeg/PyAV维度OpenCV VideoCaptureFFmpeg/PyAV上手难度低中高解码能力依赖预编译的FFmpeg版本部分解码器缺失默认支持范围更广时间戳控制弱强硬件解码支持但不透明支持且可控性好复用性和维护适合快速原型适合生产系统音频流处理基本忽略可以精细控制我的经验是原型阶段用OpenCV省时间没问题一旦要对接多格式、多路并发或硬件解码直接切PyAV或者用FFmpeg命令做解耦别犹豫。5. 踩坑实录这些坑会让你的“完整链路”断在半路5.1 BGR与RGB的噩梦这是视频检测项目里最高频的坑没有之一。OpenCV读出来的帧通道顺序是BGR不是RGB。如果你在模型训练时用的是RGB图比如通过PIL加载、用PyTorch的ToTensor转换过那么推理阶段用OpenCV直接读图再送模型R和B通道就互换了。表现非常隐蔽检测框位置可能大体正常因为轮廓信息主要靠灰度梯度但颜色相关的分类会明显出错。比如红绿灯识别红灯可能被识别成绿灯或者分类置信度大幅下降。排查方法很简单把输入模型的张量保存成图片看看它和原图颜色是否一致。import cv2 # 假设 frame 是OpenCV读出来的BGR vis_img frame.copy() # BGR cv2.imwrite(debug.jpg, vis_img) # 正常如果是模型内部用的RGB那就必须先转换rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)这个转换做在resize之前还是之后对结果影响不大但建议在resize之前做避免颜色插值在不同的色彩空间里产生微小差异。5.2 帧率、时间基与抽帧策略MP4的帧率不是恒定的。很多视频为了控制码流会使用可变帧率VFR。在一个VFR视频里帧与帧之间的时间间隔不是固定的如果程序只按帧序号cap.read()来等间隔抽样抽出来的帧在时间轴上是不均匀的。更稳妥的做法是使用时间戳。OpenCV里可以通过CAP_PROP_POS_MSEC按毫秒定位但反序列化时要注意别每次都set会触发解码器重定位性能很差。PyAV里每个frame.pts是当前帧的显示时间戳配合流的时间基可以换算成秒。import av container av.open(demo.mp4) stream container.streams.video[0] time_base stream.time_base for frame in container.decode(stream): seconds frame.pts * time_base # 根据seconds判断当前帧是否要送入模型如果你需要每秒做一次检测正确做法是按视频帧率解码但只保留“时间戳变化超过1秒的帧”参与推理。这样可以保证检测结果在时间轴上均匀分布。5.3 从中间开始解码为什么容易花屏有的同学优化性能跳过前面一段不处理直接定位到第1000帧开始检测。结果发现输出从某个时刻开始前几帧全是花屏或错误框。原因是视频流从任意位置开始解码不一定能立即找到I帧。P帧和B帧因为缺少参考帧无法正确重建画面。大多数播放器会“快进”到最近的关键帧再开始解码而程序如果不做这个处理就会拿到残缺帧。用OpenCV定位cap cv2.VideoCapture(demo.mp4) cap.set(cv2.CAP_PROP_POS_MSEC, 10000) # 跳到第10秒 ret, frame cap.read()由于内部实现OpenCV可能会自动跳到10秒附近的关键帧但偏差不可控。如果检测任务对时间敏感性高最好用FFmpeg的精确seek做关键帧对齐。5.4 内存/显存溢出视频处理的“隐形炸弹”我在项目里见过几种典型的内存爆炸写法一边cap.read()一边把frame加到列表里最后统一处理。一个30分钟的视频能直接耗尽16GB内存。解码线程不控制队列长度无限put推理线程来不及消费进程直接OOM。模型输出结果也全部缓存在内存里没及时写入磁盘。解决办法是给队列设置上限比如queue.Queue(maxsize64)put时如果满了就阻塞或丢弃。对长时间视频要分批写入结果不要在内存里累积。GPU显存同理如果连续推理不释放中间张量显存也会被占满用with torch.no_grad():能省掉部分计算图内存。5.5 编码器规格不统一同一个“MP4”内部的视频流可能是H.264、H.265HEVC、VP9、AV1甚至AVI容器里可能装着MJPEG。普通OpenCV发行版默认可能没有编译H.265解码器导致某些视频打不开。你看到的现象是VideoCapture不报错但cap.read()返回False或者第一帧是None。排查方法还是先ffprobe看看编码类型ffprobe -v error -select_streams v:0 -show_entries streamcodec_name -of defaultnoprint_wrappers1 demo.mp4如果编码是h265或hevc我的建议是直接用支持该格式的FFmpeg/PyAV解码不要折腾OpenCV的预编译库。对于封闭的部署环境还要确认目标机器的FFmpeg确实编译进了对应解码器。5.6 多路并发时的线程安全与资源泄漏同时处理多路视频时很多人图省事给每一路各开一个线程各自创建自己的VideoCapture对象。这在小规模场景下没问题但要注意OpenCV的VideoCapture在多线程环境下的稳定性有时会偶发读取到损坏帧。另外如果用了subprocess.Popen调用FFmpeg记得在结束时要关闭管道并等待子进程退出否则会残留子进程慢慢把系统资源耗尽。我的做法是每路视频用独立的进程而不是线程。虽然进程启动成本高一些但隔离性好一路崩了不影响其它路。解码进程通过消息队列把帧发给推理进程系统整体更稳。6. 工程化进阶视频量大、实时性要求高的正确姿势6.1 只解I帧极简抽帧法的适用场景如果业务只需要视频里“大体发生了什么”比如快速做缩略图、粗筛可疑片段、给下游检索系统建索引那么完全不需要解码每一帧。只解I帧就够了I帧本身就是完整的图像。FFmpeg可以直接筛选I帧ffmpeg -i demo.mp4 -vf selecteq(pict_type,I) -vsync vfr frame_%04d.png这样输出的图片数量会大幅减少解码开销也降低不少。但要注意I帧在编码器的时间间隔通常固定比如每隔2秒一个。如果业务需要在更细的时间粒度上做检测只解I帧就不够了还是得正常解码。6.2 硬件解码与GPU推理打通CPU软解在1080p30fps的视频上大约会占满2到4个CPU核。如果同一台机器还要跑6路视频再加一个GPU模型CPU可能直接成为瓶颈。现代GPU基本都支持视频硬件解码。NVIDIA卡走NVDECIntel核显走VAAPIApple平台走VideoToolbox。用FFmpeg打开硬解很方便ffmpeg -hwaccel cuda -i demo.mp4 -f rawvideo -pix_fmt bgr24 pipe:1把解码出的帧直接通过GPU显存或PCIe传输给推理模型可以减少一次CPU和GPU之间的数据拷贝。NVIDIA官方推出的DALI数据管道就能把视频解码和图像预处理直接放在GPU上做配合TensorRT推理延迟可以压得很低。不过硬解码对驱动的要求比较苛刻容器化部署时要提前验证好环境。6.3 多路视频并行进程池与GPU调度假设你有8路摄像头每路30fps。一般来说不需要每路都全帧率跑模型大多数检测任务每秒2到5帧就够。这时候架构可以这样设计每一路视频由一个解码进程负责只输出需要的帧。所有解码进程把帧推到同一个“待推理队列”。一个GPU推理进程从队列取帧组batch后送入模型。结果按来源视频ID和时间戳写回存储。Python里可以用multiprocessing实现。注意batch不能无限大GPU显存有限一般4到16帧一个batch比较合适。如果队列堆积严重就要降抽帧频率或者增加推理进程而不是无限增大队列。6.4 不逐帧推理跳帧、滑窗与时序模型逐帧推理在很多场景下是浪费。检测任务本身有时序连续性上一帧有目标下一帧大概率也还在附近没有必要30fps全检。安防场景通常每秒1帧就够了作弊检测、动作识别则可能需要更高帧率。对动作识别来说单帧静态模型完全不够你需要给模型一个时间窗口。常见做法是滑窗每次取一个长度为T的帧序列比如16帧或32帧组织成(T, C, H, W)的张量再输入到时序模型如3D CNN、SlowFast、TimeSformer等。这时前面链路里“按时间戳抽帧”就特别重要滑窗内的帧必须真实对应一个连续的时间段而不是简单用read()顺序读出来的相邻帧。6.5 边下载边处理的流式架构最后一个建议不要把AI处理设计成“必须先有一个完整MP4文件”。很多场景比如摄像头RTSP流、网络视频流都是流式数据根本没有完整文件。用FFmpeg可以边拉流边解码ffmpeg -i rtmp://example.com/live/stream -f rawvideo -pix_fmt bgr24 pipe:1Python端继续用管道读取帧走和前面一样的预处理、推理流程。这样整个视频处理链路可以做到边下载、边解码、边检测、边落盘延迟更低存储也更省。我自己现在做视频类AI项目默认都是先ffprobe看流信息再决定解码策略模型统一在RGB通道上训练输入侧永远用cvtColor保证颜色不错处理长时间视频一定用流式加队列不允许任何人把整段视频读进内存。能硬解就硬解不能硬解就把解码放在独立进程。这套习惯基本是从上面这些坑里换来的。希望你看完这篇文章也能直接把链路搭出来少踩几个我当年踩过的坑。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门