b142fa7f0c93448cb53d284abab1b615c367f3c4
[platform/upstream/gstreamer.git] / tutorials / playback-tutorial-1.c
1 #include <stdio.h>\r
2 #include <gst/gst.h>\r
3   \r
4 /* Structure to contain all our information, so we can pass it around */\r
5 typedef struct _CustomData {\r
6   GstElement *playbin;  /* Our one and only element */\r
7   \r
8   gint n_video;          /* Number of embedded video streams */\r
9   gint n_audio;          /* Number of embedded audio streams */\r
10   gint n_text;           /* Number of embedded subtitle streams */\r
11   \r
12   gint current_video;    /* Currently playing video stream */\r
13   gint current_audio;    /* Currently playing audio stream */\r
14   gint current_text;     /* Currently playing subtitle stream */\r
15   \r
16   GMainLoop *main_loop;  /* GLib's Main Loop */\r
17 } CustomData;\r
18   \r
19 /* playbin flags */\r
20 typedef enum {\r
21   GST_PLAY_FLAG_VIDEO         = (1 << 0), /* We want video output */\r
22   GST_PLAY_FLAG_AUDIO         = (1 << 1), /* We want audio output */\r
23   GST_PLAY_FLAG_TEXT          = (1 << 2)  /* We want subtitle output */\r
24 } GstPlayFlags;\r
25   \r
26 /* Forward definition for the message and keyboard processing functions */\r
27 static gboolean handle_message (GstBus *bus, GstMessage *msg, CustomData *data);\r
28 static gboolean handle_keyboard (GIOChannel *source, GIOCondition cond, CustomData *data);\r
29   \r
30 int main(int argc, char *argv[]) {\r
31   CustomData data;\r
32   GstBus *bus;\r
33   GstStateChangeReturn ret;\r
34   gint flags;\r
35   GIOChannel *io_stdin;\r
36   \r
37   /* Initialize GStreamer */\r
38   gst_init (&argc, &argv);\r
39    \r
40   /* Create the elements */\r
41   data.playbin = gst_element_factory_make ("playbin", "playbin");\r
42   \r
43   if (!data.playbin) {\r
44     g_printerr ("Not all elements could be created.\n");\r
45     return -1;\r
46   }\r
47   \r
48   /* Set the URI to play */\r
49   g_object_set (data.playbin, "uri", "https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_cropped_multilingual.webm", NULL);\r
50   \r
51   /* Set flags to show Audio and Video but ignore Subtitles */\r
52   g_object_get (data.playbin, "flags", &flags, NULL);\r
53   flags |= GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_AUDIO;\r
54   flags &= ~GST_PLAY_FLAG_TEXT;\r
55   g_object_set (data.playbin, "flags", flags, NULL);\r
56   \r
57   /* Set connection speed. This will affect some internal decisions of playbin */\r
58   g_object_set (data.playbin, "connection-speed", 56, NULL);\r
59   \r
60   /* Add a bus watch, so we get notified when a message arrives */\r
61   bus = gst_element_get_bus (data.playbin);\r
62   gst_bus_add_watch (bus, (GstBusFunc)handle_message, &data);\r
63   \r
64   /* Add a keyboard watch so we get notified of keystrokes */\r
65 #ifdef G_OS_WIN32\r
66   io_stdin = g_io_channel_win32_new_fd (fileno (stdin));\r
67 #else\r
68   io_stdin = g_io_channel_unix_new (fileno (stdin));\r
69 #endif\r
70   g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc)handle_keyboard, &data);\r
71   \r
72   /* Start playing */\r
73   ret = gst_element_set_state (data.playbin, GST_STATE_PLAYING);\r
74   if (ret == GST_STATE_CHANGE_FAILURE) {\r
75     g_printerr ("Unable to set the pipeline to the playing state.\n");\r
76     gst_object_unref (data.playbin);\r
77     return -1;\r
78   }\r
79   \r
80   /* Create a GLib Main Loop and set it to run */\r
81   data.main_loop = g_main_loop_new (NULL, FALSE);\r
82   g_main_loop_run (data.main_loop);\r
83   \r
84   /* Free resources */\r
85   g_main_loop_unref (data.main_loop);\r
86   g_io_channel_unref (io_stdin);\r
87   gst_object_unref (bus);\r
88   gst_element_set_state (data.playbin, GST_STATE_NULL);\r
89   gst_object_unref (data.playbin);\r
90   return 0;\r
91 }\r
92   \r
93 /* Extract some metadata from the streams and print it on the screen */\r
94 static void analyze_streams (CustomData *data) {\r
95   gint i;\r
96   GstTagList *tags;\r
97   gchar *str;\r
98   guint rate;\r
99   \r
100   /* Read some properties */\r
101   g_object_get (data->playbin, "n-video", &data->n_video, NULL);\r
102   g_object_get (data->playbin, "n-audio", &data->n_audio, NULL);\r
103   g_object_get (data->playbin, "n-text", &data->n_text, NULL);\r
104   \r
105   g_print ("%d video stream(s), %d audio stream(s), %d text stream(s)\n",\r
106     data->n_video, data->n_audio, data->n_text);\r
107   \r
108   g_print ("\n");\r
109   for (i = 0; i < data->n_video; i++) {\r
110     tags = NULL;\r
111     /* Retrieve the stream's video tags */\r
112     g_signal_emit_by_name (data->playbin, "get-video-tags", i, &tags);\r
113     if (tags) {\r
114       g_print ("video stream %d:\n", i);\r
115       gst_tag_list_get_string (tags, GST_TAG_VIDEO_CODEC, &str);\r
116       g_print ("  codec: %s\n", str ? str : "unknown");\r
117       g_free (str);\r
118       gst_tag_list_unref (tags);\r
119     }\r
120   }\r
121   \r
122   g_print ("\n");\r
123   for (i = 0; i < data->n_audio; i++) {\r
124     tags = NULL;\r
125     /* Retrieve the stream's audio tags */\r
126     g_signal_emit_by_name (data->playbin, "get-audio-tags", i, &tags);\r
127     if (tags) {\r
128       g_print ("audio stream %d:\n", i);\r
129       if (gst_tag_list_get_string (tags, GST_TAG_AUDIO_CODEC, &str)) {\r
130         g_print ("  codec: %s\n", str);\r
131         g_free (str);\r
132       }\r
133       if (gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &str)) {\r
134         g_print ("  language: %s\n", str);\r
135         g_free (str);\r
136       }\r
137       if (gst_tag_list_get_uint (tags, GST_TAG_BITRATE, &rate)) {\r
138         g_print ("  bitrate: %d\n", rate);\r
139       }\r
140       gst_tag_list_unref (tags);\r
141     }\r
142   }\r
143   \r
144   g_print ("\n");\r
145   for (i = 0; i < data->n_text; i++) {\r
146     tags = NULL;\r
147     /* Retrieve the stream's subtitle tags */\r
148     g_signal_emit_by_name (data->playbin, "get-text-tags", i, &tags);\r
149     if (tags) {\r
150       g_print ("subtitle stream %d:\n", i);\r
151       if (gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &str)) {\r
152         g_print ("  language: %s\n", str);\r
153         g_free (str);\r
154       }\r
155       gst_tag_list_unref (tags);\r
156     }\r
157   }\r
158   \r
159   g_object_get (data->playbin, "current-video", &data->current_video, NULL);\r
160   g_object_get (data->playbin, "current-audio", &data->current_audio, NULL);\r
161   g_object_get (data->playbin, "current-text", &data->current_text, NULL);\r
162   \r
163   g_print ("\n");\r
164   g_print ("Currently playing video stream %d, audio stream %d and text stream %d\n",\r
165     data->current_video, data->current_audio, data->current_text);\r
166   g_print ("Type any number and hit ENTER to select a different audio stream\n");\r
167 }\r
168   \r
169 /* Process messages from GStreamer */\r
170 static gboolean handle_message (GstBus *bus, GstMessage *msg, CustomData *data) {\r
171   GError *err;\r
172   gchar *debug_info;\r
173   \r
174   switch (GST_MESSAGE_TYPE (msg)) {\r
175     case GST_MESSAGE_ERROR:\r
176       gst_message_parse_error (msg, &err, &debug_info);\r
177       g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);\r
178       g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");\r
179       g_clear_error (&err);\r
180       g_free (debug_info);\r
181       g_main_loop_quit (data->main_loop);\r
182       break;\r
183     case GST_MESSAGE_EOS:\r
184       g_print ("End-Of-Stream reached.\n");\r
185       g_main_loop_quit (data->main_loop);\r
186       break;\r
187     case GST_MESSAGE_STATE_CHANGED: {\r
188       GstState old_state, new_state, pending_state;\r
189       gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);\r
190       if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data->playbin)) {\r
191         if (new_state == GST_STATE_PLAYING) {\r
192           /* Once we are in the playing state, analyze the streams */\r
193           analyze_streams (data);\r
194         }\r
195       }\r
196     } break;\r
197     default:\r
198       break;\r
199   }\r
200   \r
201   /* We want to keep receiving messages */\r
202   return TRUE;\r
203 }\r
204   \r
205 /* Process keyboard input */\r
206 static gboolean handle_keyboard (GIOChannel *source, GIOCondition cond, CustomData *data) {\r
207   gchar *str = NULL;\r
208   \r
209   if (g_io_channel_read_line (source, &str, NULL, NULL, NULL) == G_IO_STATUS_NORMAL) {\r
210     int index = g_ascii_strtoull (str, NULL, 0);\r
211     if (index < 0 || index >= data->n_audio) {\r
212       g_printerr ("Index out of bounds\n");\r
213     } else {\r
214       /* If the input was a valid audio stream index, set the current audio stream */\r
215       g_print ("Setting current audio stream to %d\n", index);\r
216       g_object_set (data->playbin, "current-audio", index, NULL);\r
217     }\r
218   }\r
219   g_free (str);\r
220   return TRUE;\r
221 }\r