如何在python中从ffmpeg流中提取视频和音频

use*_*766 4 python audio video ffmpeg video-streaming

我想从 ffmpeg 流中获取单独的视频和单独的音频对象(python)

\n

为此,我在我的 rasbery pi 上运行它:

\n
ffmpeg -f alsa -thread_queue_size 1024 -channels 1 -i hw:2,0 -thread_queue_size 1024 -s 1920x1080 -i /dev/video0 -listen 1 -f matroska -vcodec libx264 -preset veryfast -tune zerolatency http://:8080\n
Run Code Online (Sandbox Code Playgroud)\n

从服务器端,我像这样连接到流。我知道如何从这个数据包对象中获取声音,但我不\xe2\x80\x99不明白如何从数据包对象中获取视频帧?我想将视频流呈现为逐个图片和单独的声音,以便在程序中进行音频和视频处理。

\n
    process = (\n        ffmpeg.input("http://192.168.1.78:8080").output(\n            '-',\n            format='matroska',\n            acodec='libvorbis',\n            vcodec='libx264'\n        ).run_async(pipe_stdout=True, pipe_stderr=True)\n    )\n    while process.poll() is None:\n        packet = process.stdout.read(4096)\n
Run Code Online (Sandbox Code Playgroud)\n

使用python 3.9 ffmpeg-python==0.2.0

\n

PS\n本质上我需要为每个包提供一个视频数组和单独的音频。

\n

kes*_*esh 5

本质上,我需要为每个包提供一个 numpy 视频数组和单独的音频。

困难的部分是如何通过管道传输 2 个不同的流。您的方法取决于您的操作系统。

Linux/苹果系统

(我大部分时间都使用 Windows,所以对此持保留态度)

  • 使用pass_fds选项subprocess.Popen创建第二个“ stdout.” 有关如何通过 传递附加管道的示例,请参阅此链接pass_fds
  • 在 FFmpeg 命令行上,用于'pipe:3'使 FFmpeg 将第二个输出流写入额外的管道。例如:
ffmpeg -i input_url -f rawvideo -pix_fmt rgb24 - \
                    -f s16le                   pipe:3
Run Code Online (Sandbox Code Playgroud)
  • 在 Python 中,分派 2 个线程同时读取两个管道,不会出现死锁。

(您可能需要指定编解码器和更多选项,但您明白了。)

Windows/跨平台

  • pass_fds在 Windows 中不可用
  • 使用可以传输原始视频和音频流(例如 AVI)的容器:
ffmpeg -i input_url -f avi -c:v rawvideo -pix_fmt rgb24 -c:a pcm_s16le -
Run Code Online (Sandbox Code Playgroud)
  • Python 负责通过一次读取 RIFF 文件块指定的字节数来解复用 AVI 流。首先解码标头信息,然后视频和音频块将交替直到流结束。AVI格式不太复杂,参见维基百科条目

- 我碰巧知道这一切,因为我目前正在为我的 ffmpegio 库开发这种精确的机制。该功能的发布还有一段时间,但您可以查看我的测试实现:tests/test_media.py 和 src/ffmpegio/utils/avi.py。请注意,测试是针对文件读取而不是流读取而编写的。因此,test_media.py需要修改(使用Popen而不是run(第9行)并将第30行的BytesIO(out.stdout)更改为out.stdout)

(附录)ffmpegio示例

我设法让 AVI 流机制与我的ffmpegio库一起使用,所以如果您有兴趣尝试一下,这里有几个示例。

您在OP中的代码建议按数据包进行处理,blocksize=0为此进行设置:

ffmpeg -i input_url -f rawvideo -pix_fmt rgb24 - \
                    -f s16le                   pipe:3
Run Code Online (Sandbox Code Playgroud)

如果您希望 ffmpegio 收集每个流的数据并在其中一个流具有 X 个块时输出,请设置blocksize为正整数:

ffmpeg -i input_url -f avi -c:v rawvideo -pix_fmt rgb24 -c:a pcm_s16le -
Run Code Online (Sandbox Code Playgroud)

open您可以根据需要将(无破折号)FFmpeg 选项添加到参数列表中。输入选项,在选项名称后添加"_in".

我在旧笔记本电脑上进行的快速基准测试表明,它正在以 3 倍的速度解码视频和音频流,因此它应该能够在现代设备上处理实时流。

最后,我的标准免责声明。该库还很年轻,请在 GitHub 上报告任何问题,我会尽快解决。