Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/videoio/src/cap_mfx_writer.cpp
16344 views
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
4
5
#include "cap_mfx_writer.hpp"
6
#include "opencv2/core/base.hpp"
7
#include "cap_mfx_common.hpp"
8
#include "opencv2/imgproc/hal/hal.hpp"
9
10
using namespace std;
11
using namespace cv;
12
13
inline mfxU32 codecIdByFourCC(int fourcc)
14
{
15
const int CC_MPG2 = FourCC('M', 'P', 'G', '2').vali32;
16
const int CC_H264 = FourCC('H', '2', '6', '4').vali32;
17
const int CC_X264 = FourCC('X', '2', '6', '4').vali32;
18
const int CC_AVC = FourCC('A', 'V', 'C', ' ').vali32;
19
const int CC_H265 = FourCC('H', '2', '6', '5').vali32;
20
const int CC_HEVC = FourCC('H', 'E', 'V', 'C').vali32;
21
22
if (fourcc == CC_X264 || fourcc == CC_H264 || fourcc == CC_AVC)
23
return MFX_CODEC_AVC;
24
else if (fourcc == CC_H265 || fourcc == CC_HEVC)
25
return MFX_CODEC_HEVC;
26
else if (fourcc == CC_MPG2)
27
return MFX_CODEC_MPEG2;
28
else
29
return (mfxU32)-1;
30
}
31
32
VideoWriter_IntelMFX::VideoWriter_IntelMFX(const String &filename, int _fourcc, double fps, Size frameSize_, bool)
33
: session(0), plugin(0), deviceHandler(0), bs(0), encoder(0), pool(0), frameSize(frameSize_), good(false)
34
{
35
mfxStatus res = MFX_ERR_NONE;
36
37
if (frameSize.width % 2 || frameSize.height % 2)
38
{
39
MSG(cerr << "MFX: Invalid frame size passed to encoder" << endl);
40
return;
41
}
42
43
// Init device and session
44
deviceHandler = createDeviceHandler();
45
session = new MFXVideoSession();
46
if (!deviceHandler->init(*session))
47
{
48
MSG(cerr << "MFX: Can't initialize session" << endl);
49
return;
50
}
51
52
// Load appropriate plugin
53
54
mfxU32 codecId = codecIdByFourCC(_fourcc);
55
if (codecId == (mfxU32)-1)
56
{
57
MSG(cerr << "MFX: Unsupported FourCC: " << FourCC(_fourcc) << endl);
58
return;
59
}
60
plugin = Plugin::loadEncoderPlugin(*session, codecId);
61
if (plugin && !plugin->isGood())
62
{
63
MSG(cerr << "MFX: LoadPlugin failed for codec: " << codecId << " (" << FourCC(_fourcc) << ")" << endl);
64
return;
65
}
66
67
// Init encoder
68
69
encoder = new MFXVideoENCODE(*session);
70
mfxVideoParam params;
71
memset(&params, 0, sizeof(params));
72
params.mfx.CodecId = codecId;
73
params.mfx.TargetUsage = MFX_TARGETUSAGE_BALANCED;
74
params.mfx.TargetKbps = (mfxU16)cvRound(frameSize.area() * fps / 500); // TODO: set in options
75
params.mfx.RateControlMethod = MFX_RATECONTROL_VBR;
76
params.mfx.FrameInfo.FrameRateExtN = cvRound(fps * 1000);
77
params.mfx.FrameInfo.FrameRateExtD = 1000;
78
params.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
79
params.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
80
params.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
81
params.mfx.FrameInfo.CropX = 0;
82
params.mfx.FrameInfo.CropY = 0;
83
params.mfx.FrameInfo.CropW = (mfxU16)frameSize.width;
84
params.mfx.FrameInfo.CropH = (mfxU16)frameSize.height;
85
params.mfx.FrameInfo.Width = (mfxU16)alignSize(frameSize.width, 32);
86
params.mfx.FrameInfo.Height = (mfxU16)alignSize(frameSize.height, 32);
87
params.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
88
res = encoder->Query(&params, &params);
89
DBG(cout << "MFX Query: " << res << endl << params.mfx << params.mfx.FrameInfo);
90
if (res < MFX_ERR_NONE)
91
{
92
MSG(cerr << "MFX: Query failed: " << res << endl);
93
return;
94
}
95
96
// Init surface pool
97
pool = SurfacePool::create(encoder, params);
98
if (!pool)
99
{
100
MSG(cerr << "MFX: Failed to create surface pool" << endl);
101
return;
102
}
103
104
// Init encoder
105
res = encoder->Init(&params);
106
DBG(cout << "MFX Init: " << res << endl << params.mfx.FrameInfo);
107
if (res < MFX_ERR_NONE)
108
{
109
MSG(cerr << "MFX: Failed to init encoder: " << res << endl);
110
return;
111
}
112
113
// Open output bitstream
114
{
115
mfxVideoParam par;
116
memset(&par, 0, sizeof(par));
117
res = encoder->GetVideoParam(&par);
118
DBG(cout << "MFX GetVideoParam: " << res << endl << "requested " << par.mfx.BufferSizeInKB << " kB" << endl);
119
CV_Assert(res >= MFX_ERR_NONE);
120
bs = new WriteBitstream(filename.c_str(), par.mfx.BufferSizeInKB * 1024 * 2);
121
if (!bs->isOpened())
122
{
123
MSG(cerr << "MFX: Failed to open output file: " << filename << endl);
124
return;
125
}
126
}
127
128
good = true;
129
}
130
131
VideoWriter_IntelMFX::~VideoWriter_IntelMFX()
132
{
133
if (isOpened())
134
{
135
DBG(cout << "====== Drain bitstream..." << endl);
136
Mat dummy;
137
while (write_one(dummy)) {}
138
DBG(cout << "====== Drain Finished" << endl);
139
}
140
cleanup(bs);
141
cleanup(pool);
142
cleanup(encoder);
143
cleanup(plugin);
144
cleanup(session);
145
cleanup(deviceHandler);
146
}
147
148
double VideoWriter_IntelMFX::getProperty(int) const
149
{
150
MSG(cerr << "MFX: getProperty() is not implemented" << endl);
151
return 0;
152
}
153
154
bool VideoWriter_IntelMFX::setProperty(int, double)
155
{
156
MSG(cerr << "MFX: setProperty() is not implemented" << endl);
157
return false;
158
}
159
160
bool VideoWriter_IntelMFX::isOpened() const
161
{
162
return good;
163
}
164
165
void VideoWriter_IntelMFX::write(cv::InputArray input)
166
{
167
write_one(input);
168
}
169
170
bool VideoWriter_IntelMFX::write_one(cv::InputArray bgr)
171
{
172
mfxStatus res;
173
mfxFrameSurface1 *workSurface = 0;
174
mfxSyncPoint sync;
175
176
if (!bgr.empty() && (bgr.dims() != 2 || bgr.type() != CV_8UC3 || bgr.size() != frameSize))
177
{
178
MSG(cerr << "MFX: invalid frame passed to encoder: "
179
<< "dims/depth/cn=" << bgr.dims() << "/" << bgr.depth() << "/" << bgr.channels()
180
<< ", size=" << bgr.size() << endl);
181
return false;
182
183
}
184
if (!bgr.empty())
185
{
186
workSurface = pool->getFreeSurface();
187
if (!workSurface)
188
{
189
// not enough surfaces
190
MSG(cerr << "MFX: Failed to get free surface" << endl);
191
return false;
192
}
193
Mat src = bgr.getMat();
194
hal::cvtBGRtoTwoPlaneYUV(src.data, src.step,
195
workSurface->Data.Y, workSurface->Data.UV, workSurface->Data.Pitch,
196
workSurface->Info.CropW, workSurface->Info.CropH,
197
3, false, 1);
198
}
199
200
while (true)
201
{
202
outSurface = 0;
203
DBG(cout << "Calling with surface: " << workSurface << endl);
204
res = encoder->EncodeFrameAsync(NULL, workSurface, &bs->stream, &sync);
205
if (res == MFX_ERR_NONE)
206
{
207
res = session->SyncOperation(sync, 1000); // 1 sec, TODO: provide interface to modify timeout
208
if (res == MFX_ERR_NONE)
209
{
210
// ready to write
211
if (!bs->write())
212
{
213
MSG(cerr << "MFX: Failed to write bitstream" << endl);
214
return false;
215
}
216
else
217
{
218
DBG(cout << "Write bitstream" << endl);
219
return true;
220
}
221
}
222
else
223
{
224
MSG(cerr << "MFX: Sync error: " << res << endl);
225
return false;
226
}
227
}
228
else if (res == MFX_ERR_MORE_DATA)
229
{
230
DBG(cout << "ERR_MORE_DATA" << endl);
231
return false;
232
}
233
else if (res == MFX_WRN_DEVICE_BUSY)
234
{
235
DBG(cout << "Waiting for device" << endl);
236
sleep(1);
237
continue;
238
}
239
else
240
{
241
MSG(cerr << "MFX: Bad status: " << res << endl);
242
return false;
243
}
244
}
245
}
246
247
Ptr<VideoWriter_IntelMFX> VideoWriter_IntelMFX::create(const String &filename, int _fourcc, double fps, Size frameSize, bool isColor)
248
{
249
if (codecIdByFourCC(_fourcc) > 0)
250
{
251
Ptr<VideoWriter_IntelMFX> a = makePtr<VideoWriter_IntelMFX>(filename, _fourcc, fps, frameSize, isColor);
252
if (a->isOpened())
253
return a;
254
}
255
return Ptr<VideoWriter_IntelMFX>();
256
}
257
258