LCOV - code coverage report
Current view: top level - gst-plugins-bad/gst/qtmux - atomsrecovery.c (source / functions) Hit Total Coverage
Test: GStreamer Lines: 0 507 0.0 %
Date: 2011-03-25 Functions: 0 33 0.0 %
Branches: 0 280 0.0 %

           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                 :            : }

Generated by: LCOV version 1.9