Skip to content

Instantly share code, notes, and snippets.

@roxlu
Created May 31, 2016 17:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roxlu/d0fdc60486fd42dc117384a996c1989a to your computer and use it in GitHub Desktop.
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.
#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;
}
#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 */
#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