OCV_OPTION(WITH_MATLAB "Include Matlab support" ON IF (NOT ANDROID AND NOT IOS AND NOT WINRT))
OCV_OPTION(WITH_VA "Include VA support" OFF IF (UNIX AND NOT ANDROID) )
OCV_OPTION(WITH_VA_INTEL "Include Intel VA-API/OpenCL support" OFF IF (UNIX AND NOT ANDROID) )
+OCV_OPTION(WITH_MFX "Include Intel Media SDK support" OFF IF (UNIX AND NOT ANDROID) )
OCV_OPTION(WITH_GDAL "Include GDAL Support" OFF IF (NOT ANDROID AND NOT IOS AND NOT WINRT) )
OCV_OPTION(WITH_GPHOTO2 "Include gPhoto2 library support" ON IF (UNIX AND NOT ANDROID) )
OCV_OPTION(WITH_LAPACK "Include Lapack library support" ON IF (NOT ANDROID AND NOT IOS) )
status(" Intel PerC:" HAVE_INTELPERC THEN "YES" ELSE NO)
endif(DEFINED WITH_INTELPERC)
+if(DEFINED WITH_MFX)
+ status(" Intel Media SDK:" HAVE_MFX THEN "YES (${MFX_LIBRARY})" ELSE NO)
+endif()
+
if(DEFINED WITH_GPHOTO2)
status(" gPhoto2:" HAVE_GPHOTO2 THEN "YES" ELSE NO)
endif(DEFINED WITH_GPHOTO2)
--- /dev/null
+set(root "$ENV{MFX_HOME}")
+
+find_path(MFX_INCLUDE mfxdefs.h PATHS "${root}/include" NO_DEFAULT_PATH)
+
+# TODO: ICC? MINGW? ARM? IOS?
+if(WIN32)
+ if(X86_64)
+ set(arch "x64")
+ else()
+ set(arch "win32")
+ endif()
+elseif(UNIX)
+ set(arch "lin_x64")
+else()
+ # ???
+endif()
+
+find_library(MFX_LIBRARY mfx PATHS "${root}/lib/${arch}" NO_DEFAULT_PATH)
+find_library(MFX_VA_LIBRARY va)
+find_library(MFX_VA_DRM_LIBRARY va-drm)
+
+if(MFX_INCLUDE AND MFX_LIBRARY AND MFX_VA_LIBRARY AND MFX_VA_DRM_LIBRARY)
+ add_library(mfx-va UNKNOWN IMPORTED)
+ set_target_properties(mfx-va PROPERTIES IMPORTED_LOCATION "${MFX_VA_LIBRARY}")
+
+ add_library(mfx-va-drm UNKNOWN IMPORTED)
+ set_target_properties(mfx-va-drm PROPERTIES IMPORTED_LOCATION "${MFX_VA_DRM_LIBRARY}")
+
+ add_library(mfx UNKNOWN IMPORTED)
+ set_target_properties(mfx PROPERTIES
+ IMPORTED_LOCATION "${MFX_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${MFX_INCLUDE}"
+ INTERFACE_LINK_LIBRARIES "mfx-va;mfx-va-drm;-Wl,--exclude-libs=libmfx"
+ )
+ set(HAVE_MFX 1)
+else()
+ set(HAVE_MFX 0)
+endif()
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVFindIntelPerCSDK.cmake")
endif(WITH_INTELPERC)
+if(WITH_MFX)
+ include("${OpenCV_SOURCE_DIR}/cmake/OpenCVDetectMediaSDK.cmake")
+endif()
+
# --- gPhoto2 ---
ocv_clear_vars(HAVE_GPHOTO2)
if(WITH_GPHOTO2)
/* Intel VA-API/OpenCL */
#cmakedefine HAVE_VA_INTEL
+/* Intel Media SDK */
+#cmakedefine HAVE_MFX
+
/* Lapack */
#cmakedefine HAVE_LAPACK
${CMAKE_CURRENT_LIST_DIR}/src/cap_winrt/MediaStreamSink.hpp)
endif()
+if(HAVE_MFX)
+ list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_mfx_common.cpp)
+ list(APPEND videoio_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/cap_mfx_common.hpp)
+ list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_mfx_reader.cpp)
+ list(APPEND videoio_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/cap_mfx_reader.hpp)
+ list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_mfx_writer.cpp)
+ list(APPEND videoio_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/cap_mfx_writer.hpp)
+ list(APPEND VIDEOIO_LIBRARIES mfx)
+endif()
+
if(WIN32 AND NOT ARM)
list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_cmu.cpp)
endif()
CAP_FFMPEG = 1900, //!< Open and record video file or stream using the FFMPEG library
CAP_IMAGES = 2000, //!< OpenCV Image Sequence (e.g. img_%02d.jpg)
CAP_ARAVIS = 2100, //!< Aravis SDK
- CAP_OCV_MJPEG = 2200 //!< Built-in MotionJPEG codec
+ CAP_OCV_MJPEG = 2200, //!< Built-in MotionJPEG codec
+ CAP_INTEL_MFX = 2300 //!< Intel MediaSDK
};
/** @brief %VideoCapture generic properties identifier.
#include "cap_intelperc.hpp"
#include "cap_dshow.hpp"
+#ifdef HAVE_MFX
+#include "cap_mfx_reader.hpp"
+#include "cap_mfx_writer.hpp"
+#endif
+
// All WinRT versions older than 8.0 should provide classes used for video support
#if defined(WINRT) && !defined(WINRT_8_0) && defined(__cplusplus_winrt)
# include "cap_winrt_capture.hpp"
#ifdef HAVE_GPHOTO2
CV_CAP_GPHOTO2,
#endif
+#ifdef HAVE_MFX
+ CAP_INTEL_MFX,
+#endif
-1, -1
};
capture = createGPhoto2Capture(filename);
break;
#endif
+#ifdef HAVE_MFX
+ case CAP_INTEL_MFX:
+ capture = makePtr<VideoCapture_IntelMFX>(filename);
+ break;
+#endif
}
if (capture && capture->isOpened())
static Ptr<IVideoWriter> IVideoWriter_create(int apiPreference, const String& filename, int _fourcc, double fps, Size frameSize, bool isColor)
{
Ptr<IVideoWriter> iwriter;
+#ifdef HAVE_MFX
+ if (apiPreference == CAP_INTEL_MFX || apiPreference == CAP_ANY)
+ {
+ iwriter = VideoWriter_IntelMFX::create(filename, _fourcc, fps, frameSize, isColor);
+ if (!iwriter.empty())
+ return iwriter;
+ }
+#endif
+
if( (apiPreference == CAP_OCV_MJPEG || apiPreference == CAP_ANY)
&& _fourcc == CV_FOURCC('M', 'J', 'P', 'G') )
iwriter = createMotionJpegWriter(filename, fps, frameSize, isColor);
+
return iwriter;
}
--- /dev/null
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html
+
+#include "cap_mfx_common.hpp"
+
+// Linux specific
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+using namespace std;
+using namespace cv;
+
+bool DeviceHandler::init(MFXVideoSession &session)
+{
+ mfxStatus res = MFX_ERR_NONE;
+ mfxIMPL impl = MFX_IMPL_AUTO;
+ mfxVersion ver = { {19, 1} };
+
+ res = session.Init(impl, &ver);
+ DBG(cout << "MFX SessionInit: " << res << endl);
+
+ res = session.QueryIMPL(&impl);
+ DBG(cout << "MFX QueryIMPL: " << res << " => " << asHex(impl) << endl);
+
+ res = session.QueryVersion(&ver);
+ DBG(cout << "MFX QueryVersion: " << res << " => " << ver.Major << "." << ver.Minor << endl);
+
+ if (res != MFX_ERR_NONE)
+ return false;
+
+ return initDeviceSession(session);
+}
+
+//==================================================================================================
+
+VAHandle::VAHandle() {
+ // TODO: provide a way of modifying this path
+ const string filename = "/dev/dri/card0";
+ file = open(filename.c_str(), O_RDWR);
+ if (file < 0)
+ CV_Error(Error::StsError, "Can't open file: " + filename);
+ display = vaGetDisplayDRM(file);
+}
+
+VAHandle::~VAHandle() {
+ if (display) {
+ vaTerminate(display);
+ }
+ if (file >= 0) {
+ close(file);
+ }
+}
+
+bool VAHandle::initDeviceSession(MFXVideoSession &session) {
+ int majorVer = 0, minorVer = 0;
+ VAStatus va_res = vaInitialize(display, &majorVer, &minorVer);
+ DBG(cout << "vaInitialize: " << va_res << endl << majorVer << '.' << minorVer << endl);
+ if (va_res == VA_STATUS_SUCCESS) {
+ mfxStatus mfx_res = session.SetHandle(static_cast<mfxHandleType>(MFX_HANDLE_VA_DISPLAY), display);
+ DBG(cout << "MFX SetHandle: " << mfx_res << endl);
+ if (mfx_res == MFX_ERR_NONE) {
+ return true;
+ }
+ }
+ return false;
+}
+
+//==================================================================================================
+
+SurfacePool::SurfacePool(ushort width_, ushort height_, ushort count, const mfxFrameInfo &frameInfo, uchar bpp)
+ : width(alignSize(width_, 32)),
+ height(alignSize(height_, 32)),
+ oneSize(width * height * bpp / 8),
+ buffers(count * oneSize),
+ surfaces(count)
+{
+ for(int i = 0; i < count; ++i)
+ {
+ mfxFrameSurface1 &surface = surfaces[i];
+ uint8_t * dataPtr = buffers + oneSize * i;
+ memset(&surface, 0, sizeof(mfxFrameSurface1));
+ surface.Info = frameInfo;
+ surface.Data.Y = dataPtr;
+ surface.Data.UV = dataPtr + width * height;
+ surface.Data.Pitch = width;
+ DBG(cout << "allocate surface " << (void*)&surface << ", Y = " << (void*)dataPtr << " (" << width << "x" << height << ")" << endl);
+ }
+ DBG(cout << "Allocated: " << endl
+ << "- surface data: " << buffers.size() << " bytes" << endl
+ << "- surface headers: " << surfaces.size() * sizeof(mfxFrameSurface1) << " bytes" << endl);
+}
+
+SurfacePool::~SurfacePool()
+{
+}
+
+mfxFrameSurface1 *SurfacePool::getFreeSurface()
+{
+ for(std::vector<mfxFrameSurface1>::iterator i = surfaces.begin(); i != surfaces.end(); ++i)
+ if (!i->Data.Locked)
+ return &(*i);
+ return 0;
+}
+
+//==================================================================================================
+
+ReadBitstream::ReadBitstream(const char *filename, size_t maxSize) : drain(false)
+{
+ input.open(filename, std::ios::in | std::ios::binary);
+ DBG(cout << "Open " << filename << " -> " << input.is_open() << std::endl);
+ memset(&stream, 0, sizeof(stream));
+ stream.MaxLength = maxSize;
+ stream.Data = new mfxU8[stream.MaxLength];
+ CV_Assert(stream.Data);
+}
+
+ReadBitstream::~ReadBitstream()
+{
+ delete[] stream.Data;
+}
+
+bool ReadBitstream::isOpened() const
+{
+ return input.is_open();
+}
+
+bool ReadBitstream::isDone() const
+{
+ return input.eof();
+}
+
+bool ReadBitstream::read()
+{
+ memmove(stream.Data, stream.Data + stream.DataOffset, stream.DataLength);
+ stream.DataOffset = 0;
+ input.read((char*)(stream.Data + stream.DataLength), stream.MaxLength - stream.DataLength);
+ if (input.eof() || input.good())
+ {
+ mfxU32 bytesRead = input.gcount();
+ if (bytesRead > 0)
+ {
+ stream.DataLength += bytesRead;
+ DBG(cout << "read " << bytesRead << " bytes" << endl);
+ return true;
+ }
+ }
+ return false;
+}
+
+//==================================================================================================
+
+WriteBitstream::WriteBitstream(const char * filename, size_t maxSize)
+{
+ output.open(filename, std::ios::out | std::ios::binary);
+ DBG(cout << "BS Open " << filename << " -> " << output.is_open() << std::endl);
+ memset(&stream, 0, sizeof(stream));
+ stream.MaxLength = maxSize;
+ stream.Data = new mfxU8[stream.MaxLength];
+ DBG(cout << "BS Allocate " << maxSize << " bytes (" << ((float)maxSize / (1 << 20)) << " Mb)" << endl);
+ CV_Assert(stream.Data);
+}
+
+WriteBitstream::~WriteBitstream()
+{
+ delete[] stream.Data;
+}
+
+bool WriteBitstream::write()
+{
+ output.write((char*)(stream.Data + stream.DataOffset), stream.DataLength);
+ stream.DataLength = 0;
+ return output.good();
+}
+
+bool WriteBitstream::isOpened() const
+{
+ return output.is_open();
+}
+
+//==================================================================================================
--- /dev/null
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html
+
+#ifndef MFXHELPER_H
+#define MFXHELPER_H
+
+#include "opencv2/core.hpp"
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include <mfxcommon.h>
+#include <mfxstructures.h>
+#include <mfxvideo++.h>
+#include <mfxvp8.h>
+#include <mfxjpeg.h>
+#include <mfxplugin++.h>
+
+// //
+// Debug helpers //
+// //
+
+#if 0
+# define DBG(i) i
+#else
+# define DBG(i)
+#endif
+
+#if 1
+# define MSG(i) i
+#else
+# define MSG(i)
+#endif
+
+template <typename T>
+struct HexWrap {
+ HexWrap(T val_) : val(val_) {}
+ T val;
+};
+
+template <typename T>
+inline std::ostream & operator<<(std::ostream &out, const HexWrap<T> &wrap) {
+ std::ios_base::fmtflags flags = out.flags(std::ios::hex | std::ios::showbase);
+ out << wrap.val;
+ out.flags(flags);
+ return out;
+}
+
+template <typename T>
+inline ::HexWrap<T> asHex(const T & val) {
+ return ::HexWrap<T>(val);
+}
+
+struct FourCC
+{
+ FourCC(uint val) : val32(val) {}
+ FourCC(char a, char b, char c, char d) { val8[0] = a; val8[1] = b; val8[2] = c; val8[3] = d; }
+ union {
+ uint val32;
+ int vali32;
+ uchar val8[4];
+ };
+};
+
+inline std::ostream & operator<<(std::ostream &out, FourCC cc) {
+ for (size_t i = 0; i < 4; out << cc.val8[i++]) {}
+ out << " (" << asHex(cc.val32) << ")";
+ return out;
+}
+
+inline std::string mfxStatusToString(mfxStatus s) {
+ switch (s)
+ {
+ case MFX_ERR_NONE: return "MFX_ERR_NONE";
+ case MFX_ERR_UNKNOWN: return "MFX_ERR_UNKNOWN";
+ case MFX_ERR_NULL_PTR: return "MFX_ERR_NULL_PTR";
+ case MFX_ERR_UNSUPPORTED: return "MFX_ERR_UNSUPPORTED";
+ case MFX_ERR_MEMORY_ALLOC: return "MFX_ERR_MEMORY_ALLOC";
+ case MFX_ERR_NOT_ENOUGH_BUFFER: return "MFX_ERR_NOT_ENOUGH_BUFFER";
+ case MFX_ERR_INVALID_HANDLE: return "MFX_ERR_INVALID_HANDLE";
+ case MFX_ERR_LOCK_MEMORY: return "MFX_ERR_LOCK_MEMORY";
+ case MFX_ERR_NOT_INITIALIZED: return "MFX_ERR_NOT_INITIALIZED";
+ case MFX_ERR_NOT_FOUND: return "MFX_ERR_NOT_FOUND";
+ case MFX_ERR_MORE_DATA: return "MFX_ERR_MORE_DATA";
+ case MFX_ERR_MORE_SURFACE: return "MFX_ERR_MORE_SURFACE";
+ case MFX_ERR_ABORTED: return "MFX_ERR_ABORTED";
+ case MFX_ERR_DEVICE_LOST: return "MFX_ERR_DEVICE_LOST";
+ case MFX_ERR_INCOMPATIBLE_VIDEO_PARAM: return "MFX_ERR_INCOMPATIBLE_VIDEO_PARAM";
+ case MFX_ERR_INVALID_VIDEO_PARAM: return "MFX_ERR_INVALID_VIDEO_PARAM";
+ case MFX_ERR_UNDEFINED_BEHAVIOR: return "MFX_ERR_UNDEFINED_BEHAVIOR";
+ case MFX_ERR_DEVICE_FAILED: return "MFX_ERR_DEVICE_FAILED";
+ case MFX_ERR_MORE_BITSTREAM: return "MFX_ERR_MORE_BITSTREAM";
+ case MFX_ERR_INCOMPATIBLE_AUDIO_PARAM: return "MFX_ERR_INCOMPATIBLE_AUDIO_PARAM";
+ case MFX_ERR_INVALID_AUDIO_PARAM: return "MFX_ERR_INVALID_AUDIO_PARAM";
+ case MFX_ERR_GPU_HANG: return "MFX_ERR_GPU_HANG";
+ case MFX_ERR_REALLOC_SURFACE: return "MFX_ERR_REALLOC_SURFACE";
+ case MFX_WRN_IN_EXECUTION: return "MFX_WRN_IN_EXECUTION";
+ case MFX_WRN_DEVICE_BUSY: return "MFX_WRN_DEVICE_BUSY";
+ case MFX_WRN_VIDEO_PARAM_CHANGED: return "MFX_WRN_VIDEO_PARAM_CHANGED";
+ case MFX_WRN_PARTIAL_ACCELERATION: return "MFX_WRN_PARTIAL_ACCELERATION";
+ case MFX_WRN_INCOMPATIBLE_VIDEO_PARAM: return "MFX_WRN_INCOMPATIBLE_VIDEO_PARAM";
+ case MFX_WRN_VALUE_NOT_CHANGED: return "MFX_WRN_VALUE_NOT_CHANGED";
+ case MFX_WRN_OUT_OF_RANGE: return "MFX_WRN_OUT_OF_RANGE";
+ case MFX_WRN_FILTER_SKIPPED: return "MFX_WRN_FILTER_SKIPPED";
+ case MFX_WRN_INCOMPATIBLE_AUDIO_PARAM: return "MFX_WRN_INCOMPATIBLE_AUDIO_PARAM";
+ default: return "<Invalid mfxStatus>";
+ }
+}
+
+inline std::ostream & operator<<(std::ostream &out, mfxStatus s) {
+ out << mfxStatusToString(s) << " (" << (int)s << ")"; return out;
+}
+
+inline std::ostream & operator<<(std::ostream &out, const mfxInfoMFX &info) {
+ out << "InfoMFX:" << std::endl
+ << "| Codec: " << FourCC(info.CodecId) << " / " << info.CodecProfile << " / " << info.CodecLevel << std::endl
+ << "| DecodedOrder: " << info.DecodedOrder << std::endl
+ << "| TimeStampCalc: " << info.TimeStampCalc << std::endl
+ ;
+ return out;
+}
+
+inline std::ostream & operator<<(std::ostream & out, const mfxFrameInfo & info) {
+ out << "FrameInfo: " << std::endl
+ << "| FourCC: " << FourCC(info.FourCC) << std::endl
+ << "| Size: " << info.Width << "x" << info.Height << std::endl
+ << "| ROI: " << "(" << info.CropX << ";" << info.CropY << ") " << info.CropW << "x" << info.CropH << std::endl
+ << "| BitDepth(L/C): " << info.BitDepthLuma << " / " << info.BitDepthChroma << std::endl
+ << "| Shift: " << info.Shift << std::endl
+ << "| TemporalID: " << info.FrameId.TemporalId << std::endl
+ << "| FrameRate: " << info.FrameRateExtN << "/" << info.FrameRateExtD << std::endl
+ << "| AspectRatio: " << info.AspectRatioW << "x" << info.AspectRatioH << std::endl
+ << "| PicStruct: " << info.PicStruct << std::endl
+ << "| ChromaFormat: " << info.ChromaFormat << std::endl
+ ;
+ return out;
+}
+
+inline std::ostream & operator<<(std::ostream &out, const mfxFrameData &data) {
+ out << "FrameData:" << std::endl
+ << "| NumExtParam: " << data.NumExtParam << std::endl
+ << "| MemType: " << data.MemType << std::endl
+ << "| PitchHigh: " << data.PitchHigh << std::endl
+ << "| TimeStamp: " << data.TimeStamp << std::endl
+ << "| FrameOrder: " << data.FrameOrder << std::endl
+ << "| Locked: " << data.Locked << std::endl
+ << "| Pitch: " << data.PitchHigh << ", " << data.PitchLow << std::endl
+ << "| Y: " << (void*)data.Y << std::endl
+ << "| U: " << (void*)data.U << std::endl
+ << "| V: " << (void*)data.V << std::endl
+ ;
+ return out;
+}
+
+//==================================================================================================
+
+static const int CC_MPG2 = FourCC('M', 'P', 'G', '2').vali32;
+static const int CC_H264 = FourCC('H', '2', '6', '4').vali32;
+static const int CC_X264 = FourCC('X', '2', '6', '4').vali32;
+static const int CC_AVC = FourCC('A', 'V', 'C', ' ').vali32;
+static const int CC_H265 = FourCC('H', '2', '6', '5').vali32;
+static const int CC_HEVC = FourCC('H', 'E', 'V', 'C').vali32;
+static const int CC_VC1 = FourCC('V', 'C', '1', ' ').vali32;
+
+//==================================================================================================
+
+template <typename T>
+inline void cleanup(T * &ptr)
+{
+ if (ptr)
+ {
+ delete ptr;
+ ptr = 0;
+ }
+}
+
+//==================================================================================================
+
+struct Plugin
+{
+public:
+ static Plugin * loadEncoderPlugin(MFXVideoSession &session, mfxU32 codecId)
+ {
+ static const mfxPluginUID hevc_enc_uid = { 0x6f, 0xad, 0xc7, 0x91, 0xa0, 0xc2, 0xeb, 0x47, 0x9a, 0xb6, 0xdc, 0xd5, 0xea, 0x9d, 0xa3, 0x47 };
+ if (codecId == MFX_CODEC_HEVC)
+ return new Plugin(session, hevc_enc_uid);
+ return 0;
+ }
+ static Plugin * loadDecoderPlugin(MFXVideoSession &session, mfxU32 codecId)
+ {
+ static const mfxPluginUID hevc_dec_uid = { 0x33, 0xa6, 0x1c, 0x0b, 0x4c, 0x27, 0x45, 0x4c, 0xa8, 0xd8, 0x5d, 0xde, 0x75, 0x7c, 0x6f, 0x8e };
+ if (codecId == MFX_CODEC_HEVC)
+ return new Plugin(session, hevc_dec_uid);
+ return 0;
+ }
+ ~Plugin()
+ {
+ if (isGood())
+ MFXVideoUSER_UnLoad(session, &uid);
+ }
+ bool isGood() const { return res >= MFX_ERR_NONE; }
+private:
+ MFXVideoSession &session;
+ mfxPluginUID uid;
+ mfxStatus res;
+private:
+ Plugin(MFXVideoSession &_session, mfxPluginUID _uid) : session(_session), uid(_uid)
+ {
+ res = MFXVideoUSER_Load(session, &uid, 1);
+ }
+ Plugin(const Plugin &);
+ Plugin &operator=(const Plugin &);
+};
+
+//==================================================================================================
+
+struct ReadBitstream
+{
+public:
+ ReadBitstream(const char * filename, size_t maxSize = 10 * 1024 * 1024);
+ ~ReadBitstream();
+ bool isOpened() const;
+ bool isDone() const;
+ bool read();
+private:
+ ReadBitstream(const ReadBitstream &);
+ ReadBitstream &operator=(const ReadBitstream &);
+public:
+ std::fstream input;
+ mfxBitstream stream;
+ bool drain;
+};
+
+//==================================================================================================
+
+struct WriteBitstream
+{
+public:
+ WriteBitstream(const char * filename, size_t maxSize);
+ ~WriteBitstream();
+ bool write();
+ bool isOpened() const;
+private:
+ WriteBitstream(const WriteBitstream &);
+ WriteBitstream &operator=(const WriteBitstream &);
+public:
+ std::fstream output;
+ mfxBitstream stream;
+};
+
+//==================================================================================================
+
+class SurfacePool
+{
+public:
+ SurfacePool(ushort width_, ushort height_, ushort count, const mfxFrameInfo & frameInfo, uchar bpp = 12);
+ ~SurfacePool();
+ mfxFrameSurface1 *getFreeSurface();
+
+ template <typename T>
+ static SurfacePool * create(T * instance, mfxVideoParam ¶ms)
+ {
+ CV_Assert(instance);
+ mfxFrameAllocRequest request;
+ memset(&request, 0, sizeof(request));
+ mfxStatus res = instance->QueryIOSurf(¶ms, &request);
+ 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);
+ }
+private:
+ SurfacePool(const SurfacePool &);
+ SurfacePool &operator=(const SurfacePool &);
+public:
+ ushort width, height;
+ size_t oneSize;
+ cv::AutoBuffer<uchar, 0> buffers;
+ std::vector<mfxFrameSurface1> surfaces;
+};
+
+//==================================================================================================
+
+class DeviceHandler {
+public:
+ virtual ~DeviceHandler() {}
+ bool init(MFXVideoSession &session);
+protected:
+ virtual bool initDeviceSession(MFXVideoSession &session) = 0;
+};
+
+
+// Linux specific
+
+#include <va/va_drm.h>
+
+class VAHandle : public DeviceHandler {
+public:
+ VAHandle();
+ ~VAHandle();
+private:
+ VAHandle(const VAHandle &);
+ VAHandle &operator=(const VAHandle &);
+ virtual bool initDeviceSession(MFXVideoSession &session);
+private:
+ VADisplay display;
+ int file;
+};
+
+// TODO: Windows specific
+
+
+#endif // MFXHELPER_H
--- /dev/null
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html
+
+#include "cap_mfx_reader.hpp"
+#include "opencv2/core/base.hpp"
+#include "cap_mfx_common.hpp"
+
+using namespace cv;
+using namespace std;
+
+inline bool hasExtension(const String &filename, const String &ext)
+{
+ if (filename.size() <= ext.size())
+ return false;
+ const size_t diff = filename.size() - ext.size();
+ const size_t found_at = filename.rfind(ext);
+ return found_at == diff;
+}
+
+inline mfxU32 determineCodecId(const String &filename)
+{
+ if (hasExtension(filename, ".h264") || hasExtension(filename, ".264"))
+ return MFX_CODEC_AVC;
+ else if (hasExtension(filename, ".mp2") || hasExtension(filename, ".mpeg2"))
+ return MFX_CODEC_MPEG2;
+ else if (hasExtension(filename, ".265") || hasExtension(filename, ".hevc"))
+ return MFX_CODEC_HEVC;
+ else
+ return (mfxU32)-1;
+}
+
+//==========================================================================
+
+VideoCapture_IntelMFX::VideoCapture_IntelMFX(const cv::String &filename)
+ : session(0), plugin(0), deviceHandler(0), bs(0), decoder(0), pool(0), outSurface(0), good(false)
+{
+ mfxStatus res = MFX_ERR_NONE;
+
+ // Init device and session
+
+ deviceHandler = new VAHandle();
+ session = new MFXVideoSession();
+ if (!deviceHandler->init(*session))
+ {
+ MSG(cerr << "MFX: Can't initialize session" << endl);
+ return;
+ }
+
+ // Load appropriate plugin
+
+ mfxU32 codecId = determineCodecId(filename);
+ if (codecId == (mfxU32)-1)
+ {
+ MSG(cerr << "MFX: Unsupported extension: " << filename << endl);
+ return;
+ }
+ plugin = Plugin::loadDecoderPlugin(*session, codecId);
+ if (plugin && !plugin->isGood())
+ {
+ MSG(cerr << "MFX: LoadPlugin failed for codec: " << codecId << " (" << filename << ")" << endl);
+ return;
+ }
+
+ // Read some content from file
+
+ bs = new ReadBitstream(filename.c_str());
+ if (!bs->read())
+ {
+ MSG(cerr << "MFX: Failed to read bitstream" << endl);
+ return;
+ }
+
+ // Create decoder and decode stream header
+
+ decoder = new MFXVideoDECODE(*session);
+ mfxVideoParam params;
+ memset(¶ms, 0, sizeof(params));
+ params.mfx.CodecId = codecId;
+ params.IOPattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
+ res = decoder->DecodeHeader(&bs->stream, ¶ms);
+ DBG(cout << "DecodeHeader: " << res << endl << params.mfx << params.mfx.FrameInfo << endl);
+ if (res < MFX_ERR_NONE)
+ {
+ MSG(cerr << "MFX: Failed to decode stream header: " << res << endl);
+ return;
+ }
+
+ // Adjust parameters
+
+ res = decoder->Query(¶ms, ¶ms);
+ DBG(cout << "MFX Query: " << res << endl << params.mfx << params.mfx.FrameInfo);
+ CV_Assert(res >= MFX_ERR_NONE);
+
+ // Init surface pool
+
+ pool = SurfacePool::create(decoder, params);
+ if (!pool)
+ {
+ MSG(cerr << "MFX: Failed to create surface pool" << endl);
+ return;
+ }
+
+ // Init decoder
+
+ res = decoder->Init(¶ms);
+ DBG(cout << "MFX Init: " << res << endl << params.mfx.FrameInfo);
+ if (res < MFX_ERR_NONE)
+ {
+ MSG(cerr << "MFX: Failed to init decoder: " << res << endl);
+ return;
+ }
+
+ good = true;
+}
+
+
+VideoCapture_IntelMFX::~VideoCapture_IntelMFX()
+{
+ cleanup(plugin);
+ cleanup(bs);
+ cleanup(decoder);
+ cleanup(pool);
+ session->Close();
+ cleanup(session);
+ cleanup(deviceHandler);
+}
+
+double VideoCapture_IntelMFX::getProperty(int) const
+{
+ MSG(cerr << "MFX: getProperty() is not implemented" << endl);
+ return 0;
+}
+
+bool VideoCapture_IntelMFX::setProperty(int, double)
+{
+ MSG(cerr << "MFX: setProperty() is not implemented" << endl);
+ return false;
+}
+
+bool VideoCapture_IntelMFX::grabFrame()
+{
+ mfxStatus res;
+ mfxFrameSurface1 *workSurface = 0;
+ mfxSyncPoint sync;
+
+ workSurface = pool->getFreeSurface();
+
+ while (true)
+ {
+ if (!workSurface)
+ {
+ // not enough surfaces
+ MSG(cerr << "MFX: Failed to get free surface" << endl);
+ return false;
+ }
+
+ outSurface = 0;
+ res = decoder->DecodeFrameAsync(bs->drain ? 0 : &bs->stream, workSurface, (mfxFrameSurface1**)&outSurface, &sync);
+ if (res == MFX_ERR_NONE)
+ {
+ res = session->SyncOperation(sync, 1000); // 1 sec, TODO: provide interface to modify timeout
+ if (res == MFX_ERR_NONE)
+ {
+ // ready to retrieve
+ DBG(cout << "Frame ready to retrieve" << endl);
+ return true;
+ }
+ else
+ {
+ MSG(cerr << "MFX: Sync error: " << res << endl);
+ return false;
+ }
+ }
+ else if (res == MFX_ERR_MORE_DATA)
+ {
+ if (bs->isDone())
+ {
+ if (bs->drain)
+ {
+ // finish
+ DBG(cout << "Drain finished" << endl);
+ return false;
+ }
+ else
+ {
+ DBG(cout << "Bitstream finished - Drain started" << endl);
+ bs->drain = true;
+ continue;
+ }
+ }
+ else
+ {
+ bool read_res = bs->read();
+ if (!read_res)
+ {
+ // failed to read
+ MSG(cerr << "MFX: Bitstream read failure" << endl);
+ return false;
+ }
+ else
+ {
+ DBG(cout << "Bitstream read success" << endl);
+ continue;
+ }
+ }
+ }
+ else if (res == MFX_ERR_MORE_SURFACE)
+ {
+ DBG(cout << "Getting another surface" << endl);
+ workSurface = pool->getFreeSurface();
+ continue;
+ }
+ else if (res == MFX_WRN_DEVICE_BUSY)
+ {
+ DBG(cout << "Waiting for device" << endl);
+ sleep(1);
+ continue;
+ }
+ else if (res == MFX_WRN_VIDEO_PARAM_CHANGED)
+ {
+ DBG(cout << "Video param changed" << endl);
+ continue;
+ }
+ else
+ {
+ MSG(cerr << "MFX: Bad status: " << res << endl);
+ return false;
+ }
+ return false;
+ }
+}
+
+
+bool VideoCapture_IntelMFX::retrieveFrame(int, OutputArray out)
+{
+ if (!outSurface)
+ {
+ MSG(cerr << "MFX: No frame ready to retrieve" << endl);
+ return false;
+ }
+ mfxFrameSurface1 * s = (mfxFrameSurface1*)outSurface;
+ mfxFrameInfo &info = s->Info;
+ mfxFrameData &data = s->Data;
+
+ const int cols = info.CropW;
+ const int rows = info.CropH;
+ Mat nv12(rows * 3 / 2, cols, CV_8UC1);
+
+ Mat Y(rows, cols, CV_8UC1, data.Y, data.Pitch);
+ Mat UV(rows / 2, cols, CV_8UC1, data.UV, data.Pitch);
+
+ Y.copyTo(Mat(nv12, Rect(0, 0, cols, rows)));
+ UV.copyTo(Mat(nv12, Rect(0, rows, cols, rows / 2)));
+
+ Mat u_and_v[2];
+ split(UV.reshape(2), u_and_v);
+ cvtColor(nv12, out, COLOR_YUV2BGR_NV12);
+
+ return true;
+}
+
+bool VideoCapture_IntelMFX::isOpened() const
+{
+ return good;
+}
+
+int VideoCapture_IntelMFX::getCaptureDomain()
+{
+ return CAP_INTEL_MFX;
+}
+
+//==================================================================================================
--- /dev/null
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html
+
+#ifndef CAP_MFX_HPP
+#define CAP_MFX_HPP
+
+#include "precomp.hpp"
+
+
+class MFXVideoSession;
+class Plugin;
+class DeviceHandler;
+class ReadBitstream;
+class SurfacePool;
+class MFXVideoDECODE;
+
+class VideoCapture_IntelMFX : public cv::IVideoCapture
+{
+public:
+ VideoCapture_IntelMFX(const cv::String &filename);
+ virtual ~VideoCapture_IntelMFX();
+ virtual double getProperty(int) const;
+ virtual bool setProperty(int, double);
+ virtual bool grabFrame();
+ virtual bool retrieveFrame(int, cv::OutputArray out);
+ virtual bool isOpened() const;
+ virtual int getCaptureDomain();
+private:
+ MFXVideoSession *session;
+ Plugin *plugin;
+ DeviceHandler *deviceHandler;
+ ReadBitstream *bs;
+ MFXVideoDECODE *decoder;
+ SurfacePool *pool;
+ void *outSurface;
+ bool good;
+};
+
+
+#endif
--- /dev/null
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html
+
+#include "cap_mfx_writer.hpp"
+#include "opencv2/core/base.hpp"
+#include "cap_mfx_common.hpp"
+
+using namespace std;
+using namespace cv;
+
+inline mfxU32 codecIdByFourCC(int fourcc)
+{
+ if (fourcc == CC_X264 || fourcc == CC_H264 || fourcc == CC_AVC)
+ return MFX_CODEC_AVC;
+ else if (fourcc == CC_H265 || fourcc == CC_HEVC)
+ return MFX_CODEC_HEVC;
+ else if (fourcc == CC_MPG2)
+ return MFX_CODEC_MPEG2;
+ else
+ return (mfxU32)-1;
+}
+
+VideoWriter_IntelMFX::VideoWriter_IntelMFX(const String &filename, int _fourcc, double fps, Size frameSize_, bool)
+ : session(0), plugin(0), deviceHandler(0), bs(0), encoder(0), pool(0), frameSize(frameSize_), good(false)
+{
+ mfxStatus res = MFX_ERR_NONE;
+
+ if (frameSize.width % 2 || frameSize.height % 2)
+ {
+ MSG(cerr << "MFX: Invalid frame size passed to encoder" << endl);
+ return;
+ }
+
+ // Init device and session
+
+ deviceHandler = new VAHandle();
+ session = new MFXVideoSession();
+ if (!deviceHandler->init(*session))
+ {
+ MSG(cerr << "MFX: Can't initialize session" << endl);
+ return;
+ }
+
+ // Load appropriate plugin
+
+ mfxU32 codecId = codecIdByFourCC(_fourcc);
+ if (codecId == (mfxU32)-1)
+ {
+ MSG(cerr << "MFX: Unsupported FourCC: " << FourCC(_fourcc) << endl);
+ return;
+ }
+ plugin = Plugin::loadEncoderPlugin(*session, codecId);
+ if (plugin && !plugin->isGood())
+ {
+ MSG(cerr << "MFX: LoadPlugin failed for codec: " << codecId << " (" << FourCC(_fourcc) << ")" << endl);
+ return;
+ }
+
+ // Init encoder
+
+ encoder = new MFXVideoENCODE(*session);
+ mfxVideoParam params;
+ memset(¶ms, 0, sizeof(params));
+ params.mfx.CodecId = codecId;
+ params.mfx.TargetUsage = MFX_TARGETUSAGE_BALANCED;
+ params.mfx.TargetKbps = frameSize.area() * fps / 500; // TODO: set in options
+ params.mfx.RateControlMethod = MFX_RATECONTROL_VBR;
+ params.mfx.FrameInfo.FrameRateExtN = cvRound(fps * 1000);
+ params.mfx.FrameInfo.FrameRateExtD = 1000;
+ params.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
+ params.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
+ params.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
+ params.mfx.FrameInfo.CropX = 0;
+ params.mfx.FrameInfo.CropY = 0;
+ params.mfx.FrameInfo.CropW = frameSize.width;
+ params.mfx.FrameInfo.CropH = frameSize.height;
+ params.mfx.FrameInfo.Width = alignSize(frameSize.width, 32);
+ params.mfx.FrameInfo.Height = alignSize(frameSize.height, 32);
+ params.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
+ res = encoder->Query(¶ms, ¶ms);
+ DBG(cout << "MFX Query: " << res << endl << params.mfx << params.mfx.FrameInfo);
+ if (res < MFX_ERR_NONE)
+ {
+ MSG(cerr << "MFX: Query failed: " << res << endl);
+ return;
+ }
+
+ // Init surface pool
+ pool = SurfacePool::create(encoder, params);
+ if (!pool)
+ {
+ MSG(cerr << "MFX: Failed to create surface pool" << endl);
+ return;
+ }
+
+ // Init encoder
+ res = encoder->Init(¶ms);
+ DBG(cout << "MFX Init: " << res << endl << params.mfx.FrameInfo);
+ if (res < MFX_ERR_NONE)
+ {
+ MSG(cerr << "MFX: Failed to init encoder: " << res << endl);
+ return;
+ }
+
+ // Open output bitstream
+ {
+ mfxVideoParam par;
+ memset(&par, 0, sizeof(par));
+ res = encoder->GetVideoParam(&par);
+ DBG(cout << "MFX GetVideoParam: " << res << endl << "requested " << par.mfx.BufferSizeInKB << " kB" << endl);
+ CV_Assert(res >= MFX_ERR_NONE);
+ bs = new WriteBitstream(filename.c_str(), par.mfx.BufferSizeInKB * 1024 * 2);
+ if (!bs->isOpened())
+ {
+ MSG(cerr << "MFX: Failed to open output file: " << filename << endl);
+ return;
+ }
+ }
+
+ good = true;
+}
+
+VideoWriter_IntelMFX::~VideoWriter_IntelMFX()
+{
+ if (isOpened())
+ {
+ DBG(cout << "====== Drain bitstream..." << endl);
+ Mat dummy;
+ while (write_one(dummy)) {}
+ DBG(cout << "====== Drain Finished" << endl);
+ }
+ cleanup(bs);
+ cleanup(pool);
+ cleanup(encoder);
+ cleanup(plugin);
+ cleanup(session);
+ cleanup(deviceHandler);
+}
+
+double VideoWriter_IntelMFX::getProperty(int) const
+{
+ MSG(cerr << "MFX: getProperty() is not implemented" << endl);
+ return 0;
+}
+
+bool VideoWriter_IntelMFX::setProperty(int, double)
+{
+ MSG(cerr << "MFX: setProperty() is not implemented" << endl);
+ return false;
+}
+
+bool VideoWriter_IntelMFX::isOpened() const
+{
+ return good;
+}
+
+void VideoWriter_IntelMFX::write(cv::InputArray input)
+{
+ write_one(input);
+}
+
+inline static void to_nv12(cv::InputArray bgr, cv::Mat & Y, cv::Mat & UV)
+{
+ const int height = bgr.rows();
+ const int width = bgr.cols();
+ Mat yuv;
+ cvtColor(bgr, yuv, CV_BGR2YUV_I420);
+ CV_Assert(yuv.isContinuous());
+ Mat Y_(Y, Rect(0, 0, width, height));
+ yuv.rowRange(0, height).copyTo(Y_);
+ Mat UV_planar(height, width / 2, CV_8UC1, yuv.ptr(height));
+ Mat u_and_v[2] = {
+ UV_planar.rowRange(0, height / 2),
+ UV_planar.rowRange(height / 2, height),
+ };
+ Mat uv;
+ cv::merge(u_and_v, 2, uv);
+ Mat UV_(UV, Rect(0, 0, width, height / 2));
+ uv.reshape(1).copyTo(UV_);
+}
+
+bool VideoWriter_IntelMFX::write_one(cv::InputArray bgr)
+{
+ mfxStatus res;
+ mfxFrameSurface1 *workSurface = 0;
+ mfxSyncPoint sync;
+
+ if (!bgr.empty() && (bgr.dims() != 2 || bgr.type() != CV_8UC3 || bgr.size() != frameSize))
+ {
+ MSG(cerr << "MFX: invalid frame passed to encoder: "
+ << "dims/depth/cn=" << bgr.dims() << "/" << bgr.depth() << "/" << bgr.channels()
+ << ", size=" << bgr.size() << endl);
+ return false;
+
+ }
+ if (!bgr.empty())
+ {
+ workSurface = pool->getFreeSurface();
+ if (!workSurface)
+ {
+ // not enough surfaces
+ MSG(cerr << "MFX: Failed to get free surface" << endl);
+ return false;
+ }
+ const int rows = workSurface->Info.Height;
+ const int cols = workSurface->Info.Width;
+ Mat Y(rows, cols, CV_8UC1, workSurface->Data.Y, workSurface->Data.Pitch);
+ Mat UV(rows / 2, cols, CV_8UC1, workSurface->Data.UV, workSurface->Data.Pitch);
+ to_nv12(bgr, Y, UV);
+ CV_Assert(Y.ptr() == workSurface->Data.Y);
+ CV_Assert(UV.ptr() == workSurface->Data.UV);
+ }
+
+ while (true)
+ {
+ outSurface = 0;
+ DBG(cout << "Calling with surface: " << workSurface << endl);
+ 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
+ if (res == MFX_ERR_NONE)
+ {
+ // ready to write
+ if (!bs->write())
+ {
+ MSG(cerr << "MFX: Failed to write bitstream" << endl);
+ return false;
+ }
+ else
+ {
+ DBG(cout << "Write bitstream" << endl);
+ return true;
+ }
+ }
+ else
+ {
+ MSG(cerr << "MFX: Sync error: " << res << endl);
+ return false;
+ }
+ }
+ else if (res == MFX_ERR_MORE_DATA)
+ {
+ DBG(cout << "ERR_MORE_DATA" << endl);
+ return false;
+ }
+ else if (res == MFX_WRN_DEVICE_BUSY)
+ {
+ DBG(cout << "Waiting for device" << endl);
+ sleep(1);
+ continue;
+ }
+ else
+ {
+ MSG(cerr << "MFX: Bad status: " << res << endl);
+ return false;
+ }
+ return true;
+ }
+}
+
+Ptr<VideoWriter_IntelMFX> VideoWriter_IntelMFX::create(const String &filename, int _fourcc, double fps, Size frameSize, bool isColor)
+{
+ if (codecIdByFourCC(_fourcc) > 0)
+ {
+ Ptr<VideoWriter_IntelMFX> a = makePtr<VideoWriter_IntelMFX>(filename, _fourcc, fps, frameSize, isColor);
+ if (a->isOpened())
+ return a;
+ }
+ return Ptr<VideoWriter_IntelMFX>();
+}
--- /dev/null
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html
+
+#ifndef CAP_MFX_WRITER_HPP
+#define CAP_MFX_WRITER_HPP
+
+#include "precomp.hpp"
+
+class MFXVideoSession;
+class Plugin;
+class DeviceHandler;
+class WriteBitstream;
+class SurfacePool;
+class MFXVideoDECODE;
+class MFXVideoENCODE;
+
+class VideoWriter_IntelMFX : public cv::IVideoWriter
+{
+public:
+ VideoWriter_IntelMFX(const cv::String &filename, int _fourcc, double fps, cv::Size frameSize, bool isColor);
+ virtual ~VideoWriter_IntelMFX();
+ virtual double getProperty(int) const;
+ virtual bool setProperty(int, double);
+ virtual bool isOpened() const;
+ virtual void write(cv::InputArray input);
+ static cv::Ptr<VideoWriter_IntelMFX> create(const cv::String& filename, int _fourcc, double fps, cv::Size frameSize, bool isColor);
+
+protected:
+ bool write_one(cv::InputArray bgr);
+
+private:
+ VideoWriter_IntelMFX(const VideoWriter_IntelMFX &);
+ VideoWriter_IntelMFX & operator=(const VideoWriter_IntelMFX &);
+
+private:
+ MFXVideoSession *session;
+ Plugin *plugin;
+ DeviceHandler *deviceHandler;
+ WriteBitstream *bs;
+ MFXVideoENCODE *encoder;
+ SurfacePool *pool;
+ void *outSurface;
+ cv::Size frameSize;
+ bool good;
+};
+
+#endif // CAP_MFX_WRITER_HPP
--- /dev/null
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html
+
+#include "test_precomp.hpp"
+#include "opencv2/videoio.hpp"
+#include "opencv2/highgui.hpp"
+#include <sstream>
+#include <queue>
+#include <cstdio>
+
+#ifdef HAVE_MFX
+
+using namespace cv;
+using namespace std;
+using namespace std::tr1;
+
+
+TEST(Videoio_MFX, read_invalid)
+{
+ VideoCapture cap;
+ ASSERT_NO_THROW(cap.open("nonexistent-file", CAP_INTEL_MFX));
+ ASSERT_FALSE(cap.isOpened());
+ Mat img;
+ ASSERT_NO_THROW(cap >> img);
+ ASSERT_TRUE(img.empty());
+}
+
+TEST(Videoio_MFX, write_invalid)
+{
+ const string filename = cv::tempfile(".264");
+ VideoWriter writer;
+ bool res;
+ ASSERT_NO_THROW(res = writer.open(CAP_INTEL_MFX, filename, VideoWriter::fourcc('H', '2', '6', '4'), 1, Size(641, 480), true));
+ EXPECT_FALSE(res);
+ EXPECT_FALSE(writer.isOpened());
+ ASSERT_NO_THROW(res = writer.open(CAP_INTEL_MFX,filename, VideoWriter::fourcc('H', '2', '6', '4'), 1, Size(640, 481), true));
+ EXPECT_FALSE(res);
+ EXPECT_FALSE(writer.isOpened());
+ ASSERT_NO_THROW(res = writer.open(CAP_INTEL_MFX,filename, VideoWriter::fourcc('A', 'B', 'C', 'D'), 1, Size(640, 480), true));
+ EXPECT_FALSE(res);
+ EXPECT_FALSE(writer.isOpened());
+ ASSERT_NO_THROW(res = writer.open(CAP_INTEL_MFX,String(), VideoWriter::fourcc('H', '2', '6', '4'), 1, Size(640, 480), true));
+ EXPECT_FALSE(res);
+ EXPECT_FALSE(writer.isOpened());
+ ASSERT_NO_THROW(res = writer.open(CAP_INTEL_MFX,filename, VideoWriter::fourcc('H', '2', '6', '4'), 0, Size(640, 480), true));
+ EXPECT_FALSE(res);
+ EXPECT_FALSE(writer.isOpened());
+
+ ASSERT_NO_THROW(res = writer.open(CAP_INTEL_MFX,filename, VideoWriter::fourcc('H', '2', '6', '4'), 30, Size(640, 480), true));
+ ASSERT_TRUE(res);
+ ASSERT_TRUE(writer.isOpened());
+ Mat t;
+ // write some bad frames
+ t = Mat(Size(1024, 768), CV_8UC3);
+ EXPECT_NO_THROW(writer << t);
+ t = Mat(Size(320, 240), CV_8UC3);
+ EXPECT_NO_THROW(writer << t);
+ t = Mat(Size(640, 480), CV_8UC2);
+ EXPECT_NO_THROW(writer << t);
+
+ // cleanup
+ ASSERT_NO_THROW(writer.release());
+ remove(filename.c_str());
+}
+
+
+//==================================================================================================
+
+const int FRAME_COUNT = 20;
+
+inline void generateFrame(int i, Mat & frame)
+{
+ frame = 0;
+ ostringstream buf; buf << "Frame " << setw(2) << setfill('0') << i + 1;
+ int baseLine = 0;
+ Size box = getTextSize(buf.str(), FONT_HERSHEY_COMPLEX, 2, 5, &baseLine);
+ putText(frame, buf.str(), Point((frame.cols - box.width) / 2, (frame.rows - box.height) / 2 + baseLine),
+ FONT_HERSHEY_COMPLEX, 2, Scalar(255, 255, 255), 5, LINE_AA);
+ Point p(i * frame.cols / (FRAME_COUNT - 1), i * frame.rows / (FRAME_COUNT - 1));
+ circle(frame, p, 20, Scalar(200, 25, 55), 5, LINE_AA);
+}
+
+inline int fourccByExt(const String &ext)
+{
+ if (ext == ".mpeg2")
+ return VideoWriter::fourcc('M', 'P', 'G', '2');
+ else if (ext == ".264")
+ return VideoWriter::fourcc('H', '2', '6', '4');
+ else if (ext == ".265")
+ return VideoWriter::fourcc('H', '2', '6', '5');
+ return -1;
+}
+
+//==================================================================================================
+
+typedef tuple<Size, double, const char *> Size_FPS_Ext;
+typedef testing::TestWithParam< Size_FPS_Ext > Videoio_MFX;
+
+TEST_P(Videoio_MFX, read_write_raw)
+{
+ const Size FRAME_SIZE = get<0>(GetParam());
+ const double FPS = get<1>(GetParam());
+ const char *ext = get<2>(GetParam());
+ const String filename = cv::tempfile(ext);
+ const int fourcc = fourccByExt(ext);
+
+ bool isColor = true;
+ queue<Mat> goodFrames;
+
+ // Write video
+ VideoWriter writer;
+ writer.open(CAP_INTEL_MFX, filename, fourcc, FPS, FRAME_SIZE, isColor);
+ ASSERT_TRUE(writer.isOpened());
+ Mat frame(FRAME_SIZE, CV_8UC3);
+ for (int i = 0; i < FRAME_COUNT; ++i)
+ {
+ generateFrame(i, frame);
+ goodFrames.push(frame.clone());
+ writer << frame;
+ }
+ writer.release();
+ EXPECT_FALSE(writer.isOpened());
+
+ // Read video
+ VideoCapture cap;
+ cap.open(filename, CAP_INTEL_MFX);
+ ASSERT_TRUE(cap.isOpened());
+ for (int i = 0; i < FRAME_COUNT; ++i)
+ {
+ ASSERT_TRUE(cap.read(frame));
+ ASSERT_FALSE(frame.empty());
+ ASSERT_EQ(FRAME_SIZE.width, frame.cols);
+ ASSERT_EQ(FRAME_SIZE.height, frame.rows);
+ // verify
+ ASSERT_NE(goodFrames.size(), 0u);
+ const Mat &goodFrame = goodFrames.front();
+ EXPECT_EQ(goodFrame.depth(), frame.depth());
+ EXPECT_EQ(goodFrame.channels(), frame.channels());
+ EXPECT_EQ(goodFrame.type(), frame.type());
+ double psnr = cvtest::PSNR(goodFrame, frame);
+ if (fourcc == VideoWriter::fourcc('M', 'P', 'G', '2'))
+ EXPECT_GT(psnr, 37); // experimentally chosen value
+ else
+ EXPECT_GT(psnr, 43); // experimentally chosen value
+ goodFrames.pop();
+ }
+ EXPECT_FALSE(cap.read(frame));
+ EXPECT_TRUE(frame.empty());
+ cap.release();
+ EXPECT_FALSE(cap.isOpened());
+ remove(filename.c_str());
+}
+
+INSTANTIATE_TEST_CASE_P(videoio, Videoio_MFX,
+ testing::Combine(
+ testing::Values(Size(640, 480), Size(638, 478), Size(636, 476), Size(1920, 1080)),
+ testing::Values(1, 30, 100),
+ testing::Values(".mpeg2", ".264", ".265")));
+
+#endif