| // Copyright (c) 2010 The WebM project authors. All Rights Reserved. | |
| // | |
| // Use of this source code is governed by a BSD-style license | |
| // that can be found in the LICENSE file in the root of the source | |
| // tree. An additional intellectual property rights grant can be found | |
| // in the file PATENTS. All contributing project authors may | |
| // be found in the AUTHORS file in the root of the source tree. | |
| #include <windows.h> | |
| #include <windowsx.h> | |
| #include <comdef.h> | |
| #include <mfapi.h> | |
| #include <mferror.h> | |
| #include <mfidl.h> | |
| #include <string> | |
| #include "debugutil.hpp" | |
| #include "comdllwrapper.hpp" | |
| #include "eventutil.hpp" | |
| #include "hrtext.hpp" | |
| #include "memutil.hpp" | |
| #include "mftranswrap.hpp" | |
| #include "mfutil.hpp" | |
| namespace WebmMfUtil | |
| { | |
| HRESULT MfTransformWrapper::CreateInstance(std::wstring dll_path, | |
| GUID mfobj_clsid, | |
| MfTransformWrapper** ptr_instance) | |
| { | |
| if (dll_path.empty() || GUID_NULL == mfobj_clsid) | |
| { | |
| return E_INVALIDARG; | |
| } | |
| MfTransformWrapper* ptr_wrapper = new (std::nothrow) MfTransformWrapper(); | |
| if (!ptr_wrapper) | |
| { | |
| return E_OUTOFMEMORY; | |
| } | |
| HRESULT hr = ptr_wrapper->Create_(dll_path, mfobj_clsid); | |
| if (SUCCEEDED(hr)) | |
| { | |
| *ptr_instance = ptr_wrapper; | |
| ptr_wrapper->AddRef(); | |
| } | |
| else | |
| { | |
| DBGLOG("ERROR, Create_ failed" << HRLOG(hr)); | |
| } | |
| return hr; | |
| } | |
| HRESULT MfTransformWrapper::QueryInterface(REFIID, void**) | |
| { | |
| return E_NOTIMPL; | |
| } | |
| ULONG MfTransformWrapper::AddRef() | |
| { | |
| return InterlockedIncrement(&ref_count_); | |
| } | |
| ULONG MfTransformWrapper::Release() | |
| { | |
| UINT ref_count = InterlockedDecrement(&ref_count_); | |
| if (ref_count == 0) | |
| { | |
| delete this; | |
| } | |
| return ref_count; | |
| } | |
| MfTransformWrapper::MfTransformWrapper(): | |
| ptr_transform_dll_(NULL), | |
| ref_count_(0), | |
| buf_size_(0) | |
| { | |
| } | |
| MfTransformWrapper::~MfTransformWrapper() | |
| { | |
| } | |
| HRESULT MfTransformWrapper::Create_(std::wstring dll_path, GUID mfobj_clsid) | |
| { | |
| HRESULT hr = ComDllWrapper::Create(dll_path, mfobj_clsid, | |
| &ptr_transform_dll_); | |
| if (FAILED(hr) || !ptr_transform_dll_) | |
| { | |
| DBGLOG("ComDllWrapper::Create failed path=" << dll_path.c_str() | |
| << HRLOG(hr)); | |
| return hr; | |
| } | |
| hr = ptr_transform_dll_->CreateInstance(IID_IMFTransform, | |
| reinterpret_cast<void**>(&ptr_transform_)); | |
| if (FAILED(hr) || !ptr_transform_) | |
| { | |
| DBGLOG("GetInterfacePtr failed" << HRLOG(hr)); | |
| return hr; | |
| } | |
| return hr; | |
| } | |
| HRESULT MfTransformWrapper::GetInputType(IMFMediaType** ptr_type) const | |
| { | |
| return copy_media_type(ptr_input_type_, ptr_type); | |
| } | |
| HRESULT MfTransformWrapper::GetOutputType(IMFMediaType** ptr_type) const | |
| { | |
| return copy_media_type(ptr_output_type_, ptr_type); | |
| } | |
| HRESULT MfTransformWrapper::SetInputType(IMFMediaTypePtr& ptr_type) | |
| { | |
| if (!ptr_transform_) | |
| { | |
| DBGLOG("ERROR, transform obj not created, E_INVALIDARG"); | |
| return E_INVALIDARG; | |
| } | |
| if (!ptr_type) | |
| { | |
| DBGLOG("ERROR, media type required, E_INVALIDARG"); | |
| return E_INVALIDARG; | |
| } | |
| HRESULT hr; | |
| hr = ptr_transform_->SetInputType(0, ptr_type, 0); | |
| if (FAILED(hr)) | |
| { | |
| DBGLOG("IMFTransform::SetInputType failed" << HRLOG(hr)); | |
| return hr; | |
| } | |
| ptr_input_type_ = ptr_type; | |
| return hr; | |
| } | |
| HRESULT MfTransformWrapper::SetOutputType(IMFMediaTypePtr& ptr_type) | |
| { | |
| if (!ptr_transform_) | |
| { | |
| DBGLOG("ERROR, transform obj not created, E_INVALIDARG"); | |
| return E_INVALIDARG; | |
| } | |
| HRESULT hr; | |
| if (!ptr_type) | |
| { | |
| hr = ptr_transform_->GetOutputAvailableType(0, 0, &ptr_type); | |
| if (FAILED(hr)) | |
| { | |
| DBGLOG("GetOutputAvailableType failed" << HRLOG(hr)); | |
| return hr; | |
| } | |
| } | |
| hr = ptr_transform_->SetOutputType(0, ptr_type, 0); | |
| if (FAILED(hr)) | |
| { | |
| DBGLOG("IMFTransform::SetOutputType failed" << HRLOG(hr)); | |
| return hr; | |
| } | |
| ptr_output_type_ = ptr_type; | |
| // TODO(tomfinegan): relocate |ptr_transform_buffer_| setup | |
| MFT_OUTPUT_STREAM_INFO stream_info = {0}; | |
| CHK(hr, ptr_transform_->GetOutputStreamInfo(0, &stream_info)); | |
| if (FAILED(hr)) | |
| { | |
| return hr; | |
| } | |
| buf_size_ = stream_info.cbSize; | |
| CHK(hr, MFCreateMemoryBuffer((DWORD)buf_size_, &ptr_buf_)); | |
| return hr; | |
| } | |
| HRESULT MfTransformWrapper::Transform(IMFSample* ptr_in_sample, | |
| IMFSample** ptr_out_sample) | |
| { | |
| if (!ptr_in_sample) | |
| { | |
| DBGLOG("ERROR, NULL sample, E_INVALIDARG"); | |
| return E_INVALIDARG; | |
| } | |
| HRESULT hr; | |
| CHK(hr, ptr_transform_->ProcessInput(0, ptr_in_sample, 0)); | |
| if (FAILED(hr)) | |
| { | |
| return hr; | |
| } | |
| IMFSamplePtr output_sample; | |
| CHK(hr, MFCreateSample(&output_sample)); | |
| if (FAILED(hr)) | |
| { | |
| return hr; | |
| } | |
| CHK(hr, output_sample->AddBuffer(ptr_buf_)); | |
| if (FAILED(hr)) | |
| { | |
| return hr; | |
| } | |
| MFT_OUTPUT_DATA_BUFFER mf_sample_buffer = {0}; | |
| mf_sample_buffer.pSample = output_sample; | |
| // can't use CHK: MF_E_TRANSFORM_NEEDS_MORE_INPUT is an expected error, and | |
| // we don't want lies about that being an error in debugging output | |
| hr = ptr_transform_->ProcessOutput(0, 1, &mf_sample_buffer, NULL); | |
| if (MF_E_TRANSFORM_NEED_MORE_INPUT == hr) | |
| { | |
| // caller must discard the input sample: the MFT now owns it | |
| return S_FALSE; | |
| } | |
| if (SUCCEEDED(hr)) | |
| { | |
| *ptr_out_sample = output_sample.Detach(); | |
| } | |
| return hr; | |
| } | |
| } // WebmMfUtil namespace |