mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-19 08:11:16 +00:00
190 lines
5.7 KiB
C
190 lines
5.7 KiB
C
#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-int,channels=1,rate=8000,signed=(boolean)true,width=16,depth=16,endianness=1234";
|
|
|
|
typedef struct
|
|
{
|
|
GMainLoop *loop;
|
|
GstElement *source;
|
|
GstElement *sink;
|
|
} ProgramData;
|
|
|
|
/* called when the appsink notifies us that there is a new buffer ready for
|
|
* processing */
|
|
static void
|
|
on_new_buffer_from_source (GstElement * elt, ProgramData * data)
|
|
{
|
|
guint size;
|
|
GstBuffer *app_buffer, *buffer;
|
|
GstElement *source;
|
|
|
|
/* get the buffer from appsink */
|
|
buffer = gst_app_sink_pull_buffer (GST_APP_SINK (elt));
|
|
|
|
/* turn it into an app buffer, it's not really needed, we could simply push
|
|
* the retrieved buffer from appsink into appsrc just fine. */
|
|
size = gst_buffer_get_size (buffer);
|
|
g_print ("Pushing a buffer of size %d\n", size);
|
|
app_buffer = gst_buffer_new_and_alloc (size);
|
|
|
|
gst_buffer_copy_into (app_buffer, buffer, GST_BUFFER_COPY_MEMORY, 0, size);
|
|
|
|
/* newer basesrc will set caps for use automatically but it does not really
|
|
* hurt to set it on the buffer again */
|
|
gst_buffer_set_caps (app_buffer, GST_BUFFER_CAPS (buffer));
|
|
|
|
/* we don't need the appsink buffer anymore */
|
|
gst_buffer_unref (buffer);
|
|
|
|
/* get source an push new buffer */
|
|
source = gst_bin_get_by_name (GST_BIN (data->sink), "testsource");
|
|
gst_app_src_push_buffer (GST_APP_SRC (source), app_buffer);
|
|
}
|
|
|
|
/* called when we get a GstMessage from the source pipeline when we get EOS, we
|
|
* notify the appsrc of it. */
|
|
static gboolean
|
|
on_source_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), "testsource");
|
|
gst_app_src_end_of_stream (GST_APP_SRC (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_sink_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;
|
|
}
|
|
|
|
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 ("/usr/share/sounds/ekiga/ring.wav");
|
|
|
|
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. */
|
|
string =
|
|
g_strdup_printf
|
|
("filesrc location=\"%s\" ! wavparse ! audioconvert ! audioresample ! appsink caps=\"%s\" name=testsink",
|
|
filename, audio_caps);
|
|
g_free (filename);
|
|
data->source = gst_parse_launch (string, NULL);
|
|
g_free (string);
|
|
|
|
if (data->source == NULL) {
|
|
g_print ("Bad source\n");
|
|
return -1;
|
|
}
|
|
|
|
/* to be notified of messages from this pipeline, mostly EOS */
|
|
bus = gst_element_get_bus (data->source);
|
|
gst_bus_add_watch (bus, (GstBusFunc) on_source_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->source), "testsink");
|
|
g_object_set (G_OBJECT (testsink), "emit-signals", TRUE, "sync", FALSE, NULL);
|
|
g_signal_connect (testsink, "new-buffer",
|
|
G_CALLBACK (on_new_buffer_from_source), data);
|
|
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. */
|
|
string =
|
|
g_strdup_printf ("appsrc name=testsource caps=\"%s\" ! autoaudiosink",
|
|
audio_caps);
|
|
data->sink = gst_parse_launch (string, NULL);
|
|
g_free (string);
|
|
|
|
if (data->sink == NULL) {
|
|
g_print ("Bad sink\n");
|
|
return -1;
|
|
}
|
|
|
|
testsource = gst_bin_get_by_name (GST_BIN (data->sink), "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); */
|
|
gst_object_unref (testsource);
|
|
|
|
bus = gst_element_get_bus (data->sink);
|
|
gst_bus_add_watch (bus, (GstBusFunc) on_sink_message, data);
|
|
gst_object_unref (bus);
|
|
|
|
/* launching things */
|
|
gst_element_set_state (data->sink, GST_STATE_PLAYING);
|
|
gst_element_set_state (data->source, 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->source, GST_STATE_NULL);
|
|
gst_element_set_state (data->sink, GST_STATE_NULL);
|
|
|
|
gst_object_unref (data->source);
|
|
gst_object_unref (data->sink);
|
|
g_main_loop_unref (data->loop);
|
|
g_free (data);
|
|
|
|
return 0;
|
|
}
|