diff --git a/CMakeLists.txt b/CMakeLists.txt index dbbb10ac9f..aba65ba23f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -266,6 +266,9 @@ OCV_OPTION(WITH_CUDNN "Include NVIDIA CUDA Deep Neural Network (cuDNN) library s OCV_OPTION(WITH_NVCUVID "Include NVidia Video Decoding library support" OFF # disabled, details: https://github.com/opencv/opencv/issues/14850 VISIBLE_IF WITH_CUDA VERIFY HAVE_NVCUVID) +OCV_OPTION(WITH_NVCUVENC "Include NVidia Video Encoding library support" OFF + VISIBLE_IF WITH_CUDA + VERIFY HAVE_NVCUVENC) OCV_OPTION(WITH_EIGEN "Include Eigen2/Eigen3 support" (NOT CV_DISABLE_OPTIMIZATION AND NOT CMAKE_CROSSCOMPILING) VISIBLE_IF NOT WINRT VERIFY HAVE_EIGEN) @@ -1661,6 +1664,7 @@ if(WITH_CUDA OR HAVE_CUDA) IF HAVE_CUFFT THEN "CUFFT" IF HAVE_CUBLAS THEN "CUBLAS" IF HAVE_NVCUVID THEN "NVCUVID" + IF HAVE_NVCUVENC THEN "NVCUVENC" IF CUDA_FAST_MATH THEN "FAST_MATH" ELSE "no extra features") status("") diff --git a/cmake/FindCUDA.cmake b/cmake/FindCUDA.cmake index 37d557a792..ca04bb4a4e 100644 --- a/cmake/FindCUDA.cmake +++ b/cmake/FindCUDA.cmake @@ -287,7 +287,7 @@ # Only available for CUDA version 5.5+. # CUDA_npps_LIBRARY -- NVIDIA Performance Primitives lib (signal processing). # Only available for CUDA version 5.5+. -# CUDA_nvcuvenc_LIBRARY -- CUDA Video Encoder library. +# CUDA_nvencodeapi_LIBRARY -- CUDA Video Encoder library. # Only available for CUDA version 3.2+. # Windows only. # CUDA_nvcuvid_LIBRARY -- CUDA Video Decoder library. @@ -530,7 +530,7 @@ macro(cuda_unset_include_and_libraries) unset(CUDA_nppc_LIBRARY CACHE) unset(CUDA_nppi_LIBRARY CACHE) unset(CUDA_npps_LIBRARY CACHE) - unset(CUDA_nvcuvenc_LIBRARY CACHE) + unset(CUDA_nvencodeapi_LIBRARY CACHE) unset(CUDA_nvcuvid_LIBRARY CACHE) endmacro() @@ -790,7 +790,7 @@ if(NOT CUDA_VERSION VERSION_LESS "3.2") find_cuda_helper_libs(cusparse) find_cuda_helper_libs(curand) if (WIN32) - find_cuda_helper_libs(nvcuvenc) + find_cuda_helper_libs(nvencodeapi) find_cuda_helper_libs(nvcuvid) endif() endif() diff --git a/cmake/OpenCVDetectCUDA.cmake b/cmake/OpenCVDetectCUDA.cmake index acc101396c..69d0455cc8 100644 --- a/cmake/OpenCVDetectCUDA.cmake +++ b/cmake/OpenCVDetectCUDA.cmake @@ -28,6 +28,7 @@ else() endif() if(CUDA_FOUND) + unset(CUDA_nvcuvenc_LIBRARY CACHE) set(HAVE_CUDA 1) if(NOT CUDA_VERSION VERSION_LESS 11.0) # CUDA 11.0 removes nppicom @@ -53,7 +54,7 @@ if(CUDA_FOUND) endif() endif() - if(WITH_NVCUVID) + if(WITH_NVCUVID OR WITH_NVCUVENC) macro(ocv_cuda_SEARCH_NVCUVID_HEADER _filename _result) # place header file under CUDA_TOOLKIT_TARGET_DIR or CUDA_TOOLKIT_ROOT_DIR find_path(_header_result @@ -71,18 +72,25 @@ if(CUDA_FOUND) endif() unset(_header_result CACHE) endmacro() - ocv_cuda_SEARCH_NVCUVID_HEADER("nvcuvid.h" HAVE_NVCUVID_HEADER) - ocv_cuda_SEARCH_NVCUVID_HEADER("dynlink_nvcuvid.h" HAVE_DYNLINK_NVCUVID_HEADER) - find_cuda_helper_libs(nvcuvid) - if(WIN32) - find_cuda_helper_libs(nvcuvenc) + if(WITH_NVCUVID) + ocv_cuda_SEARCH_NVCUVID_HEADER("nvcuvid.h" HAVE_NVCUVID_HEADER) + ocv_cuda_SEARCH_NVCUVID_HEADER("dynlink_nvcuvid.h" HAVE_DYNLINK_NVCUVID_HEADER) + find_cuda_helper_libs(nvcuvid) + if(CUDA_nvcuvid_LIBRARY AND (${HAVE_NVCUVID_HEADER} OR ${HAVE_DYNLINK_NVCUVID_HEADER})) + # make sure to have both header and library before enabling + set(HAVE_NVCUVID 1) + endif() endif() - if(CUDA_nvcuvid_LIBRARY AND (${HAVE_NVCUVID_HEADER} OR ${HAVE_DYNLINK_NVCUVID_HEADER})) - # make sure to have both header and library before enabling - set(HAVE_NVCUVID 1) - endif() - if(CUDA_nvcuvenc_LIBRARY) - set(HAVE_NVCUVENC 1) + if(WITH_NVCUVENC) + ocv_cuda_SEARCH_NVCUVID_HEADER("nvEncodeAPI.h" HAVE_NVCUVENC_HEADER) + if(WIN32) + find_cuda_helper_libs(nvencodeapi) + else() + find_cuda_helper_libs(nvidia-encode) + endif() + if((CUDA_nvencodeapi_LIBRARY OR CUDA_nvidia-encode_LIBRARY) AND ${HAVE_NVCUVENC_HEADER}) + set(HAVE_NVCUVENC 1) + endif() endif() endif() diff --git a/cmake/templates/OpenCVConfig-CUDA.cmake.in b/cmake/templates/OpenCVConfig-CUDA.cmake.in index e71c9e2e31..25a20556ec 100644 --- a/cmake/templates/OpenCVConfig-CUDA.cmake.in +++ b/cmake/templates/OpenCVConfig-CUDA.cmake.in @@ -5,7 +5,7 @@ set(OpenCV_CUDA_VERSION "@CUDA_VERSION_STRING@") set(OpenCV_USE_CUBLAS "@HAVE_CUBLAS@") set(OpenCV_USE_CUFFT "@HAVE_CUFFT@") set(OpenCV_USE_NVCUVID "@HAVE_NVCUVID@") - +set(OpenCV_USE_NVCUVENC "@HAVE_NVCUVENC@") set(OpenCV_CUDNN_VERSION "@CUDNN_VERSION@") set(OpenCV_USE_CUDNN "@HAVE_CUDNN@") @@ -36,14 +36,6 @@ if(OpenCV_USE_CUFFT) list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_CUFFT_LIBRARIES}) endif() -if(OpenCV_USE_NVCUVID) - list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_nvcuvid_LIBRARIES}) -endif() - -if(WIN32) - list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_nvcuvenc_LIBRARIES}) -endif() - set(OpenCV_CUDA_LIBS_RELPATH "") foreach(l ${OpenCV_CUDA_LIBS_ABSPATH}) get_filename_component(_tmp ${l} PATH) diff --git a/samples/gpu/video_reader.cpp b/samples/gpu/video_reader.cpp index ea141c3b1a..e8a738f905 100644 --- a/samples/gpu/video_reader.cpp +++ b/samples/gpu/video_reader.cpp @@ -22,65 +22,41 @@ int main(int argc, const char* argv[]) const std::string fname(argv[1]); cv::namedWindow("CPU", cv::WINDOW_NORMAL); +#if defined(HAVE_OPENGL) cv::namedWindow("GPU", cv::WINDOW_OPENGL); cv::cuda::setGlDevice(); +#else + cv::namedWindow("GPU", cv::WINDOW_NORMAL); +#endif + cv::TickMeter tm; cv::Mat frame; cv::VideoCapture reader(fname); + for (;;) + { + if (!reader.read(frame)) + break; + cv::imshow("CPU", frame); + if (cv::waitKey(3) > 0) + break; + } cv::cuda::GpuMat d_frame; cv::Ptr d_reader = cv::cudacodec::createVideoReader(fname); - - cv::TickMeter tm; - std::vector cpu_times; - std::vector gpu_times; - - int gpu_frame_count=0, cpu_frame_count=0; - for (;;) { - tm.reset(); tm.start(); - if (!reader.read(frame)) - break; - tm.stop(); - cpu_times.push_back(tm.getTimeMilli()); - cpu_frame_count++; - - cv::imshow("CPU", frame); - - if (cv::waitKey(3) > 0) - break; - } - - for (;;) - { - tm.reset(); tm.start(); if (!d_reader->nextFrame(d_frame)) break; - tm.stop(); - gpu_times.push_back(tm.getTimeMilli()); - gpu_frame_count++; - - cv::imshow("GPU", d_frame); - +#if defined(HAVE_OPENGL) + cv::imshow("GPU", cv::ogl::Texture2D(d_frame)); +#else + d_frame.download(frame); + cv::imshow("GPU", frame); +#endif if (cv::waitKey(3) > 0) break; } - if (!cpu_times.empty() && !gpu_times.empty()) - { - std::cout << std::endl << "Results:" << std::endl; - - std::sort(cpu_times.begin(), cpu_times.end()); - std::sort(gpu_times.begin(), gpu_times.end()); - - double cpu_avg = std::accumulate(cpu_times.begin(), cpu_times.end(), 0.0) / cpu_times.size(); - double gpu_avg = std::accumulate(gpu_times.begin(), gpu_times.end(), 0.0) / gpu_times.size(); - - std::cout << "CPU : Avg : " << cpu_avg << " ms FPS : " << 1000.0 / cpu_avg << " Frames " << cpu_frame_count << std::endl; - std::cout << "GPU : Avg : " << gpu_avg << " ms FPS : " << 1000.0 / gpu_avg << " Frames " << gpu_frame_count << std::endl; - } - return 0; } diff --git a/samples/gpu/video_writer.cpp b/samples/gpu/video_writer.cpp index fa1d709c09..02b17700fc 100644 --- a/samples/gpu/video_writer.cpp +++ b/samples/gpu/video_writer.cpp @@ -2,7 +2,7 @@ #include "opencv2/opencv_modules.hpp" -#if defined(HAVE_OPENCV_CUDACODEC) && defined(_WIN32) +#if defined(HAVE_OPENCV_CUDACODEC) #include #include @@ -20,7 +20,7 @@ int main(int argc, const char* argv[]) return -1; } - const double FPS = 25.0; + constexpr double fps = 25.0; cv::VideoCapture reader(argv[1]); @@ -37,17 +37,12 @@ int main(int argc, const char* argv[]) cv::Mat frame; cv::cuda::GpuMat d_frame; - - std::vector cpu_times; - std::vector gpu_times; - TickMeter tm; + cv::cuda::Stream stream; for (int i = 1;; ++i) { std::cout << "Read " << i << " frame" << std::endl; - reader >> frame; - if (frame.empty()) { std::cout << "Stop" << std::endl; @@ -57,47 +52,27 @@ int main(int argc, const char* argv[]) if (!writer.isOpened()) { std::cout << "Frame Size : " << frame.cols << "x" << frame.rows << std::endl; - std::cout << "Open CPU Writer" << std::endl; - - if (!writer.open("output_cpu.avi", cv::VideoWriter::fourcc('X', 'V', 'I', 'D'), FPS, frame.size())) + const String outputFilename = "output_cpu.avi"; + if (!writer.open(outputFilename, cv::VideoWriter::fourcc('X', 'V', 'I', 'D'), fps, frame.size())) return -1; + std::cout << "Writing to " << outputFilename << std::endl; } if (d_writer.empty()) { std::cout << "Open CUDA Writer" << std::endl; - - const cv::String outputFilename = "output_gpu.avi"; - d_writer = cv::cudacodec::createVideoWriter(outputFilename, frame.size(), FPS); + const cv::String outputFilename = "output_gpu.h264"; + d_writer = cv::cudacodec::createVideoWriter(outputFilename, frame.size(), cv::cudacodec::Codec::H264, fps, cv::cudacodec::ColorFormat::BGR, 0, stream); + std::cout << "Writing to " << outputFilename << std::endl; } - d_frame.upload(frame); - + d_frame.upload(frame, stream); std::cout << "Write " << i << " frame" << std::endl; - - tm.reset(); tm.start(); writer.write(frame); - tm.stop(); - cpu_times.push_back(tm.getTimeMilli()); - - tm.reset(); tm.start(); d_writer->write(d_frame); - tm.stop(); - gpu_times.push_back(tm.getTimeMilli()); } - std::cout << std::endl << "Results:" << std::endl; - - std::sort(cpu_times.begin(), cpu_times.end()); - std::sort(gpu_times.begin(), gpu_times.end()); - - double cpu_avg = std::accumulate(cpu_times.begin(), cpu_times.end(), 0.0) / cpu_times.size(); - double gpu_avg = std::accumulate(gpu_times.begin(), gpu_times.end(), 0.0) / gpu_times.size(); - - std::cout << "CPU [XVID] : Avg : " << cpu_avg << " ms FPS : " << 1000.0 / cpu_avg << std::endl; - std::cout << "GPU [H264] : Avg : " << gpu_avg << " ms FPS : " << 1000.0 / gpu_avg << std::endl; - return 0; }