playback-tutorial-3/basic-tutorial-8: Fix buffer duration calculations
[platform/upstream/gstreamer.git] / markdown / tutorials / playback / short-cutting-the-pipeline.md
1 # Playback tutorial 3: Short-cutting the pipeline
2
3 ## Goal
4
5 [](tutorials/basic/short-cutting-the-pipeline.md) showed
6 how an application can manually extract or inject data into a pipeline
7 by using two special elements called `appsrc` and `appsink`.
8 `playbin` allows using these elements too, but the method to connect
9 them is different. To connect an `appsink` to `playbin` see [](tutorials/playback/custom-playbin-sinks.md).
10 This tutorial shows:
11
12   - How to connect `appsrc` with `playbin`
13   - How to configure the `appsrc`
14
15 ## A playbin waveform generator
16
17 Copy this code into a text file named `playback-tutorial-3.c`.
18
19 **playback-tutorial-3.c**
20
21 ``` c
22 #include <gst/gst.h>
23 #include <gst/audio/audio.h>
24 #include <string.h>
25
26 #define CHUNK_SIZE 1024   /* Amount of bytes we are sending in each buffer */
27 #define SAMPLE_RATE 44100 /* Samples per second we are sending */
28
29 /* Structure to contain all our information, so we can pass it to callbacks */
30 typedef struct _CustomData {
31   GstElement *pipeline;
32   GstElement *app_source;
33
34   guint64 num_samples;   /* Number of samples generated so far (for timestamp generation) */
35   gfloat a, b, c, d;     /* For waveform generation */
36
37   guint sourceid;        /* To control the GSource */
38
39   GMainLoop *main_loop;  /* GLib's Main Loop */
40 } CustomData;
41
42 /* This method is called by the idle GSource in the mainloop, to feed CHUNK_SIZE bytes into appsrc.
43  * The ide handler is added to the mainloop when appsrc requests us to start sending data (need-data signal)
44  * and is removed when appsrc has enough data (enough-data signal).
45  */
46 static gboolean push_data (CustomData *data) {
47   GstBuffer *buffer;
48   GstFlowReturn ret;
49   int i;
50   GstMapInfo map;
51   gint16 *raw;
52   gint num_samples = CHUNK_SIZE / 2; /* Because each sample is 16 bits */
53   gfloat freq;
54
55   /* Create a new empty buffer */
56   buffer = gst_buffer_new_and_alloc (CHUNK_SIZE);
57
58   /* Set its timestamp and duration */
59   GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (data->num_samples, GST_SECOND, SAMPLE_RATE);
60   GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (num_samples, GST_SECOND, SAMPLE_RATE);
61
62   /* Generate some psychodelic waveforms */
63   gst_buffer_map (buffer, &map, GST_MAP_WRITE);
64   raw = (gint16 *)map.data;
65   data->c += data->d;
66   data->d -= data->c / 1000;
67   freq = 1100 + 1000 * data->d;
68   for (i = 0; i < num_samples; i++) {
69     data->a += data->b;
70     data->b -= data->a / freq;
71     raw[i] = (gint16)(500 * data->a);
72   }
73   gst_buffer_unmap (buffer, &map);
74   data->num_samples += num_samples;
75
76   /* Push the buffer into the appsrc */
77   g_signal_emit_by_name (data->app_source, "push-buffer", buffer, &ret);
78
79   /* Free the buffer now that we are done with it */
80   gst_buffer_unref (buffer);
81
82   if (ret != GST_FLOW_OK) {
83     /* We got some error, stop sending data */
84     return FALSE;
85   }
86
87   return TRUE;
88 }
89
90 /* This signal callback triggers when appsrc needs data. Here, we add an idle handler
91  * to the mainloop to start pushing data into the appsrc */
92 static void start_feed (GstElement *source, guint size, CustomData *data) {
93   if (data->sourceid == 0) {
94     g_print ("Start feeding\n");
95     data->sourceid = g_idle_add ((GSourceFunc) push_data, data);
96   }
97 }
98
99 /* This callback triggers when appsrc has enough data and we can stop sending.
100  * We remove the idle handler from the mainloop */
101 static void stop_feed (GstElement *source, CustomData *data) {
102   if (data->sourceid != 0) {
103     g_print ("Stop feeding\n");
104     g_source_remove (data->sourceid);
105     data->sourceid = 0;
106   }
107 }
108
109 /* This function is called when an error message is posted on the bus */
110 static void error_cb (GstBus *bus, GstMessage *msg, CustomData *data) {
111   GError *err;
112   gchar *debug_info;
113
114   /* Print error details on the screen */
115   gst_message_parse_error (msg, &err, &debug_info);
116   g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);
117   g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");
118   g_clear_error (&err);
119   g_free (debug_info);
120
121   g_main_loop_quit (data->main_loop);
122 }
123
124 /* This function is called when playbin has created the appsrc element, so we have
125  * a chance to configure it. */
126 static void source_setup (GstElement *pipeline, GstElement *source, CustomData *data) {
127   GstAudioInfo info;
128   GstCaps *audio_caps;
129
130   g_print ("Source has been created. Configuring.\n");
131   data->app_source = source;
132
133   /* Configure appsrc */
134   gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, SAMPLE_RATE, 1, NULL);
135   audio_caps = gst_audio_info_to_caps (&info);
136   g_object_set (source, "caps", audio_caps, "format", GST_FORMAT_TIME, NULL);
137   g_signal_connect (source, "need-data", G_CALLBACK (start_feed), data);
138   g_signal_connect (source, "enough-data", G_CALLBACK (stop_feed), data);
139   gst_caps_unref (audio_caps);
140 }
141
142 int main(int argc, char *argv[]) {
143   CustomData data;
144   GstBus *bus;
145
146   /* Initialize cumstom data structure */
147   memset (&data, 0, sizeof (data));
148   data.b = 1; /* For waveform generation */
149   data.d = 1;
150
151   /* Initialize GStreamer */
152   gst_init (&argc, &argv);
153
154   /* Create the playbin element */
155   data.pipeline = gst_parse_launch ("playbin uri=appsrc://", NULL);
156   g_signal_connect (data.pipeline, "source-setup", G_CALLBACK (source_setup), &data);
157
158   /* Instruct the bus to emit signals for each received message, and connect to the interesting signals */
159   bus = gst_element_get_bus (data.pipeline);
160   gst_bus_add_signal_watch (bus);
161   g_signal_connect (G_OBJECT (bus), "message::error", (GCallback)error_cb, &data);
162   gst_object_unref (bus);
163
164   /* Start playing the pipeline */
165   gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
166
167   /* Create a GLib Main Loop and set it to run */
168   data.main_loop = g_main_loop_new (NULL, FALSE);
169   g_main_loop_run (data.main_loop);
170
171   /* Free resources */
172   gst_element_set_state (data.pipeline, GST_STATE_NULL);
173   gst_object_unref (data.pipeline);
174   return 0;
175 }
176 ```
177
178 To use an `appsrc` as the source for the pipeline, simply instantiate a
179 `playbin` and set its URI to `appsrc://`
180
181 ``` c
182 /* Create the playbin element */
183 data.pipeline = gst_parse_launch ("playbin uri=appsrc://", NULL);
184 ```
185
186 `playbin` will create an internal `appsrc` element and fire the
187 `source-setup` signal to allow the application to configure
188 it:
189
190 ``` c
191 g_signal_connect (data.pipeline, "source-setup", G_CALLBACK (source_setup), &data);
192 ```
193
194 In particular, it is important to set the caps property of `appsrc`,
195 since, once the signal handler returns, `playbin` will instantiate the
196 next element in the pipeline according to these
197 caps:
198
199 ``` c
200 /* This function is called when playbin has created the appsrc element, so we have
201  * a chance to configure it. */
202 static void source_setup (GstElement *pipeline, GstElement *source, CustomData *data) {
203   GstAudioInfo info;
204   GstCaps *audio_caps;
205
206   g_print ("Source has been created. Configuring.\n");
207   data->app_source = source;
208
209   /* Configure appsrc */
210   gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, SAMPLE_RATE, 1, NULL);
211   audio_caps = gst_audio_info_to_caps (&info);
212   g_object_set (source, "caps", audio_caps, "format", GST_FORMAT_TIME, NULL);
213   g_signal_connect (source, "need-data", G_CALLBACK (start_feed), data);
214   g_signal_connect (source, "enough-data", G_CALLBACK (stop_feed), data);
215   gst_caps_unref (audio_caps);
216 }
217 ```
218
219 The configuration of the `appsrc` is exactly the same as in
220 [](tutorials/basic/short-cutting-the-pipeline.md):
221 the caps are set to `audio/x-raw`, and two callbacks are registered,
222 so the element can tell the application when it needs to start and stop
223 pushing data. See [](tutorials/basic/short-cutting-the-pipeline.md)
224 for more details.
225
226 From this point onwards, `playbin` takes care of the rest of the
227 pipeline, and the application only needs to worry about generating more
228 data when told so.
229
230 To learn how data can be extracted from `playbin` using the
231 `appsink` element, see [](tutorials/playback/custom-playbin-sinks.md).
232
233 ## Conclusion
234
235 This tutorial applies the concepts shown in
236 [](tutorials/basic/short-cutting-the-pipeline.md) to
237 `playbin`. In particular, it has shown:
238
239   - How to connect `appsrc` with `playbin` using the special
240     URI `appsrc://`
241   - How to configure the `appsrc` using the `source-setup` signal
242
243 It has been a pleasure having you here, and see you soon!