You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-10 06:10:52 +02:00
avformat/mxfdec: use both body_sid and track_number to find the track of a packet
In order to do that we have to parse the EssenceContainerData and assign the proper body_sid and index_sid to the tracks from the corresponding source packages. This fixes packets returned in the wrong stream for some OP1-b files. Based on a patch by Alex Mogurenko from https://github.com/da8eat/FFmpeg Reference: http://mogurenko.com/2018/01/02/mxf-op1b-ffmpeg-part1/ Signed-off-by: Marton Balint <cus@passwd.hu>
This commit is contained in:
@@ -162,6 +162,8 @@ typedef struct {
|
|||||||
int intra_only;
|
int intra_only;
|
||||||
uint64_t sample_count;
|
uint64_t sample_count;
|
||||||
int64_t original_duration; /* st->duration in SampleRate/EditRate units */
|
int64_t original_duration; /* st->duration in SampleRate/EditRate units */
|
||||||
|
int index_sid;
|
||||||
|
int body_sid;
|
||||||
} MXFTrack;
|
} MXFTrack;
|
||||||
|
|
||||||
typedef struct MXFDescriptor {
|
typedef struct MXFDescriptor {
|
||||||
@@ -223,6 +225,15 @@ typedef struct MXFPackage {
|
|||||||
int comment_count;
|
int comment_count;
|
||||||
} MXFPackage;
|
} MXFPackage;
|
||||||
|
|
||||||
|
typedef struct MXFEssenceContainerData {
|
||||||
|
UID uid;
|
||||||
|
enum MXFMetadataSetType type;
|
||||||
|
UID package_uid;
|
||||||
|
UID package_ul;
|
||||||
|
int index_sid;
|
||||||
|
int body_sid;
|
||||||
|
} MXFEssenceContainerData;
|
||||||
|
|
||||||
typedef struct MXFMetadataSet {
|
typedef struct MXFMetadataSet {
|
||||||
UID uid;
|
UID uid;
|
||||||
enum MXFMetadataSetType type;
|
enum MXFMetadataSetType type;
|
||||||
@@ -247,6 +258,8 @@ typedef struct MXFContext {
|
|||||||
MXFOP op;
|
MXFOP op;
|
||||||
UID *packages_refs;
|
UID *packages_refs;
|
||||||
int packages_count;
|
int packages_count;
|
||||||
|
UID *essence_container_data_refs;
|
||||||
|
int essence_container_data_count;
|
||||||
MXFMetadataSet **metadata_sets;
|
MXFMetadataSet **metadata_sets;
|
||||||
int metadata_sets_count;
|
int metadata_sets_count;
|
||||||
AVFormatContext *fc;
|
AVFormatContext *fc;
|
||||||
@@ -385,20 +398,43 @@ static int klv_read_packet(KLVPacket *klv, AVIOContext *pb)
|
|||||||
return klv->length == -1 ? -1 : 0;
|
return klv->length == -1 ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mxf_get_stream_index(AVFormatContext *s, KLVPacket *klv)
|
static int mxf_get_stream_index(AVFormatContext *s, KLVPacket *klv, int body_sid)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < s->nb_streams; i++) {
|
for (i = 0; i < s->nb_streams; i++) {
|
||||||
MXFTrack *track = s->streams[i]->priv_data;
|
MXFTrack *track = s->streams[i]->priv_data;
|
||||||
/* SMPTE 379M 7.3 */
|
/* SMPTE 379M 7.3 */
|
||||||
if (track && !memcmp(klv->key + sizeof(mxf_essence_element_key), track->track_number, sizeof(track->track_number)))
|
if (track && (!body_sid || !track->body_sid || track->body_sid == body_sid) && !memcmp(klv->key + sizeof(mxf_essence_element_key), track->track_number, sizeof(track->track_number)))
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
/* return 0 if only one stream, for OP Atom files with 0 as track number */
|
/* return 0 if only one stream, for OP Atom files with 0 as track number */
|
||||||
return s->nb_streams == 1 ? 0 : -1;
|
return s->nb_streams == 1 ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int find_body_sid_by_offset(MXFContext *mxf, int64_t offset)
|
||||||
|
{
|
||||||
|
// we look for partition where the offset is placed
|
||||||
|
int a, b, m;
|
||||||
|
int64_t this_partition;
|
||||||
|
|
||||||
|
a = -1;
|
||||||
|
b = mxf->partitions_count;
|
||||||
|
|
||||||
|
while (b - a > 1) {
|
||||||
|
m = (a + b) >> 1;
|
||||||
|
this_partition = mxf->partitions[m].this_partition;
|
||||||
|
if (this_partition <= offset)
|
||||||
|
a = m;
|
||||||
|
else
|
||||||
|
b = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == -1)
|
||||||
|
return 0;
|
||||||
|
return mxf->partitions[a].body_sid;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: use AVBitStreamFilter */
|
/* XXX: use AVBitStreamFilter */
|
||||||
static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st, AVPacket *pkt, int64_t length)
|
static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st, AVPacket *pkt, int64_t length)
|
||||||
{
|
{
|
||||||
@@ -440,6 +476,7 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv
|
|||||||
uint8_t ivec[16];
|
uint8_t ivec[16];
|
||||||
uint8_t tmpbuf[16];
|
uint8_t tmpbuf[16];
|
||||||
int index;
|
int index;
|
||||||
|
int body_sid;
|
||||||
|
|
||||||
if (!mxf->aesc && s->key && s->keylen == 16) {
|
if (!mxf->aesc && s->key && s->keylen == 16) {
|
||||||
mxf->aesc = av_aes_alloc();
|
mxf->aesc = av_aes_alloc();
|
||||||
@@ -457,7 +494,9 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv
|
|||||||
avio_read(pb, klv->key, 16);
|
avio_read(pb, klv->key, 16);
|
||||||
if (!IS_KLV_KEY(klv, mxf_essence_element_key))
|
if (!IS_KLV_KEY(klv, mxf_essence_element_key))
|
||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
index = mxf_get_stream_index(s, klv);
|
|
||||||
|
body_sid = find_body_sid_by_offset(mxf, klv->offset);
|
||||||
|
index = mxf_get_stream_index(s, klv, body_sid);
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
// source size
|
// source size
|
||||||
@@ -757,6 +796,9 @@ static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int siz
|
|||||||
av_log(mxf->fc, AV_LOG_VERBOSE, "Multiple packages_refs\n");
|
av_log(mxf->fc, AV_LOG_VERBOSE, "Multiple packages_refs\n");
|
||||||
av_free(mxf->packages_refs);
|
av_free(mxf->packages_refs);
|
||||||
return mxf_read_strong_ref_array(pb, &mxf->packages_refs, &mxf->packages_count);
|
return mxf_read_strong_ref_array(pb, &mxf->packages_refs, &mxf->packages_count);
|
||||||
|
case 0x1902:
|
||||||
|
av_free(mxf->essence_container_data_refs);
|
||||||
|
return mxf_read_strong_ref_array(pb, &mxf->essence_container_data_refs, &mxf->essence_container_data_count);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -893,6 +935,25 @@ static int mxf_read_package(void *arg, AVIOContext *pb, int tag, int size, UID u
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mxf_read_essence_container_data(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
|
||||||
|
{
|
||||||
|
MXFEssenceContainerData *essence_data = arg;
|
||||||
|
switch(tag) {
|
||||||
|
case 0x2701:
|
||||||
|
/* linked package umid UMID */
|
||||||
|
avio_read(pb, essence_data->package_ul, 16);
|
||||||
|
avio_read(pb, essence_data->package_uid, 16);
|
||||||
|
break;
|
||||||
|
case 0x3f06:
|
||||||
|
essence_data->index_sid = avio_rb32(pb);
|
||||||
|
break;
|
||||||
|
case 0x3f07:
|
||||||
|
essence_data->body_sid = avio_rb32(pb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *segment)
|
static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *segment)
|
||||||
{
|
{
|
||||||
int i, length;
|
int i, length;
|
||||||
@@ -1996,6 +2057,21 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
|
|||||||
av_log(mxf->fc, AV_LOG_ERROR, "material track %d: no corresponding source track found\n", material_track->track_id);
|
av_log(mxf->fc, AV_LOG_ERROR, "material track %d: no corresponding source track found\n", material_track->track_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (k = 0; k < mxf->essence_container_data_count; k++) {
|
||||||
|
MXFEssenceContainerData *essence_data;
|
||||||
|
|
||||||
|
if (!(essence_data = mxf_resolve_strong_ref(mxf, &mxf->essence_container_data_refs[k], EssenceContainerData))) {
|
||||||
|
av_log(mxf, AV_LOG_TRACE, "could not resolve essence container data strong ref\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!memcmp(component->source_package_ul, essence_data->package_ul, sizeof(UID)) && !memcmp(component->source_package_uid, essence_data->package_uid, sizeof(UID))) {
|
||||||
|
source_track->body_sid = essence_data->body_sid;
|
||||||
|
source_track->index_sid = essence_data->index_sid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(source_track && component)
|
if(source_track && component)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2402,6 +2478,7 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = {
|
|||||||
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x0c,0x00 }, mxf_read_pulldown_component, sizeof(MXFPulldownComponent), PulldownComponent },
|
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x0c,0x00 }, mxf_read_pulldown_component, sizeof(MXFPulldownComponent), PulldownComponent },
|
||||||
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x04,0x01,0x02,0x02,0x00,0x00 }, mxf_read_cryptographic_context, sizeof(MXFCryptoContext), CryptoContext },
|
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x04,0x01,0x02,0x02,0x00,0x00 }, mxf_read_cryptographic_context, sizeof(MXFCryptoContext), CryptoContext },
|
||||||
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x10,0x01,0x00 }, mxf_read_index_table_segment, sizeof(MXFIndexTableSegment), IndexTableSegment },
|
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x10,0x01,0x00 }, mxf_read_index_table_segment, sizeof(MXFIndexTableSegment), IndexTableSegment },
|
||||||
|
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x23,0x00 }, mxf_read_essence_container_data, sizeof(MXFEssenceContainerData), EssenceContainerData },
|
||||||
{ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, NULL, 0, AnyType },
|
{ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, NULL, 0, AnyType },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3111,7 +3188,8 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
|
|||||||
if (IS_KLV_KEY(klv.key, mxf_essence_element_key) ||
|
if (IS_KLV_KEY(klv.key, mxf_essence_element_key) ||
|
||||||
IS_KLV_KEY(klv.key, mxf_canopus_essence_element_key) ||
|
IS_KLV_KEY(klv.key, mxf_canopus_essence_element_key) ||
|
||||||
IS_KLV_KEY(klv.key, mxf_avid_essence_element_key)) {
|
IS_KLV_KEY(klv.key, mxf_avid_essence_element_key)) {
|
||||||
int index = mxf_get_stream_index(s, &klv);
|
int body_sid = find_body_sid_by_offset(mxf, klv.offset);
|
||||||
|
int index = mxf_get_stream_index(s, &klv, body_sid);
|
||||||
int64_t next_ofs, next_klv;
|
int64_t next_ofs, next_klv;
|
||||||
AVStream *st;
|
AVStream *st;
|
||||||
|
|
||||||
@@ -3237,6 +3315,7 @@ static int mxf_read_close(AVFormatContext *s)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
av_freep(&mxf->packages_refs);
|
av_freep(&mxf->packages_refs);
|
||||||
|
av_freep(&mxf->essence_container_data_refs);
|
||||||
|
|
||||||
for (i = 0; i < s->nb_streams; i++)
|
for (i = 0; i < s->nb_streams; i++)
|
||||||
s->streams[i]->priv_data = NULL;
|
s->streams[i]->priv_data = NULL;
|
||||||
|
Reference in New Issue
Block a user