MediaFoundation + VP8 + Color Formats - c++

My ultimate goal is to add video support to my Virtual Class application. My method is:
Capture frames using Media Foundation
Encode with VP8 using LibVPX
Transmit with UDP
Decode at the receipient site
Show frames in a Window
The first problem arises with my WebCam's supported color encodings. The webcam Media Types contain only MFVideoFormat_NV12. My first debugging attempt saves the receiving image to a bitmap so I can test it is correctly captured (error handling removed):
HRESULT CAP::StartRecord(HWND hh, CComPtr<IMFMediaSource> src)
{
MFCreateSourceReaderFromMediaSource(src, 0, &sr);
CComPtr<IMFMediaType> fmt;
sr->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM,&fmt);
LogMediaType(fmt); // Shows: MFVideoFormat_NV12
auto [wi, he] = WidthHeight(fmt);
for (;;)
{
DWORD streamIndex = 0, flags = 0;
LONGLONG llTimeStamp = 0;
CComPtr<IMFSample> pSample;
hr = sr->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM,0,&streamIndex,&flags,&llTimeStamp,&pSample);
if (FAILED(hr))
break;
if (!pSample)
continue;
CComPtr<IMFMediaBuffer> bu;
pSample->ConvertToContiguousBuffer(&bu);
SaveSampleNV12(bu, wi, he);
}
...
}
SaveSampleNV12 uses code from here to convert NV12 to RGB, then:
void SaveSampleNV12(CComPtr<IMFMediaBuffer> mm, int width32, int height32)
{
DWORD le = 0;
mm->GetCurrentLength(&le);
BYTE *pDatad = NULL;
auto hr = mm->Lock(&pDatad, NULL, NULL);
vector<char> rgb(1000000);
NV12ToRGB((BYTE*)rgb.data(), pDatad, width32, height32);
mm->Unlock();
HANDLE file;
BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER fileInfo;
DWORD write = 0;
auto df = L"r:\\f.bmp";
file = CreateFile(df.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); //Sets up the new bmp to be written to
int bits = 24;
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 = width32;
fileInfo.biHeight = height32;
fileInfo.biPlanes = 1;
fileInfo.biBitCount = bits;
fileInfo.biCompression = BI_RGB;
fileInfo.biSizeImage = width32 * height32 * (bits / 8);
fileInfo.biXPelsPerMeter = 0;// 2400;
fileInfo.biYPelsPerMeter = 0;// 2400;
fileInfo.biClrImportant = 0;
fileInfo.biClrUsed = 0;
WriteFile(file, &fileHeader, sizeof(fileHeader), &write, NULL);
WriteFile(file, &fileInfo, sizeof(fileInfo), &write, NULL);
unsigned char* ptrIn = (unsigned char*)rgb.data();
int rgbs = width32 * height32 * (bits / 8);
vector<char> d2(rgbs);
unsigned char* ptrOut = (unsigned char*)d2.data();
for (int i = 0; i < (width32*height32) / 2; ++i)
{
int y0 = ptrIn[0];
int u0 = ptrIn[1];
int y1 = ptrIn[2];
int v0 = ptrIn[3];
ptrIn += 4;
int c = y0 - 16;
int d = u0 - 128;
int e = v0 - 128;
int bb = clip((298 * c + 516 * d + 128) >> 8); // blue
int gg = clip((298 * c - 100 * d - 208 * e + 128) >> 8); // green
int rr = clip((298 * c + 409 * e + 128) >> 8); // red
ptrOut[0] = bb;
ptrOut[1] = gg;
ptrOut[2] = rr;
c = y1 - 16;
ptrOut[3] = clip((298 * c + 516 * d + 128) >> 8); // blue
ptrOut[4] = clip((298 * c - 100 * d - 208 * e + 128) >> 8); // green
ptrOut[5] = clip((298 * c + 409 * e + 128) >> 8); // red
ptrOut += 6;
}
unsigned char* cc = (unsigned char*)d2.data();
WriteFile(file, cc, rgbs, &write, NULL);
CloseHandle(file);
}
This returns a weird full of Pink image. Something I'm doing wrong, but what?
Thanks a lot.

The solution is to use IMFTransform to tranform between various color spaces.

Related

Capture mouse cursor and apply transparency masking in Win32

Im trying to capture mouse cursor using windows API GetCursorInfo and taking in to CURSORINFO structure after I reading ICONINFO using GetIconInfo so I will get hbmMask and hbmColor bitmap
The hbmMask bitmap is first applied with an AND raster operation, then the hbmColor bitmap is applied with an XOR raster operation. This results in an opaque cursor and a transparent background but this is not happening in my POC complete code in below example.
After doing AND raster on mask data and XOR on color data the final result will be cursor and covered with white colored rectangle 32*32.
void save_as_bitmap(unsigned char *bitmap_data, int rowPitch, int width, int height, char *filename)
{
// A file is created, this is where we will save the screen capture.
FILE *f;
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = width;
//Make the size negative if the image is upside down.
bi.biHeight = -height;
//There is only one plane in RGB color space where as 3 planes in YUV.
bi.biPlanes = 1;
//In windows RGB, 8 bit - depth for each of R, G, B and alpha.
bi.biBitCount = 32;
//We are not compressing the image.
bi.biCompression = BI_RGB;
// The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps.
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
// rowPitch = the size of the row in bytes.
DWORD dwSizeofImage = rowPitch * height;
// Add the size of the headers to the size of the bitmap to get the total file size
DWORD dwSizeofDIB = dwSizeofImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//Offset to where the actual bitmap bits start.
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
//Size of the file
bmfHeader.bfSize = dwSizeofDIB;
//bfType must always be BM for Bitmaps
bmfHeader.bfType = 0x4D42; //BM
// TODO: Handle getting current directory
fopen_s(&f, filename, "wb");
DWORD dwBytesWritten = 0;
dwBytesWritten += fwrite(&bmfHeader, sizeof(BITMAPFILEHEADER), 1, f);
dwBytesWritten += fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, f);
dwBytesWritten += fwrite(bitmap_data, 1, dwSizeofImage, f);
fclose(f);
}
//ST484 : HBIMAPtoBYTE : Convert BITMAP to BYTE array.
std::vector<BYTE> HBIMAPtoBYTE( HBITMAP hBitmap,
int &hBitmapSize,
bool &bResult,
int &nWidth,
int &nHeight )
{
bResult = true;
BITMAP bmp;
if (!GetObject(hBitmap, sizeof(BITMAP), (LPVOID)&bmp))
{
DeleteObject(hBitmap);
bResult = false;
}
int rpcbiPlanes = 32;
BITMAPINFO info;
memset(&info, 0, sizeof(BITMAPINFO));
info.bmiHeader.biSize = sizeof(info.bmiHeader);
info.bmiHeader.biWidth = bmp.bmWidth;
info.bmiHeader.biHeight = -bmp.bmHeight;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = rpcbiPlanes;
info.bmiHeader.biCompression= BI_RGB;
size_t pixelSize = info.bmiHeader.biBitCount / 8;
size_t scanlineSize = (pixelSize * info.bmiHeader.biWidth + 3) & ~3;
size_t bitmapSize = bmp.bmHeight * scanlineSize;
hBitmapSize = bitmapSize;
nWidth = bmp.bmWidth;
nHeight = bmp.bmHeight;
std::vector<BYTE> pixels(bitmapSize);
HDC hdc = ::GetDC(NULL);
if(!GetDIBits(hdc, hBitmap, 0, bmp.bmHeight, &pixels[0], &info, DIB_RGB_COLORS))
{
hBitmapSize = 0;
bResult = false;
}
return pixels;
}
// getHCursor : Capture cursor.
CURSORINFO getHCursor()
{
CURSORINFO cursorInfo;
cursorInfo.cbSize = sizeof(CURSORINFO);
if (GetCursorInfo(&cursorInfo) == 0)
{
MessageBox(NULL, _T("Exception : GetCursorInfo creation failed"),_T("message"),MB_OK|MB_SYSTEMMODAL);
cursorInfo.hCursor = NULL;
return cursorInfo;
}
return cursorInfo;
}
//Main Call
int _tmain(int argc, _TCHAR* argv[])
{
int CountP = 0;
while (true)
{
CURSORINFO CursorInfo = getHCursor();
if (CursorInfo.hCursor == NULL)
{
::Sleep(MinSleep);
continue;
}
ICONINFO iconInfo;
if (!GetIconInfo(CursorInfo.hCursor, &iconInfo))
{
MessageBox(NULL, _T("Exception : GetIconInfo creation failed"),_T("message"),MB_OK|MB_SYSTEMMODAL);
::Sleep(MinSleep);
}
std::vector<BYTE> bColorBitmap;
std::vector<BYTE> bMaskBitmap;
std::vector<BYTE> bDestBitmap;
int sz_hbmColor = 0;
int sz_hbmMask = 0;
int sz_hbDest = 0;
int nWidth = 0;
int nHeight = 0;
bool hbmColor_result = false;
bool hbmMask_result = false;
bool hbmDest_result = false;
int rpcbiPlanes = 32;
bool isColorShape = (iconInfo.hbmColor != NULL);
// read mask and color in to byte vector.
bColorBitmap = HBIMAPtoBYTE(iconInfo.hbmColor,sz_hbmColor,hbmColor_result,nWidth,nHeight);
bMaskBitmap = HBIMAPtoBYTE(iconInfo.hbmMask,sz_hbmMask,hbmMask_result,nWidth,nHeight);
//Create Dummy bitmap using width and height filled with black color.
HBITMAP desBitmap = CreateBitmap(nWidth,nHeight,1,rpcbiPlanes,NULL);
if(desBitmap != NULL)
{
// read dummy bitmap in to byte vector.
bDestBitmap = HBIMAPtoBYTE(desBitmap,sz_hbDest,hbmDest_result,nWidth,nHeight);
}
//the mask bitmap is first applied with an AND raster operation.
for(int i = 0; i < nHeight ; i++)
{
for(int j = 0; j < nWidth; j++)
{
bDestBitmap[i*4*nWidth + j*4 ] &= bMaskBitmap[i*4*nWidth + j*4 ];
bDestBitmap[i*4*nWidth + j*4 + 1] &= bMaskBitmap[i*4*nWidth + j*4 + 1];
bDestBitmap[i*4*nWidth + j*4 + 2] &= bMaskBitmap[i*4*nWidth + j*4 + 2];
bDestBitmap[i*4*nWidth + j*4 + 3] &= bMaskBitmap[i*4*nWidth + j*4 + 3];
}
}
//then the color bitmap is applied with an XOR raster operation.
for(int i = 0; i < nHeight ; i++)
{
for(int j = 0; j < nWidth; j++)
{
bDestBitmap[i*4*nWidth + j*4 ] ^= bColorBitmap[i*4*nWidth + j*4 ];
bDestBitmap[i*4*nWidth + j*4 + 1] ^= bColorBitmap[i*4*nWidth + j*4 + 1];
bDestBitmap[i*4*nWidth + j*4 + 2] ^= bColorBitmap[i*4*nWidth + j*4 + 2];
bDestBitmap[i*4*nWidth + j*4 + 3] ^= bColorBitmap[i*4*nWidth + j*4 + 3];
}
}
//Save Color bitmap.
sprintf_s(file_name,"C:\\Test\\captured\\Cursor_%d.bmp", CountP);
save_as_bitmap(&(bDestBitmap[0]), nWidth*4, nWidth, nHeight, file_name);
CountP++;
Sleep(MaxSleep);
}
return 0;
}
After saving cursor getting image like this
Finally I found excellent result using windows API.
Include comctl32.lib in to your project
HIMAGELIST iCursorList=ImageList_Create(nWidth,nHeight,ILC_COLOR32|ILC_MASK,8,8);
ImageList_AddMasked(iCursorList,iconInfo.hbmColor,000000);
DeleteObject(iconInfo.hbmColor);
TRANSPARENT_HICON = ImageList_GetIcon(iCursorList,0,ILD_TRANSPARENT);
1 ) Create ImageList_Create using width, height, ILC_COLOR32|ILC_MASK
2 ) Add bitmap in to ImageList_AddMasked and apply which color you want to make transparent, 000000 are black color in my code.
3 ) Get transparent icon from ImageList_GetIcon.

Generate Image from generated byte array in UWP vc++

Reference with this Question & answer by #Decade Moon
How can i use that method for generate image from byte array instead of image file.
i tried like below but nothing works. no image are shown
std::vector<char> data= std::vector<char>(imgx->Height * imgx->Width * 4);
int offset;
for (int row = 0; row < imgx->Height; row++)
{
for (int col = 0; col < imgx->Width; col++)
{
offset = (row * (int)(imgx->Width * 4)) + (col * 4);
data[offset] = 0x58; // Red
data[offset + 1] = 0x58; // Green
data[offset + 2] = 0x58; // Blue
data[offset + 3] = 0x58; // Alpha
}
};
My approach is little bit different from the reply you reffered to, but it works pretty well.
#include <wrl.h>
#include <robuffer.h>
using namespace Windows::UI::Xaml::Media::Imaging;
using namespace Windows::Storage::Streams;
using namespace Microsoft::WRL;
typedef uint8 byte;
byte* GetPointerToPixelData(IBuffer^ pixelBuffer, unsigned int *length)
{
if (length != nullptr)
{
*length = pixelBuffer ->Length;
}
// Query the IBufferByteAccess interface.
ComPtr<IBufferByteAccess> bufferByteAccess;
reinterpret_cast<IInspectable*>(pixelBuffer)->QueryInterface(IID_PPV_ARGS(&bufferByteAccess));
// Retrieve the buffer data.
byte* pixels = nullptr;
bufferByteAccess->Buffer(&pixels);
return pixels;
}
MainPage::MainPage()
{
InitializeComponent();
auto bitmap = ref new WriteableBitmap(50, 50);
image->Source = bitmap;
unsigned int length;
byte* sourcePixels = GetPointerToPixelData(bitmap->PixelBuffer, &length);
const unsigned int width = bitmap->PixelWidth;
const unsigned int height = bitmap->PixelHeight;
create_async([this, width, height, sourcePixels] {
byte* temp = sourcePixels;
// generate RED - BLUE gradient
for(unsigned int k = 0; k < height; k++) {
for (unsigned int i = 0; i < (width * 4); i += 4) {
int pos = k * (width * 4) + (i);
temp[pos] = (byte)(0xFF * k / (float)height); // B
temp[pos + 1] = 0x0; // G
temp[pos + 2] = 0xFF - (byte)(0xFF * k / (float)height); // R
temp[pos + 3] = 0xFF; // A
}
}
});
}

GDIPlus::Bitmap Brightening Image c++

The aim of the following function is to get the R,G,B values of each pixel from a Bitmap loaded from file and increase them by 10.
void PerformTransformation(Gdiplus::Bitmap* bitmap, LPCTSTR SaveFileName) {
Gdiplus::BitmapData* bitmapData = new Gdiplus::BitmapData;
UINT Width = bitmap->GetWidth();
UINT Height = bitmap->GetHeight();
Gdiplus::Rect rect(0, 0,Width,Height );
bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead, PixelFormat32bppARGB, bitmapData);
byte* pixels = (byte*)bitmapData->Scan0;
INT iStride = abs(bitmapData->Stride);
for (UINT col = 0; col < Width; ++col)
for (UINT row = 0; row < Height; ++row)
{
unsigned int curColor = pixels[row * iStride / 4 + col];
int b = curColor & 0xff;
int g = (curColor & 0xff00) >> 8;
int r = (curColor & 0xff0000) >> 16;
if ((r + 10) > 255) r = 255; else r += 10;
if ((g + 10) > 255) g = 255; else g += 10;
if ((b + 10) > 255) b = 255; else b += 10;
pixels[curColor & 0xff ] = b;
pixels[curColor & 0xff00 >> 8] = g;
pixels[curColor & 0xff0000 >> 16] = r;
}
bitmap->UnlockBits(bitmapData);
CLSID pngClsid;
GetEncoderClsid(L"image/png", &pngClsid);
bitmap->Save(SaveFileName, &pngClsid, NULL);
}
However when checking the save file, the brightness has not increased. I have tried to increase the values to update each R,G,B value to be 100 each but the image remains the same, Seems like i'm not setting the new values correctly.
Can anyone show me what im doing wrong?
EDIT:
After following some guidance i now have the image brightening but only brightening a quarter of the image.
Changed Code
void PerformTransformation(Gdiplus::Bitmap* bitmap, LPCTSTR SaveFileName) {
Gdiplus::BitmapData* bitmapData = new Gdiplus::BitmapData;
UINT Width = bitmap->GetWidth();
UINT Height = bitmap->GetHeight();
Gdiplus::Rect rect(0, 0,Width,Height );
// Lock a 5x3 rectangular portion of the bitmap for reading.
bitmap->LockBits(&rect, Gdiplus::ImageLockModeWrite,
PixelFormat32bppARGB, bitmapData);
byte* Pixels = (byte*)bitmapData->Scan0;
INT stride_bytes_count = abs(bitmapData->Stride);
UINT row_index, col_index;
byte pixel[4];
for (col_index = 0; col_index < Width; ++col_index) {
for (row_index = 0; row_index < Height; ++row_index)
{
unsigned int curColor = Pixels[row_index * stride_bytes_count /
4 + col_index];
int b = curColor & 0xff;
int g = (curColor & 0xff00) >> 8;
int r = (curColor & 0xff0000) >> 16;
if ((r + 10) > 255) r = 255; else r += 10;
if ((g + 10) > 255) g = 255; else g += 10;
if ((b + 10) > 255) b = 255; else b += 10;
pixel[0] = b;
pixel[1] = g;
pixel[2] = r;
Pixels[row_index * stride_bytes_count / 4 + col_index] = *pixel;
}
}
bitmap->UnlockBits(bitmapData);
::DeleteObject(bitmapData);
CLSID pngClsid;
GetEncoderClsid(L"image/png", &pngClsid);
bitmap->Save(SaveFileName, &pngClsid, NULL);
}
};
You never check return codes.
You access bitmap data in reading mode (Gdiplus::ImageLockModeRead)
You are indexing pixel channel values by color value pixels[curColor & 0xff]
You never delete allocated bitmapData object

LibQREncode qrcode to BMP

I'm creating a qrcode with the library qrencode.h
This creation is working nice but how would one output the qrcode to a BMP file within c++?
At this very moment i have this code:
const char* szSourceSring = QRCODE_TEXT;
unsigned int unWidth, x, y, l, n, unWidthAdjusted, unDataBytes;
unsigned char* pRGBData, *pSourceData, *pDestData;
QRcode* pQRC;
FILE* f;
if (pQRC = QRcode_encodeString(szSourceSring, 4, QR_ECLEVEL_H, QR_MODE_8, 1))
{
unWidth = pQRC->width;
unWidthAdjusted = unWidth * OUT_FILE_PIXEL_PRESCALER * 3;
if (unWidthAdjusted % 4)
unWidthAdjusted = (unWidthAdjusted / 4 + 1) * 4;
unDataBytes = unWidthAdjusted * unWidth * OUT_FILE_PIXEL_PRESCALER;
// Allocate pixels buffer
if (!(pRGBData = (unsigned char*)malloc(unDataBytes)))
{
printf("Out of memory");
}
// Preset to white
memset(pRGBData, 0xff, unDataBytes);
// Prepare bmp headers
BITMAPFILEHEADER kFileHeader;
kFileHeader.bfType = 0x4D42; // "BM"
kFileHeader.bfSize = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) +
unDataBytes;
kFileHeader.bfReserved1 = 0;
kFileHeader.bfReserved2 = 0;
kFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER);
BITMAPINFOHEADER kInfoHeader;
kInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
kInfoHeader.biWidth = unWidth * OUT_FILE_PIXEL_PRESCALER;
kInfoHeader.biHeight = -((int)unWidth * OUT_FILE_PIXEL_PRESCALER);
kInfoHeader.biPlanes = 1;
kInfoHeader.biBitCount = 24;
kInfoHeader.biCompression = BI_RGB;
kInfoHeader.biSizeImage = 0;
kInfoHeader.biXPelsPerMeter = 0;
kInfoHeader.biYPelsPerMeter = 0;
kInfoHeader.biClrUsed = 0;
kInfoHeader.biClrImportant = 0;
// Convert QrCode bits to bmp pixels
pSourceData = pQRC->data;
for(y = 0; y < unWidth; y++)
{
pDestData = pRGBData + unWidthAdjusted * y * OUT_FILE_PIXEL_PRESCALER;
for(x = 0; x < unWidth; x++)
{
if (*pSourceData & 1)
{
for(l = 0; l < OUT_FILE_PIXEL_PRESCALER; l++)
{
for(n = 0; n < OUT_FILE_PIXEL_PRESCALER; n++)
{
*(pDestData + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_B;
*(pDestData + 1 + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_G;
*(pDestData + 2 + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_R;
}
}
}
pDestData += 3 * OUT_FILE_PIXEL_PRESCALER;
pSourceData++;
}
}
// Output the bmp file
/*if (((f = fopen(OUT_FILE, "r")) != NULL))
{*/
f = fopen(OUT_FILE, "wb");
fwrite(&kFileHeader, sizeof(BITMAPFILEHEADER), 14, f);
fwrite(&kInfoHeader, sizeof(BITMAPINFOHEADER), 40, f);
fwrite(pRGBData, sizeof(unsigned char), unDataBytes, f);
fclose(f);
/* }
else
{
printf("Unable to open file");
}
*/
// Free data
free(pRGBData);
QRcode_free(pQRC);
}
else
{
printf("NULL returned");
}
But somehow this creates a BMP with corrupt headers. Whenever i'm opening the bmp file it says:
"BMP Image has unsupported header size"
What am i doing wrong?
And is it possible to save to png instead of BMP?
I have access to the libPNG library
Here is a code example which dumps a 24 bpp bmp file created from a QR-Code. The error you see is probably not caused by the QR-Code library, but rather something in the bmp file code.
The bmp file created by this example works fine with the image viewer packaged with my Windows 8.1. If you also do not see the error, you could check for differences in each binary output to pinpoint the problem. If you want.
This question is tagged "C++" and "C++11", so this example uses the C++ std library for file output, and doesn't use malloc. (But almost equally bad -- I use new and delete in some container code, where a std::vector member is preferred...don't tell anyone). Also, this example writes each piece of data directly to the file, instead of using a file-sized intermediate buffer, like pDestData.
#include <iostream>
#include <fstream>
// A fake (or "somewhat limited") QR Code data container
struct Qrc {
int dimsize; // the width and height
unsigned char* data; // buffer which contains the elements
Qrc() {
static const unsigned int bin[] = { // encodes an important secret message
0xfc8b7d7f,0xa801a83,0xd6e54d76,0xaa9eb2ed,0x43ed05db,0xb8786837,0x55555fe0,
0x5a4c807f,0xcf315c00,0x6e8019ce,0xc7819e0d,0xd4857ba8,0x4ac5e347,0xf6f349ba,
0xd433ccdd,0x2998361e,0x4453fab3,0x526d9085,0x81f38924,0xb4da0811,0x84b3131a,
0x9639915e,0x3b74a4ff,0x42aa0c11,0x4127be16,0x1f4350,0xff620296,0xad54de1,
0xd38c2272,0xa3f76155,0x5366a7ab,0x9bdd2257,0x300d5520,0x85842e7f,0 };
dimsize = 33;
data = new unsigned char[dimsize * dimsize];
auto p = data;
auto endp = p + dimsize * dimsize;
for(unsigned int b : bin) {
for(int i=0; i<32; ++i) {
if(p == endp) break;
*(p++) = b & (1 << i) ? 255 : 0;
} } }
Qrc(const Qrc&) = delete;
Qrc& operator = (const Qrc&) = delete;
~Qrc() { delete [] data; }
};
struct BIH { // a private definition of BITMAPINFOHEADER
unsigned int sz;
int width, height;
unsigned short planes;
short bits;
unsigned int compress, szimage;
int xppm, yppm;
unsigned int clrused, clrimp;
};
void SaveBmp(const char* filename, const Qrc& qrc) {
// Asker's Qrc struct delivered as a pointer, from a C API, but this example doesn't mimic that.
std::ofstream ofs(filename, std::ios_base::out | std::ios_base::binary);
if(!ofs) {
std::cout << "Writing " << filename << " failed\n";
return;
}
const int side_len = qrc.dimsize; // width and height of the (square) QR Code
const int pixel_side_len = 4; // QRC element's size in the bmp image (in pixels)
const int bmp_line_bytes = side_len * pixel_side_len * 3;
const int bmp_line_pad_bytes = (4 - bmp_line_bytes % 4) % 4; // bmp line data padding size
const int bmp_data_size = side_len * (bmp_line_bytes + bmp_line_pad_bytes);
BIH bih = { sizeof(bih) };
bih.width = side_len * pixel_side_len; // element count * element size
bih.height = -side_len * pixel_side_len; // negative height => data begins at top of image
bih.planes = 1;
bih.bits = 24;
const int header_size = sizeof(bih) + 14; // size of the bmp file header
const int filesize = header_size + bmp_data_size; // size of the whole file
ofs.write("BM", 2);
ofs.write(reinterpret_cast<const char*>(&filesize), 4);
ofs.write("\0\0\0\0", 4); // 2x 16-bit reserved fields
ofs.write(reinterpret_cast<const char*>(&header_size), 4);
ofs.write(reinterpret_cast<const char*>(&bih), sizeof(bih));
// pixel colors, as Blue, Green, Red char-valued triples
// the terminating null also makes these usable as 32bpp BGRA values, with Alpha always 0.
static const char fg_color[] = "\0\0\0";
static const char bg_color[] = "\xff\xff\xff";
auto pd = qrc.data;
// send pixel data directly to the bmp file
// QRC elements are expanded into squares
// whose sides are "pixel_side_len" in length.
for(int y=0; y<side_len; ++y) {
for(int j=0; j<pixel_side_len; ++j) {
auto pdj = pd;
for(int x=0; x<side_len; ++x) {
for(int i=0; i<pixel_side_len; ++i) {
// *pdj will be 0 or 255 (from "fake" Qrc)
// Using "*pdj & 1" here, just to match asker's code
// without knowing why this was done.
ofs.write(*pdj & 1 ? fg_color : bg_color, 3);
}
++pdj;
}
if(bmp_line_pad_bytes) {
ofs.write("\0\0\0", bmp_line_pad_bytes);
}
}
pd += side_len;
}
}
int main() {
SaveBmp("MyQrCode.bmp", Qrc());
}

How to get one picture from YUV frame in C++

In C++ i have an
LPBYTE pYUV;
It's contains a YUV data. I used this code to save it to an image file named Original.bmp
BITMAPINFOHEADER* bi = new BITMAPINFOHEADER;
bi->biSize = sizeof(BITMAPINFOHEADER);
bi->biWidth = pVSI->nWidth;
bi->biHeight = pVSI->nHeight;
bi->biPlanes = 1;
bi->biBitCount = 24;
bi->biCompression = 0;
bi->biSizeImage = 0;
bi->biXPelsPerMeter = 2835;
bi->biYPelsPerMeter = 2835;
bi->biClrUsed = 0;
bi->biClrImportant = 0;
BITMAPINFO* bmi = (BITMAPINFO*)bi;
HDC dc = ::GetDC(NULL);
HBITMAP bmp = CreateDIBitmap(dc, bi, CBM_INIT, pYUV, bmi, DIB_RGB_COLORS);
::ReleaseDC(NULL, dc);
CBitmapEx bitmap;
bitmap.Load(bmp);
bitmap.Save(_T("Original.bmp"));
When i open the Original.bmp, it's look like this
It's have too many same picture in the image.How do i process the LPBYTE pYUV to make one picture in the Original.bmp file ?
ps: I can do this by draw it to DirectX by this code.
But i don't know how to write it to image file
LPBYTE apDst[3] = { 0 };
apDst[0] = (LPBYTE)pSurface; // Y
apDst[1] = (LPBYTE)pSurface + nPitch*nH; // U
apDst[2] = (LPBYTE)pSurface + nPitch*nH * 5 / 4; //V
LPBYTE apSrc[3] = { 0 };
apSrc[0] = pYUV; // Y
apSrc[1] = pYUV + nW*nH * 5 / 4; // V
apSrc[2] = pYUV + nW*nH; // U
int anPch[3] = { 0 };
anPch[0] = nW; // Y
anPch[1] = nW / 2; // V
anPch[2] = nW / 2; // U
LPBYTE pDst, pSrc;
int i, k;
int w, h, p;
int div[3] = { 1, 2, 2 };
for (k = 0; k < 3; k++)
{
pSrc = apSrc[k];
pDst = apDst[k];
w = nW / div[k]; // w means the width of one row
h = nH / div[k]; // h means the rows
p = nPitch / div[k];
for (i = 0; i < h; i++)
{
memcpy(pDst, pSrc, w);
pDst += p;
pSrc += anPch[k];
}
}
and It work like this
Thanks in advance.