Created
May 31, 2016 17:57
-
-
Save roxlu/d0fdc60486fd42dc117384a996c1989a to your computer and use it in GitHub Desktop.
Bare bone wip to encode using windows media foundation and intel hw-accel.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <poly/Log.h> | |
#include <VideoEncoderWindowsMediaFoundation.h> | |
using namespace poly; | |
int main() { | |
SX_VERBOSE("H264 Test"); | |
VideoEncoderWindowsMediaFoundation video_encoder; | |
if (0 != video_encoder.init()) { | |
exit(EXIT_FAILURE); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <comdef.h> | |
#include <poly/Log.h> | |
#include <VideoEncoderWindowsMediaFoundation.h> | |
namespace poly { | |
/* --------------------------------------------------------------- */ | |
static std::string hresult_to_string(HRESULT hr); | |
/* --------------------------------------------------------------- */ | |
VideoEncoderWindowsMediaFoundation::VideoEncoderWindowsMediaFoundation() | |
:transform(NULL) | |
{ | |
} | |
VideoEncoderWindowsMediaFoundation::~VideoEncoderWindowsMediaFoundation() { | |
shutdown(); | |
} | |
int VideoEncoderWindowsMediaFoundation::init() { | |
HRESULT hr = S_OK; | |
int r = 0; | |
GUID clsid = { 0 }; | |
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); | |
if (false == SUCCEEDED(hr)) { | |
SX_ERROR("Failed to init COM."); | |
r = -10; | |
goto error; | |
} | |
hr = MFStartup(MF_VERSION); | |
if (false == SUCCEEDED(hr)) { | |
SX_ERROR("Failed to startup MF."); | |
r = -15; | |
goto error; | |
} | |
if (0 != findAndActivateHardwareEncoder(&transform, clsid)) { | |
SX_ERROR("Failed to find a hardware encoder."); | |
r = -20; | |
goto error; | |
} | |
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&transform)); | |
if (false == SUCCEEDED(hr)) { | |
SX_ERROR("Failed to create the transform object: %s", hresult_to_string(hr).c_str()); | |
r = -30; | |
goto error; | |
} | |
error: | |
if (r < 0) { | |
shutdown(); | |
} | |
return r; | |
} | |
int VideoEncoderWindowsMediaFoundation::shutdown() { | |
HRESULT hr = S_OK; | |
int r = 0; | |
if (NULL != transform) { | |
SX_ERROR("Should cleanup transform. (exiting)"); | |
exit(EXIT_FAILURE); | |
} | |
hr = MFShutdown(); | |
if (false == SUCCEEDED(hr)) { | |
SX_ERROR("Failed to shutdown MF."); | |
r -= 10; | |
} | |
return 0; | |
} | |
/* --------------------------------------------------------------- */ | |
int VideoEncoderWindowsMediaFoundation::findAndActivateHardwareEncoder(IMFTransform** tf, GUID& guid) { | |
int r = 0; | |
HRESULT hr = S_OK; | |
UINT32 flags = 0; | |
UINT32 count = 0; | |
UINT32 i = 0; | |
IMFActivate** result = NULL; | |
IMFActivate* activate = NULL; | |
IMFActivate* found_activate = NULL; | |
MFT_REGISTER_TYPE_INFO info = { MFMediaType_Video, MFVideoFormat_H264 }; | |
flags |= MFT_ENUM_FLAG_LOCALMFT; | |
flags |= MFT_ENUM_FLAG_TRANSCODE_ONLY; | |
flags |= MFT_ENUM_FLAG_SYNCMFT; | |
flags |= MFT_ENUM_FLAG_ASYNCMFT; | |
flags |= MFT_ENUM_FLAG_HARDWARE; | |
if (NULL == tf) { | |
SX_ERROR("Given output transform is NULL."); | |
r = -5; | |
goto error; | |
} | |
if (NULL != (*tf)) { | |
SX_ERROR("Given output transform ptr is not NULL. Already initialized?"); | |
r = -7; | |
goto error; | |
} | |
hr = MFTEnumEx(MFT_CATEGORY_VIDEO_ENCODER, flags, NULL, &info, &result, &count); | |
if (false == SUCCEEDED(hr)) { | |
SX_ERROR("Failed to enumerate hardware video encoders."); | |
r = -10; | |
goto error; | |
} | |
if (NULL == result) { | |
SX_ERROR("Result is NULL."); | |
r = -20; | |
goto error; | |
} | |
for (i = 0; i < count; ++i) { | |
activate = result[i]; | |
flags = 0; | |
hr = activate->GetUINT32(MF_TRANSFORM_FLAGS_Attribute, &flags); | |
if (false == SUCCEEDED(hr)) { | |
SX_ERROR("Activation Object %u does not expose flags.", i); | |
continue; | |
} | |
if (MFT_ENUM_FLAG_ASYNCMFT == (flags & MFT_ENUM_FLAG_ASYNCMFT)) { | |
SX_DEBUG("Activation Object %u supports async operation.", i); | |
} | |
if (MFT_ENUM_FLAG_SYNCMFT == (flags & MFT_ENUM_FLAG_SYNCMFT)) { | |
SX_DEBUG("Activation Object %u supports sync operation.", i); | |
} | |
if (MFT_ENUM_FLAG_HARDWARE == (flags & MFT_ENUM_FLAG_HARDWARE)) { | |
SX_DEBUG("Activation Object %u supports hardware encoding.", i); | |
found_activate = activate; | |
break; | |
} | |
} | |
if (NULL == found_activate) { | |
SX_ERROR("We did not find a hardware encoder."); | |
r = -20; | |
goto error; | |
} | |
#if 0 | |
hr = found_activate->ActivateObject(IID_IMFTransform, (void**)tf); | |
//hr = found_activate->ActivateObject(IID_PPV_ARGS(tf)); | |
if (false == SUCCEEDED(hr)) { | |
_com_error err(hr); | |
LPCTSTR errmsg = err.ErrorMessage(); | |
SX_ERROR("Failed to create the transform: %s (%08X)", errmsg, hr); | |
r = -30; | |
goto error; | |
} | |
#endif | |
hr = found_activate->GetGUID(MFT_TRANSFORM_CLSID_Attribute, &guid); | |
if (false == SUCCEEDED(hr)) { | |
SX_ERROR("Failed to retrieve the CLSID attribute from the activation object."); | |
r = -40; | |
goto error; | |
} | |
{ | |
SX_VERBOSE("Guid = {%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}", | |
guid.Data1, guid.Data2, guid.Data3, | |
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], | |
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); | |
} | |
error: | |
for (i = 0; i < count; ++i) { | |
result[i]->ShutdownObject(); | |
result[i]->Release(); | |
} | |
if (NULL != result) { | |
CoTaskMemFree(result); | |
result = NULL; | |
} | |
return r; | |
} | |
/* --------------------------------------------------------------- */ | |
static std::string hresult_to_string(HRESULT hr) { | |
_com_error err(hr); | |
LPCTSTR errmsg = err.ErrorMessage(); | |
std::string msg(errmsg); | |
return msg; | |
} | |
/* --------------------------------------------------------------- */ | |
} /* namespace poly */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef POLY_VIDEO_ENCODER_WINDOWS_MEDIA_FOUNDATION_H | |
#define POLY_VIDEO_ENCODER_WINDOWS_MEDIA_FOUNDATION_H | |
#include <Objbase.h> /* CoInitialize(), CoCreateInstance(). */ | |
#include <Mftransform.h> /* IMFTransform. */ | |
#include <Mfapi.h> /* MFTEnumEx(). */ | |
#include <Codecapi.h> | |
namespace poly { | |
class VideoEncoderWindowsMediaFoundation { | |
public: | |
VideoEncoderWindowsMediaFoundation(); | |
~VideoEncoderWindowsMediaFoundation(); | |
int init(); | |
int shutdown(); | |
private: | |
int findAndActivateHardwareEncoder(IMFTransform** tf, GUID& guid); | |
private: | |
IMFTransform* transform; | |
}; | |
} /* namespace poly */ | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment