├── CMakeLists.txt ├── README.md ├── demo_gstreamer_1_version.cpp ├── demo_gstreamer_2_init.cpp ├── demo_gstreamer_3_element_factory.cpp ├── demo_gstreamer_4_get_element_info.cpp ├── demo_gstreamer_5_link_elements.cpp ├── demo_gstreamer_6_pads.cpp ├── demo_gstreamer_8_helloworld.cpp └── demo_gstreamer_rtsp.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(gstreamer_learn) 3 | set(CMAKE_CXX_STANDARD 11) 4 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 5 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread -g") 6 | 7 | 8 | MESSAGE(STATUS "operation system is ${CMAKE_SYSTEM}") 9 | MESSAGE(STATUS "CMAKE_SYSTEM_NAME is ${CMAKE_SYSTEM}") 10 | IF (CMAKE_SYSTEM_NAME MATCHES "Linux") 11 | MESSAGE(STATUS "current platform: Linux ") 12 | ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Windows") 13 | MESSAGE(STATUS "current platform: Windows") 14 | ELSEIF (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") 15 | MESSAGE(STATUS "current platform: FreeBSD") 16 | ELSE () 17 | MESSAGE(STATUS "other platform: ${CMAKE_SYSTEM_NAME}") 18 | ENDIF (CMAKE_SYSTEM_NAME MATCHES "Linux") 19 | 20 | 21 | if(${CMAKE_SYSTEM} MATCHES "Linux-4.9.140-tegra") 22 | message("On TEGRA PLATFORM.") 23 | add_definitions(-DPLATFORM_TEGRA) 24 | set(SYS_USR_LIB /usr/lib/aarch64-linux-gnu) 25 | set(SYS_LIB /lib/aarch64-linux-gnu) 26 | set(DS_LIB /opt/nvidia/deepstream/deepstream-4.0/lib) 27 | else() 28 | message("On X86 PLATFORM.") 29 | set(SYS_USR_LIB /usr/lib/x86_64-linux-gnu) 30 | set(SYS_LIB /lib/x86_64-linux-gnu) 31 | endif() 32 | 33 | include_directories( 34 | includes 35 | /usr/include/gstreamer-1.0 36 | /usr/include/glib-2.0 37 | ${SYS_USR_LIB}/glib-2.0/include 38 | ) 39 | link_libraries( 40 | ${SYS_USR_LIB}/libgtk3-nocsd.so.0 41 | ${SYS_USR_LIB}/libgstreamer-1.0.so.0 42 | ${SYS_USR_LIB}/libgobject-2.0.so.0 43 | ${SYS_USR_LIB}/libglib-2.0.so.0 44 | ${SYS_LIB}/libc.so.6 45 | # /lib/ld-linux-aarch64.so.1 46 | ${SYS_LIB}/libdl.so.2 47 | ${SYS_LIB}/libpthread.so.0 48 | ${SYS_USR_LIB}/libgmodule-2.0.so.0 49 | ${SYS_LIB}/libm.so.6 50 | ${SYS_USR_LIB}/libffi.so.6 51 | ${SYS_LIB}/libpcre.so.3 52 | ) 53 | 54 | add_executable(demo_1_version_ demo_gstreamer_1_version.cpp) 55 | add_executable(demo_2_init_ demo_gstreamer_2_init.cpp) 56 | add_executable(demo_3_element_fac_ demo_gstreamer_3_element_factory.cpp) 57 | add_executable(demo_4_get_element_info_ demo_gstreamer_4_get_element_info.cpp) 58 | add_executable(demo_5_link_elements_ demo_gstreamer_5_link_elements.cpp) 59 | add_executable(demo_6_pads_ demo_gstreamer_6_pads.cpp) 60 | add_executable(demo_8_helloworld_ demo_gstreamer_8_helloworld.cpp) 61 | 62 | add_executable(demo_gstreamer_rtsp_ demo_gstreamer_rtsp.cpp) 63 | 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gstreamer_learn 2 | 我用来学习GStreamer的程序,内部有多个demo,只依赖GStreamer,可以自己编译并运行、调试和学习。 3 | 4 | 依赖:GStreamer 5 | ```shell 6 | sudo apt install \ 7 | libssl1.0.0 \ 8 | libgstreamer1.0-0 \ 9 | gstreamer1.0-tools \ 10 | gstreamer1.0-plugins-good \ 11 | gstreamer1.0-plugins-bad \ 12 | gstreamer1.0-plugins-ugly \ 13 | gstreamer1.0-libav \ 14 | libgstrtspserver-1.0-0 \ 15 | libjansson4=2.11-1 16 | ``` 17 | 18 | 编译: 19 | ```shell 20 | mkdir build 21 | cd build 22 | cmake .. 23 | make 24 | ``` 25 | 26 | 运行: 27 | ```shell 28 | ./demo_1_version_ 29 | ./demo_2_init_ 30 | ./demo_3_element_fac_ 31 | ./demo_4_get_element_info_ 32 | ./demo_5_link_elements_ 33 | ./demo_6_pads_ 34 | ./demo_8_helloworld_ 35 | ./demo_gstreamer_rtsp_ 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /demo_gstreamer_1_version.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by toson on 20-2-10. 3 | // 4 | 5 | #include "cstdio" 6 | #include 7 | 8 | int main(int argc, char *argv[]) { 9 | const gchar *nano_str; 10 | guint major, minor, micro, nano; 11 | 12 | gst_version(&major, &minor, µ, &nano); 13 | 14 | if (nano == 1) 15 | nano_str = "(CVS)"; 16 | else if (nano == 2) 17 | nano_str = "(Prerelease)"; 18 | else 19 | nano_str = ""; 20 | 21 | printf("This program is linked against GStreamer %d.%d.%d %s\n", 22 | major, minor, micro, nano_str); 23 | printf("This program is linked against GStreamer %d.%d.%d %d\n", 24 | GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO, GST_VERSION_NANO); 25 | 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /demo_gstreamer_2_init.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by toson on 20-2-10. 3 | // 4 | // 简易初始化 5 | 6 | #include "cstdio" 7 | #include 8 | 9 | //你可以使用GST_VERSION_MAJOR, GST_VERSION_MINOR以及GST_VERSION_MICRO 三个宏得到你的GStreamer版本信息, 10 | //或者使用函数gst_version得到当前你所调用的程序库的版本信息。 11 | //目前GStreamer使用了一种 保证主要版本和次要版本中API-/以及ABI兼容的策略。 12 | //当命令行参数不需要被GStreamer解析的时候,你可以在调用函数gst_init时使用2个NULL参数。 13 | //注[1] 这个例子中的代码可以直接提取出来,并在GStreamer的examples/manual目录下可以找到。 14 | //———————————————— 15 | //版权声明:本文为CSDN博主「北雨南萍」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 16 | //原文链接:https://blog.csdn.net/fireroll/article/details/46859973 17 | int main(int argc, char *argv[]) { 18 | guint major, minor, micro, nano; 19 | gst_version(&major, &minor, µ, &nano); 20 | printf("GStreamer version: %d.%d.%d %s\n", 21 | major, minor, micro, nano == 1 ? "(CVS)" : nano == 2 ? "(Prerelease)" : ""); 22 | 23 | gst_init(&argc, &argv); 24 | 25 | return 0; 26 | } 27 | 28 | 29 | //你同样可以使用GOption表来初始化你的参数。 30 | //如例子中的代码所示,你可以通过 GOption 表来定义你的命令行选项。 31 | //将表与由 gst_init_get_option_group 函数返回的选项组一同传给GLib初始化函数。 32 | //通过使用GOption表来初始化GSreamer,你的程序还可以解析除标准GStreamer选项以外的命令行选项. 33 | //———————————————— 34 | //版权声明:本文为CSDN博主「北雨南萍」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 35 | //原文链接:https://blog.csdn.net/fireroll/article/details/46859973 36 | #include 37 | 38 | int main1(int argc, char *argv[]) { 39 | guint major, minor, micro, nano; 40 | gst_version(&major, &minor, µ, &nano); 41 | printf("GStreamer version: %d.%d.%d %s\n", major, minor, micro, 42 | nano == 1 ? "(CVS)" : nano == 2 ? "(Prerelease)" : ""); 43 | 44 | gboolean silent = FALSE; 45 | gchar *savefile = NULL; 46 | GOptionContext *ctx; 47 | GError *err = NULL; 48 | GOptionEntry entries[] = { 49 | {"silent", 's', 0, G_OPTION_ARG_NONE, &silent, 50 | "do not output status information", NULL}, 51 | {"output", 'o', 0, G_OPTION_ARG_STRING, &savefile, 52 | "save xml representation of pipeline to FILE and exit", "FILE"}, 53 | {NULL} 54 | }; 55 | 56 | ctx = g_option_context_new("- Your application"); 57 | g_option_context_add_main_entries(ctx, entries, NULL); 58 | g_option_context_add_group(ctx, gst_init_get_option_group()); 59 | if (!g_option_context_parse(ctx, &argc, &argv, &err)) { 60 | g_print("Failed to initialize: %s\n", err->message); 61 | g_error_free(err); 62 | return 1; 63 | } 64 | 65 | printf("Run me with --help to see the Application options appended.\n"); 66 | 67 | return 0; 68 | } -------------------------------------------------------------------------------- /demo_gstreamer_3_element_factory.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by toson on 20-2-10. 3 | // 4 | // 5.2. 创建一个GstElement对象 5 | 6 | #include "cstdio" 7 | 8 | //创建一个元件的最简单的方法是通过函数gst_element_factory_make ()。 9 | //这个函数使用一个已存在的工厂对象名和一个新的元件名来创建元件。 10 | //创建完之后, 你可以用新的元件名在箱柜(bin)中查询得到这个元件。 11 | //这个名字同样可以用来调试程序的输 出。你可以通过传递 NULL 来得到一个默认的具有唯一性的名字。 12 | //当你不再需要一个元件时,你需要使用 gst_object_unref ()来对它进行解引用。 13 | //这会将一个元件的引用数减少1。任何一个元件在创建时,其引用记数为1。当其引用记数为0时,该元件会被销毁。 14 | // 15 | //下面的例子[1] 显示了如果通过一个fakesrc工厂对象来创建一个名叫source的元件。 16 | //程序会检查元件是否创建成功。检查完毕后,程序会销毁元件。 17 | //———————————————— 18 | //版权声明:本文为CSDN博主「北雨南萍」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 19 | //原文链接:https://blog.csdn.net/fireroll/article/details/46859973 20 | #include 21 | 22 | int 23 | main1 (int argc, 24 | char *argv[]) 25 | { 26 | GstElement *element; 27 | 28 | /* init GStreamer */ 29 | gst_init (&argc, &argv); 30 | 31 | /* create element */ 32 | element = gst_element_factory_make ("fakesrc", "source"); 33 | if (!element) { 34 | g_print ("Failed to create element of type 'fakesrc'\n"); 35 | return -1; 36 | } 37 | 38 | gst_object_unref (GST_OBJECT (element)); 39 | 40 | return 0; 41 | } 42 | 43 | //gst_element_factory_make 是2个函数的速记。 44 | //一个GstElement 对象由工厂对象创建而来。 45 | //为了创建一个元件,你需要使用一个唯一的工厂对象名字来访问一个 GstElementFactory对象。 46 | //gst_element_factory_find ()就 是做了这样的事。 47 | // 48 | //下面的代码段创建了一个工厂对象,这个工厂对象被用来创建一个fakesrc元件 —— 伪装的数据源。 49 | //函数 gst_element_factory_create() 将会使用元件工厂并根据给定的名字来创建一个元件。 50 | #include 51 | 52 | int 53 | main2 (int argc, 54 | char *argv[]) 55 | { 56 | GstElementFactory *factory; 57 | GstElement * element; 58 | 59 | /* init GStreamer */ 60 | gst_init (&argc, &argv); 61 | 62 | /* create element, method #2 */ 63 | factory = gst_element_factory_find ("fakesrc"); 64 | if (!factory) { 65 | g_print ("Failed to find factory of type 'fakesrc'\n"); 66 | return -1; 67 | } 68 | element = gst_element_factory_create (factory, "source"); 69 | if (!element) { 70 | g_print ("Failed to create element, even though its factory exists!\n"); 71 | return -1; 72 | } 73 | 74 | gst_object_unref (GST_OBJECT (element)); 75 | 76 | return 0; 77 | } 78 | //GstElement的属性大多通过标准的 GObject 对象实现的。 79 | //使用 GObject 的方法可以对GstElement实行查询、设置、获取属性的值。同样 GParamSpecs 也被支持。 80 | //每个 GstElement 都从其基类 GstObject 继承了至少一个“名字”属性。 81 | //这个名字属性将在函数gst_element_factory_make ()或者函数gst_element_factory_create ()中使用到。 82 | //你可通过函数 gst_object_set_name 设置该属性,通过 gst_object_get_name 得到一个对象的名字属性。 83 | //你也可以通过下面的方法来得到一个对象的名字属性。 84 | //———————————————— 85 | //版权声明:本文为CSDN博主「北雨南萍」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 86 | //原文链接:https://blog.csdn.net/fireroll/article/details/46859973 87 | #include 88 | 89 | int 90 | main (int argc, 91 | char *argv[]) 92 | { 93 | GstElement *element; 94 | gchar *name; 95 | 96 | /* init GStreamer */ 97 | gst_init (&argc, &argv); 98 | 99 | /* create element */ 100 | element = gst_element_factory_make ("fakesrc", "source1234324234"); 101 | 102 | /* get name */ 103 | g_object_get (G_OBJECT (element), "name", &name, NULL); 104 | g_print ("The name of the element is '%s'.\n", name); 105 | g_free (name); 106 | 107 | gst_object_unref (GST_OBJECT (element)); 108 | 109 | return 0; 110 | } 111 | //大多数的插件(plugins)都提供了一些额外的方法,这些方法给程序员提供了更多的关于该元件的注册信息或配置信息。 112 | //gst-inspect 是一个用来查询特定元件特性(properties)的实用工具。 113 | //它也提供了诸如函数简短介绍,参数的类型及其支持的范围等信息。关于 gst-inspect 更详细的信息请参考附录。 114 | //关于GObject特性更详细的信息,我们推荐你去阅读 GObject手册 以及 Glib 对象系统介绍. 115 | //GstElement对象同样提供了许多的 GObject 信号方法来实现一个灵活的回调机制。 116 | //你同样可以使用 gst-inspect来检查一个特定元件所支持的信号。 117 | //总之,信号和特性是元件与应用程序交互的最基本的方式。 118 | //———————————————— 119 | //版权声明:本文为CSDN博主「北雨南萍」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 120 | //原文链接:https://blog.csdn.net/fireroll/article/details/46859973 121 | -------------------------------------------------------------------------------- /demo_gstreamer_4_get_element_info.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by toson on 20-2-10. 3 | // 4 | // 5.4.1.通过元 件工厂得到元件的信息 5 | 6 | #include "cstdio" 7 | 8 | //———————————————— 9 | //版权声明:本文为CSDN博主「北雨南萍」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 10 | //原文链接:https://blog.csdn.net/fireroll/article/details/46859973 11 | 12 | //像gst-inspect 这样的工具可以给出一个元件的概要: 13 | //插件(plugin)的作者、 14 | //描述性的元件名称(或者简称)、 15 | //元件的等级(rank) 16 | //以及元件的类别(category)。 17 | // 18 | //类别可以用来得到一个元件的类型,这个类型是在使用工厂元件创建该元件时做创建的。 19 | //例如类别可以是 Codec/Decoder/Video(视频解码器)、Source/Video(视频发生器)、Sink/Video(视频输出器)。 20 | //音频也有类似的类别。同样还存在 Codec/Demuxer和Codec/Muxer,甚至更多的类别。 21 | //Gst-inspect将会列出当前所有的工厂对象,gst-inspect 将会列出特定工厂对象的所有概要信息。 22 | #include 23 | 24 | const char *strs[] = {"audiotestsrc", "rtspsrc", "filesrc", "location", 25 | "h264parse", "nvv4l2decoder", "avdec_h264", "nvstreammux", 26 | "autovideosink", "nveglglessink", 27 | "fakesrc", "identity", "fakesink", 28 | "oggdemux", 29 | "openh264dec", "d3dvideosink" 30 | }; 31 | 32 | int 33 | main(int argc, 34 | char *argv[]) { 35 | GstElementFactory *factory; 36 | 37 | /* init GStreamer */ 38 | gst_init(&argc, &argv); 39 | 40 | for (auto str : strs) { 41 | g_print("------\n"); 42 | factory = gst_element_factory_find(str); 43 | if (!factory) { 44 | g_print("You don't have the '%s' element installed!\n", str); 45 | continue; 46 | } 47 | /* display information */ 48 | g_print("The '%s' element is a member of the category %s.\n\tDescription: %s\n", 49 | gst_plugin_feature_get_name (GST_PLUGIN_FEATURE(factory)), 50 | gst_element_factory_get_klass (factory), 51 | gst_element_factory_get_description (factory)); 52 | } 53 | 54 | //你可以通过gst_registry_pool_feature_list (GST_TYPE_ELEMENT_FACTORY)得到所有在GStreamer中注册过的工厂元件。 55 | //gst_registry_pool_feature_list (GST_TYPE_ELEMENT_FACTORY) 56 | 57 | return 0; 58 | } 59 | 60 | 61 | //nvidia@nvidia-desktop:~/projects/gstreamer_l/build$ ./demo_4_get_element_info_ 62 | //------ 63 | //The 'audiotestsrc' element is a member of the category Source/Audio. 64 | // Description: Creates audio test signals of given frequency and volume 65 | //------ 66 | //The 'rtspsrc' element is a member of the category Source/Network. 67 | // Description: Receive data over the network via RTSP (RFC 2326) 68 | //------ 69 | //The 'filesrc' element is a member of the category Source/File. 70 | // Description: Read from arbitrary point in a file 71 | //------ 72 | //You don't have the 'location' element installed! 73 | //------ 74 | //The 'h264parse' element is a member of the category Codec/Parser/Converter/Video. 75 | // Description: Parses H.264 streams 76 | //------ 77 | //The 'nvv4l2decoder' element is a member of the category Codec/Decoder/Video. 78 | // Description: Decode video streams via V4L2 API 79 | //------ 80 | //The 'avdec_h264' element is a member of the category Codec/Decoder/Video. 81 | // Description: libav h264 decoder 82 | //------ 83 | //The 'nvstreammux' element is a member of the category Generic. 84 | // Description: N-to-1 pipe stream multiplexing 85 | //------ 86 | //The 'autovideosink' element is a member of the category Sink/Video. 87 | // Description: Wrapper video sink for automatically detected video sink 88 | //------ 89 | //The 'nveglglessink' element is a member of the category Sink/Video. 90 | // Description: An EGL/GLES Video Output Sink Implementing the VideoOverlay interface 91 | //------ 92 | //The 'fakesrc' element is a member of the category Source. 93 | // Description: Push empty (no data) buffers around 94 | //------ 95 | //The 'identity' element is a member of the category Generic. 96 | // Description: Pass data without modification 97 | //------ 98 | //The 'fakesink' element is a member of the category Sink. 99 | // Description: Black hole for data 100 | //------ 101 | //The 'oggdemux' element is a member of the category Codec/Demuxer. 102 | // Description: demux ogg streams (info about ogg: http://xiph.org) 103 | //------ 104 | //You don't have the 'openh264dec' element installed! 105 | //------ 106 | //You don't have the 'd3dvideosink' element installed! 107 | 108 | -------------------------------------------------------------------------------- /demo_gstreamer_5_link_elements.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by toson on 20-2-10. 3 | // 4 | // 5.4.1.通过元 件工厂得到元件的信息 5 | 6 | #include "cstdio" 7 | //通过将一个源元件,零个或多个类过滤元件,和一个接收元件链接在一起,你可以建立起一条媒体管道。 8 | //数据将在这些元件间流过。这是 GStreamer 中处理媒体的基本概念。 9 | //图5-5 用3个链接的元件形象化了媒体管道。 10 | //图5-5.形象化3个链接的元件 11 | // 12 | //通过链接这三个元件,我们创建了一条简单的元件链。 13 | //元件链中源元件("element1")的输出将会是类过滤元件 ("element2")的输入。 14 | //类过滤元件将会对数据进行某些操作, 15 | //然后将数据输出给最终的接收元件("element3")。 16 | //把上述过程想象成一个简单的 Ogg/Vorbis 音频解码器。 17 | //源元件从磁盘读取文件。 18 | //第二个元件就是Ogg/Vorbis 音频解码器 19 | //。最终的接收元件是你的声卡,它用来播放经过解码的音频数据。 20 | //我们将在该手册的后部分用一个简单的图来构建这个 Ogg/Vorbis 播放器。 21 | //上述的过程用代码表示为: 22 | //———————————————— 23 | //版权声明:本文为CSDN博主「北雨南萍」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 24 | //原文链接:https://blog.csdn.net/fireroll/article/details/46859973 25 | #include 26 | 27 | int 28 | main (int argc, 29 | char *argv[]) 30 | { 31 | GstElement *pipeline; 32 | GstElement *source, *filter, *sink; 33 | 34 | /* init */ 35 | gst_init (&argc, &argv); 36 | 37 | /* create pipeline */ 38 | pipeline = gst_pipeline_new ("my-pipeline"); 39 | 40 | /* create elements */ 41 | source = gst_element_factory_make ("fakesrc", "source"); 42 | filter = gst_element_factory_make ("identity", "filter"); 43 | sink = gst_element_factory_make ("fakesink", "sink"); 44 | 45 | /* must add elements to pipeline before linking them */ 46 | gst_bin_add_many (GST_BIN (pipeline), source, filter, sink, NULL); 47 | 48 | /* link */ 49 | if (!gst_element_link_many (source, filter, sink, NULL)) { 50 | g_warning ("Failed to link elements!"); 51 | } 52 | 53 | } 54 | //对于一些特定的链接行为,可以通过函数gst_element_link () 以及 gst_element_link_pads()来实现。 55 | //你可以使用不同的gst_pad_link_* ()函数来得到单个衬垫的引用并将它们链接起来。 56 | //更详细的信息请参考API手册。 57 | // 58 | //注意:在链接不同的元件之前,你需要确保这些元件都被加在同一个箱柜中, 59 | //因为将一个元件加载到一个箱柜中会破坏该元件已存在的一些链接关系。 60 | //同时,你不能直接链接不在同一箱柜或管道中的元件。 61 | //如果你想要连接处于不同层次中的元件或衬垫,你将使用到精灵衬垫(关于精灵衬垫更多的信息将在后续章节中讲到) 。 62 | 63 | 64 | 65 | ///5.6. 元件状态 66 | //一个元件在被创建后,它不会执行任何操作。所以你需要改变元件的状态,使得它能够做某些事情。 67 | //Gstreamer中,元件有四种状态,每种状态都有其特定的意义。 68 | //这四种状态为: 69 | // . GST_STATE_NULL: 默认状态。该状态将会回收所有被该元件占用的资源。 70 | // . GST_STATE_READY: 准备状态。 71 | // 元件会得到所有所需的全局资源,这些全局资源将被通过该元件的数据流所使用。 72 | // 例如打开设备、分配缓存等。但在这种状态下,数据流仍未开始被处 理, 73 | // 所以数据流的位置信息应该自动置0。 74 | // 如果数据流先前被打开过,它应该被关闭,并且其位置信息、特性信息应该被重新置为初始状态。 75 | // . GST_STATE_PAUSED: 在这种状态下,元件已经对流开始了处理,但此刻暂停了处理。 76 | // 因此该状态下元件可以修改流的位置信息,读取或者处理流数据, 77 | // 以及一旦状态变为 PLAYING,流可以重放数据流。这种情况下,时钟是禁止运行的。 78 | // 总之, PAUSED 状态除了不能运行时钟外,其它与 PLAYING 状态一模一样。 79 | // 处于 PAUSED 状态的元件会很快变换到 PLAYING 状态。 80 | // 举例来说,视频或音频输出元件会等待数据的到来,并将它们压入队列。 81 | // 一旦状态改变,元件就会处理接收到的数据。同样,视频接收元件能够播放数据的第 一帧。 82 | // (因为这并不会影响时钟)。自动加载器(Autopluggers)可以对已经加载进管道的插件进行这种状态转换。 83 | // 其它更多的像codecs或者 filters这种元件不需要在这个状态上做任何事情。 84 | // . GST_STATE_PLAYING: PLAYING 状态除了当前运行时钟外,其它与 PAUSED 状态一模一样。 85 | // 你可以通过函数gst_element_set_state()来改变一个元件的状态。 86 | // 你如果显式地改变一个元件的状态,GStreamer可能会 使它在内部经过一些中间状态。 87 | // 例如你将一个元件从 NULL 状态设置为 PLAYING 状态, 88 | // GStreamer在其内部会使得元件经历过 READY 以及 PAUSED 状态。 89 | // 90 | //当处于GST_STATE_PLAYING 状态,管道会自动处理数据。 91 | //它们不需要任何形式的迭代。 GStreamer 会开启一个新的线程来处理数据。 92 | //GStreamer 同样可以使用 GstBus在管道线程和应用程序现成间交互信息。 93 | //———————————————— 94 | //版权声明:本文为CSDN博主「北雨南萍」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 95 | //原文链接:https://blog.csdn.net/fireroll/article/details/46859973 -------------------------------------------------------------------------------- /demo_gstreamer_6_pads.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by toson on 20-2-10. 3 | // 4 | // 6.1 衬垫(Pads) 5 | 6 | //如我们在Elements一章中看到的那样,衬垫(Pads)是元件对 外的接口。 7 | //数据流从一个元件的源衬垫(source pad)到另一个元件的接收衬垫(sink pad)。 8 | //衬垫的功能(capabilities)决定了一个元件所能处理的媒体类型。 9 | //在这章的后续讲解中,我们将对衬垫的功能做更详细的说明。 (见第8.2节). 10 | 11 | //一个衬垫的类型由2个特性决定: 12 | // . 它的数据导向(direction)以及它的时效性(availability)。 13 | // 14 | //正如我们先前提到 的,Gstreamer定义了2种衬垫的数据导向:源衬垫以及接收衬垫。 15 | //衬垫的数据导向这个术语是从元件内部的角度给予定义的: 元件通过它们的接收衬垫接收数据,通过它们的源衬垫输出数据。 16 | //如果通过一张图来形象地表述,接收衬垫画在元件的左侧,而源衬垫画在元件的右侧,数据从左向右流动。 [1] 17 | // 18 | //衬垫的时效性比衬垫的数据导向复杂得多。一个衬垫可以拥有三种类型的时效性: 19 | // . 永久型(always)、随机型(sometimes)、请求型(on request)。 20 | //三种时效性的意义顾名思义: 永久型的衬垫一直会存在, 21 | //随机型的衬垫只在某种特定的条件下才存在(会随机消失的衬垫也属于随机型), 22 | //请求型的衬垫只在应用程序明确发出请求时才出现。 23 | 24 | 25 | #include "cstdio" 26 | 27 | //8.1.1. 动态(随机)衬垫 28 | //一些元件在其被创建时不会立刻产生所有它将用到的衬垫。 29 | //例如在一个Ogg demuxer的元件中可能发生这种情况。这个元件将会读取Ogg流, 30 | //每当它在Ogg流中检测到一些元数据流时(例如vorbis,theora ),它会为每个元数据流创建动态衬垫。 31 | //同样,它也会在流终止时删除该衬垫。动态衬垫在demuxer这种元件中可以起到很大的作用。 32 | //运行gst-inspect oggdemux只会显示出一个衬垫在元件中: 33 | //一个名字叫作'sink'的接收衬垫,其它的衬垫都处于'休眠'中, 34 | //你可以从衬垫模板(pad template)中的"Exists: Sometimes"的属性看到这些信息。 35 | //衬垫会根据你所播放的Ogg文件的类型而产生,认识到这点 对于你创建一个动态管道特别重要。 36 | //当元件通过它的随机型(sometimes)衬垫模板创建了一个随机型(sometimes)的衬垫的时侯, 37 | //你可以通过对该元件绑定一个信号处理器(signal handler),通过它来得知衬垫被创建。下面一段代码演示了如何这样做: 38 | //名叫'sink'的接收衬垫,其它的衬垫都处于'休眠'中,显而易见这是衬垫”有时存在”的特性。 39 | //衬垫会根据你所播放的Ogg文件的类型而产生,这点在你 准备创建一个动态管道时显得特别重要, 40 | //当元件创建了一个”有时存在”的衬垫时,你可以通过对该元件触发一个信号处理器(signal handler) 来得知衬垫被创建。 41 | //下面一段代码演示了如何这样做: 42 | #include 43 | 44 | static void 45 | cb_new_pad(GstElement *element, 46 | GstPad *pad, 47 | gpointer data) { 48 | gchar *name; 49 | 50 | 51 | name = gst_pad_get_name (pad); 52 | g_print("A new pad %s was created\n", name); 53 | g_free(name); 54 | 55 | 56 | /* here, you would setup a new pad link for the newly created pad */ 57 | //[..] 58 | 59 | 60 | } 61 | 62 | 63 | int 64 | main(int argc, 65 | char *argv[]) { 66 | GstElement *pipeline, *source, *demux; 67 | GMainLoop *loop; 68 | 69 | 70 | /* init */ 71 | gst_init(&argc, &argv); 72 | 73 | 74 | /* create elements */ 75 | pipeline = gst_pipeline_new("my_pipeline"); 76 | source = gst_element_factory_make("filesrc", "source"); 77 | g_object_set(source, "location", argv[1], NULL); 78 | demux = gst_element_factory_make("oggdemux", "demuxer"); 79 | 80 | 81 | /* you would normally check that the elements were created properly */ 82 | 83 | 84 | /* put together a pipeline */ 85 | gst_bin_add_many(GST_BIN (pipeline), source, demux, NULL); 86 | gst_element_link_pads(source, "src", demux, "sink"); 87 | 88 | 89 | /* listen for newly created pads */ 90 | g_signal_connect (demux, "pad-added", G_CALLBACK(cb_new_pad), NULL); 91 | 92 | 93 | /* start the pipeline */ 94 | gst_element_set_state(GST_ELEMENT (pipeline), GST_STATE_PLAYING); 95 | loop = g_main_loop_new(NULL, FALSE); 96 | g_main_loop_run(loop); 97 | 98 | 99 | } 100 | //———————————————— 101 | //版权声明:本文为CSDN博主「北雨南萍」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 102 | //原文链接:https://blog.csdn.net/fireroll/article/details/46859973 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /demo_gstreamer_8_helloworld.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by toson on 20-2-10. 3 | // 4 | // 10.1. 第一个Hello world程序 5 | // 一个简易的,支持Ogg/Vorbis格式的音频播放器。 6 | 7 | #include "cstdio" 8 | 9 | //我们现在开始创建第一个简易的应用程序 – 一个基于命令行并支持Ogg/Vorbis格式的音频播放器。 10 | //我们只需要使用标准的 Gstreamer的组件(components)就能够开发出这个程序。 11 | //它通过命令行来指定播放的文件。让我们开始这段旅程: 12 | //如在 第4章中学到的那样, 13 | //第一件事情是要通过gst_init()函数来初始化 GStreamer库。确保程序包含了 gst/gst.h 头文件, 14 | //这样GStreamer库中的对象和函数才能够被正确地定义。你可以通过#include 指令来包含 gst/gst.h 头文件。 15 | //然后你可以通过函数gst_element_factory_make ()来创建不同的元件。 16 | //对于Ogg/Vorbis音频播放器,我们需要一个源元件从磁盘读取文件。 GStreamer 中有一个”filesrc”的元件可以胜任此事。 17 | //其次我们需要一些东西来解析从磁盘读取的文件。 GStreamer 中有两个元件可以分别来解析Ogg/Vorbis文件。 18 | //第一个将 Ogg 数据流解析成元数据流的元件叫”oggdemux”。第二个是 Vorbis 音频解码器,通常称为”vorbisdec”。 19 | //由于”oggdemux”为每个元数据流动态创建衬垫,所以你得为”oggdemux”元件设置"pad- added" 的事件处理函数。 20 | //像8.1.1部分讲 解的那样,"pad-added" 的事件处理函数可以用来将 Ogg 解码元件和 Vorbis 解码元件连接起来。 21 | //最后,我们还需要一个音频输出元件 - “alsasink”。它会将数据传送给 ALSA 音频设备。 22 | //万事俱备,只欠东风。我们需要把所有的元件都包含到一个容器元件中 - GstPipeline, 23 | //然后在这个管道中一直轮循,直到我们播放完整的歌曲。我们在第6章中 学习过如何将元件包含进容器元件, 24 | //在5.6部分了解过元件的状 态信息。我们同样需要在管道总线上加消息处理来处理错误信息和检测流结束标志。 25 | //现在给出我们第一个音频播放器的所有代码: 26 | //———————————————— 27 | //版权声明:本文为CSDN博主「北雨南萍」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 28 | //原文链接:https://blog.csdn.net/fireroll/article/details/46859973 29 | 30 | 31 | #include 32 | 33 | 34 | /* 35 | * Global objects are usually a bad thing. For the purpose of this 36 | * example, we will use them, however. 37 | */ 38 | 39 | 40 | GstElement *pipeline, *source, *parser, *decoder, *conv, *sink; 41 | 42 | 43 | static gboolean 44 | bus_call (GstBus *bus, 45 | GstMessage *msg, 46 | gpointer data) 47 | { 48 | GMainLoop *loop = (GMainLoop *)data; 49 | 50 | 51 | switch (GST_MESSAGE_TYPE (msg)) { 52 | case GST_MESSAGE_EOS: 53 | g_print ("End-of-stream\n"); 54 | g_main_loop_quit (loop); 55 | break; 56 | case GST_MESSAGE_ERROR: { 57 | gchar *debug; 58 | GError *err; 59 | 60 | 61 | gst_message_parse_error (msg, &err, &debug); 62 | g_free (debug); 63 | 64 | 65 | g_print ("Error: %s\n", err->message); 66 | g_error_free (err); 67 | 68 | 69 | g_main_loop_quit (loop); 70 | break; 71 | } 72 | default: 73 | break; 74 | } 75 | 76 | 77 | return TRUE; 78 | } 79 | 80 | 81 | ///demo_gstreamer_8_helloworld.cpp:91:15: error: ‘gst_element_get_pad’ was not declared in this scope 82 | /// sinkpad = gst_element_get_pad (decoder, "sink"); 83 | //static void 84 | //new_pad (GstElement *element, 85 | // GstPad *pad, 86 | // gpointer data) 87 | //{ 88 | // GstPad *sinkpad; 89 | // /* We can now link this pad with the audio decoder */ 90 | // g_print ("Dynamic pad created, linking parser/decoder\n"); 91 | // 92 | // 93 | // sinkpad = gst_element_get_pad (decoder, "sink"); 94 | // gst_pad_link (pad, sinkpad); 95 | // 96 | // 97 | // gst_object_unref (sinkpad); 98 | //} 99 | 100 | 101 | int 102 | main (int argc, 103 | char *argv[]) 104 | { 105 | GMainLoop *loop; 106 | GstBus *bus; 107 | 108 | 109 | /* initialize GStreamer */ 110 | gst_init (&argc, &argv); 111 | loop = g_main_loop_new (NULL, FALSE); 112 | 113 | 114 | /* check input arguments */ 115 | if (argc != 2) { 116 | g_print ("Usage: %s \n", argv[0]); 117 | return -1; 118 | } 119 | 120 | 121 | /* create elements */ 122 | pipeline = gst_pipeline_new ("audio-player"); 123 | source = gst_element_factory_make ("filesrc", "file-source"); 124 | parser = gst_element_factory_make ("oggdemux", "ogg-parser"); 125 | decoder = gst_element_factory_make ("vorbisdec", "vorbis-decoder"); 126 | conv = gst_element_factory_make ("audioconvert", "converter"); 127 | sink = gst_element_factory_make ("alsasink", "alsa-output"); 128 | if (!pipeline || !source || !parser || !decoder || !conv || !sink) { 129 | g_print ("One element could not be created\n"); 130 | return -1; 131 | } 132 | 133 | 134 | /* set filename property on the file source. Also add a message 135 | * handler. */ 136 | g_object_set (G_OBJECT (source), "location", argv[1], NULL); 137 | 138 | 139 | bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); 140 | gst_bus_add_watch (bus, bus_call, loop); 141 | gst_object_unref (bus); 142 | 143 | 144 | /* put all elements in a bin */ 145 | gst_bin_add_many (GST_BIN (pipeline), 146 | source, parser, decoder, conv, sink, NULL); 147 | 148 | 149 | /* link together - note that we cannot link the parser and 150 | * decoder yet, becuse the parser uses dynamic pads. For that, 151 | * we set a pad-added signal handler. */ 152 | gst_element_link (source, parser); 153 | gst_element_link_many (decoder, conv, sink, NULL); 154 | // g_signal_connect (parser, "pad-added", G_CALLBACK (new_pad), NULL); 155 | 156 | 157 | /* Now set to playing and iterate. */ 158 | g_print ("Setting to PLAYING\n"); 159 | gst_element_set_state (pipeline, GST_STATE_PLAYING); 160 | g_print ("Running\n"); 161 | g_main_loop_run (loop); 162 | 163 | 164 | /* clean up nicely */ 165 | g_print ("Returned, stopping playback\n"); 166 | gst_element_set_state (pipeline, GST_STATE_NULL); 167 | g_print ("Deleting pipeline\n"); 168 | gst_object_unref (GST_OBJECT (pipeline)); 169 | 170 | 171 | return 0; 172 | } 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /demo_gstreamer_rtsp.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by toson on 20-2-10. 3 | // 4 | // gstreamer如何接入RTSP流(IP摄像头)的代码范例。 5 | //———————————————— 6 | //版权声明:本文为CSDN博主「柳鲲鹏」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 7 | //原文链接:https://blog.csdn.net/quantum7/article/details/82151637 8 | 9 | #include "cstdio" 10 | 11 | #define RTSPCAM "rtsp://admin:admin123@192.168.1.106:554/cam/realmonitor?channel=1&subtype=0" 12 | 13 | #include "gst/gst.h" 14 | 15 | static void on_pad_added(GstElement *element, GstPad *pad, gpointer data) { 16 | GstPad *sinkpad; 17 | GstElement *decoder = (GstElement *) data; 18 | /* We can now link this pad with the rtsp-decoder sink pad */ 19 | g_print("Dynamic pad created, linking source/demuxer\n"); 20 | sinkpad = gst_element_get_static_pad(decoder, "sink"); 21 | gst_pad_link(pad, sinkpad); 22 | gst_object_unref(sinkpad); 23 | } 24 | 25 | static void cb_new_rtspsrc_pad(GstElement *element, GstPad *pad, gpointer data) { 26 | gchar *name; 27 | GstCaps *p_caps; 28 | gchar *description; 29 | GstElement *p_rtph264depay; 30 | 31 | name = gst_pad_get_name(pad); 32 | g_print("A new pad %s was created\n", name); 33 | 34 | // here, you would setup a new pad link for the newly created pad 35 | // sooo, now find that rtph264depay is needed and link them? 36 | p_caps = gst_pad_get_pad_template_caps(pad); 37 | 38 | description = gst_caps_to_string(p_caps); 39 | printf("%s\n", p_caps, ", ", description, "\n"); 40 | g_free(description); 41 | 42 | p_rtph264depay = GST_ELEMENT(data); 43 | 44 | // try to link the pads then ... 45 | if (!gst_element_link_pads(element, name, p_rtph264depay, "sink")) { 46 | printf("Failed to link elements 3\n"); 47 | } 48 | 49 | g_free(name); 50 | } 51 | 52 | 53 | int main(int argc, char *argv[]) { 54 | GstElement *pipeline = NULL, *source = NULL, *rtppay = NULL, *parse = NULL, 55 | *decodebin = NULL, *sink = NULL, *filter1 = NULL; 56 | GstCaps *filtercaps = NULL; 57 | 58 | /* Initialize GStreamer */ 59 | gst_init(&argc, &argv); 60 | 61 | /* Build Pipeline */ 62 | pipeline = gst_pipeline_new("Toson"); 63 | 64 | source = gst_element_factory_make ( "rtspsrc", "source"); 65 | g_object_set (G_OBJECT (source), "latency", 2000, NULL); 66 | rtppay = gst_element_factory_make ( "rtph264depay", "depayl"); 67 | parse = gst_element_factory_make ( "h264parse", "parse"); 68 | decodebin = gst_element_factory_make ( "avdec_h264", "decode"); 69 | #ifdef PLATFORM_TEGRA 70 | sink = gst_element_factory_make ( "nveglglessink", "sink"); 71 | #else 72 | sink = gst_element_factory_make ( "autovideosink", "sink"); 73 | #endif 74 | 75 | if (!pipeline || !source || !rtppay || !parse || !decodebin || !sink) { 76 | g_printerr("One element could not be created.\n"); 77 | } 78 | 79 | g_object_set (G_OBJECT (sink), "sync", FALSE, NULL); 80 | 81 | //create_uri(url,url_size, ip_address, port); 82 | g_object_set(GST_OBJECT(source), "location", RTSPCAM, NULL); 83 | //"rtsp://:554/live/ch00_0" 84 | 85 | //无必要 86 | filter1 = gst_element_factory_make("capsfilter", "filter"); 87 | filtercaps = gst_caps_from_string("application/x-rtp"); 88 | g_object_set (G_OBJECT (filter1), "caps", filtercaps, NULL); 89 | gst_caps_unref(filtercaps); 90 | 91 | gst_bin_add (GST_BIN (pipeline), source); 92 | gst_bin_add_many (GST_BIN (pipeline), rtppay, NULL); 93 | // listen for newly created pads 94 | g_signal_connect(source, "pad-added", G_CALLBACK(cb_new_rtspsrc_pad), rtppay); 95 | gst_bin_add_many (GST_BIN (pipeline), parse,NULL); 96 | if (!gst_element_link(rtppay, parse)) 97 | { 98 | printf("\nNOPE\n"); 99 | } 100 | 101 | gst_bin_add_many (GST_BIN (pipeline), decodebin, sink, NULL); 102 | 103 | if (!gst_element_link_many(parse, decodebin, sink, NULL)) 104 | { 105 | printf("\nFailed to link parse to sink"); 106 | } 107 | 108 | //不是必须 109 | //g_signal_connect(rtppay, "pad-added", G_CALLBACK(on_pad_added), parse); 110 | 111 | gst_element_set_state (pipeline, GST_STATE_PLAYING); 112 | 113 | GstBus* bus = gst_element_get_bus(pipeline); 114 | GstMessage* msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS)); 115 | 116 | if (msg != NULL) 117 | { 118 | gst_message_unref(msg); 119 | } 120 | gst_object_unref (bus); 121 | 122 | gst_element_set_state(pipeline, GST_STATE_NULL); 123 | gst_object_unref(pipeline); 124 | 125 | } 126 | --------------------------------------------------------------------------------