Linux 将原始 OpenCV 图像通过管道传输到 FFmpeg

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5825173/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 03:51:42  来源:igfitidea点击:

Pipe raw OpenCV images to FFmpeg

pythonlinuxopencvffmpegpipe

提问by BrianTheLion

Here's a fairly straightforward example of reading off a web cam using OpenCV's python bindings:

这是一个使用 OpenCV 的 python 绑定读取网络摄像头的相当简单的示例:

'''capture.py'''
import cv, sys
cap = cv.CaptureFromCAM(0)                    # 0 is for /dev/video0
while True :
    if not cv.GrabFrame(cap) : break
    frame = cv.RetrieveFrame(cap)
    sys.stdout.write( frame.tostring() )

Now I want to pipe the output to ffmpeg as in:

现在我想将输出通过管道传输到 ffmpeg,如下所示:

$ python capture.py | ffmpeg -f image2pipe -pix_fmt bgr8 -i - -s 640x480 foo.avi

Sadly, I can't get the ffmpeg magic incantation quite right and it fails with

可悲的是,我无法完全正确地获得 ffmpeg 魔法咒语,并且它失败了

  libavutil     50.15. 1 / 50.15. 1
  libavcodec    52.72. 2 / 52.72. 2
  libavformat   52.64. 2 / 52.64. 2
  libavdevice   52. 2. 0 / 52. 2. 0
  libavfilter    1.19. 0 /  1.19. 0
  libswscale     0.11. 0 /  0.11. 0
  libpostproc   51. 2. 0 / 51. 2. 0
Output #0, avi, to 'out.avi':
    Stream #0.0: Video: flv, yuv420p, 640x480, q=2-31, 19660 kb/s, 90k tbn, 30 tbc
[image2pipe @ 0x1508640]max_analyze_duration reached
[image2pipe @ 0x1508640]Estimating duration from bitrate, this may be inaccurate
Input #0, image2pipe, from 'pipe:':
  Duration: N/A, bitrate: N/A
    Stream #0.0: Video: 0x0000, bgr8, 25 fps, 25 tbr, 25 tbn, 25 tbc
swScaler: 0x0 -> 640x480 is invalid scaling dimension
  • The captured frames are definitely 640x480.
  • I'm pretty sure the pixel order for the OpenCV image type (IplImage) is GBR, one byte per channel. At least, that's what seems to be coming off the camera.
  • 捕获的帧绝对是 640x480。
  • 我很确定 OpenCV 图像类型 (IplImage) 的像素顺序是 GBR,每个通道一个字节。至少,这似乎是从相机中消失的。

I'm no ffmpeg guru. Has anyone done this successfully?

我不是 ffmpeg 大师。有没有人成功地做到了这一点?

采纳答案by BrianTheLion

Took a bunch of fiddling but I figured it out using the FFmpeg rawvideo demuxer:

花了一堆摆弄,但我想通了使用 FFmpeg rawvideo demuxer

python capture.py | ffmpeg -f rawvideo -pixel_format bgr24 -video_size 640x480 -framerate 30 -i - foo.avi

Since there is no header in raw video specifying the assumed video parameters, the user must specify them in order to be able to decode the data correctly:

由于原始视频中没有指定假定视频参数的标头,因此用户必须指定它们才能正确解码数据:

  • -framerateSet input video frame rate. Default value is 25.
  • -pixel_formatSet the input video pixel format. Default value is yuv420p.
  • -video_sizeSet the input video size. There is no default, so this value must be specified explicitly.
  • -framerate设置输入视频帧率。默认值为 25。
  • -pixel_format设置输入视频像素格式。默认值为 yuv420p。
  • -video_size设置输入视频大小。没有默认值,因此必须明确指定此值。

And here's a little something extra for the power users. Same thing but using VLC to stream the live output to the web, Flash format:

这里有一些额外的东西给高级用户。同样的事情,但使用 VLC 将实时输出流式传输到网络,Flash 格式:

python capture.py | cvlc --demux=rawvideo --rawvid-fps=30 --rawvid-width=320 --rawvid-height=240  --rawvid-chroma=RV24 - --sout "#transcode{vcodec=h264,vb=200,fps=30,width=320,height=240}:std{access=http{mime=video/x-flv},mux=ffmpeg{mux=flv},dst=:8081/stream.flv}"

Edit: Create a webm stream using ffmpeg and ffserver

编辑:使用 ffmpeg 和 ffserver 创建 webm 流

python capture.py | ffmpeg -f rawvideo -pixel_format rgb24 -video_size 640x480 -framerate 25 -i - http://localhost:8090/feed1.ffm

回答by hgabe

Took me an hour to figure out that by default, windows pipes are not binary. This causes some bytes (specifically newlines) to be modified/omitted, and the resulting video is slowly shifting because the frame size is not constant.

我花了一个小时才弄清楚默认情况下,Windows 管道不是二进制的。这会导致一些字节(特别是换行符)被修改/省略,并且生成的视频正在缓慢移动,因为帧大小不是恒定的。

To work this around, the modified python file:

为了解决这个问题,修改后的 python 文件:

"""
videoCapture.py
"""
import cv2, sys
import time

if sys.platform == "win32":
    import os, msvcrt
    msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)

cap = cv2.VideoCapture(0)                    # 0 is for /dev/video0
while True :
    ret, frm = cap.read()
    sys.stdout.write( frm.tostring() )

To test if piping the raw video is successful, use ffplay. Make sure you specify a higher framerate than what is coming from the pipe, otherwise the video will start to lag

要测试管道原始视频是否成功,请使用 ffplay。确保您指定的帧率高于来自管道的帧率,否则视频将开始滞后

python videoCapture.py | ffplay -f rawvideo -pix_fmt bgr24 -s 640x480 -framerate 40 -i -

回答by Matt W

Not sure if this is Mac OS-specific, or python3-specific, but I needed to cast the frame to a string in order for this to work for me, like so:

不确定这是 Mac OS 特定的还是 python3 特定的,但我需要将框架转换为字符串才能使其对我有用,如下所示:

sys.stdout.write(str(frame.tostring()))

回答by abhiTronix

I'm Kind of late, But my powerful VidGearPython Library automates the process of pipelining OpenCV frames into FFmpeg on any platform. Here's a basic python example:

我有点晚了,但是我强大的VidGearPython 库可以在任何平台上自动将 OpenCV 帧流水线化为 FFmpeg 的过程。这是一个基本的python示例:

# import libraries
from vidgear.gears import WriteGear
import cv2

output_params = {"-vcodec":"libx264", "-crf": 0, "-preset": "fast"} #define (Codec,CRF,preset) FFmpeg tweak parameters for writer

stream = cv2.VideoCapture(0) #Open live webcam video stream on first index(i.e. 0) device

writer = WriteGear(output_filename = 'Output.mp4', compression_mode = True, logging = True, **output_params) #Define writer with output filename 'Output.mp4' 

# infinite loop
while True:

    (grabbed, frame) = stream.read()
    # read frames

    # check if frame empty
    if not is grabbed:
        #if True break the infinite loop
        break


    # {do something with frame here}
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # write a modified frame to writer
        writer.write(gray) 

        # Show output window
    cv2.imshow("Output Frame", frame)

    key = cv2.waitKey(1) & 0xFF
    # check for 'q' key-press
    if key == ord("q"):
        #if 'q' key-pressed break out
        break

cv2.destroyAllWindows()
# close output window

stream.release()
# safely close video stream
writer.close()
# safely close writer

Source: https://github.com/abhiTronix/vidgear/wiki/Compression-Mode:-FFmpeg#2-writegear-apicompression-mode-with-opencv-directly

来源:https: //github.com/abhiTronix/vidgear/wiki/Compression-Mode: -FFmpeg#2-writegear-apicompression-mode-with-opencv-directly

You can check out VidGear Docsfor more advanced applications and features.

您可以查看VidGear Docs以获取更高级的应用程序和功能。

Hope that helps!

希望有帮助!