blob: 9519de4421a87d0ea675f6d4f734cf636cc676d2 [file] [log] [blame]
// 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.h"
#include "comdllwrapper.h"
#include "eventutil.h"
#include "hrtext.h"
#include "memutil.h"
#include "mftranswrap.h"
#include "mfutil.h"
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