1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html
5 #include "cap_mfx_reader.hpp"
6 #include "opencv2/core/base.hpp"
7 #include "cap_mfx_common.hpp"
8 #include "opencv2/imgproc/hal/hal.hpp"
9 #include "cap_interface.hpp"
14 inline bool hasExtension(const String &filename, const String &ext)
16 if (filename.size() <= ext.size())
18 const size_t diff = filename.size() - ext.size();
19 const size_t found_at = filename.rfind(ext);
20 return found_at == diff;
23 inline mfxU32 determineCodecId(const String &filename)
25 if (hasExtension(filename, ".h264") || hasExtension(filename, ".264"))
27 else if (hasExtension(filename, ".mp2") || hasExtension(filename, ".mpeg2"))
28 return MFX_CODEC_MPEG2;
29 else if (hasExtension(filename, ".265") || hasExtension(filename, ".hevc"))
30 return MFX_CODEC_HEVC;
35 //==========================================================================
37 VideoCapture_IntelMFX::VideoCapture_IntelMFX(const cv::String &filename)
38 : session(0), plugin(0), deviceHandler(0), bs(0), decoder(0), pool(0), outSurface(0), good(false)
40 mfxStatus res = MFX_ERR_NONE;
42 // Init device and session
43 deviceHandler = createDeviceHandler();
44 session = new MFXVideoSession();
45 if (!deviceHandler->init(*session))
47 MSG(cerr << "MFX: Can't initialize session" << endl);
51 // Load appropriate plugin
53 mfxU32 codecId = determineCodecId(filename);
54 if (codecId == (mfxU32)-1)
56 MSG(cerr << "MFX: Unsupported extension: " << filename << endl);
59 plugin = Plugin::loadDecoderPlugin(*session, codecId);
60 if (plugin && !plugin->isGood())
62 MSG(cerr << "MFX: LoadPlugin failed for codec: " << codecId << " (" << filename << ")" << endl);
66 // Read some content from file
68 bs = new ReadBitstream(filename.c_str());
71 MSG(cerr << "MFX: Failed to read bitstream" << endl);
75 // Create decoder and decode stream header
77 decoder = new MFXVideoDECODE(*session);
79 memset(¶ms, 0, sizeof(params));
80 params.mfx.CodecId = codecId;
81 params.IOPattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
82 res = decoder->DecodeHeader(&bs->stream, ¶ms);
83 DBG(cout << "DecodeHeader: " << res << endl << params.mfx << params.mfx.FrameInfo << endl);
84 if (res < MFX_ERR_NONE)
86 MSG(cerr << "MFX: Failed to decode stream header: " << res << endl);
92 res = decoder->Query(¶ms, ¶ms);
93 DBG(cout << "MFX Query: " << res << endl << params.mfx << params.mfx.FrameInfo);
94 CV_Assert(res >= MFX_ERR_NONE);
98 pool = SurfacePool::create(decoder, params);
101 MSG(cerr << "MFX: Failed to create surface pool" << endl);
107 res = decoder->Init(¶ms);
108 DBG(cout << "MFX Init: " << res << endl << params.mfx.FrameInfo);
109 if (res < MFX_ERR_NONE)
111 MSG(cerr << "MFX: Failed to init decoder: " << res << endl);
115 frameSize = Size(params.mfx.FrameInfo.CropW, params.mfx.FrameInfo.CropH);
120 VideoCapture_IntelMFX::~VideoCapture_IntelMFX()
128 cleanup(deviceHandler);
131 double VideoCapture_IntelMFX::getProperty(int prop) const
135 MSG(cerr << "MFX: can not call getProperty(), backend has not been initialized" << endl);
140 case CAP_PROP_FRAME_WIDTH:
141 return frameSize.width;
142 case CAP_PROP_FRAME_HEIGHT:
143 return frameSize.height;
145 MSG(cerr << "MFX: unsupported property" << endl);
150 bool VideoCapture_IntelMFX::setProperty(int, double)
152 MSG(cerr << "MFX: setProperty() is not implemented" << endl);
156 bool VideoCapture_IntelMFX::grabFrame()
159 mfxFrameSurface1 *workSurface = 0;
162 workSurface = pool->getFreeSurface();
168 // not enough surfaces
169 MSG(cerr << "MFX: Failed to get free surface" << endl);
174 res = decoder->DecodeFrameAsync(bs->drain ? 0 : &bs->stream, workSurface, (mfxFrameSurface1**)&outSurface, &sync);
175 if (res == MFX_ERR_NONE)
177 res = session->SyncOperation(sync, 1000); // 1 sec, TODO: provide interface to modify timeout
178 if (res == MFX_ERR_NONE)
181 DBG(cout << "Frame ready to retrieve" << endl);
186 MSG(cerr << "MFX: Sync error: " << res << endl);
190 else if (res == MFX_ERR_MORE_DATA)
197 DBG(cout << "Drain finished" << endl);
202 DBG(cout << "Bitstream finished - Drain started" << endl);
209 bool read_res = bs->read();
213 MSG(cerr << "MFX: Bitstream read failure" << endl);
218 DBG(cout << "Bitstream read success" << endl);
223 else if (res == MFX_ERR_MORE_SURFACE)
225 DBG(cout << "Getting another surface" << endl);
226 workSurface = pool->getFreeSurface();
229 else if (res == MFX_WRN_DEVICE_BUSY)
231 DBG(cout << "Waiting for device" << endl);
235 else if (res == MFX_WRN_VIDEO_PARAM_CHANGED)
237 DBG(cout << "Video param changed" << endl);
242 MSG(cerr << "MFX: Bad status: " << res << endl);
249 bool VideoCapture_IntelMFX::retrieveFrame(int, OutputArray out)
253 MSG(cerr << "MFX: No frame ready to retrieve" << endl);
256 mfxFrameSurface1 * s = (mfxFrameSurface1*)outSurface;
257 mfxFrameInfo &info = s->Info;
258 mfxFrameData &data = s->Data;
260 const int cols = info.CropW;
261 const int rows = info.CropH;
263 out.create(rows, cols, CV_8UC3);
264 Mat res = out.getMat();
266 hal::cvtTwoPlaneYUVtoBGR(data.Y, data.UV, data.Pitch, res.data, res.step, cols, rows, 3, false, 0);
271 bool VideoCapture_IntelMFX::isOpened() const
276 int VideoCapture_IntelMFX::getCaptureDomain()
278 return CAP_INTEL_MFX;
281 //==================================================================================================
283 cv::Ptr<IVideoCapture> cv::create_MFX_capture(const std::string &filename)
285 return cv::makePtr<VideoCapture_IntelMFX>(filename);