[FFmpeg-cvslog] mxfdec: Speed up metadata and index parsing
Tomas Härdin
git at videolan.org
Thu Dec 8 21:36:27 CET 2011
ffmpeg | branch: master | Tomas Härdin <tomas.hardin at codemill.se> | Mon Mar 14 17:00:21 2011 +0100| [dcd30b83b414282423e6aceacd3e370bbc52c195] | committer: Tomas Härdin
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 aren't needlessly
parsed. This speeds up parsing large files a lot.
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=dcd30b83b414282423e6aceacd3e370bbc52c195
---
libavformat/mxfdec.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 119 insertions(+), 9 deletions(-)
diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index 6913855..eaba084 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 {
@@ -441,7 +445,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:
@@ -1304,34 +1308,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 -1;
}
avio_seek(s->pb, -14, SEEK_CUR);
mxf->fc = s;
+ mxf->run_in = avio_tell(s->pb);
+
while (!url_feof(s->pb)) {
const MXFMetadataReadTableEntry *metadata;
- if (klv_read_packet(&klv, s->pb) < 0)
- return -1;
+ 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++) {
@@ -1354,6 +1458,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);
}
More information about the ffmpeg-cvslog
mailing list