using namespace std;
using namespace cv;
+static mfxIMPL getImpl()
+{
+ static const size_t res = utils::getConfigurationParameterSizeT("OPENCV_VIDEOIO_MFX_IMPL", MFX_IMPL_AUTO_ANY);
+ return (mfxIMPL)res;
+}
+
+static size_t getExtraSurfaceNum()
+{
+ static const size_t res = cv::utils::getConfigurationParameterSizeT("OPENCV_VIDEOIO_MFX_EXTRA_SURFACE_NUM", 1);
+ return res;
+}
+
+static size_t getPoolTimeoutSec()
+{
+ static const size_t res = utils::getConfigurationParameterSizeT("OPENCV_VIDEOIO_MFX_POOL_TIMEOUT", 1);
+ return res;
+}
+
+//==================================================================================================
+
bool DeviceHandler::init(MFXVideoSession &session)
{
mfxStatus res = MFX_ERR_NONE;
- mfxIMPL impl = MFX_IMPL_AUTO_ANY;
+ mfxIMPL impl = getImpl();
mfxVersion ver = { {19, 1} };
res = session.Init(impl, &ver);
{
}
+SurfacePool * SurfacePool::_create(const mfxFrameAllocRequest &request, const mfxVideoParam ¶ms)
+{
+ return new SurfacePool(request.Info.Width,
+ request.Info.Height,
+ saturate_cast<ushort>((size_t)request.NumFrameSuggested + getExtraSurfaceNum()),
+ params.mfx.FrameInfo);
+}
+
mfxFrameSurface1 *SurfacePool::getFreeSurface()
{
- for(std::vector<mfxFrameSurface1>::iterator i = surfaces.begin(); i != surfaces.end(); ++i)
- if (!i->Data.Locked)
- return &(*i);
+ const int64 start = cv::getTickCount();
+ do
+ {
+ for(std::vector<mfxFrameSurface1>::iterator i = surfaces.begin(); i != surfaces.end(); ++i)
+ if (!i->Data.Locked)
+ return &(*i);
+ sleep_ms(10);
+ }
+ while((cv::getTickCount() - start) / cv::getTickFrequency() < getPoolTimeoutSec()); // seconds
+ DBG(cout << "No free surface!" << std::endl);
return 0;
}
#define MFXHELPER_H
#include "opencv2/core.hpp"
+#include "opencv2/core/utils/configuration.private.hpp"
#include <iostream>
#include <fstream>
DBG(std::cout << "MFX QueryIOSurf: " << res << std::endl);
if (res < MFX_ERR_NONE)
return 0;
- return new SurfacePool(request.Info.Width,
- request.Info.Height,
- request.NumFrameSuggested,
- params.mfx.FrameInfo);
+ return _create(request, params);
}
private:
+ static SurfacePool* _create(const mfxFrameAllocRequest& request, const mfxVideoParam& params);
+private:
SurfacePool(const SurfacePool &);
SurfacePool &operator=(const SurfacePool &);
public:
};
+// TODO: move to core::util?
+#ifdef CV_CXX11
+#include <thread>
+static void sleep_ms(int64 ms)
+{
+ std::this_thread::sleep_for(std::chrono::milliseconds(ms));
+}
+#elif defined(__linux__)
+#include <time.h>
+static void sleep_ms(int64 ms)
+{
+ nanosleep(ms * 1000 * 1000);
+}
+#elif defined _WIN32
+static void sleep_ms(int64 ms)
+{
+ Sleep(ms);
+}
+#else
+#error "Can not detect sleep_ms() implementation"
+#endif
+
+
// Linux specific
#ifdef __linux__
#ifdef _WIN32
#include <Windows.h>
-inline void sleep(unsigned long sec) { Sleep(1000 * sec); }
class DXHandle : public DeviceHandler {
public:
else if (res == MFX_WRN_DEVICE_BUSY)
{
DBG(cout << "Waiting for device" << endl);
- sleep(1);
+ sleep_ms(1000);
continue;
}
else if (res == MFX_WRN_VIDEO_PARAM_CHANGED)
using namespace std;
using namespace cv;
+static size_t getBitrateDivisor()
+{
+ static const size_t res = utils::getConfigurationParameterSizeT("OPENCV_VIDEOIO_MFX_BITRATE_DIVISOR", 300);
+ return res;
+}
+
+static mfxU32 getWriterTimeoutMS()
+{
+ static const size_t res = utils::getConfigurationParameterSizeT("OPENCV_VIDEOIO_MFX_WRITER_TIMEOUT", 1);
+ return saturate_cast<mfxU32>(res * 1000); // convert from seconds
+}
+
inline mfxU32 codecIdByFourCC(int fourcc)
{
const int CC_MPG2 = FourCC('M', 'P', 'G', '2').vali32;
memset(¶ms, 0, sizeof(params));
params.mfx.CodecId = codecId;
params.mfx.TargetUsage = MFX_TARGETUSAGE_BALANCED;
- params.mfx.TargetKbps = (mfxU16)cvRound(frameSize.area() * fps / 500); // TODO: set in options
+ params.mfx.TargetKbps = saturate_cast<mfxU16>((frameSize.area() * fps) / (42.6666 * getBitrateDivisor())); // TODO: set in options
params.mfx.RateControlMethod = MFX_RATECONTROL_VBR;
params.mfx.FrameInfo.FrameRateExtN = cvRound(fps * 1000);
params.mfx.FrameInfo.FrameRateExtD = 1000;
res = encoder->EncodeFrameAsync(NULL, workSurface, &bs->stream, &sync);
if (res == MFX_ERR_NONE)
{
- res = session->SyncOperation(sync, 1000); // 1 sec, TODO: provide interface to modify timeout
+ res = session->SyncOperation(sync, getWriterTimeoutMS()); // TODO: provide interface to modify timeout
if (res == MFX_ERR_NONE)
{
// ready to write
else if (res == MFX_WRN_DEVICE_BUSY)
{
DBG(cout << "Waiting for device" << endl);
- sleep(1);
+ sleep_ms(1000);
continue;
}
else