Le ven. 17 déc. 2021 à 19:12, Marton Balint <c...@passwd.hu> a écrit :
> > > On Fri, 17 Dec 2021, Marc-Antoine ARNAUD wrote: > > > Hi all, > > > > Can I have an update on this patch submission ? > > Is something required to be done before it can be merged ? > > New channel layout API is on its way, which makes in-demuxer channel > reordering uneeded. Therefore the reordering option should not be added > as it is in this patch. I can rework the patch after the channel layout > API is in. (should happen in a couple of weeks at most). > > Regards, > Marton > So it will happen only after the release 5 of FFMpeg right ? Is it possible to merge it, and we can rework it after the new API is released ? Patches are related to IMF (new format) patches, and if FFmpeg can accept IMF without MCA support it will generate a lot of errors in audio mapping. So even if it's not performant for now, is it possible to imagine to merge patches and rework after ? Thanks a lot, Marc-Antoine > > > > > Thanks you, > > Marc-Antoine > > > > > > Le ven. 3 déc. 2021 à 10:57, Marc-Antoine Arnaud > > <marc-antoine.arn...@luminvent.com> a écrit : > >> > >> --- > >> doc/demuxers.texi | 10 ++ > >> libavformat/mxf.h | 3 + > >> libavformat/mxfdec.c | 335 +++++++++++++++++++++++++++++++++++++++++- > >> libavformat/version.h | 2 +- > >> 4 files changed, 343 insertions(+), 7 deletions(-) > >> > >> diff --git a/doc/demuxers.texi b/doc/demuxers.texi > >> index cab8a7072c..23b6753602 100644 > >> --- a/doc/demuxers.texi > >> +++ b/doc/demuxers.texi > >> @@ -770,6 +770,16 @@ MJPEG stream. Turning this option on by setting it > to 1 will result in a stricte > >> of the boundary value. > >> @end table > >> > >> +@section mxf > >> + > >> +MXF demuxer. > >> + > >> +@table @option > >> + > >> +@item -skip_audio_reordering @var{bool} > >> +This option will disable the audio reordering based on Multi-Channel > Audio (MCA) labelling (SMPTE ST-377-4). > >> +@end table > >> + > >> @section rawvideo > >> > >> Raw video demuxer. > >> diff --git a/libavformat/mxf.h b/libavformat/mxf.h > >> index fe9c52732c..d53a16df51 100644 > >> --- a/libavformat/mxf.h > >> +++ b/libavformat/mxf.h > >> @@ -50,6 +50,9 @@ enum MXFMetadataSetType { > >> TaggedValue, > >> TapeDescriptor, > >> AVCSubDescriptor, > >> + AudioChannelLabelSubDescriptor, > >> + SoundfieldGroupLabelSubDescriptor, > >> + GroupOfSoundfieldGroupsLabelSubDescriptor, > >> }; > >> > >> enum MXFFrameLayout { > >> diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c > >> index af9d33f796..6e1da75542 100644 > >> --- a/libavformat/mxfdec.c > >> +++ b/libavformat/mxfdec.c > >> @@ -51,11 +51,14 @@ > >> #include "libavutil/mastering_display_metadata.h" > >> #include "libavutil/mathematics.h" > >> #include "libavcodec/bytestream.h" > >> +#include "libavcodec/internal.h" > >> +#include "libavutil/channel_layout.h" > >> #include "libavutil/intreadwrite.h" > >> #include "libavutil/parseutils.h" > >> #include "libavutil/timecode.h" > >> #include "libavutil/opt.h" > >> #include "avformat.h" > >> +#include "avlanguage.h" > >> #include "internal.h" > >> #include "mxf.h" > >> > >> @@ -177,6 +180,8 @@ typedef struct { > >> int body_sid; > >> MXFWrappingScheme wrapping; > >> int edit_units_per_packet; /* how many edit units to read at a > time (PCM, ClipWrapped) */ > >> + int require_reordering; > >> + int channel_ordering[FF_SANE_NB_CHANNELS]; > >> } MXFTrack; > >> > >> typedef struct MXFDescriptor { > >> @@ -205,6 +210,8 @@ typedef struct MXFDescriptor { > >> unsigned int vert_subsampling; > >> UID *file_descriptors_refs; > >> int file_descriptors_count; > >> + UID *sub_descriptors_refs; > >> + int sub_descriptors_count; > >> int linked_track_id; > >> uint8_t *extradata; > >> int extradata_size; > >> @@ -217,6 +224,18 @@ typedef struct MXFDescriptor { > >> size_t coll_size; > >> } MXFDescriptor; > >> > >> +typedef struct MXFMCASubDescriptor { > >> + MXFMetadataSet meta; > >> + UID uid; > >> + UID mca_link_id; > >> + UID soundfield_group_link_id; > >> + UID *group_of_soundfield_groups_link_id_refs; > >> + int group_of_soundfield_groups_link_id_count; > >> + UID mca_label_dictionary_id; > >> + int mca_channel_id; > >> + char *language; > >> +} MXFMCASubDescriptor; > >> + > >> typedef struct MXFIndexTableSegment { > >> MXFMetadataSet meta; > >> int edit_unit_byte_count; > >> @@ -290,6 +309,7 @@ typedef struct MXFContext { > >> int nb_index_tables; > >> MXFIndexTable *index_tables; > >> int eia608_extract; > >> + int skip_audio_reordering; > >> } MXFContext; > >> > >> /* NOTE: klv_offset is not set (-1) for local keys */ > >> @@ -311,6 +331,7 @@ static const uint8_t mxf_system_item_key_cp[] > = { 0x06,0x0e,0x2b,0x > >> static const uint8_t mxf_system_item_key_gc[] = { > 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x03,0x01,0x14 }; > >> static const uint8_t mxf_klv_key[] = { > 0x06,0x0e,0x2b,0x34 }; > >> static const uint8_t mxf_apple_coll_prefix[] = { > 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x0e,0x20,0x04,0x01,0x05,0x03,0x01 > }; > >> + > >> /* complete keys to match */ > >> static const uint8_t mxf_crypto_source_container_ul[] = { > 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x02,0x02,0x00,0x00,0x00 > }; > >> static const uint8_t mxf_encrypted_triplet_key[] = { > 0x06,0x0e,0x2b,0x34,0x02,0x04,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x7e,0x01,0x00 > }; > >> @@ -323,6 +344,17 @@ static const uint8_t mxf_indirect_value_utf16be[] > = { 0x42,0x01,0x10,0x > >> static const uint8_t mxf_apple_coll_max_cll[] = { > 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x0e,0x20,0x04,0x01,0x05,0x03,0x01,0x01 > }; > >> static const uint8_t mxf_apple_coll_max_fall[] = { > 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x0e,0x20,0x04,0x01,0x05,0x03,0x01,0x02 > }; > >> > >> +static const uint8_t mxf_mca_label_dictionary_id[] = { > 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x01,0x03,0x07,0x01,0x01,0x00,0x00,0x00 > }; > >> +static const uint8_t mxf_mca_tag_symbol[] = { > 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x01,0x03,0x07,0x01,0x02,0x00,0x00,0x00 > }; > >> +static const uint8_t mxf_mca_tag_name[] = { > 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x01,0x03,0x07,0x01,0x03,0x00,0x00,0x00 > }; > >> +static const uint8_t mxf_group_of_soundfield_groups_link_id[] = { > 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x01,0x03,0x07,0x01,0x04,0x00,0x00,0x00 > }; > >> +static const uint8_t mxf_mca_link_id[] = { > 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x01,0x03,0x07,0x01,0x05,0x00,0x00,0x00 > }; > >> +static const uint8_t mxf_mca_channel_id[] = { > 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x01,0x03,0x04,0x0a,0x00,0x00,0x00,0x00 > }; > >> +static const uint8_t mxf_soundfield_group_link_id[] = { > 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x01,0x03,0x07,0x01,0x06,0x00,0x00,0x00 > }; > >> +static const uint8_t mxf_mca_rfc5646_spoken_language[] = { > 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0d,0x03,0x01,0x01,0x02,0x03,0x15,0x00,0x00 > }; > >> + > >> +static const uint8_t mxf_sub_descriptor[] = { > 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x04,0x06,0x10,0x00,0x00 > }; > >> + > >> static const uint8_t mxf_mastering_display_prefix[13] = { > FF_MXF_MasteringDisplay_PREFIX }; > >> static const uint8_t mxf_mastering_display_uls[4][16] = { > >> FF_MXF_MasteringDisplayPrimaries, > >> @@ -343,6 +375,13 @@ static void mxf_free_metadataset(MXFMetadataSet > **ctx, int freectx) > >> av_freep(&((MXFDescriptor *)*ctx)->mastering); > >> av_freep(&((MXFDescriptor *)*ctx)->coll); > >> av_freep(&((MXFDescriptor *)*ctx)->file_descriptors_refs); > >> + av_freep(&((MXFDescriptor *)*ctx)->sub_descriptors_refs); > >> + break; > >> + case AudioChannelLabelSubDescriptor: > >> + case SoundfieldGroupLabelSubDescriptor: > >> + case GroupOfSoundfieldGroupsLabelSubDescriptor: > >> + av_freep(&((MXFMCASubDescriptor *)*ctx)->language); > >> + av_freep(&((MXFMCASubDescriptor > *)*ctx)->group_of_soundfield_groups_link_id_refs); > >> break; > >> case Sequence: > >> av_freep(&((MXFSequence *)*ctx)->structural_components_refs); > >> @@ -906,6 +945,30 @@ static int mxf_read_strong_ref_array(AVIOContext > *pb, UID **refs, int *count) > >> return 0; > >> } > >> > >> +static inline int mxf_read_us_ascii_string(AVIOContext *pb, int size, > char** str) > >> +{ > >> + int ret; > >> + size_t buf_size; > >> + > >> + if (size < 0 || size > INT_MAX - 1) > >> + return AVERROR(EINVAL); > >> + > >> + buf_size = size + 1; > >> + av_free(*str); > >> + *str = av_malloc(buf_size); > >> + if (!*str) > >> + return AVERROR(ENOMEM); > >> + > >> + ret = avio_get_str(pb, size, *str, buf_size); > >> + > >> + if (ret < 0) { > >> + av_freep(str); > >> + return ret; > >> + } > >> + > >> + return ret; > >> +} > >> + > >> static inline int mxf_read_utf16_string(AVIOContext *pb, int size, > char** str, int be) > >> { > >> int ret; > >> @@ -1360,11 +1423,40 @@ static int mxf_read_generic_descriptor(void > *arg, AVIOContext *pb, int tag, int > >> descriptor->coll->MaxFALL = avio_rb16(pb); > >> } > >> } > >> + > >> + if (IS_KLV_KEY(uid, mxf_sub_descriptor)) > >> + return mxf_read_strong_ref_array(pb, > &descriptor->sub_descriptors_refs, &descriptor->sub_descriptors_count); > >> + > >> break; > >> } > >> return 0; > >> } > >> > >> +static int mxf_read_mca_sub_descriptor(void *arg, AVIOContext *pb, int > tag, int size, UID uid, int64_t klv_offset) > >> +{ > >> + MXFMCASubDescriptor *mca_sub_descriptor = arg; > >> + > >> + if (IS_KLV_KEY(uid, mxf_mca_label_dictionary_id)) > >> + avio_read(pb, mca_sub_descriptor->mca_label_dictionary_id, 16); > >> + > >> + if (IS_KLV_KEY(uid, mxf_mca_link_id)) > >> + avio_read(pb, mca_sub_descriptor->mca_link_id, 16); > >> + > >> + if (IS_KLV_KEY(uid, mxf_soundfield_group_link_id)) > >> + avio_read(pb, mca_sub_descriptor->soundfield_group_link_id, > 16); > >> + > >> + if (IS_KLV_KEY(uid, mxf_group_of_soundfield_groups_link_id)) > >> + return mxf_read_strong_ref_array(pb, > &mca_sub_descriptor->group_of_soundfield_groups_link_id_refs, > &mca_sub_descriptor->group_of_soundfield_groups_link_id_count); > >> + > >> + if (IS_KLV_KEY(uid, mxf_mca_channel_id)) > >> + mca_sub_descriptor->mca_channel_id = avio_rb32(pb); > >> + > >> + if (IS_KLV_KEY(uid, mxf_mca_rfc5646_spoken_language)) > >> + return mxf_read_us_ascii_string(pb, size, > &mca_sub_descriptor->language); > >> + > >> + return 0; > >> +} > >> + > >> static int mxf_read_indirect_value(void *arg, AVIOContext *pb, int > size) > >> { > >> MXFTaggedValue *tagged_value = arg; > >> @@ -1494,6 +1586,50 @@ static const MXFCodecUL > mxf_data_essence_container_uls[] = { > >> { { > 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 > }, 0, AV_CODEC_ID_NONE }, > >> }; > >> > >> +typedef struct MXFChannelOrderingUL { > >> + UID uid; > >> + uint64_t layout_mask; > >> + enum AVAudioServiceType service_type; > >> +} MXFChannelOrderingUL; > >> + > >> +static const MXFChannelOrderingUL mxf_channel_ordering[] = { > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00 > }, AV_CH_FRONT_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x02,0x00,0x00,0x00,0x00 > }, AV_CH_FRONT_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x03,0x00,0x00,0x00,0x00 > }, AV_CH_FRONT_CENTER, AV_AUDIO_SERVICE_TYPE_MAIN }, // Center > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x04,0x00,0x00,0x00,0x00 > }, AV_CH_LOW_FREQUENCY, AV_AUDIO_SERVICE_TYPE_MAIN }, // Low > Frequency Effects > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x05,0x00,0x00,0x00,0x00 > }, AV_CH_SIDE_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left > Surround > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x06,0x00,0x00,0x00,0x00 > }, AV_CH_SIDE_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right > Surround > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x07,0x00,0x00,0x00,0x00 > }, AV_CH_SIDE_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Side > Surround > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x08,0x00,0x00,0x00,0x00 > }, AV_CH_SIDE_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Side > Surround > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x09,0x00,0x00,0x00,0x00 > }, AV_CH_BACK_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Rear > Surround > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0a,0x00,0x00,0x00,0x00 > }, AV_CH_BACK_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Rear > Surround > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0b,0x00,0x00,0x00,0x00 > }, AV_CH_FRONT_LEFT_OF_CENTER, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Center > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0c,0x00,0x00,0x00,0x00 > }, AV_CH_FRONT_RIGHT_OF_CENTER, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right > Center > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0d,0x00,0x00,0x00,0x00 > }, AV_CH_BACK_CENTER, AV_AUDIO_SERVICE_TYPE_MAIN }, // Center > Surround > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0e,0x00,0x00,0x00,0x00 > }, AV_CH_FRONT_CENTER, AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED }, > // Hearing impaired audio channel > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0f,0x00,0x00,0x00,0x00 > }, AV_CH_FRONT_CENTER, AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED }, > // Visually impaired narrative audio channel > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x01,0x00,0x00 > }, AV_CH_TOP_FRONT_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Height > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x02,0x00,0x00 > }, AV_CH_TOP_FRONT_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right > Height > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x03,0x00,0x00 > }, AV_CH_TOP_FRONT_CENTER, AV_AUDIO_SERVICE_TYPE_MAIN }, // Center > Height > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x04,0x00,0x00 > }, AV_CH_TOP_SIDE_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left > Surround Height > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x05,0x00,0x00 > }, AV_CH_TOP_SIDE_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right > Surround Height > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x06,0x00,0x00 > }, AV_CH_TOP_SIDE_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Side > Surround Height > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x07,0x00,0x00 > }, AV_CH_TOP_SIDE_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Side > Surround Height > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x08,0x00,0x00 > }, AV_CH_TOP_BACK_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Rear > Surround Height > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x09,0x00,0x00 > }, AV_CH_TOP_BACK_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Rear > Surround Height > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x0a,0x00,0x00 > }, AV_CH_TOP_SIDE_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Top > Surround > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x0b,0x00,0x00 > }, AV_CH_TOP_SIDE_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Top > Surround > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x0c,0x00,0x00 > }, AV_CH_TOP_CENTER, AV_AUDIO_SERVICE_TYPE_MAIN }, // Top > Surround > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x0d,0x00,0x00 > }, AV_CH_LOW_FREQUENCY, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Front > Subwoofer > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x0e,0x00,0x00 > }, AV_CH_LOW_FREQUENCY_2, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right > Front Subwoofer > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x0f,0x00,0x00 > }, AV_CH_TOP_BACK_CENTER, AV_AUDIO_SERVICE_TYPE_MAIN }, // Center > Rear Height > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x10,0x00,0x00 > }, AV_CH_BACK_CENTER, AV_AUDIO_SERVICE_TYPE_MAIN }, // Center Rear > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x11,0x00,0x00 > }, AV_CH_BOTTOM_FRONT_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Below > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x12,0x00,0x00 > }, AV_CH_BOTTOM_FRONT_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Below > >> + { { > 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x13,0x00,0x00 > }, AV_CH_BOTTOM_FRONT_CENTER, AV_AUDIO_SERVICE_TYPE_MAIN }, // Center > Below > >> + { { > 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 > }, 0, AV_AUDIO_SERVICE_TYPE_NB }, > >> +}; > >> + > >> static MXFWrappingScheme mxf_get_wrapping_kind(UID > *essence_container_ul) > >> { > >> int val; > >> @@ -2292,6 +2428,156 @@ static enum AVColorRange > mxf_get_color_range(MXFContext *mxf, MXFDescriptor *des > >> return AVCOL_RANGE_UNSPECIFIED; > >> } > >> > >> +static int is_pcm(enum AVCodecID codec_id) > >> +{ > >> + /* we only care about "normal" PCM codecs until we get samples */ > >> + return codec_id >= AV_CODEC_ID_PCM_S16LE && codec_id < > AV_CODEC_ID_PCM_S24DAUD; > >> +} > >> + > >> +static int set_language(AVFormatContext *s, const char *rfc5646, > AVDictionary **met) > >> +{ > >> + // language abbr should contain at least 2 chars > >> + if (rfc5646 && strlen(rfc5646) > 1) { > >> + char primary_tag[4] = > >> + {rfc5646[0], rfc5646[1], rfc5646[2] != '-' ? rfc5646[2] : > '\0', '\0'}; > >> + > >> + const char *iso6392 = ff_convert_lang_to(primary_tag, > >> + > AV_LANG_ISO639_2_BIBL); > >> + if (iso6392) > >> + return(av_dict_set(met, "language", iso6392, 0)); > >> + } > >> + return 0; > >> +} > >> + > >> +static MXFMCASubDescriptor *find_mca_link_id(MXFContext *mxf, enum > MXFMetadataSetType type, UID *mca_link_id) > >> +{ > >> + for (int k = 0; k < mxf->metadata_sets_count; k++) { > >> + MXFMCASubDescriptor *group = > (MXFMCASubDescriptor*)mxf->metadata_sets[k]; > >> + if (group->meta.type == type && !memcmp(&group->mca_link_id, > mca_link_id, 16)) > >> + return group; > >> + } > >> + return NULL; > >> +} > >> + > >> +static int parse_mca_labels(MXFContext *mxf, MXFTrack *source_track, > MXFDescriptor *descriptor, AVStream *st) > >> +{ > >> + uint64_t routing[FF_SANE_NB_CHANNELS] = {0}; > >> + char *language = NULL; > >> + int ambigous_language = 0; > >> + enum AVAudioServiceType service_type = AV_AUDIO_SERVICE_TYPE_NB; > >> + int ambigous_service_type = 0; > >> + int has_channel_label = 0; > >> + > >> + for (int i = 0; i < descriptor->sub_descriptors_count; i++) { > >> + char *channel_language; > >> + > >> + MXFMCASubDescriptor *label = mxf_resolve_strong_ref(mxf, > &descriptor->sub_descriptors_refs[i], AudioChannelLabelSubDescriptor); > >> + if (label == NULL) > >> + continue; > >> + > >> + has_channel_label = 1; > >> + for (const MXFChannelOrderingUL* channel_ordering = > mxf_channel_ordering; channel_ordering->uid[0]; channel_ordering++) { > >> + if (IS_KLV_KEY(channel_ordering->uid, > label->mca_label_dictionary_id)) { > >> + int target_channel = label->mca_channel_id; > >> + if (target_channel == 0 && descriptor->channels == 1) > >> + target_channel = 1; > >> + if (target_channel <= 0 || target_channel > > descriptor->channels) { > >> + av_log(mxf->fc, AV_LOG_ERROR, > "AudioChannelLabelSubDescriptor has invalid MCA channel ID %d\n", > target_channel); > >> + return AVERROR_INVALIDDATA; > >> + } > >> + routing[target_channel - 1] = > channel_ordering->layout_mask; > >> + if (service_type == AV_AUDIO_SERVICE_TYPE_NB) > >> + service_type = channel_ordering->service_type; > >> + else if (service_type != > channel_ordering->service_type) > >> + ambigous_service_type = 1; > >> + break; > >> + } > >> + } > >> + > >> + channel_language = label->language; > >> + if (!channel_language) { > >> + MXFMCASubDescriptor *group = find_mca_link_id(mxf, > SoundfieldGroupLabelSubDescriptor, &label->soundfield_group_link_id); > >> + if (group) { > >> + channel_language = group->language; > >> + if (!channel_language && > group->group_of_soundfield_groups_link_id_count) { > >> + MXFMCASubDescriptor *supergroup = > find_mca_link_id(mxf, GroupOfSoundfieldGroupsLabelSubDescriptor, > >> + > group->group_of_soundfield_groups_link_id_refs); > >> + if (supergroup) > >> + channel_language = supergroup->language; > >> + } > >> + } > >> + } > >> + if (channel_language) { > >> + if (language && strcmp(language, channel_language)) > >> + ambigous_language = 1; > >> + else > >> + language = channel_language; > >> + } > >> + } > >> + > >> + if (language && !ambigous_language) { > >> + int ret = set_language(mxf->fc, language, &st->metadata); > >> + if (ret < 0) > >> + return ret; > >> + } > >> + > >> + if (service_type != AV_AUDIO_SERVICE_TYPE_NB && service_type != > AV_AUDIO_SERVICE_TYPE_MAIN && !ambigous_service_type) { > >> + enum AVAudioServiceType *ast; > >> + uint8_t* side_data = av_stream_new_side_data(st, > AV_PKT_DATA_AUDIO_SERVICE_TYPE, sizeof(*ast)); > >> + if (!side_data) > >> + return AVERROR(ENOMEM); > >> + ast = (enum AVAudioServiceType*)side_data; > >> + *ast = service_type; > >> + } > >> + > >> + if (has_channel_label) { > >> + uint64_t channel_layout = 0; > >> + int require_reorder = 0; > >> + > >> + for (int i = 0; i < descriptor->channels; i++) { > >> + if (!routing[i]) { > >> + av_log(mxf->fc, AV_LOG_WARNING, "Designation of audio > channel %d in stream #%d is unknown or unsupported, " > >> + "falling back to > unknown channel layout\n", st->index, i); > >> + return 0; > >> + } > >> + if (channel_layout & routing[i]) { > >> + av_log(mxf->fc, AV_LOG_WARNING, "%s audio channel is > used multiple times in stream #%d, " > >> + "falling back to > unknown channel layout\n", > >> + > av_get_channel_name(routing[i]), st->index); > >> + return 0; > >> + } > >> + if (routing[i] < channel_layout) > >> + require_reorder = 1; > >> + channel_layout |= routing[i]; > >> + } > >> + > >> + av_assert0(descriptor->channels == > av_get_channel_layout_nb_channels(channel_layout)); > >> + > >> + if (require_reorder) { > >> + if (mxf->skip_audio_reordering) > >> + return 0; > >> + if (!is_pcm(st->codecpar->codec_id)) { > >> + av_log(mxf->fc, AV_LOG_WARNING, "Audio channel > reordering for stream #%d is not supported because it is using a non-PCM > codec, " > >> + "falling back to > unknown channel layout\n", st->index); > >> + return 0; > >> + } > >> + av_log(mxf->fc, AV_LOG_VERBOSE, "MCA mapping for stream > #%d: ", st->index); > >> + for (int j = 0; j < descriptor->channels; j++) { > >> + int reordered_channel = > av_get_channel_layout_channel_index(channel_layout, routing[j]); > >> + av_assert0(reordered_channel >= 0 && reordered_channel > < descriptor->channels); > >> + source_track->channel_ordering[j] = reordered_channel; > >> + av_log(mxf->fc, AV_LOG_VERBOSE, "%s%s: %d->%d", j ? ", > " : "", av_get_channel_name(routing[j]), j, reordered_channel); > >> + } > >> + av_log(mxf->fc, AV_LOG_VERBOSE, "\n"); > >> + source_track->require_reordering = 1; > >> + } > >> + > >> + st->codecpar->channel_layout = channel_layout; > >> + } > >> + > >> + return 0; > >> +} > >> + > >> static int mxf_parse_structural_metadata(MXFContext *mxf) > >> { > >> MXFPackage *material_package = NULL; > >> @@ -2688,6 +2974,15 @@ static int > mxf_parse_structural_metadata(MXFContext *mxf) > >> sti->need_parsing = AVSTREAM_PARSE_FULL; > >> } > >> st->codecpar->bits_per_coded_sample = > av_get_bits_per_sample(st->codecpar->codec_id); > >> + > >> + if (descriptor->channels <= 0 || descriptor->channels >= > FF_SANE_NB_CHANNELS) { > >> + av_log(mxf->fc, AV_LOG_ERROR, "Invalid number of > channels %d, must be less than %d\n", descriptor->channels, > FF_SANE_NB_CHANNELS); > >> + return AVERROR_INVALIDDATA; > >> + } > >> + > >> + ret = parse_mca_labels(mxf, source_track, descriptor, st); > >> + if (ret < 0) > >> + return ret; > >> } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) { > >> enum AVMediaType type; > >> container_ul = > mxf_get_codec_ul(mxf_data_essence_container_uls, essence_container_ul); > >> @@ -2888,6 +3183,9 @@ static const MXFMetadataReadTableEntry > mxf_metadata_read_table[] = { > >> { { > 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x5c,0x00 > }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* > VANC/VBI - SMPTE 436M */ > >> { { > 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x5e,0x00 > }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* > MPEG2AudioDescriptor */ > >> { { > 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x64,0x00 > }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* DC > Timed Text Descriptor */ > >> + { { > 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x6b,0x00 > }, mxf_read_mca_sub_descriptor, sizeof(MXFMCASubDescriptor), > AudioChannelLabelSubDescriptor }, > >> + { { > 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x6c,0x00 > }, mxf_read_mca_sub_descriptor, sizeof(MXFMCASubDescriptor), > SoundfieldGroupLabelSubDescriptor }, > >> + { { > 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x6d,0x00 > }, mxf_read_mca_sub_descriptor, sizeof(MXFMCASubDescriptor), > GroupOfSoundfieldGroupsLabelSubDescriptor }, > >> { { > 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3A,0x00 > }, mxf_read_track, sizeof(MXFTrack), Track }, /* Static Track */ > >> { { > 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3B,0x00 > }, mxf_read_track, sizeof(MXFTrack), Track }, /* Generic Track */ > >> { { > 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x14,0x00 > }, mxf_read_timecode_component, sizeof(MXFTimecodeComponent), > TimecodeComponent }, > >> @@ -3187,12 +3485,6 @@ static void > mxf_compute_essence_containers(AVFormatContext *s) > >> } > >> } > >> > >> -static int is_pcm(enum AVCodecID codec_id) > >> -{ > >> - /* we only care about "normal" PCM codecs until we get samples */ > >> - return codec_id >= AV_CODEC_ID_PCM_S16LE && codec_id < > AV_CODEC_ID_PCM_S24DAUD; > >> -} > >> - > >> static MXFIndexTable *mxf_find_index_table(MXFContext *mxf, int > index_sid) > >> { > >> int i; > >> @@ -3619,6 +3911,25 @@ static int mxf_set_pts(MXFContext *mxf, AVStream > *st, AVPacket *pkt) > >> return 0; > >> } > >> > >> +static int mxf_audio_remapping(int* channel_ordering, uint8_t* data, > int size, int sample_size, int channels) > >> +{ > >> + int sample_offset = channels * sample_size; > >> + int number_of_samples = size / sample_offset; > >> + uint8_t tmp[FF_SANE_NB_CHANNELS * 4]; > >> + uint8_t* data_ptr = data; > >> + > >> + for (int sample = 0; sample < number_of_samples; ++sample) { > >> + memcpy(tmp, data_ptr, sample_offset); > >> + > >> + for (int channel = 0; channel < channels; ++channel) { > >> + memcpy(&data_ptr[sample_size * channel_ordering[channel]], > &tmp[sample_size * channel], sample_size); > >> + } > >> + > >> + data_ptr += sample_offset; > >> + } > >> + return 0; > >> +} > >> + > >> static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) > >> { > >> KLVPacket klv; > >> @@ -3733,6 +4044,15 @@ static int mxf_read_packet(AVFormatContext *s, > AVPacket *pkt) > >> return ret; > >> } > >> > >> + // for audio, process audio remapping if MCA label > requires it > >> + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && > track->require_reordering) { > >> + int byte_per_sample = > st->codecpar->bits_per_coded_sample / 8; > >> + ret = mxf_audio_remapping(track->channel_ordering, > pkt->data, pkt->size, byte_per_sample, st->codecpar->channels); > >> + if (ret < 0) { > >> + return ret; > >> + } > >> + } > >> + > >> /* seek for truncated packets */ > >> avio_seek(s->pb, klv.next_klv, SEEK_SET); > >> > >> @@ -3920,6 +4240,9 @@ static const AVOption options[] = { > >> { "eia608_extract", "extract eia 608 captions from s436m track", > >> offsetof(MXFContext, eia608_extract), AV_OPT_TYPE_BOOL, {.i64 = > 0}, 0, 1, > >> AV_OPT_FLAG_DECODING_PARAM }, > >> + { "skip_audio_reordering", "skip audio reordering based on > Multi-Channel Audio labelling", > >> + offsetof(MXFContext, skip_audio_reordering), AV_OPT_TYPE_BOOL, > {.i64 = 0}, 0, 1, > >> + AV_OPT_FLAG_DECODING_PARAM }, > >> { NULL }, > >> }; > >> > >> diff --git a/libavformat/version.h b/libavformat/version.h > >> index 0705ee4112..21ca6ed096 100644 > >> --- a/libavformat/version.h > >> +++ b/libavformat/version.h > >> @@ -33,7 +33,7 @@ > >> // Also please add any ticket numbers that you believe might be > affected here > >> #define LIBAVFORMAT_VERSION_MAJOR 59 > >> #define LIBAVFORMAT_VERSION_MINOR 9 > >> -#define LIBAVFORMAT_VERSION_MICRO 102 > >> +#define LIBAVFORMAT_VERSION_MICRO 103 > >> > >> #define LIBAVFORMAT_VERSION_INT > AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ > >> > LIBAVFORMAT_VERSION_MINOR, \ > >> -- > >> 2.33.1 > >> > > > > > > -- > > Marc-Antoine ARNAUD > > CEO & Founder > > > > mobile: +33 6 84 71 84 45 > > email: arnaud.marc-anto...@luminvent.com > > website: luminvent.com > > _______________________________________________ > > ffmpeg-devel mailing list > > ffmpeg-devel@ffmpeg.org > > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > > > To unsubscribe, visit link above, or email > > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". > -- Marc-Antoine ARNAUD CEO & Founder mobile: +33 6 84 71 84 45 <+33+6+84+71+84+45> email: arnaud <arnaud.marc-anto...@luminvent.com> .marc-anto...@luminvent.com <arnaud.marc-anto...@luminvent.com> <arnaud.marc-anto...@luminvent.com> website: luminvent.com _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".