opencv/samples/tapi/video_acceleration.cpp

212 lines
7.3 KiB
C++
Raw Normal View History

Merge pull request #19460 from mikhail-nikolskiy:videoio-hw videoio: HW decode/encode in FFMPEG backend; new properties with support in FFMPEG/GST/MSMF * HW acceleration in FFMPEG backend * fixes on Windows, remove D3D9 * HW acceleration in FFMPEG backend * fixes on Windows, remove D3D9 * improve va test * Copyright * check LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 78, 100) // FFMPEG 3.4+ * CAP_MSMF test on .mp4 * .mp4 in test * improve va test * Copyright * check LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 78, 100) // FFMPEG 3.4+ * CAP_MSMF test on .mp4 * .mp4 in test * .avi for GStreamer test * revert changes around seek() * cv_writer_open_with_params * params.warnUnusedParameters * VideoCaptureParameters in GStreamer * open_with_params * params->getUnused * Reduce PSNR threshold 33->32 (other tests use 30) * require FFMPEG 4.0+; PSNR 30 as in other tests * GStreamer AVI-demux plugin not installed in Ubuntu test environment? * fix build on very old ffmpeg * fix build on very old ffmpeg * fix build issues * fix build issues (static_cast) * FFMPEG built on Windows without H264 encoder? * fix for write_nothing test on VAAPI * fix warnings * fix cv_writer_get_prop in plugins * use avcodec_get_hw_frames_parameters; more robust fallback to SW codecs * internal function hw_check_device() for device check/logging * two separate tests for HW read and write * image size 640x480 in encode test * WITH_VA=ON (only .h headers used in OpenCV, no linkage dependency) * exception on VP9 SW encoder? * rebase master; refine info message * videoio: fix FFmpeg standalone plugin build * videoio(ffmpeg): eliminate MSVC build warnings * address review comments * videoio(hw): update videocapture_acceleration.read test - remove parallel decoding by SW code path - check PSNR against the original generated image * videoio: minor fixes * videoio(test): disable unsupported MSMF cases (SW and HW) * videoio(test): update PSNR thresholds for HW acceleration read * videoio(test): update debug messages * "hw_acceleration" whitelisting parameter * little optimization in test * D3D11VA supports decoders, doesn't support encoders * videoio(test): adjust PSNR threshold in write_read_position tests * videoio(ffmpeg): fix rejecting on acceleration device name mismatch * videoio(ffmpeg): fix compilation USE_AV_HW_CODECS=0, add more debug logging * videoio: rework VideoAccelerationType behavior - enum is not a bitset - default value is backend specific - only '_NONE' and '_ANY' may fallback on software processing - specific H/W acceleration doesn't fallback on software processing. It fails if there is no support for specified H/W acceleration. * videoio(test): fix for current FFmpeg wrapper Co-authored-by: Alexander Alekhin <alexander.a.alekhin@gmail.com>
2021-03-01 23:51:04 +08:00
#include <iostream>
#include <chrono>
#include "opencv2/core.hpp"
#include "opencv2/core/ocl.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
using namespace std;
const char* keys =
"{ i input | | input video file }"
"{ o output | | output video file, or specify 'null' to measure decoding without rendering to screen}"
"{ backend | any | VideoCapture and VideoWriter backend, valid values: 'any', 'ffmpeg', 'msmf', 'gstreamer' }"
"{ accel | any | GPU Video Acceleration, valid values: 'none', 'any', 'd3d11', 'vaapi', 'mfx' }"
"{ device | -1 | Video Acceleration device (GPU) index (-1 means default device) }"
"{ out_w | | output width (resize by calling cv::resize) }"
"{ out_h | | output height (resize by calling cv::resize) }"
"{ bitwise_not| false | apply simple image processing - bitwise_not pixels by calling cv::bitwise_not }"
"{ opencl | true | use OpenCL (inside VideoCapture/VideoWriter and for image processing) }"
"{ codec | H264 | codec id (four characters string) of output file encoder }"
"{ h help | | print help message }";
struct {
cv::VideoCaptureAPIs backend;
const char* str;
} backend_strings[] = {
{ cv::CAP_ANY, "any" },
{ cv::CAP_FFMPEG, "ffmpeg" },
{ cv::CAP_MSMF, "msmf" },
{ cv::CAP_GSTREAMER, "gstreamer" },
};
struct {
VideoAccelerationType acceleration;
const char* str;
} acceleration_strings[] = {
{ VIDEO_ACCELERATION_NONE, "none" },
{ VIDEO_ACCELERATION_ANY, "any" },
{ VIDEO_ACCELERATION_D3D11, "d3d11" },
{ VIDEO_ACCELERATION_VAAPI, "vaapi" },
{ VIDEO_ACCELERATION_MFX, "mfx" },
};
class FPSCounter {
public:
FPSCounter(double _interval) : interval(_interval) {
}
~FPSCounter() {
NewFrame(true);
}
void NewFrame(bool last_frame = false) {
num_frames++;
auto now = std::chrono::high_resolution_clock::now();
if (!last_time.time_since_epoch().count()) {
last_time = now;
}
double sec = std::chrono::duration_cast<std::chrono::duration<double>>(now - last_time).count();
if (sec >= interval || last_frame) {
printf("FPS(last %.2f sec) = %.2f\n", sec, num_frames / sec);
fflush(stdout);
num_frames = 0;
last_time = now;
}
}
private:
double interval = 1;
std::chrono::time_point<std::chrono::high_resolution_clock> last_time;
int num_frames = 0;
};
int main(int argc, char** argv)
{
cv::CommandLineParser cmd(argc, argv, keys);
if (cmd.has("help"))
{
cout << "Usage : video_acceleration [options]" << endl;
cout << "Available options:" << endl;
cmd.printMessage();
return EXIT_SUCCESS;
}
string infile = cmd.get<string>("i");
string outfile = cmd.get<string>("o");
string codec = cmd.get<string>("codec");
int device = cmd.get<int>("device");
int out_w = cmd.get<int>("out_w");
int out_h = cmd.get<int>("out_h");
bool use_opencl = cmd.get<bool>("opencl");
bool bitwise_not = cmd.get<bool>("bitwise_not");
cv::VideoCaptureAPIs backend = cv::CAP_ANY;
string backend_str = cmd.get<string>("backend");
for (size_t i = 0; i < sizeof(backend_strings)/sizeof(backend_strings[0]); i++) {
if (backend_str == backend_strings[i].str) {
backend = backend_strings[i].backend;
break;
}
}
VideoAccelerationType accel = VIDEO_ACCELERATION_ANY;
string accel_str = cmd.get<string>("accel");
for (size_t i = 0; i < sizeof(acceleration_strings) / sizeof(acceleration_strings[0]); i++) {
if (accel_str == acceleration_strings[i].str) {
accel = acceleration_strings[i].acceleration;
break;
}
}
ocl::setUseOpenCL(use_opencl);
VideoCapture capture(infile, backend, {
CAP_PROP_HW_ACCELERATION, (int)accel,
CAP_PROP_HW_DEVICE, device
});
if (!capture.isOpened()) {
cerr << "Failed to open VideoCapture" << endl;
return 1;
}
cout << "VideoCapture backend = " << capture.getBackendName() << endl;
VideoAccelerationType actual_accel = static_cast<VideoAccelerationType>(static_cast<int>(capture.get(CAP_PROP_HW_ACCELERATION)));
for (size_t i = 0; i < sizeof(acceleration_strings) / sizeof(acceleration_strings[0]); i++) {
if (actual_accel == acceleration_strings[i].acceleration) {
cout << "VideoCapture acceleration = " << acceleration_strings[i].str << endl;
cout << "VideoCapture acceleration device = " << (int)capture.get(CAP_PROP_HW_DEVICE) << endl;
break;
}
}
VideoWriter writer;
if (!outfile.empty() && outfile != "null") {
const char* codec_str = codec.c_str();
int fourcc = VideoWriter::fourcc(codec_str[0], codec_str[1], codec_str[2], codec_str[3]);
double fps = capture.get(CAP_PROP_FPS);
Size frameSize = { out_w, out_h };
if (!out_w || !out_h) {
frameSize = { (int)capture.get(CAP_PROP_FRAME_WIDTH), (int)capture.get(CAP_PROP_FRAME_HEIGHT) };
}
writer = VideoWriter(outfile, backend, fourcc, fps, frameSize, {
VIDEOWRITER_PROP_HW_ACCELERATION, (int)accel,
VIDEOWRITER_PROP_HW_DEVICE, device
});
if (!writer.isOpened()) {
cerr << "Failed to open VideoWriter" << endl;
return 1;
}
cout << "VideoWriter backend = " << writer.getBackendName() << endl;
actual_accel = static_cast<VideoAccelerationType>(static_cast<int>(writer.get(VIDEOWRITER_PROP_HW_ACCELERATION)));
Merge pull request #19460 from mikhail-nikolskiy:videoio-hw videoio: HW decode/encode in FFMPEG backend; new properties with support in FFMPEG/GST/MSMF * HW acceleration in FFMPEG backend * fixes on Windows, remove D3D9 * HW acceleration in FFMPEG backend * fixes on Windows, remove D3D9 * improve va test * Copyright * check LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 78, 100) // FFMPEG 3.4+ * CAP_MSMF test on .mp4 * .mp4 in test * improve va test * Copyright * check LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 78, 100) // FFMPEG 3.4+ * CAP_MSMF test on .mp4 * .mp4 in test * .avi for GStreamer test * revert changes around seek() * cv_writer_open_with_params * params.warnUnusedParameters * VideoCaptureParameters in GStreamer * open_with_params * params->getUnused * Reduce PSNR threshold 33->32 (other tests use 30) * require FFMPEG 4.0+; PSNR 30 as in other tests * GStreamer AVI-demux plugin not installed in Ubuntu test environment? * fix build on very old ffmpeg * fix build on very old ffmpeg * fix build issues * fix build issues (static_cast) * FFMPEG built on Windows without H264 encoder? * fix for write_nothing test on VAAPI * fix warnings * fix cv_writer_get_prop in plugins * use avcodec_get_hw_frames_parameters; more robust fallback to SW codecs * internal function hw_check_device() for device check/logging * two separate tests for HW read and write * image size 640x480 in encode test * WITH_VA=ON (only .h headers used in OpenCV, no linkage dependency) * exception on VP9 SW encoder? * rebase master; refine info message * videoio: fix FFmpeg standalone plugin build * videoio(ffmpeg): eliminate MSVC build warnings * address review comments * videoio(hw): update videocapture_acceleration.read test - remove parallel decoding by SW code path - check PSNR against the original generated image * videoio: minor fixes * videoio(test): disable unsupported MSMF cases (SW and HW) * videoio(test): update PSNR thresholds for HW acceleration read * videoio(test): update debug messages * "hw_acceleration" whitelisting parameter * little optimization in test * D3D11VA supports decoders, doesn't support encoders * videoio(test): adjust PSNR threshold in write_read_position tests * videoio(ffmpeg): fix rejecting on acceleration device name mismatch * videoio(ffmpeg): fix compilation USE_AV_HW_CODECS=0, add more debug logging * videoio: rework VideoAccelerationType behavior - enum is not a bitset - default value is backend specific - only '_NONE' and '_ANY' may fallback on software processing - specific H/W acceleration doesn't fallback on software processing. It fails if there is no support for specified H/W acceleration. * videoio(test): fix for current FFmpeg wrapper Co-authored-by: Alexander Alekhin <alexander.a.alekhin@gmail.com>
2021-03-01 23:51:04 +08:00
for (size_t i = 0; i < sizeof(acceleration_strings) / sizeof(acceleration_strings[0]); i++) {
if (actual_accel == acceleration_strings[i].acceleration) {
cout << "VideoWriter acceleration = " << acceleration_strings[i].str << endl;
cout << "VideoWriter acceleration device = " << (int)writer.get(VIDEOWRITER_PROP_HW_DEVICE) << endl;
Merge pull request #19460 from mikhail-nikolskiy:videoio-hw videoio: HW decode/encode in FFMPEG backend; new properties with support in FFMPEG/GST/MSMF * HW acceleration in FFMPEG backend * fixes on Windows, remove D3D9 * HW acceleration in FFMPEG backend * fixes on Windows, remove D3D9 * improve va test * Copyright * check LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 78, 100) // FFMPEG 3.4+ * CAP_MSMF test on .mp4 * .mp4 in test * improve va test * Copyright * check LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 78, 100) // FFMPEG 3.4+ * CAP_MSMF test on .mp4 * .mp4 in test * .avi for GStreamer test * revert changes around seek() * cv_writer_open_with_params * params.warnUnusedParameters * VideoCaptureParameters in GStreamer * open_with_params * params->getUnused * Reduce PSNR threshold 33->32 (other tests use 30) * require FFMPEG 4.0+; PSNR 30 as in other tests * GStreamer AVI-demux plugin not installed in Ubuntu test environment? * fix build on very old ffmpeg * fix build on very old ffmpeg * fix build issues * fix build issues (static_cast) * FFMPEG built on Windows without H264 encoder? * fix for write_nothing test on VAAPI * fix warnings * fix cv_writer_get_prop in plugins * use avcodec_get_hw_frames_parameters; more robust fallback to SW codecs * internal function hw_check_device() for device check/logging * two separate tests for HW read and write * image size 640x480 in encode test * WITH_VA=ON (only .h headers used in OpenCV, no linkage dependency) * exception on VP9 SW encoder? * rebase master; refine info message * videoio: fix FFmpeg standalone plugin build * videoio(ffmpeg): eliminate MSVC build warnings * address review comments * videoio(hw): update videocapture_acceleration.read test - remove parallel decoding by SW code path - check PSNR against the original generated image * videoio: minor fixes * videoio(test): disable unsupported MSMF cases (SW and HW) * videoio(test): update PSNR thresholds for HW acceleration read * videoio(test): update debug messages * "hw_acceleration" whitelisting parameter * little optimization in test * D3D11VA supports decoders, doesn't support encoders * videoio(test): adjust PSNR threshold in write_read_position tests * videoio(ffmpeg): fix rejecting on acceleration device name mismatch * videoio(ffmpeg): fix compilation USE_AV_HW_CODECS=0, add more debug logging * videoio: rework VideoAccelerationType behavior - enum is not a bitset - default value is backend specific - only '_NONE' and '_ANY' may fallback on software processing - specific H/W acceleration doesn't fallback on software processing. It fails if there is no support for specified H/W acceleration. * videoio(test): fix for current FFmpeg wrapper Co-authored-by: Alexander Alekhin <alexander.a.alekhin@gmail.com>
2021-03-01 23:51:04 +08:00
break;
}
}
}
cout << "\nStarting frame loop. Press ESC to exit\n";
FPSCounter fps_counter(0.5); // print FPS every 0.5 seconds
UMat frame, frame2, frame3;
for (;;)
{
capture.read(frame);
if (frame.empty()) {
cout << "End of stream" << endl;
break;
}
if (out_w && out_h) {
cv::resize(frame, frame2, cv::Size(out_w, out_h));
//cv::cvtColor(frame, outframe, COLOR_BGRA2RGBA);
}
else {
frame2 = frame;
}
if (bitwise_not) {
cv::bitwise_not(frame2, frame3);
}
else {
frame3 = frame2;
}
if (writer.isOpened()) {
writer.write(frame3);
}
if (outfile.empty()) {
imshow("output", frame3);
char key = (char) waitKey(1);
if (key == 27)
break;
else if (key == 'm') {
ocl::setUseOpenCL(!cv::ocl::useOpenCL());
cout << "Switched to " << (ocl::useOpenCL() ? "OpenCL enabled" : "CPU") << " mode\n";
}
}
fps_counter.NewFrame();
}
return EXIT_SUCCESS;
}