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