#include "FFNvDecoderManager.h" #include #include "cuda_kernels.h" #include "NvJpegEncoder.h" #include #include #include #include #include "FFSaveImg.h" #ifdef _WIN32 #include "Winsock2.h" #pragma comment(lib, "ws2_32.lib") #endif #ifdef __linux__ #include "arpa/inet.h" #endif #include "utiltools.hpp" #include "curl/curl.h" #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; } static long get_cur_time_ms() { chrono::time_point tpMicro = chrono::time_point_cast(chrono::system_clock::now()); return tpMicro.time_since_epoch().count(); } /** * 注意: gpuFrame 在解码器设置的显卡上,后续操作要十分注意这一点,尤其是多线程情况 * */ void postDecoded(const void * userPtr, AVFrame * gpuFrame){ // long first_time = get_cur_time_ms(); // long second_time = 0; // int a = 1; // while(true){ // a = a * 99; // if(a > 1000000){ // a = 1; // } // second_time = get_cur_time_ms(); // if(second_time - first_time > 100){ // break; // } // } // return ; // std::this_thread::sleep_for(std::chrono::milliseconds(100)); 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(100)); 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 } } } } //get请求和post请求数据响应函数 size_t req_reply(void *ptr, size_t size, size_t nmemb, void *stream) { //在注释的里面可以打印请求流,cookie的信息 //cout << "----->reply" << endl; string *str = (string*)stream; //cout << *str << endl; (*str).append((char*)ptr, size*nmemb); return size * nmemb; } //http POST请求 CURLcode curl_post_body_getVideoRealStream(const string &url, const string &postParams, string &response, string devid, string ip, string port) { // curl初始化 CURL *curl = curl_easy_init(); // curl返回值 CURLcode res; if (curl) { // set params //设置curl的请求头 struct curl_slist* header_list = NULL; header_list = curl_slist_append(header_list, "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"); // header_list = curl_slist_append(header_list, "Content-Type:application/x-www-form-urlencoded; charset=UTF-8"); header_list = curl_slist_append(header_list, "Accept: application/json"); header_list = curl_slist_append(header_list, "Content-Type: application/json");//text/html header_list = curl_slist_append(header_list, "charsets: utf-8"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); //不接收响应头数据0代表不接收 1代表接收 curl_easy_setopt(curl, CURLOPT_HEADER, 0); //设置请求为post请求 // curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); //设置请求的URL地址 curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); //设置post请求的参数 // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postParams.c_str()); //设置ssl验证 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); //CURLOPT_VERBOSE的值为1时,会显示详细的调试信息 curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); string strResult = "{ \ \"authinfo\": \"hisense|hisense123|201807311630\", \ \"method\": \"getVideoRealStream\", \ \"deviceId\": \""+devid+"\", \ \"streamFormat\": \"0\", \ \"recvIp\": \""+ip+"\", \ \"recvPort\": \""+port+"\", \ \"remark\": \"\", \ \"protocol\": \"1\" \ }"; curl_easy_setopt(curl,CURLOPT_POSTFIELDS,strResult.c_str()); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); //设置数据接收和写入函数 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); //设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 6); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6); // 开启post请求 res = curl_easy_perform(curl); } //释放curl curl_easy_cleanup(curl); return res; } //http POST请求 CURLcode curl_post_body_stopVideoRealStream(const string &url, const string &postParams, string &response, string handleId) { // curl初始化 CURL *curl = curl_easy_init(); // curl返回值 CURLcode res; if (curl) { // set params //设置curl的请求头 struct curl_slist* header_list = NULL; header_list = curl_slist_append(header_list, "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"); // header_list = curl_slist_append(header_list, "Content-Type:application/x-www-form-urlencoded; charset=UTF-8"); header_list = curl_slist_append(header_list, "Accept: application/json"); header_list = curl_slist_append(header_list, "Content-Type: application/json");//text/html header_list = curl_slist_append(header_list, "charsets: utf-8"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); //不接收响应头数据0代表不接收 1代表接收 curl_easy_setopt(curl, CURLOPT_HEADER, 0); //设置请求为post请求 // curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); //设置请求的URL地址 curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); //设置post请求的参数 // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postParams.c_str()); //设置ssl验证 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); //CURLOPT_VERBOSE的值为1时,会显示详细的调试信息 curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); string strResult = "{ \ \"authinfo\": \"hisense|hisense123|201807311630\", \ \"method\": \"stopVideoRealStream\", \ \"handleId\": \""+ handleId + "\" \ }"; curl_easy_setopt(curl,CURLOPT_POSTFIELDS,strResult.c_str()); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); //设置数据接收和写入函数 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); //设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 6); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6); // 开启post请求 res = curl_easy_perform(curl); } //释放curl curl_easy_cleanup(curl); return res; } void decode_finished_cbk(const void* userPtr){ cout << "当前时间戳: " << UtilTools::get_cur_time_ms() << endl; } string recv_port = "13012"; bool decode_request_stream_cbk(const char* deviceId){ // cout << "需在此请求流" << endl; string url_post = "http://172.16.6.129:7000/httpRequest"; string paramsLogin = "key1=value1&key2=value2"; string resPost; static string last_handleid = ""; if(!last_handleid.empty()){ auto res3 = curl_post_body_stopVideoRealStream(url_post, paramsLogin, resPost, last_handleid); if (res3 == CURLE_OK) { cout << resPost << endl; } } auto res = curl_post_body_getVideoRealStream(url_post, paramsLogin, resPost, deviceId, "172.16.6.129", recv_port); if (res == CURLE_OK) { cout << resPost << endl; size_t start = resPost.find_last_of(":") + 3; size_t end = resPost.find_last_of("\""); if (start == end){ return false; } last_handleid = resPost.substr(start,end - start); cout << last_handleid << 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://192.168.10.4:8554/street"; 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.snap_time_interval = 100; 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(char* devid, char* gpu_id, int port){ FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); MgrDecConfig config; config.name = devid; 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; config.snap_time_interval = 100; recv_port = to_string(port); 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 = argv[1]; char* gpuid = argv[2]; int port = atoi(argv[3]); char* devId = argv[4]; cout << test_uri << " gpu_id:" << gpuid << " port:" << port << " devId:" << devId << 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::seconds(10)); FFNvDecoderManager* pDecManager = FFNvDecoderManager::getInstance(); int count = pDecManager->count(); cout << "当前时间:" << UtilTools::get_cur_time_ms() << " 当前运行路数: " << pDecManager->count() << endl; vector vec_img = pDecManager->timing_snapshot_all(); for (auto imgInfo : vec_img){ auto task_id = imgInfo->dec_name; std::string fpath_ori = "./time_snapshot/" + task_id + "_" + std::to_string(imgInfo->timestamp) + ".jpg"; saveJpg(imgInfo->width, imgInfo->height, imgInfo->pData, fpath_ori.c_str()); pDecManager->releaseFFImgInfo(imgInfo); } } 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(devId, 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(); }