2012-05-01 8 views
9

मैं निम्नलिखित करने का प्रयास कर रहा हूं: gstreamer का उपयोग करके वीडियो स्ट्रीम प्राप्त करें और इसे opencv के साथ संसाधित करें। मुझे कुछ समाधान मिल गए हैं, और उनमें से एक वीडियो को (gstreamer से) फीफो में लिखना है और फिर इसे ओपनसीवी का उपयोग करके पढ़ना है। (OPTION3 यहां MJPEG streaming and decoding)। समस्या यह है कि मैं पाइप खोल नहीं सकता है। cvCreateFileCapture बस कभी वापस नहीं आता है। यहां एक भाग कोड लिखा गया है:gstreamer एप्लिकेशन को opencv प्रसंस्करण जोड़ना

if(mkfifo("fifo.avi", S_IRUSR| S_IWUSR) == -1) 
{ 
    cout<<"Cant create fifo"<<endl; 
    cout<<errno<<endl; 
} 

loop = g_main_loop_new(NULL, false); 

fsink = gst_element_factory_make("filesink", "fsink"); 
g_object_set(G_OBJECT(fsink), "location", "fifo.avi", NULL); 

playbin = gst_element_factory_make("playbin2", "play");  
g_object_set(G_OBJECT(playbin), "uri", uri.c_str(), NULL); 
g_object_set(G_OBJECT(playbin), "video-sink", fsink, NULL); 

bus = gst_pipeline_get_bus(GST_PIPELINE(playbin)); 
gst_bus_add_signal_watch(bus); 

g_signal_connect(bus, "message::buffering", G_CALLBACK(&set_playbin_state), playbin); 
gst_object_unref(bus); 

cvNamedWindow("output", CV_WINDOW_AUTOSIZE); 
capture = cvCreateFileCapture("fifo.avi"); 

कार्यक्रम अंतिम पंक्ति में ढेर है। पीएस: मैं opencv 2.3.1 का उपयोग कर रहा हूँ।

उत्तर

11

तो। थोड़ी देर के बाद, मुझे एक समाधान मिला है, जिसमें बफर से डेटा पुनर्प्राप्त करना शामिल है। तो विचार प्लेबिन बनाना और ऐपसंक को "वीडियो-सिंक" के रूप में सेट करना है। यहां कोड नमूना है:

cout<<"Creating appsink"<<endl; 
appsink = gst_element_factory_make("appsink", "asink"); 
gst_app_sink_set_emit_signals((GstAppSink*)appsink, true); 
gst_app_sink_set_drop((GstAppSink*)appsink, true); 
gst_app_sink_set_max_buffers((GstAppSink*)appsink, 1); 

//creating and initialising pipeline 

g_object_set(G_OBJECT(playbin), "video-sink", appsink, NULL); 

g_signal_connect(appsink, "new-buffer", G_CALLBACK(DisplayFrame), (gpointer) mark); 

//callback function looks like this 

gboolean Core::DisplayFrame(GstAppSink *fks, gpointer mark) 
{ 
static bool init = false; 
static IplImage *frame; 
GstBuffer* buf; 
Mark* mk = (Mark*) mark; 

if(!init) 
{ 
    init = true; 
    frame = cvCreateImage(cvSize(mk->frame_w, mk->frame_h), IPL_DEPTH_8U, 1); 
} 
buf = gst_app_sink_pull_buffer(fks); 
frame->imageData = (char*)GST_BUFFER_DATA(buf); 

ProcessFrame(frame); 
gst_buffer_unref(buf); 
return true; 
} 

यह काम करता है। पीएस। इस विधि के बारे में बहुत सारी जानकारी है, लेकिन मैंने इसके लिए बहुत समय बिताया। तो मैंने खोज करने के लिए कम से कम कुछ कीवर्ड प्रदान करने के लिए इसे यहां पोस्ट करने का निर्णय लिया।

अद्यतन। और gstreamer और opencv को जोड़ने के बारे में थोड़ी अधिक जानकारी। यह बफर को iplimage में कनवर्ट करने के बारे में है। सबसे पहले, हमें जितना संभव हो सके रूपांतरण को आसान बनाने के लिए आरजीबी बफर प्राप्त करने की आवश्यकता है। ऐसा करने के लिए हम appsink साथ appsinks, ffmpegcolorspace को

cout<<"Creating appsink"<<endl; 
appsink = gst_element_factory_make("appsink", "asink"); 
gst_app_sink_set_emit_signals((GstAppSink*)appsink, true); 
gst_app_sink_set_drop((GstAppSink*)appsink, true); 
gst_app_sink_set_max_buffers((GstAppSink*)appsink, 1); 
csp = gst_element_factory_make("ffmpegcolorspace", "csp"); 
sinkpipe = gst_pipeline_new("sinkp"); 
gst_bin_add_many(GST_BIN(sinkpipe), csp, appsink, NULL); 
gst_element_link_filtered(csp, appsink, gst_caps_new_simple("video/x-raw-rgb", NULL)); 
pad = gst_element_get_static_pad(csp, "sink"); 
gst_element_add_pad(sinkpipe, gst_ghost_pad_new("ghost", pad)); 
g_object_unref(pad); 

//... 

g_object_set(G_OBJECT(playbin), "video-sink", sinkpipe, NULL); 

//... 

g_signal_connect(appsink, "new-buffer", G_CALLBACK(GetFrame), (gpointer) mark); 

//... 

//caps_struct can be retrieved via writing data probe 
//search for it in streamer manual 

cout<<"Getting frame resolution"<<endl; 
gst_structure_get_int(caps_struct, "width", &(mark->frame_w)); 
gst_structure_get_int(caps_struct, "height", &(mark->frame_h)); 
gst_structure_get_int(caps_struct, "depth", &depth); 

mark->GeneratePoints(); 
frame = cvCreateImage(cvSize(mark->frame_w, mark->frame_h), depth/3, 3); 


//callback function 

gboolean Core::GetFrame(GstAppSink *fks, gpointer frame) 
{ 

IplImage* frame_temp = frame 
IplImage* frame_temp_two = cvCloneImage(frame_temp); 

GstBuffer* buf; 
buf = gst_app_sink_pull_buffer(fks); 
frame_temp_two->imageData = (char*) GST_BUFFER_DATA(buf); 
cvConvertImage(frame_temp_two, frame_temp, CV_CVTIMG_SWAP_RB); 
ProcessFrame(frame_temp); 
gst_buffer_unref(buf); 
return true; 
} 

मुझे आशा है कि यह किसी को मदद मिलेगी जुड़े बदलने वाले हैं।

7

यहां Gstreamer 1.4.0 और OpenCV 2.4.9 के लिए मेरा पूरा स्रोत कोड समाधान है।

यह gst_parse_launch() का उपयोग सामान्य कमांड लाइन को पार्स करने के लिए करता है जिसे आप gst-launch पर देंगे। Gstreamer पाइपलाइन उन्हें OpenCV को खिलाने से पहले फ्रेम को RGB888 प्रारूप में परिवर्तित करता है ताकि रूपांतरण जितना संभव हो सके उतना आसान हो।

ओपनसीवी फ्रेम प्रसंस्करण new_sample() कॉलबैक में नहीं किया जाता है, लेकिन यह केवल फ्रेम को जीस्ट्रीमर से पकड़ता है और इसे कतार में धक्का देता है जो तब मुख्य धागे में खपत किया जाएगा। इस तरह हम चटाई कॉल उदा। ओपनसीवी से imshow() वास्तव में स्क्रीन पर छवि प्रस्तुत करने के लिए।

~ 150 लाइनें ... डीबग प्रिंट आदि को हटाकर < कोड की 100 पंक्तियों को घटाया जा सकता है।

शायद एक Deque पढ़ने के आसपास वहाँ धागा तुल्यकालन जोड़ें/लिखने

#include <gst/gst.h> 
#include <gst/app/gstappsink.h> 
#include <stdlib.h> 

#include "opencv2/opencv.hpp" 
using namespace cv; 

// TODO: use synchronized deque 
std::deque<Mat> frameQueue; 

GstFlowReturn 
new_preroll(GstAppSink *appsink, gpointer data) { 
    g_print ("Got preroll!\n"); 
    return GST_FLOW_OK; 
} 

GstFlowReturn 
new_sample(GstAppSink *appsink, gpointer data) { 
    static int framecount = 0; 
    framecount++; 

    GstSample *sample = gst_app_sink_pull_sample(appsink); 
    GstCaps *caps = gst_sample_get_caps(sample); 
    GstBuffer *buffer = gst_sample_get_buffer(sample); 
    const GstStructure *info = gst_sample_get_info(sample); 

    // ---- Read frame and convert to opencv format --------------- 

    GstMapInfo map; 
    gst_buffer_map (buffer, &map, GST_MAP_READ); 

    // convert gstreamer data to OpenCV Mat, you could actually 
    // resolve height/width from caps... 
    Mat frame(Size(320, 240), CV_8UC3, (char*)map.data, Mat::AUTO_STEP); 
    int frameSize = map.size; 

    // TODO: synchronize this.... 
    frameQueue.push_back(frame); 

    gst_buffer_unmap(buffer, &map); 

    // ------------------------------------------------------------ 

    // print dot every 30 frames 
    if (framecount%30 == 0) { 
    g_print ("."); 
    } 

    // show caps on first frame 
    if (framecount == 1) { 
    g_print ("%s\n", gst_caps_to_string(caps)); 
    } 

    gst_sample_unref (sample); 
    return GST_FLOW_OK; 
} 

static gboolean 
my_bus_callback (GstBus *bus, GstMessage *message, gpointer data) { 
    g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message)); 
    switch (GST_MESSAGE_TYPE (message)) { 
    case GST_MESSAGE_ERROR: { 
     GError *err; 
     gchar *debug; 

     gst_message_parse_error (message, &err, &debug); 
     g_print ("Error: %s\n", err->message); 
     g_error_free (err); 
     g_free (debug);  
     break; 
    } 
    case GST_MESSAGE_EOS: 
     /* end-of-stream */ 
     break; 
    default: 
     /* unhandled message */ 
     break; 
    } 
    /* we want to be notified again the next time there is a message 
    * on the bus, so returning TRUE (FALSE means we want to stop watching 
    * for messages on the bus and our callback should not be called again) 
    */ 
    return TRUE; 
} 

int 
main (int argc, char *argv[]) 
{ 
    GError *error = NULL; 

    gst_init (&argc, &argv); 

    gchar *descr = g_strdup(
    "videotestsrc pattern=ball ! " 
    "video/x-raw,format=RGB ! " 
    "videoconvert ! " 
    "appsink name=sink sync=true" 
); 
    GstElement *pipeline = gst_parse_launch (descr, &error); 

    if (error != NULL) { 
    g_print ("could not construct pipeline: %s\n", error->message); 
    g_error_free (error); 
    exit (-1); 
    } 

    /* get sink */ 
    GstElement *sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink"); 

    gst_app_sink_set_emit_signals((GstAppSink*)sink, true); 
    gst_app_sink_set_drop((GstAppSink*)sink, true); 
    gst_app_sink_set_max_buffers((GstAppSink*)sink, 1); 
    GstAppSinkCallbacks callbacks = { NULL, new_preroll, new_sample }; 
    gst_app_sink_set_callbacks (GST_APP_SINK(sink), &callbacks, NULL, NULL); 

    GstBus *bus; 
    guint bus_watch_id; 
    bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); 
    bus_watch_id = gst_bus_add_watch (bus, my_bus_callback, NULL); 
    gst_object_unref (bus); 

    gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); 

    namedWindow("edges",1); 
    while(1) { 
    g_main_iteration(false); 

     // TODO: synchronize... 
    if (frameQueue.size() > 0) { 
     // this lags pretty badly even when grabbing frames from webcam 
     Mat frame = frameQueue.front(); 
     Mat edges; 
     cvtColor(frame, edges, CV_RGB2GRAY); 
     GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5); 
     Canny(edges, edges, 0, 30, 3); 
     imshow("edges", edges); 
     cv::waitKey(30); 
     frameQueue.clear(); 
    } 
    } 

    gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); 
    gst_object_unref (GST_OBJECT (pipeline)); 

    return 0; 
} 

OSX/लिनक्स पर संकलन करने के लिए बनाने के इस तरह फ़ाइल करना चाहिए करना चाहिए:

GST_FLAGS=$(shell pkg-config --cflags --libs gstreamer-gl-1.0 gstreamer-tag-1.0 gstreamer-net-1.0 gstreamer-sdp-1.0 \ 
    gstreamer-1.0 gstreamer-allocators-1.0 gstreamer-insertbin-1.0 gstreamer-plugins-base-1.0 \ 
    gstreamer-codecparsers-1.0 gstreamer-base-1.0 gstreamer-app-1.0 gstreamer-check-1.0 \ 
    gstreamer-controller-1.0 gstreamer-video-1.0 gstreamer-fft-1.0 gstreamer-mpegts-1.0 \ 
    gstreamer-pbutils-1.0 gstreamer-rtp-1.0 gstreamer-rtsp-1.0 \ 
    gstreamer-riff-1.0 gstreamer-audio-1.0 gstreamer-plugins-bad-1.0 opencv) 

OPENCV_FLAGS=$(shell pkg-config --cflags --libs opencv) 

all: gst_opencv 

gst_opencv: gst_opencv 
    g++ $(GST_FLAGS) $(OPENCV_FLAGS) gst_opencv -o gst_opencv 

clean: 
    rm -f gst_opencv