[FFmpeg-devel] [PATCH 1/2] avformat/mxf: support MCA audio information
Marc-Antoine ARNAUD
marc-antoine.arnaud at luminvent.com
Tue Dec 21 12:44:27 EET 2021
Le ven. 17 déc. 2021 à 19:12, Marton Balint <cus at 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.arnaud at 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
> >>
> >> + at section mxf
> >> +
> >> +MXF demuxer.
> >> +
> >> + at table @option
> >> +
> >> + at item -skip_audio_reordering @var{bool}
> >> +This option will disable the audio reordering based on Multi-Channel
> Audio (MCA) labelling (SMPTE ST-377-4).
> >> + at 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 at luminvent.com
> > website: luminvent.com
> > _______________________________________________
> > ffmpeg-devel mailing list
> > ffmpeg-devel at ffmpeg.org
> > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> >
> > To unsubscribe, visit link above, or email
> > ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at 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-antoine at luminvent.com>
.marc-antoine at luminvent.com <arnaud.marc-antoine at luminvent.com>
<arnaud.marc-antoine at luminvent.com>
website: luminvent.com
More information about the ffmpeg-devel
mailing list