[FFmpeg-devel] [PATCH] avformat/mxf: support MCA audio information
Tomas Härdin
tjoppen at acc.umu.se
Wed Aug 18 16:16:57 EEST 2021
tor 2021-08-12 klockan 14:38 +0200 skrev Marc-Antoine Arnaud:
@@ -177,6 +179,7 @@ typedef struct {
int body_sid;
MXFWrappingScheme wrapping;
int edit_units_per_packet; /* how many edit units to read at a
time (PCM, ClipWrapped) */
+ int* channel_ordering;
Is there a maximum number of channels? If so then this should be made
constant size.
} MXFTrack;
typedef struct MXFDescriptor {
@@ -217,6 +220,15 @@ typedef struct MXFDescriptor {
size_t coll_size;
} MXFDescriptor;
+typedef struct MXFMCASubDescriptor {
+ MXFMetadataSet meta;
+ UID uid;
+ UID mca_link_id;
+ UID mca_group_link_id;
+ UID mca_label_dictionnary_id;
+ char *language;
Language doesn't seem to be used
+} MXFMCASubDescriptor;
+static inline int mxf_read_us_ascii_string(AVIOContext *pb, int size,
char** str)
+{
+ int ret;
+ size_t buf_size;
+
+ if (size < 0)
+ return AVERROR(EINVAL);
+
+ buf_size = size + 1;
+ av_free(*str);
+ *str = av_malloc(buf_size);
av_realloc()
static int mxf_parse_structural_metadata(MXFContext *mxf)
{
MXFPackage *material_package = NULL;
@@ -2322,7 +2461,10 @@ static int
mxf_parse_structural_metadata(MXFContext *mxf)
const MXFCodecUL *pix_fmt_ul = NULL;
AVStream *st;
AVTimecode tc;
+ enum AVAudioServiceType *ast;
+ int* channel_ordering;
int flags;
+ int current_channel;
if (!(material_track = mxf_resolve_strong_ref(mxf,
&material_package->tracks_refs[i], Track))) {
av_log(mxf->fc, AV_LOG_ERROR, "could not resolve material
track strong ref\n");
@@ -2681,6 +2823,185 @@ static int
mxf_parse_structural_metadata(MXFContext *mxf)
st->internal->need_parsing = AVSTREAM_PARSE_FULL;
}
st->codecpar->bits_per_coded_sample =
av_get_bits_per_sample(st->codecpar->codec_id);
+
+ current_channel = 0;
+
+ channel_ordering = av_mallocz_array(descriptor->channels,
sizeof(int));
+
+ for (j = 0; j < descriptor->sub_descriptors_count; j++) {
+ MXFMCASubDescriptor *mca_sub_descriptor =
mxf_resolve_strong_ref(mxf, &descriptor->sub_descriptors_refs[j],
MCASubDescriptor);
+ if (mca_sub_descriptor == NULL) {
+ continue;
+ }
+
+ // Soundfield group
+ if (IS_KLV_KEY(mca_sub_descriptor-
>mca_label_dictionnary_id, mxf_soundfield_group)) {
+ if (IS_KLV_KEY(mca_sub_descriptor-
>mca_label_dictionnary_id, mxf_soundfield_group_51)) {
+ st->codecpar->channel_layout =
AV_CH_LAYOUT_5POINT1;
+ continue;
+ }
Consider using a table lookup for this instead.
+
+ // Audio channel
+ if (IS_KLV_KEY(mca_sub_descriptor-
>mca_label_dictionnary_id, mxf_audio_channel)) {
+ if (IS_KLV_KEY(mca_sub_descriptor-
>mca_label_dictionnary_id, mxf_left_audio_channel)) {
+ channel_ordering[current_channel] = 0;
+ current_channel += 1;
+ }
Same here, except for the special case for the impaired stuff.
+
+ // TODO support other channels
+ // mxf_smpte_st2067_8_mono_one_audio_channel
+ // mxf_smpte_st2067_8_mono_two_audio_channel
+ // mxf_smpte_st2067_8_left_total_audio_channel
+ // mxf_smpte_st2067_8_right_total_audio_channel
+ //
mxf_smpte_st2067_8_left_surround_total_audio_channel
+ //
mxf_smpte_st2067_8_right_surround_total_audio_channel
+ // mxf_smpte_st2067_8_surround_audio_channel
These should be a ticket, not just a comment in the code. Or just
implement them :)
+ }
+
+ // set language from MCA spoken language information
+ // av_dict_set(&st->metadata, "language",
mca_sub_descriptor->language, 0);
Stray dead code. Is language not accurate perhaps?
+ }
+
+ // check if the mapping is not required
+ bool require_reordering = false;
+ for (j = 0; j < descriptor->channels; ++j) {
+ if (channel_ordering[j] != j) {
+ require_reordering = true;
+ break;
+ }
+ }
+
+ if (require_reordering && is_pcm(st->codecpar->codec_id))
{
+ current_channel = 0;
+ av_log(mxf->fc, AV_LOG_INFO, "MCA Audio mapping (");
+ for(j = 0; j < descriptor->channels; ++j) {
+ for(int k = 0; k < descriptor->channels; ++k) {
+ if(channel_ordering[k] == current_channel) {
+ av_log(mxf->fc, AV_LOG_INFO, "%d -> %d",
channel_ordering[k], k);
+ if (current_channel != descriptor-
>channels - 1)
+ av_log(mxf->fc, AV_LOG_INFO, ", ");
+ current_channel += 1;
+ }
+ }
+ }
+ av_log(mxf->fc, AV_LOG_INFO, ")\n");
AV_LOG_DEBUG
+static void 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 = av_malloc(sample_offset);
Could avoid malloc here as well if we capped the number of channels.
+ 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) {
+ for (int sample_index = 0; sample_index < sample_size;
++sample_index) {
+ data_ptr[sample_size * channel_ordering[channel] +
sample_index] = tmp[sample_size * channel + sample_index];
+ }
+ }
This looks like it would be very slow. Lots of copying.
/Tomas
More information about the ffmpeg-devel
mailing list