30 #include "theora/theora.h" 
   31 #include "vorbis/codec.h" 
   37 static int video_inited = 0;
 
   38 static int scale_video = 0;
 
   39 static int playing = 1;
 
   41 static uint g_screenWidth = 0;
 
   42 static uint g_screenHeight = 0;
 
   43 static int g_screenX = 0;
 
   44 static int g_screenY = 0;
 
   50 static GLint gl_screenYH = 0;
 
   51 static GLint gl_screenXW = 0;
 
   54 static GLfloat glVertices[4][4] = {{0}};
 
   59 static int timer_started = 0;
 
   62 static struct timeval timer_expire = { 0, 0 };
 
   64 static int timer_expire;
 
   67 static int audio_inited = 0;
 
   68 static int audio_buffer_tail = 0;
 
   69 static ALuint audio_sid = 0;
 
   70 #define OGG_AUDIO_BUFFERS       15 
   74 static int audiobuf_fill = 0;
 
   75 static short *audiobuf = NULL;
 
   76 static longlong audiobuf_granulepos = 0; 
 
   77 static int audiofd_fragsize = 0;
 
   80 static longlong videobuf_granulepos = -1;
 
   81 static double videobuf_time = 0;
 
   83 static bool use_shaders = 
true;
 
   92         int bytes = 
cfread(buffer, 1, 8192, movie->
cfp);
 
  113 static double OGG_get_time()
 
  119         gettimeofday(&tv, NULL);
 
  120         now = tv.tv_sec * 1000 + tv.tv_usec / 1000;
 
  125         return (now - base_time) * 0.001;
 
  134 static void OGG_timer_init()
 
  139         gettimeofday(&timer_expire, NULL);
 
  141         timer_expire.tv_usec += (
int)((videobuf_time - OGG_get_time()) * 1000000.0);
 
  143         if (timer_expire.tv_usec > 1000000) {
 
  144                 nsec = timer_expire.tv_usec / 1000000;
 
  145                 timer_expire.tv_sec += nsec;
 
  146                 timer_expire.tv_usec -= nsec * 1000000;
 
  150         timer_expire += (
int)((videobuf_time - OGG_get_time()) * 1000000.0);
 
  156 static void OGG_timer_do_wait()
 
  163         struct timespec ts, tsRem;
 
  166         gettimeofday(&tv, NULL);
 
  168         if (tv.tv_sec > timer_expire.tv_sec)
 
  171         if ( (tv.tv_sec == timer_expire.tv_sec) && (tv.tv_usec >= timer_expire.tv_usec) )
 
  174         ts.tv_sec = timer_expire.tv_sec - tv.tv_sec;
 
  175         ts.tv_nsec = 1000 * (timer_expire.tv_usec - tv.tv_usec);
 
  177         if (ts.tv_nsec < 0) {
 
  178                 ts.tv_nsec += 1000000000UL;
 
  182         if ( (nanosleep(&ts, &tsRem) == -1) && (errno == EINTR) ) {
 
  184                 if ( (nanosleep(&tsRem, NULL) == -1) && (errno == EINTR) ) {
 
  185                         mprintf((
"MVE: Timer error! Aborting movie playback!\n"));
 
  191     timer_expire.tv_usec += (
int)((videobuf_time - OGG_get_time()) * 1000000.0);
 
  193     if (timer_expire.tv_usec > 1000000) {
 
  194         nsec = timer_expire.tv_usec / 1000000;
 
  195         timer_expire.tv_sec += nsec;
 
  196         timer_expire.tv_usec -= nsec * 1000000;
 
  203         if (tv > timer_expire)
 
  206         ts = timer_expire - tv;
 
  213         timer_expire += (
int)((videobuf_time - OGG_get_time()) * 1000000.0);
 
  225 static void OGG_audio_init(vorbis_info *vinfo)
 
  239         audiofd_fragsize = (((vinfo->channels * 16) / 8) * vinfo->rate);
 
  241         audiobuf = (
short *) 
vm_malloc(audiofd_fragsize);
 
  244 static void OGG_audio_close()
 
  260                 if ( (audio_buffers[
i] != 0) && alIsBuffer(audio_buffers[
i]) ) {
 
  266         audio_buffer_tail = 0;
 
  269         audiobuf_granulepos = 0;
 
  270         audiofd_fragsize = 0;
 
  272         if (audiobuf != NULL) {
 
  278 static void OGG_audio_write(vorbis_info *vorbis, 
bool *ready)
 
  280         ALint status, queued, processed = 0;
 
  283         if ( !audio_inited || !(*ready) )
 
  286         OpenAL_ErrorCheck( alGetSourcei(audio_sid, AL_BUFFERS_PROCESSED, &processed), 
return );
 
  288         while (processed-- > 2)
 
  294         OpenAL_ErrorCheck( alGetSourcei(audio_sid, AL_BUFFERS_QUEUED, &queued), 
return );
 
  296         if ( audiobuf_fill && (queued < OGG_AUDIO_BUFFERS) ) {
 
  297                 if ( !audio_buffers[audio_buffer_tail] )
 
  300                 ALenum format = (vorbis->channels == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
 
  302                 OpenAL_ErrorCheck( alBufferData(audio_buffers[audio_buffer_tail], format, audiobuf, audiobuf_fill, vorbis->rate), 
return );
 
  304                 OpenAL_ErrorCheck( alSourceQueueBuffers(audio_sid, 1, &audio_buffers[audio_buffer_tail]), 
return );
 
  306                 if (++audio_buffer_tail == OGG_AUDIO_BUFFERS)
 
  307                         audio_buffer_tail = 0;
 
  317         OpenAL_ErrorCheck( alGetSourcei(audio_sid, AL_BUFFERS_QUEUED, &queued), 
return );
 
  319         if ( (status != AL_PLAYING) && (queued > 0) )
 
  331 static void OGG_video_init(theora_info *tinfo)
 
  333         float scale_by = 0.0f;
 
  340         g_screenWidth = tinfo->frame_width;
 
  341         g_screenHeight = tinfo->frame_height;
 
  361                         if ( ytex + utex + vtex == 0 ) {
 
  362                                 nprintf((
"MOVIE", 
"ERROR: Can't create a GL texture"));
 
  369                         if ( sdr_handle >= 0)
 
  381                                 nprintf((
"MOVIE", 
"ERROR: Can't create a GL texture"));
 
  439                 float movie_ratio = (
float)g_screenWidth / (
float)g_screenHeight;
 
  441                 if (screen_ratio > movie_ratio)
 
  464                         nprintf((
"MOVIE", 
"ERROR: Can't allocate memory for pixelbuf"));
 
  468                 memset( 
pixelbuf, 0, g_screenWidth * g_screenHeight * 3 );
 
  483                 gl_screenYH = g_screenY + g_screenHeight;
 
  484                 gl_screenXW = g_screenX + g_screenWidth;
 
  486                 gl_screenU = 
i2fl(g_screenWidth) / 
i2fl(wp2);
 
  487                 gl_screenV = 
i2fl(g_screenHeight) / 
i2fl(hp2);
 
  490                         gl_screenU = 
i2fl(tinfo->frame_width-1) / 
i2fl(2048) ;
 
  491                         gl_screenV = 
i2fl(tinfo->frame_height-1) / 
i2fl(2048);
 
  498                 glVertices[0][0] = (
GLfloat)g_screenX;
 
  499                 glVertices[0][1] = (
GLfloat)g_screenY;
 
  500                 glVertices[0][2] = 0.0f;
 
  501                 glVertices[0][3] = 0.0f;
 
  503                 glVertices[1][0] = (
GLfloat)g_screenX;
 
  504                 glVertices[1][1] = (
GLfloat)gl_screenYH;
 
  505                 glVertices[1][2] = 0.0f;
 
  506                 glVertices[1][3] = gl_screenV;
 
  508                 glVertices[2][0] = (
GLfloat)gl_screenXW;
 
  509                 glVertices[2][1] = (
GLfloat)g_screenY;
 
  510                 glVertices[2][2] = gl_screenU;
 
  511                 glVertices[2][3] = 0.0f;
 
  513                 glVertices[3][0] = (
GLfloat)gl_screenXW;
 
  514                 glVertices[3][1] = (
GLfloat)gl_screenYH;
 
  515                 glVertices[3][2] = gl_screenU;
 
  516                 glVertices[3][3] = gl_screenV;
 
  527         if(!use_shaders && tinfo->frame_height > 450) {
 
  528                 mprintf((
"VIDEO: No shader support and hd video is beeing played this can get choppy."));
 
  533 static void OGG_video_close()
 
  535         if ( !video_inited ) {
 
  559                 ytex = utex = vtex = 0;
 
  584 static void convert_YUV_to_RGB(yuv_buffer *yuv)
 
  587         int R = 0, G = 0, 
B = 0;
 
  590         uint width_2 = g_screenWidth/2;
 
  598         for (y = 0; y < g_screenHeight; y++) {
 
  599                 for (x = 0; x < width_2; x++) {
 
  601                         Y1 = *y_ptr; y_ptr++;
 
  602                         Y2 = *y_ptr; y_ptr++;
 
  614                         R = ((C           + 409 * E + 128) >> 8);
 
  615                         G = ((C - 100 * D - 208 * E + 128) >> 8);
 
  616                         B = ((C + 516 * D           + 128) >> 8);
 
  629                         R = ((C           + 409 * E + 128) >> 8);
 
  630                         G = ((C - 100 * D - 208 * E + 128) >> 8);
 
  631                         B = ((C + 516 * D           + 128) >> 8);
 
  642                 y_ptr += (yuv->y_stride - yuv->y_width);
 
  646                         u_ptr += yuv->uv_stride;
 
  647                         v_ptr += yuv->uv_stride;
 
  653 static void OGG_video_draw(theora_state *tstate)
 
  657         theora_decode_YUVout(tstate, &yuv);
 
  659                 convert_YUV_to_RGB(&yuv);
 
  704         videobuf_granulepos = -1;
 
  710                 vorbis_block_clear(&movie->
vblock);
 
  711                 vorbis_dsp_clear(&movie->
vstate);
 
  712                 vorbis_comment_clear(&movie->
vcomment);
 
  713                 vorbis_info_clear(&movie->
vinfo);
 
  719                 theora_clear(&movie->
tstate);
 
  720                 theora_comment_clear(&movie->
tcomment);
 
  721                 theora_info_clear(&movie->
tinfo);
 
  754         memset( lower_name, 0, 
sizeof(lower_name) );
 
  755         strncpy( lower_name, filename, 
sizeof(lower_name)-1 );
 
  758         char *p = strchr( lower_name, 
'.' );
 
  768         if (movie->
cfp == NULL)
 
  771         if (movie->
cfp == NULL) {
 
  772                 mprintf((
"Theora ERROR:  Unable to find and open movie file named '%s'\n", lower_name));
 
  780         vorbis_info_init(&movie->
vinfo);
 
  781         vorbis_comment_init(&movie->
vcomment);
 
  784         theora_comment_init(&movie->
tcomment);
 
  785         theora_info_init(&movie->
tinfo);
 
  789         while ( !stateflag ) {
 
  790                 int ret = OGG_buffer_data(movie);
 
  796                         ogg_stream_state test;
 
  799                         if ( !ogg_page_bos(&movie->
opage) ) {
 
  801                                 OGG_queue_page(movie);
 
  806                         ogg_stream_init(&test, ogg_page_serialno(&movie->
opage));
 
  807                         ogg_stream_pagein(&test, &movie->
opage);
 
  808                         ogg_stream_packetout(&test, &movie->
opacket);
 
  813                                 memcpy( &movie->
t_osstate, &test, 
sizeof(test) );
 
  817                                 memcpy( &movie->
v_osstate, &test, 
sizeof(test) );
 
  821                                 ogg_stream_clear(&test);
 
  829                 mprintf((
"Theora ERROR: Unable to find video data in '%s'\n", lower_name));
 
  834         if ( (movie->
vinfo.channels < 0) || (movie->
vinfo.channels > 2) ) {
 
  835                 mprintf((
"Theora ERROR:  Unsupported number of audio channels!\n"));
 
  841                 vorbis_info_clear(&movie->
vinfo);
 
  842                 vorbis_comment_clear(&movie->
vcomment);
 
  853                 while ( (movie->
theora_p < 3) && (ret) ){
 
  855                                 mprintf((
"Theora ERROR:  Error parsing Theora stream headers on '%s'!  Corrupt stream?\n", lower_name));
 
  869                         if ( (ret < 0) || vorbis_synthesis_headerin(&movie->
vinfo, &movie->
vcomment, &movie->
opacket) ) {
 
  870                                 mprintf((
"Theora ERROR:  Error parsing Vorbis stream headers on '%s'!  Corrupt stream?\n", lower_name));
 
  883                         OGG_queue_page(movie); 
 
  885                         ret = OGG_buffer_data(movie); 
 
  888                                 mprintf((
"Theora ERROR:  End of file while searching for codec headers in '%s'!\n", lower_name));
 
  898         if (movie->
tinfo.pixelformat != OC_PF_420) {
 
  899                 mprintf((
"Theora ERROR:  Only the yuv420p chroma is supported!\n"));
 
  903         if (movie->
tinfo.offset_x || movie->
tinfo.offset_y) {
 
  904                 mprintf((
"Theora ERROR:  Player does not support frame offsets!\n"));
 
  910                 vorbis_synthesis_init(&movie->
vstate, &movie->
vinfo);
 
  927         bool stateflag = 
false;
 
  928         bool videobuf_ready = 
false;
 
  929         bool audiobuf_ready = 
false;
 
  930         double last_time = 0.0; 
 
  932         if ( (movie == NULL) || !movie->
theora_p )
 
  941                 OGG_audio_init(&movie->
vinfo);
 
  944         OGG_video_init(&movie->
tinfo);
 
  956                 while ( movie->
vorbis_p && !audiobuf_ready ) {
 
  961                         if ( (ret = vorbis_synthesis_pcmout(&movie->
vstate, &pcm)) > 0 ) {
 
  962                                 int count = (audiobuf_fill / 2);
 
  963                                 int maxsamples = (audiofd_fragsize - audiobuf_fill) / 2 / movie->
vinfo.channels;
 
  965                                 for (i = 0; (i < ret) && (i < maxsamples); i++) {
 
  966                                         for (j = 0; j < movie->
vinfo.channels; j++) {
 
  967                                                 float val = pcm[j][
i] * 32767.0f + 0.5f;
 
  975                                                 audiobuf[count++] = (short)val;
 
  979                                 vorbis_synthesis_read(&movie->
vstate, i);
 
  981                                 audiobuf_fill += (i * movie->
vinfo.channels * 2);
 
  983                                 if (audiobuf_fill == audiofd_fragsize)
 
  984                                         audiobuf_ready = 
true;
 
  986                                 if (movie->
vstate.granulepos >= 0)
 
  987                                         audiobuf_granulepos = movie->
vstate.granulepos - ret + 
i;
 
  989                                         audiobuf_granulepos += 
i;
 
  993                                         if ( vorbis_synthesis(&movie->
vblock, &movie->
opacket) == 0 )
 
  994                                                 vorbis_synthesis_blockin(&movie->
vstate, &movie->
vblock);
 
 1003                 while ( !videobuf_ready ) {
 
 1010                         videobuf_time = theora_granule_time(&movie->
tstate, movie->
tstate.granulepos);
 
 1012                         double now_time = OGG_get_time();
 
 1013                         double delay = videobuf_time - OGG_get_time();
 
 1016                         if ( (delay >= 0.0) || (now_time - last_time >= 1.0) )
 
 1017                                 videobuf_ready = 
true;
 
 1020                 if ( !videobuf_ready && (movie->
vorbis_p && !audiobuf_ready) && 
cfeof(movie->
cfp) )
 
 1023                 if ( !videobuf_ready || (movie->
vorbis_p && !audiobuf_ready) ) {
 
 1025                         OGG_buffer_data(movie);
 
 1028                                 OGG_queue_page(movie);
 
 1033                         OGG_audio_write(&movie->
vinfo, &audiobuf_ready);
 
 1036                 if ( stateflag && videobuf_ready && (videobuf_time <= OGG_get_time()) ) {
 
 1037                         OGG_video_draw(&movie->
tstate);
 
 1038                         last_time = OGG_get_time();
 
 1039                         videobuf_ready = 
false;
 
 1043                 if ( videobuf_ready && (audiobuf_ready || !movie->
vorbis_p) )
 
 1051                         OGG_timer_do_wait();
 
GLenum GLsizei GLenum format
 
#define OGG_AUDIO_BUFFERS
 
ogg_stream_state v_osstate
 
#define vm_malloc_q(size)
 
#define OpenAL_ErrorCheck(x, y)
 
WINGDIAPI void APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count)
 
int cfread(void *buf, int elsize, int nelem, CFILE *fp)
 
void Color(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha=255)
 
void SetTextureSource(gr_texture_source ts)
 
WINGDIAPI void APIENTRY glMatrixMode(GLenum mode)
 
int timer_get_microseconds()
 
void theora_close(THEORAFILE *movie)
 
WINGDIAPI void APIENTRY glLoadIdentity(void)
 
WINGDIAPI void APIENTRY glDeleteTextures(GLsizei n, const GLuint *textures)
 
#define gr_maybe_create_shader
 
void SetZbufferType(gr_zbuffer_type zt)
 
#define OpenAL_ErrorPrint(x)
 
ALuint *typedef ALuint *typedef ALenum
 
opengl_texture_state Texture
 
#define GL_TEXTURE_WRAP_S
 
WINGDIAPI void APIENTRY glPopMatrix(void)
 
#define CLAMP(x, min, max)
 
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
 
void add_vertex_component(vertex_format_data::vertex_format format_type, uint stride, void *src)
 
ALuint *typedef ALuint *typedef ALint
 
ogg_stream_state t_osstate
 
ogg_sync_state osyncstate
 
WINGDIAPI void APIENTRY glGenTextures(GLsizei n, GLuint *textures)
 
void SetAlphaBlendMode(gr_alpha_blend ab)
 
void opengl_tcache_get_adjusted_texture_size(int w_in, int h_in, int *w_out, int *h_out)
 
WINGDIAPI void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
 
#define GL_TEXTURE_MAG_FILTER
 
opengl_uniform_state Uniform
 
void SetTarget(GLenum tex_target)
 
GLint GLint GLint GLint GLint x
 
for(int idx=0;idx< i;idx++)
 
THEORAFILE * theora_open(char *filename)
 
void Enable(GLuint tex_id=0)
 
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
 
void BindArrayBuffer(GLuint id)
 
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
 
#define GL_TEXTURE_WRAP_T
 
void theora_play(THEORAFILE *movie)
 
WINGDIAPI void APIENTRY glPushMatrix(void)
 
#define GL_TEXTURE_MIN_FILTER
 
void opengl_set_texture_target(GLenum target)
 
void SetShaderMode(GLboolean mode)
 
void Delete(GLuint tex_id)
 
WINGDIAPI void APIENTRY glScalef(GLfloat x, GLfloat y, GLfloat z)
 
WINGDIAPI void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
 
WINGDIAPI void APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param)
 
bool is_minimum_GLSL_version()
 
void opengl_shader_set_current(opengl_shader_t *shader_obj)
 
int cfclose(CFILE *cfile)
 
int timer_get_milliseconds()
 
void opengl_bind_vertex_layout(vertex_layout &layout)
 
void SetActiveUnit(GLuint id=0)
 
#define GL_TRIANGLE_STRIP