ffmpeg解码播放

王柳  金牌会员 | 2024-6-20 14:55:56 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 542|帖子 542|积分 1626

  1. int VideoDecodeModule::Open(std::string strUrl)
  2. {
  3.         AVFormatContext *pFormatCtx = nullptr;
  4.         AVCodec *pCodec = nullptr;
  5.         AVCodecContext* pCodecCtx = nullptr;
  6.         AVDictionary *opt = nullptr;
  7.         std::string decodeName = "";
  8.         AVBufferRef* pBufferRef = nullptr;
  9.         int ret = 0;
  10.         int videoStream = -1;
  11.         char errorbuf[1024] = { 0 };
  12.         av_dict_set(&opt, "buffer_size", "1024000", 0);        // 缓冲区大小 单位字节 解决高画质模糊的问题
  13.         av_dict_set(&opt, "max_delay", "100", 0);              // 最大延时 单位微妙
  14.         av_dict_set(&opt, "stimeout", "3000000", 0);           // 设置超时断开连接时间 3s 单位微妙
  15.         av_dict_set(&opt, "rtsp_transport", "tcp", 0);         // 以tcp方式打开,如果以udp方式打开将tcp替换为udp
  16.         av_dict_set(&opt, "fflags", "nobuffer", 0);
  17.         av_dict_set(&opt, "rtbufsize", "6", 0);
  18.         av_dict_set(&opt, "start_time_realtime", 0, 0);
  19.         if ((ret = avformat_open_input(&pFormatCtx, strUrl.data(), nullptr, &opt)) != 0)
  20.         {
  21.                 av_strerror(ret, errorbuf, sizeof(errorbuf));
  22.                 return -1;
  23.         }
  24.        
  25.         m_spFormatContext = std::shared_ptr<AVFormatContext>(pFormatCtx, [](AVFormatContext* ctx){
  26.                 avformat_close_input(&ctx);
  27.         });
  28.         /*if ((ret = avformat_find_stream_info(pFormatCtx, nullptr)) < 0)
  29.         {
  30.                 av_strerror(ret, errorbuf, sizeof(errorbuf));
  31.                 return -1;
  32.         }*/
  33.         if ((ret = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &pCodec, 0)) < 0)
  34.         {
  35.                 av_strerror(ret, errorbuf, sizeof(errorbuf));
  36.                 return -1;
  37.         }
  38.         videoStream = ret;
  39.         m_video = pFormatCtx->streams[videoStream];
  40.         if (m_decodeType == DT_CPU)
  41.         {
  42.                 if (!(pCodec = avcodec_find_decoder(m_video->codecpar->codec_id)))
  43.                 {
  44.                         int error = AVERROR(ENOMEM);
  45.                         return -1;
  46.                 }
  47.         }
  48.         else if (m_decodeType == DT_INTER_QSV)
  49.         {
  50.                 decodeName = GetCodeName(m_video->codecpar->codec_id, DT_INTER_QSV);
  51.                 if (av_hwdevice_ctx_create(&pBufferRef, AV_HWDEVICE_TYPE_QSV, "auto", nullptr, 0) != 0)
  52.                 {
  53.                         return -1;
  54.                 }
  55.                 if (!(pCodec = avcodec_find_decoder_by_name(decodeName.data())))
  56.                 {
  57.                         int error = AVERROR(ENOMEM);
  58.                         return -1;
  59.                 }
  60.         }
  61.         else if (m_decodeType == DT_NVIDIA_CUDA)
  62.         {
  63.                 decodeName = GetCodeName(m_video->codecpar->codec_id, DT_NVIDIA_CUDA);
  64.                 if (av_hwdevice_ctx_create(&pBufferRef, AV_HWDEVICE_TYPE_CUDA, "auto", nullptr, 0) != 0)
  65.                 {
  66.                         return -1;
  67.                 }
  68.                 if (!(pCodec = avcodec_find_decoder_by_name(decodeName.data())))
  69.                 {
  70.                         int error = AVERROR(ENOMEM);
  71.                         return -1;
  72.                 }
  73.         }
  74.         if (auto frame = av_frame_alloc())
  75.         {
  76.                 m_spSwFrame = std::shared_ptr<AVFrame>(frame, [](AVFrame* p) {av_frame_free(&p); });
  77.         }
  78.        
  79.         if (!(pCodecCtx = avcodec_alloc_context3(pCodec)))
  80.         {
  81.                 return -1;
  82.         }
  83.         m_spCodecContext = std::shared_ptr<AVCodecContext>(pCodecCtx, [](AVCodecContext* ctx)
  84.         {
  85.                 avcodec_free_context(&ctx);
  86.         });
  87.         m_spCodecContext->codec_id = m_video->codecpar->codec_id;
  88.         if (m_video->codecpar->extradata_size)
  89.         {
  90.                 m_spCodecContext->extradata = (uint8_t*)av_mallocz(m_video->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
  91.                 if (!m_spCodecContext->extradata)
  92.                 {
  93.                         return -1;
  94.                 }
  95.                 memcpy(m_spCodecContext->extradata, m_video->codecpar->extradata, m_video->codecpar->extradata_size);
  96.                 m_spCodecContext->extradata_size = m_video->codecpar->extradata_size;
  97.         }
  98.         m_spCodecContext->flags2 |= AV_CODEC_FLAG2_FAST;    // 允许不符合规范的加速技巧。
  99.         m_spCodecContext->thread_count = 8;                 // 使用8线程解码
  100.         if ((ret = avcodec_parameters_to_context(m_spCodecContext.get(), m_video->codecpar)) < 0)
  101.         {
  102.                 av_strerror(ret, errorbuf, sizeof(errorbuf));
  103.                 return -1;
  104.         }
  105.        
  106.         if (m_decodeType == DT_INTER_QSV)
  107.         {
  108.                 m_spCodecContext->opaque = pBufferRef;
  109.                 m_spCodecContext->get_format = GetHWQsvFormat;
  110.         }
  111.         else if (m_decodeType == DT_NVIDIA_CUDA)
  112.         {
  113.                 m_spCodecContext->hw_device_ctx = av_buffer_ref(pBufferRef);
  114.                 m_spCodecContext->opaque = this;
  115.                 m_spCodecContext->get_format = GetHWCudaFormat;
  116.         }
  117.         if ((ret = avcodec_open2(m_spCodecContext.get(), pCodec, nullptr)) < 0)
  118.         {
  119.                 av_strerror(ret, errorbuf, sizeof(errorbuf));
  120.                 return -1;
  121.         }
  122.         m_isConnect = true;
  123.         return ret;
  124. }
复制代码
avformat_find_stream_info 比较耗时,播放视频会比较慢,这里将他屏蔽掉,对播放视频没有影响
2:吸收数据
  1. void VideoDecodeModule::PushFrameQueue(std::shared_ptr<AVPacket> spPacket)
  2. {
  3.         if (spPacket && !spPacket->size && spPacket->data)
  4.         {
  5.                 return;
  6.         }
  7.         int ret = avcodec_send_packet(m_spCodecContext.get(), spPacket.get());
  8.         if (ret < 0)
  9.         {
  10.                 char errorbuf[1024] = { 0 };
  11.                 av_strerror(ret, errorbuf, sizeof(errorbuf));
  12.                 return;
  13.         }
  14.         while (true)
  15.         {
  16.                 auto spFrame = std::shared_ptr<AVFrame>(av_frame_alloc(), [](AVFrame* p)
  17.                 {
  18.                         av_frame_free(&p);
  19.                 });
  20.                 if (!spFrame)
  21.                 {
  22.                         return;
  23.                 }
  24.                 ret = avcodec_receive_frame(m_spCodecContext.get(), spFrame.get());
  25.                 if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
  26.                 {
  27.                         return;
  28.                 }
  29.                 if (ret < 0)
  30.                 {
  31.                         break;
  32.                 }
  33.                 if (m_decodeType == DT_INTER_QSV || m_decodeType == DT_NVIDIA_CUDA)
  34.                 {
  35.                         HandleHWVideoFrame(spFrame);
  36.                 }
  37.                 else if (m_decodeType == DT_CPU)
  38.                 {
  39.                         HandleVideoFrame(spFrame);
  40.                 }
  41.         }
  42. }
复制代码
3:吸收视频帧
  1. void VideoDecodeModule::HandleVideoFrame(const std::shared_ptr<AVFrame>& spFrame)
  2. {
  3.         if (!spFrame)
  4.                 return;
  5.         //if (GetFrameExtra() % 6 != 0)
  6.         //        return;
  7.         /// 解码的图片宽
  8.         int width = spFrame->width;
  9.         /// 解码的图片高
  10.         int height = spFrame->height;
  11.         // 计算转码后的图片裸数据需要的大小
  12.         int nSrcbuffSize = av_image_get_buffer_size(m_pixelFormat, width, height, 1);
  13.         if (nSrcbuffSize > m_dstBuffer.size())
  14.         {
  15.                 m_dstBuffer.resize(nSrcbuffSize, '\0');
  16.         }
  17.         std::shared_ptr<SwsContext>        spSwsContext = nullptr;
  18.         /// 判断是否需要格式转换
  19.         if (m_pixelFormat != (AVPixelFormat)spFrame->format)
  20.         {
  21.                 AVPixelFormat srcFmt = (AVPixelFormat)spFrame->format;
  22.                 //SwsContext* image_sws_ctx = sws_getContext(width, height, srcFmt, m_scaleWidth, m_scaleHeight, m_pixelFormat, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
  23.                
  24.                 SwsContext* image_sws_ctx = sws_getCachedContext(NULL, width, height, srcFmt, m_scaleWidth, m_scaleHeight, m_pixelFormat, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
  25.                
  26.                 spSwsContext = std::shared_ptr<SwsContext>(image_sws_ctx, [](SwsContext* p) {sws_freeContext(p); });
  27.                 uint8_t* data[4] = { nullptr };
  28.                 int linesize[4] = { 0 };
  29.                 av_image_fill_arrays(data, linesize, m_dstBuffer.data(), m_pixelFormat, width, height, 1);
  30.                 int ret = sws_scale(spSwsContext.get(), (uint8_t const* const*)spFrame->data, spFrame->linesize, 0, height, data, linesize);
  31.                 if (ret < 0)
  32.                         return;
  33.         }
  34.         if (m_HwndShow)
  35.         {
  36.                 m_spSdlRender->DrawFrame(spFrame.get());
  37.         }
  38.         /*if (m_HwndShow)
  39.         {
  40.                 BYTE** data = spFrame->data;
  41.                 int* linesize = spFrame->linesize;
  42.                 m_SdlTexture = SDL_CreateTexture(m_SdlRender, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, width, height);
  43.                 SDL_UpdateYUVTexture(m_SdlTexture, NULL, data[0], linesize[0],
  44.                         data[1], linesize[1],
  45.                         data[2], linesize[2]);
  46.                 SDL_RenderClear(m_SdlRender);
  47.                 SDL_RenderCopy(m_SdlRender, m_SdlTexture, NULL, NULL);
  48.                 SDL_RenderPresent(m_SdlRender);
  49.         }*/
  50.         if (m_pFrameDataCallBack)
  51.         {
  52.                 FrameInfo info;
  53.                 info.format = GetVideoFormatByAVPixelFormat(m_pixelFormat);
  54.                 info.width = width;
  55.                 info.height = height;
  56.                 info.pts = spFrame->pts / 1000;
  57.                 m_pFrameDataCallBack->cbFrameDataCallBack(m_dstBuffer.data(), m_dstBuffer.size(), info, m_pFrameDataCallBack->pUser);
  58.         }
  59. }
复制代码
工程:https://download.csdn.net/download/weixin_38887743/88748651

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

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王柳

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表