Path: blob/master/modules/videoio/src/cap_mfx_writer.cpp
16344 views
// This file is part of OpenCV project.1// It is subject to the license terms in the LICENSE file found in the top-level directory2// of this distribution and at http://opencv.org/license.html34#include "cap_mfx_writer.hpp"5#include "opencv2/core/base.hpp"6#include "cap_mfx_common.hpp"7#include "opencv2/imgproc/hal/hal.hpp"89using namespace std;10using namespace cv;1112inline mfxU32 codecIdByFourCC(int fourcc)13{14const int CC_MPG2 = FourCC('M', 'P', 'G', '2').vali32;15const int CC_H264 = FourCC('H', '2', '6', '4').vali32;16const int CC_X264 = FourCC('X', '2', '6', '4').vali32;17const int CC_AVC = FourCC('A', 'V', 'C', ' ').vali32;18const int CC_H265 = FourCC('H', '2', '6', '5').vali32;19const int CC_HEVC = FourCC('H', 'E', 'V', 'C').vali32;2021if (fourcc == CC_X264 || fourcc == CC_H264 || fourcc == CC_AVC)22return MFX_CODEC_AVC;23else if (fourcc == CC_H265 || fourcc == CC_HEVC)24return MFX_CODEC_HEVC;25else if (fourcc == CC_MPG2)26return MFX_CODEC_MPEG2;27else28return (mfxU32)-1;29}3031VideoWriter_IntelMFX::VideoWriter_IntelMFX(const String &filename, int _fourcc, double fps, Size frameSize_, bool)32: session(0), plugin(0), deviceHandler(0), bs(0), encoder(0), pool(0), frameSize(frameSize_), good(false)33{34mfxStatus res = MFX_ERR_NONE;3536if (frameSize.width % 2 || frameSize.height % 2)37{38MSG(cerr << "MFX: Invalid frame size passed to encoder" << endl);39return;40}4142// Init device and session43deviceHandler = createDeviceHandler();44session = new MFXVideoSession();45if (!deviceHandler->init(*session))46{47MSG(cerr << "MFX: Can't initialize session" << endl);48return;49}5051// Load appropriate plugin5253mfxU32 codecId = codecIdByFourCC(_fourcc);54if (codecId == (mfxU32)-1)55{56MSG(cerr << "MFX: Unsupported FourCC: " << FourCC(_fourcc) << endl);57return;58}59plugin = Plugin::loadEncoderPlugin(*session, codecId);60if (plugin && !plugin->isGood())61{62MSG(cerr << "MFX: LoadPlugin failed for codec: " << codecId << " (" << FourCC(_fourcc) << ")" << endl);63return;64}6566// Init encoder6768encoder = new MFXVideoENCODE(*session);69mfxVideoParam params;70memset(¶ms, 0, sizeof(params));71params.mfx.CodecId = codecId;72params.mfx.TargetUsage = MFX_TARGETUSAGE_BALANCED;73params.mfx.TargetKbps = (mfxU16)cvRound(frameSize.area() * fps / 500); // TODO: set in options74params.mfx.RateControlMethod = MFX_RATECONTROL_VBR;75params.mfx.FrameInfo.FrameRateExtN = cvRound(fps * 1000);76params.mfx.FrameInfo.FrameRateExtD = 1000;77params.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;78params.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;79params.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;80params.mfx.FrameInfo.CropX = 0;81params.mfx.FrameInfo.CropY = 0;82params.mfx.FrameInfo.CropW = (mfxU16)frameSize.width;83params.mfx.FrameInfo.CropH = (mfxU16)frameSize.height;84params.mfx.FrameInfo.Width = (mfxU16)alignSize(frameSize.width, 32);85params.mfx.FrameInfo.Height = (mfxU16)alignSize(frameSize.height, 32);86params.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;87res = encoder->Query(¶ms, ¶ms);88DBG(cout << "MFX Query: " << res << endl << params.mfx << params.mfx.FrameInfo);89if (res < MFX_ERR_NONE)90{91MSG(cerr << "MFX: Query failed: " << res << endl);92return;93}9495// Init surface pool96pool = SurfacePool::create(encoder, params);97if (!pool)98{99MSG(cerr << "MFX: Failed to create surface pool" << endl);100return;101}102103// Init encoder104res = encoder->Init(¶ms);105DBG(cout << "MFX Init: " << res << endl << params.mfx.FrameInfo);106if (res < MFX_ERR_NONE)107{108MSG(cerr << "MFX: Failed to init encoder: " << res << endl);109return;110}111112// Open output bitstream113{114mfxVideoParam par;115memset(&par, 0, sizeof(par));116res = encoder->GetVideoParam(&par);117DBG(cout << "MFX GetVideoParam: " << res << endl << "requested " << par.mfx.BufferSizeInKB << " kB" << endl);118CV_Assert(res >= MFX_ERR_NONE);119bs = new WriteBitstream(filename.c_str(), par.mfx.BufferSizeInKB * 1024 * 2);120if (!bs->isOpened())121{122MSG(cerr << "MFX: Failed to open output file: " << filename << endl);123return;124}125}126127good = true;128}129130VideoWriter_IntelMFX::~VideoWriter_IntelMFX()131{132if (isOpened())133{134DBG(cout << "====== Drain bitstream..." << endl);135Mat dummy;136while (write_one(dummy)) {}137DBG(cout << "====== Drain Finished" << endl);138}139cleanup(bs);140cleanup(pool);141cleanup(encoder);142cleanup(plugin);143cleanup(session);144cleanup(deviceHandler);145}146147double VideoWriter_IntelMFX::getProperty(int) const148{149MSG(cerr << "MFX: getProperty() is not implemented" << endl);150return 0;151}152153bool VideoWriter_IntelMFX::setProperty(int, double)154{155MSG(cerr << "MFX: setProperty() is not implemented" << endl);156return false;157}158159bool VideoWriter_IntelMFX::isOpened() const160{161return good;162}163164void VideoWriter_IntelMFX::write(cv::InputArray input)165{166write_one(input);167}168169bool VideoWriter_IntelMFX::write_one(cv::InputArray bgr)170{171mfxStatus res;172mfxFrameSurface1 *workSurface = 0;173mfxSyncPoint sync;174175if (!bgr.empty() && (bgr.dims() != 2 || bgr.type() != CV_8UC3 || bgr.size() != frameSize))176{177MSG(cerr << "MFX: invalid frame passed to encoder: "178<< "dims/depth/cn=" << bgr.dims() << "/" << bgr.depth() << "/" << bgr.channels()179<< ", size=" << bgr.size() << endl);180return false;181182}183if (!bgr.empty())184{185workSurface = pool->getFreeSurface();186if (!workSurface)187{188// not enough surfaces189MSG(cerr << "MFX: Failed to get free surface" << endl);190return false;191}192Mat src = bgr.getMat();193hal::cvtBGRtoTwoPlaneYUV(src.data, src.step,194workSurface->Data.Y, workSurface->Data.UV, workSurface->Data.Pitch,195workSurface->Info.CropW, workSurface->Info.CropH,1963, false, 1);197}198199while (true)200{201outSurface = 0;202DBG(cout << "Calling with surface: " << workSurface << endl);203res = encoder->EncodeFrameAsync(NULL, workSurface, &bs->stream, &sync);204if (res == MFX_ERR_NONE)205{206res = session->SyncOperation(sync, 1000); // 1 sec, TODO: provide interface to modify timeout207if (res == MFX_ERR_NONE)208{209// ready to write210if (!bs->write())211{212MSG(cerr << "MFX: Failed to write bitstream" << endl);213return false;214}215else216{217DBG(cout << "Write bitstream" << endl);218return true;219}220}221else222{223MSG(cerr << "MFX: Sync error: " << res << endl);224return false;225}226}227else if (res == MFX_ERR_MORE_DATA)228{229DBG(cout << "ERR_MORE_DATA" << endl);230return false;231}232else if (res == MFX_WRN_DEVICE_BUSY)233{234DBG(cout << "Waiting for device" << endl);235sleep(1);236continue;237}238else239{240MSG(cerr << "MFX: Bad status: " << res << endl);241return false;242}243}244}245246Ptr<VideoWriter_IntelMFX> VideoWriter_IntelMFX::create(const String &filename, int _fourcc, double fps, Size frameSize, bool isColor)247{248if (codecIdByFourCC(_fourcc) > 0)249{250Ptr<VideoWriter_IntelMFX> a = makePtr<VideoWriter_IntelMFX>(filename, _fourcc, fps, frameSize, isColor);251if (a->isOpened())252return a;253}254return Ptr<VideoWriter_IntelMFX>();255}256257258