tizen 2.0 init
[framework/multimedia/gst-plugins-good0.10.git] / gst / isomp4 / gstqtmoovrecover.c
1 /* Quicktime muxer plugin for GStreamer
2  * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@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 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.
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  * Library General Public License for more details.
13  *
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.
18  */
19 /*
20  * Unless otherwise indicated, Source Code is licensed under MIT license.
21  * See further explanation attached in License Statement (distributed in the file
22  * LICENSE).
23  *
24  * Permission is hereby granted, free of charge, to any person obtaining a copy of
25  * this software and associated documentation files (the "Software"), to deal in
26  * the Software without restriction, including without limitation the rights to
27  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
28  * of the Software, and to permit persons to whom the Software is furnished to do
29  * so, subject to the following conditions:
30  *
31  * The above copyright notice and this permission notice shall be included in all
32  * copies or substantial portions of the Software.
33  *
34  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40  * SOFTWARE.
41  */
42
43
44 /**
45  * SECTION:element-qtmoovrecover
46  * @short_description: Utility element for recovering unfinished quicktime files
47  *
48  * <refsect2>
49  * <para>
50  * This element recovers quicktime files created with qtmux using the moov
51  * recovery feature.
52  * </para>
53  * <title>Example pipelines</title>
54  * <para>
55  * <programlisting>
56  * TODO
57  * </programlisting>
58  * </para>
59  * </refsect2>
60  *
61  * Documentation last reviewed on 2011-04-21
62  */
63
64 #ifdef HAVE_CONFIG_H
65 #include "config.h"
66 #endif
67
68 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
69  * with newer GLib versions (>= 2.31.0) */
70 #define GLIB_DISABLE_DEPRECATION_WARNINGS
71
72 #include <glib/gstdio.h>
73 #include <gst/gst.h>
74
75 #include "gstqtmoovrecover.h"
76
77 GST_DEBUG_CATEGORY_STATIC (gst_qt_moov_recover_debug);
78 #define GST_CAT_DEFAULT gst_qt_moov_recover_debug
79
80 /* QTMoovRecover signals and args */
81 enum
82 {
83   /* FILL ME */
84   LAST_SIGNAL
85 };
86
87 enum
88 {
89   PROP_0,
90   PROP_RECOVERY_INPUT,
91   PROP_BROKEN_INPUT,
92   PROP_FIXED_OUTPUT,
93   PROP_FAST_START_MODE
94 };
95
96 GST_BOILERPLATE (GstQTMoovRecover, gst_qt_moov_recover, GstPipeline,
97     GST_TYPE_PIPELINE);
98
99 /* property functions */
100 static void gst_qt_moov_recover_set_property (GObject * object,
101     guint prop_id, const GValue * value, GParamSpec * pspec);
102 static void gst_qt_moov_recover_get_property (GObject * object,
103     guint prop_id, GValue * value, GParamSpec * pspec);
104
105 static GstStateChangeReturn gst_qt_moov_recover_change_state (GstElement *
106     element, GstStateChange transition);
107
108 static void gst_qt_moov_recover_finalize (GObject * object);
109
110 static void
111 gst_qt_moov_recover_base_init (gpointer g_class)
112 {
113   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
114 #if 0
115   GstQTMoovRecoverClass *klass = (GstQTMoovRecoverClass *) g_class;
116 #endif
117   gst_element_class_set_details_simple (element_class, "QT Moov Recover",
118       "Util", "Recovers unfinished qtmux files",
119       "Thiago Santos <thiago.sousa.santos@collabora.co.uk>");
120 }
121
122 static void
123 gst_qt_moov_recover_class_init (GstQTMoovRecoverClass * klass)
124 {
125   GObjectClass *gobject_class;
126   GstElementClass *gstelement_class;
127
128   gobject_class = (GObjectClass *) klass;
129   gstelement_class = (GstElementClass *) klass;
130
131   parent_class = g_type_class_peek_parent (klass);
132
133   gobject_class->finalize = gst_qt_moov_recover_finalize;
134   gobject_class->get_property = gst_qt_moov_recover_get_property;
135   gobject_class->set_property = gst_qt_moov_recover_set_property;
136
137   gstelement_class->change_state = gst_qt_moov_recover_change_state;
138
139   g_object_class_install_property (gobject_class, PROP_FIXED_OUTPUT,
140       g_param_spec_string ("fixed-output",
141           "Path to write the fixed file",
142           "Path to write the fixed file to (used as output)",
143           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
144   g_object_class_install_property (gobject_class, PROP_BROKEN_INPUT,
145       g_param_spec_string ("broken-input",
146           "Path to broken input file",
147           "Path to broken input file. (If qtmux was on faststart mode, this "
148           "file is the faststart file)", NULL,
149           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
150   g_object_class_install_property (gobject_class, PROP_RECOVERY_INPUT,
151       g_param_spec_string ("recovery-input",
152           "Path to recovery file",
153           "Path to recovery file (used as input)", NULL,
154           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
155   g_object_class_install_property (gobject_class, PROP_FAST_START_MODE,
156       g_param_spec_boolean ("faststart-mode",
157           "If the broken input is from faststart mode",
158           "If the broken input is from faststart mode",
159           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
160
161   GST_DEBUG_CATEGORY_INIT (gst_qt_moov_recover_debug, "qtmoovrecover", 0,
162       "QT Moovie Recover");
163 }
164
165 static void
166 gst_qt_moov_recover_init (GstQTMoovRecover * qtmr,
167     GstQTMoovRecoverClass * qtmr_klass)
168 {
169 }
170
171 static void
172 gst_qt_moov_recover_finalize (GObject * object)
173 {
174   G_OBJECT_CLASS (parent_class)->finalize (object);
175 }
176
177 static void
178 gst_qt_moov_recover_run (void *data)
179 {
180   FILE *moovrec = NULL;
181   FILE *mdatinput = NULL;
182   FILE *output = NULL;
183   MdatRecovFile *mdat_recov = NULL;
184   MoovRecovFile *moov_recov = NULL;
185   GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (data);
186   GError *err = NULL;
187
188   GST_LOG_OBJECT (qtmr, "Starting task");
189
190   GST_DEBUG_OBJECT (qtmr, "Validating properties");
191   GST_OBJECT_LOCK (qtmr);
192   /* validate properties */
193   if (qtmr->broken_input == NULL) {
194     GST_OBJECT_UNLOCK (qtmr);
195     GST_ELEMENT_ERROR (qtmr, RESOURCE, SETTINGS,
196         ("Please set broken-input property"), (NULL));
197     goto end;
198   }
199   if (qtmr->recovery_input == NULL) {
200     GST_OBJECT_UNLOCK (qtmr);
201     GST_ELEMENT_ERROR (qtmr, RESOURCE, SETTINGS,
202         ("Please set recovery-input property"), (NULL));
203     goto end;
204   }
205   if (qtmr->fixed_output == NULL) {
206     GST_OBJECT_UNLOCK (qtmr);
207     GST_ELEMENT_ERROR (qtmr, RESOURCE, SETTINGS,
208         ("Please set fixed-output property"), (NULL));
209     goto end;
210   }
211
212   GST_DEBUG_OBJECT (qtmr, "Opening input/output files");
213   /* open files */
214   moovrec = g_fopen (qtmr->recovery_input, "rb");
215   if (moovrec == NULL) {
216     GST_OBJECT_UNLOCK (qtmr);
217     GST_ELEMENT_ERROR (qtmr, RESOURCE, OPEN_READ,
218         ("Failed to open recovery-input file"), (NULL));
219     goto end;
220   }
221
222   mdatinput = g_fopen (qtmr->broken_input, "rb");
223   if (mdatinput == NULL) {
224     GST_OBJECT_UNLOCK (qtmr);
225     GST_ELEMENT_ERROR (qtmr, RESOURCE, OPEN_READ,
226         ("Failed to open broken-input file"), (NULL));
227     goto end;
228   }
229   output = g_fopen (qtmr->fixed_output, "wb+");
230   if (output == NULL) {
231     GST_OBJECT_UNLOCK (qtmr);
232     GST_ELEMENT_ERROR (qtmr, RESOURCE, OPEN_READ_WRITE,
233         ("Failed to open fixed-output file"), (NULL));
234     goto end;
235   }
236   GST_OBJECT_UNLOCK (qtmr);
237
238   GST_DEBUG_OBJECT (qtmr, "Parsing input files");
239   /* now create our structures */
240   mdat_recov = mdat_recov_file_create (mdatinput, qtmr->faststart_mode, &err);
241   mdatinput = NULL;
242   if (mdat_recov == NULL) {
243     GST_ELEMENT_ERROR (qtmr, RESOURCE, FAILED,
244         ("Broken file could not be parsed correctly"), (NULL));
245     goto end;
246   }
247   moov_recov = moov_recov_file_create (moovrec, &err);
248   moovrec = NULL;
249   if (moov_recov == NULL) {
250     GST_ELEMENT_ERROR (qtmr, RESOURCE, FAILED,
251         ("Recovery file could not be parsed correctly"), (NULL));
252     goto end;
253   }
254
255   /* now parse the buffers data from moovrec */
256   if (!moov_recov_parse_buffers (moov_recov, mdat_recov, &err)) {
257     goto end;
258   }
259
260   GST_DEBUG_OBJECT (qtmr, "Writing fixed file to output");
261   if (!moov_recov_write_file (moov_recov, mdat_recov, output, &err)) {
262     goto end;
263   }
264
265   /* here means success */
266   GST_DEBUG_OBJECT (qtmr, "Finished successfully, posting EOS");
267   gst_element_post_message (GST_ELEMENT_CAST (qtmr),
268       gst_message_new_eos (GST_OBJECT_CAST (qtmr)));
269
270 end:
271   GST_LOG_OBJECT (qtmr, "Finalizing task");
272   if (err) {
273     GST_ELEMENT_ERROR (qtmr, RESOURCE, FAILED, ("%s", err->message), (NULL));
274     g_error_free (err);
275   }
276
277   if (moov_recov)
278     moov_recov_file_free (moov_recov);
279   if (moovrec)
280     fclose (moovrec);
281
282   if (mdat_recov)
283     mdat_recov_file_free (mdat_recov);
284   if (mdatinput)
285     fclose (mdatinput);
286
287   if (output)
288     fclose (output);
289   GST_LOG_OBJECT (qtmr, "Leaving task");
290   gst_task_stop (qtmr->task);
291 }
292
293 static void
294 gst_qt_moov_recover_get_property (GObject * object,
295     guint prop_id, GValue * value, GParamSpec * pspec)
296 {
297   GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (object);
298
299   GST_OBJECT_LOCK (qtmr);
300   switch (prop_id) {
301     case PROP_FAST_START_MODE:
302       g_value_set_boolean (value, qtmr->faststart_mode);
303       break;
304     case PROP_BROKEN_INPUT:
305       g_value_set_string (value, qtmr->broken_input);
306       break;
307     case PROP_RECOVERY_INPUT:
308       g_value_set_string (value, qtmr->recovery_input);
309       break;
310     case PROP_FIXED_OUTPUT:
311       g_value_set_string (value, qtmr->fixed_output);
312       break;
313     default:
314       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
315       break;
316   }
317   GST_OBJECT_UNLOCK (qtmr);
318 }
319
320 static void
321 gst_qt_moov_recover_set_property (GObject * object,
322     guint prop_id, const GValue * value, GParamSpec * pspec)
323 {
324   GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (object);
325
326   GST_OBJECT_LOCK (qtmr);
327   switch (prop_id) {
328     case PROP_FAST_START_MODE:
329       qtmr->faststart_mode = g_value_get_boolean (value);
330       break;
331     case PROP_BROKEN_INPUT:
332       g_free (qtmr->broken_input);
333       qtmr->broken_input = g_value_dup_string (value);
334       break;
335     case PROP_RECOVERY_INPUT:
336       g_free (qtmr->recovery_input);
337       qtmr->recovery_input = g_value_dup_string (value);
338       break;
339     case PROP_FIXED_OUTPUT:
340       g_free (qtmr->fixed_output);
341       qtmr->fixed_output = g_value_dup_string (value);
342       break;
343     default:
344       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
345       break;
346   }
347   GST_OBJECT_UNLOCK (qtmr);
348 }
349
350 static GstStateChangeReturn
351 gst_qt_moov_recover_change_state (GstElement * element,
352     GstStateChange transition)
353 {
354   GstStateChangeReturn ret;
355   GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (element);
356
357   switch (transition) {
358     case GST_STATE_CHANGE_NULL_TO_READY:
359       qtmr->task = gst_task_create (gst_qt_moov_recover_run, qtmr);
360       g_static_rec_mutex_init (&qtmr->task_mutex);
361       gst_task_set_lock (qtmr->task, &qtmr->task_mutex);
362       break;
363     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
364       gst_task_start (qtmr->task);
365       break;
366     default:
367       break;
368   }
369
370   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
371
372   switch (transition) {
373     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
374       gst_task_stop (qtmr->task);
375       gst_task_join (qtmr->task);
376       break;
377     case GST_STATE_CHANGE_READY_TO_NULL:
378       g_assert (gst_task_get_state (qtmr->task) == GST_TASK_STOPPED);
379       gst_object_unref (qtmr->task);
380       qtmr->task = NULL;
381       g_static_rec_mutex_free (&qtmr->task_mutex);
382       break;
383     default:
384       break;
385   }
386   return ret;
387 }
388
389
390 gboolean
391 gst_qt_moov_recover_register (GstPlugin * plugin)
392 {
393   return gst_element_register (plugin, "qtmoovrecover", GST_RANK_NONE,
394       GST_TYPE_QT_MOOV_RECOVER);
395 }