使用ffmpeg将h264视频字节解码为内存中的JPEG帧

问题描述 投票:0回答:1

我正在使用 python 和 ffmpeg (4.4.2) 从进程连续生成的图像生成 h264 视频流。我的目标是通过 websocket 连接发送此流,并在接收端将其解码为单独的图像帧,并通过不断将帧推送到 HTML 中的

<img>
标签来模拟流。

但是,在尝试组合

rawvideo
输入格式、
image2pipe
格式、使用
mjpeg
png
重新编码传入流等之后,我无法在接收端读取图像。所以我很乐意知道做这样的事情的标准方法是什么。

在源头,我将 while 循环中的帧传输到 ffmpeg 中以组装 h264 编码视频。我的命令是:

        command = [
            'ffmpeg',
            '-f', 'rawvideo',
            '-pix_fmt', 'rgb24',
            '-s', f'{shape[1]}x{shape[0]}',
            '-re',
            '-i', 'pipe:',
            '-vcodec', 'h264',
            '-f', 'rawvideo',
            # '-vsync', 'vfr',
            '-hide_banner',
            '-loglevel', 'error',
            'pipe:'
        ]

在 websocket 连接的接收端,我可以通过以下方式将图像存储在存储中:

        command = [
            'ffmpeg',
            '-i', '-',  # Read from stdin
            '-c:v', 'mjpeg',
            '-f', 'image2',
            '-hide_banner',
            '-loglevel', 'error',
            f'encoded/img_%d_encoded.jpg'
        ]

在我的 ffmpeg 命令中。

但是,我想提取管道中的每个单独的帧并加载到我的应用程序中,而不将它们保存在存储中。所以基本上,我想要 ffmpeg 中的

'encoded/img_%d_encoded.jpg'
行发生的任何事情,但允许我访问接收端 ffmpeg 管道的 stdout 子进程管道中的每个帧,在自己的线程中运行。

  • 最适合完成上述用例的 ffmpeg 命令是什么?如何将其调整得更快或具有更高的质量?
  • 我可以使用
    process.stdout.read(2560x1440x3)
    从标准输出缓冲区读取每一帧吗?

如果您强烈建议我推荐 ffmpeg 的更新版本,请这样做。

PS:可以理解,这可能不是创建流的最佳方式。尽管如此,我认为这不会太复杂,而且延迟应该很低。我可以通过 websocket 传输 JPEG 图像并在我的

<img>
标签中查看它们,但我想节省带宽并在接收端中继一些计算工作。

python ffmpeg video-streaming h.264
1个回答
0
投票

首先,我建议使用 Python 中的“av”库,它是 ffmpeg 的优秀包装器。它提供了更好的控制,消除了对子流程的需要。此外,它还提供了更强大的错误处理选项。

服务器

创建一个 WebSocket 服务器来管理您的 H.264 流,我认为它是 RTSP 流。将

av.open
container.demux
一起使用以获得
av.packet
,然后您可以通过 WebSocket 将其传输到客户端。该数据包将是 H.264 数据包。

客户

通过WebSocket连接到服务器并接收H.264数据包。为 H.264 建立一个

av.codecContext
,您可以在其中输入数据包并对其进行解码。解码后,您可以使用
frame.to_image()
将帧转换为图像,或者更好的是,为 MJPEG/JPEG 创建编解码器上下文并将帧编码为 JPEG。然后,您可以根据需要管理 JPEG。

问题是为什么这个过程不直接在客户端上进行。我理解其目的是节省带宽,但只有在传输 H.264 数据包时才能实现带宽节省。因此,服务器的作用主要是解析流,这不像解码那样占用资源。无论如何,客户将承担更艰巨的任务。如果您的目标是获得最佳延迟,则应考虑避免可能不需要的不必要的额外步骤。

这是一个取决于用例的选择。如果您要构建一个流媒体服务器来广播一个源两个不同的客户端,这将是有意义的。如果需要低延迟,你应该看看如果你的相机有 MJPEG/HTTP 那将是最好的,因为你不需要转码,当然它有带宽的缺点。

选择取决于用例。如果您正在开发一个向不同客户端广播单个源的流媒体服务器,那么这种方法是有意义的。如果需要低延迟,您应该检查您的相机是否支持 MJPEG/HTTP,因为这将是最佳选择,因为它消除了转码的需要,尽管带宽有缺点。

此外,重新评估你的方法可能是有益的。例如,由于需要信令服务器,使用 WebRTC 可能会更复杂,但它允许浏览器直接使用 H264,而不需要转码。有一个令人印象深刻的 Go 项目,名为“RTSPtoWebRTC”,可以为您处理所有这些。

此外,您可以利用 fMP4,其中 H.264 封装在分段 MP4 流中,从而也无需转码,但在 JS 端更复杂。

© www.soinside.com 2019 - 2024. All rights reserved.