video_acceleration.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #include <iostream>
  2. #include <chrono>
  3. #include "opencv2/core.hpp"
  4. #include "opencv2/core/ocl.hpp"
  5. #include "opencv2/core/utility.hpp"
  6. #include "opencv2/imgproc.hpp"
  7. #include "opencv2/videoio.hpp"
  8. #include "opencv2/highgui.hpp"
  9. using namespace cv;
  10. using namespace std;
  11. const char* keys =
  12. "{ i input | | input video file }"
  13. "{ o output | | output video file, or specify 'null' to measure decoding without rendering to screen}"
  14. "{ backend | any | VideoCapture and VideoWriter backend, valid values: 'any', 'ffmpeg', 'msmf', 'gstreamer' }"
  15. "{ accel | any | GPU Video Acceleration, valid values: 'none', 'any', 'd3d11', 'vaapi', 'mfx' }"
  16. "{ device | -1 | Video Acceleration device (GPU) index (-1 means default device) }"
  17. "{ out_w | | output width (resize by calling cv::resize) }"
  18. "{ out_h | | output height (resize by calling cv::resize) }"
  19. "{ bitwise_not| false | apply simple image processing - bitwise_not pixels by calling cv::bitwise_not }"
  20. "{ opencl | true | use OpenCL (inside VideoCapture/VideoWriter and for image processing) }"
  21. "{ codec | H264 | codec id (four characters string) of output file encoder }"
  22. "{ h help | | print help message }";
  23. struct {
  24. cv::VideoCaptureAPIs backend;
  25. const char* str;
  26. } backend_strings[] = {
  27. { cv::CAP_ANY, "any" },
  28. { cv::CAP_FFMPEG, "ffmpeg" },
  29. { cv::CAP_MSMF, "msmf" },
  30. { cv::CAP_GSTREAMER, "gstreamer" },
  31. };
  32. struct {
  33. VideoAccelerationType acceleration;
  34. const char* str;
  35. } acceleration_strings[] = {
  36. { VIDEO_ACCELERATION_NONE, "none" },
  37. { VIDEO_ACCELERATION_ANY, "any" },
  38. { VIDEO_ACCELERATION_D3D11, "d3d11" },
  39. { VIDEO_ACCELERATION_VAAPI, "vaapi" },
  40. { VIDEO_ACCELERATION_MFX, "mfx" },
  41. { VIDEO_ACCELERATION_DRM, "drm" },
  42. };
  43. class FPSCounter {
  44. public:
  45. FPSCounter(double _interval) : interval(_interval) {
  46. }
  47. ~FPSCounter() {
  48. NewFrame(true);
  49. }
  50. void NewFrame(bool last_frame = false) {
  51. num_frames++;
  52. auto now = std::chrono::high_resolution_clock::now();
  53. if (!last_time.time_since_epoch().count()) {
  54. last_time = now;
  55. }
  56. double sec = std::chrono::duration_cast<std::chrono::duration<double>>(now - last_time).count();
  57. if (sec >= interval || last_frame) {
  58. printf("FPS(last %.2f sec) = %.2f\n", sec, num_frames / sec);
  59. fflush(stdout);
  60. num_frames = 0;
  61. last_time = now;
  62. }
  63. }
  64. private:
  65. double interval = 1;
  66. std::chrono::time_point<std::chrono::high_resolution_clock> last_time;
  67. int num_frames = 0;
  68. };
  69. int main(int argc, char** argv)
  70. {
  71. cv::CommandLineParser cmd(argc, argv, keys);
  72. if (cmd.has("help"))
  73. {
  74. cout << "Usage : video_acceleration [options]" << endl;
  75. cout << "Available options:" << endl;
  76. cmd.printMessage();
  77. return EXIT_SUCCESS;
  78. }
  79. string infile = cmd.get<string>("i");
  80. string outfile = cmd.get<string>("o");
  81. string codec = cmd.get<string>("codec");
  82. int device = cmd.get<int>("device");
  83. int out_w = cmd.get<int>("out_w");
  84. int out_h = cmd.get<int>("out_h");
  85. bool use_opencl = cmd.get<bool>("opencl");
  86. bool bitwise_not = cmd.get<bool>("bitwise_not");
  87. cv::VideoCaptureAPIs backend = cv::CAP_ANY;
  88. string backend_str = cmd.get<string>("backend");
  89. for (size_t i = 0; i < sizeof(backend_strings)/sizeof(backend_strings[0]); i++) {
  90. if (backend_str == backend_strings[i].str) {
  91. backend = backend_strings[i].backend;
  92. break;
  93. }
  94. }
  95. VideoAccelerationType accel = VIDEO_ACCELERATION_ANY;
  96. string accel_str = cmd.get<string>("accel");
  97. for (size_t i = 0; i < sizeof(acceleration_strings) / sizeof(acceleration_strings[0]); i++) {
  98. if (accel_str == acceleration_strings[i].str) {
  99. accel = acceleration_strings[i].acceleration;
  100. break;
  101. }
  102. }
  103. ocl::setUseOpenCL(use_opencl);
  104. VideoCapture capture(infile, backend, {
  105. CAP_PROP_HW_ACCELERATION, (int)accel,
  106. CAP_PROP_HW_DEVICE, device
  107. });
  108. if (!capture.isOpened()) {
  109. cerr << "Failed to open VideoCapture" << endl;
  110. return 1;
  111. }
  112. cout << "VideoCapture backend = " << capture.getBackendName() << endl;
  113. VideoAccelerationType actual_accel = static_cast<VideoAccelerationType>(static_cast<int>(capture.get(CAP_PROP_HW_ACCELERATION)));
  114. for (size_t i = 0; i < sizeof(acceleration_strings) / sizeof(acceleration_strings[0]); i++) {
  115. if (actual_accel == acceleration_strings[i].acceleration) {
  116. cout << "VideoCapture acceleration = " << acceleration_strings[i].str << endl;
  117. cout << "VideoCapture acceleration device = " << (int)capture.get(CAP_PROP_HW_DEVICE) << endl;
  118. break;
  119. }
  120. }
  121. VideoWriter writer;
  122. if (!outfile.empty() && outfile != "null") {
  123. const char* codec_str = codec.c_str();
  124. int fourcc = VideoWriter::fourcc(codec_str[0], codec_str[1], codec_str[2], codec_str[3]);
  125. double fps = capture.get(CAP_PROP_FPS);
  126. Size frameSize = { out_w, out_h };
  127. if (!out_w || !out_h) {
  128. frameSize = { (int)capture.get(CAP_PROP_FRAME_WIDTH), (int)capture.get(CAP_PROP_FRAME_HEIGHT) };
  129. }
  130. writer = VideoWriter(outfile, backend, fourcc, fps, frameSize, {
  131. VIDEOWRITER_PROP_HW_ACCELERATION, (int)accel,
  132. VIDEOWRITER_PROP_HW_DEVICE, device
  133. });
  134. if (!writer.isOpened()) {
  135. cerr << "Failed to open VideoWriter" << endl;
  136. return 1;
  137. }
  138. cout << "VideoWriter backend = " << writer.getBackendName() << endl;
  139. actual_accel = static_cast<VideoAccelerationType>(static_cast<int>(writer.get(VIDEOWRITER_PROP_HW_ACCELERATION)));
  140. for (size_t i = 0; i < sizeof(acceleration_strings) / sizeof(acceleration_strings[0]); i++) {
  141. if (actual_accel == acceleration_strings[i].acceleration) {
  142. cout << "VideoWriter acceleration = " << acceleration_strings[i].str << endl;
  143. cout << "VideoWriter acceleration device = " << (int)writer.get(VIDEOWRITER_PROP_HW_DEVICE) << endl;
  144. break;
  145. }
  146. }
  147. }
  148. cout << "\nStarting frame loop. Press ESC to exit\n";
  149. FPSCounter fps_counter(0.5); // print FPS every 0.5 seconds
  150. UMat frame, frame2, frame3;
  151. for (;;)
  152. {
  153. capture.read(frame);
  154. if (frame.empty()) {
  155. cout << "End of stream" << endl;
  156. break;
  157. }
  158. if (out_w && out_h) {
  159. cv::resize(frame, frame2, cv::Size(out_w, out_h));
  160. //cv::cvtColor(frame, outframe, COLOR_BGRA2RGBA);
  161. }
  162. else {
  163. frame2 = frame;
  164. }
  165. if (bitwise_not) {
  166. cv::bitwise_not(frame2, frame3);
  167. }
  168. else {
  169. frame3 = frame2;
  170. }
  171. if (writer.isOpened()) {
  172. writer.write(frame3);
  173. }
  174. if (outfile.empty()) {
  175. imshow("output", frame3);
  176. char key = (char) waitKey(1);
  177. if (key == 27)
  178. break;
  179. else if (key == 'm') {
  180. ocl::setUseOpenCL(!cv::ocl::useOpenCL());
  181. cout << "Switched to " << (ocl::useOpenCL() ? "OpenCL enabled" : "CPU") << " mode\n";
  182. }
  183. }
  184. fps_counter.NewFrame();
  185. }
  186. return EXIT_SUCCESS;
  187. }