Video player in vc++ (each frame being shown in a new window)
I am trying to show all the frames of a video sequence in the same window. But currently it is showing each frame in a different window. e.g. once it shows first frame, I need to close that window and then another window pops up and it shows next frame and then I need to close that one and then next window pops up...and so on.
i am using createwindow function to create a window and I associate HINSTANCE of a frame to HWND using CreateWindow function. If I do createwindow only once it just shows first frame in a window and once I close it nothing happens..
can anybody help me out with this???
Here is the part of code related to it:-
Code:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
So when I call it in loop, each time it creates a new window for each frame. But if I call CreateWindow only once, then it doesn't update frame. If I am right its happening that way coz it doesn't associate new hInstance with window as hInstance is being updated with each frame.
Is there a way to associate/update hInstance to a hWnd without calling CreateWindow function? Or am I thinking in wrong direction? Can someone clarify please.
Re: Video player in vc++ (each frame being shown in a new window)
We need to see more of your code to be able to help you.
For starters, InitInstance should be called only once. It's meant to initialize your instance of your program.
If you only want 1 window, then you only call CreateWindow once.
You can update your existing window by implementing a proper window procedure function, and handle WM_PAINT messages to paint your window.
Re: Video player in vc++ (each frame being shown in a new window)
Quote:
I am trying to show all the frames of a video sequence in the same window.
What does that "show" mean? You extract frames somehow (how?), and your problem is just drawing image? Or your window embeds video player that gets positioned to appropriate frame time? Depending on the answer there could be few totally different resolution approaches.
Quote:
i am using createwindow function to create a window and I associate HINSTANCE of a frame to HWND using CreateWindow function.
Quote:
it doesn't associate new hInstance with window as hInstance is being updated with each frame.
This sounds senseless. HINSTANCE is a base address of a binary module (.exe or .dll), therefore, it has nothing to do with a frame. You need to explain, which way frames are obtained in your program, and why you do think they have an "association" with module instance.
Re: Video player in vc++ (each frame being shown in a new window)
I am pasting my complete code here :-
"Image.h" :-
Code:
#if !defined(AFX_IMAGE_H__E34B6FBB_5FED_457A_B3D1_D4844DCD4951__INCLUDED_)
#define AFX_IMAGE_H__E34B6FBB_5FED_457A_B3D1_D4844DCD4951__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "resource.h"
#include "stdafx.h"
#include "resource.h"
#include <stdio.h>
// Class structure of Image
class MyImage
{
private:
int Width;
int Height;
char ImagePath[_MAX_PATH];
unsigned char* Data;
unsigned char* NewData;
public:
int playFlag; // 0 = pause and 1 = play
int stopFlag; // set 1 when user hits stop, equal to 0 rest of the time
int channelNum; // 0->All to be displayed, 1->Y, 2->U, 3->V
MyImage() {playFlag=1; stopFlag=0;channelNum=0;};
~MyImage() { if(Data) delete Data; };
void setWidth(int w) { Width = w; };
void setHeight(int h) { Height = h; };
void setImageData(unsigned char *img ) { Data = img; };
void setImagePath(char *path) { strcpy(ImagePath, path); }
int getWidth() { return Width; };
int getHeight() { return Height; };
unsigned char* getImageData() { return NewData; };
char* getImagePath() { return ImagePath; }
void ReadImage();
void ConvertYUVtoRGB();
};
#endif // !defined(AFX_IMAGE_H__E34B6FBB_5FED_457A_B3D1_D4844DCD4951__INCLUDED_)
AND "Image.cpp" :-
Code:
// Image.cpp : Defines the entry point for the application.
//
#include "Image.h"
MyImage myImage;
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
FILE *IN_FILE;
int flag;
HWND hWnd;
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
int w, h;
char ImagePath[_MAX_PATH];
sscanf(lpCmdLine, "%s", &ImagePath);
//ImagePath = {"M:\\MediaPlayer\\data\\yuv\\image1.rgb"};
w = 352;
h = 288;
myImage.setWidth(w);
myImage.setHeight(h);
myImage.setImagePath(ImagePath);
flag = 0;
while(1)
{
if(myImage.playFlag==1)
{
myImage.ReadImage();
myImage.ConvertYUVtoRGB();
}
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_IMAGE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_IMAGE);
// Main message loop:
/*while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}*/
}
return msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_IMAGE);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_IMAGE;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
//HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[MAX_LOADSTRING];
LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_PLAY:
myImage.playFlag = 1;
myImage.stopFlag = 0;
break;
case IDM_PAUSE:
myImage.playFlag = 0;
break;
case IDM_STOP:
myImage.playFlag = 1;
myImage.stopFlag = 1;
break;
case ID_CHANNEL_ALL:
myImage.channelNum = 0;
break;
case ID_CHANNEL_Y:
myImage.channelNum = 1;
break;
case ID_CHANNEL_U:
myImage.channelNum = 2;
break;
case ID_CHANNEL_V:
myImage.channelNum = 3;
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
RECT rt;
GetClientRect(hWnd, &rt);
char text[1000];
BITMAPINFO bmi;
CBitmap bitmap;
memset(&bmi,0,sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = myImage.getWidth();
bmi.bmiHeader.biHeight = -myImage.getHeight(); // Use negative height. DIB is top-down.
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = myImage.getWidth()*myImage.getHeight();
SetDIBitsToDevice(hdc,
myImage.getWidth()+50,100,myImage.getWidth(),myImage.getHeight(),
0,0,0,myImage.getHeight(),
myImage.getImageData(),&bmi,DIB_RGB_COLORS);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
// clipper function for range 0 to 255
double ClipRGB(double num)
{
if(num < 0.0)
num = 0.0;
if(num > 255.0)
num = 255.0;
return num;
}
// MyImage functions defined here
void MyImage::ConvertYUVtoRGB()
{
int i;
double iY,iU,iV;
double iR,iG,iB;
NewData = new unsigned char[Width*Height*3];
for(i=0; i<Height*Width; i++)
{
iY = (double) Data[3*i];
iU = (double) Data[3*i+1];
iV = (double) Data[3*i+2];
if(myImage.channelNum == 0) // All channels to be displayed
{
iR = iY + 1.4075*(iV-128.0); /* softpixel.com formula (http://softpixel.com/~cwright/progra...olorspace/yuv/) */
iG = iY - 0.3455*(iU-128.0) - 0.7169*(iV-128.0);
iB = iY + 1.7790*(iU-128.0);
}
else if(myImage.channelNum == 1) // Y channel to be displayed
{
/*iR = iY;
iG = iY;
iB = iY;*/
iR = iY + 1.4075*(128.0-128.0);
iG = iY - 0.3455*(128.0-128.0) - 0.7169*(128.0-128.0);
iB = iY + 1.7790*(128.0-128.0);
}
else if(myImage.channelNum == 2) // U channel to be displayed
{
/*iR = 0.0;
iG = 0.3455*(iU-128.0);
iB = 1.7790*(iU-128.0);*/
iR = iY + 1.4075*(128.0-128.0);
iG = iY - 0.3455*(iU-128.0) - 0.7169*(128.0-128.0);
iB = iY + 1.7790*(iU-128.0);
}
else if(myImage.channelNum == 3) // V channel to be displayed
{
/*iR = 1.4075*(iV-128.0);
iG = 0.0 - 0.7169*(iV-128.0);
iB = 0.0;*/
iR = iY + 1.4075*(iV-128.0);
iG = iY - 0.3455*(128.0-128.0) - 0.7169*(iV-128.0);
iB = iY + 1.7790*(128.0-128.0);
}
iR = ClipRGB(iR); // Clipping of RGB values
iG = ClipRGB(iG);
iB = ClipRGB(iB);
NewData[3*i] = (unsigned char) iB;
NewData[3*i+1] = (unsigned char) iG;
NewData[3*i+2] = (unsigned char) iR;
}
}
void MyImage::ReadImage()
{
int i,j,ctr;
char *Ybuf = new char[Height*Width];
char *Ubuf = new char[Height*Width/4];
char *Vbuf = new char[Height*Width/4];
char *IUbuf = new char[Height*Width/2];
char *IVbuf = new char[Height*Width/2];
char *NewUbuf = new char[Height*Width];
char *NewVbuf = new char[Height*Width];
if(myImage.stopFlag == 1)
{
fclose(IN_FILE);
IN_FILE = fopen(ImagePath, "rb");
if (IN_FILE == NULL)
{
fprintf(stderr, "Error");
exit(0);
}
myImage.playFlag = 0;
}
if(flag == 0)
{
IN_FILE = fopen(ImagePath, "rb");
if (IN_FILE == NULL)
{
fprintf(stderr, "Error");
exit(0);
}
flag = 1;
}
for (i = 0; i < Width*Height; i++)
{
Ybuf[i] = fgetc(IN_FILE);
}
for (i = 0; i < Width*Height/4; i++)
{
Ubuf[i] = fgetc(IN_FILE);
}
for (i = 0; i < Width*Height/4; i++)
{
Vbuf[i] = fgetc(IN_FILE);
}
ctr = 0;
for (i = 0; i < Height/2; i++)
{
for (j = 0; j < Width/2; j++)
{
IUbuf[ctr] = Ubuf[i*Width/2+j];
IUbuf[ctr+Width/2] = Ubuf[i*Width/2+j];
IVbuf[ctr] = Vbuf[i*Width/2+j];
IVbuf[ctr+Width/2] = Vbuf[i*Width/2+j];
ctr++;
}
ctr = ctr + Width/2;
}
ctr = 0;
for (i = 0; i < Width*Height; i+=2)
{
NewUbuf[i] = IUbuf[ctr];
NewUbuf[i+1] = IUbuf[ctr];
NewVbuf[i] = IVbuf[ctr];
NewVbuf[i+1] = IVbuf[ctr];
ctr++;
}
FILE *OUT_FILE;
OUT_FILE = fopen("M:\\uval.txt","w");
char ch= ' ',nl='\n';
for (i = 0; i < Width*Height; i++)
{
fputc( NewUbuf[i], OUT_FILE);
fputc( ch, OUT_FILE);
if( ((i+1)%Width) == 0)
{
fputc( nl, OUT_FILE);
}
}
Data = new unsigned char[Width*Height*3];
for (i = 0; i < Height*Width; i++)
{
Data[3*i] = Ybuf[i];
Data[3*i+1] = NewUbuf[i];
Data[3*i+2] = NewVbuf[i];
/*Data[3*i+1] = (unsigned char) 0;
Data[3*i+2] = (unsigned char) 0;*/
}
delete [] Ybuf;
delete [] Ubuf;
delete [] Vbuf;
//fclose(IN_FILE);
}
I am extracting frames from a .YUV file (video frames in sequence in YUV format) from memory. And I want to play the video in a window instance.
I hope my question would be more clear now.
Re: Video player in vc++ (each frame being shown in a new window)
I think this version of "Image.cpp" will make more sense :-
Code:
// Image.cpp : Defines the entry point for the application.
//
#include "Image.h"
MyImage myImage;
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
FILE *IN_FILE;
int flag;
HWND hWnd;
WNDCLASSEX wcex;
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
int w, h;
char ImagePath[_MAX_PATH];
sscanf(lpCmdLine, "%s", &ImagePath);
//ImagePath = {"M:\\MediaPlayer\\data\\yuv\\image1.rgb"};
w = 352;
h = 288;
myImage.setWidth(w);
myImage.setHeight(h);
myImage.setImagePath(ImagePath);
flag = 0;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_IMAGE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_IMAGE);
while(1)
{
if(myImage.playFlag==1)
{
myImage.ReadImage();
myImage.ConvertYUVtoRGB();
}
// Code to update the window to be added here. How to use WndProc for updating?
}
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
//WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_IMAGE);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_IMAGE;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
//HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[MAX_LOADSTRING];
LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_PLAY:
myImage.playFlag = 1;
myImage.stopFlag = 0;
break;
case IDM_PAUSE:
myImage.playFlag = 0;
break;
case IDM_STOP:
myImage.playFlag = 1;
myImage.stopFlag = 1;
break;
case ID_CHANNEL_ALL:
myImage.channelNum = 0;
break;
case ID_CHANNEL_Y:
myImage.channelNum = 1;
break;
case ID_CHANNEL_U:
myImage.channelNum = 2;
break;
case ID_CHANNEL_V:
myImage.channelNum = 3;
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
RECT rt;
GetClientRect(hWnd, &rt);
char text[1000];
BITMAPINFO bmi;
CBitmap bitmap;
memset(&bmi,0,sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = myImage.getWidth();
bmi.bmiHeader.biHeight = -myImage.getHeight(); // Use negative height. DIB is top-down.
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = myImage.getWidth()*myImage.getHeight();
SetDIBitsToDevice(hdc,
myImage.getWidth()+50,100,myImage.getWidth(),myImage.getHeight(),
0,0,0,myImage.getHeight(),
myImage.getImageData(),&bmi,DIB_RGB_COLORS);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
// clipper function for range 0 to 255
double ClipRGB(double num)
{
if(num < 0.0)
num = 0.0;
if(num > 255.0)
num = 255.0;
return num;
}
// MyImage functions defined here
void MyImage::ConvertYUVtoRGB()
{
int i;
double iY,iU,iV;
double iR,iG,iB;
NewData = new unsigned char[Width*Height*3];
for(i=0; i<Height*Width; i++)
{
iY = (double) Data[3*i];
iU = (double) Data[3*i+1];
iV = (double) Data[3*i+2];
if(myImage.channelNum == 0) // All channels to be displayed
{
iR = iY + 1.4075*(iV-128.0); /* softpixel.com formula (http://softpixel.com/~cwright/progra...olorspace/yuv/) */
iG = iY - 0.3455*(iU-128.0) - 0.7169*(iV-128.0);
iB = iY + 1.7790*(iU-128.0);
}
else if(myImage.channelNum == 1) // Y channel to be displayed
{
/*iR = iY;
iG = iY;
iB = iY;*/
iR = iY + 1.4075*(128.0-128.0);
iG = iY - 0.3455*(128.0-128.0) - 0.7169*(128.0-128.0);
iB = iY + 1.7790*(128.0-128.0);
}
else if(myImage.channelNum == 2) // U channel to be displayed
{
/*iR = 0.0;
iG = 0.3455*(iU-128.0);
iB = 1.7790*(iU-128.0);*/
iR = iY + 1.4075*(128.0-128.0);
iG = iY - 0.3455*(iU-128.0) - 0.7169*(128.0-128.0);
iB = iY + 1.7790*(iU-128.0);
}
else if(myImage.channelNum == 3) // V channel to be displayed
{
/*iR = 1.4075*(iV-128.0);
iG = 0.0 - 0.7169*(iV-128.0);
iB = 0.0;*/
iR = iY + 1.4075*(iV-128.0);
iG = iY - 0.3455*(128.0-128.0) - 0.7169*(iV-128.0);
iB = iY + 1.7790*(128.0-128.0);
}
iR = ClipRGB(iR); // Clipping of RGB values
iG = ClipRGB(iG);
iB = ClipRGB(iB);
NewData[3*i] = (unsigned char) iB;
NewData[3*i+1] = (unsigned char) iG;
NewData[3*i+2] = (unsigned char) iR;
}
}
void MyImage::ReadImage()
{
int i,j,ctr;
char *Ybuf = new char[Height*Width];
char *Ubuf = new char[Height*Width/4];
char *Vbuf = new char[Height*Width/4];
char *IUbuf = new char[Height*Width/2];
char *IVbuf = new char[Height*Width/2];
char *NewUbuf = new char[Height*Width];
char *NewVbuf = new char[Height*Width];
if(myImage.stopFlag == 1)
{
fclose(IN_FILE);
IN_FILE = fopen(ImagePath, "rb");
if (IN_FILE == NULL)
{
fprintf(stderr, "Error");
exit(0);
}
myImage.playFlag = 0;
}
if(flag == 0)
{
IN_FILE = fopen(ImagePath, "rb");
if (IN_FILE == NULL)
{
fprintf(stderr, "Error");
exit(0);
}
flag = 1;
}
for (i = 0; i < Width*Height; i++)
{
Ybuf[i] = fgetc(IN_FILE);
}
for (i = 0; i < Width*Height/4; i++)
{
Ubuf[i] = fgetc(IN_FILE);
}
for (i = 0; i < Width*Height/4; i++)
{
Vbuf[i] = fgetc(IN_FILE);
}
ctr = 0;
for (i = 0; i < Height/2; i++)
{
for (j = 0; j < Width/2; j++)
{
IUbuf[ctr] = Ubuf[i*Width/2+j];
IUbuf[ctr+Width/2] = Ubuf[i*Width/2+j];
IVbuf[ctr] = Vbuf[i*Width/2+j];
IVbuf[ctr+Width/2] = Vbuf[i*Width/2+j];
ctr++;
}
ctr = ctr + Width/2;
}
ctr = 0;
for (i = 0; i < Width*Height; i+=2)
{
NewUbuf[i] = IUbuf[ctr];
NewUbuf[i+1] = IUbuf[ctr];
NewVbuf[i] = IVbuf[ctr];
NewVbuf[i+1] = IVbuf[ctr];
ctr++;
}
FILE *OUT_FILE;
OUT_FILE = fopen("M:\\uval.txt","w");
char ch= ' ',nl='\n';
for (i = 0; i < Width*Height; i++)
{
fputc( NewUbuf[i], OUT_FILE);
fputc( ch, OUT_FILE);
if( ((i+1)%Width) == 0)
{
fputc( nl, OUT_FILE);
}
}
Data = new unsigned char[Width*Height*3];
for (i = 0; i < Height*Width; i++)
{
Data[3*i] = Ybuf[i];
Data[3*i+1] = NewUbuf[i];
Data[3*i+2] = NewVbuf[i];
/*Data[3*i+1] = (unsigned char) 0;
Data[3*i+2] = (unsigned char) 0;*/
}
delete [] Ybuf;
delete [] Ubuf;
delete [] Vbuf;
//fclose(IN_FILE);
}
In this case whats happening is that InitInstance is being called once and a window is created but I don't know how to update the window with frames. I have WndProc function in my code. How exactly shall I call that function? As in with what parameters? And I shall do that in my while loop just after converting the frame to RGB format right?
Re: Video player in vc++ (each frame being shown in a new window)
Please, use code tags. Do you really expect anyone to read/understand the code like you've posted it?
I have added the code tags for you now, but in the future, please use them [ code ] ... [ /code ] (without the spaces).
Regarding your problem, I don't see a message loop. Every windows application needs a message loop. For example, see http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx
Re: Video player in vc++ (each frame being shown in a new window)
Quote:
Originally Posted by
hellSigma
I think this version of "Image.cpp" will make more sense :-
Actually not much in the light of what you said above.
First of all, this is not video player. It's rather image renderer, as I can see ReadImage reads from separate files, converts between color spaces and saves data for future rendering.
Second, your window becomes dead immediately after first UpdateWindow call. Due to UpdateWindow the window procedure receives single WM_PAINT message, which creates first draw occurrence. And what's next? To react to user input events, message pump must exist, exactly what Marc already pointed out. Okay, imagine you have the pump. What is your plan for animating your view?
Code:
while(1)
{
if(myImage.playFlag==1)
{
myImage.ReadImage();
myImage.ConvertYUVtoRGB();
}
// Code to update the window to be added here. How to use WndProc for updating?
}
Again, imagine you solved window update issue. Look what your while loop does: it reads image, prepares it for rendering and renders one, doing all this without any timing, as fast as hard drive can read, CPU can calculate and video card can blit. Your movie is gonna end in a few moments. This is definitely not what you would expect, isn't it?
So, what is your plan about animation?
Quote:
In this case whats happening is that InitInstance is being called once and a window is created but I don't know how to update the window with frames. I have WndProc function in my code. How exactly shall I call that function? As in with what parameters? And I shall do that in my while loop just after converting the frame to RGB format right?
You never call window procedure directly. Never. Instead, you let Windows do that for you when message queu gets processed. To spin up the message queue processing you need to create Message Loop in your program and start dispatching messages coming to your program.
Next step would be implementing some mechanism for processing images in timely fashion. The simplest approach would be window timer. You create timer with 100ms timeout (to play 10 frames per second), and on every timer event you synthesize the next image path, read the imape, prepare it for RGB colorspace, store data and invalidate your window. This invalidation results in Windows sending WM_PAINT message where you render the stored data. So all the process appears driven by timer events. It's important to understand that your program code execution must relinquish to let Windows properly do its part behind the scene.
Re: Video player in vc++ (each frame being shown in a new window)
Re: Video player in vc++ (each frame being shown in a new window)
You really need to get rid of your current idea of reading/rendering images inside your message loop (which looks scary now :)). Instead, you need a classic message loop, and your image stuff moved to timer handler.