🎉 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

Started by
1 comment, last by lunix 18 years, 3 months ago
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?
Advertisement
What the heck. If this is the wrong forum I appoligize.

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