Advertisement
Guest User

Untitled

a guest
Dec 11th, 2017
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.35 KB | None | 0 0
  1. /* Compile: gcc -g -o basic-tutorial-8b basic-tutorial-8b.c `pkg-config gstreamermm-1.0 --cflags --libs` */
  2.  
  3. #include <gst/gst.h>
  4. #include <gst/audio/audio.h>
  5. #include <stdint.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9.  
  10. #define CHUNK_SIZE 1024   /* Amount of bytes we are sending in each buffer */
  11. #define SAMPLE uint8_t
  12.  
  13. /* Structure to contain all our information, so we can pass it to callbacks */
  14. typedef struct _CustomData {
  15.   GstElement *pipeline, *app_source, *tee, *audio_queue, *audio_convert1, *audio_resample, *audio_sink;
  16.   GstElement *video_queue, *audio_convert2, *visual, *video_convert, *video_sink;
  17.   GstElement *app_queue, *app_sink;
  18.  
  19.   uint64_t playback_offset;   /* Number of samples generated so far (for timestamp generation) */
  20.   uint32_t samplerate;
  21.   uint8_t  channels;
  22.   size_t   length;
  23.  
  24.   SAMPLE *samples;
  25.  
  26.   guint sourceid;        /* To control the GSource */
  27.  
  28.   GMainLoop *main_loop;  /* GLib's Main Loop */
  29. } CustomData;
  30.  
  31. void load_raw(CustomData *data, char *path, uint32_t samplerate, uint8_t channels)
  32. {
  33.     /* Yes this is quick and dirty -- I'm just using it for testing. */
  34.  
  35.     data->samplerate = samplerate;
  36.     data->channels = channels;
  37.     FILE *file = fopen(path, "r");
  38.  
  39.     /* Go to the end of the file to get its length */
  40.     fseek(file, 0L, SEEK_END);
  41.     data->length = ftell(file) * sizeof(SAMPLE);
  42.  
  43.     rewind(file);
  44.  
  45.     /* Read the data */
  46.     data->samples = calloc(data->length, sizeof(SAMPLE));
  47.  
  48.     fread(data->samples, data->length, sizeof(SAMPLE), file);
  49.  
  50.     fclose(file);
  51. }
  52.  
  53. /* This method is called by the idle GSource in the mainloop, to feed CHUNK_SIZE bytes into appsrc.
  54.  * The ide handler is added to the mainloop when appsrc requests us to start sending data (need-data signal)
  55.  * and is removed when appsrc has enough data (enough-data signal).
  56.  */
  57. static gboolean push_data (CustomData *data) {
  58.   GstBuffer *buffer;
  59.   GstFlowReturn ret;
  60.   int i;
  61.   GstMapInfo map;
  62.   SAMPLE *raw;
  63.   gint num_samples = CHUNK_SIZE / sizeof(SAMPLE);
  64.   gfloat freq;
  65.  
  66.   /* Create a new empty buffer */
  67.   buffer = gst_buffer_new_and_alloc (CHUNK_SIZE);
  68.  
  69.   /* Set its timestamp and duration */
  70.   GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (data->playback_offset, GST_SECOND, data->samplerate);
  71.   GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (CHUNK_SIZE, GST_SECOND, data->samplerate);
  72.  
  73.   /* Generate some psychodelic waveforms */
  74.   gst_buffer_map (buffer, &map, GST_MAP_WRITE);
  75.   raw = (SAMPLE *) map.data;
  76.  
  77.   memcpy(raw, data->samples + (data->playback_offset * data->channels), num_samples);
  78.  
  79.   gst_buffer_unmap (buffer, &map);
  80.   data->playback_offset += num_samples;
  81.  
  82.   /* Push the buffer into the appsrc */
  83.   g_signal_emit_by_name (data->app_source, "push-buffer", buffer, &ret);
  84.  
  85.   /* Free the buffer now that we are done with it */
  86.   gst_buffer_unref (buffer);
  87.  
  88.   if (ret != GST_FLOW_OK) {
  89.     /* We got some error, stop sending data */
  90.     return FALSE;
  91.   }
  92.  
  93.   return TRUE;
  94. }
  95.  
  96. /* This signal callback triggers when appsrc needs data. Here, we add an idle handler
  97.  * to the mainloop to start pushing data into the appsrc */
  98. static void start_feed (GstElement *source, guint size, CustomData *data) {
  99.   if (data->sourceid == 0) {
  100.     g_print ("Start feeding\n");
  101.     data->sourceid = g_idle_add ((GSourceFunc) push_data, data);
  102.   }
  103. }
  104.  
  105. /* This callback triggers when appsrc has enough data and we can stop sending.
  106.  * We remove the idle handler from the mainloop */
  107. static void stop_feed (GstElement *source, CustomData *data) {
  108.   if (data->sourceid != 0) {
  109.     g_print ("Stop feeding\n");
  110.     g_source_remove (data->sourceid);
  111.     data->sourceid = 0;
  112.   }
  113. }
  114.  
  115. /* The appsink has received a buffer */
  116. static void new_sample (GstElement *sink, CustomData *data) {
  117.   GstSample *sample;
  118.  
  119.   /* Retrieve the buffer */
  120.   g_signal_emit_by_name (sink, "pull-sample", &sample);
  121.   if (sample) {
  122.     GstBuffer *buffer = gst_sample_get_buffer(sample);
  123.     /* The only thing we do in this example is print a * to indicate a received buffer */
  124.     g_print ("*");
  125.     gst_buffer_unref (sample);
  126.   }
  127. }
  128.  
  129. /* This function is called when an error message is posted on the bus */
  130. static void error_cb (GstBus *bus, GstMessage *msg, CustomData *data) {
  131.   GError *err;
  132.   gchar *debug_info;
  133.  
  134.   /* Print error details on the screen */
  135.   gst_message_parse_error (msg, &err, &debug_info);
  136.   g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);
  137.   g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");
  138.   g_clear_error (&err);
  139.   g_free (debug_info);
  140.  
  141.   g_main_loop_quit (data->main_loop);
  142. }
  143.  
  144. int main(int argc, char *argv[]) {
  145.   CustomData data;
  146.   GstPad *tee_audio_pad, *tee_video_pad, *tee_app_pad;
  147.   GstPad *queue_audio_pad, *queue_video_pad, *queue_app_pad;
  148.   GstAudioInfo info;
  149.   GstCaps *audio_caps;
  150.   GstBus *bus;
  151.  
  152.   /* Initialize cumstom data structure */
  153.   memset (&data, 0, sizeof (data));
  154.  
  155.   /* Initialize GStreamer */
  156.   gst_init (&argc, &argv);
  157.  
  158.   /* Load the file */
  159.   load_raw(&data, "./wicked dub_8.raw", 44100, 1);
  160.  
  161.   /* Create the elements */
  162.   data.app_source = gst_element_factory_make ("appsrc", "audio_source");
  163.   data.tee = gst_element_factory_make ("tee", "tee");
  164.   data.audio_queue = gst_element_factory_make ("queue", "audio_queue");
  165.   data.audio_convert1 = gst_element_factory_make ("audioconvert", "audio_convert1");
  166.   data.audio_resample = gst_element_factory_make ("audioresample", "audio_resample");
  167.   data.audio_sink = gst_element_factory_make ("autoaudiosink", "audio_sink");
  168.   data.video_queue = gst_element_factory_make ("queue", "video_queue");
  169.   data.audio_convert2 = gst_element_factory_make ("audioconvert", "audio_convert2");
  170.   data.visual = gst_element_factory_make ("wavescope", "visual");
  171.   data.video_convert = gst_element_factory_make ("videoconvert", "csp");
  172.   data.video_sink = gst_element_factory_make ("autovideosink", "video_sink");
  173.   data.app_queue = gst_element_factory_make ("queue", "app_queue");
  174.   data.app_sink = gst_element_factory_make ("appsink", "app_sink");
  175.  
  176.   /* Create the empty pipeline */
  177.   data.pipeline = gst_pipeline_new ("test-pipeline");
  178.  
  179.   if (!data.pipeline || !data.app_source || !data.tee || !data.audio_queue || !data.audio_convert1 ||
  180.       !data.audio_resample || !data.audio_sink || !data.video_queue || !data.audio_convert2 || !data.visual ||
  181.       !data.video_convert || !data.video_sink || !data.app_queue || !data.app_sink) {
  182.     g_printerr ("Not all elements could be created.\n");
  183.     return -1;
  184.   }
  185.  
  186.   /* Configure wavescope */
  187.   g_object_set (data.visual, "shader", 0, "style", 0, NULL);
  188.  
  189.   /* Configure appsrc */
  190.   gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_U8, (gint) data.samplerate, (gint) data.channels, NULL);
  191.   audio_caps = gst_audio_info_to_caps (&info);
  192.   g_object_set (data.app_source, "caps", audio_caps, "format", GST_FORMAT_TIME, NULL);
  193.   g_signal_connect (data.app_source, "need-data", G_CALLBACK (start_feed), &data);
  194.   g_signal_connect (data.app_source, "enough-data", G_CALLBACK (stop_feed), &data);
  195.  
  196.   /* Configure appsink */
  197.   g_object_set (data.app_sink, "emit-signals", TRUE, "caps", audio_caps, NULL);
  198.   g_signal_connect (data.app_sink, "new-sample", G_CALLBACK (new_sample), &data);
  199.   gst_caps_unref (audio_caps);
  200.   //g_free (audio_caps_text);
  201.  
  202.   /* Link all elements that can be automatically linked because they have "Always" pads */
  203.   gst_bin_add_many (GST_BIN (data.pipeline), data.app_source, data.tee, data.audio_queue, data.audio_convert1, data.audio_resample,
  204.       data.audio_sink, data.video_queue, data.audio_convert2, data.visual, data.video_convert, data.video_sink, data.app_queue,
  205.       data.app_sink, NULL);
  206.   if (gst_element_link_many (data.app_source, data.tee, NULL) != TRUE ||
  207.       gst_element_link_many (data.audio_queue, data.audio_convert1, data.audio_resample, data.audio_sink, NULL) != TRUE ||
  208.       gst_element_link_many (data.video_queue, data.audio_convert2, data.visual, data.video_convert, data.video_sink, NULL) != TRUE ||
  209.       gst_element_link_many (data.app_queue, data.app_sink, NULL) != TRUE) {
  210.     g_printerr ("Elements could not be linked.\n");
  211.     gst_object_unref (data.pipeline);
  212.     return -1;
  213.   }
  214.  
  215.   /* Manually link the Tee, which has "Request" pads */
  216.   tee_audio_pad = gst_element_get_request_pad (data.tee, "src_%u");
  217.   g_print ("Obtained request pad %s for audio branch.\n", gst_pad_get_name (tee_audio_pad));
  218.   queue_audio_pad = gst_element_get_static_pad (data.audio_queue, "sink");
  219.   tee_video_pad = gst_element_get_request_pad (data.tee, "src_%u");
  220.   g_print ("Obtained request pad %s for video branch.\n", gst_pad_get_name (tee_video_pad));
  221.   queue_video_pad = gst_element_get_static_pad (data.video_queue, "sink");
  222.   tee_app_pad = gst_element_get_request_pad (data.tee, "src_%u");
  223.   g_print ("Obtained request pad %s for app branch.\n", gst_pad_get_name (tee_app_pad));
  224.   queue_app_pad = gst_element_get_static_pad (data.app_queue, "sink");
  225.   if (gst_pad_link (tee_audio_pad, queue_audio_pad) != GST_PAD_LINK_OK ||
  226.       gst_pad_link (tee_video_pad, queue_video_pad) != GST_PAD_LINK_OK ||
  227.       gst_pad_link (tee_app_pad, queue_app_pad) != GST_PAD_LINK_OK) {
  228.     g_printerr ("Tee could not be linked\n");
  229.     gst_object_unref (data.pipeline);
  230.     return -1;
  231.   }
  232.   gst_object_unref (queue_audio_pad);
  233.   gst_object_unref (queue_video_pad);
  234.   gst_object_unref (queue_app_pad);
  235.  
  236.   /* Instruct the bus to emit signals for each received message, and connect to the interesting signals */
  237.   bus = gst_element_get_bus (data.pipeline);
  238.   gst_bus_add_signal_watch (bus);
  239.   g_signal_connect (G_OBJECT (bus), "message::error", (GCallback)error_cb, &data);
  240.   gst_object_unref (bus);
  241.  
  242.   /* Start playing the pipeline */
  243.   gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
  244.  
  245.   /* Create a GLib Main Loop and set it to run */
  246.   data.main_loop = g_main_loop_new (NULL, FALSE);
  247.   g_main_loop_run (data.main_loop);
  248.  
  249.   /* Release the request pads from the Tee, and unref them */
  250.   gst_element_release_request_pad (data.tee, tee_audio_pad);
  251.   gst_element_release_request_pad (data.tee, tee_video_pad);
  252.   gst_element_release_request_pad (data.tee, tee_app_pad);
  253.   gst_object_unref (tee_audio_pad);
  254.   gst_object_unref (tee_video_pad);
  255.   gst_object_unref (tee_app_pad);
  256.  
  257.   /* Free resources */
  258.   gst_element_set_state (data.pipeline, GST_STATE_NULL);
  259.   gst_object_unref (data.pipeline);
  260.   return 0;
  261. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement