gpt4 book ai didi

Python opencv子进程写入返回损坏的管道

转载 作者:行者123 更新时间:2023-12-04 23:10:45 24 4
gpt4 key购买 nike

我想读取一个 rtsp 视频源,添加覆盖文本并将其推送到 RTMP 端点。我正在使用 Videocapture 读取视频源和 python 子进程将帧写回 RTMP 端点。我提到了这个FFmpeg stream video to rtmp from frames OpenCV python

import sys
import subprocess

import cv2
import ffmpeg
rtmp_url = "rtmp://127.0.0.1:1935/live/test"

path = 0
cap = cv2.VideoCapture("rtsp://10.0.1.7/media.sdp")

# gather video info to ffmpeg
fps = int(cap.get(cv2.CAP_PROP_FPS))
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))



command = ['ffmpeg', '-i', '-', "-c", "copy", '-f', 'flv', rtmp_url]
p = subprocess.Popen(command, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE)

font = cv2.FONT_HERSHEY_SIMPLEX
while cap.isOpened():

ret, frame = cap.read()
cv2.putText(frame, 'TEXT ON VIDEO', (50, 50), font, 1, (0, 255, 255), 2, cv2.LINE_4)
cv2.imshow('video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break

if not ret:
print("frame read failed")
break

try:
p.stdin.write(frame.tobytes())
except Exception as e:
print (e)


cap.release()
p.stdin.close()
p.stderr.close()
p.wait()
python 脚本返回“[Errno 32] Broken pipe”。在终端中运行 ffmpeg 命令可以正常工作。

ffmpeg -i rtsp://10.0.1.7/media.sdp -c copy -f flvrtmp://127.0.0.1:1935/live/test


上面的命令工作正常,我可以将输入流推送到 RTMP 端点。但是我无法将处理后的帧写入运行 ffmpeg 的子进程。
请让我知道,如果我错过了什么。

最佳答案

将原始帧写入标准输入管道时不能使用 "-c", "copy"frame 返回的 ret, frame = cap.read() 是一个 BGR 颜色格式的 uint8 NumPy 数组(cap.read() 解码视频并转换颜色格式)。
FFmpeg 术语中,frame 格式是“rawvideo”。

  • command 应该告诉 FFmpeg 期望原始视频作为输入,具有特定的大小和像素格式:command = ['ffmpeg', '-f', 'rawvideo', '-s', f'{width}x{height}', '-pixel_format', 'bgr24', ...
  • 因为输入的是原始视频,我们必须重新编码。
    我们可以指定编码的像素格式和视频编解码器:'-pix_fmt', 'yuv420p', '-c:v', 'libx264' ...

  • 评论:
  • 解码和重新编码视频会损失一些质量(但别无选择)。
  • 建议的解决方案会丢失音频(有保留音频的解决方案,但 OpenCV 缺乏音频支持)。
  • 发布的解决方案重用了以下 post 中的一些代码。
    很少有 FFmpeg 参数没有解释(如 '-bufsize', '64M' )。

  • 执行监听器应用程序:
  • 如果没有接收视频的“监听器”,RTMP 流将无法工作。
    监听器应该在启动 RTMP 流之前启动(由于 TCP 使用)。
  • 我们可以使用 FFplay 子进程作为“监听器”应用程序:
     ffplay_process = sp.Popen(['ffplay', '-listen', '1', '-i', rtmp_url])

  • 流式合成视频帧:
    从一个更简单的代码示例开始,它流式传输合成帧(不捕获 RTSP 视频)。
    以下“自包含”代码示例在灰色背景上写入黄色文本,并将帧传递给 FFmpeg 以进行 RTMP 流式传输:
    import cv2
    import numpy as np
    import subprocess as sp

    width = 320
    height = 240

    fps = 5

    rtmp_url = "rtmp://127.0.0.1:1935/live/test"

    # Start the TCP server first, before the sending client.
    ffplay_process = sp.Popen(['ffplay', '-listen', '1', '-i', rtmp_url]) # Use FFplay sub-process for receiving the RTMP video.


    command = ['ffmpeg',
    '-re',
    '-f', 'rawvideo', # Apply raw video as input
    '-s', f'{width}x{height}',
    '-pixel_format', 'bgr24',
    '-r', f'{fps}',
    '-i', '-',
    '-pix_fmt', 'yuv420p',
    '-c:v', 'libx264',
    '-bufsize', '64M',
    '-maxrate', '4M',
    '-f', 'flv',
    rtmp_url]

    process = sp.Popen(command, stdin=sp.PIPE) # Execute FFmpeg sub-process for RTSP streaming

    frame_counter = 0;

    while True:
    # Build sythetic frame in BGR color format (3D NumPy array).
    frame = np.full((height, width, 3), 60, np.uint8)
    cv2.putText(frame, 'TEXT ON VIDEO ' + str(frame_counter), (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2, cv2.LINE_4) # Put a frame counter for showing progress.

    process.stdin.write(frame.tobytes()) # Write raw frame to stdin pipe.

    cv2.imshow('frame', frame) # Show frame for testing

    key = cv2.waitKey(int(round(1000/fps))) # We need to call cv2.waitKey after cv2.imshow

    if key == ord('q'): # Press 'q' for exit
    break

    frame_counter += 1

    process.stdin.close() # Close stdin pipe
    process.wait() # Wait for FFmpeg sub-process to finish
    ffplay_process.kill() # Forcefully close FFplay sub-process
    cv2.destroyAllWindows() # Close OpenCV window

    输出样本:
    enter image description here

    从 RTSP 流中捕获视频帧。
    以下代码示例从 public RTSP stream 捕获视频帧,写入文本,然后将帧传递给 FFmpeg 以进行 RTMP 流式传输:
    import cv2
    import numpy as np
    import subprocess as sp

    # Use public RTSP Streaming for testing.
    rtsp_stream = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"

    rtmp_url = "rtmp://127.0.0.1:1935/live/test"

    cap = cv2.VideoCapture(rtsp_stream)

    # gather video info to ffmpeg
    fps = int(cap.get(cv2.CAP_PROP_FPS))
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))


    # Start the TCP server first, before the sending client.
    ffplay_process = sp.Popen(['ffplay', '-listen', '1', '-i', rtmp_url]) # Use FFplay sub-process for receiving the RTMP video.


    command = ['ffmpeg',
    '-re',
    '-f', 'rawvideo', # Apply raw video as input
    '-s', f'{width}x{height}',
    '-pixel_format', 'bgr24',
    '-r', f'{fps}',
    '-i', '-',
    '-pix_fmt', 'yuv420p',
    '-c:v', 'libx264',
    '-bufsize', '64M',
    '-maxrate', '4M',
    '-f', 'flv',
    rtmp_url]

    process = sp.Popen(command, stdin=sp.PIPE) # Execute FFmpeg sub-process for RTSP streaming

    frame_counter = 0;

    while cap.isOpened():
    # Read frame from RTSP stream.
    ret, frame = cap.read()

    if not ret:
    print("frame read failed")
    break

    cv2.putText(frame, 'TEXT ON VIDEO', (0, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2, cv2.LINE_4)
    cv2.putText(frame, str(frame_counter), (100, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2, cv2.LINE_4)

    process.stdin.write(frame.tobytes()) # Write raw frame to stdin pipe.

    cv2.imshow('frame', frame) # Show frame for testing

    key = cv2.waitKey(1) # We need to call cv2.waitKey after cv2.imshow

    if key == ord('q'): # Press 'q' for exit
    break

    frame_counter += 1

    cap.release()
    process.stdin.close() # Close stdin pipe
    process.wait() # Wait for FFmpeg sub-process to finish
    ffplay_process.kill() # Forcefully close FFplay sub-process
    cv2.destroyAllWindows() # Close OpenCV window

    输出样本:
    enter image description here

    关于Python opencv子进程写入返回损坏的管道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69188430/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com