Записать данные изображения BITMAPINFOHEADER в IDirect3DTexture9 - PullRequest
1 голос
/ 23 июня 2011

Я пишу рендерер DX9 и в настоящее время работаю над возможностью воспроизведения файлов фильмов AVI.Я смог извлечь любой указанный кадр, используя AVIStreamGetFrame(), который возвращает упакованный DIB, и оттуда я хочу иметь возможность скопировать эти растровые данные в уже существующий IDirect3DTexture9 *.

Моя проблемаНедостаточное понимание формата файла растрового изображения и знание того, как преобразовать данные пикселей, передаваемые из BITMAPINFOHEADER, в формат, который может интерпретировать IDirect3DTexture9.

Сначала я создаю свою текстуру DX9 следующим образом:

LPBITMAPINFO bmpInfo = m_pVideoData->GetVideoFormat();
D3DXCreateTexture(LtGEngine::GetInstance()->GetDevice(), 
                  bmpInfo->bmiHeader.biWidth, 
                  bmpInfo->bmiHeader.biHeight, 
                  D3DX_DEFAULT, 
                  0, 
                  D3DFMT_A8R8G8B8,   // <- DETERMINE HOW?
                  D3DPOOL_MANAGED,   // <- OR D3DPOOL_SYSTEMMEM? 
                  &m_pD3DTexture);

Вопросы, которые у меня есть, перечислены в комментариях выше.Когда я получаю BITMAPINFO и, например, он читает bmpInfo.bmiHeader.biBitCount = 8 (или 16 и т. Д.), Означает ли это, что мне нужно соответственно изменить D3DFMT_ *?

Позже, когда я получу LPBITMAPINFOHEADER для кадра, который я хочу визуализировать, я теряюсь в том, что делать с pBits, возвращенным из функции IDirect3DTexture9::LockRect().Вот что у меня есть:

// Retrieve a frame from the video data as a BITMAPINFOHEADER
LPBITMAPINFOHEADER pBmpInfoHeader;
m_pVideoData->GetVideoFrame(0, 0, &pBmpInfoHeader);

D3DLOCKED_RECT rect;
if(FAILED(m_pD3DTexture->LockRect(0, &rect, NULL, 0)))
{
    m_pD3DTexture->UnlockRect(0);
}
DWORD* pDest = (DWORD*)rect.pBits;
// Now what to copy from pBmpInfoHeader?

Есть ли какие-либо вызовы API, которые делают это для меня, чего я не видел?Или кто-нибудь знает более легкий путь, чем этот?Спасибо за чтение / помощь.

1 Ответ

1 голос
/ 24 июня 2011

Работай!

Пара замечаний для рассмотрения.Мой AVI-файл (в данном случае один кадр / растровое изображение) был в 16-битном формате, поэтому мне пришлось создать целевую текстуру с помощью D3DFMT_X1R5G5B5.Кроме того, растровые изображения хранятся в перевернутом виде, поэтому мне пришлось поменять указатель и прочитать каждую строку в обратном направлении.

Вот код:

// Retrieve a frame from the video data as a BITMAPINFOHEADER
LPBITMAPINFOHEADER pBmpInfoHeader;
m_pVideoData->GetVideoFrame(0, 0, &pBmpInfoHeader);

// Get dimentions
long nWidth = pBmpInfoHeader->biWidth;
long nHeight = pBmpInfoHeader->biHeight;

// Bitmap width correction (might not be needed...)
if (nWidth % 4 != 0)
    nWidth = nWidth + (4 - nWidth%4);

// Get Pixel data (should be after the header in memory)
WORD bitCount = pBmpInfoHeader->biBitCount;
DWORD size = nWidth * nHeight * bitCount/8;
BYTE *pPixelSrc = (BYTE *)pBmpInfoHeader + sizeof(pBmpInfoHeader);

// Lock the texture so we can write this frame's texel data
D3DLOCKED_RECT lock;
if(FAILED(m_pD3DTexture->LockRect(0, &lock, NULL, 0)))
{
    m_pD3DTexture->UnlockRect(0);
    return;
}

int iNumBytesPerRowSrc = pBmpInfoHeader->biWidth * (pBmpInfoHeader->biBitCount/8);  
int iNumBytesPerRowDst = lock.Pitch;
int iNumBytesToCopyPerRow = min(iNumBytesPerRowSrc, iNumBytesPerRowDst);

// Bitmap data is stored upside down
// Start at the end and work backwards
pPixelSrc += (iNumBytesPerRowSrc * nHeight);

// Store a pointer to the texture pixel data and write new data
BYTE* ucTexDst = (BYTE *)lock.pBits;
for(int y = 0; y < nHeight; ++y)
{
    pPixelSrc -= iNumBytesPerRowSrc;
    memcpy(ucTexDst, pPixelSrc, iNumBytesToCopyPerRow);
    ucTexDst += iNumBytesPerRowDst;
}

// Unlock texture so gfx card can resume its business
m_pD3DTexture->UnlockRect(0);
...