upload tizen1.0 source
[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 #include <glib/gstdio.h>
69 #include <gst/gst.h>
70
71 #include "gstqtmoovrecover.h"
72
73 GST_DEBUG_CATEGORY_STATIC (gst_qt_moov_recover_debug);
74 #define GST_CAT_DEFAULT gst_qt_moov_recover_debug
75
76 /* QTMoovRecover signals and args */
77 enum
78 {
79   /* FILL ME */
80   LAST_SIGNAL
81 };
82
83 enum
84 {
85   PROP_0,
86   PROP_RECOVERY_INPUT,
87   PROP_BROKEN_INPUT,
88   PROP_FIXED_OUTPUT,
89   PROP_FAST_START_MODE
90 };
91
92 GST_BOILERPLATE (GstQTMoovRecover, gst_qt_moov_recover, GstPipeline,
93     GST_TYPE_PIPELINE);
94
95 /* property functions */
96 static void gst_qt_moov_recover_set_property (GObject * object,
97     guint prop_id, const GValue * value, GParamSpec * pspec);
98 static void gst_qt_moov_recover_get_property (GObject * object,
99     guint prop_id, GValue * value, GParamSpec * pspec);
100
101 static GstStateChangeReturn gst_qt_moov_recover_change_state (GstElement *
102     element, GstStateChange transition);
103
104 static void gst_qt_moov_recover_finalize (GObject * object);
105
106 static void
107 gst_qt_moov_recover_base_init (gpointer g_class)
108 {
109   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
110 #if 0
111   GstQTMoovRecoverClass *klass = (GstQTMoovRecoverClass *) g_class;
112 #endif
113   gst_element_class_set_details_simple (element_class, "QT Moov Recover",
114       "Util", "Recovers unfinished qtmux files",
115       "Thiago Santos <thiago.sousa.santos@collabora.co.uk>");
116 }
117
118 static void
119 gst_qt_moov_recover_class_init (GstQTMoovRecoverClass * klass)
120 {
121   GObjectClass *gobject_class;
122   GstElementClass *gstelement_class;
123
124   gobject_class = (GObjectClass *) klass;
125   gstelement_class = (GstElementClass *) klass;
126
127   parent_class = g_type_class_peek_parent (klass);
128
129   gobject_class->finalize = gst_qt_moov_recover_finalize;
130   gobject_class->get_property = gst_qt_moov_recover_get_property;
131   gobject_class->set_property = gst_qt_moov_recover_set_property;
132
133   gstelement_class->change_state = gst_qt_moov_recover_change_state;
134
135   g_object_class_install_property (gobject_class, PROP_FIXED_OUTPUT,
136       g_param_spec_string ("fixed-output",
137           "Path to write the fixed file",
138           "Path to write the fixed file to (used as output)",
139           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
140   g_object_class_install_property (gobject_class, PROP_BROKEN_INPUT,
141       g_param_spec_string ("broken-input",
142           "Path to broken input file",
143           "Path to broken input file. (If qtmux was on faststart mode, this "
144           "file is the faststart file)", NULL,
145           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
146   g_object_class_install_property (gobject_class, PROP_RECOVERY_INPUT,
147       g_param_spec_string ("recovery-input",
148           "Path to recovery file",
149           "Path to recovery file (used as input)", NULL,
150           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
151   g_object_class_install_property (gobject_class, PROP_FAST_START_MODE,
152       g_param_spec_boolean ("faststart-mode",
153           "If the broken input is from faststart mode",
154           "If the broken input is from faststart mode",
155           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
156
157   GST_DEBUG_CATEGORY_INIT (gst_qt_moov_recover_debug, "qtmoovrecover", 0,
158       "QT Moovie Recover");
159 }
160
161 static void
162 gst_qt_moov_recover_init (GstQTMoovRecover * qtmr,
163     GstQTMoovRecoverClass * qtmr_klass)
164 {
165 }
166
167 static void
168 gst_qt_moov_recover_finalize (GObject * object)
169 {
170   G_OBJECT_CLASS (parent_class)->finalize (object);
171 }
172
173 static void
174 gst_qt_moov_recover_run (void *data)
175 {
176   FILE *moovrec = NULL;
177   FILE *mdatinput = NULL;
178   FILE *output = NULL;
179   MdatRecovFile *mdat_recov = NULL;
180   MoovRecovFile *moov_recov = NULL;
181   GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (data);
182   GError *err = NULL;
183
184   GST_LOG_OBJECT (qtmr, "Starting task");
185
186   GST_DEBUG_OBJECT (qtmr, "Validating properties");
187   GST_OBJECT_LOCK (qtmr);
188   /* validate properties */
189   if (qtmr->broken_input == NULL) {
190     GST_OBJECT_UNLOCK (qtmr);
191     GST_ELEMENT_ERROR (qtmr, RESOURCE, SETTINGS,
192         ("Please set broken-input property"), (NULL));
193     goto end;
194   }
195   if (qtmr->recovery_input == NULL) {
196     GST_OBJECT_UNLOCK (qtmr);
197     GST_ELEMENT_ERROR (qtmr, RESOURCE, SETTINGS,
198         ("Please set recovery-input property"), (NULL));
199     goto end;
200   }
201   if (qtmr->fixed_output == NULL) {
202     GST_OBJECT_UNLOCK (qtmr);
203     GST_ELEMENT_ERROR (qtmr, RESOURCE, SETTINGS,
204         ("Please set fixed-output property"), (NULL));
205     goto end;
206   }
207
208   GST_DEBUG_OBJECT (qtmr, "Opening input/output files");
209   /* open files */
210   moovrec = g_fopen (qtmr->recovery_input, "rb");
211   if (moovrec == NULL) {
212     GST_OBJECT_UNLOCK (qtmr);
213     GST_ELEMENT_ERROR (qtmr, RESOURCE, OPEN_READ,
214         ("Failed to open recovery-input file"), (NULL));
215     goto end;
216   }
217
218   mdatinput = g_fopen (qtmr->broken_input, "rb");
219   if (mdatinput == NULL) {
220     GST_OBJECT_UNLOCK (qtmr);
221     GST_ELEMENT_ERROR (qtmr, RESOURCE, OPEN_READ,
222         ("Failed to open broken-input file"), (NULL));
223     goto end;
224   }
225   output = g_fopen (qtmr->fixed_output, "wb+");
226   if (output == NULL) {
227     GST_OBJECT_UNLOCK (qtmr);
228     GST_ELEMENT_ERROR (qtmr, RESOURCE, OPEN_READ_WRITE,
229         ("Failed to open fixed-output file"), (NULL));
230     goto end;
231   }
232   GST_OBJECT_UNLOCK (qtmr);
233
234   GST_DEBUG_OBJECT (qtmr, "Parsing input files");
235   /* now create our structures */
236   mdat_recov = mdat_recov_file_create (mdatinput, qtmr->faststart_mode, &err);
237   mdatinput = NULL;
238   if (mdat_recov == NULL) {
239     GST_ELEMENT_ERROR (qtmr, RESOURCE, FAILED,
240         ("Broken file could not be parsed correctly"), (NULL));
241     goto end;
242   }
243   moov_recov = moov_recov_file_create (moovrec, &err);
244   moovrec = NULL;
245   if (moov_recov == NULL) {
246     GST_ELEMENT_ERROR (qtmr, RESOURCE, FAILED,
247         ("Recovery file could not be parsed correctly"), (NULL));
248     goto end;
249   }
250
251   /* now parse the buffers data from moovrec */
252   if (!moov_recov_parse_buffers (moov_recov, mdat_recov, &err)) {
253     goto end;
254   }
255
256   GST_DEBUG_OBJECT (qtmr, "Writing fixed file to output");
257   if (!moov_recov_write_file (moov_recov, mdat_recov, output, &err)) {
258     goto end;
259   }
260
261   /* here means success */
262   GST_DEBUG_OBJECT (qtmr, "Finished successfully, posting EOS");
263   gst_element_post_message (GST_ELEMENT_CAST (qtmr),
264       gst_message_new_eos (GST_OBJECT_CAST (qtmr)));
265
266 end:
267   GST_LOG_OBJECT (qtmr, "Finalizing task");
268   if (err) {
269     GST_ELEMENT_ERROR (qtmr, RESOURCE, FAILED, ("%s", err->message), (NULL));
270     g_error_free (err);
271   }
272
273   if (moov_recov)
274     moov_recov_file_free (moov_recov);
275   if (moovrec)
276     fclose (moovrec);
277
278   if (mdat_recov)
279     mdat_recov_file_free (mdat_recov);
280   if (mdatinput)
281     fclose (mdatinput);
282
283   if (output)
284     fclose (output);
285   GST_LOG_OBJECT (qtmr, "Leaving task");
286   gst_task_stop (qtmr->task);
287 }
288
289 static void
290 gst_qt_moov_recover_get_property (GObject * object,
291     guint prop_id, GValue * value, GParamSpec * pspec)
292 {
293   GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (object);
294
295   GST_OBJECT_LOCK (qtmr);
296   switch (prop_id) {
297     case PROP_FAST_START_MODE:
298       g_value_set_boolean (value, qtmr->faststart_mode);
299       break;
300     case PROP_BROKEN_INPUT:
301       g_value_set_string (value, qtmr->broken_input);
302       break;
303     case PROP_RECOVERY_INPUT:
304       g_value_set_string (value, qtmr->recovery_input);
305       break;
306     case PROP_FIXED_OUTPUT:
307       g_value_set_string (value, qtmr->fixed_output);
308       break;
309     default:
310       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
311       break;
312   }
313   GST_OBJECT_UNLOCK (qtmr);
314 }
315
316 static void
317 gst_qt_moov_recover_set_property (GObject * object,
318     guint prop_id, const GValue * value, GParamSpec * pspec)
319 {
320   GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (object);
321
322   GST_OBJECT_LOCK (qtmr);
323   switch (prop_id) {
324     case PROP_FAST_START_MODE:
325       qtmr->faststart_mode = g_value_get_boolean (value);
326       break;
327     case PROP_BROKEN_INPUT:
328       g_free (qtmr->broken_input);
329       qtmr->broken_input = g_value_dup_string (value);
330       break;
331     case PROP_RECOVERY_INPUT:
332       g_free (qtmr->recovery_input);
333       qtmr->recovery_input = g_value_dup_string (value);
334       break;
335     case PROP_FIXED_OUTPUT:
336       g_free (qtmr->fixed_output);
337       qtmr->fixed_output = g_value_dup_string (value);
338       break;
339     default:
340       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
341       break;
342   }
343   GST_OBJECT_UNLOCK (qtmr);
344 }
345
346 static GstStateChangeReturn
347 gst_qt_moov_recover_change_state (GstElement * element,
348     GstStateChange transition)
349 {
350   GstStateChangeReturn ret;
351   GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (element);
352
353   switch (transition) {
354     case GST_STATE_CHANGE_NULL_TO_READY:
355       qtmr->task = gst_task_create (gst_qt_moov_recover_run, qtmr);
356       g_static_rec_mutex_init (&qtmr->task_mutex);
357       gst_task_set_lock (qtmr->task, &qtmr->task_mutex);
358       break;
359     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
360       gst_task_start (qtmr->task);
361       break;
362     default:
363       break;
364   }
365
366   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
367
368   switch (transition) {
369     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
370       gst_task_stop (qtmr->task);
371       gst_task_join (qtmr->task);
372       break;
373     case GST_STATE_CHANGE_READY_TO_NULL:
374       g_assert (gst_task_get_state (qtmr->task) == GST_TASK_STOPPED);
375       gst_object_unref (qtmr->task);
376       qtmr->task = NULL;
377       g_static_rec_mutex_free (&qtmr->task_mutex);
378       break;
379     default:
380       break;
381   }
382   return ret;
383 }
384
385
386 gboolean
387 gst_qt_moov_recover_register (GstPlugin * plugin)
388 {
389   return gst_element_register (plugin, "qtmoovrecover", GST_RANK_NONE,
390       GST_TYPE_QT_MOOV_RECOVER);
391 }