1 /* Example application for using GstProfile and encodebin
2 * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
26 #include <glib/gprintf.h>
28 #include <gst/pbutils/pbutils.h>
29 #include <gst/pbutils/encoding-profile.h>
30 #include "gstcapslist.h"
32 static gboolean silent = FALSE;
41 caps = gst_caps_new_empty ();
43 g_print ("Available container formats:\n");
44 l = gst_caps_list_container_formats (GST_RANK_NONE);
45 len = gst_caps_get_size (l);
46 for (i = 0; i < len; i++) {
47 GstStructure *st = gst_caps_steal_structure (l, 0);
50 gst_caps_append_structure (caps, st);
52 tmpstr = gst_caps_to_string (caps);
53 desc = gst_pb_utils_get_codec_description (caps);
54 g_print (" %s - %s\n", desc, tmpstr);
58 gst_caps_remove_structure (caps, 0);
63 g_print ("Available video codecs:\n");
64 l = gst_caps_list_video_encoding_formats (GST_RANK_NONE);
65 len = gst_caps_get_size (l);
66 for (i = 0; i < len; i++) {
67 GstStructure *st = gst_caps_steal_structure (l, 0);
70 gst_caps_append_structure (caps, st);
72 tmpstr = gst_caps_to_string (caps);
73 desc = gst_pb_utils_get_codec_description (caps);
74 g_print (" %s - %s\n", desc, tmpstr);
78 gst_caps_remove_structure (caps, 0);
83 g_print ("Available audio codecs:\n");
84 l = gst_caps_list_audio_encoding_formats (GST_RANK_NONE);
85 len = gst_caps_get_size (l);
86 for (i = 0; i < len; i++) {
87 GstStructure *st = gst_caps_steal_structure (l, 0);
90 gst_caps_append_structure (caps, st);
92 tmpstr = gst_caps_to_string (caps);
93 desc = gst_pb_utils_get_codec_description (caps);
94 g_print (" %s - %s\n", desc, tmpstr);
98 gst_caps_remove_structure (caps, 0);
103 gst_caps_unref (caps);
107 generate_filename (const GstCaps * container, const GstCaps * vcodec,
108 const GstCaps * acodec)
114 a = gst_pb_utils_get_codec_description (container);
115 b = gst_pb_utils_get_codec_description (vcodec);
116 c = gst_pb_utils_get_codec_description (acodec);
119 a = g_strdup_printf ("%.10s",
120 g_uri_escape_string (gst_caps_to_string (container), NULL, FALSE));
122 b = g_strdup_printf ("%.10s",
123 g_uri_escape_string (gst_caps_to_string (vcodec), NULL, FALSE));
125 c = g_strdup_printf ("%.10s",
126 g_uri_escape_string (gst_caps_to_string (acodec), NULL, FALSE));
128 for (i = 0; i < 256 && res == NULL; i++) {
129 res = g_strdup_printf ("%s-%s-%s-%d.file", a, b, c, i);
130 if (g_file_test (res, G_FILE_TEST_EXISTS)) {
135 /* Make sure file doesn't already exist */
144 static GstEncodingProfile *
145 create_profile (GstCaps * cf, GstCaps * vf, GstCaps * af)
147 GstEncodingContainerProfile *cprof = NULL;
150 gst_encoding_container_profile_new ((gchar *) "test-application-profile",
154 gst_encoding_container_profile_add_profile (cprof,
155 (GstEncodingProfile *) gst_encoding_video_profile_new (vf,
158 gst_encoding_container_profile_add_profile (cprof, (GstEncodingProfile *)
159 gst_encoding_audio_profile_new (af, NULL, NULL, 0));
161 /* Let's print out some info */
163 gchar *desc = gst_pb_utils_get_codec_description (cf);
164 gchar *cd = gst_caps_to_string (cf);
165 g_print ("Encoding parameters\n");
166 g_print (" Container format : %s (%s)\n", desc, cd);
170 desc = gst_pb_utils_get_codec_description (vf);
171 cd = gst_caps_to_string (vf);
172 g_print (" Video format : %s (%s)\n", desc, cd);
177 desc = gst_pb_utils_get_codec_description (af);
178 cd = gst_caps_to_string (af);
179 g_print (" Audio format : %s (%s)\n", desc, cd);
185 return (GstEncodingProfile *) cprof;
188 static GstEncodingProfile *
189 create_profile_from_string (gchar * format, gchar * vformat, gchar * aformat)
191 GstEncodingProfile *prof = NULL;
192 GstCaps *cf = NULL, *vf = NULL, *af = NULL;
195 cf = gst_caps_from_string (format);
197 vf = gst_caps_from_string (vformat);
199 af = gst_caps_from_string (aformat);
201 if (G_UNLIKELY ((vformat && (vf == NULL)) || (aformat && (af == NULL))))
204 prof = create_profile (cf, vf, af);
218 pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstElement * encodebin)
222 sinkpad = gst_element_get_compatible_pad (encodebin, pad, NULL);
224 if (sinkpad == NULL) {
227 /* Ask encodebin for a compatible pad */
228 caps = gst_pad_query_caps (pad, NULL);
229 g_signal_emit_by_name (encodebin, "request-pad", caps, &sinkpad);
231 gst_caps_unref (caps);
233 if (sinkpad == NULL) {
234 g_print ("Couldn't get an encoding channel for pad %s:%s\n",
235 GST_DEBUG_PAD_NAME (pad));
239 if (G_UNLIKELY (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) {
240 g_print ("Couldn't link pads\n");
247 autoplug_continue_cb (GstElement * uridecodebin, GstPad * somepad,
248 GstCaps * caps, GstElement * encodebin)
252 g_signal_emit_by_name (encodebin, "request-pad", caps, &sinkpad);
261 bus_message_cb (GstBus * bus, GstMessage * message, GMainLoop * mainloop)
263 switch (GST_MESSAGE_TYPE (message)) {
264 case GST_MESSAGE_ERROR:
266 gst_bus_set_flushing (bus, TRUE);
267 g_main_loop_quit (mainloop);
269 case GST_MESSAGE_EOS:
271 g_main_loop_quit (mainloop);
279 transcode_file (gchar * uri, gchar * outputuri, GstEncodingProfile * prof)
281 GstElement *pipeline;
286 GstCaps *profilecaps, *rescaps;
289 g_print (" Input URI : %s\n", uri);
290 g_print (" Output URI : %s\n", outputuri);
292 sink = gst_element_make_from_uri (GST_URI_SINK, outputuri, "sink");
293 if (G_UNLIKELY (sink == NULL)) {
294 g_print ("Can't create output sink, most likely invalid output URI !\n");
298 src = gst_element_factory_make ("uridecodebin", NULL);
299 if (G_UNLIKELY (src == NULL)) {
300 g_print ("Can't create uridecodebin for input URI, aborting!\n");
304 /* Figure out the streams that can be passed as-is to encodebin */
305 g_object_get (src, "caps", &rescaps, NULL);
306 rescaps = gst_caps_copy (rescaps);
307 profilecaps = gst_encoding_profile_get_input_caps (prof);
308 gst_caps_append (rescaps, profilecaps);
311 g_object_set (src, "uri", uri, "caps", rescaps, NULL);
313 ebin = gst_element_factory_make ("encodebin", NULL);
314 g_object_set (ebin, "profile", prof, NULL);
316 g_signal_connect (src, "autoplug-continue", G_CALLBACK (autoplug_continue_cb),
318 g_signal_connect (src, "pad-added", G_CALLBACK (pad_added_cb), ebin);
320 pipeline = gst_pipeline_new ("encoding-pipeline");
322 gst_bin_add_many (GST_BIN (pipeline), src, ebin, sink, NULL);
324 gst_element_link (ebin, sink);
326 mainloop = g_main_loop_new (NULL, FALSE);
328 bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
329 gst_bus_add_signal_watch (bus);
330 g_signal_connect (bus, "message", G_CALLBACK (bus_message_cb), mainloop);
332 if (gst_element_set_state (pipeline,
333 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
334 g_print ("Failed to start the encoding\n");
338 g_main_loop_run (mainloop);
340 gst_element_set_state (pipeline, GST_STATE_NULL);
341 gst_object_unref (pipeline);
345 ensure_uri (gchar * location)
350 if (gst_uri_is_valid (location))
351 return g_strdup (location);
353 if (!g_path_is_absolute (location)) {
355 cur_dir = g_get_current_dir ();
356 path = g_build_filename (cur_dir, location, NULL);
359 path = g_strdup (location);
361 res = g_filename_to_uri (path, NULL, NULL);
368 main (int argc, char **argv)
371 gchar *outputuri = NULL;
372 gchar *format = NULL;
373 gchar *aformat = NULL;
374 gchar *vformat = NULL;
375 gboolean allmissing = FALSE;
376 gboolean listcodecs = FALSE;
377 GOptionEntry options[] = {
378 {"silent", 's', 0, G_OPTION_ARG_NONE, &silent,
379 "Don't output the information structure", NULL},
380 {"outputuri", 'o', 0, G_OPTION_ARG_STRING, &outputuri,
381 "URI to encode to", "URI (<protocol>://<location>)"},
382 {"format", 'f', 0, G_OPTION_ARG_STRING, &format,
383 "Container format", "<GstCaps>"},
384 {"vformat", 'v', 0, G_OPTION_ARG_STRING, &vformat,
385 "Video format", "<GstCaps>"},
386 {"aformat", 'a', 0, G_OPTION_ARG_STRING, &aformat,
387 "Audio format", "<GstCaps>"},
388 {"allmissing", 'm', 0, G_OPTION_ARG_NONE, &allmissing,
389 "encode to all matching format/codec that aren't specified", NULL},
390 {"list-codecs", 'l', 0, G_OPTION_ARG_NONE, &listcodecs,
391 "list all available codecs and container formats", NULL},
395 GstEncodingProfile *prof;
398 #if !GLIB_CHECK_VERSION (2, 31, 0)
399 if (!g_thread_supported ())
400 g_thread_init (NULL);
403 ctx = g_option_context_new ("- encode URIs with GstProfile and encodebin");
404 g_option_context_add_main_entries (ctx, options, NULL);
405 g_option_context_add_group (ctx, gst_init_get_option_group ());
407 if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
408 g_print ("Error initializing: %s\n", err->message);
414 g_option_context_free (ctx);
418 if (outputuri == NULL || argc != 2) {
419 g_print ("%s", g_option_context_get_help (ctx, TRUE, NULL));
420 g_option_context_free (ctx);
424 g_option_context_free (ctx);
426 /* Fixup outputuri to be a URI */
427 inputuri = ensure_uri (argv[1]);
428 outputuri = ensure_uri (outputuri);
432 GstCaps *formats = NULL;
433 GstCaps *vformats = NULL;
434 GstCaps *aformats = NULL;
435 guint f, v, a, flen, vlen, alen;
438 formats = gst_caps_list_container_formats (GST_RANK_NONE);
440 formats = gst_caps_from_string (format);
443 vformats = gst_caps_list_video_encoding_formats (GST_RANK_NONE);
445 vformats = gst_caps_from_string (vformat);
448 aformats = gst_caps_list_audio_encoding_formats (GST_RANK_NONE);
450 aformats = gst_caps_from_string (aformat);
452 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_MUXER,
455 flen = gst_caps_get_size (formats);
457 for (f = 0; f < flen; f++) {
459 gst_caps_new_full (gst_caps_steal_structure (formats, 0), NULL);
461 gst_caps_list_compatible_codecs (container, vformats, muxers);
463 gst_caps_list_compatible_codecs (container, aformats, muxers);
465 vlen = gst_caps_get_size (compatv);
466 alen = gst_caps_get_size (compata);
469 for (v = 0; v < vlen; v++) {
471 gst_caps_new_full (gst_structure_copy (gst_caps_get_structure
472 (compatv, v)), NULL);
473 for (a = 0; a < alen; a++) {
475 gst_caps_new_full (gst_structure_copy (gst_caps_get_structure
476 (compata, a)), NULL);
479 create_profile ((GstCaps *) container, (GstCaps *) vcodec,
481 if (G_UNLIKELY (prof == NULL)) {
482 g_print ("Wrong arguments\n");
486 ensure_uri (generate_filename (container, vcodec, acodec));
487 transcode_file (inputuri, outputuri, prof);
488 gst_encoding_profile_unref (prof);
490 gst_caps_unref (acodec);
492 gst_caps_unref (vcodec);
494 gst_caps_unref (container);
499 /* Create the profile */
500 prof = create_profile_from_string (format, vformat, aformat);
501 if (G_UNLIKELY (prof == NULL)) {
502 g_print ("Encoding arguments are not valid !\n");
507 transcode_file (inputuri, outputuri, prof);
510 gst_encoding_profile_unref (prof);