kkroening / ffmpeg-python

Python bindings for FFmpeg - with complex filtering support
Apache License 2.0
10.05k stars 892 forks source link

Pipe encoded bytes as input in pipeline #818

Open iokarkan opened 9 months ago

iokarkan commented 9 months ago

I am trying to send encoded video packets from a source location via websockets (as per project requirements) towards a destination location and transcode them. I am trying to pipe the transferred encoded packets into stdin of an ffmpeg pipeline at the destination location but I cannot produce an output stream.

I can verify receiving the packets at the destination Flask SocketIO server, but I'm not sure what to write in terms of input() in the ffmpeg command.

My source location pipeline:

(
ffmpeg
    # width x height
    .input('pipe:', format='rawvideo', pix_fmt='rgb24', s=f"{shape[1]}x{shape[0]}")
    .output('pipe:', vcodec='mpeg4', f='h264')
    .overwrite_output()
    # reduce verbosity
    .global_args('-hide_banner', '-loglevel', 'error')
    .run_async(pipe_stdin=True, pipe_stdout=True)
)

and my destination pipeline:

class StreamTranscoder:
    def __init__(self):
        self.packet_queue = queue.Queue()
        self.pipe = (
            ffmpeg
            .input('pipe:', format='h264', analyzeduration=10000000, probesize=10000000)
            .output('udp://192.168.3.15:23000', format='rawvideo', pix_fmt='rgb24')
            .overwrite_output()
            .run_async(pipe_stdin=True)
        )

        self.pipe = subprocess.Popen(command, stdin=subprocess.PIPE)
        self.reader = thr.Thread(target=self.read_data, daemon=True)
        self.reader.start()

    def read_data(self):
        while True:
            try:
                self.pipe.stdin.write(self.packet_queue.get())
                self.pipe.stdin.flush()  # Ensure the data is sent to ffmpeg
            except KeyboardInterrupt:
                break
        self.kill_stream()

    def kill_stream(self):
        self.pipe.stdin.close()
        self.pipe.wait()
        self.pipe.kill()

stream = StreamTranscoder()

@socketio.on('test_ffmpeg')
def test_ffmpeg(data):
    print("FFMPEG packet received")
    print(len(data))
    stream.packet_queue.put(data)
    return

When I'm trying to open the stream using:

ffplay udp://127.0.0.1:23000

on the 192.168.3.15 computer, I'm getting no image, and when closing the Flask socket server I see the message:

[h264 @ 0x55dd39a47900] missing picture in access unit with size 2000000 # NB: this is the total bytes I've sent
[extract_extradata @ 0x55dd39a46f00] Invalid NAL unit 0, skipping.
    Last message repeated 132 times
[h264 @ 0x55dd39a47900] Invalid NAL unit 0, skipping.
    Last message repeated 132 times
[h264 @ 0x55dd39a47900] no frame!
[h264 @ 0x55dd39a35480] decoding for stream 0 failed
[h264 @ 0x55dd39a35480] Could not find codec parameters for stream 0 (Video: h264, none): unspecified size
Consider increasing the value for the 'analyzeduration' (10000000) and 'probesize' (10000000) options
Input #0, h264, from 'pipe:':
  Duration: N/A, bitrate: N/A
  Stream #0:0: Video: h264, none, 15 tbr, 1200k tbn, 30 tbc
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> rawvideo (native))
Cannot determine format of input stream 0:0 after EOF
Error marking filters as finished
32io commented 1 month ago

two self.pipes ??????