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;
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;
case 0x1001:
sequence->structural_components_count = avio_rb32(pb);
sequence->structural_components_refs = av_calloc(sequence->structural_components_count, sizeof(UID));
- if (!sequence->structural_components_refs)
+ if (!sequence->structural_components_refs) {
+ sequence->structural_components_count = 0;
return AVERROR(ENOMEM);
+ }
avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */
avio_read(pb, (uint8_t *)sequence->structural_components_refs, sequence->structural_components_count * sizeof(UID));
break;
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) {
+ essence_group->structural_components_count = 0;
+ 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;
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);
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;
{ { 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 },
};
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 MXFDescriptor* mxf_resolve_multidescriptor(MXFContext *mxf, MXFDescriptor *descriptor, int track_id)
+{
+ MXFDescriptor *sub_descriptor = NULL;
+ int i;
+
+ if (!descriptor)
+ return NULL;
+
+ if (descriptor->type == MultipleDescriptor) {
+ for (i = 0; i < descriptor->sub_descriptors_count; i++) {
+ sub_descriptor = mxf_resolve_strong_ref(mxf, &descriptor->sub_descriptors_refs[i], Descriptor);
+
+ if (!sub_descriptor) {
+ av_log(mxf->fc, AV_LOG_ERROR, "could not resolve sub descriptor strong ref\n");
+ continue;
+ }
+ if (sub_descriptor->linked_track_id == track_id) {
+ return sub_descriptor;
+ }
+ }
+ } else if (descriptor->type == Descriptor)
+ return descriptor;
+
+ 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)
+ 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;
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);
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);
/* 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;
}
st->id = source_track->track_id;
st->priv_data = source_track;
- source_track->original_duration = st->duration = component->duration;
+
+ source_package->descriptor = mxf_resolve_strong_ref(mxf, &source_package->descriptor_ref, AnyType);
+ descriptor = mxf_resolve_multidescriptor(mxf, source_package->descriptor, source_track->track_id);
+
+ /* A SourceClip from a EssenceGroup may only be a single frame of essence data. The clips duration is then how many
+ * frames its suppose to repeat for. Descriptor->duration, if present, contains the real duration of the essence data */
+ if (descriptor && descriptor->duration != AV_NOPTS_VALUE)
+ source_track->original_duration = st->duration = FFMIN(descriptor->duration, component->duration);
+ else
+ source_track->original_duration = st->duration = component->duration;
+
if (st->duration == -1)
st->duration = AV_NOPTS_VALUE;
st->start_time = component->start_position;
codec_ul = mxf_get_codec_ul(ff_mxf_data_definition_uls, &source_track->sequence->data_definition_ul);
st->codec->codec_type = codec_ul->id;
- source_package->descriptor = mxf_resolve_strong_ref(mxf, &source_package->descriptor_ref, AnyType);
- if (source_package->descriptor) {
- if (source_package->descriptor->type == MultipleDescriptor) {
- for (j = 0; j < source_package->descriptor->sub_descriptors_count; j++) {
- MXFDescriptor *sub_descriptor = mxf_resolve_strong_ref(mxf, &source_package->descriptor->sub_descriptors_refs[j], Descriptor);
-
- if (!sub_descriptor) {
- av_log(mxf->fc, AV_LOG_ERROR, "could not resolve sub descriptor strong ref\n");
- continue;
- }
- if (sub_descriptor->linked_track_id == source_track->track_id) {
- descriptor = sub_descriptor;
- break;
- }
- }
- } else if (source_package->descriptor->type == Descriptor)
- descriptor = source_package->descriptor;
- }
if (!descriptor) {
av_log(mxf->fc, AV_LOG_INFO, "source track %d: stream %d, no descriptor found\n", source_track->track_id, st->index);
continue;
{ { 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 */
{ { 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;
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);
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);