From e5d217f04899e00b5d6af11fa396242649e75cc1 Mon Sep 17 00:00:00 2001 From: Mark Reid Date: Sun, 30 Nov 2014 12:16:27 -0800 Subject: [PATCH] libavformat/mxfdec.c: initial support for EssenceGroups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous version reviewed-by: Tomas Härdin Signed-off-by: Michael Niedermayer --- libavformat/mxf.c | 1 + libavformat/mxf.h | 1 + libavformat/mxfdec.c | 148 +++++++++++++++++++++++++++++++++++-------- 3 files changed, 123 insertions(+), 27 deletions(-) diff --git a/libavformat/mxf.c b/libavformat/mxf.c index 4dc54d7194..14d143e5f0 100644 --- a/libavformat/mxf.c +++ b/libavformat/mxf.c @@ -94,6 +94,7 @@ static const struct { {AV_PIX_FMT_RGB565BE,{'R', 5, 'G', 6, 'B', 5 }}, {AV_PIX_FMT_RGBA, {'R', 8, 'G', 8, 'B', 8, 'A', 8 }}, {AV_PIX_FMT_PAL8, {'P', 8 }}, + {AV_PIX_FMT_GRAY8, {'A', 8 }}, }; static const int num_pixel_layouts = FF_ARRAY_ELEMS(ff_mxf_pixel_layouts); diff --git a/libavformat/mxf.h b/libavformat/mxf.h index 5b95efa697..d9e17c6b3f 100644 --- a/libavformat/mxf.h +++ b/libavformat/mxf.h @@ -46,6 +46,7 @@ enum MXFMetadataSetType { IndexTableSegment, EssenceContainerData, TypeBottom,// add metadata type before this + EssenceGroup, }; enum MXFFrameLayout { diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index bc0a10b542..8aaf4c333f 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -133,6 +133,14 @@ typedef struct { UID input_segment_ref; } MXFPulldownComponent; +typedef struct { + UID uid; + enum MXFMetadataSetType type; + UID *structural_components_refs; + int structural_components_count; + int64_t duration; +} MXFEssenceGroup; + typedef struct { UID uid; enum MXFMetadataSetType type; @@ -161,6 +169,7 @@ typedef struct { int field_dominance; int channels; int bits_per_sample; + int64_t duration; /* ContainerDuration optional property */ unsigned int component_depth; unsigned int horiz_subsampling; unsigned int vert_subsampling; @@ -742,6 +751,25 @@ static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, UID return 0; } +static int mxf_read_essence_group(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) +{ + MXFEssenceGroup *essence_group = arg; + switch (tag) { + case 0x0202: + essence_group->duration = avio_rb64(pb); + break; + case 0x0501: + essence_group->structural_components_count = avio_rb32(pb); + essence_group->structural_components_refs = av_calloc(essence_group->structural_components_count, sizeof(UID)); + if (!essence_group->structural_components_refs) + return AVERROR(ENOMEM); + avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */ + avio_read(pb, (uint8_t *)essence_group->structural_components_refs, essence_group->structural_components_count * sizeof(UID)); + break; + } + return 0; +} + static int mxf_read_utf16_string(AVIOContext *pb, int size, char** str) { int ret; @@ -872,7 +900,6 @@ static void mxf_read_pixel_layout(AVIOContext *pb, MXFDescriptor *descriptor) static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFDescriptor *descriptor = arg; - descriptor->pix_fmt = AV_PIX_FMT_NONE; switch(tag) { case 0x3F01: descriptor->sub_descriptors_count = avio_rb32(pb); @@ -882,6 +909,9 @@ static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */ avio_read(pb, (uint8_t *)descriptor->sub_descriptors_refs, descriptor->sub_descriptors_count * sizeof(UID)); break; + case 0x3002: /* ContainerDuration */ + descriptor->duration = avio_rb64(pb); + break; case 0x3004: avio_read(pb, descriptor->essence_container_ul, 16); break; @@ -994,6 +1024,7 @@ static const MXFCodecUL mxf_picture_essence_container_uls[] = { { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x04,0x60,0x01 }, 14, AV_CODEC_ID_MPEG2VIDEO }, /* MPEG-ES Frame wrapped */ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x02,0x41,0x01 }, 14, AV_CODEC_ID_DVVIDEO }, /* DV 625 25mbps */ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x05,0x00,0x00 }, 14, AV_CODEC_ID_RAWVIDEO }, /* Uncompressed Picture */ + { { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0xff,0x4b,0x46,0x41,0x41,0x00,0x0d,0x4d,0x4f }, 14, AV_CODEC_ID_RAWVIDEO }, /* Legacy ?? Uncompressed Picture */ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE }, }; @@ -1457,12 +1488,75 @@ static MXFTimecodeComponent* mxf_resolve_timecode_component(MXFContext *mxf, UID return NULL; } +static MXFPackage* mxf_resolve_source_package(MXFContext *mxf, UID package_uid) +{ + MXFPackage *package = NULL; + int i; + + for (i = 0; i < mxf->packages_count; i++) { + package = mxf_resolve_strong_ref(mxf, &mxf->packages_refs[i], SourcePackage); + if (!package) + continue; + + if (!memcmp(package->package_uid, package_uid, 16)) + return package; + } + return NULL; +} + +static MXFStructuralComponent* mxf_resolve_essence_group_choice(MXFContext *mxf, MXFEssenceGroup *essence_group) +{ + MXFStructuralComponent *component = NULL; + MXFPackage *package = NULL; + MXFDescriptor *descriptor = NULL; + int i; + + if (!essence_group || !essence_group->structural_components_count) + return NULL; + + /* essence groups contains multiple representations of the same media, + this return the first components with a valid Descriptor typically index 0 */ + for (i =0; i < essence_group->structural_components_count; i++){ + component = mxf_resolve_strong_ref(mxf, &essence_group->structural_components_refs[i], SourceClip); + if (!component) + continue; + + if (!(package = mxf_resolve_source_package(mxf, component->source_package_uid))) + continue; + + descriptor = mxf_resolve_strong_ref(mxf, &package->descriptor_ref, Descriptor); + if (descriptor){ + /* HACK: force the duration of the component to match the duration of the descriptor */ + if (descriptor->duration != AV_NOPTS_VALUE) + component->duration = descriptor->duration; + return component; + } + } + return NULL; +} + +static MXFStructuralComponent* mxf_resolve_sourceclip(MXFContext *mxf, UID *strong_ref) +{ + MXFStructuralComponent *component = NULL; + + component = mxf_resolve_strong_ref(mxf, strong_ref, AnyType); + if (!component) + return NULL; + switch (component->type) { + case SourceClip: + return component; + case EssenceGroup: + return mxf_resolve_essence_group_choice(mxf, (MXFEssenceGroup*) component); + default: + break; + } + return NULL; +} + static int mxf_parse_physical_source_package(MXFContext *mxf, MXFTrack *source_track, AVStream *st) { - MXFPackage *temp_package = NULL; MXFPackage *physical_package = NULL; MXFTrack *physical_track = NULL; - MXFStructuralComponent *component = NULL; MXFStructuralComponent *sourceclip = NULL; MXFTimecodeComponent *mxf_tc = NULL; int i, j, k; @@ -1471,21 +1565,11 @@ static int mxf_parse_physical_source_package(MXFContext *mxf, MXFTrack *source_t int64_t start_position; for (i = 0; i < source_track->sequence->structural_components_count; i++) { - component = mxf_resolve_strong_ref(mxf, &source_track->sequence->structural_components_refs[i], SourceClip); - if (!component) + sourceclip = mxf_resolve_strong_ref(mxf, &source_track->sequence->structural_components_refs[i], SourceClip); + if (!sourceclip) continue; - for (j = 0; j < mxf->packages_count; j++) { - temp_package = mxf_resolve_strong_ref(mxf, &mxf->packages_refs[j], SourcePackage); - if (!temp_package) - continue; - if (!memcmp(temp_package->package_uid, component->source_package_uid, 16)){ - physical_package = temp_package; - sourceclip = component; - break; - } - } - if (!physical_package) + if (!(physical_package = mxf_resolve_source_package(mxf, sourceclip->source_package_uid))) break; mxf_add_uid_metadata(&st->metadata, "reel_uid", physical_package->package_uid); @@ -1532,7 +1616,6 @@ static int mxf_parse_physical_source_package(MXFContext *mxf, MXFTrack *source_t static int mxf_parse_structural_metadata(MXFContext *mxf) { MXFPackage *material_package = NULL; - MXFPackage *temp_package = NULL; int i, j, k, ret; av_dlog(mxf->fc, "metadata sets count %d\n", mxf->metadata_sets_count); @@ -1599,19 +1682,11 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) /* TODO: handle multiple source clips */ for (j = 0; j < material_track->sequence->structural_components_count; j++) { - component = mxf_resolve_strong_ref(mxf, &material_track->sequence->structural_components_refs[j], SourceClip); + component = mxf_resolve_sourceclip(mxf, &material_track->sequence->structural_components_refs[j]); if (!component) continue; - for (k = 0; k < mxf->packages_count; k++) { - temp_package = mxf_resolve_strong_ref(mxf, &mxf->packages_refs[k], SourcePackage); - if (!temp_package) - continue; - if (!memcmp(temp_package->package_uid, component->source_package_uid, 16)) { - source_package = temp_package; - break; - } - } + source_package = mxf_resolve_source_package(mxf, component->source_package_uid); if (!source_package) { av_dlog(mxf->fc, "material track %d: no corresponding source package found\n", material_track->track_id); break; @@ -1976,6 +2051,7 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = { { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x37,0x00 }, mxf_read_package, sizeof(MXFPackage), SourcePackage }, { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x36,0x00 }, mxf_read_package, sizeof(MXFPackage), MaterialPackage }, { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x0f,0x00 }, mxf_read_sequence, sizeof(MXFSequence), Sequence }, + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x05,0x00 }, mxf_read_essence_group, sizeof(MXFEssenceGroup), EssenceGroup}, { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x11,0x00 }, mxf_read_source_clip, sizeof(MXFStructuralComponent), SourceClip }, { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x44,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), MultipleDescriptor }, { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x42,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* Generic Sound */ @@ -1996,6 +2072,20 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = { { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, NULL, 0, AnyType }, }; +static int mxf_metadataset_init(MXFMetadataSet *ctx, enum MXFMetadataSetType type) +{ + switch (type){ + case MultipleDescriptor: + case Descriptor: + ((MXFDescriptor*)ctx)->pix_fmt = AV_PIX_FMT_NONE; + ((MXFDescriptor*)ctx)->duration = AV_NOPTS_VALUE; + break; + default: + break; + } + return 0; +} + static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadFunc *read_child, int ctx_size, enum MXFMetadataSetType type) { AVIOContext *pb = mxf->fc->pb; @@ -2004,6 +2094,7 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF if (!ctx) return AVERROR(ENOMEM); + mxf_metadataset_init(ctx, type); while (avio_tell(pb) + 4 < klv_end && !avio_feof(pb)) { int ret; int tag = avio_rb16(pb); @@ -2741,6 +2832,9 @@ static int mxf_read_close(AVFormatContext *s) case Sequence: av_freep(&((MXFSequence *)mxf->metadata_sets[i])->structural_components_refs); break; + case EssenceGroup: + av_freep(&((MXFEssenceGroup *)mxf->metadata_sets[i])->structural_components_refs); + break; case SourcePackage: case MaterialPackage: av_freep(&((MXFPackage *)mxf->metadata_sets[i])->tracks_refs);