天天看點

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。

Dxgi中關于DXGI_MAPPED_RECT中Pitch與Width差異

圖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.對于不遵守此聲明或者其他違法使用本文内容者,本人依法保留追究權等。