mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +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; | ||||
| 
 | ||||
|     std::unique_ptr<IMFTransform, MFRelease<IMFTransform>> transform; | ||||
|     unique_mfptr<IMFTransform> transform; | ||||
|     DWORD in_stream_id = 0; | ||||
|     DWORD out_stream_id = 0; | ||||
| }; | ||||
|  | @ -108,14 +108,17 @@ int WMFDecoder::Impl::DecodingLoop(ADTSData adts_header, | |||
|     MFOutputState output_status = OK; | ||||
|     char* output_buffer = nullptr; | ||||
|     DWORD output_len = 0; | ||||
|     IMFSample* output = nullptr; | ||||
|     DWORD tmp = 0; | ||||
|     // IMFSample* output_tmp = nullptr;
 | ||||
|     IMFMediaBuffer* mdbuf = nullptr; | ||||
|     unique_mfptr<IMFSample> output; | ||||
| 
 | ||||
|     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)
 | ||||
|         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
 | ||||
|             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); | ||||
| 
 | ||||
|     std::array<std::vector<u8>, 2> out_streams; | ||||
|     IMFSample* sample = nullptr; | ||||
|     unique_mfptr<IMFSample> sample; | ||||
|     ADTSData adts_header; | ||||
|     char* aac_tag = (char*)calloc(1, 14); | ||||
|     int input_status = 0; | ||||
|  | @ -202,11 +205,11 @@ std::optional<BinaryResponse> WMFDecoder::Impl::Decode(const BinaryRequest& requ | |||
|         selected = true; | ||||
|     } | ||||
| 
 | ||||
|     sample = CreateSample((void*)data, request.size, 1, 0); | ||||
|     sample.reset(CreateSample((void*)data, request.size, 1, 0)); | ||||
|     sample->SetUINT32(MFSampleExtension_CleanPoint, 1); | ||||
| 
 | ||||
|     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 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) { | ||||
|     HRESULT hr = S_OK; | ||||
|     IMFMediaBuffer* buf = nullptr; | ||||
|     IMFMediaBuffer* buf_tmp = nullptr; | ||||
|     unique_mfptr<IMFMediaBuffer> buf; | ||||
|     IMFSample* sample = nullptr; | ||||
| 
 | ||||
|     hr = MFCreateSample(&sample); | ||||
|  | @ -88,11 +89,12 @@ IMFSample* CreateSample(void* data, DWORD len, DWORD alignment, LONGLONG duratio | |||
|         return nullptr; | ||||
|     } | ||||
|     // 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)) { | ||||
|         ReportError("Unable to allocate a memory buffer for sample", hr); | ||||
|         return nullptr; | ||||
|     } | ||||
|     buf.reset(buf_tmp); | ||||
|     if (data) { | ||||
|         BYTE* buffer; | ||||
|         // lock the MediaBuffer
 | ||||
|  | @ -100,7 +102,7 @@ IMFSample* CreateSample(void* data, DWORD len, DWORD alignment, LONGLONG duratio | |||
|         hr = buf->Lock(&buffer, nullptr, nullptr); | ||||
|         if (FAILED(hr)) { | ||||
|             SafeRelease(&sample); | ||||
|             SafeRelease(&buf); | ||||
|             buf.reset(); | ||||
|             return nullptr; | ||||
|         } | ||||
| 
 | ||||
|  | @ -110,9 +112,8 @@ IMFSample* CreateSample(void* data, DWORD len, DWORD alignment, LONGLONG duratio | |||
|         buf->Unlock(); | ||||
|     } | ||||
| 
 | ||||
|     sample->AddBuffer(buf); | ||||
|     sample->AddBuffer(buf.get()); | ||||
|     hr = sample->SetSampleDuration(duration); | ||||
|     SafeRelease(&buf); | ||||
|     return sample; | ||||
| } | ||||
| 
 | ||||
|  | @ -260,59 +261,55 @@ int SendSample(IMFTransform* transform, DWORD in_stream_id, IMFSample* in_sample | |||
|     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; | ||||
|     MFT_OUTPUT_DATA_BUFFER out_buffers; | ||||
|     IMFSample* sample = nullptr; | ||||
|     IMFSample* sample_tmp = nullptr; | ||||
|     MFT_OUTPUT_STREAM_INFO out_info; | ||||
|     DWORD status = 0; | ||||
|     unique_mfptr<IMFSample> sample; | ||||
|     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); | ||||
| 
 | ||||
|     if (FAILED(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) || | ||||
|                         (out_info.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES); | ||||
| 
 | ||||
|     while (true) { | ||||
|         sample = nullptr; | ||||
|         *out_sample = nullptr; | ||||
|         status = 0; | ||||
| 
 | ||||
|         if (!mft_create_sample) { | ||||
|             sample = CreateSample(nullptr, out_info.cbSize, out_info.cbAlignment); | ||||
|             if (!sample) { | ||||
|             sample_tmp = CreateSample(nullptr, out_info.cbSize, out_info.cbAlignment); | ||||
|             if (!sample_tmp) { | ||||
|                 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.pSample = sample; | ||||
|         out_buffers.pSample = sample.get(); | ||||
| 
 | ||||
|         hr = transform->ProcessOutput(0, 1, &out_buffers, &status); | ||||
| 
 | ||||
|         if (!FAILED(hr)) { | ||||
|             *out_sample = out_buffers.pSample; | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { | ||||
|             // 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) { | ||||
|             ReportError("MFT: stream format changed, re-configuration required", hr); | ||||
|             return NEED_RECONFIG; | ||||
|             return std::make_tuple(NEED_RECONFIG, std::move(sample)); | ||||
|         } | ||||
| 
 | ||||
|         break; | ||||
|  | @ -320,19 +317,19 @@ MFOutputState ReceiveSample(IMFTransform* transform, DWORD out_stream_id, IMFSam | |||
| 
 | ||||
|     if (out_buffers.dwStatus & MFT_OUTPUT_DATA_BUFFER_INCOMPLETE) { | ||||
|         // 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); | ||||
|         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) { | ||||
|     std::unique_ptr<IMFMediaBuffer, MFRelease<IMFMediaBuffer>> buffer; | ||||
|     unique_mfptr<IMFMediaBuffer> buffer; | ||||
|     IMFMediaBuffer* tmp; | ||||
|     HRESULT hr = S_OK; | ||||
|     BYTE* data; | ||||
|  | @ -343,14 +340,14 @@ int CopySampleToBuffer(IMFSample* sample, void** output, DWORD* len) { | |||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     sample->ConvertToContiguousBuffer(&tmp); | ||||
|     hr = sample->ConvertToContiguousBuffer(&tmp); | ||||
|     if (FAILED(hr)) { | ||||
|         ReportError("Failed to get sample buffer", hr); | ||||
|         return -1; | ||||
|     } | ||||
|     buffer.reset(tmp); | ||||
| 
 | ||||
|     hr = buffer->Lock(&data, nullptr, nullptr); | ||||
|     hr = tmp->Lock(&data, nullptr, nullptr); | ||||
|     if (FAILED(hr)) { | ||||
|         ReportError("Failed to lock the buffer", hr); | ||||
|         return -1; | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ | |||
| 
 | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #include <tuple> | ||||
| 
 | ||||
| #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); | ||||
| 
 | ||||
| // exported functions
 | ||||
|  | @ -52,5 +56,6 @@ bool SelectOutputMediaType(IMFTransform* transform, int out_stream_id, | |||
|                            GUID audio_format = MFAudioFormat_PCM); | ||||
| void MFFlush(IMFTransform* transform); | ||||
| 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); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue