陆其明吧 关注:195贴子:6,655
  • 3回复贴,共1

请教 陆老师 自己写的 TransformFilter 播放正常 Seek 后怪现象

只看楼主收藏回复

由于使用 FFMPEG 解码 所以解码速度应该没有问题
代码 如下 分块了
//-----------------------------------------
// 解码并输出
// 1. 更新解码参数
// 2. FFMPEG 解码 输入流 到 YUV420P 图像帧
// 3. 转换 YUV420P 图像帧 置 指定格式
// 4. 复制 帧时间戳
//-----------------------------------------
HRESULT CVideoFilter::Transform(IMediaSample *pIn, IMediaSample *pOut)
{// 检查 Sample 输入 和 输出
CheckPointer(pIn,E_POINTER);
CheckPointer(pOut,E_POINTER);
// 更新解码数据
update_dec_parameter(pOut);
// 输入数据解码
AVFrame * frame = NULL;
if (Decoder(pIn,frame) == 1) // 解码成功
{
Convert(frame,pOut); // 转换图像格式
av_free(frame);
}
CopyTimeStamp(pIn,pOut);
return S_OK;
}
//-----------------------------------------
// 解码 ( 只 解码 输入 Pin 数据)
// 1. DirectShow 输出 Pin 数据 转换 FFMPEG Packet 数据
// 2. FFMPEG 解码 输入数据
// return -1 失败
// return 1 成功
//-----------------------------------------
int CVideoFilter::Decoder(IMediaSample *pSource, AVFrame *& frame)
{
// 声明解码数据
AVPacket pkt = {0};
// 初始化 解码包
av_init_packet(&pkt);
pkt.size = pSource->GetActualDataLength();
pSource->GetPointer(&(pkt.data));
// 解码原始帧初始化
frame = avcodec_alloc_frame();
// 声明解码返参变量
int bytesDecoded = -1;
int frameFinished = -1;
// 解码
bytesDecoded = avcodec_decode_video2(avcore_codec->pCodecCtx, frame, &frameFinished, &pkt);
if (bytesDecoded > 0) // 解码成功
{
if (frameFinished > 0) // 解码数据 正常
return 1;
}
return -1;
}
//-----------------------------------------
// 转换图像
// 1. 获取 DirectShow 输出图像格式
// 2. 根据 DirectShow 输出图像格式 分情况处理
//-----------------------------------------
int bmp;
HRESULT CVideoFilter::Convert(AVFrame * frame,IMediaSample * pDest)
{
// RGB32
if (m_dshow_pixfmt == VOFMT_RGB32)
{
// 直接分配 Frame 缓存指针 为 Dest 指针
AVFrame * pDest_Frame = NULL;
BYTE * pDestBuffer = NULL;
pDest_Frame = avcodec_alloc_frame();
pDest->GetPointer(&pDestBuffer);
int size = avpicture_get_size(m_pixfmt,m_width,avcore_codec->pCodecCtx->height);
uint8_t * buffer = (uint8_t *)av_malloc(size);
avpicture_fill((AVPicture *)pDest_Frame, (uint8_t*)pDestBuffer, m_pixfmt, m_width, avcore_codec->pCodecCtx->height);
// 转换图像 至 RGB32
int height;
height = sws_scale(m_swsctx,frame->data,frame->linesize,0,frame->height,pDest_Frame->data,pDest_Frame->linesize);
pDest->SetActualDataLength(m_width*height*4);
// avcore_savebyte(pDestBuffer,m_width,frame->height,bmp++,32);
// memcpy(pDestBuffer,pDest_Frame->data[0],m_width * height * 4);
av_free(pDest_Frame);
av_free(buffer);
return S_OK;
}
return S_FALSE;
}


1楼2012-08-26 12:54回复
    //-----------------------------------------
    // 复制 Sample 时间戳
    // 1. 复制 Time
    // 2. 复制 Media Time
    // 3. 设置为同步点
    //-----------------------------------------
    void CVideoFilter::CopyTimeStamp(IMediaSample *pSource, IMediaSample *pDest)
    {
    REFERENCE_TIME TimeStart, TimeEnd;
    HRESULT hr;
    if (NOERROR == pSource->GetTime(&TimeStart, &TimeEnd)) {
    //
    hr = pDest->SetTime(&TimeStart, &TimeEnd);
    }
    LONGLONG MediaStart, MediaEnd;
    if (pSource->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) {
    hr = pDest->SetMediaTime(&MediaStart,&MediaEnd);
    }
    // 设置为同步点
    pDest->SetSyncPoint(TRUE);
    // Copy the preroll property
    pDest->SetPreroll(TRUE);
    // Copy the discontinuity property
    pDest->SetDiscontinuity(TRUE);
    }
    


    2楼2012-08-26 12:54
    回复
      2025-12-05 10:50:56
      广告
      不感兴趣
      开通SVIP免广告
      void update_dec_parameter(IMediaSample *pDest)
      {
      // 取 dest width, dest height
      AM_MEDIA_TYPE *pmt = NULL;
      HRESULT hr = S_OK;
      hr = pDest->GetMediaType(&pmt);
      if(SUCCEEDED(hr) && pmt) // 则说明 宽度 已经被动态改变了
      {
      if(pmt->formattype == FORMAT_VideoInfo)
      {
      VIDEOINFOHEADER* hrOut = (VIDEOINFOHEADER*)pmt->pbFormat;
      m_width = hrOut->bmiHeader.biWidth;
      m_height = hrOut->bmiHeader.biHeight;
      }
      else if(pmt->formattype == FORMAT_VideoInfo2)
      {
      VIDEOINFOHEADER2* hrOut = (VIDEOINFOHEADER2*)pmt->pbFormat;
      m_width = hrOut->bmiHeader.biWidth;
      m_height = hrOut->bmiHeader.biHeight;
      }
      // 说明请求改变 成功 设置 MediaType
      m_mt = *pmt;
      m_mt.majortype = MEDIATYPE_Video;
      m_mt.subtype = MEDIASUBTYPE_RGB32;
      m_mt.formattype = FORMAT_VideoInfo2;
      VIDEOINFOHEADER2 * pvi = (VIDEOINFOHEADER2 *) malloc(sizeof(VIDEOINFOHEADER2));
      pvi->bmiHeader.biCompression = BI_RGB;
      pvi->bmiHeader.biBitCount = 32;
      pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
      pvi->bmiHeader.biWidth = abs(m_width);
      pvi->bmiHeader.biHeight = abs(avcore_codec->CodecCtx.height);
      pvi->bmiHeader.biSizeImage = abs(m_width) * abs(avcore_codec->CodecCtx.height) * 4;
      pvi->bmiHeader.biPlanes = 1;
      pvi->bmiHeader.biClrImportant = 0;
      // 求 最大公约数
      int c_max = avcore_mindiv(abs(m_width),abs(avcore_codec->CodecCtx.height));
      pvi->dwPictAspectRatioX = abs(m_width)/c_max;
      pvi->dwPictAspectRatioY = abs(avcore_codec->CodecCtx.height)/c_max;
      pvi->dwBitRate = 0;
      // pvi->AvgTimePerFrame = avg_frame;
      SetRectEmpty(&(pvi->rcSource));
      SetRectEmpty(&(pvi->rcTarget));
      pvi->rcSource.right = abs(m_width);
      pvi->rcSource.bottom = abs(avcore_codec->CodecCtx.height);
      pvi->rcTarget.right = abs(m_width);
      pvi->rcTarget.bottom = abs(avcore_codec->CodecCtx.height);
      m_mt.pbFormat = (BYTE * )pvi;
      m_mt.cbFormat = sizeof(VIDEOINFOHEADER2);
      m_mt.bFixedSizeSamples = true;
      m_mt.lSampleSize = (ULONG(pvi->bmiHeader.biSizeImage));
      m_mt.bTemporalCompression = false;
      // 更新
      DeleteMediaType(pmt);
      pDest->SetMediaType(&m_mt);
      // out pin MediaType 更新
      m_pOutput->SetMediaType((CMediaType*)(&m_mt));
      // 更新 Sws 上下文 指针
      if (!m_swsctx) sws_freeContext(m_swsctx);
      // 创建 Swsctx
      m_swsctx = sws_getContext(m_width, avcore_codec->pCodecCtx->height,
      avcore_codec->pCodecCtx->pix_fmt,
      m_width, avcore_codec->pCodecCtx->height,
      m_pixfmt,
      SWS_BICUBIC, NULL, NULL, NULL);
      }
      }
      // 初始化解码 参数
      HRESULT init_dec_parameter(CAVCoreCodec * _avcore_codec){
      avcore_codec = _avcore_codec; // 解码器
      if (!avcore_codec) return S_FALSE;
      // 初始化 宽度 高度 为 解码器 宽度高度
      m_width = _avcore_codec->pCodecCtx->width;
      m_height = _avcore_codec->pCodecCtx->height;
      // 设置默认 输出格式
      m_dshow_pixfmt = av_def_video_out_fmt;
      if (m_dshow_pixfmt == VOFMT_RGB32)
      {
      m_pixfmt = PIX_FMT_RGB32;
      }
      return S_OK;
      }


      3楼2012-08-26 12:55
      回复
        原来 H264 是花屏的 最后发现 VR 自动改变 MT ,,, 要做处理
        现在 H264 RM 一切 正常
        但是 SEEK 后 发现 停顿一会 然后立马就跳帧 跳走了 这是怎么回事??? 难道时间戳 不能进行简单 COPY ??? 还是 质量控制??? 陆老师 拜托了


        4楼2012-08-26 12:57
        回复