diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index 95f1fcf6e..937b0faee 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -28,7 +28,7 @@ add_library(audio_core STATIC $<$:sdl2_sink.cpp sdl2_sink.h> $<$:cubeb_sink.cpp cubeb_sink.h> $<$:hle/ffmpeg_decoder.cpp hle/ffmpeg_decoder.h hle/ffmpeg_dl.cpp hle/ffmpeg_dl.h> - $<$:hle/wmf_decoder.cpp hle/wmf_decoder.h hle/wmf_decoder_utils.cpp hle/wmf_decoder_utils.h hle/adts_reader.c> + $<$:hle/wmf_decoder.cpp hle/wmf_decoder.h hle/wmf_decoder_utils.cpp hle/wmf_decoder_utils.h hle/adts_reader.cpp> ) create_target_directory_groups(audio_core) diff --git a/src/audio_core/hle/adts.h b/src/audio_core/hle/adts.h index cba952a22..c806e2d82 100644 --- a/src/audio_core/hle/adts.h +++ b/src/audio_core/hle/adts.h @@ -1,20 +1,20 @@ +// Copyright 2019 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. #pragma once -#ifndef ADTS_ADT -#define ADTS_ADT -#include -#include -#include +#include +#include "common/common_types.h" struct ADTSData { bool MPEG2; - uint8_t profile; - uint8_t channels; - uint8_t channel_idx; - uint8_t framecount; - uint8_t samplerate_idx; - uint32_t length; - uint32_t samplerate; + u8 profile; + u8 channels; + u8 channel_idx; + u8 framecount; + u8 samplerate_idx; + u32 length; + u32 samplerate; }; typedef struct ADTSData ADTSData; @@ -22,10 +22,9 @@ typedef struct ADTSData ADTSData; #ifdef __cplusplus extern "C" { #endif // __cplusplus -uint32_t parse_adts(char* buffer, struct ADTSData* out); +u32 parse_adts(char* buffer, struct ADTSData* out); // last two bytes of MF AAC decoder user data -uint16_t mf_get_aac_tag(struct ADTSData input); +u16 mf_get_aac_tag(struct ADTSData input); #ifdef __cplusplus } #endif // __cplusplus -#endif // ADTS_ADT diff --git a/src/audio_core/hle/adts_reader.c b/src/audio_core/hle/adts_reader.cpp similarity index 70% rename from src/audio_core/hle/adts_reader.c rename to src/audio_core/hle/adts_reader.cpp index 7be57d4fc..ce3d1eda4 100644 --- a/src/audio_core/hle/adts_reader.c +++ b/src/audio_core/hle/adts_reader.cpp @@ -1,12 +1,14 @@ - +// Copyright 2019 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. #include "adts.h" -const uint32_t freq_table[16] = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, +constexpr std::array freq_table = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0}; -const short channel_table[8] = {0, 1, 2, 3, 4, 5, 6, 8}; +constexpr std::array channel_table = {0, 1, 2, 3, 4, 5, 6, 8}; -uint32_t parse_adts(char* buffer, struct ADTSData* out) { - uint32_t tmp = 0; +u32 parse_adts(char* buffer, struct ADTSData* out) { + u32 tmp = 0; // sync word 0xfff tmp = (buffer[0] << 8) | (buffer[1] & 0xf0); @@ -38,8 +40,8 @@ uint32_t parse_adts(char* buffer, struct ADTSData* out) { } // last two bytes of MF AAC decoder user data -uint16_t mf_get_aac_tag(struct ADTSData input) { - uint16_t tag = 0; +u16 mf_get_aac_tag(struct ADTSData input) { + u16 tag = 0; tag |= input.profile << 11; tag |= input.samplerate_idx << 7; diff --git a/src/audio_core/hle/wmf_decoder.cpp b/src/audio_core/hle/wmf_decoder.cpp index f612b8983..390ccd8dc 100644 --- a/src/audio_core/hle/wmf_decoder.cpp +++ b/src/audio_core/hle/wmf_decoder.cpp @@ -27,13 +27,13 @@ private: Memory::MemorySystem& memory; - IMFTransform* transform = NULL; + IMFTransform* transform = nullptr; DWORD in_stream_id = 0; DWORD out_stream_id = 0; }; WMFDecoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) { - mf_coinit(); + MFCoInit(); } WMFDecoder::Impl::~Impl() = default; @@ -46,7 +46,7 @@ std::optional WMFDecoder::Impl::ProcessRequest(const BinaryReque switch (request.cmd) { case DecoderCommand::Init: { - LOG_INFO(Audio_DSP, "AACDecoder initializing"); + LOG_INFO(Audio_DSP, "WMFDecoder initializing"); return Initalize(request); } case DecoderCommand::Decode: { @@ -73,7 +73,7 @@ std::optional WMFDecoder::Impl::Initalize(const BinaryRequest& r std::memcpy(&response, &request, sizeof(response)); response.unknown1 = 0x0; - if (mf_decoder_init(&transform) != 0) { + if (MFDecoderInit(&transform) != 0) { LOG_CRITICAL(Audio_DSP, "Can't init decoder"); return response; } @@ -95,8 +95,8 @@ std::optional WMFDecoder::Impl::Initalize(const BinaryRequest& r void WMFDecoder::Impl::Clear() { if (initalized) { - mf_flush(&transform); - mf_deinit(&transform); + MFFlush(&transform); + MFDeInit(&transform); } initalized = false; selected = false; @@ -105,16 +105,16 @@ void WMFDecoder::Impl::Clear() { int WMFDecoder::Impl::DecodingLoop(ADTSData adts_header, std::array, 2>& out_streams) { int output_status = 0; - char* output_buffer = NULL; + char* output_buffer = nullptr; DWORD output_len = 0; - IMFSample* output = NULL; + IMFSample* output = nullptr; while (true) { - output_status = receive_sample(transform, out_stream_id, &output); + output_status = ReceiveSample(transform, out_stream_id, &output); // 0 -> okay; 3 -> okay but more data available (buffer too small) if (output_status == 0 || output_status == 3) { - copy_sample_to_buffer(output, (void**)&output_buffer, &output_len); + CopySampleToBuffer(output, (void**)&output_buffer, &output_len); // the following was taken from ffmpeg version of the decoder f32 val_f32; @@ -174,12 +174,12 @@ std::optional WMFDecoder::Impl::Decode(const BinaryRequest& requ u8* data = memory.GetFCRAMPointer(request.src_addr - Memory::FCRAM_PADDR); std::array, 2> out_streams; - IMFSample* sample = NULL; + IMFSample* sample = nullptr; ADTSData adts_header; char* aac_tag = (char*)calloc(1, 14); int input_status = 0; - if (detect_mediatype((char*)data, request.size, &adts_header, &aac_tag) != 0) { + if (DetectMediaType((char*)data, request.size, &adts_header, &aac_tag) != 0) { LOG_ERROR(Audio_DSP, "Unable to deduce decoding parameters from ADTS stream"); return response; } @@ -187,23 +187,23 @@ std::optional WMFDecoder::Impl::Decode(const BinaryRequest& requ if (!selected) { LOG_DEBUG(Audio_DSP, "New ADTS stream: channels = {}, sample rate = {}", adts_header.channels, adts_header.samplerate); - select_input_mediatype(transform, in_stream_id, adts_header, (UINT8*)aac_tag, 14); - select_output_mediatype(transform, out_stream_id); - send_sample(transform, in_stream_id, NULL); + SelectInputMediaType(transform, in_stream_id, adts_header, (UINT8*)aac_tag, 14); + SelectOutputMediaType(transform, out_stream_id); + SendSample(transform, in_stream_id, nullptr); // cache the result from detect_mediatype and call select_*_mediatype only once // This could increase performance very slightly transform->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); selected = true; } - sample = create_sample((void*)data, request.size, 1, 0); + sample = CreateSample((void*)data, request.size, 1, 0); sample->SetUINT32(MFSampleExtension_CleanPoint, 1); while (true) { - input_status = send_sample(transform, in_stream_id, sample); + input_status = SendSample(transform, in_stream_id, sample); if (DecodingLoop(adts_header, out_streams) < 0) { - // if the decode issues is caused by MFT not accepting new samples, try again + // if the decode issues are caused by MFT not accepting new samples, try again // NOTICE: you are required to check the output even if you already knew/guessed // MFT didn't accept the input sample if (input_status == 1) { diff --git a/src/audio_core/hle/wmf_decoder_utils.cpp b/src/audio_core/hle/wmf_decoder_utils.cpp index 58b00505b..50a8a5554 100644 --- a/src/audio_core/hle/wmf_decoder_utils.cpp +++ b/src/audio_core/hle/wmf_decoder_utils.cpp @@ -1,3 +1,6 @@ +// Copyright 2019 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. #include "common/logging/log.h" #include "wmf_decoder_utils.h" @@ -9,17 +12,17 @@ void ReportError(std::string msg, HRESULT hr) { LPSTR err; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, hr, + nullptr, hr, // hardcode to use en_US because if any user had problems with this // we can help them w/o translating anything - MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPSTR)&err, 0, NULL); - if (err != NULL) { + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPSTR)&err, 0, nullptr); + if (err != nullptr) { LOG_CRITICAL(Audio_DSP, "{}: {}", msg, err); } LOG_CRITICAL(Audio_DSP, "{}: {:08x}", msg, hr); } -int mf_coinit() { +int MFCoInit() { HRESULT hr = S_OK; // lite startup is faster and all what we need is included @@ -35,7 +38,7 @@ int mf_coinit() { return 0; } -int mf_decoder_init(IMFTransform** transform, GUID audio_format) { +int MFDecoderInit(IMFTransform** transform, GUID audio_format) { HRESULT hr = S_OK; MFT_REGISTER_TYPE_INFO reg = {0}; GUID category = MFT_CATEGORY_AUDIO_DECODER; @@ -47,7 +50,7 @@ int mf_decoder_init(IMFTransform** transform, GUID audio_format) { hr = MFTEnumEx(category, MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_LOCALMFT | MFT_ENUM_FLAG_SORTANDFILTER, - ®, NULL, &activate, &num_activate); + ®, nullptr, &activate, &num_activate); if (FAILED(hr) || num_activate < 1) { ReportError("Failed to enumerate decoders", hr); CoTaskMemFree(activate); @@ -57,10 +60,10 @@ int mf_decoder_init(IMFTransform** transform, GUID audio_format) { for (unsigned int n = 0; n < num_activate; n++) { hr = activate[n]->ActivateObject(IID_IMFTransform, (void**)transform); if (FAILED(hr)) - *transform = NULL; + *transform = nullptr; activate[n]->Release(); } - if (*transform == NULL) { + if (*transform == nullptr) { ReportError("Failed to initialize MFT", hr); CoTaskMemFree(activate); return -1; @@ -69,37 +72,37 @@ int mf_decoder_init(IMFTransform** transform, GUID audio_format) { return 0; } -void mf_deinit(IMFTransform** transform) { +void MFDeInit(IMFTransform** transform) { MFShutdownObject(*transform); SafeRelease(transform); CoUninitialize(); } -IMFSample* create_sample(void* data, DWORD len, DWORD alignment, LONGLONG duration) { +IMFSample* CreateSample(void* data, DWORD len, DWORD alignment, LONGLONG duration) { HRESULT hr = S_OK; - IMFMediaBuffer* buf = NULL; - IMFSample* sample = NULL; + IMFMediaBuffer* buf = nullptr; + IMFSample* sample = nullptr; hr = MFCreateSample(&sample); if (FAILED(hr)) { ReportError("Unable to allocate a sample", hr); - return NULL; + return nullptr; } // Yes, the argument for alignment is the actual alignment - 1 hr = MFCreateAlignedMemoryBuffer(len, alignment - 1, &buf); if (FAILED(hr)) { ReportError("Unable to allocate a memory buffer for sample", hr); - return NULL; + return nullptr; } if (data) { BYTE* buffer; // lock the MediaBuffer // this is actually not a thread-safe lock - hr = buf->Lock(&buffer, NULL, NULL); + hr = buf->Lock(&buffer, nullptr, nullptr); if (FAILED(hr)) { SafeRelease(&sample); SafeRelease(&buf); - return NULL; + return nullptr; } memcpy(buffer, data, len); @@ -114,7 +117,7 @@ IMFSample* create_sample(void* data, DWORD len, DWORD alignment, LONGLONG durati return sample; } -int select_input_mediatype(IMFTransform* transform, int in_stream_id, ADTSData adts, +bool SelectInputMediaType(IMFTransform* transform, int in_stream_id, ADTSData adts, UINT8* user_data, UINT32 user_data_len, GUID audio_format) { HRESULT hr = S_OK; IMFMediaType* t; @@ -124,7 +127,7 @@ int select_input_mediatype(IMFTransform* transform, int in_stream_id, ADTSData a hr = MFCreateMediaType(&t); if (FAILED(hr)) { ReportError("Unable to create an empty MediaType", hr); - return -1; + return false; } // basic definition @@ -149,13 +152,13 @@ int select_input_mediatype(IMFTransform* transform, int in_stream_id, ADTSData a hr = transform->SetInputType(in_stream_id, t, 0); if (FAILED(hr)) { ReportError("failed to select input types for MFT", hr); - return -1; + return false; } - return 0; + return true; } -int select_output_mediatype(IMFTransform* transform, int out_stream_id, GUID audio_format) { +bool SelectOutputMediaType(IMFTransform* transform, int out_stream_id, GUID audio_format) { HRESULT hr = S_OK; UINT32 tmp; IMFMediaType* t; @@ -166,11 +169,11 @@ int select_output_mediatype(IMFTransform* transform, int out_stream_id, GUID aud for (DWORD i = 0;; i++) { hr = transform->GetOutputAvailableType(out_stream_id, i, &t); if (hr == MF_E_NO_MORE_TYPES || hr == E_NOTIMPL) { - return 0; + return true; } if (FAILED(hr)) { ReportError("failed to get output types for MFT", hr); - return -1; + return false; } hr = t->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &tmp); @@ -183,26 +186,26 @@ int select_output_mediatype(IMFTransform* transform, int out_stream_id, GUID aud if (FAILED(hr)) { ReportError("failed to set MF_MT_AUDIO_BLOCK_ALIGNMENT for MFT on output stream", hr); - return -1; + return false; } hr = transform->SetOutputType(out_stream_id, t, 0); if (FAILED(hr)) { ReportError("failed to select output types for MFT", hr); - return -1; + return false; } - return 0; + return true; } else { continue; } - return -1; + return false; } ReportError("MFT: Unable to find preferred output format", E_NOTIMPL); - return -1; + return false; } -int detect_mediatype(char* buffer, size_t len, ADTSData* output, char** aac_tag) { +int DetectMediaType(char* buffer, size_t len, ADTSData* output, char** aac_tag) { if (len < 7) { return -1; } @@ -224,7 +227,7 @@ int detect_mediatype(char* buffer, size_t len, ADTSData* output, char** aac_tag) return 0; } -int mf_flush(IMFTransform** transform) { +void MFFlush(IMFTransform** transform) { HRESULT hr = (*transform)->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0); if (FAILED(hr)) { ReportError("MFT: Flush command failed", hr); @@ -233,11 +236,9 @@ int mf_flush(IMFTransform** transform) { if (FAILED(hr)) { ReportError("Failed to end streaming for MFT", hr); } - - return 0; } -int send_sample(IMFTransform* transform, DWORD in_stream_id, IMFSample* in_sample) { +int SendSample(IMFTransform* transform, DWORD in_stream_id, IMFSample* in_sample) { HRESULT hr = S_OK; if (in_sample) { @@ -261,16 +262,16 @@ int send_sample(IMFTransform* transform, DWORD in_stream_id, IMFSample* in_sampl } // return: 0: okay; 1: needs more sample; 2: needs reconfiguring; 3: more data available -int receive_sample(IMFTransform* transform, DWORD out_stream_id, IMFSample** out_sample) { +int ReceiveSample(IMFTransform* transform, DWORD out_stream_id, IMFSample** out_sample) { HRESULT hr; MFT_OUTPUT_DATA_BUFFER out_buffers; - IMFSample* sample = NULL; + IMFSample* sample = nullptr; MFT_OUTPUT_STREAM_INFO out_info; DWORD status = 0; bool mft_create_sample = false; if (!out_sample) { - ReportError("NULL pointer passed to receive_sample()", MF_E_SAMPLE_NOT_WRITABLE); + ReportError("nullptr pointer passed to receive_sample()", MF_E_SAMPLE_NOT_WRITABLE); return -1; } @@ -284,12 +285,12 @@ int receive_sample(IMFTransform* transform, DWORD out_stream_id, IMFSample** out (out_info.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES); while (true) { - sample = NULL; - *out_sample = NULL; + sample = nullptr; + *out_sample = nullptr; status = 0; if (!mft_create_sample) { - sample = create_sample(NULL, out_info.cbSize, out_info.cbAlignment); + sample = CreateSample(nullptr, out_info.cbSize, out_info.cbAlignment); if (!sample) { ReportError("MFT: Unable to allocate memory for samples", hr); return -1; @@ -307,7 +308,7 @@ int receive_sample(IMFTransform* transform, DWORD out_stream_id, IMFSample** out } if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { - // TODO: better handling try again and EOF cases using drain value + // Most likely reasons: data corrupted; your actions not expected by MFT return 1; } @@ -320,11 +321,11 @@ int receive_sample(IMFTransform* transform, DWORD out_stream_id, IMFSample** out } if (out_buffers.dwStatus & MFT_OUTPUT_DATA_BUFFER_INCOMPLETE) { + // this status is also unreliable but whatever return 3; } - // TODO: better handling try again and EOF cases using drain value - if (*out_sample == NULL) { + if (*out_sample == nullptr) { ReportError("MFT: decoding failure", hr); return -1; } @@ -332,7 +333,7 @@ int receive_sample(IMFTransform* transform, DWORD out_stream_id, IMFSample** out return 0; } -int copy_sample_to_buffer(IMFSample* sample, void** output, DWORD* len) { +int CopySampleToBuffer(IMFSample* sample, void** output, DWORD* len) { IMFMediaBuffer* buffer; HRESULT hr = S_OK; BYTE* data; @@ -349,7 +350,7 @@ int copy_sample_to_buffer(IMFSample* sample, void** output, DWORD* len) { return -1; } - hr = buffer->Lock(&data, NULL, NULL); + hr = buffer->Lock(&data, nullptr, nullptr); if (FAILED(hr)) { ReportError("Failed to lock the buffer", hr); SafeRelease(&buffer); diff --git a/src/audio_core/hle/wmf_decoder_utils.h b/src/audio_core/hle/wmf_decoder_utils.h index ac7e522d7..128c30477 100644 --- a/src/audio_core/hle/wmf_decoder_utils.h +++ b/src/audio_core/hle/wmf_decoder_utils.h @@ -1,8 +1,9 @@ +// Copyright 2019 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. #pragma once -#ifndef MF_DECODER -#define MF_DECODER - +// AAC decoder related APIs are only available with WIN7+ #define WINVER _WIN32_WINNT_WIN7 #include @@ -23,26 +24,24 @@ template void SafeRelease(T** ppT) { if (*ppT) { (*ppT)->Release(); - *ppT = NULL; + *ppT = nullptr; } } void ReportError(std::string msg, HRESULT hr); // exported functions -int mf_coinit(); -int mf_decoder_init(IMFTransform** transform, GUID audio_format = MFAudioFormat_AAC); -void mf_deinit(IMFTransform** transform); -IMFSample* create_sample(void* data, DWORD len, DWORD alignment = 1, LONGLONG duration = 0); -int select_input_mediatype(IMFTransform* transform, int in_stream_id, ADTSData adts, +int MFCoInit(); +int MFDecoderInit(IMFTransform** transform, GUID audio_format = MFAudioFormat_AAC); +void MFDeInit(IMFTransform** transform); +IMFSample* CreateSample(void* data, DWORD len, DWORD alignment = 1, LONGLONG duration = 0); +bool SelectInputMediaType(IMFTransform* transform, int in_stream_id, ADTSData adts, UINT8* user_data, UINT32 user_data_len, GUID audio_format = MFAudioFormat_AAC); -int detect_mediatype(char* buffer, size_t len, ADTSData* output, char** aac_tag); -int select_output_mediatype(IMFTransform* transform, int out_stream_id, +int DetectMediaType(char* buffer, size_t len, ADTSData* output, char** aac_tag); +bool SelectOutputMediaType(IMFTransform* transform, int out_stream_id, GUID audio_format = MFAudioFormat_PCM); -int mf_flush(IMFTransform** transform); -int send_sample(IMFTransform* transform, DWORD in_stream_id, IMFSample* in_sample); -int receive_sample(IMFTransform* transform, DWORD out_stream_id, IMFSample** out_sample); -int copy_sample_to_buffer(IMFSample* sample, void** output, DWORD* len); - -#endif // MF_DECODER +void MFFlush(IMFTransform** transform); +int SendSample(IMFTransform* transform, DWORD in_stream_id, IMFSample* in_sample); +int ReceiveSample(IMFTransform* transform, DWORD out_stream_id, IMFSample** out_sample); +int CopySampleToBuffer(IMFSample* sample, void** output, DWORD* len); diff --git a/src/tests/audio_core/audio_fixures.h b/src/tests/audio_core/audio_fixures.h index 3035840a3..58147b6fd 100644 --- a/src/tests/audio_core/audio_fixures.h +++ b/src/tests/audio_core/audio_fixures.h @@ -1,5 +1,12 @@ -const int fixure_buffer_size = 41; -const unsigned char fixure_buffer[41] = { +// Copyright 2019 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once +#include + +constexpr int fixure_buffer_size = 41; +constexpr std::array fixure_buffer[41] = { 0xff, 0xf1, 0x4c, 0x80, 0x05, 0x3f, 0xfc, 0x21, 0x1a, 0x4e, 0xb0, 0x00, 0x00, 0x00, 0x05, 0xfc, 0x4e, 0x1f, 0x08, 0x88, 0x00, 0x00, 0x00, 0xc4, 0x1a, 0x03, 0xfc, 0x9c, 0x3e, 0x1d, 0x08, 0x84, 0x03, 0xd8, 0x3f, 0xe4, 0xe1, 0x20, 0x00, 0x0b, 0x38}; diff --git a/src/tests/audio_core/decoder_tests.cpp b/src/tests/audio_core/decoder_tests.cpp index 5a723c299..d8f31127d 100644 --- a/src/tests/audio_core/decoder_tests.cpp +++ b/src/tests/audio_core/decoder_tests.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright 2019 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #if defined(HAVE_MF) || defined(HAVE_FFMPEG)