1、這里有個簡單的例子,可以看看GStreamer如何編程的。
2、GStreamer GstAppSink的官方Document,翻譯了一下它的描述部分,點擊這里。
3、GStreamer GstAppSrc的官方Document,翻譯了以下它的描述部分,點擊這里。
4、GStreamer中的Padscapabilities
Pads 允許信息進入或者離開一個element,這個Capabilities(簡稱Caps)就是指定哪些信息可以通過Pad來傳輸。例如:“RGB視頻,尺寸為320*200並且每秒30幀”或者“16位的音頻采樣,5.1聲道,每秒采樣44.1k” 甚至可以是類似於mp3/h264之類的壓縮格式。
Pads支持多重Capabilities(比如,一個視頻的sink可以支持RGB輸出或者YUV輸出),Capabilites可以指定一個范圍而不必須是一個特定值(比如,一個音頻sink可以支持從1~48000的采樣率)。然而,數據從一個pad流向另一個pad的時候,必須是一個雙方都能支持的格式。某一種數據形式是兩個pad都能支持的,這樣pads的Capabilities就固定下來,這個過程就被稱為協商。
作為一個應用開發者,我們通常都是用連接一個個element的方法來建立pipeline的,在這里,你需要了解使用的element的Pad的Caps。
5、Pad模板
Pad是由Pad模板創建的,模板里面會列出一個Pad所有可能的Capabilities。模板對於創建幾個相似的Pad是很有幫助的,但也會比較早的判斷出兩個element是否可以連接:如果兩個Pad的模板都不具備共同的子集的話,就沒有必要進行更深層的協商了。
Pad模板檢查是協商流程的第一步。隨着流程的逐步深入,Pad會正式初始化,也會確定他們的Capability(除非協商失敗)
6、queue
queue element會創建一個新的線程。通常來說,有多於一個sink element時就需要使用多個線程。這是因為在同步時,sink通常是阻塞起來等待其他的sink都准備好,如果僅僅只有一個線程是如法做到這一點的。
7、tee
tee比較特別但很有用,tee有1個輸入pad而沒有輸出pad,需要有申請,tee才會生成。通過這種方法,輸入流可以被復制成多份。和Always Pad比起來,Request Pad因為並非一直存在,所以是不能自動連接element的。
例子:
建立一個如上的pipeline的步驟如下:
1)初始化GStreamer;
2)創建上圖中的所有element;
3)創建pipeline;
4)配置element;
5)把element放進pipeline中,然后將可以連接起來的原件連接起來;
(1)app source -> tee (2)audio_queue -> audio_convert -> audio_resample -> audio_sink (3)video_queue ->wave_scope->video_convert->video_sink
6) 手工連接tee->audio_queue和tee->video_queue;
7)設置pipeline狀態為PLAYING;
8)監測BUS信號即可。
上訴過程的代碼可以參考官方文檔:https://gstreamer.freedesktop.org/documentation/tutorials/basic/multithreading-and-pad-availability.html
同時也可以參考《GStreamer講解.pdf》 P56。
關於上面的第6步,兩個參考講解還有一點不一致,官方文檔更簡單,需要進一步測試才能確定這兩種方式是不是都可行。
從GStreamer獲取攝像頭數據的代碼:
1、h文件

1 #ifndef GSTREAMERVIDEOENCODER_H 2 #define GSTREAMERVIDEOENCODER_H 3 4 #include <QObject> 5 #include <QWidget> 6 #include <gst/gst.h> 7 #include <gst/app/gstappsink.h> 8 #include <gst/app/gstappsrc.h> 9 #include <glib.h> 10 #include <iostream> 11 #include <sstream> 12 #include <thread> 13 #include "../IOutputOrignalImage.h" 14 #include "../GlobalData.h" 15 16 class GStreamerCameraExtract 17 { 18 public: 19 GStreamerCameraExtract() {} 20 ~GStreamerCameraExtract() {} 21 22 public: 23 GstBus *bus; 24 GstElement *pipeline; 25 GstMessage *msg; 26 GstElement *v4l2_src; 27 GstAppSink* appsink; 28 GstElement *src_caps_filter; 29 GstCaps *caps_src; 30 GstCaps *caps_sink; 31 GstElement *video_convert; 32 GstElement *h264Encoder; 33 GstAppSinkCallbacks appsink_callbacks; 34 QByteArray cameraBuffer; 35 IOutputOrignalImage *callback; 36 37 public: 38 int CreateCameraExtractPipeline(); 39 void ReadLocalCameraImage(); 40 void StopPipeline(); 41 }; 42 43 #endif // GSTREAMERVIDEOENCODER_H
2、cpp文件

1 #include "GStreamerCameraExtract.h" 2 3 static GstFlowReturn appsink_new_sample_callback(GstAppSink *slt,gpointer user_data) 4 { 5 GStreamerCameraExtract *encoder = (GStreamerCameraExtract *)user_data; 6 7 encoder->ReadLocalCameraImage(); 8 } 9 10 void GStreamerCameraExtract::ReadLocalCameraImage() 11 { 12 gint height; 13 gint width; 14 15 GstSample * sample = gst_app_sink_pull_sample(appsink); 16 17 GstBuffer * gstImageBuffer= gst_sample_get_buffer(sample); 18 GstCaps * caps = gst_sample_get_caps(sample); 19 const GstStructure *caps_st = gst_caps_get_structure (caps, 0); 20 21 if ((gst_structure_get_int (caps_st, "width", &width) != 0) && \ 22 (gst_structure_get_int (caps_st, "height", &height) != 0) ) 23 { 24 cameraBuffer.resize(width*height*3); 25 26 gst_buffer_extract(gstImageBuffer, 0, cameraBuffer.data(), cameraBuffer.size()); 27 28 callback->OutputOrignalImage(&cameraBuffer); 29 } 30 31 gst_buffer_unref(gstImageBuffer); 32 //gst_sample_unref(sample); //一定不能添加這一句 33 } 34 35 void GStreamerCameraExtract::StopPipeline() 36 { 37 gst_element_set_state(pipeline,GST_STATE_NULL); 38 g_object_unref(pipeline); 39 40 g_object_unref(bus); 41 } 42 43 int GStreamerCameraExtract::CreateCameraExtractPipeline() 44 { 45 pipeline = gst_pipeline_new("mypipeline"); 46 v4l2_src = gst_element_factory_make("v4l2src","src"); 47 src_caps_filter = gst_element_factory_make("capsfilter","srccapsfilter"); 48 caps_src = gst_caps_new_simple("video/x-raw", 49 "width",G_TYPE_INT,PICTURE_WIDTH, 50 "height",G_TYPE_INT,PICTURE_HEIGHT, 51 "framerate",GST_TYPE_FRACTION,FRAME_PER_SECOND,1, 52 NULL); 53 caps_sink = gst_caps_new_simple("video/x-raw", 54 "format",G_TYPE_STRING,"RGB", 55 "colorimetry",G_TYPE_STRING,"bt709", 56 "width",G_TYPE_INT,PICTURE_WIDTH, 57 "height",G_TYPE_INT,PICTURE_HEIGHT,NULL); 58 video_convert = gst_element_factory_make("videoconvert","videoconv"); 59 appsink = (GstAppSink*)gst_element_factory_make("appsink","sink1"); 60 61 if(!pipeline || !v4l2_src ||!src_caps_filter \ 62 ||!caps_src ||!appsink \ 63 ||!caps_sink || !video_convert ) 64 { 65 std::cout<<"create element error"<<std::endl; 66 return -1; 67 } 68 69 g_object_set(v4l2_src,"device",CAMERA_DEVICE_NAME,NULL); 70 71 g_object_set(src_caps_filter,"caps",caps_src,NULL); 72 gst_caps_unref(caps_src); 73 74 gst_app_sink_set_caps(appsink,caps_sink); 75 gst_caps_unref(caps_sink); 76 77 gst_bin_add_many(GST_BIN(pipeline),v4l2_src,src_caps_filter,video_convert,appsink,NULL); 78 79 if(gst_element_link_many(v4l2_src,src_caps_filter,video_convert,appsink,NULL) == FALSE) 80 { 81 std::cout<<"link src & appsink error!"<<std::endl; 82 gst_object_unref(pipeline); 83 return -1; 84 } 85 86 gst_app_sink_set_drop(appsink, true); 87 gst_app_sink_set_max_buffers(appsink, 1); 88 89 appsink_callbacks = {NULL,NULL,appsink_new_sample_callback,NULL}; 90 gst_app_sink_set_callbacks(appsink,&appsink_callbacks,this,NULL); 91 92 g_signal_connect(pipeline, "deep-notify", G_CALLBACK(gst_object_default_deep_notify), NULL); 93 94 int ret = gst_element_set_state(pipeline,GST_STATE_PLAYING); 95 if(ret == GST_STATE_CHANGE_FAILURE) 96 { 97 std::cout<<"set playing state error!"<<std::endl; 98 } 99 100 bus = gst_element_get_bus(pipeline); 101 102 return 0; 103 }
使用GStreamer 將攝像頭數據采用硬件編碼為H264格式數據的代碼,暫不貼出了。