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,對音視頻有些研究,需要合作交流的,歡迎騷擾!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章