mirror of https://git.ffmpeg.org/ffmpeg.git
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.
This commit is contained in:
parent
e1914b5a2f
commit
dcd30b83b4
|
@ -187,6 +187,10 @@ typedef struct {
|
||||||
int64_t first_essence_length;
|
int64_t first_essence_length;
|
||||||
KLVPacket current_klv_data;
|
KLVPacket current_klv_data;
|
||||||
int current_klv_index;
|
int current_klv_index;
|
||||||
|
int run_in;
|
||||||
|
MXFPartition *current_partition;
|
||||||
|
int parsing_backward;
|
||||||
|
int64_t last_forward_tell;
|
||||||
} MXFContext;
|
} MXFContext;
|
||||||
|
|
||||||
enum MXFWrappingScheme {
|
enum MXFWrappingScheme {
|
||||||
|
@ -441,7 +445,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
|
||||||
if (!mxf->partitions)
|
if (!mxf->partitions)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
partition = &mxf->partitions[mxf->partitions_count++];
|
partition = mxf->current_partition = &mxf->partitions[mxf->partitions_count++];
|
||||||
|
|
||||||
switch(uid[13]) {
|
switch(uid[13]) {
|
||||||
case 2:
|
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;
|
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)
|
static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap)
|
||||||
{
|
{
|
||||||
MXFContext *mxf = s->priv_data;
|
MXFContext *mxf = s->priv_data;
|
||||||
KLVPacket klv;
|
KLVPacket klv;
|
||||||
|
|
||||||
|
mxf->last_forward_tell = INT64_MAX;
|
||||||
|
|
||||||
if (!mxf_read_sync(s->pb, mxf_header_partition_pack_key, 14)) {
|
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");
|
av_log(s, AV_LOG_ERROR, "could not find header partition pack key\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
avio_seek(s->pb, -14, SEEK_CUR);
|
avio_seek(s->pb, -14, SEEK_CUR);
|
||||||
mxf->fc = s;
|
mxf->fc = s;
|
||||||
|
mxf->run_in = avio_tell(s->pb);
|
||||||
|
|
||||||
while (!url_feof(s->pb)) {
|
while (!url_feof(s->pb)) {
|
||||||
const MXFMetadataReadTableEntry *metadata;
|
const MXFMetadataReadTableEntry *metadata;
|
||||||
|
|
||||||
if (klv_read_packet(&klv, s->pb) < 0)
|
if (klv_read_packet(&klv, s->pb) < 0) {
|
||||||
return -1;
|
/* 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);
|
PRINT_KEY(s, "read header", klv.key);
|
||||||
av_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset);
|
av_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset);
|
||||||
if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) ||
|
if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) ||
|
||||||
IS_KLV_KEY(klv.key, mxf_essence_element_key)) {
|
IS_KLV_KEY(klv.key, mxf_essence_element_key) ||
|
||||||
/* FIXME avoid seek */
|
IS_KLV_KEY(klv.key, mxf_system_item_key)) {
|
||||||
avio_seek(s->pb, klv.offset, SEEK_SET);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (IS_KLV_KEY(klv.key, mxf_system_item_key)) {
|
if (IS_KLV_KEY(klv.key, mxf_system_item_key)) {
|
||||||
mxf->system_item = 1;
|
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;
|
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++) {
|
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)
|
if (!metadata->read)
|
||||||
avio_skip(s->pb, klv.length);
|
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);
|
return mxf_parse_structural_metadata(mxf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue