🎉 Celebrating 25 Years of GameDev.net! 🎉
Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!
OpenGL AVI texture mapper
Im new to these forums however I spent a hair pulling weekend trying to get compressed AVI's to play in windows. For some reason I couldnt get the NeHe tutorial to work on XVID AVI's.
In the interest of saving other people this pain and frustration I would like to post my AVI player as a sort of tutorial/sample code. Would this be the correct forum? It is written as a C++ class and uses the VFW interface. The other thing is that the hearder file is 6K and the class is 8K. Would this be too much to post in a CODE block?
What the heck. If this is the wrong forum I appoligize.
GLAvi.h
GLAvi.h
[source lang=cpp]/******************************************************************************* $Id:$ Date: $DATE$ Author: Neil Brideau <corn@shaw.ca> Project: Playing Compressed Avis in OpenGL WIN32 Description: Tutorial Demo Code. $Log:$*******************************************************************************/#ifndef _GL_AVI_H_INCLUDED_#define _GL_AVI_H_INCLUDED_// Includes ==================================================================/#include <stdio.h> #include <windows.h> // Windows#include <vfw.h> // Video For Windows#include <GL/gl.h> // OpenGL// Libraries =================================================================/ #pragma comment(lib, "vfw32.lib")#pragma comment(lib, "opengl32.lib")/** @class GLAvi Grabs compressed avi frames and places them in a texture using windows VFW interface. This is sample code. In the interest of simplicity the output format of the texture is limited to 1024x1024 at 24bits. I spent a whole weekend trying to play XVID videos in OpenGL for reasons still unknown to me I could not get NeHe's tutorial to work on compressed avi's. This method ended up working for me so I thought I would share. Usage: GLfloat coords[4];GLAvi * movie = NULL;// Make movie object and check initialization// Also get the suggested texture coordinatesbool Initialize(void) { movie = new GLAvi(); if (!movie->Init("Sacrifice.avi")) return false; movie->GetTexCrds(&coords[0]); return true;}// Draw a textured quad with current movie frame// using the suggested texture coordinatesbool Draw(GLvoid) { movie->GetNextFrame(GetTickCount()); glBegin(GL_QUADS); glTexCoord2f(coords[0], coords[2]); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(coords[1], coords[2]); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(coords[1], coords[3]); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(coords[0], coords[3]); glVertex3f(-1.0f, 1.0f, 1.0f); glEnd(); return true;}*/class GLAvi { /** @name Construktorz and Destruktorz @{ */ public: /** Default constructor */ GLAvi(void); /** Default destructor */ ~GLAvi(void); /** @} */ /** @name Public interface methods @{ */ public: /** Initialize the VFW interface. This method intializes vfw and generates a texture @param filename The filename of the avi we are to play @returns success... hopefully :) */ bool Init(const char * filename); /** Updates the texture with a new frame if necessary based on the FPS. Leaves texture bound @returns true on success or false if video is done. */ bool GetNextFrame(GLuint ticks); /** @} */ /** @name Accessor Methods Allows one to modify certain parameters or aquire certain parameters */ public: /** Used to set frames per second Turns into ticks per frame internally. This is set automagically by Init(). @param fps Frames per second */ void SetFPS(float fps); /** Seeks X seconds from the start of the avi Approximately @param seconds # seconds */ void SeekTime(int seconds); /** Changes current frame to frame X @param Frame # to use */ void SeekFrame(int frame); /** Returns the last frame # in the avi @returns Last frame number*/ unsigned int GetLastFrame(void); /** Returns width of avi */ int GetWidth(void); /** Returns height of avi */ int GetHeight(void); /** Returns texture object */ GLuint GetTex(void); /** Texture coordinate suggestion Methods to suggest texture coordinates. If you want to display the avi on a quad these can help X right , X left, Y Top, Y Bottom */ void GetTexCrds(GLfloat * crds); /** @} */ private: /** Internal reset mechanism */ void Reset(void); /** @name Private member variables @{ */ private: bool m_isinit; // Time syncronization routines int m_tpf; // Ticks per frame GLuint m_firsttick; // Tick we started at GLuint m_lasttick; // Tick stamp of last frame unsigned int m_currframe; // Current frame we are displaying unsigned int m_lastframe; // EOF private: // Output format and texture data GLuint m_tex; // Texture object int m_bpp; // Bytes per pixel output format 3 (24 bit) int m_dim; // Texture dimensions (Limiting to 1024x1024) unsigned char * m_texframe; // Pointer to our frame as a texture unsigned char * m_avidata; // Pointer to compressed avi frame private: // Windows VFW and AVIFILE data HIC m_hic; // Handle to our decompressor PAVISTREAM m_stream; // Handle to our avi stream LPBITMAPINFOHEADER m_outformat;// Contains decompressor output format LPBITMAPINFOHEADER m_informat; // Contains decompressor input format};#endif
GLAvi.cpp
[source lang=cpp]/******************************************************************************* $Id:$ Date: $DATE$ Author: Neil Brideau <corn@shaw.ca> Project: Playing Compressed Avis in OpenGL WIN32 Description: Tutorial Demo Code. $Log:$*******************************************************************************/#include "GLAvi.h"GLAvi::GLAvi(void) { m_isinit = false; m_firsttick = 0; m_lasttick = 0; m_currframe = 0; m_tpf = 0; m_tex = 0; m_bpp = 3; // 24 bits m_dim = 1024; // 1024 x 1024 texture m_stream = NULL; m_avidata = NULL; m_texframe = NULL; m_informat = NULL; m_outformat = NULL; // TODO Better memory alloc in Init m_avidata = new unsigned char[m_dim * m_dim * m_bpp]; if (!m_avidata) { printf("ERROR! MEMALLOC m_avidata \n"); return; } // TODO Better memory alloc in Init m_texframe = new unsigned char[m_dim * m_dim * m_bpp]; if (!m_texframe) { printf("ERROR! MEMALLOC m_texframe\n"); return; } memset(m_texframe, 0, m_dim * m_dim * m_bpp); memset(m_avidata, 0, m_dim * m_dim * m_bpp); AVIFileInit(); return;}GLAvi::~GLAvi(void) { Reset(); AVIFileExit(); delete [] m_avidata; delete [] m_texframe; return;}void GLAvi::Reset(void) { // Reset vars m_isinit = false; m_firsttick = 0; m_lasttick = 0; m_currframe = 0; m_tpf = 0; // Delete format structs delete [] m_informat; delete [] m_outformat; // Delete / release resources if (m_tex) glDeleteTextures(1, &m_tex); if (m_stream) AVIStreamRelease(m_stream); if (m_hic) ICDecompressEnd(m_hic); // Reset pointer and handles m_tex = 0; m_stream = NULL; m_hic = NULL; m_informat = NULL; m_outformat = NULL; return;}void GLAvi::SetFPS(float fps) { // Ticks per frame. Not the most accurate // but good enough for rock and roll m_tpf = (int)(1.0f / (fps / 1000.0f)); //m_tpf *= 2; return;}void GLAvi::SeekTime(int seconds) { m_currframe = seconds * 1000 / m_tpf; return;}void GLAvi::SeekFrame(int frame) { m_currframe = frame; return;}unsigned int GLAvi::GetLastFrame(void) { return m_currframe;}int GLAvi::GetWidth(void) { if (!m_isinit) return 0; return m_informat->biWidth;}int GLAvi::GetHeight(void) { if (!m_isinit) return 0; return m_informat->biHeight;}GLuint GLAvi::GetTex(void) { return m_tex;}void GLAvi::GetTexCrds(GLfloat * crds) { // For suggested texture coordinates TODO FIXME not done! // X Left crds[0] = 0.0f; // X Right crds[1] = 1.0f - ((float)(m_dim - m_informat->biWidth) / (float)m_dim); // Y Top crds[2] = -0.125f; // Y Bottom crds[3] = 1.125f - ((float)(m_dim - m_informat->biHeight) / (float)m_dim); return;}bool GLAvi::Init(const char * filename) { AVISTREAMINFO avi_info; // AVI stream information. Used for fps LONG size; // Size of AVI format header struct Reset(); // Open our avi stream if (AVIStreamOpenFromFile(&m_stream, filename, streamtypeVIDEO, 0, OF_READ, NULL)) { printf("[GLAvi::Init] AVIStreamOpenFromFile returned an error code\n"); return false; } // Get some information from avi stream if (AVIStreamInfo(m_stream, &avi_info, sizeof(avi_info))) { printf("[GLAvi::Init] AVIStreamInfo returned an error code\n"); return false; } // Set our frames per second SetFPS(((float)avi_info.dwRate / (float)avi_info.dwScale)); // Get our format header size with macro if (AVIStreamFormatSize(m_stream, 0, &size)) { printf("[GLAvi::Init] AVIStreamFormatSize returned an error code\n"); return false; } // Setup our format structs m_informat = (LPBITMAPINFOHEADER)new unsigned char[size]; m_outformat = (LPBITMAPINFOHEADER)new unsigned char[size]; if (!m_informat || !m_outformat) { printf("[GLAvi::Init] ERROR MEMALLOC m_format\n"); return false; } memset(m_outformat, 0, size); memset(m_informat, 0, size); // Read in our input format if (AVIStreamReadFormat(m_stream, 0, m_informat, &size)) { printf("[GLAvi::Init] AVIStreamReadFormat returned and error code\n"); return false; } // Since we dont want 2048x2048 textures we fail on large inputs if (m_informat->biWidth > 1024) { printf("[GLAvi::Init] Input size to large\n"); return false; } // Setup our output format m_outformat->biSize = size; // Sizof self (BITMAPINFOHEADER) m_outformat->biWidth = m_informat->biWidth; // Set output size to input size for now m_outformat->biHeight = m_informat->biHeight; // Set output size to input size for now m_outformat->biPlanes = 1; // RGB 1 plane m_outformat->biBitCount = m_bpp * 8; // Byts per pixel * 8 // Determine EOF m_lastframe = AVIStreamLength(m_stream); // Now use ICLocate to find an appropriate decompressor m_hic = ICLocate(ICTYPE_VIDEO, avi_info.fccHandler, m_informat, m_outformat, ICMODE_DECOMPRESS); if (!m_hic) { printf("[GLAvi::Init] ICLocate did not return a decompressor\n"); return false; } // Determine if decompressor will work on AVI stream if (ICDecompressQuery(m_hic, m_informat, m_outformat) != ICERR_OK) { printf("[GLAvi::Init] ICDecompressQuery failed cannot decompress format\n"); return false; } // Start our decompressor if (ICDecompressBegin(m_hic, m_informat, m_outformat) != ICERR_OK) { printf("[GLAvi::Init] ICDecompressBegin failed"); return false; } // Will become our frames texture glGenTextures(1, &m_tex); glBindTexture(GL_TEXTURE_2D, m_tex); // Build 1024 X 1024 24 bit texture. The decoder returns frames BGR so we use // The BL_BGR_EXT extension as our format glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_dim, m_dim, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, m_texframe); // Really nice quality filtering glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); m_isinit = true; return true;}/**/bool GLAvi::GetNextFrame(GLuint ticks) { if (!m_isinit) return false; if (m_currframe > m_lastframe) return false; // Auto bind texture for our caller :) glBindTexture(GL_TEXTURE_2D, m_tex); // See if we need to update out texture if ((ticks - m_lasttick) > m_tpf) { m_lasttick = ticks; m_currframe++; // Use AVI stream to read one frame into buffer; if (AVIStreamRead(m_stream, m_currframe, 1, m_avidata, m_dim * m_dim * m_bpp, NULL, NULL)) { printf("[GLAvi::GetNextFrame] AVIStreamRead returned an error"); return false; } // Decompress frame into our texture buffer if (ICDecompress(m_hic, 0, m_informat, m_avidata, m_outformat, m_texframe) != ICERR_OK) { printf("[GLAvi::GetNextFrame] ICDecompress returned an error"); return false; } // Update only the portion of our texture that changed glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_informat->biWidth, m_informat->biHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, m_texframe); } return true;}
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement