2016-05-20 8 views
4

いくつかのopencvプロセスをgstreamerパイプラインに追加し、それをudpsink経由で送信したいとします。gstreamerパイプラインにopencv matを書き込む方法は?

私はこのようなのgstreamerからフレームを読むことができるよ:

// may add some plugins to the pipeline later 
cv::VideoCapture cap("v4l2src ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB ! videoconvert ! appsink"); 
cv::Mat frame; 
while(ture){ 
    cap >> frame; 
    // do some processing to the frame 
} 

しかし、何を把握することはできませんするには、次のパイプラインに処理されたフレームを渡す方法です:appsrc ! x264enc ! mpegtsmux ! udpsink host=localhost port=5000

私はしました

cv::VideoWriter writer = cv::VideoWriter("appsrc ! x264enc ! mpegtsmux ! udpsink host=localhost port=5000", 0, (double)30, cv::Size(640, 480), true); 
writer << processedFrame; 

を試してみましたが、受信側では何も受信しません。 (私は受信機として$gst-launch-1.0 udpsrc port=5000 ! tsparse ! tsdemux ! h264parse ! avdec_h264 ! videoconvert ! ximagesink sync=falseパイプラインを使用します)

私の質問は、私はgstreamerパイプラインに処理されたopencv Matを渡して、何らかのエンコーディングをさせてから、udpsinkでネットワーク経由で送信できますか?「はい」の場合、これをどのように達成できますか?

私はVideoWriterをデバッグする方法はありますか?フレームが実際に書き込まれているかどうかのチェックなど。

私は、ubuntu 14.04でopencv 2.4.12とgstreamer 1.2を使用しています。

どのようなヘルプも素晴らしいです!

EDIT: の詳細情報を提供するために、私は次のコードをテストし、それがどうやらそこappsrcパイプラインと間違って何かがありますが、私はので、何が悪かったのか見当がつかないGStreamer Plugin: Embedded video playback halted; module appsrc0 reported: Internal data flow error.

#include <stdio.h> 
#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/opencv.hpp> 

int main(int argc, char *argv[]){ 
    cv::VideoCapture cap("v4l2src ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB ! videoconvert ! appsink"); 
    if (!cap.isOpened()) { 
     printf("=ERR= can't create capture\n"); 
     return -1; 
    } 
    cv::VideoWriter writer; 
    // problem here 
    writer.open("appsrc ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB ! autovideoconvert ! ximagesink sync=false", 0, (double)30, cv::Size(640, 480), true); 
    if (!writer.isOpened()) { 
     printf("=ERR= can't create writer\n"); 
     return -1; 
    } 

    cv::Mat frame; 
    int key; 

    while (true) { 
     cap >> frame; 
     if (frame.empty()) { 
      printf("no frame\n"); 
      break; 
     } 
     writer << frame; 
     key = cv::waitKey(30); 
    } 

    cv::destroyWindow("video"); 
} 

を与えましたパイプラインgst-launch-1.0 v4l2src ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB ! videoconvert ! ximagesink sync=falseは正常に動作します。

+0

appsrc要素に適切な上限を設定する必要があります(機能 - appsrcの引数はcapsと呼ばれます) - どの形式が 'processedFrame'ですか? – nayana

+0

私はappsrcにsourceと同じ 'video/x-raw、frameerate = 30/1、width = 640、height = 480、format = RGB'を設定しようとしましたが、動作しませんでした。 gstreamerの大文字のopencv Matのフォーマットを調べる方法はありますか? – j0e1in

答えて

9

:何私はキャップのためcaps=属性を使用することを意図していないが、そうでないかもしれない違いがある - それはあなたがアップデートとして計上コードに、appsrc

3からincommingのバッファを列挙しなければなりません私は最終的に答えを得ました。 appsrcの後にキーを使用するのはvideoconvertなので、キャップを設定する必要はありません。したがって、ライターのパイプラインはappsrc ! videoconvert ! x264enc ! mpegtsmux ! udpsink host=localhost port=5000のようになります。

次は、gstreamerパイプラインから画像を読み取り、opencv画像処理をいくつか行い、パイプラインに書き戻すサンプルコードです。

この方法では、任意のopencvプロセスをgstreamerパイプラインに簡単に追加できます。

// Compile with: $ g++ opencv_gst.cpp -o opencv_gst `pkg-config --cflags --libs opencv` 

#include <stdio.h> 
#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/opencv.hpp> 

int main(int argc, char** argv) { 

    // Original gstreamer pipeline: 
    //  == Sender == 
    //  gst-launch-1.0 v4l2src 
    //  ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB 
    //  ! videoconvert 
    //  ! x264enc noise-reduction=10000 tune=zerolatency byte-stream=true threads=4 
    //  ! mpegtsmux 
    //  ! udpsink host=localhost port=5000 
    //  
    //  == Receiver == 
    //  gst-launch-1.0 -ve udpsrc port=5000 
    //  ! tsparse ! tsdemux 
    //  ! h264parse ! avdec_h264 
    //  ! videoconvert 
    //  ! ximagesink sync=false 

    // first part of sender pipeline 
    cv::VideoCapture cap("v4l2src ! video/x-raw, framerate=30/1, width=640, height=480, format=RGB ! videoconvert ! appsink"); 
    if (!cap.isOpened()) { 
     printf("=ERR= can't create video capture\n"); 
     return -1; 
    } 

    // second part of sender pipeline 
    cv::VideoWriter writer; 
    writer.open("appsrc ! videoconvert ! x264enc noise-reduction=10000 tune=zerolatency byte-stream=true threads=4 ! mpegtsmux ! udpsink host=localhost port=9999" 
       , 0, (double)30, cv::Size(640, 480), true); 
    if (!writer.isOpened()) { 
     printf("=ERR= can't create video writer\n"); 
     return -1; 
    } 

    cv::Mat frame; 
    int key; 

    while (true) { 

     cap >> frame; 
     if (frame.empty()) 
      break; 

     /* Process the frame here */ 

     writer << frame; 
     key = cv::waitKey(30); 
    } 
} 

これが役に立ちます。 ;)

+0

こんにちは!私はNGINXメディアサーバーであるRTMPストリームにフレームをプッシュしたいのと同じ問題を抱えていますが、動作していないし、またHTMLページで直接開こうとしました。 –

1

[OK]を、これは...その答えないコメントのために長いが、いくつかのヒントです:

1A、レシーバ側で受け取っているかどうか確認するために使用ネットキャスト.. そのシンプル:チェックより

shell> nc -l 5000 -u 

受信者に何かを送信するときに何が印刷されているのですか?ncはすべてを画面にダンプするように設定されています..

1b、受信者用にvlcを試して、デバッグメッセージ(Tools> Messages - Ctrl + M)を押します。 ..

appsrc ! x264enc ! mpegtsmux ! rtpmp2tpay ! udpsink host=localhost port=5000 

その後、VLC rtp://@:5000である:

はところであなたは、パイプのRTPでそれをテストすることができ.. 2デバッグに続いてオープンネットワークストリームをログレバーを設定し、URLとして udp://@:5000を使用アイデンティティの要素を使用してappsrc後に流れるいただきまし

2、(非常に有用..私はデバッグパイプの問題にしばしばそれを使用する)チェック:

変更(アイデンティティの要素に注意しudpsinkため-v)にごパイプ:

cv::VideoWriter writer = cv::VideoWriter("appsrc ! identity silent=false ! x264enc ! mpegtsmux ! udpsink -v host=localhost port=5000", 0, (double)30, cv::Size(640, 480), true); 

次に、コードを実行して出力を確認します。検索の時間後

writer.open("appsrc caps="video/x-raw, framerate=30/1, width=640, height=480, format=RGB" ! autovideoconvert ! ximagesink sync=false", 0, (double)30, cv::Size(640, 480), true); 
+0

ありがとうございます。返事が遅れて申し訳ありません。私はすべての方法を試しましたが、appsrcパイプラインで 'Internal data flow error 'を得ました。私はパイプラインで必要なものを逃したと思う。 – j0e1in

関連する問題