cudacodecモジュールを使って動画デコード処理を行う - atinfinity/lab GitHub Wiki
OpenCVのcudacodecモジュールは,CUDAを用いた動画のエンコード/デコード機能を提供しています.ここではcudacodecモジュールの動画デコード機能を使うための手順をまとめています.
fixed to use NVCUVID in 'cudacodec' module. #6036にて対応がマージされたので2016/8/8時点のmasterブランチでは以降の変更は不要です(OpenCV 3.2に取り込まれる見通し)。
最近のNVIDIA CUDA ToolkitではNVCUVENCが同梱されていないようで,cudacodecモジュールのエンコード処理を使うことができなくなっているようです.そのため,以降の手順に沿ってOpenCVソースコードを修正してエンコード処理を無効化します.
★の行を削除する.
  if(WITH_NVCUVID)
    find_cuda_helper_libs(nvcuvid)
    if(WIN32) ★
      find_cuda_helper_libs(nvcuvenc) ★
    endif() ★
    set(HAVE_NVCUVID 1)
  endif()
★の行を削除する.
if(HAVE_NVCUVID)
  list(APPEND extra_libs ${CUDA_CUDA_LIBRARY} ${CUDA_nvcuvid_LIBRARY})
  if(WIN32) ★
    list(APPEND extra_libs ${CUDA_nvcuvenc_LIBRARY}) ★
  endif() ★
endif()
★の行を削除する.
#include "opencv2/cudacodec.hpp"
#include "opencv2/core/private.cuda.hpp"
#ifdef HAVE_NVCUVID
    #include <nvcuvid.h>
    #ifdef WIN32
        #define NOMINMAX
        #include <windows.h>
        #include <NVEncoderAPI.h> ★★の行の条件を#if defined(HAVE_NVCUVID) || !defined(WIN32)に変更する.
#include "precomp.hpp"
using namespace cv;
using namespace cv::cuda;
using namespace cv::cudacodec;
#if !defined(HAVE_NVCUVID) || !defined(WIN32) ★以下のCMakeオプションをONにしてOpenCVライブラリを生成します.
- BUILD_opencv_cudacodec
- BUILD_opencv_cudev
- WITH_CUDA
- WITH_NVCUVID
コマンドラインでCMakeを実行する場合は以下のようなオプションを付与することで同様のことが行えます.
-D BUILD_opencv_cudacodec=ON ^
-D BUILD_opencv_cudev=ON ^
-D WITH_CUDA=ON ^
-D WITH_NVCUVID=ON ^
ライブラリはopencv_cudev300.lib,opencv_cudacodec300.libをリンクします.
(デバッグ版の場合はopencv_cudev300d.lib,opencv_cudacodec300d.lib)
また,ヘッダファイルはopencv2/cudacodec.hppをインクルードします.
cudacodecモジュールを使って動画デコード処理を行うサンプルコードです.
#include <opencv2/core.hpp>
#include <opencv2/core/opengl.hpp>
#include <opencv2/cudacodec.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <numeric>
int main(int argc, const char* argv[])
{
    if (argc != 2) return -1;
    const std::string fname(argv[1]);
    cv::namedWindow("GPU", cv::WINDOW_OPENGL);
    cv::cuda::setGlDevice();
    cv::cuda::GpuMat d_frame;
    cv::Ptr<cv::cudacodec::VideoReader> d_reader = cv::cudacodec::createVideoReader(fname);
    std::vector<double> gpu_times;
    double f = 1000.0f / cv::getTickFrequency();
    int64 start = 0;
    int64 end   = 0;
    for (;;)
    {
        start = cv::getTickCount();
        if (!d_reader->nextFrame(d_frame))
            break;
        end = cv::getTickCount();
        gpu_times.push_back((end - start) * f);
        cv::imshow("GPU", d_frame);
        if (cv::waitKey(1) > 0)
            break;
    }
    if (!gpu_times.empty())
    {
        std::cout << std::endl << "Results:" << std::endl;
        std::sort(gpu_times.begin(), gpu_times.end());
        double gpu_avg = std::accumulate(gpu_times.begin(), gpu_times.end(), 0.0) / gpu_times.size();
        std::cout << "  GPU : Avg : " << gpu_avg << "[ms], FPS : " << 1000.0 / gpu_avg << std::endl;
    }
    return 0;
}- 
cudacodecモジュールのエンコード処理がサポートする動画フォーマット,コーデックには制限があるようです.
- そのため,サポート外の動画フォーマット,コーデックとなる動画ファイルは扱うことができません.
筆者の環境(Windows 8.1 Pro with Media Center)にてopencv_extra にあるテストデータを用いたデコード成否結果を参考までに下記の表にまとめました.
| ファイル名 | コーデック | FourCC | デコード成否 | 
|---|---|---|---|
| big_buck_bunny.avi | XviD | XVID | ○ | 
| big_buck_bunny.mov | MPEG4 Visual | mp4v | ○ | 
| big_buck_bunny.mp4 | MPEG4 Visual | mp4v | ○ | 
| big_buck_bunny.mpg | MPEG1 | MPEG1 | × | 
| big_buck_bunny.wmv | Microsoft MPEG-4 Video Codec V3 | MP43 | × | 
筆者は以下の環境で動作確認しました.