Update theme submodule
[platform/upstream/gstreamer.git] / tutorials / playback-tutorial-4.c
1 #include <gst/gst.h>
2 #include <string.h>
3   
4 #define GRAPH_LENGTH 78
5   
6 /* playbin flags */
7 typedef enum {
8   GST_PLAY_FLAG_DOWNLOAD      = (1 << 7) /* Enable progressive download (on selected formats) */
9 } GstPlayFlags;
10   
11 typedef struct _CustomData {
12   gboolean is_live;
13   GstElement *pipeline;
14   GMainLoop *loop;
15   gint buffering_level;
16 } CustomData;
17   
18 static void got_location (GstObject *gstobject, GstObject *prop_object, GParamSpec *prop, gpointer data) {
19   gchar *location;
20   g_object_get (G_OBJECT (prop_object), "temp-location", &location, NULL);
21   g_print ("Temporary file: %s\n", location);
22   g_free (location);
23   /* Uncomment this line to keep the temporary file after the program exits */
24   /* g_object_set (G_OBJECT (prop_object), "temp-remove", FALSE, NULL); */
25 }
26   
27 static void cb_message (GstBus *bus, GstMessage *msg, CustomData *data) {
28   
29   switch (GST_MESSAGE_TYPE (msg)) {
30     case GST_MESSAGE_ERROR: {
31       GError *err;
32       gchar *debug;
33       
34       gst_message_parse_error (msg, &err, &debug);
35       g_print ("Error: %s\n", err->message);
36       g_error_free (err);
37       g_free (debug);
38       
39       gst_element_set_state (data->pipeline, GST_STATE_READY);
40       g_main_loop_quit (data->loop);
41       break;
42     }
43     case GST_MESSAGE_EOS:
44       /* end-of-stream */
45       gst_element_set_state (data->pipeline, GST_STATE_READY);
46       g_main_loop_quit (data->loop);
47       break;
48     case GST_MESSAGE_BUFFERING:
49       /* If the stream is live, we do not care about buffering. */
50       if (data->is_live) break;
51       
52       gst_message_parse_buffering (msg, &data->buffering_level);
53       
54       /* Wait until buffering is complete before start/resume playing */
55       if (data->buffering_level < 100)
56         gst_element_set_state (data->pipeline, GST_STATE_PAUSED);
57       else
58         gst_element_set_state (data->pipeline, GST_STATE_PLAYING);
59       break;
60     case GST_MESSAGE_CLOCK_LOST:
61       /* Get a new clock */
62       gst_element_set_state (data->pipeline, GST_STATE_PAUSED);
63       gst_element_set_state (data->pipeline, GST_STATE_PLAYING);
64       break;
65     default:
66       /* Unhandled message */
67       break;
68     }
69 }
70   
71 static gboolean refresh_ui (CustomData *data) {
72   GstQuery *query;
73   gboolean result;
74   
75   query = gst_query_new_buffering (GST_FORMAT_PERCENT);
76   result = gst_element_query (data->pipeline, query);
77   if (result) {
78     gint n_ranges, range, i;
79     gchar graph[GRAPH_LENGTH + 1];
80     gint64 position = 0, duration = 0;
81     
82     memset (graph, ' ', GRAPH_LENGTH);
83     graph[GRAPH_LENGTH] = '\0';
84     
85     n_ranges = gst_query_get_n_buffering_ranges (query);
86     for (range = 0; range < n_ranges; range++) {
87       gint64 start, stop;
88       gst_query_parse_nth_buffering_range (query, range, &start, &stop);
89       start = start * GRAPH_LENGTH / (stop - start);
90       stop = stop * GRAPH_LENGTH / (stop - start);
91       for (i = (gint)start; i < stop; i++)
92         graph [i] = '-';
93     }
94     if (gst_element_query_position (data->pipeline, GST_FORMAT_TIME, &position) &&
95         GST_CLOCK_TIME_IS_VALID (position) &&
96         gst_element_query_duration (data->pipeline, GST_FORMAT_TIME, &duration) &&
97         GST_CLOCK_TIME_IS_VALID (duration)) {
98       i = (gint)(GRAPH_LENGTH * (double)position / (double)(duration + 1));
99       graph [i] = data->buffering_level < 100 ? 'X' : '>';
100     }
101     g_print ("[%s]", graph);
102     if (data->buffering_level < 100) {
103       g_print (" Buffering: %3d%%", data->buffering_level);
104     } else {
105       g_print ("                ");
106     }
107     g_print ("\r");
108   }
109   
110   return TRUE;
111   
112 }
113   
114 int main(int argc, char *argv[]) {
115   GstElement *pipeline;
116   GstBus *bus;
117   GstStateChangeReturn ret;
118   GMainLoop *main_loop;
119   CustomData data;
120   guint flags;
121   
122   /* Initialize GStreamer */
123   gst_init (&argc, &argv);
124   
125   /* Initialize our data structure */
126   memset (&data, 0, sizeof (data));
127   data.buffering_level = 100;
128   
129   /* Build the pipeline */
130   pipeline = gst_parse_launch ("playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm", NULL);
131   bus = gst_element_get_bus (pipeline);
132   
133   /* Set the download flag */
134   g_object_get (pipeline, "flags", &flags, NULL);
135   flags |= GST_PLAY_FLAG_DOWNLOAD;
136   g_object_set (pipeline, "flags", flags, NULL);
137   
138   /* Uncomment this line to limit the amount of downloaded data */
139   /* g_object_set (pipeline, "ring-buffer-max-size", (guint64)4000000, NULL); */
140   
141   /* Start playing */
142   ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
143   if (ret == GST_STATE_CHANGE_FAILURE) {
144     g_printerr ("Unable to set the pipeline to the playing state.\n");
145     gst_object_unref (pipeline);
146     return -1;
147   } else if (ret == GST_STATE_CHANGE_NO_PREROLL) {
148     data.is_live = TRUE;
149   }
150   
151   main_loop = g_main_loop_new (NULL, FALSE);
152   data.loop = main_loop;
153   data.pipeline = pipeline;
154   
155   gst_bus_add_signal_watch (bus);
156   g_signal_connect (bus, "message", G_CALLBACK (cb_message), &data);
157   g_signal_connect (pipeline, "deep-notify::temp-location", G_CALLBACK (got_location), NULL);
158   
159   /* Register a function that GLib will call every second */
160   g_timeout_add_seconds (1, (GSourceFunc)refresh_ui, &data);
161   
162   g_main_loop_run (main_loop);
163   
164   /* Free resources */
165   g_main_loop_unref (main_loop);
166   gst_object_unref (bus);
167   gst_element_set_state (pipeline, GST_STATE_NULL);
168   gst_object_unref (pipeline);
169
170   g_print ("\n");
171   return 0;
172 }