王柳 发表于 2024-6-20 14:55:56

ffmpeg解码播放

int VideoDecodeModule::Open(std::string strUrl)
{
        AVFormatContext *pFormatCtx = nullptr;
        AVCodec *pCodec = nullptr;
        AVCodecContext* pCodecCtx = nullptr;
        AVDictionary *opt = nullptr;
        std::string decodeName = "";
        AVBufferRef* pBufferRef = nullptr;
        int ret = 0;
        int videoStream = -1;
        char errorbuf = { 0 };
        av_dict_set(&opt, "buffer_size", "1024000", 0);      // 缓冲区大小 单位字节 解决高画质模糊的问题
        av_dict_set(&opt, "max_delay", "100", 0);            // 最大延时 单位微妙
        av_dict_set(&opt, "stimeout", "3000000", 0);         // 设置超时断开连接时间 3s 单位微妙
        av_dict_set(&opt, "rtsp_transport", "tcp", 0);         // 以tcp方式打开,如果以udp方式打开将tcp替换为udp
        av_dict_set(&opt, "fflags", "nobuffer", 0);
        av_dict_set(&opt, "rtbufsize", "6", 0);
        av_dict_set(&opt, "start_time_realtime", 0, 0);

        if ((ret = avformat_open_input(&pFormatCtx, strUrl.data(), nullptr, &opt)) != 0)
        {
                av_strerror(ret, errorbuf, sizeof(errorbuf));
                return -1;
        }
       
        m_spFormatContext = std::shared_ptr<AVFormatContext>(pFormatCtx, [](AVFormatContext* ctx){
                avformat_close_input(&ctx);
        });

        /*if ((ret = avformat_find_stream_info(pFormatCtx, nullptr)) < 0)
        {
                av_strerror(ret, errorbuf, sizeof(errorbuf));
                return -1;
        }*/

        if ((ret = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &pCodec, 0)) < 0)
        {
                av_strerror(ret, errorbuf, sizeof(errorbuf));
                return -1;
        }
        videoStream = ret;
        m_video = pFormatCtx->streams;

        if (m_decodeType == DT_CPU)
        {
                if (!(pCodec = avcodec_find_decoder(m_video->codecpar->codec_id)))
                {
                        int error = AVERROR(ENOMEM);
                        return -1;
                }
        }
        else if (m_decodeType == DT_INTER_QSV)
        {
                decodeName = GetCodeName(m_video->codecpar->codec_id, DT_INTER_QSV);
                if (av_hwdevice_ctx_create(&pBufferRef, AV_HWDEVICE_TYPE_QSV, "auto", nullptr, 0) != 0)
                {
                        return -1;
                }
                if (!(pCodec = avcodec_find_decoder_by_name(decodeName.data())))
                {
                        int error = AVERROR(ENOMEM);
                        return -1;
                }
        }
        else if (m_decodeType == DT_NVIDIA_CUDA)
        {
                decodeName = GetCodeName(m_video->codecpar->codec_id, DT_NVIDIA_CUDA);
                if (av_hwdevice_ctx_create(&pBufferRef, AV_HWDEVICE_TYPE_CUDA, "auto", nullptr, 0) != 0)
                {
                        return -1;
                }
                if (!(pCodec = avcodec_find_decoder_by_name(decodeName.data())))
                {
                        int error = AVERROR(ENOMEM);
                        return -1;
                }
        }

        if (auto frame = av_frame_alloc())
        {
                m_spSwFrame = std::shared_ptr<AVFrame>(frame, [](AVFrame* p) {av_frame_free(&p); });
        }
       
        if (!(pCodecCtx = avcodec_alloc_context3(pCodec)))
        {
                return -1;
        }

        m_spCodecContext = std::shared_ptr<AVCodecContext>(pCodecCtx, [](AVCodecContext* ctx)
        {
                avcodec_free_context(&ctx);
        });

        m_spCodecContext->codec_id = m_video->codecpar->codec_id;
        if (m_video->codecpar->extradata_size)
        {
                m_spCodecContext->extradata = (uint8_t*)av_mallocz(m_video->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
                if (!m_spCodecContext->extradata)
                {
                        return -1;
                }
                memcpy(m_spCodecContext->extradata, m_video->codecpar->extradata, m_video->codecpar->extradata_size);
                m_spCodecContext->extradata_size = m_video->codecpar->extradata_size;
        }

        m_spCodecContext->flags2 |= AV_CODEC_FLAG2_FAST;    // 允许不符合规范的加速技巧。
        m_spCodecContext->thread_count = 8;               // 使用8线程解码

        if ((ret = avcodec_parameters_to_context(m_spCodecContext.get(), m_video->codecpar)) < 0)
        {
                av_strerror(ret, errorbuf, sizeof(errorbuf));
                return -1;
        }
       
        if (m_decodeType == DT_INTER_QSV)
        {
                m_spCodecContext->opaque = pBufferRef;
                m_spCodecContext->get_format = GetHWQsvFormat;
        }
        else if (m_decodeType == DT_NVIDIA_CUDA)
        {
                m_spCodecContext->hw_device_ctx = av_buffer_ref(pBufferRef);
                m_spCodecContext->opaque = this;
                m_spCodecContext->get_format = GetHWCudaFormat;
        }

        if ((ret = avcodec_open2(m_spCodecContext.get(), pCodec, nullptr)) < 0)
        {
                av_strerror(ret, errorbuf, sizeof(errorbuf));
                return -1;
        }
        m_isConnect = true;
        return ret;
} avformat_find_stream_info 比较耗时,播放视频会比较慢,这里将他屏蔽掉,对播放视频没有影响
2:吸收数据
void VideoDecodeModule::PushFrameQueue(std::shared_ptr<AVPacket> spPacket)
{
        if (spPacket && !spPacket->size && spPacket->data)
        {
                return;
        }
        int ret = avcodec_send_packet(m_spCodecContext.get(), spPacket.get());
        if (ret < 0)
        {
                char errorbuf = { 0 };
                av_strerror(ret, errorbuf, sizeof(errorbuf));
                return;
        }
        while (true)
        {
                auto spFrame = std::shared_ptr<AVFrame>(av_frame_alloc(), [](AVFrame* p)
                {
                        av_frame_free(&p);
                });
                if (!spFrame)
                {
                        return;
                }
                ret = avcodec_receive_frame(m_spCodecContext.get(), spFrame.get());
                if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
                {
                        return;
                }
                if (ret < 0)
                {
                        break;
                }

                if (m_decodeType == DT_INTER_QSV || m_decodeType == DT_NVIDIA_CUDA)
                {
                        HandleHWVideoFrame(spFrame);
                }
                else if (m_decodeType == DT_CPU)
                {
                        HandleVideoFrame(spFrame);
                }
        }
} 3:吸收视频帧

void VideoDecodeModule::HandleVideoFrame(const std::shared_ptr<AVFrame>& spFrame)
{
        if (!spFrame)
                return;
        //if (GetFrameExtra() % 6 != 0)
        //        return;
        /// 解码的图片宽
        int width = spFrame->width;
        /// 解码的图片高
        int height = spFrame->height;
        // 计算转码后的图片裸数据需要的大小
        int nSrcbuffSize = av_image_get_buffer_size(m_pixelFormat, width, height, 1);
        if (nSrcbuffSize > m_dstBuffer.size())
        {
                m_dstBuffer.resize(nSrcbuffSize, '\0');
        }
        std::shared_ptr<SwsContext>        spSwsContext = nullptr;
        /// 判断是否需要格式转换
        if (m_pixelFormat != (AVPixelFormat)spFrame->format)
        {
                AVPixelFormat srcFmt = (AVPixelFormat)spFrame->format;
                //SwsContext* image_sws_ctx = sws_getContext(width, height, srcFmt, m_scaleWidth, m_scaleHeight, m_pixelFormat, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
               
                SwsContext* image_sws_ctx = sws_getCachedContext(NULL, width, height, srcFmt, m_scaleWidth, m_scaleHeight, m_pixelFormat, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
               
                spSwsContext = std::shared_ptr<SwsContext>(image_sws_ctx, [](SwsContext* p) {sws_freeContext(p); });
                uint8_t* data = { nullptr };
                int linesize = { 0 };
                av_image_fill_arrays(data, linesize, m_dstBuffer.data(), m_pixelFormat, width, height, 1);

                int ret = sws_scale(spSwsContext.get(), (uint8_t const* const*)spFrame->data, spFrame->linesize, 0, height, data, linesize);
                if (ret < 0)
                        return;
        }

        if (m_HwndShow)
        {
                m_spSdlRender->DrawFrame(spFrame.get());
        }


        /*if (m_HwndShow)
        {
                BYTE** data = spFrame->data;
                int* linesize = spFrame->linesize;

                m_SdlTexture = SDL_CreateTexture(m_SdlRender, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, width, height);
                SDL_UpdateYUVTexture(m_SdlTexture, NULL, data, linesize,
                        data, linesize,
                        data, linesize);
                SDL_RenderClear(m_SdlRender);
                SDL_RenderCopy(m_SdlRender, m_SdlTexture, NULL, NULL);
                SDL_RenderPresent(m_SdlRender);
        }*/

        if (m_pFrameDataCallBack)
        {
                FrameInfo info;
                info.format = GetVideoFormatByAVPixelFormat(m_pixelFormat);
                info.width = width;
                info.height = height;
                info.pts = spFrame->pts / 1000;

                m_pFrameDataCallBack->cbFrameDataCallBack(m_dstBuffer.data(), m_dstBuffer.size(), info, m_pFrameDataCallBack->pUser);
        }
} 工程:https://download.csdn.net/download/weixin_38887743/88748651

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: ffmpeg解码播放