Blame |
Last modification |
View Log
| RSS feed
/* ========================================================================
* PROJECT: DirectShow Video Processing Library (DSVL)
* File: OpenGL/GLUT shared memory buffer sample
* Version: 0.0.8 (05/13/2005)
* ========================================================================
* Author: Thomas Pintaric, Vienna University of Technology
* Contact: pintaric@ims.tuwien.ac.at http://ims.tuwien.ac.at/~thomas
* =======================================================================
*
* Copyright (C) 2005 Vienna University of Technology
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* For further information please contact Thomas Pintaric under
* <pintaric@ims.tuwien.ac.at> or write to Thomas Pintaric,
* Vienna University of Technology, Favoritenstr. 9-11/E188/2, A-1040
* Vienna, Austria.
* ========================================================================*/
/*
* This sample demonstrates the use of a shared memory buffer to access
* video frames.
*
*/
#define SHOW_ROTATING_CUBE
#ifdef _DEBUG
static unsigned long frame_counter = 0;
#endif
#include "DSVL.h" // DirectShow Video Processing Library
#include <stdio.h> // Standard C/C++ Input-Output
#include <windows.h> // Standard Header For MSWindows Applications
#include <gl/glut.h> // The GL Utility Toolkit (GLUT) Header
// The Following Directive Fixes The Problem With Extra Console Window
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
//---------------------------------------------------------------------------
DSVL_VideoSource *dsvl_vs = NULL;
DWORD WINAPI DummyThreadProc(LPVOID lpParameter);
MemoryBufferHandle g_mbHandle;
BYTE* g_pPixelBuffer = NULL;
LONGLONG g_Timestamp = _INVALID_TIMESTAMP;
LONG cap_width = 0;
LONG cap_height = 0;
double cap_fps = 0.0;
#ifndef GL_BGR
#define GL_BGR GL_BGR_EXT
#endif
#ifndef GL_BGRA
#define GL_BGRA GL_BGRA_EXT
#endif
//---------------------------------------------------------------------------
#define TEXTURES_NUM 1 // We Have 1 Texture
#define CUBE_TEX 0 // Our Cube Texture Index
// A Structure For RGB Bitmaps
typedef struct _RGBIMG {
GLuint w; // Image's Width
GLuint h; // Image's Height
GLubyte* data; // Image's Data (Pixels)
} RGBIMG;
const GLuint TEX_WIDTH = 1024; // texture should be large enough to store full-size
const GLuint TEX_HEIGHT =1024; // PAL video frames (720x576px)
// Global Variables
bool g_gamemode; // GLUT GameMode ON/OFF
bool g_fullscreen; // Fullscreen Mode ON/OFF (When g_gamemode Is OFF)
GLfloat g_xrot = 0.0f; // X Rotation
GLfloat g_yrot = 0.0f; // Y Rotation
GLfloat g_zrot = 0.0f; // Z Rotation
GLuint g_texid[TEXTURES_NUM]; // Our Textures' Id List
const bool showFullscreenDialog = false;
#ifdef SHOW_ROTATING_CUBE
bool showRotatingCube = true;
#else
bool showRotatingCube = false;
#endif
//---------------------------------------------------------------------------
bool setup_dsWrapper(char* lpCmdLine = "")
{
CoInitialize(NULL);
dsvl_vs = new DSVL_VideoSource();
if(strlen(lpCmdLine) == 0)
{
MessageBox(NULL,"No XML configuration file specified.\nusage: glutSample config.xml","glutSample",MB_OK);
exit(0);
}
if(FAILED(dsvl_vs->BuildGraphFromXMLFile(lpCmdLine))) return(false);
if(FAILED(dsvl_vs->GetCurrentMediaFormat(&cap_width,&cap_height,&cap_fps,NULL))) return(false);
if(FAILED(dsvl_vs->EnableMemoryBuffer(3))) return(false);
// three concurrent threads will concurrently query for samples
if(FAILED(dsvl_vs->Run())) return(false);
// create two dummy threads that will sparsely request memory buffers, but
// block them for extended periods of time
DWORD thread0;
HANDLE hThread0 = CreateThread(NULL,0,DummyThreadProc,(LPVOID)30,0,&thread0);
DWORD thread1;
HANDLE hThread1 = CreateThread(NULL,0,DummyThreadProc,(LPVOID)157,0,&thread1);
return(true);
}
//---------------------------------------------------------------------------
// a dummy thread that will also try to acquire video buffers
DWORD WINAPI DummyThreadProc(LPVOID lpParameter)
{
long delay = (long) lpParameter;
MemoryBufferHandle l_mbHandle;
BYTE* l_pPixelBuffer = NULL;
while(true)
{
DWORD wait_result = dsvl_vs->WaitForNextSample(INFINITE);
if(wait_result == WAIT_OBJECT_0)
{
if(SUCCEEDED(dsvl_vs->CheckoutMemoryBuffer(&l_mbHandle, &l_pPixelBuffer)))
{
Sleep(delay); // do nothing...
dsvl_vs->CheckinMemoryBuffer(l_mbHandle);
}
}
}
return(0);
}
//---------------------------------------------------------------------------
// Setup Our Textures. Returns true On Success, false On Fail
bool setup_textures()
{
RGBIMG img = {TEX_WIDTH,TEX_HEIGHT,NULL};
long data_size = 4 * sizeof(GLubyte) * img.h * img.w;
img.data = (GLubyte*) malloc(data_size);
FillMemory(img.data,data_size,0x7f);
// Create The Textures' Id List
glGenTextures(TEXTURES_NUM, g_texid);
// Typical Texture Generation Using Data From The Image
glBindTexture(GL_TEXTURE_2D, g_texid[CUBE_TEX]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, img.w, img.h, 0, GL_BGRA, GL_UNSIGNED_BYTE, img.data);
// Finished With Our Image, Free The Allocated Data
delete img.data;
return true;
}
// Our GL Specific Initializations. Returns true On Success, false On Fail.
bool init(void)
{
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
if (!setup_textures()) return false;
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Pixel Storage Mode To Byte Alignment
glEnable(GL_CULL_FACE); // Cull Polygons
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
return true;
}
// Our Rendering Is Done Here
void render(void)
{
DWORD wait_result = dsvl_vs->WaitForNextSample(100/60);
//if(wait_result == WAIT_OBJECT_0)
{
#ifdef _DEBUG
frame_counter++;
#endif
//dsvl_vs->Lock();
if(SUCCEEDED(dsvl_vs->CheckoutMemoryBuffer(&g_mbHandle, &g_pPixelBuffer)))
{
glBindTexture(GL_TEXTURE_2D, g_texid[CUBE_TEX]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cap_width, cap_height,
GL_BGRA, GL_UNSIGNED_BYTE, (void*)g_pPixelBuffer);
g_Timestamp = dsvl_vs->GetCurrentTimestamp();
dsvl_vs->CheckinMemoryBuffer(g_mbHandle);
}
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
float u_rt = (float)cap_width / TEX_WIDTH;
float v_rt = (float)cap_height / TEX_HEIGHT;
glDisable(GL_DEPTH_TEST);
glBindTexture(GL_TEXTURE_2D, g_texid[CUBE_TEX]);
glBegin(GL_QUADS);
// video backplate
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 0.0f);
glTexCoord2f(u_rt, 0.0f); glVertex3f( 1.0f, -1.0f, 0.0f);
glTexCoord2f(u_rt, v_rt); glVertex3f( 1.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, v_rt); glVertex3f(-1.0f, 1.0f, 0.0f);
glEnd();
glEnable(GL_DEPTH_TEST);
glPopMatrix();
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glTranslatef(0.0f,0.0f,-5.0f);
glRotatef(g_xrot,1.0f,0.0f,0.0f);
glRotatef(g_yrot,0.0f,1.0f,0.0f);
glRotatef(g_zrot,0.0f,0.0f,1.0f);
glBindTexture(GL_TEXTURE_2D, g_texid[CUBE_TEX]);
if(showRotatingCube)
{
glBegin(GL_QUADS);
// Front Face
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(u_rt, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(u_rt, v_rt); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, v_rt); glVertex3f(-1.0f, 1.0f, 1.0f);
// Back Face
glTexCoord2f(u_rt, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(u_rt, v_rt); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, v_rt); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
// Top Face
glTexCoord2f(0.0f, v_rt); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(u_rt, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(u_rt, v_rt); glVertex3f( 1.0f, 1.0f, -1.0f);
// Bottom Face
glTexCoord2f(u_rt, v_rt); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, v_rt); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(u_rt, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
// Right face
glTexCoord2f(u_rt, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(u_rt, v_rt); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, v_rt); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
// Left Face
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(u_rt, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(u_rt, v_rt); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, v_rt); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
}
g_xrot += 0.3f;
g_yrot += 0.2f;
g_zrot += 0.4f;
// Swap The Buffers To Become Our Rendering Visible
glutSwapBuffers ( );
}
// Our Reshaping Handler (Required Even In Fullscreen-Only Modes)
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio And Set The Clipping Volume
if (h == 0) h = 1;
gluPerspective(50, (float)w/(float)h, 1.0, 5000.0);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
// Our Keyboard Handler (Normal Keys)
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27: // When Escape Is Pressed...
dsvl_vs->Stop();
dsvl_vs->ReleaseGraph();
delete dsvl_vs;
exit(0); // Exit The Program
break; // Ready For Next Case
case 99: // 'c'
case 67: // 'C'
showRotatingCube = !showRotatingCube;
break;
default: // Now Wrap It Up
break;
}
}
// Our Keyboard Handler For Special Keys (Like Arrow Keys And Function Keys)
void special_keys(int a_keys, int x, int y)
{
switch (a_keys) {
case GLUT_KEY_F1:
// We Can Switch Between Windowed Mode And Fullscreen Mode Only
if (!g_gamemode) {
g_fullscreen = !g_fullscreen; // Toggle g_fullscreen Flag
if (g_fullscreen) glutFullScreen(); // We Went In Fullscreen Mode
else
{
glutReshapeWindow(640, 480); // We Went In Windowed Mode
glutPositionWindow(80, 60);
}
}
break;
default:
break;
}
}
// Ask The User If He Wish To Enter GameMode Or Not
void ask_gamemode()
{
if(showFullscreenDialog)
{
int answer;
// Use Windows MessageBox To Ask The User For Game Or Windowed Mode
answer = MessageBox(NULL, "Do you want to enter exclusive mode?\n(a.k.a. 'game mode')", "Display Question",
MB_ICONQUESTION | MB_YESNO);
g_gamemode = (answer == IDYES);
// If Not Game Mode Selected, Use Windowed Mode (User Can Change That With F1)
} else g_gamemode = false;
g_fullscreen = false;
}
// Main Function For Bringing It All Together.
int main(int argc, char** argv)
{
ask_gamemode(); // Ask For Fullscreen Mode
glutInit(&argc, argv); // GLUT Initializtion
glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | GLUT_DOUBLE); // (CHANGED)
if (! glutGet(GLUT_DISPLAY_MODE_POSSIBLE))
{
MessageBox(NULL,"Display mode not supported.","Error",MB_ICONSTOP);
return -1;
}
if (g_gamemode) {
glutGameModeString("640x480:32"); // Select The 640x480 In 32bpp Mode
if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE))
glutEnterGameMode(); // Enter Full Screen
else g_gamemode = false; // Cannot Enter Game Mode, Switch To Windowed
}
if (!g_gamemode) {
glutInitWindowSize(640, 480); // Window Size If We Start In Windowed Mode
glutCreateWindow("DSVL OpenGL/GLUT Sample. Press [c] to show/hide the rotating cube."); // Window Title
}
if (!init()) { // Our Initialization
MessageBox(NULL,"Cannot initialize textures.","Error",MB_ICONSTOP);
return -1;
}
if (!setup_dsWrapper(argc > 1 ? argv[1] : "")) { // DirectShow Capture Graph Initialization
MessageBox(NULL,"Cannot initialize capture graph.","Error",MB_ICONSTOP);
return -1;
}
glutDisplayFunc(render); // Register The Display Function
glutReshapeFunc(reshape); // Register The Reshape Handler
glutKeyboardFunc(keyboard); // Register The Keyboard Handler
glutSpecialFunc(special_keys); // Register Special Keys Handler
glutIdleFunc(render); // We Render In Idle Time
glutMainLoop(); // Go To GLUT Main Loop
return 0;
}