#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;
}
本文链接地址:https://const.net.cn/801.html

标签: none

添加新评论