atomsrecovery: read from mdat only what is on headers
authorThiago Santos <thiagossantos@gmail.com>
Sun, 9 Jul 2017 05:11:49 +0000 (22:11 -0700)
committerThiago Santos <thiagossantos@gmail.com>
Wed, 25 Oct 2017 04:33:25 +0000 (21:33 -0700)
It is possible that the mdat has more data than what was stored in the
headers file. If we put that to the output the file will have bogus data
at the end and some players will complain.

https://bugzilla.gnome.org/show_bug.cgi?id=784258

gst/isomp4/atomsrecovery.c
gst/isomp4/atomsrecovery.h
gst/isomp4/gstqtmoovrecover.c

index 5462713..8d060fb 100644 (file)
@@ -88,6 +88,8 @@
 
 #include "atomsrecovery.h"
 
+#define MAX_CHUNK_SIZE (1024 * 1024)    /* 1MB */
+
 #define ATOMS_RECOV_OUTPUT_WRITE_ERROR(err) \
     g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE, \
         "Failed to write to output file: %s", g_strerror (errno))
@@ -956,7 +958,7 @@ fail:
 
 gboolean
 moov_recov_write_file (MoovRecovFile * moovrf, MdatRecovFile * mdatrf,
-    FILE * outf, GError ** err)
+    FILE * outf, GError ** err, GError ** warn)
 {
   guint8 auxdata[16];
   guint8 *data = NULL;
@@ -969,6 +971,7 @@ moov_recov_write_file (MoovRecovFile * moovrf, MdatRecovFile * mdatrf,
   guint8 *stbl_children = NULL;
   guint32 longest_duration = 0;
   guint16 version;
+  guint remaining;
 
   /* check the version */
   if (fseek (moovrf->file, 0, SEEK_SET) != 0) {
@@ -1159,12 +1162,16 @@ moov_recov_write_file (MoovRecovFile * moovrf, MdatRecovFile * mdatrf,
           (mdatrf->rawfile ? 0 : mdatrf->mdat_header_size), SEEK_SET) != 0)
     goto fail;
 
-  data = g_malloc (4096);
-  while (!feof (mdatrf->file)) {
-    gint read, write;
+  remaining = mdatrf->mdat_size - mdatrf->mdat_header_size;
+  data = g_malloc (MAX_CHUNK_SIZE);
+  while (!feof (mdatrf->file) && remaining > 0) {
+    gint read, write, readsize;
+
+    readsize = MIN (MAX_CHUNK_SIZE, remaining);
 
-    read = fread (data, 1, 4096, mdatrf->file);
+    read = fread (data, 1, readsize, mdatrf->file);
     write = fwrite (data, 1, read, outf);
+    remaining -= read;
 
     if (write != read) {
       g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
@@ -1174,6 +1181,17 @@ moov_recov_write_file (MoovRecovFile * moovrf, MdatRecovFile * mdatrf,
   }
   g_free (data);
 
+  if (remaining) {
+    g_set_error (warn, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
+        "Samples in recovery file were not present on headers."
+        " Bytes lost: %u", remaining);
+  } else if (!feof (mdatrf->file)) {
+    g_set_error (warn, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
+        "Samples in headers were not found in data file.");
+    GST_FIXME ("Rewrite mdat size if we reach this to make the file"
+        " fully correct");
+  }
+
   return TRUE;
 
 fail:
index 2d9382d..f044c9b 100644 (file)
@@ -157,6 +157,6 @@ gboolean        moov_recov_parse_buffers (MoovRecovFile * moovrf,
                                           GError ** err);
 gboolean        moov_recov_write_file    (MoovRecovFile * moovrf,
                                           MdatRecovFile * mdatrf, FILE * outf,
-                                          GError ** err);
+                                          GError ** err, GError ** warn);
 
 #endif /* __ATOMS_RECOVERY_H__ */
index 80b22eb..f5d2b91 100644 (file)
@@ -169,6 +169,7 @@ gst_qt_moov_recover_run (void *data)
   MoovRecovFile *moov_recov = NULL;
   GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (data);
   GError *err = NULL;
+  GError *warn = NULL;
 
   GST_LOG_OBJECT (qtmr, "Starting task");
 
@@ -243,10 +244,15 @@ gst_qt_moov_recover_run (void *data)
   }
 
   GST_DEBUG_OBJECT (qtmr, "Writing fixed file to output");
-  if (!moov_recov_write_file (moov_recov, mdat_recov, output, &err)) {
+  if (!moov_recov_write_file (moov_recov, mdat_recov, output, &err, &warn)) {
     goto end;
   }
 
+  if (warn) {
+    GST_ELEMENT_WARNING (qtmr, RESOURCE, FAILED, ("%s", warn->message), (NULL));
+    g_error_free (warn);
+  }
+
   /* here means success */
   GST_DEBUG_OBJECT (qtmr, "Finished successfully, posting EOS");
   gst_element_post_message (GST_ELEMENT_CAST (qtmr),