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