~ubuntu-branches/ubuntu/quantal/gst-plugins-bad0.10/quantal-proposed

« back to all changes in this revision

Viewing changes to gst/qtmux/atomsrecovery.c

  • Committer: Bazaar Package Importer
  • Author(s): Ken VanDine
  • Date: 2011-07-19 14:32:43 UTC
  • mfrom: (18.4.21 sid)
  • Revision ID: james.westby@ubuntu.com-20110719143243-p7pnkh45akfp0ihk
Tags: 0.10.22-2ubuntu1
* Rebased on debian unstable, remaining changes:
  - debian/gstreamer-plugins-bad.install
    * don't include dtmf, liveadder, rtpmux, autoconvert and shm, we include 
      them in -good

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 * This module contains functions for serializing partial information from
45
 
 * a mux in progress (by qtmux elements). This enables reconstruction of the
46
 
 * moov box if a crash happens and thus recovering the movie file.
47
 
 *
48
 
 * Usage:
49
 
 * 1) pipeline: ...yourelements ! qtmux moov-recovery-file=path.mrf ! \
50
 
 * filesink location=moovie.mov
51
 
 *
52
 
 * 2) CRASH!
53
 
 *
54
 
 * 3) gst-launch qtmoovrecover recovery-input=path.mrf broken-input=moovie.mov \
55
 
        fixed-output=recovered.mov
56
 
 *
57
 
 * 4) (Hopefully) enjoy recovered.mov.
58
 
 *
59
 
 * --- Recovery file layout ---
60
 
 * 1) Version (a guint16)
61
 
 * 2) Prefix atom (if present)
62
 
 * 3) ftyp atom
63
 
 * 4) MVHD atom (without timescale/duration set)
64
 
 * 5) moovie timescale
65
 
 * 6) number of traks
66
 
 * 7) list of trak atoms (stbl data is ignored, except for the stsd atom)
67
 
 * 8) Buffers metadata (metadata that is relevant to the container)
68
 
 *    Buffers metadata are stored in the order they are added to the mdat,
69
 
 *    each entre has a fixed size and is stored in BE. booleans are stored
70
 
 *    as a single byte where 0 means false, otherwise is true.
71
 
 *   Metadata:
72
 
 *   - guint32   track_id;
73
 
 *   - guint32   nsamples;
74
 
 *   - guint32   delta;
75
 
 *   - guint32   size;
76
 
 *   - guint64   chunk_offset;
77
 
 *   - gboolean  sync;
78
 
 *   - gboolean  do_pts;
79
 
 *   - guint64   pts_offset; (always present, ignored if do_pts is false)
80
 
 *
81
 
 * The mdat file might contain ftyp and then mdat, in case this is the faststart
82
 
 * temporary file there is no ftyp and no mdat header, only the buffers data.
83
 
 *
84
 
 * Notes about recovery file layout: We still don't store tags nor EDTS data.
85
 
 *
86
 
 * IMPORTANT: this is still at a experimental state.
87
 
 */
88
 
 
89
 
#include "atomsrecovery.h"
90
 
 
91
 
#define ATOMS_RECOV_OUTPUT_WRITE_ERROR(err) \
92
 
    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE, \
93
 
        "Failed to write to output file: %s", g_strerror (errno))
94
 
 
95
 
static gboolean
96
 
atoms_recov_write_version (FILE * f)
97
 
{
98
 
  guint8 data[2];
99
 
  GST_WRITE_UINT16_BE (data, ATOMS_RECOV_FILE_VERSION);
100
 
  return fwrite (data, 2, 1, f) == 1;
101
 
}
102
 
 
103
 
static gboolean
104
 
atoms_recov_write_ftyp_info (FILE * f, AtomFTYP * ftyp, GstBuffer * prefix)
105
 
{
106
 
  guint8 *data = NULL;
107
 
  guint64 offset = 0;
108
 
  guint64 size = 0;
109
 
 
110
 
  if (prefix) {
111
 
    if (fwrite (GST_BUFFER_DATA (prefix), 1, GST_BUFFER_SIZE (prefix), f) !=
112
 
        GST_BUFFER_SIZE (prefix)) {
113
 
      return FALSE;
114
 
    }
115
 
  }
116
 
  if (!atom_ftyp_copy_data (ftyp, &data, &size, &offset)) {
117
 
    return FALSE;
118
 
  }
119
 
  if (fwrite (data, 1, offset, f) != offset) {
120
 
    return FALSE;
121
 
  }
122
 
  return TRUE;
123
 
}
124
 
 
125
 
/**
126
 
 * Writes important info on the 'moov' atom (non-trak related)
127
 
 * to be able to recover the moov structure after a crash.
128
 
 *
129
 
 * Currently, it writes the MVHD atom.
130
 
 */
131
 
static gboolean
132
 
atoms_recov_write_moov_info (FILE * f, AtomMOOV * moov)
133
 
{
134
 
  guint8 *data;
135
 
  guint64 size;
136
 
  guint64 offset = 0;
137
 
  guint64 atom_size = 0;
138
 
  gint writen = 0;
139
 
 
140
 
  /* likely enough */
141
 
  size = 256;
142
 
  data = g_malloc (size);
143
 
  atom_size = atom_mvhd_copy_data (&moov->mvhd, &data, &size, &offset);
144
 
  if (atom_size > 0)
145
 
    writen = fwrite (data, 1, atom_size, f);
146
 
  g_free (data);
147
 
  return atom_size > 0 && writen == atom_size;
148
 
}
149
 
 
150
 
/**
151
 
 * Writes the number of traks to the file.
152
 
 * This simply writes a guint32 in BE.
153
 
 */
154
 
static gboolean
155
 
atoms_recov_write_traks_number (FILE * f, guint32 traks)
156
 
{
157
 
  guint8 data[4];
158
 
  GST_WRITE_UINT32_BE (data, traks);
159
 
  return fwrite (data, 4, 1, f) == 1;
160
 
}
161
 
 
162
 
/**
163
 
 * Writes the moov's timescale to the file
164
 
 * This simply writes a guint32 in BE.
165
 
 */
166
 
static gboolean
167
 
atoms_recov_write_moov_timescale (FILE * f, guint32 timescale)
168
 
{
169
 
  guint8 data[4];
170
 
  GST_WRITE_UINT32_BE (data, timescale);
171
 
  return fwrite (data, 4, 1, f) == 1;
172
 
}
173
 
 
174
 
/**
175
 
 * Writes the trak atom to the file.
176
 
 */
177
 
gboolean
178
 
atoms_recov_write_trak_info (FILE * f, AtomTRAK * trak)
179
 
{
180
 
  guint8 *data;
181
 
  guint64 size;
182
 
  guint64 offset = 0;
183
 
  guint64 atom_size = 0;
184
 
  gint writen = 0;
185
 
 
186
 
  /* buffer is realloced to a larger size if needed */
187
 
  size = 4 * 1024;
188
 
  data = g_malloc (size);
189
 
  atom_size = atom_trak_copy_data (trak, &data, &size, &offset);
190
 
  if (atom_size > 0)
191
 
    writen = fwrite (data, atom_size, 1, f);
192
 
  g_free (data);
193
 
  return atom_size > 0 && writen == atom_size;
194
 
}
195
 
 
196
 
gboolean
197
 
atoms_recov_write_trak_samples (FILE * f, AtomTRAK * trak, guint32 nsamples,
198
 
    guint32 delta, guint32 size, guint64 chunk_offset, gboolean sync,
199
 
    gboolean do_pts, gint64 pts_offset)
200
 
{
201
 
  guint8 data[TRAK_BUFFER_ENTRY_INFO_SIZE];
202
 
  /*
203
 
   * We have to write a TrakBufferEntryInfo
204
 
   */
205
 
  GST_WRITE_UINT32_BE (data + 0, trak->tkhd.track_ID);
206
 
  GST_WRITE_UINT32_BE (data + 4, nsamples);
207
 
  GST_WRITE_UINT32_BE (data + 8, delta);
208
 
  GST_WRITE_UINT32_BE (data + 12, size);
209
 
  GST_WRITE_UINT64_BE (data + 16, chunk_offset);
210
 
  if (sync)
211
 
    GST_WRITE_UINT8 (data + 24, 1);
212
 
  else
213
 
    GST_WRITE_UINT8 (data + 24, 0);
214
 
  if (do_pts) {
215
 
    GST_WRITE_UINT8 (data + 25, 1);
216
 
    GST_WRITE_UINT64_BE (data + 26, pts_offset);
217
 
  } else {
218
 
    GST_WRITE_UINT8 (data + 25, 0);
219
 
    GST_WRITE_UINT64_BE (data + 26, 0);
220
 
  }
221
 
 
222
 
  return fwrite (data, 1, TRAK_BUFFER_ENTRY_INFO_SIZE, f) ==
223
 
      TRAK_BUFFER_ENTRY_INFO_SIZE;
224
 
}
225
 
 
226
 
gboolean
227
 
atoms_recov_write_headers (FILE * f, AtomFTYP * ftyp, GstBuffer * prefix,
228
 
    AtomMOOV * moov, guint32 timescale, guint32 traks_number)
229
 
{
230
 
  if (!atoms_recov_write_version (f)) {
231
 
    return FALSE;
232
 
  }
233
 
 
234
 
  if (!atoms_recov_write_ftyp_info (f, ftyp, prefix)) {
235
 
    return FALSE;
236
 
  }
237
 
 
238
 
  if (!atoms_recov_write_moov_info (f, moov)) {
239
 
    return FALSE;
240
 
  }
241
 
 
242
 
  if (!atoms_recov_write_moov_timescale (f, timescale)) {
243
 
    return FALSE;
244
 
  }
245
 
 
246
 
  if (!atoms_recov_write_traks_number (f, traks_number)) {
247
 
    return FALSE;
248
 
  }
249
 
 
250
 
  return TRUE;
251
 
}
252
 
 
253
 
static gboolean
254
 
read_atom_header (FILE * f, guint32 * fourcc, guint32 * size)
255
 
{
256
 
  guint8 aux[8];
257
 
 
258
 
  if (fread (aux, 1, 8, f) != 8)
259
 
    return FALSE;
260
 
  *size = GST_READ_UINT32_BE (aux);
261
 
  *fourcc = GST_READ_UINT32_LE (aux + 4);
262
 
  return TRUE;
263
 
}
264
 
 
265
 
static gboolean
266
 
moov_recov_file_parse_prefix (MoovRecovFile * moovrf)
267
 
{
268
 
  guint32 fourcc;
269
 
  guint32 size;
270
 
  guint32 total_size = 0;
271
 
  if (fseek (moovrf->file, 2, SEEK_SET) != 0)
272
 
    return FALSE;
273
 
  if (!read_atom_header (moovrf->file, &fourcc, &size)) {
274
 
    return FALSE;
275
 
  }
276
 
 
277
 
  if (fourcc != FOURCC_ftyp) {
278
 
    /* we might have a prefix here */
279
 
    if (fseek (moovrf->file, size - 8, SEEK_CUR) != 0)
280
 
      return FALSE;
281
 
 
282
 
    total_size += size;
283
 
 
284
 
    /* now read the ftyp */
285
 
    if (!read_atom_header (moovrf->file, &fourcc, &size))
286
 
      return FALSE;
287
 
  }
288
 
 
289
 
  /* this has to be the ftyp */
290
 
  if (fourcc != FOURCC_ftyp)
291
 
    return FALSE;
292
 
  total_size += size;
293
 
  moovrf->prefix_size = total_size;
294
 
  return fseek (moovrf->file, size - 8, SEEK_CUR) == 0;
295
 
}
296
 
 
297
 
static gboolean
298
 
moov_recov_file_parse_mvhd (MoovRecovFile * moovrf)
299
 
{
300
 
  guint32 fourcc;
301
 
  guint32 size;
302
 
  if (!read_atom_header (moovrf->file, &fourcc, &size)) {
303
 
    return FALSE;
304
 
  }
305
 
  /* check for sanity */
306
 
  if (fourcc != FOURCC_mvhd)
307
 
    return FALSE;
308
 
 
309
 
  moovrf->mvhd_size = size;
310
 
  moovrf->mvhd_pos = ftell (moovrf->file) - 8;
311
 
 
312
 
  /* skip the remaining of the mvhd in the file */
313
 
  return fseek (moovrf->file, size - 8, SEEK_CUR) == 0;
314
 
}
315
 
 
316
 
static gboolean
317
 
mdat_recov_file_parse_mdat_start (MdatRecovFile * mdatrf)
318
 
{
319
 
  guint32 fourcc, size;
320
 
 
321
 
  if (!read_atom_header (mdatrf->file, &fourcc, &size)) {
322
 
    return FALSE;
323
 
  }
324
 
  if (size == 1) {
325
 
    mdatrf->mdat_header_size = 16;
326
 
    mdatrf->mdat_size = 16;
327
 
  } else {
328
 
    mdatrf->mdat_header_size = 8;
329
 
    mdatrf->mdat_size = 8;
330
 
  }
331
 
  mdatrf->mdat_start = ftell (mdatrf->file) - 8;
332
 
 
333
 
  return fourcc == FOURCC_mdat;
334
 
}
335
 
 
336
 
MdatRecovFile *
337
 
mdat_recov_file_create (FILE * file, gboolean datafile, GError ** err)
338
 
{
339
 
  MdatRecovFile *mrf = g_new0 (MdatRecovFile, 1);
340
 
  guint32 fourcc, size;
341
 
 
342
 
  g_return_val_if_fail (file != NULL, NULL);
343
 
 
344
 
  mrf->file = file;
345
 
  mrf->rawfile = datafile;
346
 
 
347
 
  /* get the file/data length */
348
 
  if (fseek (file, 0, SEEK_END) != 0)
349
 
    goto file_length_error;
350
 
  /* still needs to deduce the mdat header and ftyp size */
351
 
  mrf->data_size = ftell (file);
352
 
  if (mrf->data_size == -1L)
353
 
    goto file_length_error;
354
 
 
355
 
  if (fseek (file, 0, SEEK_SET) != 0)
356
 
    goto file_seek_error;
357
 
 
358
 
  if (datafile) {
359
 
    /* this file contains no atoms, only raw data to be placed on the mdat
360
 
     * this happens when faststart mode is used */
361
 
    mrf->mdat_start = 0;
362
 
    mrf->mdat_header_size = 16;
363
 
    mrf->mdat_size = 16;
364
 
    return mrf;
365
 
  }
366
 
 
367
 
  if (!read_atom_header (file, &fourcc, &size)) {
368
 
    goto parse_error;
369
 
  }
370
 
  if (fourcc != FOURCC_ftyp) {
371
 
    /* this could be a prefix atom, let's skip it and try again */
372
 
    if (fseek (file, size - 8, SEEK_CUR) != 0) {
373
 
      goto file_seek_error;
374
 
    }
375
 
    if (!read_atom_header (file, &fourcc, &size)) {
376
 
      goto parse_error;
377
 
    }
378
 
  }
379
 
 
380
 
  if (fourcc != FOURCC_ftyp) {
381
 
    goto parse_error;
382
 
  }
383
 
  if (fseek (file, size - 8, SEEK_CUR) != 0)
384
 
    goto file_seek_error;
385
 
 
386
 
  /* we don't parse this if we have a tmpdatafile */
387
 
  if (!mdat_recov_file_parse_mdat_start (mrf)) {
388
 
    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
389
 
        "Error while parsing mdat atom");
390
 
    goto fail;
391
 
  }
392
 
 
393
 
  return mrf;
394
 
 
395
 
parse_error:
396
 
  g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
397
 
      "Failed to parse atom");
398
 
  goto fail;
399
 
 
400
 
file_seek_error:
401
 
  g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
402
 
      "Failed to seek to start of the file");
403
 
  goto fail;
404
 
 
405
 
file_length_error:
406
 
  g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
407
 
      "Failed to determine file size");
408
 
  goto fail;
409
 
 
410
 
fail:
411
 
  mdat_recov_file_free (mrf);
412
 
  return NULL;
413
 
}
414
 
 
415
 
void
416
 
mdat_recov_file_free (MdatRecovFile * mrf)
417
 
{
418
 
  fclose (mrf->file);
419
 
  g_free (mrf);
420
 
}
421
 
 
422
 
static gboolean
423
 
moov_recov_parse_num_traks (MoovRecovFile * moovrf)
424
 
{
425
 
  guint8 traks[4];
426
 
  if (fread (traks, 1, 4, moovrf->file) != 4)
427
 
    return FALSE;
428
 
  moovrf->num_traks = GST_READ_UINT32_BE (traks);
429
 
  return TRUE;
430
 
}
431
 
 
432
 
static gboolean
433
 
moov_recov_parse_moov_timescale (MoovRecovFile * moovrf)
434
 
{
435
 
  guint8 ts[4];
436
 
  if (fread (ts, 1, 4, moovrf->file) != 4)
437
 
    return FALSE;
438
 
  moovrf->timescale = GST_READ_UINT32_BE (ts);
439
 
  return TRUE;
440
 
}
441
 
 
442
 
static gboolean
443
 
skip_atom (MoovRecovFile * moovrf, guint32 expected_fourcc)
444
 
{
445
 
  guint32 size;
446
 
  guint32 fourcc;
447
 
 
448
 
  if (!read_atom_header (moovrf->file, &fourcc, &size))
449
 
    return FALSE;
450
 
  if (fourcc != expected_fourcc)
451
 
    return FALSE;
452
 
 
453
 
  return (fseek (moovrf->file, size - 8, SEEK_CUR) == 0);
454
 
}
455
 
 
456
 
static gboolean
457
 
moov_recov_parse_tkhd (MoovRecovFile * moovrf, TrakRecovData * trakrd)
458
 
{
459
 
  guint32 size;
460
 
  guint32 fourcc;
461
 
  guint8 data[4];
462
 
 
463
 
  /* make sure we are on a tkhd atom */
464
 
  if (!read_atom_header (moovrf->file, &fourcc, &size))
465
 
    return FALSE;
466
 
  if (fourcc != FOURCC_tkhd)
467
 
    return FALSE;
468
 
 
469
 
  trakrd->tkhd_file_offset = ftell (moovrf->file) - 8;
470
 
 
471
 
  /* move 8 bytes forward to the trak_id pos */
472
 
  if (fseek (moovrf->file, 12, SEEK_CUR) != 0)
473
 
    return FALSE;
474
 
  if (fread (data, 1, 4, moovrf->file) != 4)
475
 
    return FALSE;
476
 
 
477
 
  /* advance the rest of tkhd */
478
 
  fseek (moovrf->file, 68, SEEK_CUR);
479
 
 
480
 
  trakrd->trak_id = GST_READ_UINT32_BE (data);
481
 
  return TRUE;
482
 
}
483
 
 
484
 
static gboolean
485
 
moov_recov_parse_stbl (MoovRecovFile * moovrf, TrakRecovData * trakrd)
486
 
{
487
 
  guint32 size;
488
 
  guint32 fourcc;
489
 
  guint32 auxsize;
490
 
 
491
 
  if (!read_atom_header (moovrf->file, &fourcc, &size))
492
 
    return FALSE;
493
 
  if (fourcc != FOURCC_stbl)
494
 
    return FALSE;
495
 
 
496
 
  trakrd->stbl_file_offset = ftell (moovrf->file) - 8;
497
 
  trakrd->stbl_size = size;
498
 
 
499
 
  /* skip the stsd */
500
 
  if (!read_atom_header (moovrf->file, &fourcc, &auxsize))
501
 
    return FALSE;
502
 
  if (fourcc != FOURCC_stsd)
503
 
    return FALSE;
504
 
  if (fseek (moovrf->file, auxsize - 8, SEEK_CUR) != 0)
505
 
    return FALSE;
506
 
 
507
 
  trakrd->stsd_size = auxsize;
508
 
  trakrd->post_stsd_offset = ftell (moovrf->file);
509
 
 
510
 
  /* as this is the last atom we parse, we don't skip forward */
511
 
 
512
 
  return TRUE;
513
 
}
514
 
 
515
 
static gboolean
516
 
moov_recov_parse_minf (MoovRecovFile * moovrf, TrakRecovData * trakrd)
517
 
{
518
 
  guint32 size;
519
 
  guint32 fourcc;
520
 
  guint32 auxsize;
521
 
 
522
 
  if (!read_atom_header (moovrf->file, &fourcc, &size))
523
 
    return FALSE;
524
 
  if (fourcc != FOURCC_minf)
525
 
    return FALSE;
526
 
 
527
 
  trakrd->minf_file_offset = ftell (moovrf->file) - 8;
528
 
  trakrd->minf_size = size;
529
 
 
530
 
  /* skip either of vmhd, smhd, hmhd that might follow */
531
 
  if (!read_atom_header (moovrf->file, &fourcc, &auxsize))
532
 
    return FALSE;
533
 
  if (fourcc != FOURCC_vmhd && fourcc != FOURCC_smhd && fourcc != FOURCC_hmhd &&
534
 
      fourcc != FOURCC_gmhd)
535
 
    return FALSE;
536
 
  if (fseek (moovrf->file, auxsize - 8, SEEK_CUR))
537
 
    return FALSE;
538
 
 
539
 
  /* skip a possible hdlr and the following dinf */
540
 
  if (!read_atom_header (moovrf->file, &fourcc, &auxsize))
541
 
    return FALSE;
542
 
  if (fourcc == FOURCC_hdlr) {
543
 
    if (fseek (moovrf->file, auxsize - 8, SEEK_CUR))
544
 
      return FALSE;
545
 
    if (!read_atom_header (moovrf->file, &fourcc, &auxsize))
546
 
      return FALSE;
547
 
  }
548
 
  if (fourcc != FOURCC_dinf)
549
 
    return FALSE;
550
 
  if (fseek (moovrf->file, auxsize - 8, SEEK_CUR))
551
 
    return FALSE;
552
 
 
553
 
  /* now we are ready to read the stbl */
554
 
  if (!moov_recov_parse_stbl (moovrf, trakrd))
555
 
    return FALSE;
556
 
 
557
 
  return TRUE;
558
 
}
559
 
 
560
 
static gboolean
561
 
moov_recov_parse_mdhd (MoovRecovFile * moovrf, TrakRecovData * trakrd)
562
 
{
563
 
  guint32 size;
564
 
  guint32 fourcc;
565
 
  guint8 data[4];
566
 
 
567
 
  /* make sure we are on a tkhd atom */
568
 
  if (!read_atom_header (moovrf->file, &fourcc, &size))
569
 
    return FALSE;
570
 
  if (fourcc != FOURCC_mdhd)
571
 
    return FALSE;
572
 
 
573
 
  trakrd->mdhd_file_offset = ftell (moovrf->file) - 8;
574
 
 
575
 
  /* get the timescale */
576
 
  if (fseek (moovrf->file, 12, SEEK_CUR) != 0)
577
 
    return FALSE;
578
 
  if (fread (data, 1, 4, moovrf->file) != 4)
579
 
    return FALSE;
580
 
  trakrd->timescale = GST_READ_UINT32_BE (data);
581
 
  if (fseek (moovrf->file, 8, SEEK_CUR) != 0)
582
 
    return FALSE;
583
 
  return TRUE;
584
 
}
585
 
 
586
 
static gboolean
587
 
moov_recov_parse_mdia (MoovRecovFile * moovrf, TrakRecovData * trakrd)
588
 
{
589
 
  guint32 size;
590
 
  guint32 fourcc;
591
 
 
592
 
  /* make sure we are on a tkhd atom */
593
 
  if (!read_atom_header (moovrf->file, &fourcc, &size))
594
 
    return FALSE;
595
 
  if (fourcc != FOURCC_mdia)
596
 
    return FALSE;
597
 
 
598
 
  trakrd->mdia_file_offset = ftell (moovrf->file) - 8;
599
 
  trakrd->mdia_size = size;
600
 
 
601
 
  if (!moov_recov_parse_mdhd (moovrf, trakrd))
602
 
    return FALSE;
603
 
 
604
 
  if (!skip_atom (moovrf, FOURCC_hdlr))
605
 
    return FALSE;
606
 
  if (!moov_recov_parse_minf (moovrf, trakrd))
607
 
    return FALSE;
608
 
  return TRUE;
609
 
}
610
 
 
611
 
static gboolean
612
 
moov_recov_parse_trak (MoovRecovFile * moovrf, TrakRecovData * trakrd)
613
 
{
614
 
  guint64 offset;
615
 
  guint32 size;
616
 
  guint32 fourcc;
617
 
 
618
 
  offset = ftell (moovrf->file);
619
 
  if (offset == -1) {
620
 
    return FALSE;
621
 
  }
622
 
 
623
 
  /* make sure we are on a trak atom */
624
 
  if (!read_atom_header (moovrf->file, &fourcc, &size)) {
625
 
    return FALSE;
626
 
  }
627
 
  if (fourcc != FOURCC_trak) {
628
 
    return FALSE;
629
 
  }
630
 
  trakrd->trak_size = size;
631
 
 
632
 
  /* now we should have a trak header 'tkhd' */
633
 
  if (!moov_recov_parse_tkhd (moovrf, trakrd))
634
 
    return FALSE;
635
 
 
636
 
  /* FIXME add edts handling here and in qtmux, as this is only detected
637
 
   * after buffers start flowing */
638
 
 
639
 
  if (!moov_recov_parse_mdia (moovrf, trakrd))
640
 
    return FALSE;
641
 
 
642
 
  trakrd->file_offset = offset;
643
 
  /* position after the trak */
644
 
  return fseek (moovrf->file, (long int) offset + size, SEEK_SET) == 0;
645
 
}
646
 
 
647
 
MoovRecovFile *
648
 
moov_recov_file_create (FILE * file, GError ** err)
649
 
{
650
 
  gint i;
651
 
  MoovRecovFile *moovrf = g_new0 (MoovRecovFile, 1);
652
 
 
653
 
  g_return_val_if_fail (file != NULL, NULL);
654
 
 
655
 
  moovrf->file = file;
656
 
 
657
 
  /* look for ftyp and prefix at the start */
658
 
  if (!moov_recov_file_parse_prefix (moovrf)) {
659
 
    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
660
 
        "Error while parsing prefix atoms");
661
 
    goto fail;
662
 
  }
663
 
 
664
 
  /* parse the mvhd */
665
 
  if (!moov_recov_file_parse_mvhd (moovrf)) {
666
 
    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
667
 
        "Error while parsing mvhd atom");
668
 
    goto fail;
669
 
  }
670
 
 
671
 
  if (!moov_recov_parse_moov_timescale (moovrf)) {
672
 
    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
673
 
        "Error while parsing timescale");
674
 
    goto fail;
675
 
  }
676
 
  if (!moov_recov_parse_num_traks (moovrf)) {
677
 
    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
678
 
        "Error while parsing parsing number of traks");
679
 
    goto fail;
680
 
  }
681
 
 
682
 
  /* init the traks */
683
 
  moovrf->traks_rd = g_new0 (TrakRecovData, moovrf->num_traks);
684
 
  for (i = 0; i < moovrf->num_traks; i++) {
685
 
    atom_stbl_init (&(moovrf->traks_rd[i].stbl));
686
 
  }
687
 
  for (i = 0; i < moovrf->num_traks; i++) {
688
 
    if (!moov_recov_parse_trak (moovrf, &(moovrf->traks_rd[i]))) {
689
 
      g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
690
 
          "Error while parsing trak atom");
691
 
      goto fail;
692
 
    }
693
 
  }
694
 
 
695
 
  return moovrf;
696
 
 
697
 
fail:
698
 
  moov_recov_file_free (moovrf);
699
 
  return NULL;
700
 
}
701
 
 
702
 
void
703
 
moov_recov_file_free (MoovRecovFile * moovrf)
704
 
{
705
 
  gint i;
706
 
  fclose (moovrf->file);
707
 
  if (moovrf->traks_rd) {
708
 
    for (i = 0; i < moovrf->num_traks; i++) {
709
 
      atom_stbl_clear (&(moovrf->traks_rd[i].stbl));
710
 
    }
711
 
    g_free (moovrf->traks_rd);
712
 
  }
713
 
  g_free (moovrf);
714
 
}
715
 
 
716
 
static gboolean
717
 
moov_recov_parse_buffer_entry (MoovRecovFile * moovrf, TrakBufferEntryInfo * b)
718
 
{
719
 
  guint8 data[TRAK_BUFFER_ENTRY_INFO_SIZE];
720
 
  gint read;
721
 
 
722
 
  read = fread (data, 1, TRAK_BUFFER_ENTRY_INFO_SIZE, moovrf->file);
723
 
  if (read != TRAK_BUFFER_ENTRY_INFO_SIZE)
724
 
    return FALSE;
725
 
 
726
 
  b->track_id = GST_READ_UINT32_BE (data);
727
 
  b->nsamples = GST_READ_UINT32_BE (data + 4);
728
 
  b->delta = GST_READ_UINT32_BE (data + 8);
729
 
  b->size = GST_READ_UINT32_BE (data + 12);
730
 
  b->chunk_offset = GST_READ_UINT64_BE (data + 16);
731
 
  b->sync = data[24] != 0;
732
 
  b->do_pts = data[25] != 0;
733
 
  b->pts_offset = GST_READ_UINT64_BE (data + 26);
734
 
  return TRUE;
735
 
}
736
 
 
737
 
static gboolean
738
 
mdat_recov_add_sample (MdatRecovFile * mdatrf, guint32 size)
739
 
{
740
 
  /* test if this data exists */
741
 
  if (mdatrf->mdat_size - mdatrf->mdat_header_size + size > mdatrf->data_size)
742
 
    return FALSE;
743
 
 
744
 
  mdatrf->mdat_size += size;
745
 
  return TRUE;
746
 
}
747
 
 
748
 
static TrakRecovData *
749
 
moov_recov_get_trak (MoovRecovFile * moovrf, guint32 id)
750
 
{
751
 
  gint i;
752
 
  for (i = 0; i < moovrf->num_traks; i++) {
753
 
    if (moovrf->traks_rd[i].trak_id == id)
754
 
      return &(moovrf->traks_rd[i]);
755
 
  }
756
 
  return NULL;
757
 
}
758
 
 
759
 
static void
760
 
trak_recov_data_add_sample (TrakRecovData * trak, TrakBufferEntryInfo * b)
761
 
{
762
 
  trak->duration += b->nsamples * b->delta;
763
 
  atom_stbl_add_samples (&trak->stbl, b->nsamples, b->delta, b->size,
764
 
      b->chunk_offset, b->sync, b->pts_offset);
765
 
}
766
 
 
767
 
/**
768
 
 * Parses the buffer entries in the MoovRecovFile and matches the inputs
769
 
 * with the data in the MdatRecovFile. Whenever a buffer entry of that
770
 
 * represents 'x' bytes of data, the same amount of data is 'validated' in
771
 
 * the MdatRecovFile and will be inluded in the generated moovie file.
772
 
 */
773
 
gboolean
774
 
moov_recov_parse_buffers (MoovRecovFile * moovrf, MdatRecovFile * mdatrf,
775
 
    GError ** err)
776
 
{
777
 
  TrakBufferEntryInfo entry;
778
 
  TrakRecovData *trak;
779
 
 
780
 
  /* we assume both moovrf and mdatrf are at the starting points of their
781
 
   * data reading */
782
 
  while (moov_recov_parse_buffer_entry (moovrf, &entry)) {
783
 
    /* be sure we still have this data in mdat */
784
 
    trak = moov_recov_get_trak (moovrf, entry.track_id);
785
 
    if (trak == NULL) {
786
 
      g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
787
 
          "Invalid trak id found in buffer entry");
788
 
      return FALSE;
789
 
    }
790
 
    if (!mdat_recov_add_sample (mdatrf, entry.size))
791
 
      break;
792
 
    trak_recov_data_add_sample (trak, &entry);
793
 
  }
794
 
  return TRUE;
795
 
}
796
 
 
797
 
static guint32
798
 
trak_recov_data_get_trak_atom_size (TrakRecovData * trak)
799
 
{
800
 
  AtomSTBL *stbl = &trak->stbl;
801
 
  guint64 offset;
802
 
 
803
 
  /* write out our stbl child atoms */
804
 
  offset = 0;
805
 
 
806
 
  if (!atom_stts_copy_data (&stbl->stts, NULL, NULL, &offset)) {
807
 
    goto fail;
808
 
  }
809
 
  if (atom_array_get_len (&stbl->stss.entries) > 0) {
810
 
    if (!atom_stss_copy_data (&stbl->stss, NULL, NULL, &offset)) {
811
 
      goto fail;
812
 
    }
813
 
  }
814
 
  if (!atom_stsc_copy_data (&stbl->stsc, NULL, NULL, &offset)) {
815
 
    goto fail;
816
 
  }
817
 
  if (!atom_stsz_copy_data (&stbl->stsz, NULL, NULL, &offset)) {
818
 
    goto fail;
819
 
  }
820
 
  if (stbl->ctts) {
821
 
    if (!atom_ctts_copy_data (stbl->ctts, NULL, NULL, &offset)) {
822
 
      goto fail;
823
 
    }
824
 
  }
825
 
  if (!atom_stco64_copy_data (&stbl->stco64, NULL, NULL, &offset)) {
826
 
    goto fail;
827
 
  }
828
 
 
829
 
  return trak->trak_size + ((trak->stsd_size + offset + 8) - trak->stbl_size);
830
 
 
831
 
fail:
832
 
  return 0;
833
 
}
834
 
 
835
 
static guint8 *
836
 
moov_recov_get_stbl_children_data (MoovRecovFile * moovrf, TrakRecovData * trak,
837
 
    guint64 * p_size)
838
 
{
839
 
  AtomSTBL *stbl = &trak->stbl;
840
 
  guint8 *buffer;
841
 
  guint64 size;
842
 
  guint64 offset;
843
 
 
844
 
  /* write out our stbl child atoms
845
 
   *
846
 
   * Use 1MB as a starting size, *_copy_data functions
847
 
   * will grow the buffer if needed.
848
 
   */
849
 
  size = 1024 * 1024;
850
 
  buffer = g_malloc0 (size);
851
 
  offset = 0;
852
 
 
853
 
  if (!atom_stts_copy_data (&stbl->stts, &buffer, &size, &offset)) {
854
 
    goto fail;
855
 
  }
856
 
  if (atom_array_get_len (&stbl->stss.entries) > 0) {
857
 
    if (!atom_stss_copy_data (&stbl->stss, &buffer, &size, &offset)) {
858
 
      goto fail;
859
 
    }
860
 
  }
861
 
  if (!atom_stsc_copy_data (&stbl->stsc, &buffer, &size, &offset)) {
862
 
    goto fail;
863
 
  }
864
 
  if (!atom_stsz_copy_data (&stbl->stsz, &buffer, &size, &offset)) {
865
 
    goto fail;
866
 
  }
867
 
  if (stbl->ctts) {
868
 
    if (!atom_ctts_copy_data (stbl->ctts, &buffer, &size, &offset)) {
869
 
      goto fail;
870
 
    }
871
 
  }
872
 
  if (!atom_stco64_copy_data (&stbl->stco64, &buffer, &size, &offset)) {
873
 
    goto fail;
874
 
  }
875
 
  *p_size = offset;
876
 
  return buffer;
877
 
 
878
 
fail:
879
 
  g_free (buffer);
880
 
  return NULL;
881
 
}
882
 
 
883
 
gboolean
884
 
moov_recov_write_file (MoovRecovFile * moovrf, MdatRecovFile * mdatrf,
885
 
    FILE * outf, GError ** err)
886
 
{
887
 
  guint8 auxdata[16];
888
 
  guint8 *data = NULL;
889
 
  guint8 *prefix_data = NULL;
890
 
  guint8 *mvhd_data = NULL;
891
 
  guint8 *trak_data = NULL;
892
 
  guint32 moov_size = 0;
893
 
  gint i;
894
 
  guint64 stbl_children_size = 0;
895
 
  guint8 *stbl_children = NULL;
896
 
  guint32 longest_duration = 0;
897
 
  guint16 version;
898
 
 
899
 
  /* check the version */
900
 
  if (fseek (moovrf->file, 0, SEEK_SET) != 0) {
901
 
    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
902
 
        "Failed to seek to the start of the moov recovery file");
903
 
    goto fail;
904
 
  }
905
 
  if (fread (auxdata, 1, 2, moovrf->file) != 2) {
906
 
    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
907
 
        "Failed to read version from file");
908
 
  }
909
 
 
910
 
  version = GST_READ_UINT16_BE (auxdata);
911
 
  if (version != ATOMS_RECOV_FILE_VERSION) {
912
 
    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_VERSION,
913
 
        "Input file version (%u) is not supported in this version (%u)",
914
 
        version, ATOMS_RECOV_FILE_VERSION);
915
 
    return FALSE;
916
 
  }
917
 
 
918
 
  /* write the ftyp */
919
 
  prefix_data = g_malloc (moovrf->prefix_size);
920
 
  if (fread (prefix_data, 1, moovrf->prefix_size,
921
 
          moovrf->file) != moovrf->prefix_size) {
922
 
    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
923
 
        "Failed to read the ftyp atom from file");
924
 
    goto fail;
925
 
  }
926
 
  if (fwrite (prefix_data, 1, moovrf->prefix_size, outf) != moovrf->prefix_size) {
927
 
    ATOMS_RECOV_OUTPUT_WRITE_ERROR (err);
928
 
    goto fail;
929
 
  }
930
 
  g_free (prefix_data);
931
 
  prefix_data = NULL;
932
 
 
933
 
  /* need to calculate the moov size beforehand to add the offset to
934
 
   * chunk offset entries */
935
 
  moov_size += moovrf->mvhd_size + 8;   /* mvhd + moov size + fourcc */
936
 
  for (i = 0; i < moovrf->num_traks; i++) {
937
 
    TrakRecovData *trak = &(moovrf->traks_rd[i]);
938
 
    guint32 duration;           /* in moov's timescale */
939
 
    guint32 trak_size;
940
 
 
941
 
    /* convert trak duration to moov's duration */
942
 
    duration = gst_util_uint64_scale_round (trak->duration, moovrf->timescale,
943
 
        trak->timescale);
944
 
 
945
 
    if (duration > longest_duration)
946
 
      longest_duration = duration;
947
 
    trak_size = trak_recov_data_get_trak_atom_size (trak);
948
 
    if (trak_size == 0) {
949
 
      g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_GENERIC,
950
 
          "Failed to estimate trak atom size");
951
 
      goto fail;
952
 
    }
953
 
    moov_size += trak_size;
954
 
  }
955
 
 
956
 
  /* add chunks offsets */
957
 
  for (i = 0; i < moovrf->num_traks; i++) {
958
 
    TrakRecovData *trak = &(moovrf->traks_rd[i]);
959
 
    /* 16 for the mdat header */
960
 
    gint64 offset = moov_size + ftell (outf) + 16;
961
 
    atom_stco64_chunks_add_offset (&trak->stbl.stco64, offset);
962
 
  }
963
 
 
964
 
  /* write the moov */
965
 
  GST_WRITE_UINT32_BE (auxdata, moov_size);
966
 
  GST_WRITE_UINT32_LE (auxdata + 4, FOURCC_moov);
967
 
  if (fwrite (auxdata, 1, 8, outf) != 8) {
968
 
    ATOMS_RECOV_OUTPUT_WRITE_ERROR (err);
969
 
    goto fail;
970
 
  }
971
 
 
972
 
  /* write the mvhd */
973
 
  mvhd_data = g_malloc (moovrf->mvhd_size);
974
 
  if (fseek (moovrf->file, moovrf->mvhd_pos, SEEK_SET) != 0)
975
 
    goto fail;
976
 
  if (fread (mvhd_data, 1, moovrf->mvhd_size,
977
 
          moovrf->file) != moovrf->mvhd_size)
978
 
    goto fail;
979
 
  GST_WRITE_UINT32_BE (mvhd_data + 20, moovrf->timescale);
980
 
  GST_WRITE_UINT32_BE (mvhd_data + 24, longest_duration);
981
 
  if (fwrite (mvhd_data, 1, moovrf->mvhd_size, outf) != moovrf->mvhd_size) {
982
 
    ATOMS_RECOV_OUTPUT_WRITE_ERROR (err);
983
 
    goto fail;
984
 
  }
985
 
  g_free (mvhd_data);
986
 
  mvhd_data = NULL;
987
 
 
988
 
  /* write the traks, this is the tough part because we need to update:
989
 
   * - stbl atom
990
 
   * - sizes of atoms from stbl to trak
991
 
   * - trak duration
992
 
   */
993
 
  for (i = 0; i < moovrf->num_traks; i++) {
994
 
    TrakRecovData *trak = &(moovrf->traks_rd[i]);
995
 
    guint trak_data_size;
996
 
    guint32 stbl_new_size;
997
 
    guint32 minf_new_size;
998
 
    guint32 mdia_new_size;
999
 
    guint32 trak_new_size;
1000
 
    guint32 size_diff;
1001
 
    guint32 duration;           /* in moov's timescale */
1002
 
 
1003
 
    /* convert trak duration to moov's duration */
1004
 
    duration = gst_util_uint64_scale_round (trak->duration, moovrf->timescale,
1005
 
        trak->timescale);
1006
 
 
1007
 
    stbl_children = moov_recov_get_stbl_children_data (moovrf, trak,
1008
 
        &stbl_children_size);
1009
 
    if (stbl_children == NULL)
1010
 
      goto fail;
1011
 
 
1012
 
    /* calc the new size of the atoms from stbl to trak in the atoms tree */
1013
 
    stbl_new_size = trak->stsd_size + stbl_children_size + 8;
1014
 
    size_diff = stbl_new_size - trak->stbl_size;
1015
 
    minf_new_size = trak->minf_size + size_diff;
1016
 
    mdia_new_size = trak->mdia_size + size_diff;
1017
 
    trak_new_size = trak->trak_size + size_diff;
1018
 
 
1019
 
    if (fseek (moovrf->file, trak->file_offset, SEEK_SET) != 0)
1020
 
      goto fail;
1021
 
    trak_data_size = trak->post_stsd_offset - trak->file_offset;
1022
 
    trak_data = g_malloc (trak_data_size);
1023
 
    if (fread (trak_data, 1, trak_data_size, moovrf->file) != trak_data_size) {
1024
 
      goto fail;
1025
 
    }
1026
 
    /* update the size values in those read atoms before writing */
1027
 
    GST_WRITE_UINT32_BE (trak_data, trak_new_size);
1028
 
    GST_WRITE_UINT32_BE (trak_data + (trak->mdia_file_offset -
1029
 
            trak->file_offset), mdia_new_size);
1030
 
    GST_WRITE_UINT32_BE (trak_data + (trak->minf_file_offset -
1031
 
            trak->file_offset), minf_new_size);
1032
 
    GST_WRITE_UINT32_BE (trak_data + (trak->stbl_file_offset -
1033
 
            trak->file_offset), stbl_new_size);
1034
 
 
1035
 
    /* update duration values in tkhd and mdhd */
1036
 
    GST_WRITE_UINT32_BE (trak_data + (trak->tkhd_file_offset -
1037
 
            trak->file_offset) + 28, duration);
1038
 
    GST_WRITE_UINT32_BE (trak_data + (trak->mdhd_file_offset -
1039
 
            trak->file_offset) + 24, trak->duration);
1040
 
 
1041
 
    if (fwrite (trak_data, 1, trak_data_size, outf) != trak_data_size) {
1042
 
      ATOMS_RECOV_OUTPUT_WRITE_ERROR (err);
1043
 
      goto fail;
1044
 
    }
1045
 
    if (fwrite (stbl_children, 1, stbl_children_size, outf) !=
1046
 
        stbl_children_size) {
1047
 
      ATOMS_RECOV_OUTPUT_WRITE_ERROR (err);
1048
 
      goto fail;
1049
 
    }
1050
 
    g_free (trak_data);
1051
 
    trak_data = NULL;
1052
 
    g_free (stbl_children);
1053
 
    stbl_children = NULL;
1054
 
  }
1055
 
 
1056
 
  /* write the mdat */
1057
 
  /* write the header first */
1058
 
  GST_WRITE_UINT32_BE (auxdata, 1);
1059
 
  GST_WRITE_UINT32_LE (auxdata + 4, FOURCC_mdat);
1060
 
  GST_WRITE_UINT64_BE (auxdata + 8, mdatrf->mdat_size);
1061
 
  if (fwrite (auxdata, 1, 16, outf) != 16) {
1062
 
    ATOMS_RECOV_OUTPUT_WRITE_ERROR (err);
1063
 
    goto fail;
1064
 
  }
1065
 
 
1066
 
  /* now read the mdat data and output to the file */
1067
 
  if (fseek (mdatrf->file, mdatrf->mdat_start +
1068
 
          (mdatrf->rawfile ? 0 : mdatrf->mdat_header_size), SEEK_SET) != 0)
1069
 
    goto fail;
1070
 
 
1071
 
  data = g_malloc (4096);
1072
 
  while (!feof (mdatrf->file)) {
1073
 
    gint read, write;
1074
 
 
1075
 
    read = fread (data, 1, 4096, mdatrf->file);
1076
 
    write = fwrite (data, 1, read, outf);
1077
 
 
1078
 
    if (write != read) {
1079
 
      g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
1080
 
          "Failed to copy data to output file: %s", g_strerror (errno));
1081
 
      goto fail;
1082
 
    }
1083
 
  }
1084
 
  g_free (data);
1085
 
 
1086
 
  return TRUE;
1087
 
 
1088
 
fail:
1089
 
  g_free (stbl_children);
1090
 
  g_free (mvhd_data);
1091
 
  g_free (prefix_data);
1092
 
  g_free (trak_data);
1093
 
  g_free (data);
1094
 
  return FALSE;
1095
 
}