如何使用FFmpeg裁剪/删除H.264视频特定未解码关键帧实现Datamoshing
实现Datamoshing效果的可行方案
1 现有操作的问题说明
- 你使用的noise码流过滤命令失效原因:删除关键帧后,FFmpeg默认会因后续帧缺少参考源终止码流拷贝流程;
not(key)参数是删除非关键帧,不会破坏参考链因此可以正常运行。 - 你使用的单帧提取命令确实执行了解码重编码,你的理解正确,该流程会完全重构帧类型与参考关系,无法保留原始码流的帧属性。
2 无需编码的快速实现方案
2.1 提取原始裸H.264码流
首先提取无封装、保留所有原始NALU和帧类型的裸码流,全程不重编码:
ffmpeg -i input.mp4 -c:v copy -bsf:v h264_mp4toannexb -an raw.h264
2.2 手动编辑码流删除关键帧
H.264码流中IDR关键帧对应的NALU类型值为5,你可以编写脚本遍历raw.h264的所有NALU,标记符合删除条件的IDR帧后直接删除对应数据块,将剩余数据拼接保存为modified.h264即可。
如果要快速测试效果,直接删除除第一个IDR帧外的所有IDR帧,即可获得全程的花屏扩散效果。
2.3 封装回MP4
ffmpeg -i modified.h264 -c:v copy output.mp4
3 修复原有码流过滤命令
如果不想手动处理裸码流,可添加参数让FFmpeg忽略参考帧丢失的错误继续运行:
ffmpeg -i Input.mp4 -c copy -bsf:v noise=drop='gt(t\,30)*key' -fflags +discardcorrupt -err_detect ignore_err output.mp4
4 编程实现的推荐方案
如果要自行写代码实现,推荐使用PyAV(Python)或者直接调用FFmpeg的libav*库:
- 全程不解码,直接读取视频的AVPacket数据包
- 通过包的flag字段判断是否为关键帧,符合删除条件的包直接丢弃
- 其余包直接写入输出文件,全程透传原始码流,效率极高
- 完全保留原始帧的参考关系,删除关键帧后即可得到目标效果
内容的提问来源于stack exchange,提问作者M Moto
相关产品推荐
相关产品推荐

