gstreamer学习笔记:分享几个appsink和appsrc的example
2016-12-13 16:06
567 查看
(1)appsink的使用:
需要安装gtk:sudo apt-get install libgtk2.0-dev
编译命令:gcc appsink_example.c -o appsink_example $(pkg-config --cflags --libs gstreamer-1.0 gtk+-2.0)
执行: ./appsink_example red
(2)appsrc 例子:
编译:gcc appsrc2.c -o appsrc2 $(pkg-config --cflags --libs gstreamer-0.10 gstreamer-app-0.10)
运行:./appsrc2 xx.avi
(3)appsink和appsrc一起使用的例子:
编译:
//gcc appsink_src_test.c -o appsink_src_test $(pkg-config --cflags --libs gstreamer-1.0)
// or gcc appsink_src_test.c -o appsink_src_test $(pkg-config --cflags --libs gstreamer-1.0 gstreamer-app-1.0)
#include <gst/gst.h> #define HAVE_GTK #ifdef HAVE_GTK #include <gtk/gtk.h> #endif #include <stdlib.h> #define CAPS "video/x-raw,format=RGB,width=160,pixel-aspect-ratio=1/1" int main (int argc, char *argv[]) { GstElement *pipeline, *sink; gint width, height; GstSample *sample; gchar *descr; GError *error = NULL; gint64 duration, position; GstStateChangeReturn ret; gboolean res; GstMapInfo map; gst_init (&argc, &argv); if (argc != 2) { g_print ("usage: %s <pattern>\n Writes snapshot.png in the current directory\n", argv[0]); exit (-1); } /* create a new pipeline */ descr = g_strdup_printf ("videotestsrc pattern=%s ! " " appsink name=sink caps=\"" CAPS "\"", argv[1]); pipeline = gst_parse_launch (descr, &error); if (error != NULL) { g_print ("could not construct pipeline: %s\n", error->message); g_clear_error (&error); exit (-1); } /* get sink */ sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink"); /* set to PAUSED to make the first frame arrive in the sink */ ret = gst_element_set_state (pipeline, GST_STATE_PAUSED); switch (ret) { case GST_STATE_CHANGE_FAILURE: g_print ("failed to play the file\n"); exit (-1); case GST_STATE_CHANGE_NO_PREROLL: /* for live sources, we need to set the pipeline to PLAYING before we can * receive a buffer. We don't do that yet */ g_print ("live sources not supported yet\n"); exit (-1); default: break; } /* This can block for up to 5 seconds. If your machine is really overloaded, * it might time out before the pipeline prerolled and we generate an error. A * better way is to run a mainloop and catch errors there. */ ret = gst_element_get_state (pipeline, NULL, NULL, 5 * GST_SECOND); if (ret == GST_STATE_CHANGE_FAILURE) { g_print ("failed to play the file\n"); exit (-1); } /* get the duration */ gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration); if (duration != -1) /* we have a duration, seek to 5% */ position = duration * 5 / 100; else /* no duration, seek to 1 second, this could EOS */ position = 1 * GST_SECOND; /* seek to the a position in the file. Most files have a black first frame so * by seeking to somewhere else we have a bigger chance of getting something * more interesting. An optimisation would be to detect black images and then * seek a little more */ gst_element_seek_simple (pipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_FLUSH, position); /* get the preroll buffer from appsink, this block untils appsink really * prerolls */ g_signal_emit_by_name (sink, "pull-preroll", &sample, NULL); /* if we have a buffer now, convert it to a pixbuf. It's possible that we * don't have a buffer because we went EOS right away or had an error. */ if (sample) { GstBuffer *buffer; GstCaps *caps; GstStructure *s; /* get the snapshot buffer format now. We set the caps on the appsink so * that it can only be an rgb buffer. The only thing we have not specified * on the caps is the height, which is dependant on the pixel-aspect-ratio * of the source material */ caps = gst_sample_get_caps (sample); if (!caps) { g_print ("could not get snapshot format\n"); exit (-1); } s = gst_caps_get_structure (caps, 0); /* we need to get the final caps on the buffer to get the size */ res = gst_structure_get_int (s, "width", &width); res |= gst_structure_get_int (s, "height", &height); if (!res) { g_print ("could not get snapshot dimension\n"); exit (-1); } /* create pixmap from buffer and save, gstreamer video buffers have a stride * that is rounded up to the nearest multiple of 4 */ buffer = gst_sample_get_buffer (sample); /* Mapping a buffer can fail (non-readable) */ if (gst_buffer_map (buffer, &map, GST_MAP_READ)) { /* print the buffer data for debug */ int i = 0, j = 0; g_print("width=%d, height = %d\n", width, height); for(; i < width; i++){ for(; j < height; j++){ g_print("%x ", map.data[i*width + j]); } g_print("\n"); } #ifdef HAVE_GTK GdkPixbuf * pixbuf = gdk_pixbuf_new_from_data (map.data, GDK_COLORSPACE_RGB, FALSE, 8, width, height, GST_ROUND_UP_4 (width * 3), NULL, NULL); /* save the pixbuf */ gdk_pixbuf_save (pixbuf, "snapshot.png", "png", &error, NULL); #endif gst_buffer_unmap (buffer, &map); } gst_sample_unref (sample); } else { g_print ("could not make snapshot\n"); } /* cleanup and exit */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); exit (0); }
需要安装gtk:sudo apt-get install libgtk2.0-dev
编译命令:gcc appsink_example.c -o appsink_example $(pkg-config --cflags --libs gstreamer-1.0 gtk+-2.0)
执行: ./appsink_example red
(2)appsrc 例子:
/* I don't know if it is syntax highlighter or blogger, but I can't seem to put angle brackets around header file names properly. */ #include <stdio.h> #include <gst/gst.h> #include <gst/app/gstappsrc.h> typedef struct { GstPipeline *pipeline; GstAppSrc *src; GstElement *sink; GstElement *decoder; GstElement *ffmpeg; GstElement *videosink; GMainLoop *loop; guint sourceid; FILE *file; }gst_app_t; static gst_app_t gst_app; #define BUFF_SIZE (1024) static gboolean read_data(gst_app_t *app) { GstBuffer *buffer; guint8 *ptr; gint size; GstFlowReturn ret; ptr = g_malloc(BUFF_SIZE); g_assert(ptr); //g_print("read data...................\n"); size = fread(ptr, 1, BUFF_SIZE, app->file); if(size == 0){ ret = gst_app_src_end_of_stream(app->src); g_debug("eos returned %d at %d\n", ret, __LINE__); return FALSE; } buffer = gst_buffer_new(); GST_BUFFER_MALLOCDATA(buffer) = ptr; GST_BUFFER_SIZE(buffer) = size; GST_BUFFER_DATA(buffer) = GST_BUFFER_MALLOCDATA(buffer); ret = gst_app_src_push_buffer(app->src, buffer); if(ret != GST_FLOW_OK){ g_debug("push buffer returned %d for %d bytes \n", ret, size); return FALSE; } if(size != BUFF_SIZE){ ret = gst_app_src_end_of_stream(app->src); g_debug("eos returned %d at %d\n", ret, __LINE__); return FALSE; } return TRUE; } static void start_feed (GstElement * pipeline, guint size, gst_app_t *app) { g_print("start feed...................\n"); if (app->sourceid == 0) { GST_DEBUG ("start feeding"); app->sourceid = g_idle_add ((GSourceFunc) read_data, app); } } static void stop_feed (GstElement * pipeline, gst_app_t *app) { g_print("stop feed...................\n"); if (app->sourceid != 0) { GST_DEBUG ("stop feeding"); g_source_remove (app->sourceid); app->sourceid = 0; } } static void on_pad_added(GstElement *element, GstPad *pad) { GstCaps *caps; GstStructure *str; gchar *name; GstPad *ffmpegsink; GstPadLinkReturn ret; g_debug("pad added"); caps = gst_pad_get_caps(pad); str = gst_caps_get_structure(caps, 0); g_assert(str); name = (gchar*)gst_structure_get_name(str); g_debug("pad name %s", name); if(g_strrstr(name, "video")){ ffmpegsink = gst_element_get_pad(gst_app.ffmpeg, "sink"); g_assert(ffmpegsink); ret = gst_pad_link(pad, ffmpegsink); g_debug("pad_link returned %d\n", ret); gst_object_unref(ffmpegsink); } gst_caps_unref(caps); } static gboolean bus_callback(GstBus *bus, GstMessage *message, gpointer *ptr) { gst_app_t *app = (gst_app_t*)ptr; switch(GST_MESSAGE_TYPE(message)){ case GST_MESSAGE_ERROR:{ gchar *debug; GError *err; gst_message_parse_error(message, &err, &debug); g_print("Error %s\n", err->message); g_error_free(err); g_free(debug); g_main_loop_quit(app->loop); } break; case GST_MESSAGE_WARNING:{ gchar *debug; GError *err; gchar *name; gst_message_parse_warning(message, &err, &debug); g_print("Warning %s\nDebug %s\n", err->message, debug); name = GST_MESSAGE_SRC_NAME(message); g_print("Name of src %s\n", name ? name : "nil"); g_error_free(err); g_free(debug); } break; case GST_MESSAGE_EOS: g_print("End of stream\n"); g_main_loop_quit(app->loop); break; case GST_MESSAGE_STATE_CHANGED: break; default: g_print("got message %s\n", \ gst_message_type_get_name (GST_MESSAGE_TYPE (message))); break; } return TRUE; } int main(int argc, char *argv[]) { gst_app_t *app = &gst_app; GstBus *bus; GstStateChangeReturn state_ret; if(argc != 2){ printf("File name not specified\n"); return 1; } app->file = fopen(argv[1], "r"); g_assert(app->file); gst_init(NULL, NULL); app->pipeline = (GstPipeline*)gst_pipeline_new("mypipeline"); bus = gst_pipeline_get_bus(app->pipeline); gst_bus_add_watch(bus, (GstBusFunc)bus_callback, app); gst_object_unref(bus); app->src = (GstAppSrc*)gst_element_factory_make("appsrc", "mysrc"); app->decoder = gst_element_factory_make("decodebin2", "mydecoder"); app->ffmpeg = gst_element_factory_make("ffmpegcolorspace", "myffmpeg"); app->videosink = gst_element_factory_make("autovideosink", "myvsink"); g_assert(app->src); g_assert(app->decoder); g_assert(app->ffmpeg); g_assert(app->videosink); g_signal_connect(app->src, "need-data", G_CALLBACK(start_feed), app); g_signal_connect(app->src, "enough-data", G_CALLBACK(stop_feed), app); g_signal_connect(app->decoder, "pad-added", G_CALLBACK(on_pad_added), app->decoder); gst_bin_add_many(GST_BIN(app->pipeline), (GstElement*)app->src, app->decoder, app->ffmpeg, app->videosink, NULL); if(!gst_element_link((GstElement*)app->src, app->decoder)){ g_warning("failed to link src anbd decoder"); } if(!gst_element_link(app->ffmpeg, app->videosink)){ g_warning("failed to link ffmpeg and xvsink"); } state_ret = gst_element_set_state((GstElement*)app->pipeline, GST_STATE_PLAYING); g_warning("set state returned %d\n", state_ret); app->loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(app->loop); state_ret = gst_element_set_state((GstElement*)app->pipeline, GST_STATE_NULL); g_warning("set state null returned %d\n", state_ret); return 0; }
编译:gcc appsrc2.c -o appsrc2 $(pkg-config --cflags --libs gstreamer-0.10 gstreamer-app-0.10)
运行:./appsrc2 xx.avi
(3)appsink和appsrc一起使用的例子:
/* GStreamer * * appsink-src.c: example for using appsink and appsrc. * * Copyright (C) 2008 Wim Taymans <wim.taymans@gmail.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include <gst/gst.h> #include <string.h> #include <gst/app/gstappsrc.h> #include <gst/app/gstappsink.h> /* these are the caps we are going to pass through the appsink and appsrc */ const gchar *audio_caps = "audio/x-raw,format=S16LE,channels=2,rate=44100,layout=interleaved"; #define DEVICE "alsa_output.pci-0000_00_05.0.analog-stereo.monitor" #define APPSRC_PULL_MODE (0) /* appsrc working in pull mode or not */ #define PLAY_FILE (0) /* play file or get data from pulseaudio */ #define SAVE_FILE (1) /* save a file or playing directly */ static GstBuffer* s_app_buffer = NULL; typedef struct { GMainLoop *loop; GstElement *sink_pipeline; GstElement *src_pipeline; } ProgramData; /* called when the appsink notifies us that there is a new buffer ready for * processing */ static GstFlowReturn on_new_sample_from_sink (GstElement * sink_elm, ProgramData * data) { GstSample *sample = NULL; GstBuffer *buffer, *app_buffer; GstElement *sink, *source; GstFlowReturn ret; GstMapInfo map; /* get the sample from appsink */ //sample = gst_app_sink_pull_sample (GST_APP_SINK (sink_elm)); #if 0 sink = gst_bin_get_by_name (GST_BIN (data->src_pipeline), "testsink"); g_signal_emit_by_name (sink, "pull-sample", &sample, &ret); gst_object_unref (sink); #else g_signal_emit_by_name(sink_elm, "pull-sample", &sample, &ret); #endif if(sample){ buffer = gst_sample_get_buffer (sample); g_print("on_new_sample_from_sink() call!; size = %d\n", gst_buffer_get_size(buffer)); } else{ g_print("sample is NULL \n"); return ret; } /* 查看pull 到的sample 数据 */ #if 0 /* Mapping a buffer can fail (non-readable) */ if (gst_buffer_map (buffer, &map, GST_MAP_READ)) { /* print the buffer data for debug */ int i = 0, j = 0; for(; i < 10; i++) g_print("%x ", map.data[i]); g_print("\n"); } #endif /* make a copy */ #if !APPSRC_PULL_MODE app_buffer = gst_buffer_copy (buffer); #else s_app_buffer = gst_buffer_copy(buffer); #endif /* we don't need the appsink sample anymore */ gst_sample_unref (sample); /* 如果appsrc 为push 模式,直接将数据注入给appsrc */ /* get source an push new buffer */ #if !APPSRC_PULL_MODE source = gst_bin_get_by_name (GST_BIN (data->sink_pipeline), "testsource"); //ret = gst_app_src_push_buffer (GST_APP_SRC (source), app_buffer); g_signal_emit_by_name( source, "push-buffer", app_buffer, &ret );//数据送入pipeline gst_object_unref (source); gst_buffer_unref(app_buffer); #endif return ret; } /* called when we get a GstMessage from the source pipeline when we get EOS, we * notify the appsrc of it. */ static gboolean on_appsink_message (GstBus * bus, GstMessage * message, ProgramData * data) { GstElement *source; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_EOS: g_print ("The source got dry\n"); source = gst_bin_get_by_name (GST_BIN (data->sink_pipeline), "testsource"); //gst_app_src_end_of_stream (GST_APP_SRC (source)); g_signal_emit_by_name (source, "end-of-stream", NULL); gst_object_unref (source); break; case GST_MESSAGE_ERROR: g_print ("Received error\n"); g_main_loop_quit (data->loop); break; default: break; } return TRUE; } /* called when we get a GstMessage from the sink pipeline when we get EOS, we * exit the mainloop and this testapp. */ static gboolean on_appsrc_message (GstBus * bus, GstMessage * message, ProgramData * data) { /* nil */ switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_EOS: g_print ("Finished playback\n"); g_main_loop_quit (data->loop); break; case GST_MESSAGE_ERROR: g_print ("Received error\n"); g_main_loop_quit (data->loop); break; default: break; } return TRUE; } static gboolean read_data(ProgramData* app_data) { GstElement *appsink; appsink = gst_bin_get_by_name (GST_BIN (app_data->src_pipeline), "testsink"); GstFlowReturn ret = on_new_sample_from_sink(appsink, app_data); gst_object_unref(appsink); GstElement *source = NULL; if(s_app_buffer){ g_print("read data()....\n"); source = gst_bin_get_by_name (GST_BIN (app_data->sink_pipeline), "testsource"); //ret = gst_app_src_push_buffer (GST_APP_SRC (source), app_buffer); g_signal_emit_by_name( source, "push-buffer", s_app_buffer, &ret );//数据送入pipeline gst_object_unref (source); gst_buffer_unref(s_app_buffer); s_app_buffer = NULL; } else{ g_print("read_data() s_app_buffer is NULL\n"); } return TRUE; } static void on_appsrc_need_data(GstElement *appsrc, guint unused_size, ProgramData* app_data) { g_print("on_appsrc_need_data() call !!!\n"); guint src_id = g_idle_add ((GSourceFunc) read_data, app_data); return; } int main (int argc, char *argv[]) { gchar *filename = NULL; ProgramData *data = NULL; gchar *string = NULL; GstBus *bus = NULL; GstElement *testsink = NULL; GstElement *testsource = NULL; gst_init (&argc, &argv); if (argc == 2) filename = g_strdup (argv[1]); else filename = g_strdup ("xxx/xxxx.wav"); if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { g_print ("File %s does not exist\n", filename); return -1; } data = g_new0 (ProgramData, 1); data->loop = g_main_loop_new (NULL, FALSE); /* setting up source pipeline, we read from a file and convert to our desired * caps. */ #if PLAY_FILE /* 播放wav 歌曲 */ string = g_strdup_printf ("filesrc location=\"%s\" ! wavparse ! audioconvert ! appsink caps=\"%s\" name=testsink", filename, audio_caps); #else /* 从pulseaudio 抓取 */ string = g_strdup_printf ("pulsesrc device=%s ! audioconvert ! appsink caps=\"%s\" name=testsink", DEVICE, audio_caps); #endif g_free (filename); g_print("%s\n", string); data->src_pipeline = gst_parse_launch (string, NULL); g_free (string); if (data->src_pipeline == NULL) { g_print ("Bad source\n"); return -1; } /* to be notified of messages from this pipeline, mostly EOS */ bus = gst_element_get_bus (data->src_pipeline); gst_bus_add_watch (bus, (GstBusFunc) on_appsink_message, data); gst_object_unref (bus); /* we use appsink in push mode, it sends us a signal when data is available * and we pull out the data in the signal callback. We want the appsink to * push as fast as it can, hence the sync=false */ testsink = gst_bin_get_by_name (GST_BIN (data->src_pipeline), "testsink"); #if !APPSRC_PULL_MODE g_object_set (G_OBJECT (testsink), "emit-signals", TRUE, "sync", FALSE, NULL); g_signal_connect (testsink, "new-sample", G_CALLBACK (on_new_sample_from_sink), data); #endif gst_object_unref (testsink); /* setting up sink pipeline, we push audio data into this pipeline that will * then play it back using the default audio sink. We have no blocking * behaviour on the src which means that we will push the entire file into * memory. */ #if !SAVE_FILE string = g_strdup_printf ("appsrc name=testsource caps=\"%s\" ! autoaudiosink", audio_caps); #else string = g_strdup_printf ("appsrc name=testsource caps=\"%s\" ! avenc_aac ! avmux_adts ! filesink location=sink_src.aac", audio_caps); #endif data->sink_pipeline = gst_parse_launch (string, NULL); g_free (string); if (data->sink_pipeline == NULL) { g_print ("Bad sink\n"); return -1; } testsource = gst_bin_get_by_name (GST_BIN (data->sink_pipeline), "testsource"); /* configure for time-based format */ g_object_set (testsource, "format", GST_FORMAT_TIME, NULL); /* uncomment the next line to block when appsrc has buffered enough */ /* g_object_set (testsource, "block", TRUE, NULL); */ #if APPSRC_PULL_MODE g_signal_connect (testsource, "need-data", G_CALLBACK (on_appsrc_need_data), data); #endif gst_object_unref (testsource); bus = gst_element_get_bus (data->sink_pipeline); gst_bus_add_watch (bus, (GstBusFunc) on_appsrc_message, data); gst_object_unref (bus); /* launching things */ gst_element_set_state (data->src_pipeline, GST_STATE_PLAYING); gst_element_set_state (data->sink_pipeline, GST_STATE_PLAYING); /* let's run !, this loop will quit when the sink pipeline goes EOS or when an * error occurs in the source or sink pipelines. */ g_print ("Let's run!\n"); g_main_loop_run (data->loop); g_print ("Going out\n"); gst_element_set_state (data->src_pipeline, GST_STATE_NULL); gst_element_set_state (data->sink_pipeline, GST_STATE_NULL); gst_object_unref (data->src_pipeline); gst_object_unref (data->sink_pipeline); g_main_loop_unref (data->loop); g_free (data); return 0; }
编译:
//gcc appsink_src_test.c -o appsink_src_test $(pkg-config --cflags --libs gstreamer-1.0)
// or gcc appsink_src_test.c -o appsink_src_test $(pkg-config --cflags --libs gstreamer-1.0 gstreamer-app-1.0)
相关文章推荐
- web学习笔记09-ionic开发app的几个小坑
- gstreamer --从appsrc 到 rtmpsink推流
- Android学习之AppWidget笔记分享
- 一篇非常好的linux学习笔记分享(Linux入门绝佳)
- PowerShell学习笔记[分享]
- red5 学习笔记4 NetConnection.Connect.InvalidApp 错误
- 学习笔记:App-V测试错误代码4505CD-19D06A0A-10000004
- [学习笔记]几个英语短句(1)
- JavaScript高级程序设计学习笔记3: Math对象比较常用的几个方法
- [学习笔记]几个英语短句(2)
- Dojo 学习笔记入门篇 First Dojo Example
- [学习笔记]学C#遇到的几个问题
- Google App Engine学习笔记
- JavaScript高级程序设计学习笔记3: Math对象比较常用的几个方法
- [分享]java.util包的学习笔记一
- 一篇非常好的linux学习笔记分享(转帖)
- python基础学习笔记分享版(1)
- C++/GDI+ 学习笔记(二)——几个例子
- C++/GDI+ 学习笔记(二)——几个例子
- mojoportal学习笔记之 几个模块的数据库结构