Skip to content

Instantly share code, notes, and snippets.

@roxlu
Last active November 6, 2015 17:41
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/e7ef81b14d285069c719 to your computer and use it in GitHub Desktop.
Save roxlu/e7ef81b14d285069c719 to your computer and use it in GitHub Desktop.
CoCreateInstance for Intel Quick Sync MFT fails.
1. Download these files
2. Make sure you have Visual Studio installed (I'm testing with 2015 community edition)
3. Make sure you have CMake installed
4. Open an Command Prompt, go to the directory with the downloaded files:
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=../install ..
cmake --build . --target install
5. Then execute the created file 'install/test_h264_encoding.exe'
cmake_minimum_required(VERSION 2.8)
project(h264encoding)
set(bd ${CMAKE_CURRENT_LIST_DIR})
set(sd ${bd})
set(id ${bd})
include_directories(
${id}
)
set(lib_sources
${sd}/VideoEncoderMediaFoundation.cpp
${sd}/Log.cpp
)
set(app_libs
Mfplat.lib
Mfuuid.lib
)
add_library(encoding ${lib_sources})
add_executable(test_h264_encoding ${sd}/test_h264_encoding.cpp)
target_link_libraries(test_h264_encoding encoding ${app_libs})
add_dependencies(test_h264_encoding encoding)
install(TARGETS test_h264_encoding DESTINATION bin)
#include <Log.h>
#include <sstream>
#if defined(_WIN32)
# include <stdarg.h>
# include <time.h>
# include <Winsock2.h>
#elif defined(__linux)
# include <stdarg.h>
# include <sys/time.h>
#else
# include <sys/time.h>
#endif
#if defined(__APPLE__)
# include <TargetConditionals.h>
#endif
namespace poly {
Log poly_log;
int poly_log_initialized_flag = -1;
/* --------------------------------------------------------------------------------- */
/* @todo - cleanup the if()s around the ofs file writes. */
Log::Log()
:write_to_stdout(true)
,write_to_file(true)
,use_colors(true)
,level(SX_LOG_LEVEL_ALL)
{
#if defined(_WIN32)
console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
#endif
}
Log::~Log() {
if (ofs.is_open()) {
ofs.close();
}
write_to_stdout = false;
write_to_file = false;
use_colors = false;
}
int Log::open(std::string filep) {
if (false == write_to_file) {
return 0;
}
if (0 != filepath.size()) {
printf("Error: trying to open the log file but it's already open? Calling poly_log_init() twice?\n");
return -1;
}
filepath = filep;
if (0 == filepath.size()) {
printf("Error: cannot open the log filepath because the string is empty.\n");
return -2;
}
ofs.open(filepath.c_str(), std::ios::out | std::ios::app);
if (!ofs.is_open()) {
printf("Error: cannot open the log file. No permission? %s\n", filepath.c_str());
return -3;
}
return 0;
}
void Log::log(int inlevel, int line, const char* function, const char* fmt, va_list args) {
if (inlevel > level) {
return;
}
static char buffer[1024 * 8]; /* should be big enough ;-) */
std::string slevel;
std::stringstream ss_stdout;
std::string color_msg_open;
std::string color_info_open;
std::string color_close;
if (true == write_to_file) {
if (false == ofs.is_open()) {
printf("Error: cannot log because the file hasn't been opened. Did you call poly_log_init()?\n");
return;
}
}
/* Get the date-time string. */
#if defined(_WIN32)
int milli = (int)GetTickCount();
#else
timeval miltime;
gettimeofday(&miltime, NULL);
int milli = miltime.tv_usec / 1000;
#endif
time_t t;
struct tm* info;
char time_buf[256];
time(&t);
info = localtime(&t);
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", info);
sprintf(time_buf, "%s.%03d", time_buf, milli);
std::string time_str(time_buf);
/* default colors. */
#if defined(_WIN32) || TARGET_OS_IPHONE
color_close = "";
color_info_open = "";
#else
if (true == use_colors) {
color_close = "\e[0m";
color_info_open = "\e[90m";
}
#endif
vsprintf(buffer, fmt, args);
if (write_to_file) {
ofs << time_str << " " ;
}
if (inlevel == SX_LOG_LEVEL_DEBUG) {
slevel = " debug ";
#if !defined(_WIN32) && !TARGET_OS_IPHONE
if (true == use_colors) {
color_msg_open = "\e[36m";
}
#endif
if (write_to_file) {
ofs << slevel;
}
}
else if (inlevel == SX_LOG_LEVEL_VERBOSE) {
slevel = " verbose ";
if (write_to_file) {
ofs << slevel;
}
#if !defined(_WIN32) && !TARGET_OS_IPHONE
if (true == use_colors) {
color_msg_open = "\e[92m";
}
#endif
}
else if (inlevel == SX_LOG_LEVEL_WARNING) {
slevel = " warning ";
#if !defined(_WIN32) && !TARGET_OS_IPHONE
if (true == use_colors) {
color_msg_open = "\e[93m";
}
#endif
if (write_to_file) {
ofs << slevel;
}
}
else if (inlevel == SX_LOG_LEVEL_ERROR) {
slevel = " <<ERROR>> ";
#if !defined(_WIN32) && !TARGET_OS_IPHONE
if (true == use_colors) {
color_msg_open = "\e[31m";
}
#endif
if (write_to_file) {
ofs << slevel;
}
}
if (write_to_file) {
ofs << " [" << function << ":" << line << "] = " << buffer << "\n";
}
if (write_to_stdout) {
#if 0
ss << time_str << ":"
<< slevel
<< "[" << function << ":" << line << "]"
<< " = " << buffer
<< std::endl;
#endif
#if defined(_WIN32)
SetConsoleTextAttribute(console_handle, 8);
printf("%s%10.10s[%90.90s:%03d]: ",
time_str.c_str(),
slevel.c_str(),
function,
line);
if (SX_LOG_LEVEL_DEBUG == inlevel) {
SetConsoleTextAttribute(console_handle, 11);
}
else if (SX_LOG_LEVEL_VERBOSE == inlevel) {
SetConsoleTextAttribute(console_handle, 10);
}
else if (SX_LOG_LEVEL_WARNING == inlevel) {
SetConsoleTextAttribute(console_handle, 14);
}
else if (SX_LOG_LEVEL_ERROR == inlevel) {
SetConsoleTextAttribute(console_handle, 12);
}
else {
SetConsoleTextAttribute(console_handle, 11);;
}
printf("%s\n", buffer);
SetConsoleTextAttribute(console_handle, 7);
#else
printf("%s %s %15s [%80.80s : %03d]: %s %s %s\n",
color_info_open.c_str(),
time_str.c_str(),
slevel.c_str(),
function,
line,
color_msg_open.c_str(),
buffer,
color_close.c_str());
/*
ss_stdout << color_info_open
<< time_str << ":"
<< slevel
<< "[" << function << ":" << line << "]"
<< " = "
<< color_msg_open
<< buffer
<< color_close
<< std::endl;
*/
//printf("%s", ss_stdout.str().c_str());
#endif
}
if (write_to_file) {
ofs.flush();
}
}
/* --------------------------------------------------------------------------------- */
int poly_log_init(std::string path) {
std::stringstream ss;
std::string filepath = "";
char buf[4096];
time_t t;
struct tm* info;
time(&t);
info = localtime(&t);
strftime(buf, 4096, "%Y.%m.%d", info);
if (0 == path.size()) {
filepath = "./";
}
else {
filepath = path +"/";
}
ss << filepath << "log-" << buf << ".log";
filepath = ss.str();
poly_log_initialized_flag = poly_log.open(filepath);
return poly_log_initialized_flag;
}
int poly_log_is_initialized() {
return poly_log_initialized_flag;
}
void poly_log_disable_stdout() {
poly_log.write_to_stdout = false;
}
void poly_log_enable_stdout() {
poly_log.write_to_stdout = false;
}
void poly_log_enable_colors() {
poly_log.use_colors = true;
}
void poly_log_disable_colors() {
poly_log.use_colors = false;
}
void poly_log_disable_log_to_file() {
poly_log.write_to_file = false;
}
void poly_log_enable_log_to_file() {
poly_log.write_to_file = true;
}
void poly_log_set_level(int level) {
poly_log.level = level;
}
int poly_log_get_level() {
return poly_log.level;
}
void poly_debug(int line, const char* function, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
poly_log.log(SX_LOG_LEVEL_DEBUG, line, function, fmt, args);
va_end(args);
}
void poly_verbose(int line, const char* function, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
poly_log.log(SX_LOG_LEVEL_VERBOSE, line, function, fmt, args);
va_end(args);
}
void poly_warning(int line, const char* function, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
poly_log.log(SX_LOG_LEVEL_WARNING, line, function, fmt, args);
va_end(args);
}
void poly_error(int line, const char* function, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
poly_log.log(SX_LOG_LEVEL_ERROR, line, function, fmt, args);
va_end(args);
}
} /* namespace poly */
/* -*-c++-*- */
/*
Log
===
A simple logger which can write into a file and/or to
the console. Supports colored output on all major platforms
Window, Mac and Linux.
To remove all logs features you can define `SX_DISABLE_LOG`
when compiling. This will add a couple of nop macros for
SX_DEBUG, SX_VERBOSE, SX_WARNING and SX_ERROR.
On Windows we can use 0-255 different colors, 0-14 define colors
with a black background that we prefer, these colors are:
- 0 Black
- 1 Dark blue
- 2 Dark green
- 3 Dark cyan
- 4 Dark red
- 5 Dark purple
- 6 Dark brown
- 7 White
- 8 Gray
- 9 Blue
- 10 Green
- 11 Cyan
- 12 Red
- 13 Purple
- 14 Yellow
*/
#ifndef POLY_LOG_H
#define POLY_LOG_H
#include <string>
#include <fstream>
#if defined(_WIN32)
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif
#define SX_LOG_LEVEL_ALL 5
#define SX_LOG_LEVEL_ERROR 1
#define SX_LOG_LEVEL_WARNING 2
#define SX_LOG_LEVEL_VERBOSE 3
#define SX_LOG_LEVEL_DEBUG 4
#if defined(SX_DISABLE_LOG)
# define SX_DEBUG(fmt, ...) { }
# define SX_VERBOSE(fmt, ...) { }
# define SX_WARNING(fmt, ...) { }
# define SX_ERROR(fmt, ...) { }
#else
# if defined(_MSC_VER)
# define SX_DEBUG(fmt, ...) { poly::poly_debug(__LINE__, __FUNCSIG__, fmt, ##__VA_ARGS__); }
# define SX_VERBOSE(fmt, ...) { poly::poly_verbose(__LINE__, __FUNCSIG__, fmt, ##__VA_ARGS__); }
# define SX_WARNING(fmt, ...) { poly::poly_warning(__LINE__, __FUNCSIG__, fmt, ##__VA_ARGS__); }
# define SX_ERROR(fmt, ...) { poly::poly_error(__LINE__, __FUNCSIG__, fmt, ##__VA_ARGS__); }
# else
# define SX_DEBUG(fmt, ...) { poly::poly_debug(__LINE__, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__); }
# define SX_VERBOSE(fmt, ...) { poly::poly_verbose(__LINE__, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__); }
# define SX_WARNING(fmt, ...) { poly::poly_warning(__LINE__, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__); }
# define SX_ERROR(fmt, ...) { poly::poly_error(__LINE__, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__); }
# endif
#endif
/* --------------------------------------------------------------------------------- */
namespace poly {
/* Debug control */
int poly_log_init(std::string path = "");
int poly_log_is_initialized();
void poly_log_disable_stdout();
void poly_log_enable_stdout();
void poly_log_disable_log_to_file();
void poly_log_enable_log_to_file();
void poly_log_disable_colors();
void poly_log_enable_colors();
void poly_log_set_level(int level);
int poly_log_get_level();
/* Debug wrappers. */
void poly_debug(int line, const char* function, const char* fmt, ...);
void poly_verbose(int line, const char* function, const char* fmt, ...);
void poly_warning(int line, const char* function, const char* fmt, ...);
void poly_error(int line, const char* function, const char* fmt, ...);
/* --------------------------------------------------------------------------------- */
class Log {
public:
Log();
~Log();
int open(std::string filepath); /* Open the log with the give filepath. */
void log(int level, /* Log something at the given level. */
int line, /* Refers to the line in the source code. */
const char* function, /* Funcion that logged the message. */
const char* fmt, /* We use printf() like formats. */
va_list args); /* Variable arguments. */
public:
bool write_to_stdout; /* Write output also to stdout. */
bool write_to_file; /* Write log to file. */
bool use_colors; /* Use colored output. */
int level; /* What level we should log. */
private:
std::string filepath; /* Filepath where we save the log file. */
std::ofstream ofs; /* The output file stream */
#if defined(_WIN32)
HANDLE console_handle; /* On Windows we get a handle to the console, so we can change the colors of the output. */
#endif
};
/* --------------------------------------------------------------------------------- */
extern Log poly_log;
extern int poly_log_initialized_flag;
} /* namespace poly */
#endif
#!/bin/sh
if [ ! -d build.release ] ; then
mkdir build.release
fi
cd build.release
cmake -DCMAKE_INSTALL_PREFIX=${PWD}/../install \
-DPOLY_DIR=${PWD}/../../../polytrope/ \
../
if [ $? -ne 0 ] ; then
exit
fi
cmake --build . --target install
if [ $? -ne 0 ] ; then
exit
fi
cd ../install/bin
./test_h264_encoding
#include <stdio.h>
#include <stdlib.h>
#include <Log.h>
#include <VideoEncoderMediaFoundation.h>
using namespace poly;
int main() {
poly_log_init();
SX_VERBOSE("test h264 encoding.");
VideoEncoderMediaFoundation mft;
mft.init();
return 0;
}
#include <VideoEncoderMediaFoundation.h>
#include <Log.h>
namespace poly {
static std::string hresult_to_string(HRESULT hr);
VideoEncoderMediaFoundation::VideoEncoderMediaFoundation()
:transform(NULL)
{
}
VideoEncoderMediaFoundation::~VideoEncoderMediaFoundation() {
}
int VideoEncoderMediaFoundation::init() {
int r = 0;
HRESULT hr = S_OK;
GUID clsid = { 0 } ;
DWORD num_in_streams = 0;
DWORD num_out_streams = 0;
if (NULL != transform) {
SX_ERROR("Cannot initialize, transform is not NULL.");
return -1;
}
/* Initialize COM and create the transform object. */
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (false == SUCCEEDED(hr)) {
SX_ERROR("Failed to initialize COM.");
r = -1;
goto error;
}
if (0 != findHardwareEncoder(clsid)) {
r = -2;
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, err: %08X", hresult_to_string(hr).c_str(), hr);
r = -3;
goto error;
}
hr = transform->GetStreamCount(&num_in_streams, &num_out_streams);
if (false == SUCCEEDED(hr)) {
SX_ERROR("Failed to retrieve the standard num in/out streams.");
r = -4;
goto error;
}
if (1 != num_in_streams) {
SX_ERROR("Number of input stream is not 1. This should be 1.");
r = -5;
goto error;
}
error:
if (r < 0) {
shutdown();
}
return r;
}
int VideoEncoderMediaFoundation::shutdown() {
if (NULL != transform) {
SX_ERROR("Releaes the transformm.");
}
return 0;
}
/* Set to 1 to print the name of the found encoder. */
#define VEMF_PRINT_NAME 1
int VideoEncoderMediaFoundation::findHardwareEncoder(GUID& guid) {
bool is_async = false;
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 };
#if VEMF_PRINT_NAME
WCHAR guid_str[40] = { 0 } ;
UINT32 name_len = 0;
LPWSTR friendly_name = NULL;
#endif
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;
hr = MFTEnumEx(MFT_CATEGORY_VIDEO_ENCODER, flags, NULL, &info, &result, &count);
if (false == SUCCEEDED(hr)) {
SX_ERROR("Failed to enumerate video encoders. None present?");
return -1;
}
if (NULL == result) {
SX_ERROR("Result is NULL. Not supposed to happen.");
return -2;
}
SX_VERBOSE("Found %lu encoders.", count);
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 VEMF_PRINT_NAME
hr = activate->GetAllocatedString(MFT_FRIENDLY_NAME_Attribute, &friendly_name, &name_len);
if (false == SUCCEEDED(hr)) {
SX_ERROR("Failed to retrieve the friendly name.");
}
else {
SX_VERBOSE("Got a name: %S len: %lu", friendly_name, name_len);
CoTaskMemFree(friendly_name);
}
#endif
if ( (flags & MFT_ENUM_FLAG_HARDWARE) == MFT_ENUM_FLAG_HARDWARE) {
SX_VERBOSE("%lu supports hardware encoding.", i);
found_activate = activate;
break;
}
#if 0
if ( (flags & MFT_ENUM_FLAG_ASYNCMFT) == MFT_ENUM_FLAG_ASYNCMFT) {
SX_VERBOSE("%u is async.", i);
is_async = true;
}
if ( (flags & MFT_ENUM_FLAG_SYNCMFT) == MFT_ENUM_FLAG_SYNCMFT) {
SX_VERBOSE("%u is sync.", i);
is_async = false;
}
#endif
}
if (NULL == found_activate) {
SX_ERROR("We did not find an suitable activation object.");
r = -3;
goto error;
}
hr = found_activate->GetGUID(MFT_TRANSFORM_CLSID_Attribute, &guid);
if (false == SUCCEEDED(hr)) {
SX_ERROR("Failed to retreive the CLSID attribute from the activation object.");
r = -5;
goto error;
}
#if VEMF_PRINT_NAME
if (0 == StringFromGUID2(guid, guid_str, 40)) {
SX_ERROR("Buffer to small.");
}
else {
SX_VERBOSE("Found GUID: %S", guid_str);
}
#endif
error:
for (i = 0; i < count; ++i) {
result[i]->Release();
}
CoTaskMemFree(result);
result = NULL;
return r;
}
static std::string hresult_to_string(HRESULT hr) {
switch(hr) {
case S_OK: { return "S_OK"; }
case E_FAIL: { return "E_FAIL"; }
case REGDB_E_CLASSNOTREG: { return "REGDB_E_CLASSNOTREG"; }
case CLASS_E_NOAGGREGATION: { return "CLASS_E_NOAGGREGATION"; }
case E_NOINTERFACE: { return "E_NOINTERFACE"; }
case E_POINTER: { return "E_POINTER"; }
default: { return "UNKNOWN"; }
}
}
} /* namespace poly */
/*
Windows Media Transform H264 Encoder
=====================================
0: https://msdn.microsoft.com/en-us/library/windows/desktop/aa965264(v=vs.85).aspx "Basic Processing Model"
1: https://msdn.microsoft.com/en-us/library/windows/desktop/ms698983(v=vs.85).aspx "Activation Objects"
2: https://msdn.microsoft.com/en-us/library/windows/desktop/dd940330(v=vs.85).aspx "Hardware MFTs - info on async data processing."
*/
#ifndef POLY_VIDEO_ENCODER_MEDIA_FOUNDATION_H
#define POLY_VIDEO_ENCODER_MEDIA_FOUNDATION_H
#include <Objbase.h> /* CoInitialize(), CoCreateInstance(). */
#include <Mftransform.h> /* IMFTransform */
#include <Mfapi.h> /* MFTEnumEx(). */
#include <Codecapi.h>
namespace poly {
class VideoEncoderMediaFoundation {
public:
VideoEncoderMediaFoundation();
~VideoEncoderMediaFoundation();
int init();
int shutdown();
private:
int findHardwareEncoder(GUID& result);
public:
IMFTransform* transform;
};
} /* namespace poly */
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment