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 1 #ifndef GSTREAMERVIDEOENCODER_H 2 2 #define GSTREAMERVIDEOENCODER_H 3 3 4 4 #include <QObject> 5 5 #include <QWidget> 6 6 #include <gst/gst.h> 7 7 #include <gst/app/gstappsink.h> 8 8 #include <gst/app/gstappsrc.h> 9 9 #include <glib.h> 1010 #include <iostream> 1111 #include <sstream> 1212 #include <thread> 1313 #include "../IOutputOrignalImage.h" 1414 #include "../GlobalData.h" 1515 1616 class GStreamerCameraExtract 1717 { 1818 public: 1919 GStreamerCameraExtract() {} 2020 ~GStreamerCameraExtract() {} 2121 2222 public: 2323 GstBus *bus; 2424 GstElement *pipeline; 2525 GstMessage *msg; 2626 GstElement *v4l2_src; 2727 GstAppSink* appsink; 2828 GstElement *src_caps_filter; 2929 GstCaps *caps_src; 3030 GstCaps *caps_sink; 3131 GstElement *video_convert; 3232 GstElement *h264Encoder; 3333 GstAppSinkCallbacks appsink_callbacks; 3434 QByteArray cameraBuffer; 3535 IOutputOrignalImage *callback; 3636 3737 public: 3838 int CreateCameraExtractPipeline(); 3939 void ReadLocalCameraImage(); 4040 void StopPipeline(); 4141 }; 4242 4343 #endif // GSTREAMERVIDEOENCODER_H
View Code
2、cpp文件

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