|
1 #include <gst/gst.h> |
|
2 |
|
3 #include <string.h> |
|
4 |
|
5 #include <gst/app/gstappsrc.h> |
|
6 #include <gst/app/gstappsink.h> |
|
7 #include <gst/app/gstappbuffer.h> |
|
8 |
|
9 /* these are the caps we are going to pass through the appsink and appsrc */ |
|
10 const gchar *audio_caps = |
|
11 "audio/x-raw-int,channels=1,rate=8000,signed=(boolean)true,width=16,depth=16,endianness=1234"; |
|
12 |
|
13 typedef struct |
|
14 { |
|
15 GMainLoop *loop; |
|
16 GstElement *source; |
|
17 GstElement *sink; |
|
18 } ProgramData; |
|
19 |
|
20 /* called when the appsink notifies us that there is a new buffer ready for |
|
21 * processing */ |
|
22 static void |
|
23 on_new_buffer_from_source (GstElement * elt, ProgramData * data) |
|
24 { |
|
25 guint size; |
|
26 gpointer raw_buffer; |
|
27 GstBuffer *app_buffer, *buffer; |
|
28 GstElement *source; |
|
29 |
|
30 /* get the buffer from appsink */ |
|
31 buffer = gst_app_sink_pull_buffer (GST_APP_SINK (elt)); |
|
32 |
|
33 /* turn it into an app buffer, it's not really needed, we could simply push |
|
34 * the retrieved buffer from appsink into appsrc just fine. */ |
|
35 size = GST_BUFFER_SIZE (buffer); |
|
36 g_print ("Pushing a buffer of size %d\n", size); |
|
37 raw_buffer = g_malloc0 (size); |
|
38 memcpy (raw_buffer, GST_BUFFER_DATA (buffer), size); |
|
39 app_buffer = gst_app_buffer_new (raw_buffer, size, g_free, raw_buffer); |
|
40 |
|
41 /* newer basesrc will set caps for use automatically but it does not really |
|
42 * hurt to set it on the buffer again */ |
|
43 gst_buffer_set_caps (app_buffer, GST_BUFFER_CAPS (buffer)); |
|
44 |
|
45 /* we don't need the appsink buffer anymore */ |
|
46 gst_buffer_unref (buffer); |
|
47 |
|
48 /* get source an push new buffer */ |
|
49 source = gst_bin_get_by_name (GST_BIN (data->sink), "testsource"); |
|
50 gst_app_src_push_buffer (GST_APP_SRC (source), app_buffer); |
|
51 } |
|
52 |
|
53 /* called when we get a GstMessage from the source pipeline when we get EOS, we |
|
54 * notify the appsrc of it. */ |
|
55 static gboolean |
|
56 on_source_message (GstBus * bus, GstMessage * message, ProgramData * data) |
|
57 { |
|
58 GstElement *source; |
|
59 |
|
60 switch (GST_MESSAGE_TYPE (message)) { |
|
61 case GST_MESSAGE_EOS: |
|
62 g_print ("The source got dry\n"); |
|
63 source = gst_bin_get_by_name (GST_BIN (data->sink), "testsource"); |
|
64 gst_app_src_end_of_stream (GST_APP_SRC (source)); |
|
65 break; |
|
66 case GST_MESSAGE_ERROR: |
|
67 g_print ("Received error\n"); |
|
68 g_main_loop_quit (data->loop); |
|
69 break; |
|
70 default: |
|
71 break; |
|
72 } |
|
73 return TRUE; |
|
74 } |
|
75 |
|
76 /* called when we get a GstMessage from the sink pipeline when we get EOS, we |
|
77 * exit the mainloop and this testapp. */ |
|
78 static gboolean |
|
79 on_sink_message (GstBus * bus, GstMessage * message, ProgramData * data) |
|
80 { |
|
81 /* nil */ |
|
82 switch (GST_MESSAGE_TYPE (message)) { |
|
83 case GST_MESSAGE_EOS: |
|
84 g_print ("Finished playback\n"); |
|
85 g_main_loop_quit (data->loop); |
|
86 break; |
|
87 case GST_MESSAGE_ERROR: |
|
88 g_print ("Received error\n"); |
|
89 g_main_loop_quit (data->loop); |
|
90 break; |
|
91 default: |
|
92 break; |
|
93 } |
|
94 return TRUE; |
|
95 } |
|
96 |
|
97 int |
|
98 main (int argc, char *argv[]) |
|
99 { |
|
100 gchar *filename = NULL; |
|
101 ProgramData *data = NULL; |
|
102 gchar *string = NULL; |
|
103 GstBus *bus = NULL; |
|
104 GstElement *testsink = NULL; |
|
105 GstElement *testsource = NULL; |
|
106 |
|
107 gst_init (&argc, &argv); |
|
108 |
|
109 if (argc == 2) |
|
110 filename = g_strdup (argv[1]); |
|
111 else |
|
112 filename = g_strdup ("/usr/share/sounds/ekiga/ring.wav"); |
|
113 |
|
114 data = g_new0 (ProgramData, 1); |
|
115 |
|
116 data->loop = g_main_loop_new (NULL, FALSE); |
|
117 |
|
118 /* setting up source pipeline, we read from a file and convert to our desired |
|
119 * caps. */ |
|
120 string = |
|
121 g_strdup_printf |
|
122 ("filesrc location=\"%s\" ! wavparse ! audioconvert ! audioresample ! appsink caps=\"%s\" name=testsink", |
|
123 filename, audio_caps); |
|
124 g_free (filename); |
|
125 data->source = gst_parse_launch (string, NULL); |
|
126 g_free (string); |
|
127 |
|
128 if (data->source == NULL) { |
|
129 g_print ("Bad source\n"); |
|
130 return -1; |
|
131 } |
|
132 |
|
133 /* to be notified of messages from this pipeline, mostly EOS */ |
|
134 bus = gst_element_get_bus (data->source); |
|
135 gst_bus_add_watch (bus, (GstBusFunc) on_source_message, data); |
|
136 gst_object_unref (bus); |
|
137 |
|
138 /* we use appsink in push mode, it sends us a signal when data is available |
|
139 * and we pull out the data in the signal callback. We want the appsink to |
|
140 * push as fast as it can, hence the sync=false */ |
|
141 testsink = gst_bin_get_by_name (GST_BIN (data->source), "testsink"); |
|
142 g_object_set (G_OBJECT (testsink), "emit-signals", TRUE, "sync", FALSE, NULL); |
|
143 g_signal_connect (testsink, "new-buffer", |
|
144 G_CALLBACK (on_new_buffer_from_source), data); |
|
145 gst_object_unref (testsink); |
|
146 |
|
147 /* setting up sink pipeline, we push audio data into this pipeline that will |
|
148 * then play it back using the default audio sink. We have no blocking |
|
149 * behaviour on the src which means that we will push the entire file into |
|
150 * memory. */ |
|
151 string = |
|
152 g_strdup_printf ("appsrc name=testsource caps=\"%s\" ! autoaudiosink", |
|
153 audio_caps); |
|
154 data->sink = gst_parse_launch (string, NULL); |
|
155 g_free (string); |
|
156 |
|
157 if (data->sink == NULL) { |
|
158 g_print ("Bad sink\n"); |
|
159 return -1; |
|
160 } |
|
161 |
|
162 testsource = gst_bin_get_by_name (GST_BIN (data->sink), "testsource"); |
|
163 /* configure for time-based format */ |
|
164 g_object_set (testsource, "format", GST_FORMAT_TIME, NULL); |
|
165 /* uncomment the next line to block when appsrc has buffered enough */ |
|
166 /* g_object_set (testsource, "block", TRUE, NULL); */ |
|
167 gst_object_unref (testsource); |
|
168 |
|
169 bus = gst_element_get_bus (data->sink); |
|
170 gst_bus_add_watch (bus, (GstBusFunc) on_sink_message, data); |
|
171 gst_object_unref (bus); |
|
172 |
|
173 /* launching things */ |
|
174 gst_element_set_state (data->sink, GST_STATE_PLAYING); |
|
175 gst_element_set_state (data->source, GST_STATE_PLAYING); |
|
176 |
|
177 /* let's run !, this loop will quit when the sink pipeline goes EOS or when an |
|
178 * error occurs in the source or sink pipelines. */ |
|
179 g_print ("Let's run!\n"); |
|
180 g_main_loop_run (data->loop); |
|
181 g_print ("Going out\n"); |
|
182 |
|
183 gst_element_set_state (data->source, GST_STATE_NULL); |
|
184 gst_element_set_state (data->sink, GST_STATE_NULL); |
|
185 |
|
186 gst_object_unref (data->source); |
|
187 gst_object_unref (data->sink); |
|
188 g_main_loop_unref (data->loop); |
|
189 g_free (data); |
|
190 |
|
191 return 0; |
|
192 } |