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