Browse Source
[audio] Replace libopus with FFmpeg (#4169)
[audio] Replace libopus with FFmpeg (#4169)
FFmpeg offers two opus decoders: - libopus, this one is fed the same data (that affects output) as the previous libopus decoder had as well - native opus decoder: this only takes Float32 samples, we then need to invoke swrescale to translate between s16 (what switch sends) and float32 (what FFmpeg expects), the process is computationally more expensive, but trades off neatly as the native opus decoder is very optimised It also relegates the handling to FFmpeg, which simplifies existing code (more concretely, by using the "fill/drain" scheme for packets/frames) Closes #2897 Signed-off-by: lizzie <lizzie@eden-emu.dev> Co-authored-by: crueter <crueter@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4169 Reviewed-by: CamilleLaVey <camillelavey99@gmail.com> Reviewed-by: Maufeat <sahyno1996@gmail.com>master
committed by
crueter
No known key found for this signature in database
GPG Key ID: 425ACD2D4830EBC6
22 changed files with 432 additions and 895 deletions
-
28.patch/opus/0001-disable-clang-runtime-neon.patch
-
153.patch/opus/0002-no-install.patch
-
15CMakeLists.txt
-
22CMakeModules/find/FindOpus.cmake
-
17cpmfile.json
-
19docs/Deps.md
-
2shell.nix
-
7src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt
-
45src/android/app/src/main/res/values/strings.xml
-
14src/audio_core/CMakeLists.txt
-
107src/audio_core/adsp/apps/opus/opus_decode_object.cpp
-
38src/audio_core/adsp/apps/opus/opus_decode_object.h
-
569src/audio_core/adsp/apps/opus/opus_decoder.cpp
-
27src/audio_core/adsp/apps/opus/opus_decoder.h
-
113src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp
-
39src/audio_core/adsp/apps/opus/opus_multistream_decode_object.h
-
32src/audio_core/adsp/apps/opus/opus_types.h
-
4src/audio_core/adsp/apps/opus/shared_memory.h
-
71src/audio_core/opus/hardware_opus.cpp
-
2src/audio_core/opus/hardware_opus.h
-
1src/core/CMakeLists.txt
-
2src/video_core/CMakeLists.txt
@ -1,28 +0,0 @@ |
|||
From cc15da16e533b2a801934eab2dfeaf3c3949a1dc Mon Sep 17 00:00:00 2001 |
|||
From: crueter <crueter@eden-emu.dev> |
|||
Date: Mon, 8 Sep 2025 12:28:55 -0400 |
|||
Subject: [PATCH] [cmake] disable NEON runtime check on clang-cl |
|||
|
|||
When enabling runtime NEON checking for clang-cl, the linker would error out with `undefined symbol: __emit`, since clang doesn't actually implement this instruction. Therefore it makes sense to disable the runtime check by default on this platform, until either this is fixed or a clang-cl compatible intrinsic check is added (I don't have enough knowledge of MSVC to do this) |
|||
---
|
|||
cmake/OpusConfig.cmake | 7 ++++++- |
|||
1 file changed, 6 insertions(+), 1 deletion(-) |
|||
|
|||
diff --git a/cmake/OpusConfig.cmake b/cmake/OpusConfig.cmake
|
|||
index e9319fbad..d0f459e88 100644
|
|||
--- a/cmake/OpusConfig.cmake
|
|||
+++ b/cmake/OpusConfig.cmake
|
|||
@@ -71,7 +71,12 @@ elseif(OPUS_CPU_ARM AND NOT OPUS_DISABLE_INTRINSICS)
|
|||
opus_detect_neon(COMPILER_SUPPORT_NEON) |
|||
if(COMPILER_SUPPORT_NEON) |
|||
option(OPUS_USE_NEON "Option to enable NEON" ON) |
|||
- option(OPUS_MAY_HAVE_NEON "Does runtime check for neon support" ON)
|
|||
+ if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
|||
+ set(NEON_RUNTIME_CHECK_DEFAULT OFF)
|
|||
+ else()
|
|||
+ set(NEON_RUNTIME_CHECK_DEFAULT ON)
|
|||
+ endif()
|
|||
+ option(OPUS_MAY_HAVE_NEON "Does runtime check for neon support" ${NEON_RUNTIME_CHECK_DEFAULT})
|
|||
option(OPUS_PRESUME_NEON "Assume target CPU has NEON support" OFF) |
|||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") |
|||
set(OPUS_PRESUME_NEON ON) |
|||
@ -1,153 +0,0 @@ |
|||
From bf455b67b4eaa446ffae5d25410b141b7b1b1082 Mon Sep 17 00:00:00 2001 |
|||
From: crueter <crueter@eden-emu.dev> |
|||
Date: Mon, 8 Sep 2025 12:08:20 -0400 |
|||
Subject: [PATCH] [cmake] `OPUS_INSTALL` option; only default install if root |
|||
project |
|||
|
|||
Signed-off-by: crueter <crueter@eden-emu.dev> |
|||
---
|
|||
CMakeLists.txt | 112 ++++++++++++++++++++++++++++--------------------- |
|||
1 file changed, 64 insertions(+), 48 deletions(-) |
|||
|
|||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
|||
index fcf034b19..08b5e16f8 100644
|
|||
--- a/CMakeLists.txt
|
|||
+++ b/CMakeLists.txt
|
|||
@@ -4,6 +4,13 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
|||
include(OpusPackageVersion) |
|||
get_package_version(PACKAGE_VERSION PROJECT_VERSION) |
|||
|
|||
+# root project detection
|
|||
+if(DEFINED PROJECT_NAME)
|
|||
+ set(root_project OFF)
|
|||
+else()
|
|||
+ set(root_project ON)
|
|||
+endif()
|
|||
+
|
|||
project(Opus LANGUAGES C VERSION ${PROJECT_VERSION}) |
|||
|
|||
include(OpusFunctions) |
|||
@@ -83,12 +90,16 @@ set(OPUS_DNN_FLOAT_DEBUG_HELP_STR "Run DNN computations as float for debugging p
|
|||
option(OPUS_DNN_FLOAT_DEBUG ${OPUS_DNN_FLOAT_DEBUG_HELP_STR} OFF) |
|||
add_feature_info(OPUS_DNN_FLOAT_DEBUG OPUS_DNN_FLOAT_DEBUG ${OPUS_DNN_FLOAT_DEBUG_HELP_STR}) |
|||
|
|||
+set(OPUS_INSTALL_HELP_STR "Install Opus targets")
|
|||
+option(OPUS_INSTALL ${OPUS_INSTALL_HELP_STR} ${root_project})
|
|||
+add_feature_info(OPUS_INSTALL OPUS_INSTALL ${OPUS_INSTALL_HELP_STR})
|
|||
+
|
|||
set(OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR "install pkg-config module.") |
|||
-option(OPUS_INSTALL_PKG_CONFIG_MODULE ${OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR} ON)
|
|||
+option(OPUS_INSTALL_PKG_CONFIG_MODULE ${OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR} ${OPUS_INSTALL})
|
|||
add_feature_info(OPUS_INSTALL_PKG_CONFIG_MODULE OPUS_INSTALL_PKG_CONFIG_MODULE ${OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR}) |
|||
|
|||
set(OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR "install CMake package config module.") |
|||
-option(OPUS_INSTALL_CMAKE_CONFIG_MODULE ${OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR} ON)
|
|||
+option(OPUS_INSTALL_CMAKE_CONFIG_MODULE ${OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR} ${OPUS_INSTALL})
|
|||
add_feature_info(OPUS_INSTALL_CMAKE_CONFIG_MODULE OPUS_INSTALL_CMAKE_CONFIG_MODULE ${OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR}) |
|||
|
|||
set(OPUS_DRED_HELP_STR "enable DRED.") |
|||
@@ -613,53 +624,58 @@ if(OPUS_BUILD_FRAMEWORK)
|
|||
OUTPUT_NAME Opus) |
|||
endif() |
|||
|
|||
-install(TARGETS opus
|
|||
- EXPORT OpusTargets
|
|||
- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|||
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|||
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|||
- FRAMEWORK DESTINATION ${CMAKE_INSTALL_PREFIX}
|
|||
- PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/opus)
|
|||
-
|
|||
-if(OPUS_INSTALL_PKG_CONFIG_MODULE)
|
|||
- set(prefix ${CMAKE_INSTALL_PREFIX})
|
|||
- set(exec_prefix ${CMAKE_INSTALL_PREFIX})
|
|||
- set(libdir ${CMAKE_INSTALL_FULL_LIBDIR})
|
|||
- set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR})
|
|||
- set(VERSION ${PACKAGE_VERSION})
|
|||
- if(HAVE_LIBM)
|
|||
- set(LIBM "-lm")
|
|||
+if (OPUS_INSTALL)
|
|||
+ install(TARGETS opus
|
|||
+ EXPORT OpusTargets
|
|||
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|||
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|||
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|||
+ FRAMEWORK DESTINATION ${CMAKE_INSTALL_PREFIX}
|
|||
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/opus)
|
|||
+
|
|||
+ if(OPUS_INSTALL_PKG_CONFIG_MODULE)
|
|||
+ set(prefix ${CMAKE_INSTALL_PREFIX})
|
|||
+ set(exec_prefix ${CMAKE_INSTALL_PREFIX})
|
|||
+ set(libdir ${CMAKE_INSTALL_FULL_LIBDIR})
|
|||
+ set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR})
|
|||
+ set(VERSION ${PACKAGE_VERSION})
|
|||
+ if(HAVE_LIBM)
|
|||
+ set(LIBM "-lm")
|
|||
+ endif()
|
|||
+ configure_file(opus.pc.in opus.pc)
|
|||
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/opus.pc
|
|||
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
|||
+ endif()
|
|||
+
|
|||
+ if(OPUS_INSTALL_CMAKE_CONFIG_MODULE)
|
|||
+ set(CPACK_GENERATOR TGZ)
|
|||
+ include(CPack)
|
|||
+ set(CMAKE_INSTALL_PACKAGEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
|||
+ install(EXPORT OpusTargets
|
|||
+ NAMESPACE Opus::
|
|||
+ DESTINATION ${CMAKE_INSTALL_PACKAGEDIR})
|
|||
+
|
|||
+ include(CMakePackageConfigHelpers)
|
|||
+
|
|||
+ set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
|
|||
+ configure_package_config_file(
|
|||
+ ${PROJECT_SOURCE_DIR}/cmake/OpusConfig.cmake.in
|
|||
+ OpusConfig.cmake
|
|||
+ INSTALL_DESTINATION
|
|||
+ ${CMAKE_INSTALL_PACKAGEDIR}
|
|||
+ PATH_VARS
|
|||
+ INCLUDE_INSTALL_DIR
|
|||
+ INSTALL_PREFIX
|
|||
+ ${CMAKE_INSTALL_PREFIX})
|
|||
+
|
|||
+ write_basic_package_version_file(OpusConfigVersion.cmake
|
|||
+ VERSION ${PROJECT_VERSION}
|
|||
+ COMPATIBILITY SameMajorVersion)
|
|||
+
|
|||
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/OpusConfig.cmake
|
|||
+ ${CMAKE_CURRENT_BINARY_DIR}/OpusConfigVersion.cmake
|
|||
+ DESTINATION ${CMAKE_INSTALL_PACKAGEDIR})
|
|||
endif() |
|||
- configure_file(opus.pc.in opus.pc)
|
|||
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/opus.pc
|
|||
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
|||
-endif()
|
|||
-
|
|||
-if(OPUS_INSTALL_CMAKE_CONFIG_MODULE)
|
|||
- set(CPACK_GENERATOR TGZ)
|
|||
- include(CPack)
|
|||
- set(CMAKE_INSTALL_PACKAGEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
|||
- install(EXPORT OpusTargets
|
|||
- NAMESPACE Opus::
|
|||
- DESTINATION ${CMAKE_INSTALL_PACKAGEDIR})
|
|||
-
|
|||
- include(CMakePackageConfigHelpers)
|
|||
-
|
|||
- set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
|
|||
- configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/OpusConfig.cmake.in
|
|||
- OpusConfig.cmake
|
|||
- INSTALL_DESTINATION
|
|||
- ${CMAKE_INSTALL_PACKAGEDIR}
|
|||
- PATH_VARS
|
|||
- INCLUDE_INSTALL_DIR
|
|||
- INSTALL_PREFIX
|
|||
- ${CMAKE_INSTALL_PREFIX})
|
|||
- write_basic_package_version_file(OpusConfigVersion.cmake
|
|||
- VERSION ${PROJECT_VERSION}
|
|||
- COMPATIBILITY SameMajorVersion)
|
|||
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/OpusConfig.cmake
|
|||
- ${CMAKE_CURRENT_BINARY_DIR}/OpusConfigVersion.cmake
|
|||
- DESTINATION ${CMAKE_INSTALL_PACKAGEDIR})
|
|||
endif() |
|||
|
|||
if(OPUS_BUILD_PROGRAMS) |
|||
@ -1,22 +0,0 @@ |
|||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project |
|||
# SPDX-License-Identifier: GPL-3.0-or-later |
|||
|
|||
# SPDX-FileCopyrightText: 2022 yuzu Emulator Project |
|||
# SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
find_package(PkgConfig QUIET) |
|||
pkg_search_module(OPUS QUIET IMPORTED_TARGET opus) |
|||
|
|||
include(FindPackageHandleStandardArgs) |
|||
find_package_handle_standard_args(Opus |
|||
REQUIRED_VARS OPUS_LINK_LIBRARIES |
|||
VERSION_VAR OPUS_VERSION |
|||
) |
|||
|
|||
if (MSYS2) |
|||
FixMsysPath(PkgConfig::OPUS) |
|||
endif() |
|||
|
|||
if (Opus_FOUND AND NOT TARGET Opus::opus) |
|||
add_library(Opus::opus ALIAS PkgConfig::OPUS) |
|||
endif() |
|||
@ -1,107 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "audio_core/adsp/apps/opus/opus_decode_object.h"
|
|||
#include "common/assert.h"
|
|||
|
|||
namespace AudioCore::ADSP::OpusDecoder { |
|||
namespace { |
|||
bool IsValidChannelCount(u32 channel_count) { |
|||
return channel_count == 1 || channel_count == 2; |
|||
} |
|||
} // namespace
|
|||
|
|||
u32 OpusDecodeObject::GetWorkBufferSize(u32 channel_count) { |
|||
if (!IsValidChannelCount(channel_count)) { |
|||
return 0; |
|||
} |
|||
return static_cast<u32>(sizeof(OpusDecodeObject)) + opus_decoder_get_size(channel_count); |
|||
} |
|||
|
|||
OpusDecodeObject& OpusDecodeObject::Initialize(u64 buffer, u64 buffer2) { |
|||
auto* new_decoder = reinterpret_cast<OpusDecodeObject*>(buffer); |
|||
auto* comparison = reinterpret_cast<OpusDecodeObject*>(buffer2); |
|||
|
|||
if (new_decoder->magic == DecodeObjectMagic) { |
|||
if (!new_decoder->initialized || |
|||
(new_decoder->initialized && new_decoder->self == comparison)) { |
|||
new_decoder->state_valid = true; |
|||
} |
|||
} else { |
|||
new_decoder->initialized = false; |
|||
new_decoder->state_valid = true; |
|||
} |
|||
return *new_decoder; |
|||
} |
|||
|
|||
s32 OpusDecodeObject::InitializeDecoder(u32 sample_rate, u32 channel_count) { |
|||
if (!state_valid) { |
|||
return OPUS_INVALID_STATE; |
|||
} |
|||
|
|||
if (initialized) { |
|||
return OPUS_OK; |
|||
} |
|||
|
|||
// Unfortunately libopus does not expose the OpusDecoder struct publicly, so we can't include
|
|||
// it in this class. Nintendo does not allocate memory, which is why we have a workbuffer
|
|||
// provided.
|
|||
// We could use _create and have libopus allocate it for us, but then we have to separately
|
|||
// track which decoder is being used between this and multistream in order to call the correct
|
|||
// destroy from the host side.
|
|||
// This is a bit cringe, but is safe as these objects are only ever initialized inside the given
|
|||
// workbuffer, and GetWorkBufferSize will guarantee there's enough space to follow.
|
|||
decoder = (LibOpusDecoder*)(this + 1); |
|||
s32 ret = opus_decoder_init(decoder, sample_rate, channel_count); |
|||
if (ret == OPUS_OK) { |
|||
magic = DecodeObjectMagic; |
|||
initialized = true; |
|||
state_valid = true; |
|||
self = this; |
|||
final_range = 0; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
s32 OpusDecodeObject::Shutdown() { |
|||
if (!state_valid) { |
|||
return OPUS_INVALID_STATE; |
|||
} |
|||
|
|||
if (initialized) { |
|||
magic = 0x0; |
|||
initialized = false; |
|||
state_valid = false; |
|||
self = nullptr; |
|||
final_range = 0; |
|||
decoder = nullptr; |
|||
} |
|||
return OPUS_OK; |
|||
} |
|||
|
|||
s32 OpusDecodeObject::ResetDecoder() { |
|||
return opus_decoder_ctl(decoder, OPUS_RESET_STATE); |
|||
} |
|||
|
|||
s32 OpusDecodeObject::Decode(u32& out_sample_count, u64 output_data, u64 output_data_size, |
|||
u64 input_data, u64 input_data_size) { |
|||
ASSERT(initialized); |
|||
out_sample_count = 0; |
|||
|
|||
if (!state_valid) { |
|||
return OPUS_INVALID_STATE; |
|||
} |
|||
|
|||
auto ret_code_or_samples = opus_decode( |
|||
decoder, reinterpret_cast<const u8*>(input_data), static_cast<opus_int32>(input_data_size), |
|||
reinterpret_cast<opus_int16*>(output_data), static_cast<opus_int32>(output_data_size), 0); |
|||
|
|||
if (ret_code_or_samples < OPUS_OK) { |
|||
return ret_code_or_samples; |
|||
} |
|||
|
|||
out_sample_count = ret_code_or_samples; |
|||
return opus_decoder_ctl(decoder, OPUS_GET_FINAL_RANGE_REQUEST, &final_range); |
|||
} |
|||
|
|||
} // namespace AudioCore::ADSP::OpusDecoder
|
|||
@ -1,38 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <opus.h> |
|||
|
|||
#include "common/common_types.h" |
|||
|
|||
namespace AudioCore::ADSP::OpusDecoder { |
|||
using LibOpusDecoder = ::OpusDecoder; |
|||
static constexpr u32 DecodeObjectMagic = 0xDEADBEEF; |
|||
|
|||
class OpusDecodeObject { |
|||
public: |
|||
static u32 GetWorkBufferSize(u32 channel_count); |
|||
static OpusDecodeObject& Initialize(u64 buffer, u64 buffer2); |
|||
|
|||
s32 InitializeDecoder(u32 sample_rate, u32 channel_count); |
|||
s32 Shutdown(); |
|||
s32 ResetDecoder(); |
|||
s32 Decode(u32& out_sample_count, u64 output_data, u64 output_data_size, u64 input_data, |
|||
u64 input_data_size); |
|||
u32 GetFinalRange() const noexcept { |
|||
return final_range; |
|||
} |
|||
|
|||
private: |
|||
u32 magic; |
|||
bool initialized; |
|||
bool state_valid; |
|||
OpusDecodeObject* self; |
|||
u32 final_range; |
|||
LibOpusDecoder* decoder; |
|||
}; |
|||
static_assert(std::is_trivially_constructible_v<OpusDecodeObject>); |
|||
|
|||
} // namespace AudioCore::ADSP::OpusDecoder |
|||
@ -1,113 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|||
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "audio_core/adsp/apps/opus/opus_multistream_decode_object.h"
|
|||
#include "common/assert.h"
|
|||
|
|||
namespace AudioCore::ADSP::OpusDecoder { |
|||
|
|||
namespace { |
|||
constexpr u32 OpusStreamCountMax = 255; |
|||
|
|||
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) { |
|||
return total_stream_count > 0 && total_stream_count <= OpusStreamCountMax && |
|||
static_cast<s32>(stereo_stream_count) >= 0 && |
|||
stereo_stream_count <= total_stream_count; |
|||
} |
|||
} // namespace
|
|||
|
|||
u32 OpusMultiStreamDecodeObject::GetWorkBufferSize(u32 total_stream_count, |
|||
u32 stereo_stream_count) { |
|||
if (IsValidStreamCounts(total_stream_count, stereo_stream_count)) { |
|||
return static_cast<u32>(sizeof(OpusMultiStreamDecodeObject)) + |
|||
opus_multistream_decoder_get_size(total_stream_count, stereo_stream_count); |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
OpusMultiStreamDecodeObject& OpusMultiStreamDecodeObject::Initialize(u64 buffer, u64 buffer2) { |
|||
auto* new_decoder = reinterpret_cast<OpusMultiStreamDecodeObject*>(buffer); |
|||
auto* comparison = reinterpret_cast<OpusMultiStreamDecodeObject*>(buffer2); |
|||
|
|||
if (new_decoder->magic == DecodeMultiStreamObjectMagic) { |
|||
if (!new_decoder->initialized || |
|||
(new_decoder->initialized && new_decoder->self == comparison)) { |
|||
new_decoder->state_valid = true; |
|||
} |
|||
} else { |
|||
new_decoder->initialized = false; |
|||
new_decoder->state_valid = true; |
|||
} |
|||
return *new_decoder; |
|||
} |
|||
|
|||
s32 OpusMultiStreamDecodeObject::InitializeDecoder(u32 sample_rate, u32 total_stream_count, |
|||
u32 channel_count, u32 stereo_stream_count, |
|||
u8* mappings) { |
|||
if (!state_valid) { |
|||
return OPUS_INVALID_STATE; |
|||
} |
|||
|
|||
if (initialized) { |
|||
return OPUS_OK; |
|||
} |
|||
|
|||
// See OpusDecodeObject::InitializeDecoder for an explanation of this
|
|||
decoder = (LibOpusMSDecoder*)(this + 1); |
|||
s32 ret = opus_multistream_decoder_init(decoder, sample_rate, channel_count, total_stream_count, |
|||
stereo_stream_count, mappings); |
|||
if (ret == OPUS_OK) { |
|||
magic = DecodeMultiStreamObjectMagic; |
|||
initialized = true; |
|||
state_valid = true; |
|||
self = this; |
|||
final_range = 0; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
s32 OpusMultiStreamDecodeObject::Shutdown() { |
|||
if (!state_valid) { |
|||
return OPUS_INVALID_STATE; |
|||
} |
|||
|
|||
if (initialized) { |
|||
magic = 0x0; |
|||
initialized = false; |
|||
state_valid = false; |
|||
self = nullptr; |
|||
final_range = 0; |
|||
decoder = nullptr; |
|||
} |
|||
return OPUS_OK; |
|||
} |
|||
|
|||
s32 OpusMultiStreamDecodeObject::ResetDecoder() { |
|||
return opus_multistream_decoder_ctl(decoder, OPUS_RESET_STATE); |
|||
} |
|||
|
|||
s32 OpusMultiStreamDecodeObject::Decode(u32& out_sample_count, u64 output_data, |
|||
u64 output_data_size, u64 input_data, u64 input_data_size) { |
|||
ASSERT(initialized); |
|||
out_sample_count = 0; |
|||
|
|||
if (!state_valid) { |
|||
return OPUS_INVALID_STATE; |
|||
} |
|||
|
|||
auto ret_code_or_samples = opus_multistream_decode( |
|||
decoder, reinterpret_cast<const u8*>(input_data), static_cast<opus_int32>(input_data_size), |
|||
reinterpret_cast<opus_int16*>(output_data), static_cast<opus_int32>(output_data_size), 0); |
|||
|
|||
if (ret_code_or_samples < OPUS_OK) { |
|||
return ret_code_or_samples; |
|||
} |
|||
|
|||
out_sample_count = ret_code_or_samples; |
|||
return opus_multistream_decoder_ctl(decoder, OPUS_GET_FINAL_RANGE_REQUEST, &final_range); |
|||
} |
|||
|
|||
} // namespace AudioCore::ADSP::OpusDecoder
|
|||
@ -1,39 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <opus_multistream.h> |
|||
|
|||
#include "common/common_types.h" |
|||
|
|||
namespace AudioCore::ADSP::OpusDecoder { |
|||
using LibOpusMSDecoder = ::OpusMSDecoder; |
|||
static constexpr u32 DecodeMultiStreamObjectMagic = 0xDEADBEEF; |
|||
|
|||
class OpusMultiStreamDecodeObject { |
|||
public: |
|||
static u32 GetWorkBufferSize(u32 total_stream_count, u32 stereo_stream_count); |
|||
static OpusMultiStreamDecodeObject& Initialize(u64 buffer, u64 buffer2); |
|||
|
|||
s32 InitializeDecoder(u32 sample_rate, u32 total_stream_count, u32 channel_count, |
|||
u32 stereo_stream_count, u8* mappings); |
|||
s32 Shutdown(); |
|||
s32 ResetDecoder(); |
|||
s32 Decode(u32& out_sample_count, u64 output_data, u64 output_data_size, u64 input_data, |
|||
u64 input_data_size); |
|||
u32 GetFinalRange() const noexcept { |
|||
return final_range; |
|||
} |
|||
|
|||
private: |
|||
u32 magic; |
|||
bool initialized; |
|||
bool state_valid; |
|||
OpusMultiStreamDecodeObject* self; |
|||
u32 final_range; |
|||
LibOpusMSDecoder* decoder; |
|||
}; |
|||
static_assert(std::is_trivially_constructible_v<OpusMultiStreamDecodeObject>); |
|||
|
|||
} // namespace AudioCore::ADSP::OpusDecoder |
|||
@ -0,0 +1,32 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project |
|||
// SPDX-License-Identifier: GPL-3.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/common_types.h" |
|||
|
|||
namespace AudioCore::ADSP { |
|||
|
|||
static constexpr u32 DECODE_OBJECT_MAGIC = 0xDEADBEEF; |
|||
struct LibOpusDecoder { |
|||
u32 magic; |
|||
bool initialized; |
|||
bool state_valid; |
|||
LibOpusDecoder* self; |
|||
u32 final_range; |
|||
void* decoder; |
|||
}; |
|||
static_assert(sizeof(LibOpusDecoder) == 32); |
|||
|
|||
static constexpr u32 DECODE_MULTISTREAM_OBJECT_MAGIC = 0xDEADBEEF; |
|||
struct LibOpusMultistreamDecoder { |
|||
u32 magic; |
|||
bool initialized; |
|||
bool state_valid; |
|||
LibOpusMultistreamDecoder* self; |
|||
u32 final_range; |
|||
void* decoder; |
|||
}; |
|||
static_assert(sizeof(LibOpusMultistreamDecoder) == 32); |
|||
|
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue