mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
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 <janne-libav@jannau.net>
This commit is contained in:
parent
0999151962
commit
775d3b4ab1
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user