一、什么是预览功能
我们知道,ffmpeg项目自带了三个命令行工具:ffmpeg(以下称为ffmpeg cmd)、ffplay、ffprobe(过去还有个ffserver)。ffmpeg cmd用于媒体文件编辑、转码、推流等。大家习惯了把ffmpeg cmd当成一个纯命令行,不带UI的工具。
用ffmpeg cmd处理视频时,特别是测试libavfilter滤镜效果时,先生成一个文件,再用ffplay播放看效果,会让人觉得操作繁琐,效率不高。如果能实时预览处理的效果会非常方便。
其实,ffmpeg cmd自带了预览的功能,只需要用一个特殊的muxer:
ffmpeg -re -i ~/Movies/cctv.mp4 -an -f sdl2 -
`-f sdl2`指定了输出文件格式为sdl2,这是个假的muxer(以下称为伪muxer),位于libavdevice/sdl2.c,是用SDL2实现的渲染功能。
看起来又简单又方便是吧?But……
二、FFmpeg预览功能已损坏
如果你在FFmpeg 6.0以上版本测试-f sdl2,Linux上可能没画面出来,macOS上可能直接crash,Windows上能出来画面,当你点击拖动窗口时,发现画面卡死……
Why?
UI渲染往往需要在特定线程上运行。使用SDL2,一个基本原则是在主线程做初始化和渲染,有时候还需要使用SDL2定义的SDL_main函数而不是自己实现main函数。
在FFmpeg 6.0之前,ffmpeg cmd的主要处理流程是在主线程,无意中,调用muxer或者伪muxer也是在主线程,-f sdl2用SDL2在主线程运行做渲染,没有什么问题。
从FFmpeg 6.0开始的ffmpeg cmd多线程重构,带来了两个问题:
1、创建和初始化muxer在一个子线程
2、执行muxer write frame在另一个子线程
SDL2在Linux系统做渲染,可以不在主线程,但要求SDL2的初始化和渲染在同一个线程。Windows和macOS渲染要在主线程。以上两个问题,导致ffmpeg cmd预览功能在三大桌面系统都不能用了。
FFmpeg社区有两个patch,都是把muxer初始化和write frame改到同一个线程,能满足Linux系统渲染要求,但是对Windows和macOS无效。
三、FFmpeg 7.0会修复预览功能吗?
FFmpeg 7.0不会修复ffmpeg cmd预览功能,同时还废弃了sdl2和opengl muxer。
关于sdl2伪muxer,社区有两种意见:
1、sdl2伪muxer很有用,应该修复ffmpeg cmd的预览功能
2、sdl2伪muxer的存在是个错误,应该删除它
关于这个问题,我的看法是:
1、sdl2伪muxer是个糟糕的设计
2、但是预览功能是刚需
libavdevice本身是个hack的实现,这里的hack同时包含褒义和贬义:
- 一方面,libavdevice直接借用libavformat的接口,采集设备是demuxer,输出设备是muxer,用现成的libavformat接口,有时候确实方便省事;
- 另一方面,设备本质上不同于muxer/demuxer
- 设备相比avformat,有更多的动态控制的需求,线程相关的要求;
- 还有API上,采集设备和输出设备应该用AVFrame做参数,比如图像采集输出AVFrame图像,渲染设备以AVFrame做输入。但现在硬套用avformat的接口,输入输出都是AVPacket,绝对称不上是合理的设计;
avdevice_register_all、avpriv_register_devices也是因为avdevice和avformat用同一个API却拆分成两个库而添加的hack。
如果重新设计,我认为libavdevice应该有自己的API。而如果想保留现状,libavdevice和libavformat应该合并成一个库,没必要拆分,只在编译上开关是否启用device功能。
但因为种种分歧,libavdevice止步不前。libavdevice里的sdl2也是个糟糕的设计,用avformat muxer的API做渲染。
我的设想是,用其他方式来实现ffmpeg cmd的预览功能,比如:
1、在libavfilter里加一个sink类型的filter做渲染,类似gstreamer。gstreamer有autoaudiosink、autovideosink,具体的sink实现有alsasink、glimagesink等。在这一点上,gstreamer的sink比FFmpeg的hack的libavdevice看起来要合理的多。并且,gstreamer有event loop main loop,能解决渲染的线程问题;为了解决线程问题,ffmpeg cmd需要做改造;
2、或者,在ffmpeg cmd工具里实现渲染,可以和ffplay共享渲染部分
现状是,有一波人不认为ffmpeg cmd需要预览功能,特别是做ffmpeg cmd多线程重构的Anton。不认可这个功能,讨论怎么实现就没意义了。他们认为,多进程的解决方案已经足够了。
四、跨进程的预览方式
从今往后,ffmpeg cmd预览只有多进程的方案了:把ffmpeg cmd的输出传给其他播放器做输入,例如:
./ffmpeg -re -i ~/Movies/cctv.mp4 -an -f yuv4mpegpipe - |ffplay -
有时候,用pipe跨进程传数据会有意料之外的问题。有些第三方库(比如avs3解码器),会自己打印日志到stdout,这时候视频数据和第三方库的打印会一起进入stdout再传给ffplay,导致播放画面异常。如果存在这种问题,换成其他传输方式比较稳妥,比如tcp:
ffplay -listen 1 tcp://127.0.0.1:8888
./ffmpeg -re -i ~/Movies/cctv.mp4 -an -f yuv4mpegpipe tcp://127.0.0.1:8888
虽然pipe是Unix系统的精髓,但用来传输大量视频帧数据不像是个正经方案。但是呢,又不是不能用。
关于ffmpeg cmd预览功能,不知道是否还有另辟蹊径的解决方案?
作者:quink
来源:Fun With FFmpeg
原文:https://mp.weixin.qq.com/s/d9iW5W9ovx1wCyZ5rJtRug
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。