解决windows 7下ffmpeg dxva2硬解码速度过慢

针对视频解码过程中视频帧拷贝效率低的问题,通过分析QtAV的copytoFrame()函数和FFMPEG的av_image_copy_uc_from函数,实现了显著提高视频帧从GPU到内存的拷贝速度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于项目要兼顾Win 7和Win 10,故将硬解的代码放到Win 7上跑了一下,居然发现视频一直在同步音频,且视频播放卡顿。查到最后发现是由于 av_image_copy_plane()函数执行时间过久,在我的i7-6700K上,拷贝一帧需要50+ms,这是不能接受的。


想到qtav有一个优化拷贝的选项,故将其代码download下看了看,copytoFrame()函数原型如下:

void	CopyFrame( void * pSrc, void * pDest, void * pCacheBlock,
                    UINT width, UINT height, UINT pitch )
{
    __m128i		x0, x1, x2, x3;
    __m128i		*pLoad;
    __m128i		*pStore;
    __m128i		*pCache;
    UINT		x, y, yLoad, yStore;
    UINT		rowsPerBlock;
    UINT		width64;
    UINT		extraPitch;
 
 
    rowsPerBlock = CACHED_BUFFER_SIZE / pitch;
    width64 = (width + 63) & ~0x03f;
    extraPitch = (pitch - width64) / 16;
 
    pLoad  = (__m128i *)pSrc;
    pStore = (__m128i *)pDest;
 
    //  COPY THROUGH 4KB CACHED BUFFER
    for( y = 0; y < height; y += rowsPerBlock)
    {
        //  ROWS LEFT TO COPY AT END
        if( y + rowsPerBlock > height )
            rowsPerBlock = height - y;
 
        pCache = (__m128i *)pCacheBlock;
 
        _mm_mfence();
 
        // LOAD ROWS OF PITCH WIDTH INTO CACHED BLOCK
        for( yLoad = 0; yLoad < rowsPerBlock; yLoad++ )
        {
            // COPY A ROW, CACHE LINE AT A TIME
            for( x = 0; x < pitch; x +=64 )
            {
                x0 = _mm_stream_load_si128( pLoad +0 );
                x1 = _mm_stream_load_si128( pLoad +1 );
                x2 = _mm_stream_load_si128( pLoad +2 );
                x3 = _mm_stream_load_si128( pLoad +3 );
 
                _mm_store_si128( pCache +0,	x0 );
                _mm_store_si128( pCache +1, x1 );
                _mm_store_si128( pCache +2, x2 );
                _mm_store_si128( pCache +3, x3 );
 
                pCache += 4;
                pLoad += 4;
            }
        }
 
        _mm_mfence();
 
        pCache = (__m128i *)pCacheBlock;
 
        // STORE ROWS OF FRAME WIDTH FROM CACHED BLOCK
        for( yStore = 0; yStore < rowsPerBlock; yStore++ )
        {
            // copy a row, cache line at a time
            for( x = 0; x < width64; x +=64 )
            {
                x0 = _mm_load_si128( pCache );
                x1 = _mm_load_si128( pCache +1 );
                x2 = _mm_load_si128( pCache +2 );
                x3 = _mm_load_si128( pCache +3 );
 
                _mm_stream_si128( pStore,	x0 );
                _mm_stream_si128( pStore +1, x1 );
                _mm_stream_si128( pStore +2, x2 );
                _mm_stream_si128( pStore +3, x3 );
 
                pCache += 4;
                pStore += 4;
            }
 
            pCache += extraPitch;
            pStore += extraPitch;
        }
    }
}

源自:https://software.intel.com/en-us/articles/copying-accelerated-video-decode-frame-buffers

QtAV的源代码里也是采用的此方法来做的拷贝优化。

由于目前项目中的限制,无法实现ZeroMemcpy,且在查找资料的过程中,偶然发现了新版本的ffmpeg里有一个从GPU拷贝数据的方法,函数原型为:

void av_image_copy_uc_from(uint8_t *  dst_data[4],
  const ptrdiff_t  dst_linesizes[4],
  const uint8_t *  src_data[4],
  const ptrdiff_t  src_linesizes[4],
  enum AVPixelFormat  pix_fmt,
  int  width,
  int  height 
 )  

Copy image data located in uncacheable (e.g.

GPU mapped) memory. Where available, this function will use special functionality for reading from such memory, which may result in greatly improved performance compared to plain av_image_copy().

The data pointers and the linesizes must be aligned to the maximum required by the CPU architecture.

Note
The linesize parameters have the type ptrdiff_t here, while they are int for  av_image_copy().
On x86, the linesizes currently need to be aligned to the cacheline size (i.e. 64) to get improved performance.

感兴趣的可以去FFMPEG文档里查询详细的代码,在这里我就不赘述了。

使用此函数后,copy效率大大提高,经过性能测试,该函数性能高于copyFrame(),故放弃使用copyFrame()函数,且使用copyFrame需要将拷贝过来的数据先放到一个buf[]中,再重新拷贝到AVFrame对象中存储,二次拷贝实在无法接受。(如果大家有好的建议,可以私信我)

关于copyFrame的算法,之后我会详细写一篇博文来叙述。

FFmpeg是一种开源的多媒体处理工具,其中包含了dxva2硬解码功能。DXVA2是DirectX Video Acceleration 2的缩写,它是一种能够充分利用显卡硬件加速的视频解码技术。 使用FFmpeg进行dxva2硬解码时,可以获得以下几个优势: 1. 提高解码效率:dxva2硬解码能够使用显卡的硬件加速能力,从而大大提高视频解码的效率。相较于软解码,在相同的硬件条件下,dxva2硬解码可以更快地完成对视频的解码工作。 2. 减轻CPU负担:由于dxva2硬解码利用显卡进行解码,可以减轻CPU的负担,从而为其他任务提供更多的计算资源。这对于同时进行多任务处理的用户来说,尤其是一些对计算性能要求较高的场景,是非常有益的。 3. 优化视频播放体验:dxva2硬解码可以提供更平滑和流畅的视频播放体验。它能够更好地处理高分辨率、高比特率的视频文件,避免视频卡顿或者出现掉帧的情况。 然而,dxva2硬解码也存在一些限制和要求: 1. 硬件支持要求:要使用dxva2硬解码功能,需要具备支持DXVA2的显卡硬件。不同显卡型号和厂商支持的dxva2版本可能会有所不同,所以在使用前需要确认自己的显卡是否支持dxva2硬解码2. FFmpeg版本要求:为了能够使用dxva2硬解码功能,需要使用支持dxva2FFmpeg版本。更新的FFmpeg版本通常会修复一些bug并加入新的功能,所以建议使用最新版本的FFmpeg。 总结来说,通过FFmpegdxva2硬解码功能,我们可以提高解码效率、减轻CPU负担,并获得更好的视频播放体验。需要注意的是,确保硬件和软件环境支持dxva2硬解码,并及时更新FFmpeg版本可以保证最佳的使用效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值