From 13129506ba8f5edf70d3584cb52246e24d28bb83 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 13 Sep 2026 06:19:50 +0000 Subject: [PATCH] 2026-09-13 06:19:49 Signed-off-by: lizzie --- .../adsp/apps/opus/opus_decoder.cpp | 119 +++++++++--------- 1 file changed, 58 insertions(+), 61 deletions(-) diff --git a/src/audio_core/adsp/apps/opus/opus_decoder.cpp b/src/audio_core/adsp/apps/opus/opus_decoder.cpp index 2fd8013e35..59ecda1da6 100644 --- a/src/audio_core/adsp/apps/opus/opus_decoder.cpp +++ b/src/audio_core/adsp/apps/opus/opus_decoder.cpp @@ -62,48 +62,60 @@ public: // However, native opus can also work with swrescale: // it uses planarfloat, we can resample to s16 AVCodec const* codec = avcodec_find_decoder_by_name("libopus"); - bool is_libopus = codec != nullptr; + bool is_libopus = false;//codec != nullptr; if (!codec) { LOG_WARNING(Audio_DSP, "using ffmpeg native opus decoder"); codec = avcodec_find_decoder(AV_CODEC_ID_OPUS); } - if (codec) { - if ((avc = avc ? avc : avcodec_alloc_context3(codec))) { - if (is_libopus) { - const std::array mapping_arr{0, 1}; - mappings = mappings ? mappings : mapping_arr.data(); + // handles null codec + avcodec_free_context(&avc); + if ((avc = avcodec_alloc_context3(codec))) { + if (is_libopus) { + const std::array mapping_arr{0, 1}; + mappings = mappings ? mappings : mapping_arr.data(); - // freed by avcodec_context_free() - u8 *edata = reinterpret_cast(av_mallocz(OPUS_HEAD_SIZE + 2 * OPUS_MAX_CHANNELS + AV_INPUT_BUFFER_PADDING_SIZE)); - ASSERT(edata); - edata[9] = u8(channel_count); //channels - edata[10] = u8(0); //opus->pre_skip - edata[16] = u8(0); //gain_db - edata[18] = u8(0); //channel_map - edata[OPUS_HEAD_SIZE + 0] = u8(total_stream_count); - edata[OPUS_HEAD_SIZE + 1] = u8(stereo_stream_count); - if (channel_count >= 1) edata[OPUS_HEAD_SIZE + 2] = mappings[0]; - if (channel_count >= 2) edata[OPUS_HEAD_SIZE + 3] = mappings[1]; - avc->extradata = edata; - avc->extradata_size = OPUS_HEAD_SIZE + 2 * channel_count; - } - - // FFmpeg hardcodes sample rate - avc->sample_rate = sample_rate; - avc->request_sample_fmt = AV_SAMPLE_FMT_S16; - av_channel_layout_default(&avc->ch_layout, channel_count); - if (avcodec_open2(avc, codec, nullptr) >= 0) { - pkt = av_packet_alloc(); - frame = av_frame_alloc(); - return ResultSuccess; - } - avcodec_free_context(&avc); + // freed by avcodec_context_free() + u8 *edata = reinterpret_cast(av_mallocz(OPUS_HEAD_SIZE + 2 * OPUS_MAX_CHANNELS + AV_INPUT_BUFFER_PADDING_SIZE)); + ASSERT(edata); + edata[9] = u8(channel_count); //channels + edata[10] = u8(0); //opus->pre_skip + edata[16] = u8(0); //gain_db + edata[18] = u8(0); //channel_map + edata[OPUS_HEAD_SIZE + 0] = u8(total_stream_count); + edata[OPUS_HEAD_SIZE + 1] = u8(stereo_stream_count); + if (channel_count >= 1) edata[OPUS_HEAD_SIZE + 2] = mappings[0]; + if (channel_count >= 2) edata[OPUS_HEAD_SIZE + 3] = mappings[1]; + avc->extradata = edata; + avc->extradata_size = OPUS_HEAD_SIZE + 2 * channel_count; } + + // FFmpeg hardcodes sample rate + avc->sample_rate = sample_rate; + avc->request_sample_fmt = AV_SAMPLE_FMT_S16; + av_channel_layout_default(&avc->ch_layout, channel_count); + if (avcodec_open2(avc, codec, nullptr) >= 0) { + pkt = av_packet_alloc(); + frame = av_frame_alloc(); + if (swr_alloc_set_opts2( + &swr, + &avc->ch_layout, AV_SAMPLE_FMT_S16, 48000, + &avc->ch_layout, (enum AVSampleFormat)frame->format, 48000, + 0, nullptr) >= 0) { + if (swr_init(swr) >= 0) { + return ResultSuccess; + } + } + } + swr_free(&swr); + av_frame_free(&frame); + av_packet_free(&pkt); + avcodec_free_context(&avc); } return Service::Audio::ResultLibOpusInternalError; } Result Shutdown() { + swr_free(&swr); av_frame_free(&frame); av_packet_free(&pkt); avcodec_free_context(&avc); @@ -127,44 +139,28 @@ public: if (r == AVERROR(EAGAIN)) { av_frame_unref(frame); av_packet_unref(pkt); - if ((r = av_new_packet(pkt, int(input_data_size))) >= 0) { - std::memcpy(pkt->data, reinterpret_cast(input_data), input_data_size); - r = avcodec_send_packet(avc, pkt); - ASSERT(r >= 0); - } else { - return Service::Audio::ResultLibOpusInvalidState; - } + if ((r = av_new_packet(pkt, int(input_data_size))) < 0) + break; + std::memcpy(pkt->data, reinterpret_cast(input_data), input_data_size); + if ((r = avcodec_send_packet(avc, pkt)) < 0) + break; } else if (r == AVERROR_EOF) { av_frame_unref(frame); break; } else if (r >= 0) { auto const input_bsize = av_samples_get_buffer_size(frame->linesize, frame->ch_layout.nb_channels, frame->nb_samples, AV_SAMPLE_FMT_S16, 1); if (frame->format == AV_SAMPLE_FMT_S16) { + // input_bsize == output_bsize ASSERT(size_t(int(output_data_size) - rem_output_bytes + input_bsize) <= size_t(output_data_size)); - std::memcpy(reinterpret_cast(output_data) + (int(output_data_size) - rem_output_bytes), frame->data[0], size_t(input_bsize)); + std::memcpy(reinterpret_cast(output_data + (int(output_data_size) - rem_output_bytes)), frame->data[0], size_t(input_bsize)); } else { - SwrContext *swr = nullptr; - if (swr_alloc_set_opts2( - &swr, - &avc->ch_layout, - AV_SAMPLE_FMT_S16, - 48000, - &avc->ch_layout, - (enum AVSampleFormat)frame->format, - 48000, - 0, - nullptr - ) >= 0) { - if (swr_init(swr) >= 0) { - int out_samples = int(av_rescale_rnd(swr_get_delay(swr, frame->sample_rate) + frame->nb_samples, frame->sample_rate, frame->sample_rate, AV_ROUND_UP)); - uint8_t *output = nullptr; - av_samples_alloc(&output, frame->linesize, frame->ch_layout.nb_channels, out_samples, AV_SAMPLE_FMT_S16, 0); - out_samples = swr_convert(swr, &output, out_samples, (const uint8_t **)frame->data, frame->nb_samples); - std::memcpy(reinterpret_cast(output_data) + (int(output_data_size) - rem_output_bytes), output, size_t(input_bsize)); - av_freep(&output); - } - swr_free(&swr); - } + int out_samples = int(av_rescale_rnd(swr_get_delay(swr, frame->sample_rate) + frame->nb_samples, frame->sample_rate, frame->sample_rate, AV_ROUND_UP)); + uint8_t *output = nullptr; + av_samples_alloc(&output, frame->linesize, frame->ch_layout.nb_channels, out_samples, AV_SAMPLE_FMT_S16, 0); + out_samples = swr_convert(swr, &output, out_samples, (const uint8_t **)frame->data, frame->nb_samples); + auto const output_bsize = av_samples_get_buffer_size(frame->linesize, frame->ch_layout.nb_channels, out_samples, AV_SAMPLE_FMT_S16, 1); + std::memcpy(reinterpret_cast(output_data + (int(output_data_size) - rem_output_bytes)), output, size_t(output_bsize)); + av_freep(&output); } out_sample_count += frame->nb_samples; rem_output_bytes -= input_bsize; @@ -183,6 +179,7 @@ public: AVCodecContext* avc = nullptr; AVPacket* pkt = nullptr; AVFrame* frame = nullptr; + SwrContext* swr = nullptr; }; } // namespace