Commit 7319ea36117b3270fc33661b77cc77cd8a92b0b3

Authored by Hu Chunming
1 parent e41a52bb

多显卡设置

src/FFNvDecoder.cpp
@@ -125,7 +125,6 @@ bool FFNvDecoder::init(const string& path) @@ -125,7 +125,6 @@ bool FFNvDecoder::init(const string& path)
125 cout << "Failed to create specified HW device."; 125 cout << "Failed to create specified HW device.";
126 return false; 126 return false;
127 } 127 }
128 - avctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);  
129 128
130 // 打开解码器流 129 // 打开解码器流
131 if (avcodec_open2(avctx, decoder, nullptr) < 0) { 130 if (avcodec_open2(avctx, decoder, nullptr) < 0) {
@@ -136,6 +135,79 @@ bool FFNvDecoder::init(const string&amp; path) @@ -136,6 +135,79 @@ bool FFNvDecoder::init(const string&amp; path)
136 return true; 135 return true;
137 } 136 }
138 137
  138 +bool FFNvDecoder::init2(FFDecConfig& cfg)
  139 +{
  140 + m_cfg = cfg;
  141 +
  142 + fstream infile(cfg.uri);
  143 + if (infile.is_open()){
  144 + m_bReal = false;
  145 + infile.close();
  146 + }else {
  147 + m_bReal = true;
  148 + }
  149 +
  150 +
  151 +
  152 + // 打开输入视频文件
  153 + AVDictionary *options = nullptr;
  154 + av_dict_set( &options, "bufsize", "655360", 0 );
  155 + av_dict_set( &options, "rtsp_transport", cfg.force_tcp ? "tcp" : "udp", 0 );
  156 + // av_dict_set( &options, "listen_timeout", "30", 0 ); // 单位为s
  157 + av_dict_set( &options, "stimeout", "3000000", 0 );
  158 +
  159 + av_register_all();
  160 + avformat_network_init();
  161 +
  162 + fmt_ctx = avformat_alloc_context();
  163 + const char* input_file = cfg.uri.c_str();
  164 + if (avformat_open_input(&fmt_ctx, input_file, nullptr, &options) != 0) {
  165 + cout << "Cannot open input file" << input_file;
  166 + return false;
  167 + }
  168 +
  169 + // 查找流信息
  170 + if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
  171 + cout << "Cannot find input stream information";
  172 + return false;
  173 + }
  174 +
  175 + // 查找视频流信息
  176 + AVCodec *decoder = nullptr;
  177 + stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
  178 + if (stream_index < 0) {
  179 + cout << "Cannot find a video stream in the input file";
  180 + return false;
  181 + }
  182 +
  183 +
  184 + string cuvid_dec_name = string(decoder->name) + "_cuvid";
  185 + AVCodec *vcodec = avcodec_find_decoder_by_name(cuvid_dec_name.c_str());
  186 + if (!(avctx = avcodec_alloc_context3(vcodec)))
  187 + return (bool)AVERROR(ENOMEM);
  188 +
  189 + // 得到视频流对象
  190 + stream = fmt_ctx->streams[stream_index];
  191 + if (avcodec_parameters_to_context(avctx, stream->codecpar) < 0)
  192 + return false;
  193 +
  194 + avctx->opaque = this;
  195 + // 设置解码器管理器的像素格式回调函数
  196 + avctx->get_format = get_hw_format;
  197 +
  198 + hw_pix_fmt = AV_PIX_FMT_CUDA;
  199 +
  200 + // 打开解码器流
  201 + AVDictionary *op = nullptr;
  202 + av_dict_set( &op, "gpu", cfg.gpuid.c_str(), 0 );
  203 + if (avcodec_open2(avctx, vcodec, &op) < 0) {
  204 + cout << "Failed to open codec for stream" << stream_index;
  205 + return false;
  206 + }
  207 +
  208 + return true;
  209 +}
  210 +
139 void FFNvDecoder::start(){ 211 void FFNvDecoder::start(){
140 212
141 m_bRunning = true; 213 m_bRunning = true;
@@ -210,7 +282,7 @@ void FFNvDecoder::decode_thread() @@ -210,7 +282,7 @@ void FFNvDecoder::decode_thread()
210 result = avcodec_send_packet(avctx, pkt); 282 result = avcodec_send_packet(avctx, pkt);
211 if (result < 0) 283 if (result < 0)
212 { 284 {
213 - cout << "Failed to send pkt" << result << endl; 285 + cout << "Failed to send pkt:" << result << endl;
214 continue; 286 continue;
215 } 287 }
216 288
@@ -222,16 +294,6 @@ void FFNvDecoder::decode_thread() @@ -222,16 +294,6 @@ void FFNvDecoder::decode_thread()
222 } 294 }
223 295
224 mFrameQueue.addTail(); 296 mFrameQueue.addTail();
225 -  
226 - // if (gpuFrame->format == hw_pix_fmt)  
227 - // {  
228 - // /* retrieve data from GPU to CPU */  
229 - // if (av_hwframe_transfer_data(pong_frame, gpuFrame, 0) < 0)  
230 - // {  
231 - // cout << "Failed to transfer the data to system memory";  
232 - // return;  
233 - // }  
234 - // }  
235 } 297 }
236 av_packet_unref(pkt); 298 av_packet_unref(pkt);
237 } 299 }
src/FFNvDecoder.h
@@ -29,11 +29,20 @@ using namespace std; @@ -29,11 +29,20 @@ using namespace std;
29 **************************************************/ 29 **************************************************/
30 typedef void(*POST_DECODE_CALLBACK)(const void * userPtr, AVFrame * gpuFrame); 30 typedef void(*POST_DECODE_CALLBACK)(const void * userPtr, AVFrame * gpuFrame);
31 31
  32 +struct FFDecConfig
  33 +{
  34 + string uri;
  35 + POST_DECODE_CALLBACK post_decoded_cbk;
  36 + string gpuid;
  37 + bool force_tcp{true};
  38 +};
  39 +
32 class FFNvDecoder{ 40 class FFNvDecoder{
33 public: 41 public:
34 FFNvDecoder(); 42 FFNvDecoder();
35 ~FFNvDecoder(); 43 ~FFNvDecoder();
36 bool init(const string& path); 44 bool init(const string& path);
  45 + bool init2(FFDecConfig& cfg);
37 void close(); 46 void close();
38 void start(); 47 void start();
39 void pause(); 48 void pause();
@@ -55,6 +64,7 @@ private: @@ -55,6 +64,7 @@ private:
55 public: 64 public:
56 POST_DECODE_CALLBACK post_decoded_cbk; 65 POST_DECODE_CALLBACK post_decoded_cbk;
57 const void * m_userPtr; 66 const void * m_userPtr;
  67 + FFDecConfig m_cfg;
58 68
59 private: 69 private:
60 AVStream* stream; 70 AVStream* stream;
src/FFNvDecoderManager.cpp
@@ -3,8 +3,8 @@ @@ -3,8 +3,8 @@
3 3
4 using namespace std; 4 using namespace std;
5 5
6 -FFNvDecoder* FFNvDecoderManager::createDecoder(const char * uri, POST_DECODE_CALLBACK post_decoded_cbk, string name){  
7 - int num = decoderMap.count(name); 6 +FFNvDecoder* FFNvDecoderManager::createDecoder(MgrDecConfig& config){
  7 + int num = decoderMap.count(config.name);
8 if (num > 0) 8 if (num > 0)
9 { 9 {
10 cout << "已存在name所标记的解码器" << endl; 10 cout << "已存在name所标记的解码器" << endl;
@@ -17,12 +17,12 @@ FFNvDecoder* FFNvDecoderManager::createDecoder(const char * uri, POST_DECODE_CAL @@ -17,12 +17,12 @@ FFNvDecoder* FFNvDecoderManager::createDecoder(const char * uri, POST_DECODE_CAL
17 return nullptr; 17 return nullptr;
18 } 18 }
19 19
20 - bool bRet= dec->init(uri); 20 + bool bRet= dec->init2(config.cfg);
21 if (bRet) 21 if (bRet)
22 { 22 {
23 - dec->setName(name) ;  
24 - dec->post_decoded_cbk = post_decoded_cbk;  
25 - decoderMap[name] = dec; 23 + dec->setName(config.name) ;
  24 + dec->post_decoded_cbk = config.cfg.post_decoded_cbk;
  25 + decoderMap[config.name] = dec;
26 return dec; 26 return dec;
27 } 27 }
28 28
src/FFNvDecoderManager.h
@@ -5,6 +5,12 @@ @@ -5,6 +5,12 @@
5 5
6 using namespace std; 6 using namespace std;
7 7
  8 +struct MgrDecConfig
  9 +{
  10 + FFDecConfig cfg;
  11 + string name{""};
  12 +};
  13 +
8 class FFNvDecoderManager{ 14 class FFNvDecoderManager{
9 public: 15 public:
10 static FFNvDecoderManager* getInstance(){ 16 static FFNvDecoderManager* getInstance(){
@@ -20,7 +26,7 @@ public: @@ -20,7 +26,7 @@ public:
20 closeAllDecoder(); 26 closeAllDecoder();
21 } 27 }
22 28
23 - FFNvDecoder* createDecoder(const char * uri, POST_DECODE_CALLBACK post_decoded_cbk, string name = ""); 29 + FFNvDecoder* createDecoder(MgrDecConfig& config);
24 void setUserPtr(string name, const void * userPtr); 30 void setUserPtr(string name, const void * userPtr);
25 31
26 FFNvDecoder* getDecoderByName(const string name); 32 FFNvDecoder* getDecoderByName(const string name);
src/NV12ToRGB.cu
@@ -301,26 +301,6 @@ namespace cuda_common @@ -301,26 +301,6 @@ namespace cuda_common
301 fprintf(stderr, "cudaMemcpyToSymbol failed: %s\n", cudaGetErrorString(cudaStatus)); 301 fprintf(stderr, "cudaMemcpyToSymbol failed: %s\n", cudaGetErrorString(cudaStatus));
302 } 302 }
303 303
304 - //showHueCSC();  
305 -  
306 - return cudaStatus;  
307 - }  
308 -  
309 - cudaError_t showHueCSC3()  
310 - {  
311 - /*  
312 - cudaError_t cudaStatus;  
313 -  
314 - float data[9];  
315 - cudaStatus = cudaMemcpyFromSymbol(data, constHueColorSpaceMat2, sizeof(data));  
316 - printf("hueCSC ");  
317 - for (int i = 0; i < 9; i++)  
318 - {  
319 - printf("%f ,", data[i]);  
320 - }  
321 - printf("\n");  
322 -*/  
323 - cudaError_t cudaStatus;  
324 return cudaStatus; 304 return cudaStatus;
325 } 305 }
326 306
src/NvJpegEncoder.cpp
1 #include "NvJpegEncoder.h" 1 #include "NvJpegEncoder.h"
2 2
3 -#include <nvjpeg.h>  
4 -  
5 #include <fstream> 3 #include <fstream>
6 #include <vector> 4 #include <vector>
7 #include <iostream> 5 #include <iostream>
8 6
9 7
  8 +#define CHECK_NVJPEG(S) do {nvjpegStatus_t status; \
  9 + status = S; \
  10 + if (status != NVJPEG_STATUS_SUCCESS ) std::cout << __LINE__ <<" CHECK_NVJPEG - status = " << status << std::endl; \
  11 + } while (false)
  12 +
10 13
11 int saveJpeg(const char * filepath, unsigned char* d_srcBGR, int width, int height) 14 int saveJpeg(const char * filepath, unsigned char* d_srcBGR, int width, int height)
12 { 15 {
13 - nvjpegHandle_t nvjpeg_handle;  
14 - nvjpegEncoderState_t encoder_state;  
15 - nvjpegEncoderParams_t encoder_params;  
16 -  
17 - cudaEvent_t ev_start, ev_end;  
18 - cudaEventCreate(&ev_start);  
19 - cudaEventCreate(&ev_end);  
20 -  
21 -  
22 - nvjpegImage_t input;  
23 - nvjpegInputFormat_t input_format = NVJPEG_INPUT_BGRI;  
24 - int image_width = width;  
25 - int image_height = height;  
26 -  
27 - // int channel_size = image_width * image_height;  
28 - // for (int i = 0; i < 3; i++)  
29 - // {  
30 - // input.pitch[i] = image_width;  
31 - // (cudaMalloc((void**)&(input.channel[i]), channel_size));  
32 - // (cudaMemset(input.channel[i], 50 * 40 * i, channel_size));  
33 - // } 16 + nvjpegHandle_t nvjpeg_handle;
  17 + nvjpegEncoderState_t encoder_state;
  18 + nvjpegEncoderParams_t encoder_params;
  19 +
  20 + cudaEvent_t ev_start, ev_end;
  21 + cudaEventCreate(&ev_start);
  22 + cudaEventCreate(&ev_end);
  23 +
  24 + nvjpegImage_t input;
  25 + nvjpegInputFormat_t input_format = NVJPEG_INPUT_BGRI;
  26 + int image_width = width;
  27 + int image_height = height;
  28 +
  29 + // int channel_size = image_width * image_height;
  30 + // for (int i = 0; i < 3; i++)
  31 + // {
  32 + // input.pitch[i] = image_width;
  33 + // (cudaMalloc((void**)&(input.channel[i]), channel_size));
  34 + // (cudaMemset(input.channel[i], 50 * 40 * i, channel_size));
  35 + // }
34 36
35 input.channel[0] = d_srcBGR; 37 input.channel[0] = d_srcBGR;
36 input.pitch[0] = image_width * 3; 38 input.pitch[0] = image_width * 3;
37 39
38 - nvjpegBackend_t backend = NVJPEG_BACKEND_DEFAULT;  
39 -  
40 - nvjpegCreate(backend, nullptr, &nvjpeg_handle);  
41 -  
42 - nvjpegEncoderParamsCreate(nvjpeg_handle, &encoder_params, NULL);  
43 - nvjpegEncoderStateCreate(nvjpeg_handle, &encoder_state, NULL);  
44 -  
45 - // set params  
46 - nvjpegEncoderParamsSetEncoding(encoder_params, nvjpegJpegEncoding_t::NVJPEG_ENCODING_PROGRESSIVE_DCT_HUFFMAN, NULL);  
47 - nvjpegEncoderParamsSetOptimizedHuffman(encoder_params, 1, NULL);  
48 - nvjpegEncoderParamsSetQuality(encoder_params, 70, NULL);  
49 - nvjpegEncoderParamsSetSamplingFactors(encoder_params, nvjpegChromaSubsampling_t::NVJPEG_CSS_420, NULL);  
50 -  
51 - cudaEventRecord(ev_start);  
52 - nvjpegEncodeImage(nvjpeg_handle, encoder_state, encoder_params, &input, input_format, image_width, image_height, NULL);  
53 - cudaEventRecord(ev_end);  
54 -  
55 - std::vector<unsigned char> obuffer;  
56 - size_t length;  
57 - nvjpegEncodeRetrieveBitstream(  
58 - nvjpeg_handle,  
59 - encoder_state,  
60 - NULL,  
61 - &length,  
62 - NULL);  
63 -  
64 - obuffer.resize(length);  
65 - nvjpegEncodeRetrieveBitstream(  
66 - nvjpeg_handle,  
67 - encoder_state,  
68 - obuffer.data(),  
69 - &length,  
70 - NULL);  
71 -  
72 - std::ofstream outputFile(filepath, std::ios::out | std::ios::binary);  
73 - outputFile.write(reinterpret_cast<const char *>(obuffer.data()), static_cast<int>(length));  
74 -  
75 - cudaEventSynchronize(ev_end);  
76 -  
77 - float ms;  
78 - cudaEventElapsedTime(&ms, ev_start, ev_end);  
79 - std::cout << "time spend " << ms << " ms" << std::endl;  
80 -  
81 - return 0; 40 + nvjpegBackend_t backend = NVJPEG_BACKEND_DEFAULT;
  41 +
  42 + CHECK_NVJPEG(nvjpegCreate(backend, nullptr, &nvjpeg_handle));
  43 +
  44 + CHECK_NVJPEG(nvjpegEncoderParamsCreate(nvjpeg_handle, &encoder_params, NULL));
  45 + CHECK_NVJPEG(nvjpegEncoderStateCreate(nvjpeg_handle, &encoder_state, NULL));
  46 +
  47 + // set params
  48 + CHECK_NVJPEG(nvjpegEncoderParamsSetEncoding(encoder_params, nvjpegJpegEncoding_t::NVJPEG_ENCODING_PROGRESSIVE_DCT_HUFFMAN, NULL));
  49 + CHECK_NVJPEG(nvjpegEncoderParamsSetOptimizedHuffman(encoder_params, 1, NULL));
  50 + CHECK_NVJPEG(nvjpegEncoderParamsSetQuality(encoder_params, 70, NULL));
  51 + CHECK_NVJPEG(nvjpegEncoderParamsSetSamplingFactors(encoder_params, nvjpegChromaSubsampling_t::NVJPEG_CSS_420, NULL));
  52 +
  53 + cudaEventRecord(ev_start);
  54 + CHECK_NVJPEG(nvjpegEncodeImage(nvjpeg_handle, encoder_state, encoder_params, &input, input_format, image_width, image_height, NULL));
  55 + cudaEventRecord(ev_end);
  56 +
  57 + std::vector<unsigned char> obuffer;
  58 + size_t length;
  59 + CHECK_NVJPEG(nvjpegEncodeRetrieveBitstream(
  60 + nvjpeg_handle,
  61 + encoder_state,
  62 + NULL,
  63 + &length,
  64 + NULL));
  65 +
  66 + obuffer.resize(length);
  67 + CHECK_NVJPEG(nvjpegEncodeRetrieveBitstream(
  68 + nvjpeg_handle,
  69 + encoder_state,
  70 + obuffer.data(),
  71 + &length,
  72 + NULL));
  73 +
  74 + cudaEventSynchronize(ev_end);
  75 +
  76 + // 用完销毁,避免显存泄露
  77 + nvjpegEncoderParamsDestroy(encoder_params);
  78 + nvjpegEncoderStateDestroy(encoder_state);
  79 + nvjpegDestroy(nvjpeg_handle);
  80 +
  81 + float ms;
  82 + cudaEventElapsedTime(&ms, ev_start, ev_end);
  83 + std::cout << "time spend " << ms << " ms" << std::endl;
  84 +
  85 + std::ofstream outputFile(filepath, std::ios::out | std::ios::binary);
  86 + outputFile.write(reinterpret_cast<const char *>(obuffer.data()), static_cast<int>(length));
  87 + outputFile.close();
  88 +
  89 + return 0;
82 } 90 }
83 \ No newline at end of file 91 \ No newline at end of file
src/NvJpegEncoder.h
1 - 1 +#include <nvjpeg.h>
2 2
3 int saveJpeg(const char * filepath, unsigned char* d_srcBGR, int width, int height); 3 int saveJpeg(const char * filepath, unsigned char* d_srcBGR, int width, int height);
4 \ No newline at end of file 4 \ No newline at end of file
src/cuda_kernels.h
@@ -19,7 +19,6 @@ typedef enum @@ -19,7 +19,6 @@ typedef enum
19 namespace cuda_common 19 namespace cuda_common
20 { 20 {
21 cudaError_t setColorSpace2(e_ColorSpace CSC, float hue); 21 cudaError_t setColorSpace2(e_ColorSpace CSC, float hue);
22 - cudaError_t showHueCSC3();  
23 22
24 cudaError_t NV12ToRGBnot(CUdeviceptr d_srcNV12, size_t nSourcePitch, unsigned char* d_dstRGB, int width, int height); 23 cudaError_t NV12ToRGBnot(CUdeviceptr d_srcNV12, size_t nSourcePitch, unsigned char* d_dstRGB, int width, int height);
25 cudaError_t CUDAToBGR(CUdeviceptr dataY, CUdeviceptr dataUV, size_t pitchY, size_t pitchUV, unsigned char* d_dstRGB, int width, int height); 24 cudaError_t CUDAToBGR(CUdeviceptr dataY, CUdeviceptr dataUV, size_t pitchY, size_t pitchUV, unsigned char* d_dstRGB, int width, int height);
src/main.cpp
@@ -7,7 +7,6 @@ @@ -7,7 +7,6 @@
7 7
8 unsigned char *pHwRgb = nullptr; 8 unsigned char *pHwRgb = nullptr;
9 9
10 -  
11 void postDecoded(const void * userPtr, AVFrame * gpuFrame){ 10 void postDecoded(const void * userPtr, AVFrame * gpuFrame){
12 FFNvDecoder* decoder = (FFNvDecoder*)userPtr; 11 FFNvDecoder* decoder = (FFNvDecoder*)userPtr;
13 if (decoder!= nullptr) 12 if (decoder!= nullptr)
@@ -19,42 +18,77 @@ void postDecoded(const void * userPtr, AVFrame * gpuFrame){ @@ -19,42 +18,77 @@ void postDecoded(const void * userPtr, AVFrame * gpuFrame){
19 cout << "decode successed ✿✿ヽ(°▽°)ノ✿ " << endl; 18 cout << "decode successed ✿✿ヽ(°▽°)ノ✿ " << endl;
20 19
21 if (gpuFrame->format == AV_PIX_FMT_CUDA) 20 if (gpuFrame->format == AV_PIX_FMT_CUDA)
22 - {  
23 - cudaError_t cudaStatus;  
24 - if(pHwRgb == nullptr){  
25 - cudaStatus = cudaMalloc((void **)&pHwRgb, 3 * gpuFrame->width * gpuFrame->height * sizeof(unsigned char));  
26 - }  
27 - cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], pHwRgb, gpuFrame->width, gpuFrame->height);  
28 - cudaDeviceSynchronize();  
29 - if (cudaStatus != cudaSuccess) {  
30 - cout << "CUDAToBGR failed !!!" << endl;  
31 - return;  
32 - }  
33 - saveJpeg("/home/cmhu/FFNvDecoder/a.jpg", pHwRgb, gpuFrame->width, gpuFrame->height); // 验证 CUDAToRGB 21 + {
  22 + cout << "gpuid = " << atoi(decoder->m_cfg.gpuid.c_str()) << endl;
  23 + // cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str()));
  24 + // cudaError_t cudaStatus;
  25 + // if(pHwRgb == nullptr){
  26 + // cuda_common::setColorSpace2( ITU709, 0 );
  27 + // cudaStatus = cudaMalloc((void **)&pHwRgb, 3 * gpuFrame->width * gpuFrame->height * sizeof(unsigned char));
  28 + // }
  29 + // cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], pHwRgb, gpuFrame->width, gpuFrame->height);
  30 + // cudaDeviceSynchronize();
  31 + // if (cudaStatus != cudaSuccess) {
  32 + // cout << "CUDAToBGR failed !!!" << endl;
  33 + // return;
  34 + // }
  35 +
  36 + // string path = "/home/cmhu/FFNvDecoder/" + decoder->m_cfg.gpuid + ".jpg";
  37 + // saveJpeg(path.c_str(), pHwRgb, gpuFrame->width, gpuFrame->height); // 验证 CUDAToRGB
34 } 38 }
35 } 39 }
36 } 40 }
37 41
38 int main(){ 42 int main(){
39 43
40 - cuda_common::setColorSpace2( ITU709, 0 );  
41 -  
42 FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); 44 FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance();
43 - // FFNvDecoder* decoder = pDecManager->createDecoder("rtmp://192.168.10.56:1935/objecteye/1",postDecoded,"dec1");  
44 - // if (!decoder)  
45 - // {  
46 - // return 1;  
47 - // }  
48 - // pDecManager->setUserPtr("dec1", decoder);  
49 - // pDecManager->startDecodeByName("dec1");  
50 -  
51 - FFNvDecoder* dec2 = pDecManager->createDecoder("/home/cmhu/data/duan1.avi",postDecoded,"dec2"); 45 + MgrDecConfig config;
  46 + config.name = "dec1";
  47 + config.cfg.uri = "rtmp://192.168.10.56:1935/objecteye/1";
  48 + config.cfg.post_decoded_cbk = postDecoded;
  49 + config.cfg.force_tcp = true;
  50 + config.cfg.gpuid = "1";
  51 + FFNvDecoder* decoder = pDecManager->createDecoder(config);
  52 + if (!decoder)
  53 + {
  54 + return 1;
  55 + }
  56 + pDecManager->setUserPtr(config.name, decoder);
  57 + pDecManager->startDecodeByName(config.name);
  58 +
  59 + config.name = "dec2";
  60 + config.cfg.uri = "rtmp://192.168.10.56:1935/objecteye/1";
  61 + config.cfg.gpuid = "2";
  62 + FFNvDecoder* dec2 = pDecManager->createDecoder(config);
52 if (!dec2) 63 if (!dec2)
53 { 64 {
54 return 1; 65 return 1;
55 } 66 }
56 - pDecManager->setUserPtr("dec2", dec2);  
57 - pDecManager->startDecodeByName("dec2"); 67 + pDecManager->setUserPtr(config.name, dec2);
  68 + pDecManager->startDecodeByName(config.name);
  69 +
  70 +
  71 + config.name = "dec0";
  72 + config.cfg.uri = "rtmp://192.168.10.56:1935/objecteye/1";
  73 + config.cfg.gpuid = "0";
  74 + FFNvDecoder* dec0 = pDecManager->createDecoder(config);
  75 + if (!dec0)
  76 + {
  77 + return 1;
  78 + }
  79 + pDecManager->setUserPtr(config.name, dec0);
  80 + pDecManager->startDecodeByName(config.name);
  81 +
  82 + config.name = "dec01";
  83 + config.cfg.uri = "rtmp://192.168.10.56:1935/objecteye/1";
  84 + config.cfg.gpuid = "0";
  85 + FFNvDecoder* dec01 = pDecManager->createDecoder(config);
  86 + if (!dec01)
  87 + {
  88 + return 1;
  89 + }
  90 + pDecManager->setUserPtr(config.name, dec01);
  91 + pDecManager->startDecodeByName(config.name);
58 92
59 // while (getchar() != 'q'); 93 // while (getchar() != 'q');
60 94