FFDecoder.cpp0 3.77 KB
#include "FFDecoder.h"

#include "./rtp/demuxer.h"

#include "common_header.h"
#include "../nvdec/FFCuContextManager.h"

static AVPixelFormat get_hw_format(AVCodecContext *avctx, const AVPixelFormat *pix_fmts){
	return AV_PIX_FMT_CUDA;
}

FFDecoder::FFDecoder(/* args */)
{
}

FFDecoder::~FFDecoder()
{
}

FrameData* FFDecoder::Decode(int videoType, char* data, int len, int isKey, uint64_t pts) {

    AVPacket* pkt = av_packet_alloc();
	av_init_packet(pkt);

    pkt->size = len;
    pkt->data = (uint8_t*)data;

    // ffmpeg 解码
    FrameData* frame_data = ff_decode(videoType, pkt);

    av_packet_free(&pkt);
    pkt = nullptr;

    frame_data.bKeyframe = (isKey != 0);
    frame_data.pts = pts;

    return frame_data;
}

FrameData* FFDecoder::ff_decode(int videoType, AVPacket* pkt) {
    if (m_pAVCodecCtx == nullptr) {
        LOG_INFO("frame data is zero --{}", m_dec_name);
		if (VIDEO_TYPE_H264 == videoType) {
            if (m_devid >= 0){
                m_pAVCodec = avcodec_find_decoder_by_name("h264_cuvid");
            }
            else{
				m_pAVCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
			}
			LOG_INFO("m_avCodecName is H264");		
		}
		else if (VIDEO_TYPE_H265 == videoType)
		{
            if (m_devid >= 0){
                m_pAVCodec = avcodec_find_decoder_by_name("hevc_cuvid");
            }
            else{
                m_pAVCodec = avcodec_find_decoder(AV_CODEC_ID_H265);
            }
			LOG_INFO("m_avCodecName is H265");
		}
		else{
			LOG_INFO("m_avCodecName is unknown, videoType is {}", videoType);
		}

		if (!m_pAVCodec)
		{
			LOG_ERROR("frameCallback frame decode error, ERROR_DECODER_NOT_FOUND");
			return nullptr;return;
		}

        m_pAVCodecCtx = avcodec_alloc_context3(m_pAVCodec);

        if (m_devid >= 0) {
            char gpui[8] = { 0 };
            sprintf(gpui, "%d", m_devid);
            av_dict_set(&gpu_options, "gpu", gpui, 0);

            m_pAVCodecCtx->get_format = get_hw_format;

            FFCuContextManager* pCtxMgr = FFCuContextManager::getInstance();
            m_pAVCodecCtx->hw_device_ctx = av_buffer_ref(pCtxMgr->getCuCtx(gpui));
            if (nullptr == m_pAVCodecCtx->hw_device_ctx){
                // TODO 这里应该抛出错误
                return nullptr;
            }
        }

        if (avcodec_open2(m_pAVCodecCtx, m_pAVCodec, &gpu_options) < 0)
			return nullptr;
	}

    //开始解码
    int ret = avcodec_send_packet(m_pAVCodecCtx, pkt);
    if (ret < 0) {
        //send_exception(RunMessageType::E2002, e_msg);
        LOG_ERROR("Real stream视频解码失败,请检查视频设备{}: avcodec_send_packet failed. ret={}", m_dec_name, ret);
        return;
    }
 
    if (frameW < 1) {
        frameW = m_pAVCodecCtx->width;
        frameH = m_pAVCodecCtx->height;
        if (frameW <= 0 || frameH <= 0) {
            LOG_ERROR("[{}] frame W or H is error! ({},{})", m_dec_name, frameW, frameH);
            return nullptr;
        }	
    }
	// m_fps = m_pAVCodecCtx->pkt_timebase.den == 0 ? 25.0 : av_q2d(m_pAVCodecCtx->pkt_timebase);
    m_fps = av_q2d(m_pAVCodecCtx->framerate);
	// LOG_DEBUG("frameW {}--frameH {}", frameW, frameH);

    FrameData* pData = new FrameData();
    ret = avcodec_receive_frame(m_pAVCodecCtx, pData->frame);
    if ((ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) || ret < 0){
        LOG_ERROR("{} - Failed to receive frame: {}", m_dec_name, ret);
        delete pData;
        pData = nullptr;
        return nullptr;
    }
    
    AVFrame* gpuFrame = pData->frame;
    if (gpuFrame->width != frameW || gpuFrame->height != frameH){
        LOG_INFO("AVFrame is inconsistent: width is {}, height is {}; original frameW is {}, frameH is {}--{}", gpuFrame->width, gpuFrame->height, frameW, frameH , m_dec_name);
        delete pData;
        pData = nullptr;
        return nullptr;
    }

    return pData;
}