#include "CVideoDecoder.h" #include extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" #include "libavdevice/avdevice.h" #include "libavutil/opt.h" #include "libavfilter/avfilter.h" #include "libavfilter/buffersrc.h" #include "libavfilter/buffersink.h" #include "libavutil/imgutils.h" #include "libavutil/frame.h" }; #include "CVideoDataManager.h" #include "../Include/libyuv.h" #include "FusionAndTailor.cuh" CVideoDecoder::CVideoDecoder(AVCodecContext* pDecoder, bool bHard, CVideoDataManager* pDataManager) { m_pDecoder = pDecoder; m_pDataManager = pDataManager; m_bHard = bHard; m_pDataManager->SetDecodeDataSize(m_pDecoder->width* m_pDecoder->height*3/2); _beginthreadex(nullptr, 0, &CVideoDecoder::DecodeThread, this, 0, 0); CUstream Cur = ((CUstream)pCuStream); cudaError Err = cudaStreamCreate(&(Cur)); pCuStream = Cur; } CVideoDecoder::~CVideoDecoder() { if (m_pDecoder != nullptr) { avcodec_close(m_pDecoder); m_pDecoder = nullptr; } } unsigned __stdcall CVideoDecoder::DecodeThread(void* param) { CVideoDecoder* pThis = (CVideoDecoder*)param; pThis->DecodeProcessor(); return 0; } void CVideoDecoder::DecodeProcessor() { while (true) { //if (m_pDataManager->GetSyncDataSize() > 0) { CPacketInfo* pPack = nullptr; if (m_pDataManager->GetSyncData(pPack)) { uint8_t* pData = nullptr; DecodePacket(pPack->m_pPkt, pData); //DecodePacketGpu(pPack->m_pPkt, pData); m_pDataManager->AddDecoderData(pData, pPack->m_dPtzAngle); m_pDataManager->ReleaseSyncData(pPack); } } Sleep(5); } } bool CVideoDecoder::DecodePacket(AVPacket* pkt, unsigned char* & pData) { int nRet = 0; AVFrame* tmp_frame = nullptr; avcodec_send_packet(m_pDecoder, pkt); AVFrame* pFrame = av_frame_alloc(); nRet = avcodec_receive_frame(m_pDecoder, pFrame); pData = new unsigned char[pFrame->linesize[0] * pFrame->height *3]; if (m_bHard) { // 如果采用的硬件加速剂,则调用avcodec_receive_frame()函数后,解码后的数据还在GPU中,所以需要通过此函数 // 将GPU中的数据转移到CPU中来 tmp_frame = av_frame_alloc(); if (av_hwframe_transfer_data(tmp_frame, pFrame, 0) < 0) { return false; } if (pFrame != nullptr) { av_frame_free(&pFrame); pFrame = nullptr; } pFrame = tmp_frame; //libyuv::NV12ToI420( // pFrame->data[0], pFrame->linesize[0], // pFrame->data[1], pFrame->linesize[1], // pData, pFrame->width, // pData + pFrame->width * pFrame->height, pFrame->width / 2, // pData + pFrame->width * pFrame->height * 5 / 4, pFrame->width / 2, // pFrame->width, pFrame->height //); libyuv::NV12ToRGB24( pFrame->data[0], pFrame->linesize[0], pFrame->data[1], pFrame->linesize[1], pData, pFrame->width * 3, pFrame->width, pFrame->height ); } else { int dst_stride_y2 = pFrame->width; int dst_stride_u2 = dst_stride_y2 / 2; int dst_stride_v2 = dst_stride_y2 / 2; libyuv::I420Copy(pFrame->data[0], pFrame->linesize[0], pFrame->data[1], pFrame->linesize[1], pFrame->data[2], pFrame->linesize[2], pData, pFrame->width, pData + pFrame->width * pFrame->height, pFrame->width/2, pData + pFrame->width * pFrame->height * 5 / 4, pFrame->width / 2, pFrame->width, pFrame->height); } //cv::Mat mat(pFrame->height * 3 / 2, pFrame->width, CV_8UC1, pData); av_frame_free(&pFrame); pFrame = nullptr; return true; } //注意该函数返回的指针指向的是显存数据, bool CVideoDecoder::DecodePacketGpu(AVPacket* pkt, unsigned char*& pData) { int nRet = 0; AVFrame* tmp_frame = nullptr; avcodec_send_packet(m_pDecoder, pkt); AVFrame* pFrame = av_frame_alloc(); nRet = avcodec_receive_frame(m_pDecoder, pFrame); pFrame->format = AV_PIX_FMT_NV12; CUstream CurStream = (CUstream)pCuStream; if (m_pI420 == nullptr) { cudaMalloc(&m_pI420, pFrame->width * pFrame->height * 3 / 2); YUVTailorAndBlender::setColorSpace2(0); } YUVTailorAndBlender::TurnCUDAFormatToI420(pFrame->data[0], pFrame->data[1], pFrame->linesize[0], pFrame->linesize[1], m_pI420, pFrame->width, pFrame->height, &CurStream); cudaError err = cudaDeviceSynchronize(); if (pData != nullptr) cudaFree(pData); cudaMalloc((void**)&pData, pFrame->width * pFrame->height * 3 / 2); cudaMemcpy(pData,m_pI420 , pFrame->width * pFrame->height * 3 / 2, cudaMemcpyDeviceToDevice); //下载 //cudaMemcpy(pData, m_pI420, pFrame->width * pFrame->height * 3/2, cudaMemcpyDeviceToHost); //FILE* file = fopen("111.yuv", "wb"); //已只读方式打开 //fwrite(pData, 1, pFrame->height * pFrame->width, file); //写入操作 //fwrite(pData + pFrame->height* pFrame->width, 1, pFrame->height * pFrame->width/4, file); //写入操作 //fwrite(pData + pFrame->height * pFrame->width*5/4, 1, pFrame->height * pFrame->width/4, file); //写入操作 //fclose(file); av_frame_free(&pFrame); return false; }