From 775d3b4ab174d3654864668beb8a68657bc6da9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Mon, 14 Mar 2011 17:00:21 +0100 Subject: [PATCH] mxfdec: Speed up metadata and index parsing. Specifically, this means parsing as before until we run into essence. At that point we seek to the footer and parse until EOF. After that we start seeking backward to the previous partition and parse that until we run into essence or the next partition. This procedure is repeated until we encounter the last partition we parsed in the forward direction. The end result of all this is that large essence containers are not needlessly parsed. This speeds up parsing large files a lot. Signed-off-by: Janne Grunau --- libavformat/mxfdec.c | 129 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 119 insertions(+), 10 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 7c45b01c49..2ab2efebf8 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -187,6 +187,10 @@ typedef struct { int64_t first_essence_length; KLVPacket current_klv_data; int current_klv_index; + int run_in; + MXFPartition *current_partition; + int parsing_backward; + int64_t last_forward_tell; } MXFContext; enum MXFWrappingScheme { @@ -443,7 +447,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size if (!mxf->partitions) return AVERROR(ENOMEM); - partition = &mxf->partitions[mxf->partitions_count++]; + partition = mxf->current_partition = &mxf->partitions[mxf->partitions_count++]; switch(uid[13]) { case 2: @@ -1341,35 +1345,134 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF return ctx_size ? mxf_add_metadata_set(mxf, ctx) : 0; } +/** + * Seeks to the previous partition, if possible + * @return <= 0 if we should stop parsing, > 0 if we should keep going + */ +static int mxf_seek_to_previous_partition(MXFContext *mxf) +{ + AVIOContext *pb = mxf->fc->pb; + + if (!mxf->current_partition || + mxf->run_in + mxf->current_partition->previous_partition <= mxf->last_forward_tell) + return 0; /* we've parsed all partitions */ + + /* seek to previous partition */ + avio_seek(pb, mxf->run_in + mxf->current_partition->previous_partition, SEEK_SET); + mxf->current_partition = NULL; + + av_dlog(mxf->fc, "seeking to previous partition\n"); + + return 1; +} + +/** + * Called when essence is encountered + * @return <= 0 if we should stop parsing, > 0 if we should keep going + */ +static int mxf_parse_handle_essence(MXFContext *mxf) +{ + AVIOContext *pb = mxf->fc->pb; + int64_t ret; + + if (!mxf->current_partition) { + av_log(mxf->fc, AV_LOG_ERROR, "found essence prior to PartitionPack\n"); + return AVERROR_INVALIDDATA; + } + + 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; + } + + av_dlog(mxf->fc, "seeking to footer\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"); + 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); + return ret; + } + + mxf->current_partition = NULL; + mxf->parsing_backward = 1; + } + + return 1; +} + +/** + * Called when the next partition or EOF is encountered + * @return <= 0 if we should stop parsing, > 0 if we should keep going + */ +static int mxf_parse_handle_partition_or_eof(MXFContext *mxf) +{ + return mxf->parsing_backward ? mxf_seek_to_previous_partition(mxf) : 1; +} + static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) { MXFContext *mxf = s->priv_data; KLVPacket klv; + mxf->last_forward_tell = INT64_MAX; + if (!mxf_read_sync(s->pb, mxf_header_partition_pack_key, 14)) { av_log(s, AV_LOG_ERROR, "could not find header partition pack key\n"); return AVERROR_INVALIDDATA; } avio_seek(s->pb, -14, SEEK_CUR); mxf->fc = s; + mxf->run_in = avio_tell(s->pb); + while (!s->pb->eof_reached) { - int ret; const MXFMetadataReadTableEntry *metadata; - if ((ret = klv_read_packet(&klv, s->pb)) < 0) - return ret; + if (klv_read_packet(&klv, s->pb) < 0) { + /* EOF - seek to previous partition or stop */ + if(mxf_parse_handle_partition_or_eof(mxf) <= 0) + break; + else + continue; + } + PRINT_KEY(s, "read header", klv.key); av_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset); if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) || - IS_KLV_KEY(klv.key, mxf_essence_element_key)) { - /* FIXME avoid seek */ - avio_seek(s->pb, klv.offset, SEEK_SET); - break; - } + IS_KLV_KEY(klv.key, mxf_essence_element_key) || + IS_KLV_KEY(klv.key, mxf_system_item_key)) { if (IS_KLV_KEY(klv.key, mxf_system_item_key)) { mxf->system_item = 1; - avio_skip(s->pb, klv.length); + } + + if (!mxf->essence_offset) + mxf->essence_offset = klv.offset; + + if (!mxf->first_essence_kl_length && IS_KLV_KEY(klv.key, mxf_essence_element_key)) { + mxf->first_essence_kl_length = avio_tell(s->pb) - klv.offset; + mxf->first_essence_length = klv.length; + } + + /* seek to footer, previous partition or stop */ + if (mxf_parse_handle_essence(mxf) <= 0) + break; continue; + } else if (!memcmp(klv.key, mxf_header_partition_pack_key, 13) && + klv.key[13] >= 2 && klv.key[13] <= 4 && mxf->current_partition) { + /* next partition pack - keep going, seek to previous partition or stop */ + if(mxf_parse_handle_partition_or_eof(mxf) <= 0) + break; } for (metadata = mxf_metadata_read_table; metadata->read; metadata++) { @@ -1392,6 +1495,12 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) if (!metadata->read) avio_skip(s->pb, klv.length); } + /* FIXME avoid seek */ + if (!mxf->essence_offset) { + av_log(s, AV_LOG_ERROR, "no essence\n"); + return AVERROR_INVALIDDATA; + } + avio_seek(s->pb, mxf->essence_offset, SEEK_SET); return mxf_parse_structural_metadata(mxf); }