// #include "FFNvDecoderManager.h"
// #include <iostream>

// #include "cuda_kernels.h"

// #include "NvJpegEncoder.h"

// #include <pthread.h>
// #include <thread>

// #include <chrono>

// #include <unistd.h>


// #ifdef _WIN32
// #include "Winsock2.h"
// #pragma comment(lib, "ws2_32.lib")
// #endif

// #ifdef __linux__
// #include "arpa/inet.h"
// #endif

// #include "utiltools.hpp"

// #define MIN_RTP_PORT		10000
// #define MAX_RTP_PORT		60000

// // ȡ MIN_RTP_PORT(10000)~MAX_RTP_PORT(60000)֮�������˿�(ż���������������˿ڿ���)
// int allocRtpPort() {

// 	static int s_rtpPort = MIN_RTP_PORT;
// 	if (MIN_RTP_PORT == s_rtpPort)
// 	{
// 		srand((unsigned int)time(NULL));
// 		s_rtpPort = MIN_RTP_PORT + (rand() % MIN_RTP_PORT);
// 	}

// 	if (s_rtpPort % 2)
// 		++s_rtpPort;

// 	while (true)
// 	{
// 		s_rtpPort += 2;
// 		s_rtpPort = s_rtpPort >= MAX_RTP_PORT ? MIN_RTP_PORT : s_rtpPort;

// 		int i = 0;
// 		for (; i < 2; i++)
// 		{
// 			sockaddr_in sRecvAddr;
// 			int s = socket(AF_INET, SOCK_DGRAM, 0);

// 			sRecvAddr.sin_family = AF_INET;        
// 			sRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);    
// 			sRecvAddr.sin_port = htons(s_rtpPort + i); 

// 			int nResult = bind(s, (sockaddr *)&sRecvAddr, sizeof(sRecvAddr));
// 			if (nResult != 0)
// 			{
// 				break;
// 			}

// 			nResult = close(s);
// 			if (nResult != 0)
// 			{
// 				printf("closesocket failed:%d\n", nResult);
// 				break;
// 			}
// 		}

// 		if (i == 2)
// 			break;
// 	}

// 	return s_rtpPort;
// }





// unsigned char *pHwRgb[2] = {nullptr, nullptr};

// int sum1 = 0;
// int sum2 = 0;

// cudaStream_t stream[2];

// string data_home = "/mnt/data/cmhu/tmp/";


// #define checkCudaErrors(S) do {CUresult  status; \
//         status = S; \
//         if (status != CUDA_SUCCESS ) std::cout << __LINE__ <<" checkCudaErrors - status = " << status << std::endl; \
//         } while (false)


// static void gpu_helper(int gpuid)
// {
//     cudaSetDevice(gpuid);

//     // int *dn;
//     // cudaMalloc((void **)&dn, 1 * sizeof(int));

// 	size_t free_byte;
// 	size_t total_byte;

// 	CUresult cuda_status = cuMemGetInfo(&free_byte, &total_byte);

// 	const char *pStr = nullptr;
// 	if (CUDA_SUCCESS != cuda_status) {
// 		cuGetErrorString(cuda_status, &pStr);
// 		printf("Error: cudaMemGetInfo fails, %s \n", pStr);
// 		return;
// 	}

// 	double free_db = (double)free_byte;
// 	double total_db = (double)total_byte;
// 	double used_db_1 = (total_db - free_db) / 1024.0 / 1024.0;

// 	std::cout <<"显存已使用 " << used_db_1 << " MB\n";

//     // cudaFree(dn);
// }

// int CheckCUDAProperty( int devId )
// {
//     cuInit(0);

// 	CUdevice dev = devId;
// 	size_t memSize = 0;
// 	char devName[256] = {0};
// 	int major = 0, minor = 0;
// 	CUresult rlt = CUDA_SUCCESS;

//     rlt = cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, dev);
//     checkCudaErrors( rlt );

//     rlt = cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, dev);
// 	checkCudaErrors( rlt );

// 	rlt = cuDeviceGetName( devName, sizeof( devName ), dev );
// 	checkCudaErrors( rlt );

// 	printf( "Using GPU Device %d: %s has SM %d.%d compute capability\n",
// 		    dev, devName, major, minor );

// 	rlt = cuDeviceTotalMem( &memSize, dev );
// 	checkCudaErrors( rlt );

// 	printf( "Total amount of global memory:   %4.4f MB\n",
// 		   (float)memSize / ( 1024 * 1024 ) );

// 	return 0;
// }

// /**
//  * 注意: gpuFrame 在解码器设置的显卡上,后续操作要十分注意这一点,尤其是多线程情况
//  * */
// void postDecoded(const void * userPtr, AVFrame * gpuFrame){
//     AbstractDecoder* decoder = (AbstractDecoder*)userPtr;
//     if (decoder!= nullptr)
//     {
//         // cout << "decode name: " << decoder->getName() << endl;

//             // const char* gpu_pixfmt = av_get_pix_fmt_name((AVPixelFormat)gpuFrame->format);
//             // cout << "pixfmt: " << gpu_pixfmt << endl;
//             // cout << "keyframe: " << gpuFrame->key_frame << " width: " << gpuFrame->width << " height: "<< gpuFrame->height << endl;
//             // cout << "decode successed ✿✿ヽ(°▽°)ノ✿ " << endl;

//             int sum = sum1;
//             if (decoder->getName() == "dec0")
//             {
//                 sum1 ++ ;
//                 sum = sum1;

//                 if (gpuFrame->format == AV_PIX_FMT_CUDA)
//                 {   
//                     // cout << "gpuid = " << atoi(decoder->m_cfg.gpuid.c_str()) << endl;
//                     cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str()));
//                     cudaError_t cudaStatus;
//                     if(pHwRgb[0] == nullptr){
//                         // cudaStreamCreate(&stream[0]);
//                         cuda_common::setColorSpace( ITU_709, 0 );
//                         cudaStatus = cudaMalloc((void **)&pHwRgb[0], 3 * gpuFrame->width * gpuFrame->height * sizeof(unsigned char));
//                     }
//                     cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], pHwRgb[0], gpuFrame->width, gpuFrame->height);
//                     cudaDeviceSynchronize();
//                     if (cudaStatus != cudaSuccess) {
//                         cout << "CUDAToBGR failed !!!" << endl;
//                         return;
//                     }

//                     string path = data_home + decoder->getName() + ".jpg";
//                     saveJpeg(path.c_str(), pHwRgb[0], gpuFrame->width, gpuFrame->height, stream[0]);  // 验证 CUDAToRGB 
//                 }
//             } else if (decoder->getName() == "dec2") 
//             {
//                 sum2 ++ ;
//                 sum = sum2;

//                 if (gpuFrame->format == AV_PIX_FMT_CUDA)
//                 {   
//                     // cout << "gpuid = " << atoi(decoder->m_cfg.gpuid.c_str()) << endl;
//                     cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str()));
//                     cudaError_t cudaStatus;
//                     if(pHwRgb[1] == nullptr){
//                         // cudaStreamCreate(&stream[1]);
//                         cuda_common::setColorSpace( ITU_709, 0 );
//                         cudaStatus = cudaMalloc((void **)&pHwRgb[1], 3 * gpuFrame->width * gpuFrame->height * sizeof(unsigned char));
//                     }
//                     cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], pHwRgb[1], gpuFrame->width, gpuFrame->height);
//                     cudaDeviceSynchronize();
//                     if (cudaStatus != cudaSuccess) {
//                         cout << "CUDAToBGR failed !!!" << endl;
//                         return;
//                     }

//                     string path = data_home + decoder->getName() + ".jpg";
//                     saveJpeg(path.c_str(), pHwRgb[1], gpuFrame->width, gpuFrame->height, stream[1]);  // 验证 CUDAToRGB 
//                 }
//             }
//     }
// }

// long start_time = 0;
// long end_time = 0;
// bool count_flag = false;
// int count = 0;
// int count_std = 100;


// static int sum = 0;
// unsigned char *pHwData = nullptr;

// void postDecoded0(const void * userPtr, AVFrame * gpuFrame){
//     // std::this_thread::sleep_for(std::chrono::milliseconds(30000));

//     AbstractDecoder* decoder = (AbstractDecoder*)userPtr;
//     if (decoder!= nullptr)
//     {
//         // cout << "decode name: " << decoder->getName() << endl;
//         if (decoder->getName() == "dec")
//         {
//             if (! count_flag)
//             {
//                 count_flag = true;
//                 count = 0;
//                 end_time = start_time = UtilTools::get_cur_time_ms();
//             }
//             count++;
//             sum ++ ;
//             if (count >= count_std)
//             {
//                 // end_time = UtilTools::get_cur_time_ms();
//                 // long time_using = end_time - start_time;
//                 // double time_per_frame = double(time_using)/count_std ;
//                 // cout << count_std << "帧用时:" << time_using << "ms 每帧用时:" << time_per_frame << "ms" << endl;
//                 cout << decoder->getName() << " keyframe: " << gpuFrame->key_frame << " width: " << gpuFrame->width << " height: "<< gpuFrame->height << endl;
//                 // cout << gpuFrame->pts << endl;

//                 count_flag = false;
//             }
//             // cout << "帧数:" << sum << endl;

//             if (gpuFrame->format == AV_PIX_FMT_CUDA)
//             {   
//                 cudaSetDevice(atoi(decoder->m_cfg.gpuid.c_str()));
//                 // cout << "gpu id : " << decoder->m_cfg.gpuid.c_str() << endl;
//                 cudaError_t cudaStatus;
//                 if(pHwData == nullptr){
//                     cuda_common::setColorSpace( ITU_709, 0 );
//                     cudaStatus = cudaMalloc((void **)&pHwData, 3 * gpuFrame->width * gpuFrame->height * sizeof(unsigned char));
//                 }
//                 cudaStatus = cuda_common::CUDAToBGR((CUdeviceptr)gpuFrame->data[0],(CUdeviceptr)gpuFrame->data[1], gpuFrame->linesize[0], gpuFrame->linesize[1], pHwData, gpuFrame->width, gpuFrame->height);
//                 cudaDeviceSynchronize();
//                 if (cudaStatus != cudaSuccess) {
//                     cout << "CUDAToBGR failed !!!" << endl;
//                     return;
//                 }

//                 string path = data_home + decoder->getName() + ".jpg";
//                 saveJpeg(path.c_str(), pHwData, gpuFrame->width, gpuFrame->height, nullptr);  // 验证 CUDAToRGB 
//             }
//         }
//     }
// }

// void decode_finished_cbk(const void* userPtr){
//     cout << "当前时间戳: " << UtilTools::get_cur_time_ms() << endl;
// }

// bool decode_request_stream_cbk(const char* deviceId){
//     cout << "需在此请求流" << endl;
//     return true;
// }

// // string test_uri = "rtmp://192.168.10.56:1935/objecteye/1";
// // string test_uri = "/home/cmhu/data/output_800x480.mp4";
// // string test_uri = "/home/cmhu/data/output_1920x1080.mp4";
// // string test_uri = "rtsp://176.10.0.2:8554/stream";
// // string test_uri = "/mnt/f/fiss/test_data/h265.mp4";
// string test_uri = "rtsp://176.10.0.4:8554/stream";

// void createDecode(int index, const char* gpu_id){
//     FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance();
//     MgrDecConfig config;
//     config.name = "dec" + to_string(index);
//     config.cfg.uri = test_uri;
//     config.cfg.post_decoded_cbk = postDecoded;
//     config.cfg.decode_finished_cbk = decode_finished_cbk;
//     config.cfg.force_tcp = true;
//     config.dec_type = DECODER_TYPE_FFMPEG;

//     config.cfg.gpuid = gpu_id;
//     // if (index % 2 == 0)
//     // {
//     //     config.cfg.gpuid = "0";
//     // }
//     // else
//     // {
//     //     config.cfg.gpuid = "0";
//     // }
    
//     AbstractDecoder* decoder = pDecManager->createDecoder(config);
//     if (!decoder)
//     {
//         return ;
//     }
//     pDecManager->setPostDecArg(config.name, decoder);
//     pDecManager->setFinishedDecArg(config.name, decoder);
//     pDecManager->startDecodeByName(config.name);
// }

// void createGB28181Decode(int index, char* gpu_id, int port){
//     FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance();
//     MgrDecConfig config;
//     config.name = "dec" + to_string(index);
//     config.cfg.uri = config.name;
//     config.cfg.post_decoded_cbk = postDecoded;
//     config.cfg.decode_finished_cbk = decode_finished_cbk;
//     config.cfg.request_stream_cbk = decode_request_stream_cbk;
//     config.cfg.force_tcp = true;

//     config.dec_type = DECODER_TYPE_GB28181;
//     config.cfg.port = port;//allocRtpPort();

//     config.cfg.gpuid = gpu_id;
    
//     AbstractDecoder* decoder = pDecManager->createDecoder(config);
//     if (!decoder)
//     {
//         return ;
//     }
//     pDecManager->setPostDecArg(config.name, decoder);
//     pDecManager->setFinishedDecArg(config.name, decoder);
//     pDecManager->startDecodeByName(config.name);
// }

// void logFF(void *, int level, const char *fmt, va_list ap)
// {
//     vfprintf(stdout, fmt, ap);
// }


// int main(int argc, char* argv[]){

//     test_uri = "rtsp://admin:admin@123456@192.168.60.176:554/cam/realmonitor?channel=1&subtype=0";//argv[1];
//     char* gpuid = argv[2];
//     int port = atoi(argv[3]);
//     cout << test_uri << "   gpu_id:" << gpuid << "   port:" << port << endl;

//     // av_log_set_callback(&logFF);

//     CheckCUDAProperty(atoi(gpuid));

//     pthread_t m_decode_thread;
//     pthread_create(&m_decode_thread,0,
//         [](void* arg)
//         {
//             // cudaSetDevice(atoi(gpuid));
//             while (true)
//             {
//                 std::this_thread::sleep_for(std::chrono::minutes(1));
//                 FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance();
//                 int count = pDecManager->count();
//                 cout << "当前时间:" << UtilTools::get_cur_time_ms() << "  当前运行路数: " << pDecManager->count() << endl;
//             }  

//             return (void*)0;
//         }
//     ,nullptr);


//     FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance();
//     int i = 0;

//     while (true)
//     {
//         int ch = getchar();
//         if (ch == 'q')
//         {
//             break;
//         }

//         switch (ch)
//         {
//         case 'f':
//         case 'F':
//             createDecode(i, gpuid);
//             i++;
//             break;
//         case 'g':
//         case 'G':
//             createGB28181Decode(i, gpuid, port);
//             i++;
//             break;
//         case 'r':
//         case 'R':
//             pDecManager->resumeDecoder("dec0");
//             break;
//         case 'p':
//         case 'P':
//             pDecManager->pauseDecoder("dec0");
//             break;

//         case 'c':
//         case 'C':
//             i--;
//             pDecManager->closeDecoderByName("dec" + to_string(i));
//             break;

//         case 'i':
//         case 'I':
//         {
//             int w,h;
//             pDecManager->getResolution("dec0", w,h);
//             printf( "%s : %dx%d\n", "dec0" , w,h );
//         }
//             break;

//         default:
//             break;
//         }

//         /* code */
//     }

//     cout << "总共帧数:" << sum << endl;
//     pDecManager->closeAllDecoder();
// }