#include "opencv2/core/utility.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/imgcodecs.hpp" #include "opencv2/highgui.hpp" #include #include using namespace std; using namespace cv; class GStreamerPipeline { public: // Preprocessing arguments command line GStreamerPipeline(int argc, char *argv[]) { const string keys = "{h help usage ? | | print help messages }" "{m mode | | coding mode (supported: encode, decode) }" "{p pipeline |default | pipeline name (supported: 'default', 'gst-basic', 'gst-vaapi', 'gst-libav', 'ffmpeg') }" "{cd codec |h264 | codec name (supported: 'h264', 'h265', 'mpeg2', 'mpeg4', 'mjpeg', 'vp8') }" "{f file path | | path to file }" "{vr resolution |720p | video resolution for encoding (supported: '720p', '1080p', '4k') }" "{fps |30 | fix frame per second for encoding (supported: fps > 0) }" "{fm fast | | fast measure fps }"; cmd_parser = new CommandLineParser(argc, argv, keys); cmd_parser->about("This program shows how to read a video file with GStreamer pipeline with OpenCV."); if (cmd_parser->has("help")) { cmd_parser->printMessage(); CV_Error(Error::StsBadArg, "Called help."); } fast_measure = cmd_parser->has("fast"); // fast measure fps fix_fps = cmd_parser->get("fps"); // fixed frame per second pipeline = cmd_parser->get("pipeline"), // gstreamer pipeline type mode = cmd_parser->get("mode"), // coding mode codec = cmd_parser->get("codec"), // codec type file_name = cmd_parser->get("file"), // path to videofile resolution = cmd_parser->get("resolution"); // video resolution size_t found = file_name.rfind("."); if (found != string::npos) { container = file_name.substr(found + 1); // container type } else { CV_Error(Error::StsBadArg, "Can not parse container extension."); } if (!cmd_parser->check()) { cmd_parser->printErrors(); CV_Error(Error::StsBadArg, "Failed parse arguments."); } } ~GStreamerPipeline() { delete cmd_parser; } // Start pipeline int run() { if (mode == "decode") { if (createDecodePipeline() < 0) return -1; } else if (mode == "encode") { if (createEncodePipeline() < 0) return -1; } else { cout << "Unsupported mode: " << mode << endl; cmd_parser->printErrors(); return -1; } cout << "_____________________________________" << endl; cout << "Pipeline " << mode << ":" << endl; cout << stream_pipeline.str() << endl; // Choose a show video or only measure fps cout << "_____________________________________" << endl; cout << "Start measure frame per seconds (fps)" << endl; cout << "Loading ..." << endl; vector tick_counts; cout << "Start " << mode << ": " << file_name; cout << " (" << pipeline << ")" << endl; while(true) { int64 temp_count_tick = 0; if (mode == "decode") { Mat frame; temp_count_tick = getTickCount(); cap >> frame; temp_count_tick = getTickCount() - temp_count_tick; if (frame.empty()) { break; } } else if (mode == "encode") { Mat element; while(!cap.grab()); cap.retrieve(element); temp_count_tick = getTickCount(); wrt << element; temp_count_tick = getTickCount() - temp_count_tick; } tick_counts.push_back(static_cast(temp_count_tick)); if (((mode == "decode") && fast_measure && (tick_counts.size() > 1e3)) || ((mode == "encode") && (tick_counts.size() > 3e3)) || ((mode == "encode") && fast_measure && (tick_counts.size() > 1e2))) { break; } } double time_fps = sum(tick_counts)[0] / getTickFrequency(); if (tick_counts.size() != 0) { cout << "Finished: " << tick_counts.size() << " in " << time_fps <<" sec ~ " ; cout << tick_counts.size() / time_fps <<" fps " << endl; } else { cout << "Failed " << mode << ": " << file_name; cout << " (" << pipeline << ")" << endl; return -1; } return 0; } // Free video resource void close() { cap.release(); wrt.release(); } private: // Choose the constructed GStreamer pipeline for decode int createDecodePipeline() { if (pipeline == "default") { cap = VideoCapture(file_name, CAP_GSTREAMER); } else if (pipeline.find("gst") == 0) { stream_pipeline << "filesrc location=\"" << file_name << "\""; stream_pipeline << " ! " << getGstMuxPlugin(); if (pipeline.find("basic") == 4) { stream_pipeline << getGstDefaultCodePlugin(); } else if (pipeline.find("vaapi1710") == 4) { stream_pipeline << getGstVaapiCodePlugin(); } else if (pipeline.find("libav") == 4) { stream_pipeline << getGstAvCodePlugin(); } else { cout << "Unsupported pipeline: " << pipeline << endl; cmd_parser->printErrors(); return -1; } stream_pipeline << " ! videoconvert n-threads=" << getNumThreads(); stream_pipeline << " ! appsink sync=false"; cap = VideoCapture(stream_pipeline.str(), CAP_GSTREAMER); } else if (pipeline == "ffmpeg") { cap = VideoCapture(file_name, CAP_FFMPEG); stream_pipeline << "default pipeline for ffmpeg" << endl; } else { cout << "Unsupported pipeline: " << pipeline << endl; cmd_parser->printErrors(); return -1; } return 0; } // Choose the constructed GStreamer pipeline for encode int createEncodePipeline() { if (checkConfiguration() < 0) return -1; ostringstream test_pipeline; test_pipeline << "videotestsrc pattern=smpte"; test_pipeline << " ! video/x-raw, " << getVideoSettings(); test_pipeline << " ! appsink sync=false"; cap = VideoCapture(test_pipeline.str(), CAP_GSTREAMER); if (pipeline == "default") { wrt = VideoWriter(file_name, CAP_GSTREAMER, getFourccCode(), fix_fps, fix_size, true); } else if (pipeline.find("gst") == 0) { stream_pipeline << "appsrc ! videoconvert n-threads=" << getNumThreads() << " ! "; if (pipeline.find("basic") == 4) { stream_pipeline << getGstDefaultCodePlugin(); } else if (pipeline.find("vaapi1710") == 4) { stream_pipeline << getGstVaapiCodePlugin(); } else if (pipeline.find("libav") == 4) { stream_pipeline << getGstAvCodePlugin(); } else { cout << "Unsupported pipeline: " << pipeline << endl; cmd_parser->printErrors(); return -1; } stream_pipeline << " ! " << getGstMuxPlugin(); stream_pipeline << " ! filesink location=\"" << file_name << "\""; wrt = VideoWriter(stream_pipeline.str(), CAP_GSTREAMER, 0, fix_fps, fix_size, true); } else if (pipeline == "ffmpeg") { wrt = VideoWriter(file_name, CAP_FFMPEG, getFourccCode(), fix_fps, fix_size, true); stream_pipeline << "default pipeline for ffmpeg" << endl; } else { cout << "Unsupported pipeline: " << pipeline << endl; cmd_parser->printErrors(); return -1; } return 0; } // Choose video resolution for encoding string getVideoSettings() { ostringstream video_size; if (fix_fps > 0) { video_size << "framerate=" << fix_fps << "/1, "; } else { cout << "Unsupported fps (< 0): " << fix_fps << endl; cmd_parser->printErrors(); return string(); } if (resolution == "720p") { fix_size = Size(1280, 720); } else if (resolution == "1080p") { fix_size = Size(1920, 1080); } else if (resolution == "4k") { fix_size = Size(3840, 2160); } else { cout << "Unsupported video resolution: " << resolution << endl; cmd_parser->printErrors(); return string(); } video_size << "width=" << fix_size.width << ", height=" << fix_size.height; return video_size.str(); } // Choose a video container string getGstMuxPlugin() { ostringstream plugin; if (container == "avi") { plugin << "avi"; } else if (container == "mp4") { plugin << "qt"; } else if (container == "mov") { plugin << "qt"; } else if (container == "mkv") { plugin << "matroska"; } else { cout << "Unsupported container: " << container << endl; cmd_parser->printErrors(); return string(); } if (mode == "decode") { plugin << "demux"; } else if (mode == "encode") { plugin << "mux"; } else { cout << "Unsupported mode: " << mode << endl; cmd_parser->printErrors(); return string(); } return plugin.str(); } // Choose a libav codec string getGstAvCodePlugin() { ostringstream plugin; if (mode == "decode") { if (codec == "h264") { plugin << "h264parse ! "; } else if (codec == "h265") { plugin << "h265parse ! "; } plugin << "avdec_"; } else if (mode == "encode") { plugin << "avenc_"; } else { cout << "Unsupported mode: " << mode << endl; cmd_parser->printErrors(); return string(); } if (codec == "h264") { plugin << "h264"; } else if (codec == "h265") { plugin << "h265"; } else if (codec == "mpeg2") { plugin << "mpeg2video"; } else if (codec == "mpeg4") { plugin << "mpeg4"; } else if (codec == "mjpeg") { plugin << "mjpeg"; } else if (codec == "vp8") { plugin << "vp8"; } else { cout << "Unsupported libav codec: " << codec << endl; cmd_parser->printErrors(); return string(); } return plugin.str(); } // Choose a vaapi codec string getGstVaapiCodePlugin() { ostringstream plugin; if (mode == "decode") { plugin << "vaapidecodebin"; if (container == "mkv") { plugin << " ! autovideoconvert"; } else { plugin << " ! video/x-raw, format=YV12"; } } else if (mode == "encode") { if (codec == "h264") { plugin << "vaapih264enc"; } else if (codec == "h265") { plugin << "vaapih265enc"; } else if (codec == "mpeg2") { plugin << "vaapimpeg2enc"; } else if (codec == "mjpeg") { plugin << "vaapijpegenc"; } else if (codec == "vp8") { plugin << "vaapivp8enc"; } else { cout << "Unsupported vaapi codec: " << codec << endl; cmd_parser->printErrors(); return string(); } } else { cout << "Unsupported mode: " << resolution << endl; cmd_parser->printErrors(); return string(); } return plugin.str(); } // Choose a default codec string getGstDefaultCodePlugin() { ostringstream plugin; if (mode == "decode") { plugin << " ! decodebin"; } else if (mode == "encode") { if (codec == "h264") { plugin << "x264enc"; } else if (codec == "h265") { plugin << "x265enc"; } else if (codec == "mpeg2") { plugin << "mpeg2enc"; } else if (codec == "mjpeg") { plugin << "jpegenc"; } else if (codec == "vp8") { plugin << "vp8enc"; } else { cout << "Unsupported default codec: " << codec << endl; cmd_parser->printErrors(); return string(); } } else { cout << "Unsupported mode: " << resolution << endl; cmd_parser->printErrors(); return string(); } return plugin.str(); } // Get fourcc for codec int getFourccCode() { if (codec == "h264") { return VideoWriter::fourcc('H','2','6','4'); } else if (codec == "h265") { return VideoWriter::fourcc('H','E','V','C'); } else if (codec == "mpeg2") { return VideoWriter::fourcc('M','P','E','G'); } else if (codec == "mpeg4") { return VideoWriter::fourcc('M','P','4','2'); } else if (codec == "mjpeg") { return VideoWriter::fourcc('M','J','P','G'); } else if (codec == "vp8") { return VideoWriter::fourcc('V','P','8','0'); } else { cout << "Unsupported ffmpeg codec: " << codec << endl; cmd_parser->printErrors(); return 0; } } // Check bad configuration int checkConfiguration() { if ((codec == "mpeg2" && getGstMuxPlugin() == "qtmux") || (codec == "h265" && getGstMuxPlugin() == "avimux") || (pipeline == "gst-libav" && (codec == "h264" || codec == "h265")) || (pipeline == "gst-vaapi1710" && codec=="mpeg2" && resolution=="4k") || (pipeline == "gst-vaapi1710" && codec=="mpeg2" && resolution=="1080p" && fix_fps > 30)) { cout << "Unsupported configuration" << endl; cmd_parser->printErrors(); return -1; } return 0; } bool fast_measure; // fast measure fps string pipeline, // gstreamer pipeline type container, // container type mode, // coding mode codec, // codec type file_name, // path to videofile resolution; // video resolution int fix_fps; // fixed frame per second Size fix_size; // fixed frame size VideoWriter wrt; VideoCapture cap; ostringstream stream_pipeline; CommandLineParser* cmd_parser; }; int main(int argc, char *argv[]) { try { GStreamerPipeline pipe(argc, argv); return pipe.run(); } catch(const Exception& e) { cerr << e.what() << endl; return 1; } }