FFmpeg 6.0丢失的预览功能

一、什么是预览功能

我们知道,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 6.0丢失的预览功能

关于ffmpeg cmd预览功能,不知道是否还有另辟蹊径的解决方案?

作者:quink
来源:Fun With FFmpeg
原文:https://mp.weixin.qq.com/s/d9iW5W9ovx1wCyZ5rJtRug

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论