BufferOverflow error while capturing using BitBlt and encoding through GDI+ - winapi

Windows GDI ImageCapturing application consumes more GDI objects(Around 320 TaskManager) Single Monitor and Encoding using GDI+ image returns User/ Kernal Marshalling Buffer has been overflowed ​ERROR_MARSHALL_OVERFLOW Marshalling Buffer Error
CImage* getCImageFromBuffer(uint8_t *rgbaBuffer, int imgWidth, int imgHeight, int imgBpp)
{
CImage* image = NULL;
try
{
if (rgbaBuffer != NULL)
{
image = new CImage();
image->Create(imgWidth, imgHeight, imgBpp);
BITMAPINFO bitmapInfo = FormBitmapInfo(imgWidth, imgHeight, imgBpp, true);
HRESULT hErrorCode = SetDIBitsToDevice(image->GetDC(), 0, 0, imgWidth, imgHeight, 0, 0, 0, imgHeight,
rgbaBuffer, &bitmapInfo, DIB_RGB_COLORS);
image->ReleaseDC();
if (FAILED(hErrorCode) && image)
{
cout << "FormCImageFromRGBABuffer: SetDibitsToDevice API failed "<< hErrorCode;
delete image;
image = NULL;
}
else if (FAILED(hErrorCode))
{
image = NULL;
}
}
else
{
cout<< "FormCImageFromRGBABuffer failed, rgbaBuffer is null";
}
}
catch(...)
{
cout<< "Exception in FormCImageFromRGBABuffer";
}
return image;
}

Related

How to release resources from ffmpeg

I have built a class that reads avi file and displays it.
This is the defination for the class.
typedef struct {
AVFormatContext *fmt_ctx;
int stream_idx;
AVStream *video_stream;
AVCodecContext *codec_ctx;
AVCodec *decoder;
AVPacket *packet;
AVFrame *av_frame;
AVFrame *gl_frame;
struct SwsContext *conv_ctx;
unsigned int frame_tex;
}AppData;
class ClipPlayer{
private:
AppData data;
std::vector< AVFrame* > cache;
public:
ClipPlayer();
ClipPlayer(const ClipPlayer& player);
ClipPlayer& operator=(const ClipPlayer& player);
~ClipPlayer();
void initializeAppData();
void clearAppData();
bool readFrame();
bool initReadFrame();
void playCache();
void init();
void draw();
void reset();
}
In the init function the AVI file is read and the frames are saved in memory.
void init()
{
initializeAppData();
// open video
if (avformat_open_input(&data.fmt_ctx, stdstrPathOfVideo.c_str(), NULL, NULL) < 0) {
clearAppData();
return;
}
// find stream info
if (avformat_find_stream_info(data.fmt_ctx, NULL) < 0) {
clearAppData();
return;
}
// find the video stream
for (unsigned int i = 0; i < data.fmt_ctx->nb_streams; ++i)
{
if (data.fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
data.stream_idx = i;
break;
}
}
if (data.stream_idx == -1)
{
clearAppData();
return;
}
data.video_stream = data.fmt_ctx->streams[data.stream_idx];
data.codec_ctx = data.video_stream->codec;
// find the decoder
data.decoder = avcodec_find_decoder(data.codec_ctx->codec_id);
if (data.decoder == NULL)
{
clearAppData();
return;
}
// open the decoder
if (avcodec_open2(data.codec_ctx, data.decoder, NULL) < 0)
{
clearAppData();
return;
}
// allocate the video frames
data.av_frame = av_frame_alloc();
data.gl_frame = av_frame_alloc();
int size = avpicture_get_size(AV_PIX_FMT_RGBA, data.codec_ctx->width,
data.codec_ctx->height);
uint8_t *internal_buffer = (uint8_t *)av_malloc(size * sizeof(uint8_t));
avpicture_fill((AVPicture *)data.gl_frame, internal_buffer, AV_PIX_FMT_RGBA,
data.codec_ctx->width, data.codec_ctx->height);
data.packet = (AVPacket *)av_malloc(sizeof(AVPacket));
}
/////////////////////////////////////////////////////////////
bool ClipPlayer::initReadFrame()
{
do {
glBindTexture(GL_TEXTURE_2D, data.frame_tex);
int error = av_read_frame(data.fmt_ctx, data.packet);
if (error)
{
av_free_packet(data.packet);
return false;
}
if (data.packet->stream_index == data.stream_idx)
{
int frame_finished = 0;
if (avcodec_decode_video2(data.codec_ctx, data.av_frame, &frame_finished,
data.packet) < 0) {
av_free_packet(data.packet);
return false;
}
if (frame_finished)
{
if (!data.conv_ctx)
{
data.conv_ctx = sws_getContext(data.codec_ctx->width,
data.codec_ctx->height, data.codec_ctx->pix_fmt,
data.codec_ctx->width, data.codec_ctx->height, AV_PIX_FMT_RGBA,
SWS_BICUBIC, NULL, NULL, NULL);
}
sws_scale(data.conv_ctx, data.av_frame->data, data.av_frame->linesize, 0,
data.codec_ctx->height, data.gl_frame->data, data.gl_frame->linesize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data.codec_ctx->width,
data.codec_ctx->height, GL_RGBA, GL_UNSIGNED_BYTE,
data.gl_frame->data[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
AVFrame *cachedValue = av_frame_alloc();
cachedValue->format = data.av_frame->format;
cachedValue->width = data.av_frame->width;
cachedValue->height = data.av_frame->height;
cachedValue->channels = data.av_frame->channels;
cachedValue->channel_layout = data.av_frame->channel_layout;
cachedValue->nb_samples = data.av_frame->nb_samples;
av_frame_get_buffer(cachedValue, 32);
av_frame_copy(cachedValue, data.av_frame);
av_frame_copy_props(cachedValue, data.av_frame);
cache.push_back((cachedValue));
}
}
} while (data.packet->stream_index != data.stream_idx);
////////////////////////////////////////////////////////////////////
In the play cache function the frames are displayed
void ClipPlayer::playCache()
{
glActiveTexture(GL_TEXTURE0);
sws_scale(data.conv_ctx, cache[loop]->data, cache[loop]->linesize, 0,
data.codec_ctx->height, data.gl_frame->data, data.gl_frame->linesize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data.codec_ctx->width,
data.codec_ctx->height, GL_RGBA, GL_UNSIGNED_BYTE,data.gl_frame->data[0]);
glBindTexture(GL_TEXTURE_2D, data.frame_tex);
}
In the destructor i try to free the memory
~ClipPlayer()
{
for (auto &frame : cache)
{
av_freep(frame);
}
}
I am not very proficient in using FFmpeg , my question is that have i freed the memory properly.
Your code two apparent problem.
You should use av_frame_unref() instead of av_freep() for AVFrames.
avpicture_fill is deprecated long ago. IF your ffmpeg installation is old. Update it. Otherwise use av_image_fill_arrays() instead.
You can refer up to date API documentation here: http://www.ffmpeg.org/doxygen/trunk/index.html
Hope that helps.

How to cache a AVI file using ffMpeg

I am reading a AVI file using ffMpeg.
I want to cache the file into a vector and resuse it later.
This is my code.
typedef struct {
AVFormatContext *fmt_ctx;
int stream_idx;
AVStream *video_stream;
AVCodecContext *codec_ctx;
AVCodec *decoder;
AVPacket *packet;
AVFrame *av_frame;
AVFrame *gl_frame;
struct SwsContext *conv_ctx;
unsigned int frame_tex;
}AppData;
AppData data;
Here i am caching the file to a std::vector
std::vector< AVFrame* > cache;
bool initReadFrame()
{
do {
glBindTexture(GL_TEXTURE_2D, data.frame_tex);
int error = av_read_frame(data.fmt_ctx, data.packet);
if (error)
{
av_free_packet(data.packet);
return false;
}
if (data.packet->stream_index == data.stream_idx)
{
int frame_finished = 0;
if (avcodec_decode_video2(data.codec_ctx, data.av_frame, &frame_finished,
data.packet) < 0) {
av_free_packet(data.packet);
return false;
}
if (frame_finished)
{
if (!data.conv_ctx)
{
data.conv_ctx = sws_getContext(data.codec_ctx->width,
data.codec_ctx->height, data.codec_ctx->pix_fmt,
data.codec_ctx->width, data.codec_ctx->height, AV_PIX_FMT_RGBA,
SWS_BICUBIC, NULL, NULL, NULL);
}
sws_scale(data.conv_ctx, data.av_frame->data, data.av_frame->linesize, 0,
data.codec_ctx->height, data.gl_frame->data, data.gl_frame->linesize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data.codec_ctx->width,
data.codec_ctx->height, GL_RGBA, GL_UNSIGNED_BYTE,
data.gl_frame->data[0]);
cache.push_back(av_frame_clone(data.gl_frame)); // Pushing AVFrame* to vector
}
}
av_free_packet(data.packet);
} while (data.packet->stream_index != data.stream_idx);
return true;
}
here i am trying to read the buffer and updating GL_TEXTURE_2D
void playCache()
{
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data.codec_ctx->width,
data.codec_ctx->height, GL_RGBA, GL_UNSIGNED_BYTE,
cache[temp]->data[0]);
temp++;
}
The issue i am facing is that when i try to read the Cached data the application crashes.
You are storing dead reference in your cache.
cache.push_back(av_frame_clone(data.gl_frame));
the doc says:
av_frame_clone: Create a new frame that references the same data as src.
When you destroy src, you loose its content and you can't access it in your cache.
You can try to move the ref to your new frame, or to copies its value.
Move:
AVFrame* cachedValue;
av_frame_move_ref(cachedValue, data.gl_frame);
cache.push_back(cachedValue);
Copy
AVFrame *cachedValue= av_frame_alloc();
cachedValue->format = data.gl_frame->format;
cachedValue->width = data.gl_frame->width;
cachedValue->height = data.gl_frame->height;
cachedValue->channels = data.gl_frame->channels;
cachedValue->channel_layout = data.gl_frame->channel_layout;
cachedValue->nb_samples = data.gl_frame->nb_samples;
av_frame_get_buffer(cachedValue, 32);
av_frame_copy(cachedValue, data.gl_frame);
av_frame_copy_props(cachedValue, data.gl_frame);
cache.push_back(cachedValue);
/////////////////////////////////////////////////
avformat_network_init();
initializeAppData();
// open video
if (avformat_open_input(&data.fmt_ctx, stdstrPathOfVideo.c_str(), NULL, NULL) < 0) {
clearAppData();
return;
}
// find stream info
if (avformat_find_stream_info(data.fmt_ctx, NULL) < 0) {
clearAppData();
return;
}
// dump debug info
// av_dump_format(data.fmt_ctx, 0, "D:\\E\\Event\\2019\\AVI_Badges\\Generic\\Generic.avi", 0);
// find the video stream
for (unsigned int i = 0; i < data.fmt_ctx->nb_streams; ++i)
{
if (data.fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
data.stream_idx = i;
break;
}
}
if (data.stream_idx == -1)
{
clearAppData();
return;
}
data.video_stream = data.fmt_ctx->streams[data.stream_idx];
data.codec_ctx = data.video_stream->codec;
// find the decoder
data.decoder = avcodec_find_decoder(data.codec_ctx->codec_id);
if (data.decoder == NULL)
{
clearAppData();
return;
}
// open the decoder
if (avcodec_open2(data.codec_ctx, data.decoder, NULL) < 0)
{
clearAppData();
return;
}
// allocate the video frames
data.av_frame = av_frame_alloc();
data.gl_frame = av_frame_alloc();
int size = avpicture_get_size(AV_PIX_FMT_RGBA, data.codec_ctx->width,
data.codec_ctx->height);
uint8_t *internal_buffer = (uint8_t *)av_malloc(size * sizeof(uint8_t));
avpicture_fill((AVPicture *)data.gl_frame, internal_buffer, AV_PIX_FMT_RGBA,
data.codec_ctx->width, data.codec_ctx->height);
data.packet = (AVPacket *)av_malloc(sizeof(AVPacket));

How to strech a bitmap using StretchBlt?

so I have written an application that loads bitmaps. But I would like to stretch the bitmap loaded in a way that all of them would have the same size. How can I go about implementing such a thing with StretchBlt? Here is my function that handles the bitmaps:
hBitmap = (HBITMAP)::LoadImageA(NULL, userSelectedFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (hBitmap == NULL)
{
::MessageBox(NULL, TEXT("LoadImage Failed"), TEXT("Error"), MB_OK);
return false;
}
HDC hLocalDC;
hLocalDC = ::CreateCompatibleDC(hWinDC);
if (hLocalDC == NULL)
{
::MessageBox(NULL, TEXT("CreateCompatibleDC Failed"), TEXT("Error"), MB_OK);
return false;
}
BITMAP qBitmap;
int iReturn = GetObject(reinterpret_cast<HGDIOBJ>(hBitmap), sizeof(BITMAP), reinterpret_cast<LPVOID>(&qBitmap));
if (!iReturn)
{
::MessageBox(NULL, TEXT("GetObject Failed"), TEXT("Error"), MB_OK);
return false;
}
HBITMAP hOldBmp = (HBITMAP)::SelectObject(hLocalDC, hBitmap);
if (hOldBmp == NULL)
{
::MessageBox(NULL, TEXT("SelectObject Failed"), TEXT("Error"), MB_OK);
return false;
}
BOOL qRetBlit = ::BitBlt(hWinDC, 0, 0, qBitmap.bmWidth, qBitmap.bmHeight, hLocalDC, 0, 0, SRCCOPY);
if (!qRetBlit)
{
::MessageBox(NULL, TEXT("Blit Failed"), TEXT("Error"), MB_OK);
return false;
}
::SelectObject(hLocalDC, hOldBmp);
::DeleteDC(hLocalDC);
::DeleteObject(hBitmap);
return true;
Would I have to replace StretchBlt with BitBlt?
UPDATE: I have managed to get StretchBlt to work but apparently all my images are overlapping each other. Here's the code so far:
hBitmap = (HBITMAP)::LoadImageA(NULL, myFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
// Verify that the image was loaded
if (hBitmap == NULL)
{
::MessageBox(NULL, TEXT("LoadImage Failed"), TEXT("Error"), MB_OK);
return false;
}
HDC hLocalDC;
hLocalDC = ::CreateCompatibleDC(hWinDC);
// Verify that the device context was created
if (hLocalDC == NULL)
{
::MessageBox(NULL, TEXT("CreateCompatibleDC Failed"), TEXT("Error"), MB_OK);
return false;
}
BITMAP qBitmap;
int iReturn = GetObject(reinterpret_cast<HGDIOBJ>(hBitmap), sizeof(BITMAP), reinterpret_cast<LPVOID>(&qBitmap));
if (!iReturn)
{
::MessageBox(NULL, TEXT("GetObject Failed"), TEXT("Error"), MB_OK);
return false;
}
HBITMAP hOldBmp = (HBITMAP)::SelectObject(hLocalDC, hBitmap);
if (hOldBmp == NULL)
{
::MessageBox(NULL, TEXT("SelectObject Failed"), TEXT("Error"), MB_OK);
return false;
}
/*BOOL qRetBlit = ::BitBlt(hWinDC, xPos, yPos, qBitmap.bmWidth, qBitmap.bmHeight, hLocalDC, 0, 0, SRCCOPY);
if (!qRetBlit)
{
::MessageBox(NULL, TEXT("Blit Failed"), TEXT("Error"), MB_OK);
return false;
}*/
sx = GetSystemMetrics(SM_CXSCREEN);
sy = GetSystemMetrics(SM_CXSCREEN);
BOOL qStretchBlit = StretchBlt(hWinDC, 0, 0, sx/2, sy/2, hLocalDC, 0, 0, sx, sy, SRCCOPY);
if (!qStretchBlit)
{
MessageBox(NULL, TEXT("StretchBlt Failed"), TEXT("Error"), MB_OK);
return false;
}
// Adjust positioning (not perfect)
if (iOldCounter > iCounter)
{
xPos += MOVE_X_POS;
if (xPos >= NEW_ROW_POS)
{
xPos = 0;
yPos += MOVE_Y_POS;
}
}
::SelectObject(hLocalDC, hOldBmp);
::DeleteDC(hLocalDC);
::DeleteObject(hBitmap);
return true;
Thoughts?
I have resolved my initial problem. Here are the steps I took:
Obtain the HDC using BeginPaint().
Obtain any additional information needed. For example, the dimension of the client area using GetClientRect().
Create a compatible DC using the function call CreateCompatibleDC().
Select your bitmap into the compatible DC; make sure you save the old bitmap returned by SelectObject().
Call StretchBlt() using the DC from BeginPaint() as destination and the compatible DC as source.
Select the old bitmap (obtained in step 4) back into the compatible DC using SelectObject().
Delete the compatible DC using DeleteDC().
Call EndPaint().

Getting error while creating CListCtrl

I'm trying to create a CListCtrl in MFC.
I am getting while making CImageList.
BOOL CRadioButtonTestDlg::InitImageList() {
mImageListNormal.Create(32, 32, ILC_COLOR32, 39, 1);
CString filePath;
CFileFind finder;
CString strWildcard(_T("E:\\MyAssignments\\Window system programming\\MFC\\sample_programs\\VContact\\res\\contact_images\\*.jpg"));
BOOL bWorking = finder.FindFile(strWildcard);
while (bWorking) {
bWorking = finder.FindNextFile();
if (finder.IsDots())
continue;
filePath = finder.GetFilePath();
CImage image;
CBitmap bitmap;
image.Load(filePath);
bitmap.Attach(image.Detach());
mImageListNormal.Add(&bitmap, RGB(255, 0, 255));
bitmap.DeleteObject();
}
finder.Close();
if(mAllContactListCtrl.SetImageList(&mImageListNormal, LVSIL_NORMAL) == NULL)
AfxMessageBox(_T("Falied to set ImageList"));
return TRUE;
}
call to mAllContactListCtrl.SetImageList() failed.
I want know whether using creating CBitmap from CImage is correct or I'm doing wrong some where else.
In the output I'm just getting string but not the Image.
=========================================================================
I am calling the above function from InitDialog()
BOOL CRadioButtonTestDlg::OnInitDialog() {
CDialog::OnInitDialog();
CRect rect;
mAllContactListCtrl.GetClientRect(&rect);
mAllContactListCtrl.InsertColumn(0, _T("Name"), LVCFMT_LEFT, rect.Width()-15, 0);
for (int i = 0; i < 39; i++) {
mAllContactListCtrl.InsertItem(i, _T("Some String"), i);
}
InitImageList();
return TRUE;
}

How Do I Create a 32-bit Tray Icon With Transparency (using GDI)?

I'm trying to create an icon that displays a piece of text in the system tray. (Obviously, it won't be longer than a couple of characters.)
So far I've tried:
#include <tchar.h>
#include <Windows.h>
#include <Windowsx.h>
static HICON CreateIcon(LPCTSTR txt) {
HICON hIcon = NULL;
HDC hDC = NULL; {
HDC hDCScreen = GetDC(NULL);
if (hDCScreen != NULL) {
__try { hDC = CreateCompatibleDC(hDCScreen); }
__finally { ReleaseDC(NULL, hDCScreen); }
}
}
if (hDC != NULL) {
__try {
HFONT hFont = CreateFontIndirect(&ncm.lfMessageFont);
if (hFont != NULL) {
__try { SelectFont(hDC, hFont); }
__finally { DeleteFont(hFont); }
}
int width = GetSystemMetrics(SM_CXSMICON),
height = GetSystemMetrics(SM_CYSMICON);
HBITMAP hBmp = CreateCompatibleBitmap(hDC, width, height);
if (hBmp != NULL) {
__try {
HBITMAP hMonoBmp =
CreateCompatibleBitmap(hDC, width, height);
if (hMonoBmp != NULL) {
__try {
RECT rect = { 0, 0, width, height };
HGDIOBJ prev = SelectObject(hDC, hBmp);
__try {
SetBkMode(hDC, TRANSPARENT);
SetTextColor(hDC, RGB(255, 255, 255));
ICONINFO ii = { TRUE, 0, 0, hMonoBmp, hBmp };
int textHeight =
DrawText(hDC, txt, _tcslen(txt), &rect, 0);
if (textHeight != 0) {
hIcon = CreateIconIndirect(&ii);
}
} __finally { SelectObject(hDC, prev); }
} __finally { DeleteObject(hMonoBmp); }
}
} __finally { DeleteObject(hBmp); }
}
} __finally { DeleteDC(hDC); }
}
return hIcon;
}
with this code:
static void _tmain(int argc, TCHAR* argv[]) {
HICON hIcon = CreateIcon(_T("Hi"));
if (hIcon != NULL) {
__try {
NOTIFYICONDATA nid = { sizeof(nid) };
nid.hWnd = GetConsoleWindow();
BOOL success = Shell_NotifyIcon(NIM_ADD, &nid);
if (success) {
nid.uFlags = NIF_ICON;
nid.hIcon = hIcon;
success = Shell_NotifyIcon(NIM_MODIFY, &nid);
}
} __finally { DestroyIcon(hIcon); }
}
}
but all I get is a monochrome bitmap that says Hi in white text on a black background. (If I change the RGB(255, 255, 255) even slightly, say to RGB(255, 255, 254), it becomes black, so it's monochrome.)
Any ideas?
(*Note: I'm not looking for MFC, ATL, or any other library solutions, just Win32/GDI calls.)
Edit:
Here's what it looks like currently:
If I recall correctly, a partially transparent icon (which I think is what want) has a monochrome bitmap for its mask. This mask happens to be ignored but you still have to supply it. You aren't creating a monochrome bitmap, you appear to be creating a 32bpp bitmap. I also don't see anywhere where you initialise the alpha values for you main bitmap so that the areas which you don't write to are transparent.
An example with code is provided here: How To Create an Alpha Blended Cursor or Icon in Windows XP

Resources