如何使用子进程 (Python) 将 Picamera 视频传输到 FFMPEG

Ven*_*qui 5 python subprocess ffmpeg raspberry-pi3

我看到了大量有关将 raspivid 流直接传输到 FFMPEG 以进行编码、混合和重新流式传输的信息,但这些用例主要来自 bash;相似:

raspivid -n -w 480 -h 320 -b 300000 -fps 15 -t 0 -o - | ffmpeg -i - -f mpegts udp://192.168.1.2:8090ffmpeg

我希望利用 Picamera 库的功能,这样我就可以使用 OpenCV 和类似方法进行并发处理,同时仍然使用 FFMPEG 进行流式传输。但我不知道如何正确打开 FFMPEG 作为子进程并将视频数据传输给它。我见过很多尝试、未答复的帖子声称已经这样做的人,但似乎没有一个在我的 Pi 上工作。

我应该使用 Picamera 创建视频缓冲区并将原始视频通过管道传输到 FFMPEG 吗?我可以使用 camera.capture_continuous() 并将我用于 OpenCV 计算的 bgr24 图像传递给 FFMPEG 吗?

我已经尝试了各种变体,但我不确定我是否只是误解了如何使用子流程模块、FFMPEG,或者我只是缺少一些设置。我知道原始流不会有任何元数据,但我不完全确定我需要给 FFMPEG 什么设置才能理解我给它的内容。

我有一个 Wowza 服务器,我最终将流式传输到,但我目前正在通过流式传输到笔记本电脑上的 VLC 服务器进行测试。我目前试过这个:

import subprocess as sp
import picamera
import picamera.array
import numpy as np

npimage = np.empty(
        (480, 640, 3),
        dtype=np.uint8)
with picamera.PiCamera() as camera:
    camera.resolution = (640, 480)
    camera.framerate = 24

    camera.start_recording('/dev/null', format='h264')
    command = [
        'ffmpeg',
        '-y',
        '-f', 'rawvideo',
        '-video_size', '640x480',
        '-pix_fmt', 'bgr24',
        '-framerate', '24',
        '-an',
        '-i', '-',
        '-f', 'mpegts', 'udp://192.168.1.54:1234']
    pipe = sp.Popen(command, stdin=sp.PIPE,
                    stdout=sp.PIPE, stderr=sp.PIPE, bufsize=10**8)
    if pipe.returncode != 0:
        output, error = pipe.communicate()
        print('Pipe failed: %d %s %s' % (pipe.returncode, output, error))
        raise sp.CalledProcessError(pipe.returncode, command)

    while True:
        camera.wait_recording(0)
        for i, image in enumerate(
                        camera.capture_continuous(
                            npimage,
                            format='bgr24',
                            use_video_port=True)):
            pipe.stdout.write(npimage.tostring())
    camera.stop_recording()
Run Code Online (Sandbox Code Playgroud)

我还尝试将流写入一个类似文件的对象,该对象只是创建 FFMPEG 子进程并写入它的标准输入(在初始化 picam 时,camera.start_recording() 可以得到一个这样的对象):

class PipeClass():
    """Start pipes and load ffmpeg."""

    def __init__(self):
        """Create FFMPEG subprocess."""
        self.size = 0
        command = [
            'ffmpeg',
            '-f', 'rawvideo',
            '-s', '640x480',
            '-r', '24',
            '-i', '-',
            '-an',
            '-f', 'mpegts', 'udp://192.168.1.54:1234']

        self.pipe = sp.Popen(command, stdin=sp.PIPE,
                         stdout=sp.PIPE, stderr=sp.PIPE)

        if self.pipe.returncode != 0:
            raise sp.CalledProcessError(self.pipe.returncode, command)

    def write(self, s):
        """Write to the pipe."""
        self.pipe.stdin.write(s)

    def flush(self):
        """Flush pipe."""
        print("Flushed")

usage:
(...)
with picamera.PiCamera() as camera:
    p = PipeClass()
    camera.start_recording(p, format='h264')
(...)
Run Code Online (Sandbox Code Playgroud)

对此的任何帮助将是惊人的!

小智 6

我已经能够将 PiCamera 输出流式传输到 ffmpeg,如下所示:

import picamera
import subprocess

# start the ffmpeg process with a pipe for stdin
# I'm just copying to a file, but you could stream to somewhere else
ffmpeg = subprocess.Popen([
    'ffmpeg', '-i', '-',
    '-vcodec', 'copy',
    '-an', '/home/pi/test.mpg',
    ], stdin=subprocess.PIPE)

# initialize the camera
camera = picamera.PiCamera(resolution=(800, 480), framerate=25)

# start recording to ffmpeg's stdin
camera.start_recording(ffmpeg.stdin, format='h264', bitrate=2000000)
Run Code Online (Sandbox Code Playgroud)

或者这不是您要找的?