Commit 37c36861 authored by Tomas Härdin's avatar Tomas Härdin Committed by Michael Niedermayer

mxfdec: Parse PreviousPartition in mxf_seek_to_previous_partition()

Without this patch the demuxer can get stuck in a loop if PreviousPartition
points somewhere where there's no PartitionPack, or if klv_read_packet() syncs
back up to the current partition.

This should fix Ticket3278 properly and unbreak Ticket4040.
Signed-off-by: 's avatarMichael Niedermayer <michaelni@gmx.at>
parent fc1b89d8
...@@ -89,6 +89,7 @@ typedef struct { ...@@ -89,6 +89,7 @@ typedef struct {
int64_t header_byte_count; int64_t header_byte_count;
int64_t index_byte_count; int64_t index_byte_count;
int pack_length; int pack_length;
int64_t pack_ofs; ///< absolute offset of pack in file, including run-in
} MXFPartition; } MXFPartition;
typedef struct { typedef struct {
...@@ -472,6 +473,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size ...@@ -472,6 +473,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
memset(partition, 0, sizeof(*partition)); memset(partition, 0, sizeof(*partition));
mxf->partitions_count++; mxf->partitions_count++;
partition->pack_length = avio_tell(pb) - klv_offset + size; partition->pack_length = avio_tell(pb) - klv_offset + size;
partition->pack_ofs = klv_offset;
switch(uid[13]) { switch(uid[13]) {
case 2: case 2:
...@@ -547,6 +549,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size ...@@ -547,6 +549,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
partition->index_sid, partition->body_sid); partition->index_sid, partition->body_sid);
/* sanity check PreviousPartition if set */ /* sanity check PreviousPartition if set */
//NOTE: this isn't actually enough, see mxf_seek_to_previous_partition()
if (partition->previous_partition && if (partition->previous_partition &&
mxf->run_in + partition->previous_partition >= klv_offset) { mxf->run_in + partition->previous_partition >= klv_offset) {
av_log(mxf->fc, AV_LOG_ERROR, av_log(mxf->fc, AV_LOG_ERROR,
...@@ -2076,23 +2079,53 @@ static int mxf_parse_klv(MXFContext *mxf, KLVPacket klv, MXFMetadataReadFunc *re ...@@ -2076,23 +2079,53 @@ static int mxf_parse_klv(MXFContext *mxf, KLVPacket klv, MXFMetadataReadFunc *re
} }
/** /**
* Seeks to the previous partition, if possible * Seeks to the previous partition and parses it, if possible
* @return <= 0 if we should stop parsing, > 0 if we should keep going * @return <= 0 if we should stop parsing, > 0 if we should keep going
*/ */
static int mxf_seek_to_previous_partition(MXFContext *mxf) static int mxf_seek_to_previous_partition(MXFContext *mxf)
{ {
AVIOContext *pb = mxf->fc->pb; AVIOContext *pb = mxf->fc->pb;
KLVPacket klv;
int64_t current_partition_ofs;
int ret;
if (!mxf->current_partition || if (!mxf->current_partition ||
mxf->run_in + mxf->current_partition->previous_partition <= mxf->last_forward_tell) mxf->run_in + mxf->current_partition->previous_partition <= mxf->last_forward_tell)
return 0; /* we've parsed all partitions */ return 0; /* we've parsed all partitions */
/* seek to previous partition */ /* seek to previous partition */
current_partition_ofs = mxf->current_partition->pack_ofs; //includes run-in
avio_seek(pb, mxf->run_in + mxf->current_partition->previous_partition, SEEK_SET); avio_seek(pb, mxf->run_in + mxf->current_partition->previous_partition, SEEK_SET);
mxf->current_partition = NULL; mxf->current_partition = NULL;
av_dlog(mxf->fc, "seeking to previous partition\n"); av_dlog(mxf->fc, "seeking to previous partition\n");
/* Make sure this is actually a PartitionPack, and if so parse it.
* See deadlock2.mxf
*/
if ((ret = klv_read_packet(&klv, pb)) < 0) {
av_log(mxf->fc, AV_LOG_ERROR, "failed to read PartitionPack KLV\n");
return ret;
}
if (!mxf_is_partition_pack_key(klv.key)) {
av_log(mxf->fc, AV_LOG_ERROR, "PreviousPartition @ %" PRIx64 " isn't a PartitionPack\n", klv.offset);
return AVERROR_INVALIDDATA;
}
/* We can't just check ofs >= current_partition_ofs because PreviousPartition
* can point to just before the current partition, causing klv_read_packet()
* to sync back up to it. See deadlock3.mxf
*/
if (klv.offset >= current_partition_ofs) {
av_log(mxf->fc, AV_LOG_ERROR, "PreviousPartition for PartitionPack @ %"
PRIx64 " indirectly points to itself\n", current_partition_ofs);
return AVERROR_INVALIDDATA;
}
if ((ret = mxf_parse_klv(mxf, klv, mxf_read_partition_pack, 0, 0)) < 0)
return ret;
return 1; return 1;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment