dxva2+ffmpeg硬件解码(Windows)重要笔记3,


参考了csdn上Win32Project1_ffmpeg_dxva2这个例子,很不错,直接就可以运行。

但是,有几个问题:

1、窗口无法正常缩放,缩放后,图像大小并没有一起缩放

2、H265的编码格式,显示下面有一块绿色。

3、无法从显卡获取YUV420P数据或者NV12数据

3、找了很久网上也没有相关代码实现从显卡获取数据到内存(有些方法相当慢,基本无法使用!)

 

第3个问题,万能的网络变得不再万能,基本都是无解,要么实现不了,要么速度慢:

这个相当于是从显存直接复制到内存,如果速度慢了,就失去意义了,因为硬件解码的目的就是减少CPU占用和提升解码实时性。

其实,ffmpeg就自带了一个函数的,这个函数速度还是比较快的,对了,就是这个函数

 av_image_copy_uc_from

只是大家都不会用而已,直接贴代码:

static int Extract(AVCodecContext *va, AVFrame *src, AVFrame *dst,CCacheBuffer *cache )
{
    BYTE *pNV12=new BYTE[va->width*va->height*4];
    int width;
    int height;
    int pitch;
    int format;
    int surfaceDesc_Height;
    void *pSourceFrame;
    D3DLOCKED_RECT lock;

    DWORD dwTime1=::GetTickCount();    
    LPDIRECT3DSURFACE9 d3d = (LPDIRECT3DSURFACE9)(uintptr_t)src->data[3];
    D3DSURFACE_DESC    surfaceDesc;
    IDirect3DSurface9_GetDesc(d3d, &surfaceDesc);
    if (!dst->data[0])
    {
        delete []pNV12;
        return -1;
    }
    width=surfaceDesc.Width;
    height=surfaceDesc.Height;
    format=surfaceDesc.Format;
    if ( format == MAKEFOURCC('N', 'V', '1', '2') )
    {
       height = 3 * height / 2;    // FULL Y, SUBSAMPLED UV PLANES
    }


    dwTime1=::GetTickCount();    

   
    if (FAILED(IDirect3DSurface9_LockRect(d3d, &lock, NULL, D3DLOCK_READONLY)))
    {
        delete []pNV12;
        return -1;
    }    
    pSourceFrame = lock.pBits;
    pitch = lock.Pitch;
    surfaceDesc_Height=surfaceDesc.Height;

    uint8_t *plane[2] = {
       ( uint8_t *) lock.pBits,
        (uint8_t*)lock.pBits + lock.Pitch * surfaceDesc.Height
    };
    const uint8_t *source[4]={( uint8_t *)lock.pBits,( uint8_t *)lock.pBits + lock.Pitch * surfaceDesc.Height,0,0};
    int linesize_source[4]={lock.Pitch,lock.Pitch,0,0};

    uint8_t *dest[4]={( uint8_t *)pNV12,( uint8_t *)pNV12+lock.Pitch * surfaceDesc.Height,0,0};
    int linesize_dest[4]={lock.Pitch,lock.Pitch,0,0};
    av_image_copy_uc_from(dest,linesize_dest,source,linesize_source,AV_PIX_FMT_NV12,va->width,va->height)

    IDirect3DSurface9_UnlockRect(d3d);
    libyuv::NV12ToI420(pNV12,pitch,pNV12+pitch*surfaceDesc_Height,pitch,dst->data[0],va->width,dst->data[1],va->width/2,dst->data[2],va->width/2,va->width,va->height);
    //TRACE("时间:%d\n",::GetTickCount()-dwTime1);
    delete []pNV12;

    return 0;
}
实验了下,已经相当快了!打开一个4K视频,一帧花的时间平均不到30ms。1080P或者更低分辨率肯定是更没问题的。

好了,谢谢大家!本人QQ35744025,对音视频有些研究,需要合作交流的,欢迎骚扰!

 

相关内容

    暂无相关文章