2017-07-20 6 views
2

Ich sehe eine Menge Informationen darüber, wie man einen raspivid Stream direkt an FFMPEG zum Encodieren, Muxen und Restreaming leitet, aber diese Anwendungsfälle sind meistens bash; ähnlich wie:Wie man Picamera Video zu FFMPEG mit Subprozess (Python) pipettiert

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

Ich hoffe, die Funktionalität der Picamera-Bibliothek zu nutzen, so dass ich gleichzeitige Verarbeitung mit OpenCV und ähnlichen während des Streamings mit FFMPEG machen kann. Aber ich kann nicht herausfinden, wie man FFMPEG als Subprozess richtig öffnet und Videodaten an ihn leitet. Ich habe viele Versuche gesehen, unanswered posts, und Leute claiming to have done it, aber nichts davon scheint auf meinem Pi zu funktionieren.

Sollte ich einen Videopuffer mit Picamera erstellen und das rohe Video zu FFMPEG pipen? Kann ich camera.capture_continuous() verwenden und FFMPEG die bgr24-Bilder übergeben, die ich für meine OpenCV-Berechnung verwende?

Ich habe alle möglichen Varianten ausprobiert und ich bin mir nicht sicher, ob ich nur missverstanden habe, wie man das Subprozessmodul FFMPEG benutzt oder mir einfach ein paar Einstellungen versagt. Ich verstehe, dass der Rohdatenstrom keine Metadaten hat, aber ich bin mir nicht ganz sicher, welche Einstellungen ich FFMPEG geben muss, damit er versteht, was ich ihm gebe.

Ich habe einen Wowza-Server, den ich irgendwann streamen werde, aber ich teste gerade, indem ich auf meinem Laptop zu einem VLC-Server streame. Ich habe dies zur Zeit versucht:

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

ich auch den Strom in eine Datei-ähnliches Objekt versucht haben, zu schreiben, die einfach die FFMPEG subprocess erstellt und schreibt in die stdin davon (camera.start_recording() gegeben werden kann, ein Objekt wie dieses, wenn Sie die Picam initialisieren):

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

Jede Hilfe mit diesem wäre erstaunlich!

Antwort

1

ich in der Lage gewesen PiCamera Ausgang ffmpeg mit so etwas wie die folgenden zu streamen: für

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) 

Oder ist das nicht das, was Sie suchen?

+0

mit

testOutput.exe ORIGINAL_SOURCE RTMP_OUTPUT nennen - funktioniert das überhaupt? In jedem Fall streamt OP als TS auf UDP, so dass dieser Teil unter Kontrolle ist. – hobbs

+0

Scheint für mich zu arbeiten! Die Ausgabe ist in omxplayer abspielbar. Aber ich bin offen für Verbesserungsvorschläge! –

+0

Genau das habe ich gebraucht! Ich habe die Pipes eindeutig zu dem Subprozess missbraucht, aber es hat mir geholfen, ein paar der Einstellungen zu realisieren, die ich in FFMPEG verwenden wollte, gab mir auch Probleme. Vielen Dank! – VeniVidiReliqui

0

Zwei Probleme, die ich auf den ersten Blick sehen:

  1. In Ihrem ersten Beispiel, werden Sie Ihre Daten in den Subprozess schreibt stdout statt seiner stdin. Das funktioniert definitiv nicht, und verursacht wahrscheinlich einen Hang.

  2. In beiden Beispielen starten Sie den Prozess mit stdin=sp.PIPE, stderr=sp.PIPE und lesen dann nie aus diesen Pipes. Das bedeutet, sobald ffmpeg genug Ausgabe schreibt, um den Pipe-Puffer zu füllen, wird es blockiert und Sie haben einen Deadlock. Verwenden Sie den Standardwert stdout=None, stderr=None, damit die Ausgabe von ffmpeg in das stdout- und stderr-Format Ihres Prozesses geht, oder verbinden Sie sie mit einem Dateihandle, das unter /dev/null geöffnet ist, um die Ausgabe zu verwerfen. Oder verwenden Sie die communicate Methode, um die Ausgabe jedes Mal zu erhalten, wenn Sie eine Eingabe schreiben, und tun Sie etwas Nützliches dabei (wie den Status des Streaming zu überwachen).

0

Hallo können Sie opencv & ffmpeg & ReStream es wowza oder sonst verwenden.Hier

ist eine Probe mit opencv & & ffmpeg

int main(int argc, char* argv[]) 
{ 
    if (argc < 4){ 
     cout << "eksik parametre" << endl; 
     return -1; 
    } 
    int fps = 1;      //fps degeri varsayilan 1 
    char *input_adress = argv[1];  //goruntunun alinacagi dosya yada adres bilgisi 
    char *output_adress = argv[3];  //ciktinin gonderilecegi dosya yada adres bilgisi 
    sscanf(argv[2], "%d", &fps);  //fps degeri okundu 
    VideoCapture video(input_adress); //kamera acildi 
    if (!video.isOpened()){ 
     cout << "Yayin acilamadi!!!" << endl; 
     getchar(); 
     return -1; 
    } 
    Mat frame;//frame ornegi 
    FILE *pipe;//pipe icin acilan process in input streami 
    char *cmd = (char*)calloc(100 + sizeof(output_adress), sizeof(char));//komut icin alan alindi 
    sprintf(cmd, "ffmpeg -y -f image2pipe -vcodec mjpeg -r %d -i - -r %d -vcodec libx264 -f flv %s", fps, fps, output_adress);//ffmpeg komutu 
    //ffmpeg komutu aciliyor 
    if (!(pipe = _popen(cmd, "wb"))){ 
     cout << "Acilamadi!!!" << endl; 
     return 1; 
    } 
    float wait_time = 1000.0f/(float)fps;//kac milisaniye bekletilecek 
    while (true) 
    { 
     try { 
      //videodan siradaki frame okunuyor 
      video >> frame; 
      if (frame.empty())    //eger bos frame ise video bitmis demektir 
       break; 
      adjust_brightness(frame);  //parlaklik ayarlamasini yapıyoruz 
      write_jpeg(frame, pipe);  //jpeg formatina cevirip pipe a yazıyoruz 
      if (waitKey(wait_time) >= 0) break; 
     } 
     catch (Exception ex){ 
     } 
    } 
    video.release(); 
    return 0; 
} 

in write_jpeg moethod fwrite und Fflush Berufung.

wahrscheinlich PS Behälter viel einfacher :) obwohl setzen AVC Video in einem MPEG-1 ist seltsam Dies ist Dies wird