mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	audio_core: hle: mf: multiple fixes...
... more smart pointers and re-arrange code
This commit is contained in:
		
							parent
							
								
									4bc6bfd51f
								
							
						
					
					
						commit
						be764e4f88
					
				
					 5 changed files with 33 additions and 39 deletions
				
			
		|  | @ -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 { | ||||||
|  |  | ||||||
|  | @ -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, | ||||||
|  |  | ||||||
|  | @ -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
 | ||||||
|  |  | ||||||
|  | @ -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(); | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue