Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/samples/cpp/gstreamer_pipeline.cpp
16337 views
1
#include "opencv2/core/utility.hpp"
2
#include "opencv2/imgproc.hpp"
3
#include "opencv2/imgcodecs.hpp"
4
#include "opencv2/highgui.hpp"
5
#include <string>
6
#include <iostream>
7
#include <map>
8
9
using namespace std;
10
using namespace cv;
11
12
//================================================================================
13
14
template<typename M>
15
inline typename M::mapped_type getValue(const M &dict, const typename M::key_type &key, const string & errorMessage)
16
{
17
typename M::const_iterator it = dict.find(key);
18
if (it == dict.end())
19
{
20
CV_Error(Error::StsBadArg, errorMessage);
21
}
22
return it->second;
23
}
24
25
inline map<string, Size> sizeByResolution()
26
{
27
map<string, Size> res;
28
res["720p"] = Size(1280, 720);
29
res["1080p"] = Size(1920, 1080);
30
res["4k"] = Size(3840, 2160);
31
return res;
32
}
33
34
inline map<string, int> fourccByCodec()
35
{
36
map<string, int> res;
37
res["h264"] = VideoWriter::fourcc('H','2','6','4');
38
res["h265"] = VideoWriter::fourcc('H','E','V','C');
39
res["mpeg2"] = VideoWriter::fourcc('M','P','E','G');
40
res["mpeg4"] = VideoWriter::fourcc('M','P','4','2');
41
res["mjpeg"] = VideoWriter::fourcc('M','J','P','G');
42
res["vp8"] = VideoWriter::fourcc('V','P','8','0');
43
return res;
44
}
45
46
inline map<string, string> defaultEncodeElementByCodec()
47
{
48
map<string, string> res;
49
res["h264"] = "x264enc";
50
res["h265"] = "x265enc";
51
res["mpeg2"] = "mpeg2enc";
52
res["mjpeg"] = "jpegenc";
53
res["vp8"] = "vp8enc";
54
return res;
55
}
56
57
inline map<string, string> VAAPIEncodeElementByCodec()
58
{
59
map<string, string> res;
60
res["h264"] = "parsebin ! vaapih264enc";
61
res["h265"] = "parsebin ! vaapih265enc";
62
res["mpeg2"] = "parsebin ! vaapimpeg2enc";
63
res["mjpeg"] = "parsebin ! vaapijpegenc";
64
res["vp8"] = "parsebin ! vaapivp8enc";
65
return res;
66
}
67
68
inline map<string, string> mfxDecodeElementByCodec()
69
{
70
map<string, string> res;
71
res["h264"] = "parsebin ! mfxh264dec";
72
res["h265"] = "parsebin ! mfxhevcdec";
73
res["mpeg2"] = "parsebin ! mfxmpeg2dec";
74
res["mjpeg"] = "parsebin ! mfxjpegdec";
75
return res;
76
}
77
78
inline map<string, string> mfxEncodeElementByCodec()
79
{
80
map<string, string> res;
81
res["h264"] = "mfxh264enc";
82
res["h265"] = "mfxhevcenc";
83
res["mpeg2"] = "mfxmpeg2enc";
84
res["mjpeg"] = "mfxjpegenc";
85
return res;
86
}
87
88
inline map<string, string> libavDecodeElementByCodec()
89
{
90
map<string, string> res;
91
res["h264"] = "parsebin ! avdec_h264";
92
res["h265"] = "parsebin ! avdec_h265";
93
res["mpeg2"] = "parsebin ! avdec_mpeg2video";
94
res["mpeg4"] = "parsebin ! avdec_mpeg4";
95
res["mjpeg"] = "parsebin ! avdec_mjpeg";
96
res["vp8"] = "parsebin ! avdec_vp8";
97
return res;
98
}
99
100
inline map<string, string> libavEncodeElementByCodec()
101
{
102
map<string, string> res;
103
res["h264"] = "avenc_h264";
104
res["h265"] = "avenc_h265";
105
res["mpeg2"] = "avenc_mpeg2video";
106
res["mpeg4"] = "avenc_mpeg4";
107
res["mjpeg"] = "avenc_mjpeg";
108
res["vp8"] = "avenc_vp8";
109
return res;
110
}
111
112
inline map<string, string> demuxPluginByContainer()
113
{
114
map<string, string> res;
115
res["avi"] = "avidemux";
116
res["mp4"] = "qtdemux";
117
res["mov"] = "qtdemux";
118
res["mkv"] = "matroskademux";
119
return res;
120
}
121
122
inline map<string, string> muxPluginByContainer()
123
{
124
map<string, string> res;
125
res["avi"] = "avimux";
126
res["mp4"] = "qtmux";
127
res["mov"] = "qtmux";
128
res["mkv"] = "matroskamux";
129
return res;
130
}
131
132
//================================================================================
133
134
inline string containerByName(const string &name)
135
{
136
size_t found = name.rfind(".");
137
if (found != string::npos)
138
{
139
return name.substr(found + 1); // container type
140
}
141
return string();
142
}
143
144
//================================================================================
145
146
inline Ptr<VideoCapture> createCapture(const string &backend, const string &file_name, const string &codec)
147
{
148
if (backend == "gst-default")
149
{
150
cout << "Created GStreamer capture ( " << file_name << " )" << endl;
151
return makePtr<VideoCapture>(file_name, CAP_GSTREAMER);
152
}
153
else if (backend.find("gst") == 0)
154
{
155
ostringstream line;
156
line << "filesrc location=\"" << file_name << "\"";
157
line << " ! ";
158
line << getValue(demuxPluginByContainer(), containerByName(file_name), "Invalid container");
159
line << " ! ";
160
if (backend.find("basic") == 4)
161
line << "decodebin";
162
else if (backend.find("vaapi") == 4)
163
line << "vaapidecodebin";
164
else if (backend.find("libav") == 4)
165
line << getValue(libavDecodeElementByCodec(), codec, "Invalid codec");
166
else if (backend.find("mfx") == 4)
167
line << getValue(mfxDecodeElementByCodec(), codec, "Invalid or unsupported codec");
168
else
169
return Ptr<VideoCapture>();
170
line << " ! videoconvert n-threads=" << getNumThreads();
171
line << " ! appsink sync=false";
172
cout << "Created GStreamer capture ( " << line.str() << " )" << endl;
173
return makePtr<VideoCapture>(line.str(), CAP_GSTREAMER);
174
}
175
else if (backend == "ffmpeg")
176
{
177
cout << "Created FFmpeg capture ( " << file_name << " )" << endl;
178
return makePtr<VideoCapture>(file_name, CAP_FFMPEG);
179
}
180
return Ptr<VideoCapture>();
181
}
182
183
inline Ptr<VideoCapture> createSynthSource(Size sz, unsigned fps)
184
{
185
ostringstream line;
186
line << "videotestsrc pattern=smpte";
187
line << " ! video/x-raw";
188
line << ",width=" << sz.width << ",height=" << sz.height;
189
if (fps > 0)
190
line << ",framerate=" << fps << "/1";
191
line << " ! appsink sync=false";
192
cout << "Created synthetic video source ( " << line.str() << " )" << endl;
193
return makePtr<VideoCapture>(line.str(), CAP_GSTREAMER);
194
}
195
196
inline Ptr<VideoWriter> createWriter(const string &backend, const string &file_name, const string &codec, Size sz, unsigned fps)
197
{
198
if (backend == "gst-default")
199
{
200
cout << "Created GStreamer writer ( " << file_name << ", FPS=" << fps << ", Size=" << sz << ")" << endl;
201
return makePtr<VideoWriter>(file_name, CAP_GSTREAMER, getValue(fourccByCodec(), codec, "Invalid codec"), fps, sz, true);
202
}
203
else if (backend.find("gst") == 0)
204
{
205
ostringstream line;
206
line << "appsrc ! videoconvert n-threads=" << getNumThreads() << " ! ";
207
if (backend.find("basic") == 4)
208
line << getValue(defaultEncodeElementByCodec(), codec, "Invalid codec");
209
else if (backend.find("vaapi") == 4)
210
line << getValue(VAAPIEncodeElementByCodec(), codec, "Invalid codec");
211
else if (backend.find("libav") == 4)
212
line << getValue(libavEncodeElementByCodec(), codec, "Invalid codec");
213
else if (backend.find("mfx") == 4)
214
line << getValue(mfxEncodeElementByCodec(), codec, "Invalid codec");
215
else
216
return Ptr<VideoWriter>();
217
line << " ! ";
218
line << getValue(muxPluginByContainer(), containerByName(file_name), "Invalid container");
219
line << " ! ";
220
line << "filesink location=\"" << file_name << "\"";
221
cout << "Created GStreamer writer ( " << line.str() << " )" << endl;
222
return makePtr<VideoWriter>(line.str(), CAP_GSTREAMER, 0, fps, sz, true);
223
}
224
else if (backend == "ffmpeg")
225
{
226
cout << "Created FFMpeg writer ( " << file_name << ", FPS=" << fps << ", Size=" << sz << " )" << endl;
227
return makePtr<VideoWriter>(file_name, CAP_FFMPEG, getValue(fourccByCodec(), codec, "Invalid codec"), fps, sz, true);
228
}
229
return Ptr<VideoWriter>();
230
}
231
232
//================================================================================
233
234
int main(int argc, char *argv[])
235
{
236
const string keys =
237
"{h help usage ? | | print help messages }"
238
"{m mode |decode | coding mode (supported: encode, decode) }"
239
"{b backend |default | video backend (supported: 'gst-default', 'gst-basic', 'gst-vaapi', 'gst-libav', 'gst-mfx', 'ffmpeg') }"
240
"{c codec |h264 | codec name (supported: 'h264', 'h265', 'mpeg2', 'mpeg4', 'mjpeg', 'vp8') }"
241
"{f file path | | path to file }"
242
"{r resolution |720p | video resolution for encoding (supported: '720p', '1080p', '4k') }"
243
"{fps |30 | fix frame per second for encoding (supported: fps > 0) }"
244
"{fast | | fast measure fps }";
245
CommandLineParser cmd_parser(argc, argv, keys);
246
cmd_parser.about("This program measures performance of video encoding and decoding using different backends OpenCV.");
247
if (cmd_parser.has("help"))
248
{
249
cmd_parser.printMessage();
250
return 0;
251
}
252
bool fast_measure = cmd_parser.has("fast"); // fast measure fps
253
unsigned fix_fps = cmd_parser.get<unsigned>("fps"); // fixed frame per second
254
string backend = cmd_parser.get<string>("backend"); // video backend
255
string mode = cmd_parser.get<string>("mode"); // coding mode
256
string codec = cmd_parser.get<string>("codec"); // codec type
257
string file_name = cmd_parser.get<string>("file"); // path to videofile
258
string resolution = cmd_parser.get<string>("resolution"); // video resolution
259
if (!cmd_parser.check())
260
{
261
cmd_parser.printErrors();
262
return -1;
263
}
264
if (mode != "encode" && mode != "decode")
265
{
266
cout << "Unsupported mode: " << mode << endl;
267
return -1;
268
}
269
cout << "Mode: " << mode << ", Backend: " << backend << ", File: " << file_name << ", Codec: " << codec << endl;
270
271
TickMeter total;
272
Ptr<VideoCapture> cap;
273
Ptr<VideoWriter> wrt;
274
try
275
{
276
if (mode == "decode")
277
{
278
cap = createCapture(backend, file_name, codec);
279
if (!cap)
280
{
281
cout << "Failed to create video capture" << endl;
282
return -3;
283
}
284
if (!cap->isOpened())
285
{
286
cout << "Capture is not opened" << endl;
287
return -4;
288
}
289
}
290
else if (mode == "encode")
291
{
292
Size sz = getValue(sizeByResolution(), resolution, "Invalid resolution");
293
cout << "FPS: " << fix_fps << ", Frame size: " << sz << endl;
294
cap = createSynthSource(sz, fix_fps);
295
wrt = createWriter(backend, file_name, codec, sz, fix_fps);
296
if (!cap || !wrt)
297
{
298
cout << "Failed to create synthetic video source or video writer" << endl;
299
return -3;
300
}
301
if (!cap->isOpened() || !wrt->isOpened())
302
{
303
cout << "Synthetic video source or video writer is not opened" << endl;
304
return -4;
305
}
306
}
307
}
308
catch (...)
309
{
310
cout << "Unsupported parameters" << endl;
311
return -2;
312
}
313
314
TickMeter tick;
315
Mat frame;
316
Mat element;
317
total.start();
318
while(true)
319
{
320
if (mode == "decode")
321
{
322
tick.start();
323
if (!cap->grab())
324
{
325
cout << "No more frames - break" << endl;
326
break;
327
}
328
if (!cap->retrieve(frame))
329
{
330
cout << "Failed to retrieve frame - break" << endl;
331
break;
332
}
333
if (frame.empty())
334
{
335
cout << "Empty frame received - break" << endl;
336
break;
337
}
338
tick.stop();
339
}
340
else if (mode == "encode")
341
{
342
int limit = 100;
343
while (!cap->grab() && --limit != 0)
344
{
345
cout << "Skipping empty input frame - " << limit << endl;
346
}
347
cap->retrieve(element);
348
tick.start();
349
*wrt << element;
350
tick.stop();
351
}
352
353
if (fast_measure && tick.getCounter() >= 1000)
354
{
355
cout << "Fast mode frame limit reached - break" << endl;
356
break;
357
}
358
if (mode == "encode" && tick.getCounter() >= 1000)
359
{
360
cout << "Encode frame limit reached - break" << endl;
361
break;
362
}
363
}
364
total.stop();
365
if (tick.getCounter() == 0)
366
{
367
cout << "No frames have been processed" << endl;
368
return -10;
369
}
370
else
371
{
372
double res_fps = tick.getCounter() / tick.getTimeSec();
373
cout << tick.getCounter() << " frames in " << tick.getTimeSec() << " sec ~ " << res_fps << " FPS" << " (total time: " << total.getTimeSec() << " sec)" << endl;
374
}
375
return 0;
376
}
377
378