Dxgi中关于DXGI_MAPPED_RECT中Pitch与Width差异

之前在网上查找的关于DXGI的截屏demo中成功实现了利用截屏来生成视频并进行屏幕广播,但是最近使用之前的demo时遇到了一个问题:

==》在一些机器上使用如下代码获取图像数据及其每行数据的像素数:

IDXGISurface *hStagingSurf = NULL;

DXGI_MAPPED_RECT mappedRect;

hr = hStagingSurf->Map(&mappedRect, DXGI_MAP_READ);

可是发现如下问题,在一些机器上获取得到的mappedRect->Pitch/4==width(显示器的宽)而另外一些电脑则获取到的是mappedRect->Pitch/4!=width(显示器的宽),因此如果忽略掉这个这问题的处理的话,往往会可能出现一开始分配的存储数据的缓存大小不够,导致memcpy时出现越界导致段错误的情况。

为避免上面的情况导致段错误的发生,需要对mappedRect->Pitch/4与width是否相等进行分情况处理。

==>mappedRect->Pitch/4==width是直接拷贝数据到缓存中再进行后续编解码处理。

==>mappedRect->Pitch/4!=width(显示器的宽)时需要将正确的数据进行拷贝然后再进行后续的处理。

至于如何进行正确的拷贝呢,就需要知道发生这种情况的原因是什么:

在《Width vs. Pitch (Direct3D 9)》这一篇windows的接口说明的文章中提到了:

Pitch是两个内存地址之间的距离,以字节为单位,表示一个位图行的开始和下一个位图行的开始。因为间距(Pitch)是以字节而不是像素来测量的,所以640x480x8曲面的间距值与具有相同尺寸但像素格式不同的曲面的间距(Pitch)值非常不同。此外,Pitch值有时反映Direct3D保留为缓存的字节,因此假设节距只是宽度乘以每个像素的字节数是不安全的。相反,如下图1.1所示,将宽度(width)和间距(Pitch)之间的差异可视化。在这个图中,前缓冲区和后缓冲区都是640x480x8,缓存是384x480x8。

 

图1.1 width和pitch数据存储结构对比

从上面的说明可以知道,使用map获取得到的DXGI_MAPPED_RECT的图像数据及Pitch值并不是单单我们理解的显示器中的height和width的格式来的,而是会根据显卡和硬件不同它会有时带有一点缓存(字节对齐时伴随的),因此在处理从map获取得到的DXGI_MAPPED_RECT的图像数据分为上述两种情况来处理。

DXGI_MAPPED_RECT mappedRect;
IDXGISurface *hStagingSurf = NULL;
hr = hStagingSurf->Map(&mappedRect, DXGI_MAP_READ);
if (SUCCEEDED(hr))
{
        nImgSize = abs((Coordinates[mode_cap].right - Coordinates[mode_cap].left)*(Coordinates[mode_cap].bottom - Coordinates[mode_cap].top) * 4);
        if ((mappedRect.Pitch / 4) == abs(Coordinates[mode_cap].right - Coordinates[mode_cap].left))
        {
                memcpy((BYTE*)pImgData, mappedRect.pBits, nImgSize);
        }
        else
        {
                int count_tmp = abs(Coordinates[mode_cap].bottom - Coordinates[mode_cap].top);//列数
                int count_tmp2 = abs(Coordinates[mode_cap].right - Coordinates[mode_cap].left);//每一行的像素数
                int diff_tmp = (mappedRect.Pitch / 4 - count_tmp2)*4;//每一行与需要的实际差异
                BYTE *ptr_tmp = mappedRect.pBits;
                for (int i = 0; i < count_tmp; i++)
                {
                        memcpy((BYTE*)pImgData + i*count_tmp2*4, ptr_tmp, count_tmp2*4);
                        ptr_tmp = ptr_tmp + count_tmp2*4 + diff_tmp;
                }
        }
        hStagingSurf->Unmap();
}
else
{
        xhlog("QueryFrame error5: 'hStagingSurf->Map(&mappedRect, DXGI_MAP_READ)'\n");
}

参考链接:https://docs.microsoft.com/zh-cn/windows/win32/direct3d9/width-vs--pitch?redirectedfrom=MSDN

 

每写一篇文章都不容易,尊重别人的知识产权才是对自己和技术的尊重。为了避免发生知识产权被侵权的情况,我决定做出以下声明:

1.博客中标注原创的文章,版权归原作者 吴豪乐工作室 所有;

2.未经原作者允许不得转载本文内容,否则将视为侵权;

3.转载或者引用本文内容请注明来源及原作者;

4.对于不遵守此声明或者其他违法使用本文内容者,本人依法保留追究权等。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值