Pipe raw OpenCV images to FFmpeg

voici un exemple assez simple de lecture d'une webcam utilisant les fixations Python D'OpenCV:

'''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() )

Maintenant, je veux rediriger la sortie vers ffmpeg comme dans:

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

malheureusement, je ne peux pas obtenir l'incantation magique ffmpeg tout à fait correcte et il échoue avec

  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
  • les cadres capturés sont certainement 640x480.
  • je suis assez sûr que l'ordre des pixels pour le type D'image OpenCV (IplImage) est GBR, un octet par canal. Moins, c'est ce que semble provenir de l'appareil.

Je ne suis pas un gourou ffmpeg. Quelqu'un a fait cela avec succès?

23
demandé sur BrianTheLion 2011-04-29 01:19:31

3 réponses

a pris un tas de violon mais j'ai compris en utilisant le FFmpeg rawvideo demuxer:

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

Puisqu'il n'y a pas d'en-tête dans la vidéo brute spécifiant les paramètres vidéo supposés, l'utilisateur doit les spécifier afin de pouvoir décoder les données correctement:

  • -framerate définir le taux de trame vidéo d'entrée. La valeur par défaut est de 25.
  • -pixel_format définir le format de pixel vidéo d'entrée. La valeur par défaut est yuv420p.
  • -video_size régler le d'entrée de taille de la vidéo. Il n'y a pas de valeur par défaut, cette valeur doit être spécifiée explicitement.

Et voici un petit quelque chose supplémentaire pour les utilisateurs d'alimentation. Même chose, mais en utilisant VLC pour diffuser la sortie en direct sur le web, format 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}"

Modifier: Créer un flux webm en utilisant ffmpeg et ffserver

python capture.py | ffmpeg -f rawvideo -pixel_format rgb24 -video_size 640x480 -framerate 25 -i - http://localhost:8090/feed1.ffm
31
répondu BrianTheLion 2017-05-29 17:09:51

m'a pris une heure pour comprendre que par défaut, les pipes windows ne sont pas binaires. Cela fait que certains octets (en particulier les lignes) sont modifiés / omis, et la vidéo résultante se déplace lentement parce que la taille du cadre n'est pas constante.

À ce travail autour de, la modification de fichier 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() )

pour tester si piping la vidéo brute est réussie, utilisez ffplay. Assurez-vous que vous spécifiez un framerate plus élevé que ce qui vient de la pipe, sinon la vidéo va démarrer à la traîne

python videoCapture.py | ffplay -f rawvideo -pix_fmt bgr24 -s 640x480 -framerate 40 -i -
1
répondu hgabe 2016-08-06 11:09:49

Je ne suis pas sûr que ce soit spécifique à Mac OS, ou à python3, mais j'avais besoin de lancer le cadre sur une chaîne pour que cela fonctionne pour moi, comme ça:

sys.stdout.write(str(frame.tostring()))
0
répondu Matt W 2018-03-21 17:47:23