diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 72faf4cce2..d0cbeead96 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -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;