Media Foundation Memory Fix

* audio_core: hle: mf: more smart pointers

* audio_core: hle: mf: fix memory leaks

* audio_core: hle: mf: even more smart pointers
This commit is contained in:
liushuyu 2019-01-14 14:27:43 -07:00 committed by B3N30
parent b1638b31a0
commit ea8a1f8754
3 changed files with 41 additions and 36 deletions

View file

@ -27,7 +27,7 @@ private:
Memory::MemorySystem& memory; Memory::MemorySystem& memory;
std::unique_ptr<IMFTransform, MFRelease<IMFTransform>> transform; unique_mfptr<IMFTransform> transform;
DWORD in_stream_id = 0; DWORD in_stream_id = 0;
DWORD out_stream_id = 0; DWORD out_stream_id = 0;
}; };
@ -108,14 +108,17 @@ int WMFDecoder::Impl::DecodingLoop(ADTSData adts_header,
MFOutputState output_status = OK; MFOutputState output_status = OK;
char* output_buffer = nullptr; char* output_buffer = nullptr;
DWORD output_len = 0; DWORD output_len = 0;
IMFSample* output = nullptr; DWORD tmp = 0;
// IMFSample* output_tmp = nullptr;
IMFMediaBuffer* mdbuf = nullptr;
unique_mfptr<IMFSample> output;
while (true) { while (true) {
output_status = ReceiveSample(transform.get(), out_stream_id, &output); auto [output_status, output] = ReceiveSample(transform.get(), out_stream_id);
// 0 -> okay; 3 -> okay but more data available (buffer too small) // 0 -> okay; 3 -> okay but more data available (buffer too small)
if (output_status == OK || output_status == HAVE_MORE_DATA) { if (output_status == OK || output_status == HAVE_MORE_DATA) {
CopySampleToBuffer(output, (void**)&output_buffer, &output_len); CopySampleToBuffer(output.get(), (void**)&output_buffer, &output_len);
// the following was taken from ffmpeg version of the decoder // the following was taken from ffmpeg version of the decoder
f32 val_f32; f32 val_f32;
@ -178,7 +181,7 @@ std::optional<BinaryResponse> WMFDecoder::Impl::Decode(const BinaryRequest& requ
u8* data = memory.GetFCRAMPointer(request.src_addr - Memory::FCRAM_PADDR); u8* data = memory.GetFCRAMPointer(request.src_addr - Memory::FCRAM_PADDR);
std::array<std::vector<u8>, 2> out_streams; std::array<std::vector<u8>, 2> out_streams;
IMFSample* sample = nullptr; unique_mfptr<IMFSample> sample;
ADTSData adts_header; ADTSData adts_header;
char* aac_tag = (char*)calloc(1, 14); char* aac_tag = (char*)calloc(1, 14);
int input_status = 0; int input_status = 0;
@ -202,11 +205,11 @@ std::optional<BinaryResponse> WMFDecoder::Impl::Decode(const BinaryRequest& requ
selected = true; selected = true;
} }
sample = CreateSample((void*)data, request.size, 1, 0); sample.reset(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); input_status = SendSample(transform.get(), in_stream_id, sample.get());
if (DecodingLoop(adts_header, out_streams) < 0) { if (DecodingLoop(adts_header, out_streams) < 0) {
// 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

View file

@ -79,7 +79,8 @@ void MFDeInit(IMFTransform* transform) {
IMFSample* CreateSample(void* data, DWORD len, DWORD alignment, LONGLONG duration) { IMFSample* CreateSample(void* data, DWORD len, DWORD alignment, LONGLONG duration) {
HRESULT hr = S_OK; HRESULT hr = S_OK;
IMFMediaBuffer* buf = nullptr; IMFMediaBuffer* buf_tmp = nullptr;
unique_mfptr<IMFMediaBuffer> buf;
IMFSample* sample = nullptr; IMFSample* sample = nullptr;
hr = MFCreateSample(&sample); hr = MFCreateSample(&sample);
@ -88,11 +89,12 @@ IMFSample* CreateSample(void* data, DWORD len, DWORD alignment, LONGLONG duratio
return nullptr; return nullptr;
} }
// 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); hr = MFCreateAlignedMemoryBuffer(len, alignment - 1, &buf_tmp);
if (FAILED(hr)) { if (FAILED(hr)) {
ReportError("Unable to allocate a memory buffer for sample", hr); ReportError("Unable to allocate a memory buffer for sample", hr);
return nullptr; return nullptr;
} }
buf.reset(buf_tmp);
if (data) { if (data) {
BYTE* buffer; BYTE* buffer;
// lock the MediaBuffer // lock the MediaBuffer
@ -100,7 +102,7 @@ IMFSample* CreateSample(void* data, DWORD len, DWORD alignment, LONGLONG duratio
hr = buf->Lock(&buffer, nullptr, nullptr); hr = buf->Lock(&buffer, nullptr, nullptr);
if (FAILED(hr)) { if (FAILED(hr)) {
SafeRelease(&sample); SafeRelease(&sample);
SafeRelease(&buf); buf.reset();
return nullptr; return nullptr;
} }
@ -110,9 +112,8 @@ IMFSample* CreateSample(void* data, DWORD len, DWORD alignment, LONGLONG duratio
buf->Unlock(); buf->Unlock();
} }
sample->AddBuffer(buf); sample->AddBuffer(buf.get());
hr = sample->SetSampleDuration(duration); hr = sample->SetSampleDuration(duration);
SafeRelease(&buf);
return sample; return sample;
} }
@ -260,59 +261,55 @@ int SendSample(IMFTransform* transform, DWORD in_stream_id, IMFSample* in_sample
return 0; return 0;
} }
MFOutputState ReceiveSample(IMFTransform* transform, DWORD out_stream_id, IMFSample** out_sample) { std::tuple<MFOutputState, unique_mfptr<IMFSample>> ReceiveSample(IMFTransform* transform,
DWORD out_stream_id) {
HRESULT hr; HRESULT hr;
MFT_OUTPUT_DATA_BUFFER out_buffers; MFT_OUTPUT_DATA_BUFFER out_buffers;
IMFSample* sample = nullptr; 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;
bool mft_create_sample = false; bool mft_create_sample = false;
if (!out_sample) {
ReportError("nullptr pointer passed to receive_sample()", MF_E_SAMPLE_NOT_WRITABLE);
return FATAL_ERROR;
}
hr = transform->GetOutputStreamInfo(out_stream_id, &out_info); hr = transform->GetOutputStreamInfo(out_stream_id, &out_info);
if (FAILED(hr)) { if (FAILED(hr)) {
ReportError("MFT: Failed to get stream info", hr); ReportError("MFT: Failed to get stream info", hr);
return FATAL_ERROR; return std::make_tuple(FATAL_ERROR, std::move(sample));
} }
mft_create_sample = (out_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) || mft_create_sample = (out_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) ||
(out_info.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES); (out_info.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES);
while (true) { while (true) {
sample = nullptr; sample = nullptr;
*out_sample = nullptr;
status = 0; status = 0;
if (!mft_create_sample) { if (!mft_create_sample) {
sample = CreateSample(nullptr, out_info.cbSize, out_info.cbAlignment); sample_tmp = CreateSample(nullptr, out_info.cbSize, out_info.cbAlignment);
if (!sample) { if (!sample_tmp) {
ReportError("MFT: Unable to allocate memory for samples", hr); ReportError("MFT: Unable to allocate memory for samples", hr);
return FATAL_ERROR; 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;
out_buffers.pSample = sample; out_buffers.pSample = sample.get();
hr = transform->ProcessOutput(0, 1, &out_buffers, &status); hr = transform->ProcessOutput(0, 1, &out_buffers, &status);
if (!FAILED(hr)) { if (!FAILED(hr)) {
*out_sample = out_buffers.pSample;
break; break;
} }
if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
// Most likely reasons: data corrupted; your actions not expected by MFT // Most likely reasons: data corrupted; your actions not expected by MFT
return NEED_MORE_INPUT; return std::make_tuple(NEED_MORE_INPUT, std::move(sample));
} }
if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
ReportError("MFT: stream format changed, re-configuration required", hr); ReportError("MFT: stream format changed, re-configuration required", hr);
return NEED_RECONFIG; return std::make_tuple(NEED_RECONFIG, std::move(sample));
} }
break; break;
@ -320,19 +317,19 @@ MFOutputState ReceiveSample(IMFTransform* transform, DWORD out_stream_id, IMFSam
if (out_buffers.dwStatus & MFT_OUTPUT_DATA_BUFFER_INCOMPLETE) { if (out_buffers.dwStatus & MFT_OUTPUT_DATA_BUFFER_INCOMPLETE) {
// this status is also unreliable but whatever // this status is also unreliable but whatever
return HAVE_MORE_DATA; return std::make_tuple(HAVE_MORE_DATA, std::move(sample));
} }
if (*out_sample == nullptr) { if (out_buffers.pSample == nullptr) {
ReportError("MFT: decoding failure", hr); ReportError("MFT: decoding failure", hr);
return FATAL_ERROR; return std::make_tuple(FATAL_ERROR, std::move(sample));
} }
return OK; return std::make_tuple(OK, std::move(sample));
} }
int CopySampleToBuffer(IMFSample* sample, void** output, DWORD* len) { int CopySampleToBuffer(IMFSample* sample, void** output, DWORD* len) {
std::unique_ptr<IMFMediaBuffer, MFRelease<IMFMediaBuffer>> buffer; unique_mfptr<IMFMediaBuffer> buffer;
IMFMediaBuffer* tmp; IMFMediaBuffer* tmp;
HRESULT hr = S_OK; HRESULT hr = S_OK;
BYTE* data; BYTE* data;
@ -343,14 +340,14 @@ int CopySampleToBuffer(IMFSample* sample, void** output, DWORD* len) {
return -1; return -1;
} }
sample->ConvertToContiguousBuffer(&tmp); hr = sample->ConvertToContiguousBuffer(&tmp);
if (FAILED(hr)) { if (FAILED(hr)) {
ReportError("Failed to get sample buffer", hr); ReportError("Failed to get sample buffer", hr);
return -1; return -1;
} }
buffer.reset(tmp); buffer.reset(tmp);
hr = buffer->Lock(&data, nullptr, nullptr); hr = tmp->Lock(&data, nullptr, nullptr);
if (FAILED(hr)) { if (FAILED(hr)) {
ReportError("Failed to lock the buffer", hr); ReportError("Failed to lock the buffer", hr);
return -1; return -1;

View file

@ -16,6 +16,7 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <tuple>
#include "adts.h" #include "adts.h"
@ -37,6 +38,9 @@ struct MFRelease {
}; };
}; };
template <typename T>
using unique_mfptr = std::unique_ptr<T, MFRelease<T>>;
void ReportError(std::string msg, HRESULT hr); void ReportError(std::string msg, HRESULT hr);
// exported functions // exported functions
@ -52,5 +56,6 @@ bool SelectOutputMediaType(IMFTransform* transform, int out_stream_id,
GUID audio_format = MFAudioFormat_PCM); GUID audio_format = MFAudioFormat_PCM);
void MFFlush(IMFTransform* transform); void MFFlush(IMFTransform* transform);
int SendSample(IMFTransform* transform, DWORD in_stream_id, IMFSample* in_sample); int SendSample(IMFTransform* transform, DWORD in_stream_id, IMFSample* in_sample);
MFOutputState ReceiveSample(IMFTransform* transform, DWORD out_stream_id, IMFSample** out_sample); std::tuple<MFOutputState, unique_mfptr<IMFSample>> ReceiveSample(IMFTransform* transform,
DWORD out_stream_id);
int CopySampleToBuffer(IMFSample* sample, void** output, DWORD* len); int CopySampleToBuffer(IMFSample* sample, void** output, DWORD* len);