I am trying to retrieve a thumbnail from a video using c++. I have been using the code from Microsoft, the code, grabs a frame and then displays it on the screen without saving it in the filesystem. I am trying to save the BYTE* to a suitable image format but failing at it.
My issue is that when I try to save the IMFSample to the filesystem I am getting a weird issue. This the expected output and this is the output I am getting when saving the file.
This is the code I am using to save the IMFsample to bitmap using c++, I got this from here
`
void test(IMFSample* pSample, FormatInfo format)
{
HANDLE file;
BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER fileInfo;
DWORD write = 0;
file = CreateFile(LR"(C:\Users\soham.mittal\Desktop\Thumbnails\vids\sample.bmp)", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); //Sets up the new bmp to be written to
fileHeader.bfType = 19778; //Sets our type to BM or bmp
fileHeader.bfSize = sizeof(fileHeader.bfOffBits) + sizeof(RGBTRIPLE); //Sets the size equal to the size of the header struct
fileHeader.bfReserved1 = 0; //sets the reserves to 0
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); //Sets offbits equal to the size of file and info header
fileInfo.biSize = sizeof(BITMAPINFOHEADER);
fileInfo.biWidth = format.imageWidthPels;
fileInfo.biHeight = format.imageHeightPels;
fileInfo.biPlanes = 1;
fileInfo.biBitCount = 24;
fileInfo.biCompression = BI_RGB;
fileInfo.biSizeImage = format.imageWidthPels * format.imageHeightPels * (24 / 8);
fileInfo.biXPelsPerMeter = 2400;
fileInfo.biYPelsPerMeter = 2400;
fileInfo.biClrImportant = 0;
fileInfo.biClrUsed = 0;
WriteFile(file, &fileHeader, sizeof(fileHeader), &write, NULL);
WriteFile(file, &fileInfo, sizeof(fileInfo), &write, NULL);
IMFMediaBuffer* mediaBuffer = NULL;
BYTE* pData = NULL;
pSample->ConvertToContiguousBuffer(&mediaBuffer);
auto hr = mediaBuffer->Lock(&pData, NULL, NULL);
WriteFile(file, pData, fileInfo.biSizeImage, &write, NULL);
CloseHandle(file);
mediaBuffer->Unlock();
}
`
I have tried reading documentation about it and googling this issue but to no avail. I am still stuck with this distorted image. Please help me identify any bugs in the code or point me in the right direction. Thank you :)
The output images are no longer available; however, this bitmap output code has several issues that need fixing:
The calculation of the file size,
fileHeader.bfSize = sizeof(fileHeader.bfOffBits) + sizeof(RGBTRIPLE);, is completely wrong. It should befileHeader.bfSize = fileHeader.bfOffBits + fileInfo.biSizeImagefor a 24-bpp image, and is best calculated after you've initializedfileInfo. If using other bit-depths, account for the palette entries usingsizeof(RGBQUAD); only usesizeof(RGBTRIPLE)if you're usingBITMAPCOREHEADER.The calculation of
fileInfo.biSizeImagehas to take DWORD padding of scan lines into account. A nice shortcut for doing this is to calculate the number of bits in a scanline, add 31, shift right 5 bits, then shift left 2 bits:fileInfo.biSizeImage = ((((abs(fileInfo.biWidth)*fileInfo.biBitCount)+31)>>5)<<2) * abs(fileInfo.biHeight);(theabs()is there because the height is set negative for a top-down bitmap, which I suspect is what you want).Now that I've mentioned it, use negative height to create a top-down bitmap
fileInfo.biHeight = 0 - (LONG)(format.imageHeightPels).If setting the physical dimensions, it is best to set them to 96 ppi unless there's a good reason for doing otherwise
bih.biXPelsPerMeter = (((96*10000)+127)/254);Unless you are sure that the source buffer is padded the same way your destination bitmap is padded (DWORD aligned scanlines), you want to copy the data scanline by scanline. So the code
WriteFile(file, pData, fileInfo.biSizeImage, &write, NULL);might be wrong, and you'll need to replace that with a loop that accounts for the pitch of each buffer.