gstreamer学习笔记:分享几个appsink和appsrc的example

来源:互联网 发布:五星宏辉网络运行版 编辑:程序博客网 时间:2024/05/17 18:28

(1)appsink的使用:

#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"intmain (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 GstFlowReturnon_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 gbooleanon_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 gbooleanon_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)





1 0
原创粉丝点击