avformat/mxfdec; parse random index pack to get last partition offset and use it...
authorPaul B Mahol <onemda@gmail.com>
Fri, 18 Oct 2013 10:44:56 +0000 (10:44 +0000)
committerPaul B Mahol <onemda@gmail.com>
Mon, 21 Oct 2013 13:29:30 +0000 (13:29 +0000)
Footer partition may not be present and even if present footer partition
offset may not be set in any partition except last one.

Signed-off-by: Paul B Mahol <onemda@gmail.com>
libavformat/mxfdec.c

index 72faf4c..d0cbeea 100644 (file)
@@ -213,6 +213,7 @@ typedef struct {
     struct AVAES *aesc;
     uint8_t *local_tags;
     int local_tags_count;
+    uint64_t last_partition;
     uint64_t footer_partition;
     KLVPacket current_klv_data;
     int current_klv_index;
@@ -254,6 +255,7 @@ static const uint8_t mxf_klv_key[]                         = { 0x06,0x0e,0x2b,0x
 static const uint8_t mxf_crypto_source_container_ul[]      = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x02,0x02,0x00,0x00,0x00 };
 static const uint8_t mxf_encrypted_triplet_key[]           = { 0x06,0x0e,0x2b,0x34,0x02,0x04,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x7e,0x01,0x00 };
 static const uint8_t mxf_encrypted_essence_container[]     = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0b,0x01,0x00 };
+static const uint8_t mxf_random_index_pack_key[]           = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x02,0x01,0x01,0x11,0x01,0x00 };
 static const uint8_t mxf_sony_mpeg4_extradata[]            = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0e,0x06,0x06,0x02,0x02,0x01,0x00,0x00 };
 
 #define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y)))
@@ -1852,31 +1854,33 @@ static int mxf_parse_handle_essence(MXFContext *mxf)
 
     if (mxf->parsing_backward) {
         return mxf_seek_to_previous_partition(mxf);
-    } else {
-        if (!mxf->footer_partition) {
-            av_dlog(mxf->fc, "no footer\n");
-            return 0;
-        }
+    } else if (mxf->footer_partition || mxf->last_partition){
+        uint64_t offset;
+
+        offset = mxf->footer_partition ? mxf->footer_partition : mxf->last_partition;
 
-        av_dlog(mxf->fc, "seeking to footer\n");
+        av_dlog(mxf->fc, "seeking to last partition\n");
 
         /* remember where we were so we don't end up seeking further back than this */
         mxf->last_forward_tell = avio_tell(pb);
 
         if (!pb->seekable) {
-            av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing footer\n");
+            av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing last partition\n");
             return -1;
         }
 
-        /* seek to footer partition and parse backward */
-        if ((ret = avio_seek(pb, mxf->run_in + mxf->footer_partition, SEEK_SET)) < 0) {
-            av_log(mxf->fc, AV_LOG_ERROR, "failed to seek to footer @ 0x%"PRIx64" (%"PRId64") - partial file?\n",
-                   mxf->run_in + mxf->footer_partition, ret);
+        /* seek to last partition and parse backward */
+        if ((ret = avio_seek(pb, mxf->run_in + offset, SEEK_SET)) < 0) {
+            av_log(mxf->fc, AV_LOG_ERROR, "failed to seek to last partition @ 0x%"PRIx64" (%"PRId64") - partial file?\n",
+                   mxf->run_in + offset, ret);
             return ret;
         }
 
         mxf->current_partition = NULL;
         mxf->parsing_backward = 1;
+    } else {
+        av_dlog(mxf->fc, "can't find last partition\n");
+        return 0;
     }
 
     return 1;
@@ -1968,6 +1972,34 @@ static void mxf_handle_small_eubc(AVFormatContext *s)
     mxf->edit_units_per_packet = 1920;
 }
 
+static void mxf_read_random_index_pack(AVFormatContext *s)
+{
+    MXFContext *mxf = s->priv_data;
+    uint32_t length;
+    int64_t file_size;
+    KLVPacket klv;
+
+    if (!s->pb->seekable)
+        return;
+
+    file_size = avio_size(s->pb);
+    avio_seek(s->pb, file_size - 4, SEEK_SET);
+    length = avio_rb32(s->pb);
+    if (length <= 32 || length >= FFMIN(file_size, INT_MAX))
+        goto end;
+    avio_seek(s->pb, file_size - length, SEEK_SET);
+    if (klv_read_packet(&klv, s->pb) < 0 ||
+        !IS_KLV_KEY(klv.key, mxf_random_index_pack_key) ||
+        klv.length != length - 20)
+        goto end;
+
+    avio_skip(s->pb, klv.length - 12);
+    mxf->last_partition = avio_rb64(s->pb);
+
+end:
+    avio_seek(s->pb, mxf->run_in, SEEK_SET);
+}
+
 static int mxf_read_header(AVFormatContext *s)
 {
     MXFContext *mxf = s->priv_data;
@@ -1986,6 +2018,8 @@ static int mxf_read_header(AVFormatContext *s)
     mxf->fc = s;
     mxf->run_in = avio_tell(s->pb);
 
+    mxf_read_random_index_pack(s);
+
     while (!url_feof(s->pb)) {
         const MXFMetadataReadTableEntry *metadata;