From: Marton Balint <cus@passwd.hu> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org> Subject: Re: [FFmpeg-devel] [PATCH 1/2] avformat/mxf: support MCA audio information Date: Fri, 17 Dec 2021 19:12:17 +0100 (CET) Message-ID: <c6d77eac-fd53-3e5a-6756-63c6ac8416@passwd.hu> (raw) In-Reply-To: <CA+NTGJ02x8nMk+4ApNdaH1_k1PbLoRTL=jioNdAFpS_cGByQTQ@mail.gmail.com> 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 > > Thanks you, > Marc-Antoine > > > Le ven. 3 déc. 2021 à 10:57, Marc-Antoine Arnaud > <marc-antoine.arnaud@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-antoine@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-request@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-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2021-12-17 18:12 UTC|newest] Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top [not found] <20211203095742.16108-1-marc-antoine.arnaud@luminvent.com> 2021-12-17 16:58 ` Marc-Antoine ARNAUD 2021-12-17 18:12 ` Marton Balint [this message] 2021-12-21 10:44 ` Marc-Antoine ARNAUD 2021-12-21 13:53 ` Tomas Härdin 2021-12-21 20:24 ` Marton Balint 2021-12-22 12:37 ` Tomas Härdin 2021-12-22 15:53 ` Pierre-Anthony Lemieux 2022-01-01 19:32 ` Marton Balint 2022-01-01 23:15 ` Pierre-Anthony Lemieux
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=c6d77eac-fd53-3e5a-6756-63c6ac8416@passwd.hu \ --to=cus@passwd.hu \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git