auto AAC::operator()

in vireo/internal/decode/aac.cpp [106:180]


auto AAC::operator()(uint32_t index) const -> sound::Sound {
  THROW_IF(index >= count(), OutOfRange);
  THROW_IF(index >= _this->samples.count(), OutOfRange);

  const Sample& sample = _this->samples(index);
  sound::Sound sound;
  sound.pts = sample.pts;

  struct audio_info {
    uint16_t frame_size;
    uint8_t channels;
  };

  sound.pcm = [_this = _this, index]() -> sound::PCM {
    auto decode_sample = [&_this](uint32_t index) -> audio_info {
      const Sample& sample = _this->samples(index);

      const auto sample_data = sample.nal();

      THROW_IF(sample_data.count() + 4 > _AAC::kMaxBufferSize, Unsafe);
      _this->scratch_buffer.copy(sample_data);

      const UINT size = _this->scratch_buffer.count();
      UINT valid_bytes_left = size;
      CHECK(aacDecoder_Fill(_this->decoder.get(),
                            (UCHAR**)util::get_addr(_this->scratch_buffer.data()),
                            &size,
                            &valid_bytes_left) == AAC_DEC_OK);
      CHECK(valid_bytes_left == 0);
      THROW_IF(aacDecoder_DecodeFrame(_this->decoder.get(),
                                      (INT_PCM*)_this->decoded_sample.data(),
                                      _this->decoded_sample.capacity(), 0) != AAC_DEC_OK, Invalid);
      CStreamInfo* stream_info = aacDecoder_GetStreamInfo(_this->decoder.get());

      const uint8_t audio_object_type = stream_info->aot;
      const uint8_t extension_object_type = stream_info->extAot;
      const uint16_t frame_size = stream_info->frameSize;
      const uint8_t channels = stream_info->numChannels;
      const uint32_t sample_rate = stream_info->sampleRate;

      // MPEG-4 AAC Low Complexity only with optional SBR supported
      THROW_IF(audio_object_type != 2, Unsupported);
      if (extension_object_type != 5) {  // AAC-LC
        CHECK(frame_size == AUDIO_FRAME_SIZE);
        CHECK(channels == _this->audio_settings.channels);
        CHECK(sample_rate == _this->audio_settings.sample_rate);
      } else {  // AAC-LC SBR
        CHECK(frame_size == AUDIO_FRAME_SIZE * SBR_FACTOR);
//        CHECK(channels == _this->audio_settings.channels * SBR_FACTOR);
        CHECK(sample_rate == _this->audio_settings.sample_rate * SBR_FACTOR);
      }

      const uint16_t decoded_size = frame_size * channels;
      _this->decoded_sample.set_bounds(0, decoded_size);
      return {frame_size, channels};
    };

    if (index - _this->last_index != 1) {
      _this->reset();
      if (index > 0) {
        decode_sample(index - 1); // There is 1 sample dependency between samples
      }
    }
    const auto info = decode_sample(index);
    common::Sample16 decoded_sample_copy(_this->decoded_sample);
    _this->last_index = index;
    sound::PCM pcm(info.frame_size, info.channels, move(decoded_sample_copy));
    if (pcm.size() == AUDIO_FRAME_SIZE * SBR_FACTOR) {
      return pcm.downsample(2);
    } else {
      return move(pcm);
    }
  };
  return sound;
}