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:
parent
b1638b31a0
commit
ea8a1f8754
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Reference in New Issue