mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	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
					
				
					 3 changed files with 41 additions and 36 deletions
				
			
		|  | @ -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); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue