| 
				
				
					
				
				
				 | 
			
			 | 
			@@ -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); | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			} | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
  | 
		
		
	
	
		
			
				| 
				
					
				
				
				
				 | 
			
			 | 
			
  |