Wrecked Games
September 05, 2010, 03:51:06 PM *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
News: We're just that awesome.
 
   Home   Help Search Members Login Register  
Pages: [1]
  Print  
Author Topic: use of theora plugin with modification ( people are now a bit blue )  (Read 789 times)
shibby
Newbie
*
Posts: 1


View Profile
« on: July 30, 2008, 12:16:34 AM »

Hello,

I took the theora plugin for ogre and adapt it to my need, I delete all vorbis function, took only the movieclip / driver / seekUtility, and now my driver does not blit the image to memory, but construct a unsigned char* (pixels array) that i use late to texture something.
So I did not change the algo for decodage, but I got the skin of people on video a bit blue :-s
And when I use the seeking, I have like 3 seconds where I have only 1 fps, after the decodage works fine.

I am totally noob in theora so I have problem to find why people are blue...
Here is my driver code :

Quote
#include "OMKTheoraDriver.h"
#include "OMKTracer.h"

#include "OgreTimer.h"
#include "OgreHardwarePixelBuffer.h"

//Defines
#define MAX( a, b ) ((a > b) ? a : b)
#define MIN( a, b ) ((a < b) ? a : b)


#define CLIP_RGB_COLOR( rgb_color_test, rgb_char_buffer ) \
   rgb_char_buffer = MAX( MIN(rgb_color_test, 255), 0 )


using namespace OMK::Theora ;

//Handle static member vars
unsigned int TheoraDriver::YTable[ 256 ];
unsigned int TheoraDriver::BUTable[ 256 ];
unsigned int TheoraDriver::GUTable[ 256 ];
unsigned int TheoraDriver::GVTable[ 256 ];
unsigned int TheoraDriver::RVTable[ 256 ];

//------------------------------------------------------------------//
TheoraDriver::TheoraDriver() :
   m_RGBBitmap(0),
   m_Width(0),
   m_Height(0),
  newTextureSize(0)
{
}

//------------------------------------------------------------------//
TheoraDriver::~TheoraDriver()
{
   delete [] m_RGBBitmap;
   m_RGBBitmap = 0;
}
   
//------------------------------------------------------------------//
void TheoraDriver::createPixelArray(
   int width, int height )
{
  createCoefTables( ) ;
   m_Width = width;
   m_Height = height;

   newTextureSize = width * height;
  Ogre::PixelFormat pFormat;

   m_BytesPerPixel = 3;
   newTextureSize *=3;      //RGB Texture
  pFormat = Ogre::PF_B8G8R8;   //PF_R8G8B8;

   //Create our member bitmap memory      
   m_RGBBitmap = new unsigned char[ newTextureSize ] ;
   memset( m_RGBBitmap, 0, newTextureSize );
}


//----------------------------------------------------------------------//
void TheoraDriver::renderToTexture( yuv_buffer *buffer, unsigned char **pixelForTexture )
{
   *(pixelForTexture) = decodeYUVtoTexture( buffer ) ;
}


//----------------------------------------------------------------------//
unsigned char* TheoraDriver::decodeYUVtoTexture( yuv_buffer *yuv )
{
   //Convert 4:2:0 YUV YCrCb to an RGB24 Bitmap
   //convenient pointers
   unsigned char *dstBitmap = m_RGBBitmap;
   unsigned char *dstBitmapOffset = m_RGBBitmap + (m_BytesPerPixel * m_Width);

   unsigned char *ySrc = (unsigned char*)yuv->y,
              *uSrc = (unsigned char*)yuv->u,
              *vSrc = (unsigned char*)yuv->v,
              *ySrc2 = ySrc + yuv->y_stride;
   
   //Calculate buffer offsets
   unsigned int dstOff = m_Width * m_BytesPerPixel;//( m_Width*6 ) - ( yuv->y_width*3 );
   int yOff = (yuv->y_stride * 2) - yuv->y_width;
      
   
   //Check if upside down, if so, reverse buffers and offsets
   if ( yuv->y_height < 0 )
   {
      yuv->y_height = -yuv->y_height;
      ySrc       += (yuv->y_height - 1) * yuv->y_stride;
      
      uSrc += ((yuv->y_height / 2) - 1) * yuv->uv_stride;
      vSrc += ((yuv->y_height / 2) - 1) * yuv->uv_stride;
      
      ySrc2 = ySrc - yuv->y_stride;
      yOff  = -yuv->y_width - ( yuv->y_stride * 2 );
      
      yuv->uv_stride = -yuv->uv_stride;
   }

   //Cut width and height in half (uv field is only half y field)
   yuv->y_height = yuv->y_height >> 1;
   yuv->y_width = yuv->y_width >> 1;

   //Convientient temp vars
   signed int r, g, b, u, v, bU, gUV, rV, rgbY;
   int x;
   
   //Loop does four blocks per iteration (2 rows, 2 pixels at a time)
   for (int y = yuv->y_height; y > 0; --y)
   {
      for (x = 0; x < yuv->y_width; ++x)
      {
         //Get uv pointers for row
         u = uSrc
  • ;
         v = vSrc
  • ;
         
         //get corresponding lookup values
         rgbY= YTable[*ySrc];            
         rV  = RVTable[v];
         gUV = GUTable + GVTable[v];
         bU  = BUTable;
         ++ySrc;

         //scale down - brings are values back into the 8 bits of a byte
         r = (rgbY + rV ) >> 13;
         g = (rgbY - gUV) >> 13;
         b = (rgbY + bU ) >> 13;
         
         //Clip to RGB values (255 0)
         CLIP_RGB_COLOR( r, dstBitmap[0] );
         CLIP_RGB_COLOR( g, dstBitmap[1] );
         CLIP_RGB_COLOR( b, dstBitmap[2] );

      int test = MAX( MIN(r, 255), 0 ) ;
         
         //And repeat for other pixels (note, y is unique for each
         //pixel, while uv are not)
         rgbY = YTable[*ySrc];
         r = (rgbY + rV)  >> 13;
         g = (rgbY - gUV) >> 13;
         b = (rgbY + bU)  >> 13;
         CLIP_RGB_COLOR( r, dstBitmap[m_BytesPerPixel] );
         CLIP_RGB_COLOR( g, dstBitmap[m_BytesPerPixel+1] );
         CLIP_RGB_COLOR( b, dstBitmap[m_BytesPerPixel+2] );
         ++ySrc;

         rgbY = YTable[*ySrc2];
         r = (rgbY + rV)  >> 13;
         g = (rgbY - gUV) >> 13;
         b = (rgbY + bU)  >> 13;
         CLIP_RGB_COLOR( r, dstBitmapOffset[0] );
         CLIP_RGB_COLOR( g, dstBitmapOffset[1] );
         CLIP_RGB_COLOR( b, dstBitmapOffset[2] );
         ++ySrc2;
         
         rgbY = YTable[*ySrc2];
         r = (rgbY + rV)  >> 13;
         g = (rgbY - gUV) >> 13;
         b = (rgbY + bU)  >> 13;
         CLIP_RGB_COLOR( r, dstBitmapOffset[m_BytesPerPixel] );
         CLIP_RGB_COLOR( g, dstBitmapOffset[m_BytesPerPixel+1] );
         CLIP_RGB_COLOR( b, dstBitmapOffset[m_BytesPerPixel+2] );
         ++ySrc2;

         //Advance inner loop offsets
         dstBitmap += m_BytesPerPixel << 1;
         dstBitmapOffset += m_BytesPerPixel << 1;
      } // end for x

      //Advance destination pointers by offsets
      dstBitmap      += dstOff;
      dstBitmapOffset += dstOff;
      ySrc         += yOff;
      ySrc2         += yOff;
      uSrc         += yuv->uv_stride;
      vSrc         += yuv->uv_stride;
   } //end for y

  return m_RGBBitmap ;
}

//----------------------------------------------------------------------//
void TheoraDriver::createCoefTables()
{
   //used to bring the table into the high side (scale up) so we
   //can maintain high precision and not use floats (FIXED POINT)
   int scale = 1L << 13,
      temp;
   
   for ( unsigned int i = 0; i < 256; i++ )
   {
      temp = i - 128;
      
      YTable  = (unsigned int)((1.164 * scale + 0.5) * (i - 16));   //Calc Y component
      
      RVTable = (unsigned int)((1.596 * scale + 0.5) * temp);      //Calc R component
      
      GUTable = (unsigned int)((0.391 * scale + 0.5) * temp);      //Calc G u & v components
      GVTable = (unsigned int)((0.813 * scale + 0.5) * temp);
      
      BUTable = (unsigned int)((2.018 * scale + 0.5) * temp);      //Calc B component
   }
}

Here is my movie clip code :

Quote
#include "OgreResourceGroupManager.h"
#include "OgreStringConverter.h"
#include "OgreTimer.h"

#include "OMKTheoraMovieClip.h"

#include "OMKTheoraDriver.h"
#include "OMKTracer.h"


using namespace OMK::Theora ;

//--------------------------------------------------------------------//
TheoraMovieClip::TheoraMovieClip() :
   //pt::thread( false ),
   mPlayMode(TextureEffectPause),
   m_FrameNum(0),
   m_FramesDropped(0),
   m_lastFrameTime(0.0f),
   m_EndOfVideo(false),
   m_EndOfFile(false),
   m_theora_streams(0),
   m_VideoFrameReady(false),
   videobuf_time(0.0f),
  pixels( 0 ),
  readyToBeTextured(false),
   m_Timer(0),
  mMovieLength(0)
{
   //Ensure all structures get cleared out. Already bit me in the arse Wink
   memset( &m_oggSyncState, 0, sizeof( ogg_sync_state ) );
   memset( &m_oggPage, 0, sizeof( ogg_page ) );
   memset( &m_theoraStreamState, 0, sizeof( ogg_stream_state ) );
   memset( &m_theoraInfo, 0, sizeof( theora_info ) );
   memset( &m_theoraComment, 0, sizeof( theora_comment ) );
   memset( &m_theoraState, 0, sizeof( theora_state ) );

   mDoSeek = false ;
  _seeker = 0 ;
}

//--------------------------------------------------------------------//
TheoraMovieClip::~TheoraMovieClip()
{
   changePlayMode( TextureEffectPause );

  if( m_Timer )
      delete m_Timer;

   m_Timer = 0;
   
   close();
}

bool TheoraMovieClip::grabANewImage( unsigned char** resPixels, int &height, int &width )
{
  bool res = false;
  blitFrameCheck ( ) ;
  if ( readyToBeTextured )
  {
    res = true ;
    *(resPixels) = pixels ;
    height = m_videoInterface.getHeight( ) ;
    width = m_videoInterface.getWidth( )  ;
    readyToBeTextured = false ;
  }
  return res;
}

//--------------------------------------------------------------------//   
void TheoraMovieClip::createMovieClip(
  const std::string &sMovieName,   const std::string &sGroupName )
{
   mMovieName = sMovieName;

   load( mMovieName, sGroupName );   

   _seeker = new TheoraSeekUtility( m_oggFile, &m_oggSyncState,
   &m_theoraStreamState, &m_theoraInfo,   &m_theoraState ) ;

  if( _seeker )
  {
         mMovieLength = _seeker->buildTheoraSeekMap();
  }

   // Attach our video to a texture unit
   m_videoInterface.createPixelArray(  m_theoraInfo.width,
      m_theoraInfo.height );

  changePlayMode( TextureEffectPause ) ;
}

//--------------------------------------------------------------------//
void TheoraMovieClip::load( const std::string& filename,
                           const std::string& groupName )
{
   //ensure a file is not already open
   /*if( !(m_oggFile.isNull()) )
          OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, "File name already loded! " + filename, "TheoraMovieClip::load" );*/
  OMASSERTM(m_oggFile.isNull() , "File name already loaded! "  ) ;
   m_EndOfFile = false;
  m_oggFile = Ogre::ResourceGroupManager::getSingleton().openResource( filename, groupName );

   initTheoraLayer( ) ;
   parseTheoraHeaders( ) ;
   activateTheoraCodecs( ) ;

}

//--------------------------------------------------------------------//
void TheoraMovieClip::initTheoraLayer( )
{
   //start up Ogg stream synchronization layer
   ogg_sync_init( &m_oggSyncState );
   //init supporting Theora structures needed in header parsing
   theora_comment_init(&m_theoraComment);
   theora_info_init(&m_theoraInfo);
}

//--------------------------------------------------------------------//
void TheoraMovieClip::parseTheoraHeaders( )
{
   ogg_packet tempOggPacket;
   bool NotDone = true;

   while( NotDone )
   {
      char *buffer = ogg_sync_buffer( &m_oggSyncState, 4096);
      int bytesRead = m_oggFile->read( buffer, 4096 );
      ogg_sync_wrote( &m_oggSyncState, bytesRead );
   
      if( bytesRead == 0 )
         break;
   
      while( ogg_sync_pageout( &m_oggSyncState, &m_oggPage ) > 0 )
      {
         ogg_stream_state OggStateTest;
          
         //is this an initial header? If not, stop
         if( !ogg_page_bos( &m_oggPage ) )
         {
            //This is done blindly, because stream only accept them selfs
            if(m_theora_streams)
               ogg_stream_pagein( &m_theoraStreamState, &m_oggPage );
            
            NotDone = false;
            break;
         }
   
         ogg_stream_init( &OggStateTest, ogg_page_serialno( &m_oggPage ) );
         ogg_stream_pagein( &OggStateTest, &m_oggPage );
         ogg_stream_packetout( &OggStateTest, &tempOggPacket );

         //identify the codec
         if( !m_theora_streams &&
            theora_decode_header( &m_theoraInfo, &m_theoraComment, &tempOggPacket) >=0 )
         {
            //This is the Theora Header
            memcpy( &m_theoraStreamState, &OggStateTest, sizeof(OggStateTest));
            m_theora_streams = 1;
         }
         else
         {
            //Hmm. I guess it's not a header we support, so erase it
            ogg_stream_clear(&OggStateTest);
         }
      } //end while ogg_sync_pageout
   } //end while notdone

   while( (m_theora_streams && (m_theora_streams < 3)) )
   {
      //Check 2nd'dary headers... Theora First
      int iSuccess;
      while( m_theora_streams &&
          ( m_theora_streams < 3) &&
          ( iSuccess = ogg_stream_packetout( &m_theoraStreamState, &tempOggPacket)) )
      {
     
      /*   if( iSuccess < 0 )
            OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, "Error parsing Theora stream headers.",
               "TheoraMovieClip::parseVorbisTheoraHeaders" );

         if( theora_decode_header(&m_theoraInfo, &m_theoraComment, &tempOggPacket) )
            OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, "invalid stream",
               "TheoraMovieClip::parseVorbisTheoraHeaders ");
*/
      OMASSERTM( iSuccess != 0 , "Error parsing Theora stream headers." ) ;
      OMASSERTM( !theora_decode_header(&m_theoraInfo, &m_theoraComment, &tempOggPacket) , "invalid stream" ) ;


         m_theora_streams++;         
      } //end while looking for more theora headers
   
      //Not finished with Headers, get some more file data
      if( ogg_sync_pageout( &m_oggSyncState, &m_oggPage ) > 0 )
      {
         if(m_theora_streams)
            ogg_stream_pagein( &m_theoraStreamState, &m_oggPage );
      }
      else
      {
         char *buffer = ogg_sync_buffer( &m_oggSyncState, 4096);
         int bytesRead = m_oggFile->read( buffer, 4096 );
         ogg_sync_wrote( &m_oggSyncState, bytesRead );

         /*if( bytesRead == 0 )
            OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, "End of file found prematurely",
               "TheoraMovieClip::parseVorbisTheoraHeaders " );*/
      OMASSERTM( bytesRead != 0 , "End of file found prematurely" ) ;
      }
   } //end while looking for all headers

  std::string temp = Ogre::StringConverter::toString( m_theora_streams );
   OMTRACEID("Theora" , " Theora Headers : " << temp);
}

//--------------------------------------------------------------------//
void TheoraMovieClip::activateTheoraCodecs( )
{
   if( m_theora_streams )
      theora_decode_init( &m_theoraState, &m_theoraInfo );
}

//--------------------------------------------------------------------//
void TheoraMovieClip::changePlayMode( eTexturePlayMode eMode )
{
   //TextureEffectPause = 0,         //! Video starts out paused
   //TextureEffectPlay_ASAP = 1,      //! Video starts playing as soon as posible
   //TextureEffectPlay_Looping = 2      //! Video Plays Instantly && Loops

   if( mPlayMode == eMode )
      return;

   //If current mode is paused than - sent mode must either be loop, or playASAP
   if( mPlayMode == TextureEffectPause )
   {
      mPlayMode = eMode;
   }
   else if( eMode == TextureEffectPause )
   {      
      mPlayMode = eMode;
   }
}

//--------------------------------------------------------------------//   
void TheoraMovieClip::blitFrameCheck()
{
  static int lastCallThisFunction = 0.0f ;
  static int timeJustHere = 0.0f ;
  timeJustHere = getMSTime( ) ;
  if ( mPlayMode != TextureEffectPause && ( timeJustHere - lastCallThisFunction > 40 ) )
    // 40 ms is the time for 24 images secondes, so it's enough
  {
    getNewTheoraData( ) ;
     if( m_VideoFrameReady )
     {
      lastCallThisFunction = timeJustHere ;
      pixels = 0 ;
        yuv_buffer yuv;
        theora_decode_YUVout( &m_theoraState, &yuv ) ;
        m_videoInterface.renderToTexture( &yuv, &pixels ) ;
      readyToBeTextured = true ;
        m_VideoFrameReady = false ;
        m_lastFrameTime = getMovieTime( ) ;
     }
  }
}

void TheoraMovieClip::getNewTheoraData( )
{
  int bytesRead = 1;

  if( mDoSeek && _seeker )
   {
      float seekedTo = _seeker->doSeek( mSeekTime );
      mDoSeek = false;
      m_EndOfFile = false;
   }

  if( !m_VideoFrameReady && m_theora_streams )
         decodeTheora();

   //Buffer data into Ogg Pages
   if( bytesRead > 0 )
   {
      char *buffer = ogg_sync_buffer( &m_oggSyncState, 4096);
      bytesRead = m_oggFile->read( buffer, 4096 );
      ogg_sync_wrote( &m_oggSyncState, bytesRead );

      while ( ogg_sync_pageout( &m_oggSyncState, &m_oggPage ) > 0 )
      {
         if(m_theora_streams)
            ogg_stream_pagein( &m_theoraStreamState, &m_oggPage );
      }
   }
   else
   {
      m_EndOfFile = true;
   }
}


//--------------------------------------------------------------------//
void TheoraMovieClip::decodeTheora()
{
   ogg_packet opTheora;

   for(;Wink
   {
      //get one video packet...
      if( ogg_stream_packetout( &m_theoraStreamState, &opTheora) > 0 )
      {
             theora_decode_packetin( &m_theoraState, &opTheora );
         videobuf_time = theora_granule_time( &m_theoraState, m_theoraState.granulepos );

         //update the frame counter
         m_FrameNum++;

         //check if this frame time has not passed yet.
         //If the frame is late we need to decode additonal
         //ones and keep looping, since theora at this stage
         //needs to decode all frames
         
         //gran time & our time is in seconds
         float nowTime = getMovieTime();
         float delay = videobuf_time - nowTime;
            
         if( delay >= 0.0f )
         {
            //got a good frame, within time window
            m_VideoFrameReady = true;
            break;
         }
         else if( nowTime - m_lastFrameTime >= 1.0f )
         {
            //display at least one frame per second, regardless
            m_VideoFrameReady = true;
            break;
         }
         else //frame is dropped
         {
            m_FramesDropped++;
         }
      }
      else
      {
         if( m_EndOfFile )
         {
            m_EndOfVideo = true;
         }


         //need more data
         break;
      }
   }
}

//--------------------------------------------------------------------//
float TheoraMovieClip::getMovieTime()
{
   if ( m_Timer )
   {
      return m_Timer->getMilliseconds() / 1000.0f;
   }
   else
   {
      //Initialize timer variable first time up
    m_Timer = new Ogre::Timer();
      m_Timer->reset();
      return 0.0f;
   }
}

//--------------------------------------------------------------------//
float TheoraMovieClip::getMSTime()
{
   if ( m_Timer )
   {
      return m_Timer->getMilliseconds();
   }
   else
   {
      //Initialize timer variable first time up
    m_Timer = new Ogre::Timer();
      m_Timer->reset();
      return 0.0f;
   }
}

//--------------------------------------------------------------------//
void TheoraMovieClip::close()
{
   m_EndOfFile = false ;

   delete _seeker ;
   _seeker = 0 ;

   m_oggFile.setNull();


   if(m_theora_streams)
   {
      ogg_stream_clear( &m_theoraStreamState );
      theora_clear( &m_theoraState );
      theora_comment_clear( &m_theoraComment );
      theora_info_clear( &m_theoraInfo );

      m_theora_streams = 0;
   }

   ogg_sync_clear( &m_oggSyncState );
}


void TheoraMovieClip::seekToTime( float seconds )
{
   //No point seeking to the end.. were already there
   if( seconds >= mMovieLength || seconds < 0.0f )
      return;
   
   //If seeking is not enabled, just return
   if( !_seeker )
      return;

   //Sets seeking flag on for thread to know & carry out later
   mDoSeek = true;
   mSeekTime = seconds;
}


And each time I need to see a new Image I call
Quote
res = _videoClip->grabANewImage( &pixels, height, width );

And all this is initialised like this :
Quote
  _videoClip = new TheoraMovieClip( ) ;

  _videoClip->createMovieClip( _fileName, _groupName ) ;



Since I did not change the decode function, I don't understand why I have this problem with color... The seeking is smooth for you ?


shibby :-)
Logged
pjcast
Administrator
Veteran
*****
Posts: 2544



View Profile WWW
« Reply #1 on: July 30, 2008, 06:24:42 PM »

I can think of a couple reasons for wrong colors.

1) Maybe you are using a different Pixel Format (ie instead of RGB, BGR or some such) than you think.
2) Your YUV to RGB has wrong conversion.
3) Your video is messed up (try playing in VLC).
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.11 | SMF © 2006-2009, Simple Machines LLC Valid XHTML 1.0! Valid CSS!