mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-15 04:10:07 +00:00
CoreAudio::HLE: Add FFmpeg aac decoder
This commit is contained in:
parent
bf1dbb47dc
commit
c521f3b7d6
@ -3,7 +3,7 @@
|
|||||||
cd /citra
|
cd /citra
|
||||||
|
|
||||||
mkdir build && cd build
|
mkdir build && cd build
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON
|
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_FFMPEG=OFF
|
||||||
make -j4
|
make -j4
|
||||||
|
|
||||||
ctest -VV -C Release
|
ctest -VV -C Release
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
cd /citra
|
cd /citra
|
||||||
|
|
||||||
mkdir build && cd build
|
mkdir build && cd build
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DENABLE_QT_TRANSLATION=ON -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON
|
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DENABLE_QT_TRANSLATION=ON -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_FFMPEG=OFF
|
||||||
make -j4
|
make -j4
|
||||||
|
|
||||||
ctest -VV -C Release
|
ctest -VV -C Release
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh -ex
|
#!/bin/sh -ex
|
||||||
|
|
||||||
brew update
|
brew update
|
||||||
brew install qt5 sdl2 dylibbundler p7zip ccache
|
brew install qt5 sdl2 dylibbundler p7zip ccache ffmpeg
|
||||||
|
@ -26,7 +26,7 @@ tx --version
|
|||||||
|
|
||||||
cd /citra
|
cd /citra
|
||||||
mkdir build && cd build
|
mkdir build && cd build
|
||||||
cmake .. -DENABLE_QT_TRANSLATION=ON -DGENERATE_QT_TRANSLATION=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_SDL2=OFF
|
cmake .. -DENABLE_QT_TRANSLATION=ON -DGENERATE_QT_TRANSLATION=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_SDL2=OFF -DENABLE_FFMPEG=OFF
|
||||||
make translation
|
make translation
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
|
@ -20,8 +20,17 @@ option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
|||||||
|
|
||||||
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||||
|
|
||||||
|
option(ENABLE_FFMPEG "Enable FFmpeg decoder/encoder" ON)
|
||||||
|
|
||||||
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
|
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
option(ENABLE_SCRIPTING "Enables scripting support" OFF)
|
||||||
|
|
||||||
|
CMAKE_DEPENDENT_OPTION(CITRA_USE_BUNDLED_FFMPEG "Download bundled FFmpeg binaries" ON "MSVC" OFF)
|
||||||
|
|
||||||
|
>>>>>>> CoreAudio::HLE: Add FFmpeg aac decoder
|
||||||
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)
|
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)
|
||||||
message(STATUS "Copying pre-commit hook")
|
message(STATUS "Copying pre-commit hook")
|
||||||
file(COPY hooks/pre-commit
|
file(COPY hooks/pre-commit
|
||||||
@ -251,6 +260,31 @@ if (ENABLE_QT)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (ENABLE_FFMPEG)
|
||||||
|
if (CITRA_USE_BUNDLED_FFMPEG)
|
||||||
|
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
|
||||||
|
set(FFmpeg_VER "ffmpeg-4.0.2-msvc")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "No bundled FFmpeg binaries for your toolchain. Disable CITRA_USE_BUNDLED_FFMPEG and provide your own.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (DEFINED FFmpeg_VER)
|
||||||
|
download_bundled_external("ffmpeg/" ${FFmpeg_VER} FFmpeg_PREFIX)
|
||||||
|
set(FFMPEG_DIR "${FFmpeg_PREFIX}")
|
||||||
|
set(FFMPEG_FOUND YES)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
find_package(FFmpeg REQUIRED COMPONENTS avcodec)
|
||||||
|
if ("${FFmpeg_avcodec_VERSION}" VERSION_LESS "57.48.101")
|
||||||
|
message(FATAL_ERROR "Found version for libavcodec is too low. The required version is at least 57.48.101 (included in FFmpeg 3.1 and later).")
|
||||||
|
else()
|
||||||
|
set(FFMPEG_FOUND YES)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(FFMPEG_FOUND NO)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Platform-specific library requirements
|
# Platform-specific library requirements
|
||||||
# ======================================
|
# ======================================
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ install:
|
|||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- ps: |
|
- ps: |
|
||||||
if ($env:BUILD_TYPE -eq 'mingw') {
|
if ($env:BUILD_TYPE -eq 'mingw') {
|
||||||
$dependencies = "mingw64/mingw-w64-x86_64-qt5"
|
$dependencies = "mingw64/mingw-w64-x86_64-qt5 mingw64/mingw-w64-x86_64-ffmpeg"
|
||||||
# redirect err to null to prevent warnings from becoming errors
|
# redirect err to null to prevent warnings from becoming errors
|
||||||
# workaround to prevent pacman from failing due to cyclical dependencies
|
# workaround to prevent pacman from failing due to cyclical dependencies
|
||||||
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw64/mingw-w64-x86_64-freetype mingw64/mingw-w64-x86_64-fontconfig" 2> $null
|
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw64/mingw-w64-x86_64-freetype mingw64/mingw-w64-x86_64-fontconfig" 2> $null
|
||||||
|
183
externals/cmake-modules/FindFFmpeg.cmake
vendored
Normal file
183
externals/cmake-modules/FindFFmpeg.cmake
vendored
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
# FindFFmpeg
|
||||||
|
# ----------
|
||||||
|
#
|
||||||
|
# Find the native FFmpeg includes and libraries
|
||||||
|
#
|
||||||
|
# This module defines the following variables:
|
||||||
|
#
|
||||||
|
# FFmpeg_INCLUDE_<component>: where to find <component>.h
|
||||||
|
# FFmpeg_LIBRARY_<component>: where to find the <component> library
|
||||||
|
# FFmpeg_INCLUDES: aggregate all the include paths
|
||||||
|
# FFmpeg_LIBRARIES: aggregate all the paths to the libraries
|
||||||
|
# FFmpeg_FOUND: True if all components have been found
|
||||||
|
#
|
||||||
|
# This module defines the following targets, which are prefered over variables:
|
||||||
|
#
|
||||||
|
# FFmpeg::<component>: Target to use <component> directly, with include path,
|
||||||
|
# library and dependencies set up. If you are using a static build, you are
|
||||||
|
# responsible for adding any external dependencies (such as zlib, bzlib...).
|
||||||
|
#
|
||||||
|
# <component> can be one of:
|
||||||
|
# avcodec
|
||||||
|
# avdevice
|
||||||
|
# avfilter
|
||||||
|
# avformat
|
||||||
|
# postproc
|
||||||
|
# swresample
|
||||||
|
# swscale
|
||||||
|
#
|
||||||
|
|
||||||
|
set(_FFmpeg_ALL_COMPONENTS
|
||||||
|
avcodec
|
||||||
|
avdevice
|
||||||
|
avfilter
|
||||||
|
avformat
|
||||||
|
avutil
|
||||||
|
postproc
|
||||||
|
swresample
|
||||||
|
swscale
|
||||||
|
)
|
||||||
|
|
||||||
|
set(_FFmpeg_DEPS_avcodec avutil)
|
||||||
|
set(_FFmpeg_DEPS_avdevice avcodec avformat avutil)
|
||||||
|
set(_FFmpeg_DEPS_avfilter avutil)
|
||||||
|
set(_FFmpeg_DEPS_avformat avcodec avutil)
|
||||||
|
set(_FFmpeg_DEPS_postproc avutil)
|
||||||
|
set(_FFmpeg_DEPS_swresample avutil)
|
||||||
|
set(_FFmpeg_DEPS_swscale avutil)
|
||||||
|
|
||||||
|
function(find_ffmpeg LIBNAME)
|
||||||
|
if(DEFINED ENV{FFMPEG_DIR})
|
||||||
|
set(FFMPEG_DIR $ENV{FFMPEG_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FFMPEG_DIR)
|
||||||
|
list(APPEND INCLUDE_PATHS
|
||||||
|
${FFMPEG_DIR}
|
||||||
|
${FFMPEG_DIR}/ffmpeg
|
||||||
|
${FFMPEG_DIR}/lib${LIBNAME}
|
||||||
|
${FFMPEG_DIR}/include/lib${LIBNAME}
|
||||||
|
${FFMPEG_DIR}/include/ffmpeg
|
||||||
|
${FFMPEG_DIR}/include
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
NO_CMAKE_FIND_ROOT_PATH
|
||||||
|
)
|
||||||
|
list(APPEND LIB_PATHS
|
||||||
|
${FFMPEG_DIR}
|
||||||
|
${FFMPEG_DIR}/lib
|
||||||
|
${FFMPEG_DIR}/lib${LIBNAME}
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
NO_CMAKE_FIND_ROOT_PATH
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
list(APPEND INCLUDE_PATHS
|
||||||
|
/usr/local/include/ffmpeg
|
||||||
|
/usr/local/include/lib${LIBNAME}
|
||||||
|
/usr/include/ffmpeg
|
||||||
|
/usr/include/lib${LIBNAME}
|
||||||
|
/usr/include/ffmpeg/lib${LIBNAME}
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND LIB_PATHS
|
||||||
|
/usr/local/lib
|
||||||
|
/usr/lib
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
|
||||||
|
HINTS ${INCLUDE_PATHS}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
|
||||||
|
HINTS ${LIB_PATHS}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT FFMPEG_DIR AND (NOT FFmpeg_LIBRARY_${LIBNAME} OR NOT FFmpeg_INCLUDE_${LIBNAME}))
|
||||||
|
# Didn't find it in the usual paths, try pkg-config
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
pkg_check_modules(FFmpeg_PKGCONFIG_${LIBNAME} QUIET lib${LIBNAME})
|
||||||
|
|
||||||
|
find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
|
||||||
|
${FFmpeg_PKGCONFIG_${LIBNAME}_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
|
||||||
|
${FFmpeg_PKGCONFIG_${LIBNAME}_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FFmpeg_INCLUDE_${LIBNAME} AND FFmpeg_LIBRARY_${LIBNAME})
|
||||||
|
set(FFmpeg_INCLUDE_${LIBNAME} "${FFmpeg_INCLUDE_${LIBNAME}}" PARENT_SCOPE)
|
||||||
|
set(FFmpeg_LIBRARY_${LIBNAME} "${FFmpeg_LIBRARY_${LIBNAME}}" PARENT_SCOPE)
|
||||||
|
|
||||||
|
# Extract FFmpeg version from version.h
|
||||||
|
foreach(v MAJOR MINOR MICRO)
|
||||||
|
set(FFmpeg_${LIBNAME}_VERSION_${v} 0)
|
||||||
|
endforeach()
|
||||||
|
string(TOUPPER ${LIBNAME} LIBNAME_UPPER)
|
||||||
|
file(STRINGS "${FFmpeg_INCLUDE_${LIBNAME}}/lib${LIBNAME}/version.h" _FFmpeg_VERSION_H_CONTENTS REGEX "#define LIB${LIBNAME_UPPER}_VERSION_(MAJOR|MINOR|MICRO) ")
|
||||||
|
set(_FFmpeg_VERSION_REGEX "([0-9]+)")
|
||||||
|
foreach(v MAJOR MINOR MICRO)
|
||||||
|
if("${_FFmpeg_VERSION_H_CONTENTS}" MATCHES "#define LIB${LIBNAME_UPPER}_VERSION_${v}[\\t ]+${_FFmpeg_VERSION_REGEX}")
|
||||||
|
set(FFmpeg_${LIBNAME}_VERSION_${v} "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
set(FFmpeg_${LIBNAME}_VERSION "${FFmpeg_${LIBNAME}_VERSION_MAJOR}.${FFmpeg_${LIBNAME}_VERSION_MINOR}.${FFmpeg_${LIBNAME}_VERSION_MICRO}")
|
||||||
|
set(FFmpeg_${c}_VERSION "${FFmpeg_${LIBNAME}_VERSION}" PARENT_SCOPE)
|
||||||
|
unset(_FFmpeg_VERSION_REGEX)
|
||||||
|
unset(_FFmpeg_VERSION_H_CONTENTS)
|
||||||
|
|
||||||
|
set(FFmpeg_${c}_FOUND TRUE PARENT_SCOPE)
|
||||||
|
if(NOT FFmpeg_FIND_QUIETLY)
|
||||||
|
message("-- Found ${LIBNAME}: ${FFmpeg_INCLUDE_${LIBNAME}} ${FFmpeg_LIBRARY_${LIBNAME}} (version: ${FFmpeg_${LIBNAME}_VERSION})")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
foreach(c ${_FFmpeg_ALL_COMPONENTS})
|
||||||
|
find_ffmpeg(${c})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
foreach(c ${_FFmpeg_ALL_COMPONENTS})
|
||||||
|
if(FFmpeg_${c}_FOUND)
|
||||||
|
list(APPEND FFmpeg_INCLUDES ${FFmpeg_INCLUDE_${c}})
|
||||||
|
list(APPEND FFmpeg_LIBRARIES ${FFmpeg_LIBRARY_${c}})
|
||||||
|
|
||||||
|
add_library(FFmpeg::${c} IMPORTED UNKNOWN)
|
||||||
|
set_target_properties(FFmpeg::${c} PROPERTIES
|
||||||
|
IMPORTED_LOCATION ${FFmpeg_LIBRARY_${c}}
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES ${FFmpeg_INCLUDE_${c}}
|
||||||
|
)
|
||||||
|
if(_FFmpeg_DEPS_${c})
|
||||||
|
set(deps)
|
||||||
|
foreach(dep ${_FFmpeg_DEPS_${c}})
|
||||||
|
list(APPEND deps FFmpeg::${dep})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set_target_properties(FFmpeg::${c} PROPERTIES
|
||||||
|
INTERFACE_LINK_LIBRARIES "${deps}"
|
||||||
|
)
|
||||||
|
unset(deps)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(FFmpeg_INCLUDES)
|
||||||
|
list(REMOVE_DUPLICATES FFmpeg_INCLUDES)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(c ${FFmpeg_FIND_COMPONENTS})
|
||||||
|
list(APPEND _FFmpeg_REQUIRED_VARS FFmpeg_INCLUDE_${c} FFmpeg_LIBRARY_${c})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(FFmpeg
|
||||||
|
REQUIRED_VARS ${_FFmpeg_REQUIRED_VARS}
|
||||||
|
HANDLE_COMPONENTS
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach(c ${_FFmpeg_ALL_COMPONENTS})
|
||||||
|
unset(_FFmpeg_DEPS_${c})
|
||||||
|
endforeach()
|
||||||
|
unset(_FFmpeg_ALL_COMPONENTS)
|
||||||
|
unset(_FFmpeg_REQUIRED_VARS)
|
@ -5,6 +5,8 @@ add_library(audio_core STATIC
|
|||||||
dsp_interface.cpp
|
dsp_interface.cpp
|
||||||
dsp_interface.h
|
dsp_interface.h
|
||||||
hle/common.h
|
hle/common.h
|
||||||
|
hle/decoder.cpp
|
||||||
|
hle/decoder.h
|
||||||
hle/filter.cpp
|
hle/filter.cpp
|
||||||
hle/filter.h
|
hle/filter.h
|
||||||
hle/hle.cpp
|
hle/hle.cpp
|
||||||
@ -27,6 +29,7 @@ add_library(audio_core STATIC
|
|||||||
|
|
||||||
$<$<BOOL:${SDL2_FOUND}>:sdl2_sink.cpp sdl2_sink.h>
|
$<$<BOOL:${SDL2_FOUND}>:sdl2_sink.cpp sdl2_sink.h>
|
||||||
$<$<BOOL:${ENABLE_CUBEB}>:cubeb_sink.cpp cubeb_sink.h>
|
$<$<BOOL:${ENABLE_CUBEB}>:cubeb_sink.cpp cubeb_sink.h>
|
||||||
|
$<$<BOOL:${FFMPEG_FOUND}>:hle/aac_decoder.cpp hle/aac_decoder.h hle/ffmpeg_dl.h>
|
||||||
)
|
)
|
||||||
|
|
||||||
create_target_directory_groups(audio_core)
|
create_target_directory_groups(audio_core)
|
||||||
@ -43,3 +46,13 @@ if(ENABLE_CUBEB)
|
|||||||
target_link_libraries(audio_core PRIVATE cubeb)
|
target_link_libraries(audio_core PRIVATE cubeb)
|
||||||
add_definitions(-DHAVE_CUBEB=1)
|
add_definitions(-DHAVE_CUBEB=1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(FFMPEG_FOUND)
|
||||||
|
if(UNIX)
|
||||||
|
target_link_libraries(audio_core PRIVATE FFmpeg::avcodec)
|
||||||
|
else()
|
||||||
|
target_include_directories(audio_core PRIVATE ${FFMPEG_DIR}/include)
|
||||||
|
endif()
|
||||||
|
target_compile_definitions(audio_core PRIVATE HAVE_FFMPEG)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
241
src/audio_core/hle/aac_decoder.cpp
Normal file
241
src/audio_core/hle/aac_decoder.cpp
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
// Copyright 2018 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "audio_core/hle/aac_decoder.h"
|
||||||
|
#include "audio_core/hle/ffmpeg_dl.h"
|
||||||
|
|
||||||
|
namespace AudioCore::HLE {
|
||||||
|
|
||||||
|
class AACDecoder::Impl {
|
||||||
|
public:
|
||||||
|
Impl(Memory::MemorySystem& memory);
|
||||||
|
~Impl();
|
||||||
|
std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::optional<BinaryResponse> Initalize(const BinaryRequest& request);
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
std::optional<BinaryResponse> Decode(const BinaryRequest& request);
|
||||||
|
|
||||||
|
bool initalized;
|
||||||
|
bool have_ffmpeg_dl;
|
||||||
|
|
||||||
|
Memory::MemorySystem& memory;
|
||||||
|
|
||||||
|
AVCodec* codec;
|
||||||
|
AVCodecContext* av_context = nullptr;
|
||||||
|
AVCodecParserContext* parser = nullptr;
|
||||||
|
AVPacket* av_packet;
|
||||||
|
AVFrame* decoded_frame = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
AACDecoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) {
|
||||||
|
initalized = false;
|
||||||
|
|
||||||
|
have_ffmpeg_dl = InitFFmpegDL();
|
||||||
|
}
|
||||||
|
|
||||||
|
AACDecoder::Impl::~Impl() {
|
||||||
|
if (initalized)
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<BinaryResponse> AACDecoder::Impl::ProcessRequest(const BinaryRequest& request) {
|
||||||
|
if (request.codec != DecoderCodec::AAC) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Got wrong codec {}", static_cast<u16>(request.codec));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (request.cmd) {
|
||||||
|
case DecoderCommand::Init: {
|
||||||
|
return Initalize(request);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DecoderCommand::Decode: {
|
||||||
|
return Decode(request);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DecoderCommand::Unknown: {
|
||||||
|
BinaryResponse response;
|
||||||
|
std::memcpy(&response, &request, sizeof(response));
|
||||||
|
response.unknown1 = 0x0;
|
||||||
|
return response;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", static_cast<u16>(request.cmd));
|
||||||
|
return {};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<BinaryResponse> AACDecoder::Impl::Initalize(const BinaryRequest& request) {
|
||||||
|
if (initalized) {
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!have_ffmpeg_dl) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
av_packet = av_packet_alloc_dl();
|
||||||
|
|
||||||
|
codec = avcodec_find_decoder_dl(AV_CODEC_ID_AAC);
|
||||||
|
if (!codec) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Codec not found\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
parser = av_parser_init_dl(codec->id);
|
||||||
|
if (!parser) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Parser not found\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
av_context = avcodec_alloc_context3_dl(codec);
|
||||||
|
if (!av_context) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Could not allocate audio codec context\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avcodec_open2_dl(av_context, codec, NULL) < 0) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Could not open codec\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
initalized = true;
|
||||||
|
|
||||||
|
BinaryResponse response;
|
||||||
|
std::memcpy(&response, &request, sizeof(response));
|
||||||
|
response.unknown1 = 0x0;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AACDecoder::Impl::Clear() {
|
||||||
|
if (!have_ffmpeg_dl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
avcodec_free_context_dl(&av_context);
|
||||||
|
av_parser_close_dl(parser);
|
||||||
|
av_frame_free_dl(&decoded_frame);
|
||||||
|
av_packet_free_dl(&av_packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<BinaryResponse> AACDecoder::Impl::Decode(const BinaryRequest& request) {
|
||||||
|
if (!initalized) {
|
||||||
|
LOG_DEBUG(Audio_DSP, "Decoder not initalized");
|
||||||
|
|
||||||
|
// This is a hack to continue games that are not compiled with the aac codec
|
||||||
|
BinaryResponse response;
|
||||||
|
response.codec = request.codec;
|
||||||
|
response.cmd = request.cmd;
|
||||||
|
response.num_channels = 2;
|
||||||
|
response.num_samples = 1024;
|
||||||
|
response.size = request.size;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.src_addr < Memory::FCRAM_PADDR) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Got out of bounds src_addr {:08x}", request.src_addr);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
u8* data = memory.GetFCRAMPointer(request.src_addr - Memory::FCRAM_PADDR);
|
||||||
|
|
||||||
|
std::array<std::vector<u8>, 2> out_streams;
|
||||||
|
|
||||||
|
std::size_t data_size = request.size;
|
||||||
|
while (data_size > 0) {
|
||||||
|
if (!decoded_frame) {
|
||||||
|
if (!(decoded_frame = av_frame_alloc_dl())) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Could not allocate audio frame");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = av_parser_parse2_dl(parser, av_context, &av_packet->data, &av_packet->size, data,
|
||||||
|
data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Error while parsing");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
data += ret;
|
||||||
|
data_size -= ret;
|
||||||
|
|
||||||
|
ret = avcodec_send_packet_dl(av_context, av_packet);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Error submitting the packet to the decoder");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (av_packet->size) {
|
||||||
|
while (ret >= 0) {
|
||||||
|
ret = avcodec_receive_frame_dl(av_context, decoded_frame);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||||
|
break;
|
||||||
|
else if (ret < 0) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Error during decoding");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
int bytes_per_sample = av_get_bytes_per_sample_dl(av_context->sample_fmt);
|
||||||
|
if (bytes_per_sample < 0) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Failed to calculate data size");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(decoded_frame->channels == out_streams.size());
|
||||||
|
|
||||||
|
std::size_t size = bytes_per_sample * (decoded_frame->nb_samples);
|
||||||
|
|
||||||
|
// FFmpeg converts to 32 signed floating point PCM, we need s32 PCM so we need to
|
||||||
|
// convert it
|
||||||
|
f32 val_float;
|
||||||
|
for (std::size_t current_pos(0); current_pos < size;) {
|
||||||
|
for (std::size_t channel(0); channel < out_streams.size(); channel++) {
|
||||||
|
std::memcpy(&val_float, decoded_frame->data[0] + current_pos,
|
||||||
|
sizeof(val_float));
|
||||||
|
s16 val = static_cast<s16>(0x7FFF * val_float);
|
||||||
|
out_streams[channel].push_back(val & 0xFF);
|
||||||
|
out_streams[channel].push_back(val >> 8);
|
||||||
|
}
|
||||||
|
current_pos += sizeof(val_float);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.dst_addr_ch0 < Memory::FCRAM_PADDR) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch0 {:08x}", request.dst_addr_ch0);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::memcpy(memory.GetFCRAMPointer(request.dst_addr_ch0 - Memory::FCRAM_PADDR),
|
||||||
|
out_streams[0].data(), out_streams[0].size());
|
||||||
|
|
||||||
|
if (request.dst_addr_ch1 < Memory::FCRAM_PADDR) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch1 {:08x}", request.dst_addr_ch1);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::memcpy(memory.GetFCRAMPointer(request.dst_addr_ch1 - Memory::FCRAM_PADDR),
|
||||||
|
out_streams[1].data(), out_streams[1].size());
|
||||||
|
|
||||||
|
BinaryResponse response;
|
||||||
|
response.codec = request.codec;
|
||||||
|
response.cmd = request.cmd;
|
||||||
|
response.num_channels = 2;
|
||||||
|
response.num_samples = decoded_frame->nb_samples;
|
||||||
|
response.size = request.size;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
AACDecoder::AACDecoder(Memory::MemorySystem& memory) : impl(std::make_unique<Impl>(memory)) {}
|
||||||
|
|
||||||
|
AACDecoder::~AACDecoder() = default;
|
||||||
|
|
||||||
|
std::optional<BinaryResponse> AACDecoder::ProcessRequest(const BinaryRequest& request) {
|
||||||
|
return impl->ProcessRequest(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace AudioCore::HLE
|
22
src/audio_core/hle/aac_decoder.h
Normal file
22
src/audio_core/hle/aac_decoder.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2018 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "audio_core/hle/decoder.h"
|
||||||
|
|
||||||
|
namespace AudioCore::HLE {
|
||||||
|
|
||||||
|
class AACDecoder final : public DecoderBase {
|
||||||
|
public:
|
||||||
|
AACDecoder(Memory::MemorySystem& memory);
|
||||||
|
~AACDecoder() override;
|
||||||
|
std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Impl;
|
||||||
|
std::unique_ptr<Impl> impl;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace AudioCore::HLE
|
36
src/audio_core/hle/decoder.cpp
Normal file
36
src/audio_core/hle/decoder.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2018 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "audio_core/hle/decoder.h"
|
||||||
|
|
||||||
|
namespace AudioCore::HLE {
|
||||||
|
|
||||||
|
NullDecoder::NullDecoder() {}
|
||||||
|
|
||||||
|
NullDecoder::~NullDecoder() = default;
|
||||||
|
|
||||||
|
std::optional<BinaryResponse> NullDecoder::ProcessRequest(const BinaryRequest& request) {
|
||||||
|
BinaryResponse response;
|
||||||
|
switch (request.cmd) {
|
||||||
|
case DecoderCommand::Init:
|
||||||
|
case DecoderCommand::Unknown:
|
||||||
|
std::memcpy(&response, &request, sizeof(response));
|
||||||
|
response.unknown1 = 0x0;
|
||||||
|
return response;
|
||||||
|
break;
|
||||||
|
case DecoderCommand::Decode:
|
||||||
|
response.codec = request.codec;
|
||||||
|
response.cmd = DecoderCommand::Decode;
|
||||||
|
response.num_channels = 2; // Just assume stereo here
|
||||||
|
response.size = request.size;
|
||||||
|
response.num_samples = 1024; // Just assume 1024 here
|
||||||
|
return response;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", static_cast<u16>(request.cmd));
|
||||||
|
return {};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace AudioCore::HLE
|
68
src/audio_core/hle/decoder.h
Normal file
68
src/audio_core/hle/decoder.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2018 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/swap.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
|
||||||
|
namespace AudioCore::HLE {
|
||||||
|
|
||||||
|
enum class DecoderCommand : u16 {
|
||||||
|
Init,
|
||||||
|
Decode,
|
||||||
|
Unknown,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class DecoderCodec : u16 {
|
||||||
|
None,
|
||||||
|
AAC,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BinaryRequest {
|
||||||
|
enum_le<DecoderCodec> codec =
|
||||||
|
DecoderCodec::None; // this is a guess. until now only 0x1 was observed here
|
||||||
|
enum_le<DecoderCommand> cmd = DecoderCommand::Init;
|
||||||
|
u32_le fixed = 0;
|
||||||
|
u32_le src_addr = 0;
|
||||||
|
u32_le size = 0;
|
||||||
|
u32_le dst_addr_ch0 = 0;
|
||||||
|
u32_le dst_addr_ch1 = 0;
|
||||||
|
u32_le unknown1 = 0;
|
||||||
|
u32_le unknown2 = 0;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(BinaryRequest) == 32, "Unexpected struct size for BinaryRequest");
|
||||||
|
|
||||||
|
struct BinaryResponse {
|
||||||
|
enum_le<DecoderCodec> codec =
|
||||||
|
DecoderCodec::None; // this could be something else. until now only 0x1 was observed here
|
||||||
|
enum_le<DecoderCommand> cmd = DecoderCommand::Init;
|
||||||
|
u32_le unknown1 = 0;
|
||||||
|
u32_le unknown2 = 0;
|
||||||
|
u32_le num_channels = 0; // this is a guess, so far I only observed 2 here
|
||||||
|
u32_le size = 0;
|
||||||
|
u32_le unknown3 = 0;
|
||||||
|
u32_le unknown4 = 0;
|
||||||
|
u32_le num_samples = 0; // this is a guess, so far I only observed 1024 here
|
||||||
|
};
|
||||||
|
static_assert(sizeof(BinaryResponse) == 32, "Unexpected struct size for BinaryResponse");
|
||||||
|
|
||||||
|
class DecoderBase {
|
||||||
|
public:
|
||||||
|
virtual ~DecoderBase(){};
|
||||||
|
virtual std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NullDecoder final : public DecoderBase {
|
||||||
|
public:
|
||||||
|
NullDecoder();
|
||||||
|
~NullDecoder() override;
|
||||||
|
std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace AudioCore::HLE
|
213
src/audio_core/hle/ffmpeg_dl.h
Normal file
213
src/audio_core/hle/ffmpeg_dl.h
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
// Copyright 2018 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "libavcodec/avcodec.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct FuncDL {
|
||||||
|
FuncDL() = default;
|
||||||
|
FuncDL(HMODULE dll, const char* name) {
|
||||||
|
ptr_function = nullptr;
|
||||||
|
if (dll) {
|
||||||
|
*(void**)&ptr_function = (void*)GetProcAddress(dll, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T*() const {
|
||||||
|
return ptr_function;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator bool() const {
|
||||||
|
return ptr_function != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* ptr_function = nullptr;
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
FuncDL<int(AVSampleFormat)> av_get_bytes_per_sample_dl;
|
||||||
|
FuncDL<AVFrame*(void)> av_frame_alloc_dl;
|
||||||
|
FuncDL<void(AVFrame**)> av_frame_free_dl;
|
||||||
|
FuncDL<AVCodecContext*(const AVCodec*)> avcodec_alloc_context3_dl;
|
||||||
|
FuncDL<void(AVCodecContext**)> avcodec_free_context_dl;
|
||||||
|
FuncDL<int(AVCodecContext*, const AVCodec*, AVDictionary**)> avcodec_open2_dl;
|
||||||
|
FuncDL<AVPacket*(void)> av_packet_alloc_dl;
|
||||||
|
FuncDL<void(AVPacket**)> av_packet_free_dl;
|
||||||
|
FuncDL<AVCodec*(AVCodecID)> avcodec_find_decoder_dl;
|
||||||
|
FuncDL<int(AVCodecContext*, const AVPacket*)> avcodec_send_packet_dl;
|
||||||
|
FuncDL<int(AVCodecContext*, AVFrame*)> avcodec_receive_frame_dl;
|
||||||
|
FuncDL<AVCodecParserContext*(int)> av_parser_init_dl;
|
||||||
|
FuncDL<int(AVCodecParserContext*, AVCodecContext*, uint8_t**, int*, const uint8_t*, int, int64_t,
|
||||||
|
int64_t, int64_t)>
|
||||||
|
av_parser_parse2_dl;
|
||||||
|
FuncDL<void(AVCodecParserContext*)> av_parser_close_dl;
|
||||||
|
|
||||||
|
bool InitFFmpegDL() {
|
||||||
|
HMODULE dll_util = nullptr;
|
||||||
|
dll_util = LoadLibrary("avutil-56.dll");
|
||||||
|
if (!dll_util) {
|
||||||
|
DWORD errorMessageID = GetLastError();
|
||||||
|
LPSTR messageBuffer = nullptr;
|
||||||
|
size_t size =
|
||||||
|
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||||
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
(LPSTR)&messageBuffer, 0, NULL);
|
||||||
|
|
||||||
|
std::string message(messageBuffer, size);
|
||||||
|
|
||||||
|
// Free the buffer.
|
||||||
|
LocalFree(messageBuffer);
|
||||||
|
LOG_ERROR(Audio_DSP, "Could not load avcodec-58.dll: {}", message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HMODULE dll_codec = nullptr;
|
||||||
|
dll_codec = LoadLibrary("avcodec-58.dll");
|
||||||
|
if (!dll_codec) {
|
||||||
|
DWORD errorMessageID = GetLastError();
|
||||||
|
LPSTR messageBuffer = nullptr;
|
||||||
|
size_t size =
|
||||||
|
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||||
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
(LPSTR)&messageBuffer, 0, NULL);
|
||||||
|
|
||||||
|
std::string message(messageBuffer, size);
|
||||||
|
|
||||||
|
// Free the buffer.
|
||||||
|
LocalFree(messageBuffer);
|
||||||
|
LOG_ERROR(Audio_DSP, "Could not load avcodec-58.dll: {}", message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
av_get_bytes_per_sample_dl = FuncDL<int(AVSampleFormat)>(dll_util, "av_get_bytes_per_sample");
|
||||||
|
if (!av_get_bytes_per_sample_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function av_get_bytes_per_sample");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_frame_alloc_dl = FuncDL<AVFrame*()>(dll_util, "av_frame_alloc");
|
||||||
|
if (!av_frame_alloc_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function av_frame_alloc");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_frame_free_dl = FuncDL<void(AVFrame**)>(dll_util, "av_frame_free");
|
||||||
|
if (!av_frame_free_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function av_frame_free");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
avcodec_alloc_context3_dl =
|
||||||
|
FuncDL<AVCodecContext*(const AVCodec*)>(dll_codec, "avcodec_alloc_context3");
|
||||||
|
if (!avcodec_alloc_context3_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function avcodec_alloc_context3");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
avcodec_free_context_dl = FuncDL<void(AVCodecContext**)>(dll_codec, "avcodec_free_context");
|
||||||
|
if (!av_get_bytes_per_sample_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function avcodec_free_context");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
avcodec_open2_dl =
|
||||||
|
FuncDL<int(AVCodecContext*, const AVCodec*, AVDictionary**)>(dll_codec, "avcodec_open2");
|
||||||
|
if (!avcodec_open2_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function avcodec_open2");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
av_packet_alloc_dl = FuncDL<AVPacket*(void)>(dll_codec, "av_packet_alloc");
|
||||||
|
if (!av_packet_alloc_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function av_packet_alloc");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_packet_free_dl = FuncDL<void(AVPacket**)>(dll_codec, "av_packet_free");
|
||||||
|
if (!av_packet_free_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function av_packet_free");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
avcodec_find_decoder_dl = FuncDL<AVCodec*(AVCodecID)>(dll_codec, "avcodec_find_decoder");
|
||||||
|
if (!avcodec_find_decoder_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function avcodec_find_decoder");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
avcodec_send_packet_dl =
|
||||||
|
FuncDL<int(AVCodecContext*, const AVPacket*)>(dll_codec, "avcodec_send_packet");
|
||||||
|
if (!avcodec_send_packet_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function avcodec_send_packet");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
avcodec_receive_frame_dl =
|
||||||
|
FuncDL<int(AVCodecContext*, AVFrame*)>(dll_codec, "avcodec_receive_frame");
|
||||||
|
if (!avcodec_receive_frame_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function avcodec_receive_frame");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_parser_init_dl = FuncDL<AVCodecParserContext*(int)>(dll_codec, "av_parser_init");
|
||||||
|
if (!av_parser_init_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function av_parser_init");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_parser_parse2_dl =
|
||||||
|
FuncDL<int(AVCodecParserContext*, AVCodecContext*, uint8_t**, int*, const uint8_t*, int,
|
||||||
|
int64_t, int64_t, int64_t)>(dll_codec, "av_parser_parse2");
|
||||||
|
if (!av_parser_parse2_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function av_parser_parse2");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_parser_close_dl = FuncDL<void(AVCodecParserContext*)>(dll_codec, "av_parser_close");
|
||||||
|
if (!av_parser_close_dl) {
|
||||||
|
LOG_ERROR(Audio_DSP, "Can not load function av_parser_close");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // _Win32
|
||||||
|
|
||||||
|
#if defined(__APPLE__) || defined(__linux__)
|
||||||
|
|
||||||
|
// No dynamic loading for Unix and Apple
|
||||||
|
|
||||||
|
const auto av_get_bytes_per_sample_dl = &av_get_bytes_per_sample;
|
||||||
|
const auto av_frame_alloc_dl = &av_frame_alloc;
|
||||||
|
const auto av_frame_free_dl = &av_frame_free;
|
||||||
|
const auto avcodec_alloc_context3_dl = &avcodec_alloc_context3;
|
||||||
|
const auto avcodec_free_context_dl = &avcodec_free_context;
|
||||||
|
const auto avcodec_open2_dl = &avcodec_open2;
|
||||||
|
const auto av_packet_alloc_dl = &av_packet_alloc;
|
||||||
|
const auto av_packet_free_dl = &av_packet_free;
|
||||||
|
const auto avcodec_find_decoder_dl = &avcodec_find_decoder;
|
||||||
|
const auto avcodec_send_packet_dl = &avcodec_send_packet;
|
||||||
|
const auto avcodec_receive_frame_dl = &avcodec_receive_frame;
|
||||||
|
const auto av_parser_init_dl = &av_parser_init;
|
||||||
|
const auto av_parser_parse2_dl = &av_parser_parse2;
|
||||||
|
const auto av_parser_close_dl = &av_parser_close;
|
||||||
|
|
||||||
|
bool InitFFmpegDL() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(__APPLE__) || defined(__linux__)
|
@ -3,7 +3,11 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "audio_core/audio_types.h"
|
#include "audio_core/audio_types.h"
|
||||||
|
#ifdef HAVE_FFMPEG
|
||||||
|
#include "audio_core/hle/aac_decoder.h"
|
||||||
|
#endif
|
||||||
#include "audio_core/hle/common.h"
|
#include "audio_core/hle/common.h"
|
||||||
|
#include "audio_core/hle/decoder.h"
|
||||||
#include "audio_core/hle/hle.h"
|
#include "audio_core/hle/hle.h"
|
||||||
#include "audio_core/hle/mixers.h"
|
#include "audio_core/hle/mixers.h"
|
||||||
#include "audio_core/hle/shared_memory.h"
|
#include "audio_core/hle/shared_memory.h"
|
||||||
@ -69,6 +73,8 @@ private:
|
|||||||
DspHle& parent;
|
DspHle& parent;
|
||||||
Core::TimingEventType* tick_event;
|
Core::TimingEventType* tick_event;
|
||||||
|
|
||||||
|
std::unique_ptr<HLE::DecoderBase> decoder;
|
||||||
|
|
||||||
std::weak_ptr<DSP_DSP> dsp_dsp;
|
std::weak_ptr<DSP_DSP> dsp_dsp;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -79,6 +85,13 @@ DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory) : parent(paren
|
|||||||
source.SetMemory(memory);
|
source.SetMemory(memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_FFMPEG
|
||||||
|
decoder = std::make_unique<HLE::AACDecoder>(memory);
|
||||||
|
#else
|
||||||
|
LOG_WARNING(Audio_DSP, "FFmpeg missing, this could lead to missing audio");
|
||||||
|
decoder = std::make_unique<HLE::NullDecoder>();
|
||||||
|
#endif // HAVE_FFMPEG
|
||||||
|
|
||||||
Core::Timing& timing = Core::System::GetInstance().CoreTiming();
|
Core::Timing& timing = Core::System::GetInstance().CoreTiming();
|
||||||
tick_event =
|
tick_event =
|
||||||
timing.RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) {
|
timing.RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) {
|
||||||
@ -215,6 +228,28 @@ void DspHle::Impl::PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer)
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case DspPipe::Binary: {
|
||||||
|
// TODO(B3N30): Make this async, and signal the interrupt
|
||||||
|
HLE::BinaryRequest request;
|
||||||
|
if (sizeof(request) != buffer.size()) {
|
||||||
|
LOG_CRITICAL(Audio_DSP, "got binary pipe with wrong size {}", buffer.size());
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::memcpy(&request, buffer.data(), buffer.size());
|
||||||
|
if (request.codec != HLE::DecoderCodec::AAC) {
|
||||||
|
LOG_CRITICAL(Audio_DSP, "got unknown codec {}", static_cast<u16>(request.codec));
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::optional<HLE::BinaryResponse> response = decoder->ProcessRequest(request);
|
||||||
|
if (response) {
|
||||||
|
const HLE::BinaryResponse& value = *response;
|
||||||
|
pipe_data[static_cast<u32>(pipe_number)].resize(sizeof(value));
|
||||||
|
std::memcpy(pipe_data[static_cast<u32>(pipe_number)].data(), &value, sizeof(value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
LOG_CRITICAL(Audio_DSP, "pipe_number = {} unimplemented",
|
LOG_CRITICAL(Audio_DSP, "pipe_number = {} unimplemented",
|
||||||
static_cast<std::size_t>(pipe_number));
|
static_cast<std::size_t>(pipe_number));
|
||||||
|
Loading…
Reference in New Issue
Block a user