Free caps in GUPnPDLNAProfilePriv
[gupnp:gupnp-dlna.git] / tests / dlna-encoding.c
1 /* Example application for using GstProfile and encodebin
2  * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser 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.
8  *
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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdlib.h>
25 #include <glib.h>
26 #include <gst/gst.h>
27 #include <gst/pbutils/pbutils.h>
28 #include <gst/pbutils/encoding-profile.h>
29 #include <libgupnp-dlna/gupnp-dlna-discoverer.h>
30
31 static gboolean silent = FALSE;
32
33 static void
34 pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstElement * encodebin)
35 {
36   GstPad *sinkpad;
37
38   sinkpad = gst_element_get_compatible_pad (encodebin, pad, NULL);
39
40   if (sinkpad == NULL) {
41     GstCaps *caps;
42
43     /* Ask encodebin for a compatible pad */
44     caps = gst_pad_get_caps (pad);
45     g_signal_emit_by_name (encodebin, "request-pad", caps, &sinkpad);
46     if (caps)
47       gst_caps_unref (caps);
48   }
49   if (sinkpad == NULL) {
50     g_print ("Couldn't get an encoding channel for pad %s:%s\n",
51         GST_DEBUG_PAD_NAME (pad));
52     return;
53   }
54
55   if (G_UNLIKELY (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) {
56     g_print ("Couldn't link pads\n");
57   }
58
59   return;
60 }
61
62 static gboolean
63 autoplug_continue_cb (GstElement * uridecodebin, GstPad * somepad,
64     GstCaps * caps, GstElement * encodebin)
65 {
66   GstPad *sinkpad;
67
68   g_signal_emit_by_name (encodebin, "request-pad", caps, &sinkpad);
69
70   if (sinkpad == NULL)
71     return TRUE;
72
73   return FALSE;
74 }
75
76 static void
77 bus_message_cb (GstBus * bus, GstMessage * message, GMainLoop * mainloop)
78 {
79   switch (GST_MESSAGE_TYPE (message)) {
80     case GST_MESSAGE_ERROR:
81       g_print ("ERROR\n");
82       g_main_loop_quit (mainloop);
83       break;
84     case GST_MESSAGE_EOS:
85       g_print ("Done\n");
86       g_main_loop_quit (mainloop);
87       break;
88     default:
89       break;
90   }
91 }
92
93 static void
94 transcode_file (gchar * uri, gchar * outputuri, GstEncodingProfile * prof)
95 {
96   GstElement *pipeline;
97   GstElement *src;
98   GstElement *ebin;
99   GstElement *sink;
100   GstBus *bus;
101   GstCaps *profilecaps, *rescaps;
102   GMainLoop *mainloop;
103
104   g_print (" Input URI  : %s\n", uri);
105   g_print (" Output URI : %s\n", outputuri);
106
107   sink = gst_element_make_from_uri (GST_URI_SINK, outputuri, "sink");
108   if (G_UNLIKELY (sink == NULL)) {
109     g_print ("Can't create output sink, most likely invalid output URI !\n");
110     return;
111   }
112
113   src = gst_element_factory_make ("uridecodebin", NULL);
114   if (G_UNLIKELY (src == NULL)) {
115     g_print ("Can't create uridecodebin for input URI, aborting!\n");
116     return;
117   }
118
119   /* Figure out the streams that can be passed as-is to encodebin */
120   g_object_get (src, "caps", &rescaps, NULL);
121   rescaps = gst_caps_copy (rescaps);
122   profilecaps = gst_encoding_profile_get_input_caps (prof);
123   gst_caps_append (rescaps, profilecaps);
124
125   /* Set properties */
126   g_object_set (src, "uri", uri, "caps", rescaps, NULL);
127
128   ebin = gst_element_factory_make ("encodebin", NULL);
129   g_object_set (ebin, "profile", prof, NULL);
130
131   g_signal_connect (src, "autoplug-continue", G_CALLBACK (autoplug_continue_cb),
132       ebin);
133   g_signal_connect (src, "pad-added", G_CALLBACK (pad_added_cb), ebin);
134
135   pipeline = gst_pipeline_new ("encoding-pipeline");
136
137   gst_bin_add_many (GST_BIN (pipeline), src, ebin, sink, NULL);
138
139   gst_element_link (ebin, sink);
140
141   mainloop = g_main_loop_new (NULL, FALSE);
142
143   bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
144   gst_bus_add_signal_watch (bus);
145   g_signal_connect (bus, "message", G_CALLBACK (bus_message_cb), mainloop);
146
147   if (gst_element_set_state (pipeline,
148           GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
149     g_print ("Failed to start the encoding\n");
150     return;
151   }
152
153   g_main_loop_run (mainloop);
154
155   gst_element_set_state (pipeline, GST_STATE_NULL);
156   gst_object_unref (pipeline);
157 }
158
159 static gchar *
160 ensure_uri (gchar * location)
161 {
162   gchar *res;
163   gchar *path;
164
165   if (gst_uri_is_valid (location))
166     return g_strdup (location);
167
168   if (!g_path_is_absolute (location)) {
169     gchar *cur_dir;
170     cur_dir = g_get_current_dir ();
171     path = g_build_filename (cur_dir, location, NULL);
172     g_free (cur_dir);
173   } else
174     path = g_strdup (location);
175
176   res = g_filename_to_uri (path, NULL, NULL);
177   g_free (path);
178
179   return res;
180 }
181
182 int
183 main (int argc, char **argv)
184 {
185   GError *err = NULL;
186   gchar *outputuri = NULL;
187   gchar *format = NULL;
188   GOptionEntry options[] = {
189     {"silent", 's', 0, G_OPTION_ARG_NONE, &silent,
190         "Don't output the information structure", NULL},
191     {"outputuri", 'o', 0, G_OPTION_ARG_STRING, &outputuri,
192         "URI to encode to", "URI (<protocol>://<location>)"},
193     {"format", 'f', 0, G_OPTION_ARG_STRING, &format,
194         "DLNA profile to use", NULL},
195     {NULL}
196   };
197   GOptionContext *ctx;
198   GUPnPDLNADiscoverer *discoverer;
199   GUPnPDLNAProfile *profile;
200   gchar *inputuri;
201
202   if (!g_thread_supported ())
203     g_thread_init (NULL);
204
205   ctx = g_option_context_new ("- encode URIs with GstProfile and encodebin");
206   g_option_context_add_main_entries (ctx, options, NULL);
207   g_option_context_add_group (ctx, gst_init_get_option_group ());
208
209   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
210     g_print ("Error initializing: %s\n", err->message);
211     exit (1);
212   }
213
214   g_option_context_free (ctx);
215
216   if (outputuri == NULL || argc != 2) {
217     g_print ("usage: %s <inputuri> -o <outputuri> --format <profile>\n",
218         argv[0]);
219     exit (-1);
220   }
221
222   gst_init(&argc, &argv);
223
224   /* Create the profile */
225   discoverer = gupnp_dlna_discoverer_new ((GstClockTime) GST_SECOND,
226                                           FALSE,
227                                           FALSE);
228   profile = gupnp_dlna_discoverer_get_profile (discoverer, format);
229   if (G_UNLIKELY (profile == NULL)) {
230     g_print ("Encoding arguments are not valid !\n");
231     return 1;
232   }
233
234   /* Fixup outputuri to be a URI */
235   inputuri = ensure_uri (argv[1]);
236   outputuri = ensure_uri (outputuri);
237
238   /* Trancode file */
239   transcode_file (inputuri,
240                   outputuri,
241                   gupnp_dlna_profile_get_encoding_profile (profile));
242
243   /* cleanup */
244   g_object_unref (profile);
245   g_object_unref (discoverer);
246
247   return 0;
248 }