linux + opencv + cuvid中使用cv::cuda::GpuMat類的一些坑


1.我最終成功實現了opencv中利用cuvid實現GPU視頻解碼:
核心代碼是:

 1 cv::cuda::GpuMat d_frame;
 2     cv::Ptr<cv::cudacodec::VideoReader> d_reader = cv::cudacodec::createVideoReader(mp4_file_name);
 3 for (;;)
 4 {
 5     if (!d_reader->nextFrame(d_frame))  //BRGA格式
 6         break;
 7     gpu_frame_count++;
 8     cv::Mat frame2;
 9     d_frame.download(frame2);
10     cv::imwrite("xxx.png", frame2);
11 }

2.GupMat類的參考地址是:
  https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html

  源碼在: opencv-master/modules/core/include/opencv2/core/cuda.hpp

  GPUMat類的成員變量都是public的,就算沒有提供訪問的方法也沒關系。

  一些重要的成員變量和成員函數是:

 1 class CV_EXPORTS_W GpuMat
 2 {
 3 public:
 4 
 5     /** @brief Performs data download from GpuMat (Blocking call)
 6 
 7     This function copies data from device memory to host memory. As being a blocking call, it is
 8     guaranteed that the copy operation is finished when this function returns.
 9     */
10     CV_WRAP void download(OutputArray dst) const;
11 
12     /** @brief Performs data download from GpuMat (Non-Blocking call)
13 
14     This function copies data from device memory to host memory. As being a non-blocking call, this
15     function may return even if the copy operation is not finished.
16 
17     The copy operation may be overlapped with operations in other non-default streams if \p stream is
18     not the default stream and \p dst is HostMem allocated with HostMem::PAGE_LOCKED option.
19     */
20     CV_WRAP void download(OutputArray dst, Stream& stream) const;
21 
22     //! the number of rows and columns
23     int rows, cols;
24 
25     //! a distance between successive rows in bytes; includes the gap if any
26     CV_PROP size_t step;
27 
28     //! pointer to the data
29     uchar* data;
30 
31     //! helper fields used in locateROI and adjustROI
32     uchar* datastart;
33     const uchar* dataend;
34 
35 };

data是GPU內存中,存儲圖像數據的指針

datastart的地址與data相同

dataend指向圖像存儲空間的結束位置。(很可惜,這里是錯誤的)

rows 是圖片的高度

cols是圖片的寬度

channels() 返回4, 說明每個像素是四個字節,格式是BGRA

step是圖片每行的字節數。注意:這個值是按2的冪對齊的。我測試中使用的圖片,寬度是480,每像素四字節的話,一行應該是1920; 而此處的step值是2048, 每行多出來32像素,這些像素的alpha通道值為0。

因此,雖然看起來dataend-datastart是GPU內存所占空間大小,但實際的所占空間是:step*rows

 

3. GpuMat類使用dowmload()方法后,Mat類會去掉多余的對齊的像素
   具體怎么做到的呢?搜索了很久終於找到源碼原來在:opencv-master/modules/core/src/cuda/gpu_mat.cu

   download方法的源碼是:

1 void cv::cuda::GpuMat::download(OutputArray _dst) const
2 {
3     CV_DbgAssert( !empty() );
4 
5     _dst.create(size(), type());
6     Mat dst = _dst.getMat();
7 
8     CV_CUDEV_SAFE_CALL( cudaMemcpy2D(dst.data, dst.step, data, step, cols * elemSize(), rows, cudaMemcpyDeviceToHost) );
9 }

直接這樣拷貝也是可以的:
cudaMemcpy(host_data, d_frame.data,  d_frame.rows * d_frame.step , cudaMemcpyDeviceToHost);
但要注意:
#include <cuda_runtime.h>
cudaGetDeviceCount(&num_devices);
cudaSetDevice(cuda_device);
//調用各種函數來初始化cuda運行環境,否則一執行就崩潰


    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM