audio_core: hle: mf: multiple fixes...

... more smart pointers and re-arrange code
This commit is contained in:
liushuyu 2019-01-28 22:23:57 -07:00 committed by B3N30
parent 4bc6bfd51f
commit be764e4f88
5 changed files with 33 additions and 39 deletions

View file

@ -3,7 +3,6 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include <array>
#include "common/common_types.h" #include "common/common_types.h"
struct ADTSData { struct ADTSData {

View file

@ -1,6 +1,7 @@
// Copyright 2019 Citra Emulator Project // Copyright 2019 Citra Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <array>
#include "adts.h" #include "adts.h"
constexpr std::array<u32, 16> freq_table = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, constexpr std::array<u32, 16> freq_table = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,

View file

@ -20,7 +20,7 @@ private:
std::optional<BinaryResponse> Decode(const BinaryRequest& request); std::optional<BinaryResponse> Decode(const BinaryRequest& request);
int DecodingLoop(ADTSData adts_header, std::array<std::vector<u8>, 2>& out_streams); MFOutputState DecodingLoop(ADTSData adts_header, std::array<std::vector<u8>, 2>& out_streams);
bool initalized = false; bool initalized = false;
bool selected = false; bool selected = false;
@ -103,7 +103,7 @@ void WMFDecoder::Impl::Clear() {
selected = false; selected = false;
} }
int WMFDecoder::Impl::DecodingLoop(ADTSData adts_header, MFOutputState WMFDecoder::Impl::DecodingLoop(ADTSData adts_header,
std::array<std::vector<u8>, 2>& out_streams) { std::array<std::vector<u8>, 2>& out_streams) {
MFOutputState output_status = OK; MFOutputState output_status = OK;
char* output_buffer = nullptr; char* output_buffer = nullptr;
@ -138,12 +138,12 @@ int WMFDecoder::Impl::DecodingLoop(ADTSData adts_header,
// in case of "ok" only, just return quickly // in case of "ok" only, just return quickly
if (output_status == OK) if (output_status == OK)
return 0; return OK;
// for status = 2, reset MF // for status = 2, reset MF
if (output_status == NEED_RECONFIG) { if (output_status == NEED_RECONFIG) {
Clear(); Clear();
return -1; return FATAL_ERROR;
} }
// for status = 3, try again with new buffer // for status = 3, try again with new buffer
@ -151,12 +151,12 @@ int WMFDecoder::Impl::DecodingLoop(ADTSData adts_header,
continue; continue;
if (output_status == NEED_MORE_INPUT) // according to MS document, this is not an error (?!) if (output_status == NEED_MORE_INPUT) // according to MS document, this is not an error (?!)
return 1; return NEED_MORE_INPUT;
return -1; // return on other status return FATAL_ERROR; // return on other status
} }
return -1; return FATAL_ERROR;
} }
std::optional<BinaryResponse> WMFDecoder::Impl::Decode(const BinaryRequest& request) { std::optional<BinaryResponse> WMFDecoder::Impl::Decode(const BinaryRequest& request) {
@ -205,13 +205,13 @@ std::optional<BinaryResponse> WMFDecoder::Impl::Decode(const BinaryRequest& requ
selected = true; selected = true;
} }
sample.reset(CreateSample((void*)data, request.size, 1, 0)); sample = CreateSample((void*)data, request.size, 1, 0);
sample->SetUINT32(MFSampleExtension_CleanPoint, 1); sample->SetUINT32(MFSampleExtension_CleanPoint, 1);
while (true) { while (true) {
input_status = SendSample(transform.get(), in_stream_id, sample.get()); input_status = SendSample(transform.get(), in_stream_id, sample.get());
if (DecodingLoop(adts_header, out_streams) < 0) { if (DecodingLoop(adts_header, out_streams) == FATAL_ERROR) {
// if the decode issues are 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 // NOTICE: you are required to check the output even if you already knew/guessed
// MFT didn't accept the input sample // MFT didn't accept the input sample

View file

@ -77,17 +77,19 @@ void MFDeInit(IMFTransform* transform) {
CoUninitialize(); CoUninitialize();
} }
IMFSample* CreateSample(void* data, DWORD len, DWORD alignment, LONGLONG duration) { unique_mfptr<IMFSample> CreateSample(void* data, DWORD len, DWORD alignment, LONGLONG duration) {
HRESULT hr = S_OK; HRESULT hr = S_OK;
IMFMediaBuffer* buf_tmp = nullptr; IMFMediaBuffer* buf_tmp = nullptr;
unique_mfptr<IMFMediaBuffer> buf; unique_mfptr<IMFMediaBuffer> buf;
IMFSample* sample = nullptr; IMFSample* sample_tmp = nullptr;
unique_mfptr<IMFSample> sample;
hr = MFCreateSample(&sample); hr = MFCreateSample(&sample_tmp);
if (FAILED(hr)) { if (FAILED(hr)) {
ReportError("Unable to allocate a sample", hr); ReportError("Unable to allocate a sample", hr);
return nullptr; return nullptr;
} }
sample.reset(sample_tmp);
// Yes, the argument for alignment is the actual alignment - 1 // Yes, the argument for alignment is the actual alignment - 1
hr = MFCreateAlignedMemoryBuffer(len, alignment - 1, &buf_tmp); hr = MFCreateAlignedMemoryBuffer(len, alignment - 1, &buf_tmp);
if (FAILED(hr)) { if (FAILED(hr)) {
@ -101,12 +103,11 @@ IMFSample* CreateSample(void* data, DWORD len, DWORD alignment, LONGLONG duratio
// this is actually not a thread-safe lock // this is actually not a thread-safe lock
hr = buf->Lock(&buffer, nullptr, nullptr); hr = buf->Lock(&buffer, nullptr, nullptr);
if (FAILED(hr)) { if (FAILED(hr)) {
SafeRelease(&sample); ReportError("Unable to lock down MediaBuffer", hr);
buf.reset();
return nullptr; return nullptr;
} }
memcpy(buffer, data, len); std::memcpy(buffer, data, len);
buf->SetCurrentLength(len); buf->SetCurrentLength(len);
buf->Unlock(); buf->Unlock();
@ -114,7 +115,11 @@ IMFSample* CreateSample(void* data, DWORD len, DWORD alignment, LONGLONG duratio
sample->AddBuffer(buf.get()); sample->AddBuffer(buf.get());
hr = sample->SetSampleDuration(duration); hr = sample->SetSampleDuration(duration);
return sample; if (FAILED(hr)) {
ReportError("Unable to set sample duration, but continuing anyway", hr);
}
return std::move(sample);
} }
bool SelectInputMediaType(IMFTransform* transform, int in_stream_id, const ADTSData& adts, bool SelectInputMediaType(IMFTransform* transform, int in_stream_id, const ADTSData& adts,
@ -153,13 +158,15 @@ bool SelectInputMediaType(IMFTransform* transform, int in_stream_id, const ADTSD
bool SelectOutputMediaType(IMFTransform* transform, int out_stream_id, GUID audio_format) { bool SelectOutputMediaType(IMFTransform* transform, int out_stream_id, GUID audio_format) {
HRESULT hr = S_OK; HRESULT hr = S_OK;
UINT32 tmp; UINT32 tmp;
IMFMediaType* t; IMFMediaType* type;
unique_mfptr<IMFMediaType> t;
// If you know what you need and what you are doing, you can specify the condition instead of // If you know what you need and what you are doing, you can specify the condition instead of
// searching but it's better to use search since MFT may or may not support your output // searching but it's better to use search since MFT may or may not support your output
// parameters // parameters
for (DWORD i = 0;; i++) { for (DWORD i = 0;; i++) {
hr = transform->GetOutputAvailableType(out_stream_id, i, &t); hr = transform->GetOutputAvailableType(out_stream_id, i, &type);
t.reset(type);
if (hr == MF_E_NO_MORE_TYPES || hr == E_NOTIMPL) { if (hr == MF_E_NO_MORE_TYPES || hr == E_NOTIMPL) {
return true; return true;
} }
@ -180,7 +187,7 @@ bool SelectOutputMediaType(IMFTransform* transform, int out_stream_id, GUID audi
hr); hr);
return false; return false;
} }
hr = transform->SetOutputType(out_stream_id, t, 0); hr = transform->SetOutputType(out_stream_id, t.get(), 0);
if (FAILED(hr)) { if (FAILED(hr)) {
ReportError("failed to select output types for MFT", hr); ReportError("failed to select output types for MFT", hr);
return false; return false;
@ -221,8 +228,8 @@ int DetectMediaType(char* buffer, size_t len, ADTSData* output, char** aac_tag)
tag = MFGetAACTag(tmp); tag = MFGetAACTag(tmp);
aac_tmp[12] |= (tag & 0xff00) >> 8; aac_tmp[12] |= (tag & 0xff00) >> 8;
aac_tmp[13] |= (tag & 0x00ff); aac_tmp[13] |= (tag & 0x00ff);
memcpy(*aac_tag, aac_tmp, 14); std::memcpy(*aac_tag, aac_tmp, 14);
memcpy(output, &tmp, sizeof(ADTSData)); std::memcpy(output, &tmp, sizeof(ADTSData));
return 0; return 0;
} }
@ -250,8 +257,6 @@ int SendSample(IMFTransform* transform, DWORD in_stream_id, IMFSample* in_sample
} // FAILED(hr) } // FAILED(hr)
} else { } else {
hr = transform->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0); hr = transform->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
// ffmpeg: Some MFTs (AC3) will send a frame after each drain command (???), so
// ffmpeg: this is required to make draining actually terminate.
if (FAILED(hr)) { if (FAILED(hr)) {
ReportError("MFT: Failed to drain when processing input", hr); ReportError("MFT: Failed to drain when processing input", hr);
} }
@ -264,7 +269,6 @@ std::tuple<MFOutputState, unique_mfptr<IMFSample>> ReceiveSample(IMFTransform* t
DWORD out_stream_id) { DWORD out_stream_id) {
HRESULT hr; HRESULT hr;
MFT_OUTPUT_DATA_BUFFER out_buffers; MFT_OUTPUT_DATA_BUFFER out_buffers;
IMFSample* sample_tmp = nullptr;
MFT_OUTPUT_STREAM_INFO out_info; MFT_OUTPUT_STREAM_INFO out_info;
DWORD status = 0; DWORD status = 0;
unique_mfptr<IMFSample> sample; unique_mfptr<IMFSample> sample;
@ -280,16 +284,14 @@ std::tuple<MFOutputState, unique_mfptr<IMFSample>> ReceiveSample(IMFTransform* t
(out_info.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES); (out_info.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES);
while (true) { while (true) {
sample = nullptr;
status = 0; status = 0;
if (!mft_create_sample) { if (!mft_create_sample) {
sample_tmp = CreateSample(nullptr, out_info.cbSize, out_info.cbAlignment); sample = CreateSample(nullptr, out_info.cbSize, out_info.cbAlignment);
if (!sample_tmp) { if (!sample.get()) {
ReportError("MFT: Unable to allocate memory for samples", hr); ReportError("MFT: Unable to allocate memory for samples", hr);
return std::make_tuple(FATAL_ERROR, std::move(sample)); return std::make_tuple(FATAL_ERROR, std::move(sample));
} }
sample.reset(sample_tmp);
} }
out_buffers.dwStreamID = out_stream_id; out_buffers.dwStreamID = out_stream_id;
@ -353,7 +355,7 @@ int CopySampleToBuffer(IMFSample* sample, void** output, DWORD* len) {
} }
*output = malloc(*len); *output = malloc(*len);
memcpy(*output, data, *len); std::memcpy(*output, data, *len);
// if buffer unlock fails, then... whatever, we have already got data // if buffer unlock fails, then... whatever, we have already got data
buffer->Unlock(); buffer->Unlock();

View file

@ -20,14 +20,6 @@
enum MFOutputState { FATAL_ERROR = -1, OK = 0, NEED_MORE_INPUT, NEED_RECONFIG, HAVE_MORE_DATA }; enum MFOutputState { FATAL_ERROR = -1, OK = 0, NEED_MORE_INPUT, NEED_RECONFIG, HAVE_MORE_DATA };
// utility functions // utility functions
template <class T>
void SafeRelease(T** ppT) {
if (*ppT) {
(*ppT)->Release();
*ppT = nullptr;
}
}
template <class T> template <class T>
struct MFRelease { struct MFRelease {
void operator()(T* pointer) const { void operator()(T* pointer) const {
@ -44,7 +36,7 @@ void ReportError(std::string msg, HRESULT hr);
bool MFCoInit(); bool MFCoInit();
bool MFDecoderInit(IMFTransform** transform, GUID audio_format = MFAudioFormat_AAC); bool MFDecoderInit(IMFTransform** transform, GUID audio_format = MFAudioFormat_AAC);
void MFDeInit(IMFTransform* transform); void MFDeInit(IMFTransform* transform);
IMFSample* CreateSample(void* data, DWORD len, DWORD alignment = 1, LONGLONG duration = 0); unique_mfptr<IMFSample> CreateSample(void* data, DWORD len, DWORD alignment = 1, LONGLONG duration = 0);
bool SelectInputMediaType(IMFTransform* transform, int in_stream_id, const ADTSData& adts, bool SelectInputMediaType(IMFTransform* transform, int in_stream_id, const ADTSData& adts,
UINT8* user_data, UINT32 user_data_len, UINT8* user_data, UINT32 user_data_len,
GUID audio_format = MFAudioFormat_AAC); GUID audio_format = MFAudioFormat_AAC);