void parse_audio_codec_info()

in vireo/internal/demux/mp4.cpp [292:401]


  void parse_audio_codec_info(lsmash_track_parameters_t& track_param) {
    const SampleType type = SampleType::Audio;

    lsmash_audio_summary_t* audio_summary = (lsmash_audio_summary_t*)tracks(type).summary.get();

    audio.sample_rate = audio_summary->frequency;
    THROW_IF(find(kSampleRate.begin(), kSampleRate.end(), audio.sample_rate) == kSampleRate.end(), Unsupported);

    audio.channels = audio_summary->channels;
    THROW_IF(!audio.channels, Invalid);
    THROW_IF(audio.channels > 2, Unsupported);

    if (lsmash_check_box_type_identical(audio_summary->sample_type, ISOM_CODEC_TYPE_MP4A_AUDIO)) {  // AAC
      THROW_IF(audio_summary->sample_size != 16, Unsupported);
      THROW_IF(audio_summary->aot != MP4A_AUDIO_OBJECT_TYPE_NULL &&
               audio_summary->aot != MP4A_AUDIO_OBJECT_TYPE_AAC_LC, Invalid);
      audio.codec = settings::Audio::Codec::AAC_LC;  // assume AAC-LC - unless stated otherwise via codec specific data
    } else if (lsmash_check_box_type_identical(audio_summary->sample_type, QT_CODEC_TYPE_SOWT_AUDIO)) {  // PCM 16-bit Little Endian
      THROW_IF(audio_summary->sample_size != 16, Invalid);
      audio.codec = settings::Audio::Codec::PCM_S16LE;
    } else if (lsmash_check_box_type_identical(audio_summary->sample_type, QT_CODEC_TYPE_TWOS_AUDIO)) {  // PCM 16-bit Big Endian
      THROW_IF(audio_summary->sample_size != 16, Invalid);
      audio.codec = settings::Audio::Codec::PCM_S16BE;
    } else if (lsmash_check_box_type_identical(audio_summary->sample_type, QT_CODEC_TYPE_IN24_AUDIO)) {  // PCM 24-bit
      THROW_IF(audio_summary->sample_size != 24, Invalid);
      audio.codec = settings::Audio::Codec::PCM_S24LE;  // assume Little Endian - unless stated otherwise via codec specific data
    } else if (lsmash_check_box_type_identical(audio_summary->sample_type, QT_CODEC_TYPE_LPCM_AUDIO)) {  // PCM (various)
      THROW_IF(audio_summary->sample_size != 16, Unsupported);  // can technically be different but not tested
      audio.codec = settings::Audio::Codec::PCM_S16LE;  // assume Little Endian - unless stated otherwise via codec specific data
    }

    const uint32_t audio_cs_count = lsmash_count_codec_specific_data(tracks(type).summary.get());
    THROW_IF(audio_cs_count > 10, Unsafe);
    for (int i = 0; i < audio_cs_count; ++i) {
      lsmash_codec_specific_t* cs = lsmash_get_codec_specific_data(tracks(type).summary.get(), i + 1);
      CHECK(cs);
      if (cs->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG) {
        THROW_IF(audio_summary->aot != MP4A_AUDIO_OBJECT_TYPE_AAC_LC, Unsupported);
        THROW_IF(audio_summary->samples_in_frame != AUDIO_FRAME_SIZE, Unsupported);
        lsmash_mp4sys_decoder_parameters_t* params = (lsmash_mp4sys_decoder_parameters_t*)cs->data.structured;
        THROW_IF(params->objectTypeIndication != MP4SYS_OBJECT_TYPE_Audio_ISO_14496_3, Invalid);  // AAC

        uint8_t* payload;
        uint32_t payload_length;
        lsmash_get_mp4sys_decoder_specific_info(params, &payload, &payload_length);
        common::BitReader bit_reader(common::Data32(payload, payload_length, [](uint8_t* p) { free(p); }));

        // ISO/IEC 14496-3 - Section 1.6.2.1 - AudioSpecificConfig - payload in bit string format (packed bits)
        const uint8_t audio_object_type = bit_reader.read_bits(5);                          // audioObjectType             (5 bits)
        THROW_IF(audio_object_type != 2, Unsupported);                                      // 2=AAC-LC, 5=SBR
        audio.codec = settings::Audio::Codec::AAC_LC;
        const uint8_t sampling_frequency_index = bit_reader.read_bits(4);                   // samplingFrequencyIndex      (4 bits)
        THROW_IF(sampling_frequency_index == 0x0F, Unsupported);                            // if 0x0F, samplingFrequency (24 bits) - not supported!
        const uint8_t channel_configuration = bit_reader.read_bits(4);                      // channelConfiguration        (4 bits)
        THROW_IF(channel_configuration != 1 && channel_configuration != 2, Unsupported);    // mono/stereo

        // GASpecificConfig
        THROW_IF(audio_object_type != 2, Invalid);                                          // GASpecificConfig present only for audioObjectType == 2
        const bool frame_length_flag = bit_reader.read_bits(1);                             // frameLengthFlag             (1 bit)
        THROW_IF(frame_length_flag, Unsupported);                                           // if true, alternate frame length      - not supported!
        const bool depends_on_core_coder = bit_reader.read_bits(1);                         // dependsOnCoreCoder          (1 bit)
        THROW_IF(depends_on_core_coder, Unsupported);                                       // if true, coreCoderDelay    (14 bits) - not supported!
        const bool extension_flag = bit_reader.read_bits(1);                                // extensionFlag               (1 bit)
        THROW_IF(extension_flag, Unsupported);                                              // if true, more data                   - not supported!

        if (bit_reader.remaining() >= 16) {
          // potentially we might read 24 bits here but we are checking for >= 16 bits per standard
          // BitReader will throw an exception if we try to read beyond the available data so it's safe
          THROW_IF(audio_object_type == 5, Invalid);
          const uint16_t sync_extension_type = bit_reader.read_bits(11);                   // syncExtensionType              (11 bits)
          if (sync_extension_type == 0x02B7) {
            const uint8_t extension_audio_object_type = bit_reader.read_bits(5);           // extensionAudioObjectType        (5 bits)
            THROW_IF(extension_audio_object_type != 5, Unsupported);
            const bool sbr_present_flag = bit_reader.read_bits(1);                         // sbrPresentFlag                  (1 bit)
            if (sbr_present_flag) {
              const uint8_t extension_sampling_frequency_index = bit_reader.read_bits(4);  // extensionSamplingFrequencyIndex (4 bits)
              THROW_IF(extension_sampling_frequency_index + 3 != sampling_frequency_index, Invalid);
              audio.codec = settings::Audio::Codec::AAC_LC_SBR;
            }
          }
        }
        break;  // we found the info we wanted, no need to check the rest of the codec specific data
      } else if (cs->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS) {
        if (settings::Audio::IsPCM(audio.codec)) {
          lsmash_qt_audio_format_specific_flags_t* flags = (lsmash_qt_audio_format_specific_flags_t*)cs->data.structured;
          THROW_IF(flags->format_flags & QT_AUDIO_FORMAT_FLAG_NON_INTERLEAVED, Unsupported);
          if (lsmash_check_box_type_identical(audio_summary->sample_type, QT_CODEC_TYPE_IN24_AUDIO)) {  // PCM 24-bit
            CHECK(audio.codec == settings::Audio::Codec::PCM_S24LE);
            if (flags->format_flags & QT_AUDIO_FORMAT_FLAG_BIG_ENDIAN) {
              audio.codec = settings::Audio::Codec::PCM_S24BE;  // Big Endian
            }
          } else if (lsmash_check_box_type_identical(audio_summary->sample_type, QT_CODEC_TYPE_LPCM_AUDIO)) {  // LPCM
            CHECK(audio.codec == settings::Audio::Codec::PCM_S16LE);
            THROW_IF(!(flags->format_flags & QT_AUDIO_FORMAT_FLAG_SIGNED_INTEGER), Unsupported);
            THROW_IF(!(flags->format_flags & QT_AUDIO_FORMAT_FLAG_PACKED), Unsupported);
            if (flags->format_flags & QT_AUDIO_FORMAT_FLAG_BIG_ENDIAN) {
              audio.codec = settings::Audio::Codec::PCM_S16BE;  // Big Endian
            }
          }
          break;  // we found the info we wanted, no need to check the rest of the codec specific data
        }
      } else {
        // fail if we see an unexpected codec specific data, otherwise just skip
        THROW_IF(cs->type != LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN &&
                 cs->type != LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON &&
                 cs->type != LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT &&
                 cs->type != LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_DECOMPRESSION_PARAMETERS, Unsupported);
      }
    }
  }