cl_cinematic_ogm.c

Go to the documentation of this file.
00001 
00010 #include "cl_cinematic_ogm.h"
00011 #include "cl_cinematic.h"
00012 #include "../renderer/r_draw.h"
00013 #include "../sound/s_main.h"
00014 #include "../sound/s_music.h"
00015 
00016 #if !defined(HAVE_VORBIS_CODEC_H) || (!defined(HAVE_XVID_H) && !defined(HAVE_THEORA_THEORA_H))
00017 #error "No ogm support compiled into the binary"
00018 #endif
00019 
00020 #include <ogg/ogg.h>
00021 #include <vorbis/codec.h>
00022 
00023 #ifdef HAVE_XVID_H
00024 #include <xvid.h>
00025 #endif
00026 #ifdef HAVE_THEORA_THEORA_H
00027 #include <theora/theora.h>
00028 #endif
00029 
00030 
00031 typedef struct {
00032     long vr[256];
00033     long ug[256];
00034     long vg[256];
00035     long ub[256];
00036     long yy[256];
00037 } yuvTable_t;
00038 
00039 #define OGG_BUFFER_SIZE (8 * 1024)
00040 
00041 typedef struct
00042 {
00043     qFILE ogmFile;
00044 
00045     ogg_sync_state oy; 
00046     ogg_stream_state os_audio;
00047     ogg_stream_state os_video;
00048 
00049     vorbis_dsp_state vd; 
00050     vorbis_info vi; 
00051     vorbis_comment vc; 
00055     qboolean videoStreamIsXvid;
00056 #ifdef HAVE_XVID_H
00057     xvid_dec_stats_t xvidDecodeStats;
00058     void *xvidDecodeHandle;
00059 #endif
00060     qboolean videoStreamIsTheora;
00061 #ifdef HAVE_THEORA_THEORA_H
00062     theora_info th_info;
00063     theora_comment th_comment;
00064     theora_state th_state;
00065 
00066     yuv_buffer th_yuvbuffer;
00067 #endif
00068 
00069     byte* outputBuffer;
00070     int outputWidth;
00071     int outputHeight;
00072     int outputBufferSize; 
00073     int videoFrameCount; 
00074     ogg_int64_t Vtime_unit;
00075     int currentTime; 
00076     int startTime;
00077 
00078     musicStream_t musicStream;
00079 } ogmCinematic_t;
00080 
00081 static yuvTable_t ogmCin_yuvTable;
00082 
00083 #define OGMCIN (*((ogmCinematic_t*)cin->codecData))
00084 
00085 #define OGM_CINEMATIC_BPP 4
00086 
00087 #ifdef HAVE_XVID_H
00088 
00089 static int CIN_XVID_Init (cinematic_t *cin)
00090 {
00091     int ret;
00092 
00093     xvid_gbl_init_t xvid_gbl_init;
00094     xvid_dec_create_t xvid_dec_create;
00095 
00096     /* Reset the structure with zeros */
00097     memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init_t));
00098     memset(&xvid_dec_create, 0, sizeof(xvid_dec_create_t));
00099 
00100     /* Version */
00101     xvid_gbl_init.version = XVID_VERSION;
00102 
00103     xvid_gbl_init.cpu_flags = 0;
00104     xvid_gbl_init.debug = 0;
00105 
00106     xvid_global(NULL, 0, &xvid_gbl_init, NULL);
00107 
00108     /* Version */
00109     xvid_dec_create.version = XVID_VERSION;
00110 
00111     /* Image dimensions -- set to 0, xvidcore will resize when ever it is needed */
00112     xvid_dec_create.width = 0;
00113     xvid_dec_create.height = 0;
00114 
00115     ret = xvid_decore(NULL, XVID_DEC_CREATE, &xvid_dec_create, NULL);
00116 
00117     OGMCIN.xvidDecodeHandle = xvid_dec_create.handle;
00118 
00119     return ret;
00120 }
00121 
00122 static int CIN_XVID_Decode (cinematic_t *cin, unsigned char *input, int inputSize)
00123 {
00124     int ret;
00125 
00126     xvid_dec_frame_t xvid_dec_frame;
00127 
00128     /* Reset all structures */
00129     memset(&xvid_dec_frame, 0, sizeof(xvid_dec_frame_t));
00130     memset(&OGMCIN.xvidDecodeStats, 0, sizeof(xvid_dec_stats_t));
00131 
00132     /* Set version */
00133     xvid_dec_frame.version = XVID_VERSION;
00134     OGMCIN.xvidDecodeStats.version = XVID_VERSION;
00135 
00136     /* No general flags to set */
00137     xvid_dec_frame.general = XVID_LOWDELAY;
00138 
00139     /* Input stream */
00140     xvid_dec_frame.bitstream = input;
00141     xvid_dec_frame.length = inputSize;
00142 
00143     /* Output frame structure */
00144     xvid_dec_frame.output.plane[0] = OGMCIN.outputBuffer;
00145     xvid_dec_frame.output.stride[0] = OGMCIN.outputWidth * OGM_CINEMATIC_BPP;
00146     if (OGMCIN.outputBuffer == NULL)
00147         xvid_dec_frame.output.csp = XVID_CSP_NULL;
00148     else
00149         xvid_dec_frame.output.csp = XVID_CSP_RGBA;
00150 
00151     ret = xvid_decore(OGMCIN.xvidDecodeHandle, XVID_DEC_DECODE, &xvid_dec_frame, &OGMCIN.xvidDecodeStats);
00152 
00153     return ret;
00154 }
00155 
00156 static int CIN_XVID_Shutdown (cinematic_t *cin)
00157 {
00158     int ret = 0;
00159 
00160     if (OGMCIN.xvidDecodeHandle)
00161         ret = xvid_decore(OGMCIN.xvidDecodeHandle, XVID_DEC_DESTROY, NULL, NULL);
00162 
00163     return ret;
00164 }
00165 #endif
00166 
00170 static int CIN_OGM_LoadBlockToSync (cinematic_t *cin)
00171 {
00172     int r = -1;
00173 
00174     if (OGMCIN.ogmFile.f || OGMCIN.ogmFile.z) {
00175         char *buffer = ogg_sync_buffer(&OGMCIN.oy, OGG_BUFFER_SIZE);
00176         const int bytes = FS_Read(buffer, OGG_BUFFER_SIZE, &OGMCIN.ogmFile);
00177         ogg_sync_wrote(&OGMCIN.oy, bytes);
00178 
00179         r = (bytes == 0);
00180     }
00181 
00182     return r;
00183 }
00184 
00188 static int CIN_OGM_LoadPagesToStream (cinematic_t *cin)
00189 {
00190     int r = -1;
00191     int audioPages = 0;
00192     int videoPages = 0;
00193     ogg_stream_state* osptr = NULL;
00194     ogg_page og;
00195 
00196     while (!audioPages || !videoPages) {
00197         if (ogg_sync_pageout(&OGMCIN.oy, &og) != 1)
00198             break;
00199 
00200         if (OGMCIN.os_audio.serialno == ogg_page_serialno(&og)) {
00201             osptr = &OGMCIN.os_audio;
00202             ++audioPages;
00203         }
00204         if (OGMCIN.os_video.serialno == ogg_page_serialno(&og)) {
00205             osptr = &OGMCIN.os_video;
00206             ++videoPages;
00207         }
00208 
00209         if (osptr != NULL) {
00210             ogg_stream_pagein(osptr, &og);
00211         }
00212     }
00213 
00214     if (audioPages && videoPages)
00215         r = 0;
00216 
00217     return r;
00218 }
00219 
00220 #define SIZEOF_RAWBUFF SAMPLE_SIZE * 4048
00221 static byte rawBuffer[SIZEOF_RAWBUFF];
00222 
00226 static qboolean CIN_OGM_LoadAudioFrame (cinematic_t *cin)
00227 {
00228     ogg_packet op;
00229     vorbis_block vb;
00230 
00231     memset(&op, 0, sizeof(op));
00232     memset(&vb, 0, sizeof(vb));
00233     vorbis_block_init(&OGMCIN.vd, &vb);
00234 
00235     while (OGMCIN.currentTime > (int) (OGMCIN.vd.granulepos * 1000 / OGMCIN.vi.rate)) {
00236         float **pcm;
00237         const int samples = vorbis_synthesis_pcmout(&OGMCIN.vd, &pcm);
00238 
00239         if (samples > 0) {
00240             /* vorbis -> raw */
00241             const int width = 2;
00242             const int channel = 2;
00243             int samplesNeeded = sizeof(rawBuffer) / (width * channel);
00244             const float *left = pcm[0];
00245             const float *right = (OGMCIN.vi.channels > 1) ? pcm[1] : pcm[0];
00246             short *ptr = (short*)rawBuffer;
00247             int i;
00248 
00249             if (samples < samplesNeeded)
00250                 samplesNeeded = samples;
00251 
00252             for (i = 0; i < samplesNeeded; ++i, ptr += channel) {
00253                 ptr[0] = (left[i] >= -1.0f && left[i] <= 1.0f) ? left[i] * 32767.f : 32767 * ((left[i] > 0.0f) - (left[i] < 0.0f));
00254                 ptr[1] = (right[i] >= -1.0f && right[i] <= 1.0f) ? right[i] * 32767.f : 32767 * ((right[i] > 0.0f) - (right[i] < 0.0f));
00255             }
00256 
00257             /* tell libvorbis how many samples we actually consumed */
00258             vorbis_synthesis_read(&OGMCIN.vd, i);
00259 
00260             if (!cin->noSound)
00261                 M_AddToSampleBuffer(&OGMCIN.musicStream, OGMCIN.vi.rate, i, rawBuffer);
00262         } else {
00263             /* op -> vorbis */
00264             if (ogg_stream_packetout(&OGMCIN.os_audio, &op)) {
00265                 if (vorbis_synthesis(&vb, &op) == 0)
00266                     vorbis_synthesis_blockin(&OGMCIN.vd, &vb);
00267             } else
00268                 break;
00269         }
00270     }
00271 
00272     vorbis_block_clear(&vb);
00273 
00274     return OGMCIN.currentTime > (int)(OGMCIN.vd.granulepos * 1000 / OGMCIN.vi.rate);
00275 }
00276 
00281 #ifdef HAVE_XVID_H
00282 static int CIN_XVID_LoadVideoFrame (cinematic_t *cin)
00283 {
00284     int r = 0;
00285     ogg_packet op;
00286 
00287     memset(&op, 0, sizeof(op));
00288 
00289     while (!r && (ogg_stream_packetout(&OGMCIN.os_video, &op))) {
00290         int usedBytes = CIN_XVID_Decode(cin, op.packet, op.bytes);
00291         if (OGMCIN.xvidDecodeStats.type == XVID_TYPE_VOL) {
00292             if (OGMCIN.outputWidth != OGMCIN.xvidDecodeStats.data.vol.width || OGMCIN.outputHeight
00293                     != OGMCIN.xvidDecodeStats.data.vol.height) {
00294                 OGMCIN.outputWidth = OGMCIN.xvidDecodeStats.data.vol.width;
00295                 OGMCIN.outputHeight = OGMCIN.xvidDecodeStats.data.vol.height;
00296                 Com_DPrintf(DEBUG_CLIENT, "[XVID]new resolution %dx%d\n", OGMCIN.outputWidth, OGMCIN.outputHeight);
00297             }
00298 
00299             if (OGMCIN.outputBufferSize < OGMCIN.xvidDecodeStats.data.vol.width * OGMCIN.xvidDecodeStats.data.vol.height) {
00300                 OGMCIN.outputBufferSize = OGMCIN.xvidDecodeStats.data.vol.width * OGMCIN.xvidDecodeStats.data.vol.height;
00301 
00302                 /* Free old output buffer*/
00303                 if (OGMCIN.outputBuffer)
00304                     Mem_Free(OGMCIN.outputBuffer);
00305 
00306                 /* Allocate the new buffer */
00307                 OGMCIN.outputBuffer = (byte*) Mem_PoolAlloc(OGMCIN.outputBufferSize * OGM_CINEMATIC_BPP, cl_genericPool, 0);
00308                 if (OGMCIN.outputBuffer == NULL) {
00309                     OGMCIN.outputBufferSize = 0;
00310                     r = -2;
00311                     break;
00312                 }
00313             }
00314 
00315             /* use the rest of this packet */
00316             usedBytes += CIN_XVID_Decode(cin, op.packet + usedBytes, op.bytes - usedBytes);
00317         }
00318 
00319         /* we got a real output frame ... */
00320         if (OGMCIN.xvidDecodeStats.type > 0) {
00321             r = 1;
00322 
00323             ++OGMCIN.videoFrameCount;
00324         }
00325     }
00326 
00327     return r;
00328 }
00329 #endif
00330 
00331 #ifdef HAVE_THEORA_THEORA_H
00332 
00336 static int CIN_THEORA_FindSizeShift (int x, int y)
00337 {
00338     int i;
00339 
00340     for (i = 0; (y >> i); ++i)
00341         if (x == (y >> i))
00342             return i;
00343 
00344     return -1;
00345 }
00346 
00347 
00351 static inline byte CIN_THEORA_ClampByte (int value)
00352 {
00353     if (value < 0)
00354         return 0;
00355 
00356     if (value > 255)
00357         return 255;
00358 
00359     return value;
00360 }
00361 
00362 static void CIN_THEORA_FrameYUVtoRGB24 (const unsigned char* y, const unsigned char* u, const unsigned char* v, int width,
00363         int height, int y_stride, int uv_stride, int yWShift, int uvWShift, int yHShift, int uvHShift,
00364         uint32_t* output)
00365 {
00366     int i, j;
00367 
00368     for (j = 0; j < height; ++j) {
00369         for (i = 0; i < width; ++i) {
00370             const long YY = (long) (ogmCin_yuvTable.yy[(y[(i >> yWShift) + (j >> yHShift) * y_stride])]);
00371             const int uvI = (i >> uvWShift) + (j >> uvHShift) * uv_stride;
00372 
00373             const byte r = CIN_THEORA_ClampByte((YY + ogmCin_yuvTable.vr[v[uvI]]) >> 6);
00374             const byte g = CIN_THEORA_ClampByte((YY + ogmCin_yuvTable.ug[u[uvI]] + ogmCin_yuvTable.vg[v[uvI]]) >> 6);
00375             const byte b = CIN_THEORA_ClampByte((YY + ogmCin_yuvTable.ub[u[uvI]]) >> 6);
00376 
00377             const uint32_t rgb24 = LittleLong(r | (g << 8) | (b << 16) | (255 << 24));
00378             *output++ = rgb24;
00379         }
00380     }
00381 }
00382 
00383 static int CIN_THEORA_NextNeededFrame (cinematic_t *cin)
00384 {
00385     return (int) (OGMCIN.currentTime * (ogg_int64_t) 10000 / OGMCIN.Vtime_unit);
00386 }
00387 
00392 static int CIN_THEORA_LoadVideoFrame (cinematic_t *cin)
00393 {
00394     int r = 0;
00395     ogg_packet op;
00396 
00397     memset(&op, 0, sizeof(op));
00398 
00399     while (!r && (ogg_stream_packetout(&OGMCIN.os_video, &op))) {
00400         ogg_int64_t th_frame;
00401         theora_decode_packetin(&OGMCIN.th_state, &op);
00402 
00403         th_frame = theora_granule_frame(&OGMCIN.th_state, OGMCIN.th_state.granulepos);
00404 
00405         if ((OGMCIN.videoFrameCount < th_frame && th_frame >= CIN_THEORA_NextNeededFrame(cin)) || !OGMCIN.outputBuffer) {
00406             int yWShift, uvWShift;
00407             int yHShift, uvHShift;
00408 
00409             if (theora_decode_YUVout(&OGMCIN.th_state, &OGMCIN.th_yuvbuffer))
00410                 continue;
00411 
00412             if (OGMCIN.outputWidth != OGMCIN.th_info.width || OGMCIN.outputHeight != OGMCIN.th_info.height) {
00413                 OGMCIN.outputWidth = OGMCIN.th_info.width;
00414                 OGMCIN.outputHeight = OGMCIN.th_info.height;
00415                 Com_DPrintf(DEBUG_CLIENT, "[Theora(ogg)]new resolution %dx%d\n", OGMCIN.outputWidth, OGMCIN.outputHeight);
00416             }
00417 
00418             if (OGMCIN.outputBufferSize < OGMCIN.th_info.width * OGMCIN.th_info.height) {
00419                 OGMCIN.outputBufferSize = OGMCIN.th_info.width * OGMCIN.th_info.height;
00420 
00421                 /* Free old output buffer*/
00422                 if (OGMCIN.outputBuffer)
00423                     Mem_Free(OGMCIN.outputBuffer);
00424 
00425                 /* Allocate the new buffer */
00426                 OGMCIN.outputBuffer = (byte*) Mem_PoolAlloc(OGMCIN.outputBufferSize * OGM_CINEMATIC_BPP, cl_genericPool, 0);
00427                 if (OGMCIN.outputBuffer == NULL) {
00428                     OGMCIN.outputBufferSize = 0;
00429                     r = -2;
00430                     break;
00431                 }
00432             }
00433 
00434             yWShift = CIN_THEORA_FindSizeShift(OGMCIN.th_yuvbuffer.y_width, OGMCIN.th_info.width);
00435             uvWShift = CIN_THEORA_FindSizeShift(OGMCIN.th_yuvbuffer.uv_width, OGMCIN.th_info.width);
00436             yHShift = CIN_THEORA_FindSizeShift(OGMCIN.th_yuvbuffer.y_height, OGMCIN.th_info.height);
00437             uvHShift = CIN_THEORA_FindSizeShift(OGMCIN.th_yuvbuffer.uv_height, OGMCIN.th_info.height);
00438 
00439             if (yWShift < 0 || uvWShift < 0 || yHShift < 0 || uvHShift < 0) {
00440                 Com_Printf("[Theora] unexpected resolution in a yuv-frame\n");
00441                 r = -1;
00442             } else {
00443                 CIN_THEORA_FrameYUVtoRGB24(OGMCIN.th_yuvbuffer.y, OGMCIN.th_yuvbuffer.u, OGMCIN.th_yuvbuffer.v,
00444                         OGMCIN.th_info.width, OGMCIN.th_info.height, OGMCIN.th_yuvbuffer.y_stride,
00445                         OGMCIN.th_yuvbuffer.uv_stride, yWShift, uvWShift, yHShift, uvHShift,
00446                         (uint32_t*) OGMCIN.outputBuffer);
00447 
00448                 r = 1;
00449                 OGMCIN.videoFrameCount = th_frame;
00450             }
00451         }
00452     }
00453 
00454     return r;
00455 }
00456 #endif
00457 
00462 static int CIN_OGM_LoadVideoFrame (cinematic_t *cin)
00463 {
00464 #ifdef HAVE_XVID_H
00465     if (OGMCIN.videoStreamIsXvid)
00466         return CIN_XVID_LoadVideoFrame(cin);
00467 #endif
00468 #ifdef HAVE_THEORA_THEORA_H
00469     if (OGMCIN.videoStreamIsTheora)
00470         return CIN_THEORA_LoadVideoFrame(cin);
00471 #endif
00472 
00473     /* if we come to this point, there will be no codec that use the stream content ... */
00474     if (OGMCIN.os_video.serialno) {
00475         ogg_packet op;
00476 
00477         while (ogg_stream_packetout(&OGMCIN.os_video, &op))
00478             ;
00479     }
00480 
00481     return 1;
00482 }
00483 
00487 static qboolean CIN_OGM_LoadFrame (cinematic_t *cin)
00488 {
00489     qboolean anyDataTransferred = qtrue;
00490     qboolean needVOutputData = qtrue;
00491     qboolean audioWantsMoreData = qfalse;
00492     int status;
00493 
00494     while (anyDataTransferred && (needVOutputData || audioWantsMoreData)) {
00495         anyDataTransferred = qfalse;
00496         if (needVOutputData && (status = CIN_OGM_LoadVideoFrame(cin))) {
00497             needVOutputData = qfalse;
00498             if (status > 0)
00499                 anyDataTransferred = qtrue;
00500             else
00501                 /* error (we don't need any videodata and we had no transferred) */
00502                 anyDataTransferred = qfalse;
00503         }
00504 
00505         if (needVOutputData || audioWantsMoreData) {
00506             /* try to transfer Pages to the audio- and video-Stream */
00507             if (CIN_OGM_LoadPagesToStream(cin))
00508                 /* try to load a datablock from file */
00509                 anyDataTransferred |= !CIN_OGM_LoadBlockToSync(cin);
00510             else
00511                 /* successful loadPagesToStreams() */
00512                 anyDataTransferred = qtrue;
00513         }
00514 
00515         /* load all audio after loading new pages ... */
00516         if (OGMCIN.videoFrameCount > 1)
00517             /* wait some videoframes (it's better to have some delay, than a laggy sound) */
00518             audioWantsMoreData = CIN_OGM_LoadAudioFrame(cin);
00519     }
00520 
00521     return !anyDataTransferred;
00522 }
00523 
00524 #ifdef HAVE_XVID_H
00525 
00526 typedef struct
00527 {
00528     char streamtype[8];
00529     char subtype[4];
00530 
00531     ogg_int32_t size; /* size of the structure */
00532 
00533     /* in 10^-7 seconds (dT between frames) */
00534     ogg_int64_t time_unit; /* in reference time */
00535     ogg_int64_t samples_per_unit;
00536     ogg_int32_t default_len; /* in media time */
00537 
00538     ogg_int32_t buffersize;
00539     ogg_int16_t bits_per_sample;
00540     union
00541     {
00542         struct
00543         {
00544             ogg_int32_t width;
00545             ogg_int32_t height;
00546         } stream_header_video;
00547 
00548         struct
00549         {
00550             ogg_int16_t channels;
00551             ogg_int16_t blockalign;
00552             ogg_int32_t avgbytespersec;
00553         } stream_header_audio;
00554     } sh;
00555 } stream_header_t;
00556 #endif
00557 
00563 int CIN_OGM_PlayCinematic (cinematic_t *cin, const char* filename)
00564 {
00565     int status;
00566     ogg_page og;
00567     ogg_packet op;
00568     int i;
00569 
00570     if (cin->codecData && (OGMCIN.ogmFile.f || OGMCIN.ogmFile.z)) {
00571         Com_Printf("WARNING: it seams there was already a ogm running, it will be killed to start %s\n", filename);
00572         CIN_OGM_StopCinematic(cin);
00573     }
00574 
00575     /* alloc memory for decoding of this video */
00576     assert(cin->codecData == NULL);
00577     cin->codecData = Mem_PoolAlloc(sizeof(OGMCIN), vid_genericPool, 0);
00578     memset(cin->codecData, 0, sizeof(ogmCinematic_t));
00579 
00580     if (FS_OpenFile(filename, &OGMCIN.ogmFile, FILE_READ) == -1) {
00581         Com_Printf("Can't open ogm-file for reading (%s)\n", filename);
00582         return -1;
00583     }
00584 
00585     cin->cinematicType = CINEMATIC_TYPE_OGM;
00586     OGMCIN.startTime = CL_Milliseconds();
00587 
00588     ogg_sync_init(&OGMCIN.oy); /* Now we can read pages */
00589 
00592     while (!OGMCIN.os_audio.serialno || !OGMCIN.os_video.serialno) {
00593         if (ogg_sync_pageout(&OGMCIN.oy, &og) == 1) {
00594             if (strstr((char*) (og.body + 1), "vorbis")) { 
00595                 if (OGMCIN.os_audio.serialno) {
00596                     Com_Printf("more than one audio stream, in ogm-file(%s) ... we will stay at the first one\n",
00597                             filename);
00598                 } else {
00599                     ogg_stream_init(&OGMCIN.os_audio, ogg_page_serialno(&og));
00600                     ogg_stream_pagein(&OGMCIN.os_audio, &og);
00601                 }
00602             }
00603 #ifdef HAVE_THEORA_THEORA_H
00604             else if (strstr((char*) (og.body + 1), "theora")) {
00605                 if (OGMCIN.os_video.serialno) {
00606                     Com_Printf("more than one video stream, in ogm-file(%s) ... we will stay at the first one\n",
00607                             filename);
00608                 } else {
00609                     OGMCIN.videoStreamIsTheora = qtrue;
00610                     ogg_stream_init(&OGMCIN.os_video, ogg_page_serialno(&og));
00611                     ogg_stream_pagein(&OGMCIN.os_video, &og);
00612                 }
00613             }
00614 #endif
00615 #ifdef HAVE_XVID_H
00616             else if (strstr((char*) (og.body + 1), "video")) { 
00617                 if (OGMCIN.os_video.serialno) {
00618                     Com_Printf("more than one video stream, in ogm-file(%s) ... we will stay at the first one\n",
00619                             filename);
00620                 } else {
00621                     stream_header_t* sh;
00622 
00623                     OGMCIN.videoStreamIsXvid = qtrue;
00624 
00625                     sh = (stream_header_t*) (og.body + 1);
00626 
00627                     OGMCIN.Vtime_unit = sh->time_unit;
00628 
00629                     ogg_stream_init(&OGMCIN.os_video, ogg_page_serialno(&og));
00630                     ogg_stream_pagein(&OGMCIN.os_video, &og);
00631                 }
00632             }
00633 #endif
00634         } else if (CIN_OGM_LoadBlockToSync(cin))
00635             break;
00636     }
00637 
00638     if (OGMCIN.videoStreamIsXvid && OGMCIN.videoStreamIsTheora) {
00639         Com_Printf("Found \"video\"- and \"theora\"-stream, ogm-file (%s)\n", filename);
00640         return -2;
00641     }
00642 
00643     if (!OGMCIN.os_audio.serialno) {
00644         Com_Printf("Haven't found an audio (vorbis) stream in ogm-file (%s)\n", filename);
00645         return -2;
00646     }
00647     if (!OGMCIN.os_video.serialno) {
00648         Com_Printf("Haven't found a video stream in ogm-file (%s)\n", filename);
00649         return -3;
00650     }
00651 
00652     /* load vorbis header */
00653     vorbis_info_init(&OGMCIN.vi);
00654     vorbis_comment_init(&OGMCIN.vc);
00655     i = 0;
00656     while (i < 3) {
00657         status = ogg_stream_packetout(&OGMCIN.os_audio, &op);
00658         if (status < 0) {
00659             Com_Printf("Corrupt ogg packet while loading vorbis-headers, ogm-file(%s)\n", filename);
00660             return -8;
00661         }
00662         if (status > 0) {
00663             status = vorbis_synthesis_headerin(&OGMCIN.vi, &OGMCIN.vc, &op);
00664             if (i == 0 && status < 0) {
00665                 Com_Printf("This Ogg bitstream does not contain Vorbis audio data, ogm-file(%s)\n", filename);
00666                 return -9;
00667             }
00668             ++i;
00669         } else if (CIN_OGM_LoadPagesToStream(cin)) {
00670             if (CIN_OGM_LoadBlockToSync(cin)) {
00671                 Com_Printf("Couldn't find all vorbis headers before end of ogm-file (%s)\n", filename);
00672                 return -10;
00673             }
00674         }
00675     }
00676 
00677     vorbis_synthesis_init(&OGMCIN.vd, &OGMCIN.vi);
00678 
00679 #ifdef HAVE_XVID_H
00680     status = CIN_XVID_Init(cin);
00681     if (status) {
00682         Com_Printf("[Xvid]Decore INIT problem, return value %d(ogm-file: %s)\n", status, filename);
00683         return -4;
00684     }
00685 #endif
00686 
00687 #ifdef HAVE_THEORA_THEORA_H
00688     if (OGMCIN.videoStreamIsTheora) {
00689         theora_info_init(&OGMCIN.th_info);
00690         theora_comment_init(&OGMCIN.th_comment);
00691 
00692         i = 0;
00693         while (i < 3) {
00694             status = ogg_stream_packetout(&OGMCIN.os_video, &op);
00695             if (status < 0) {
00696                 Com_Printf("Corrupt ogg packet while loading theora-headers, ogm-file(%s)\n", filename);
00697 
00698                 return -8;
00699             }
00700             if (status > 0) {
00701                 status = theora_decode_header(&OGMCIN.th_info, &OGMCIN.th_comment, &op);
00702                 if (i == 0 && status != 0) {
00703                     Com_Printf("This Ogg bitstream does not contain theora data, ogm-file(%s)\n", filename);
00704 
00705                     return -9;
00706                 }
00707                 ++i;
00708             } else if (CIN_OGM_LoadPagesToStream(cin)) {
00709                 if (CIN_OGM_LoadBlockToSync(cin)) {
00710                     Com_Printf("Couldn't find all theora headers before end of ogm-file (%s)\n", filename);
00711 
00712                     return -10;
00713                 }
00714             }
00715         }
00716 
00717         theora_decode_init(&OGMCIN.th_state, &OGMCIN.th_info);
00718         OGMCIN.Vtime_unit = ((ogg_int64_t) OGMCIN.th_info.fps_denominator * 1000 * 10000 / OGMCIN.th_info.fps_numerator);
00719     }
00720 #endif
00721 
00722     M_PlayMusicStream(&OGMCIN.musicStream);
00723 
00724     return 0;
00725 }
00726 
00730 static void CIN_OGM_DrawCinematic (cinematic_t *cin)
00731 {
00732     int texnum;
00733 
00734     assert(cin->status != CIN_STATUS_NONE);
00735 
00736     if (!OGMCIN.outputBuffer)
00737         return;
00738     texnum = R_UploadData("***cinematic***", OGMCIN.outputBuffer, OGMCIN.outputWidth, OGMCIN.outputHeight);
00739     R_DrawTexture(texnum, cin->x, cin->y, cin->w, cin->h);
00740 }
00741 
00745 qboolean CIN_OGM_RunCinematic (cinematic_t *cin)
00746 {
00747     OGMCIN.currentTime = CL_Milliseconds() - OGMCIN.startTime;
00748 
00749     while (!OGMCIN.videoFrameCount || OGMCIN.currentTime + 20 >= (int) (OGMCIN.videoFrameCount * OGMCIN.Vtime_unit / 10000)) {
00750         if (CIN_OGM_LoadFrame(cin))
00751             return qfalse;
00752     }
00753 
00754     CIN_OGM_DrawCinematic(cin);
00755 
00756     return qtrue;
00757 }
00758 
00759 void CIN_OGM_StopCinematic (cinematic_t *cin)
00760 {
00761 #ifdef HAVE_XVID_H
00762 
00763     CIN_XVID_Shutdown(cin);
00764 #endif
00765 
00766 #ifdef HAVE_THEORA_THEORA_H
00767     theora_clear(&OGMCIN.th_state);
00768     theora_comment_clear(&OGMCIN.th_comment);
00769     theora_info_clear(&OGMCIN.th_info);
00770 #endif
00771 
00772     M_StopMusicStream(&OGMCIN.musicStream);
00773 
00774     if (OGMCIN.outputBuffer)
00775         Mem_Free(OGMCIN.outputBuffer);
00776     OGMCIN.outputBuffer = NULL;
00777 
00778     vorbis_dsp_clear(&OGMCIN.vd);
00779     vorbis_comment_clear(&OGMCIN.vc);
00780     vorbis_info_clear(&OGMCIN.vi); /* must be called last (comment from vorbis example code) */
00781 
00782     ogg_stream_clear(&OGMCIN.os_audio);
00783     ogg_stream_clear(&OGMCIN.os_video);
00784 
00785     ogg_sync_clear(&OGMCIN.oy);
00786 
00787     FS_CloseFile(&OGMCIN.ogmFile);
00788 
00789     /* free data allocated for decodage */
00790     Mem_Free(cin->codecData);
00791     cin->codecData = NULL;
00792 }
00793 
00794 void CIN_OGM_Init (void)
00795 {
00796     long i;
00797     const float t_ub = (1.77200f / 2.0f) * (float)(1 << 6) + 0.5f;
00798     const float t_vr = (1.40200f / 2.0f) * (float)(1 << 6) + 0.5f;
00799     const float t_ug = (0.34414f / 2.0f) * (float)(1 << 6) + 0.5f;
00800     const float t_vg = (0.71414f / 2.0f) * (float)(1 << 6) + 0.5f;
00801 
00802     for (i = 0; i < 256; i++) {
00803         const float x = (float)(2 * i - 255);
00804 
00805         ogmCin_yuvTable.ub[i] = (long)(( t_ub * x) + (1 << 5));
00806         ogmCin_yuvTable.vr[i] = (long)(( t_vr * x) + (1 << 5));
00807         ogmCin_yuvTable.ug[i] = (long)((-t_ug * x));
00808         ogmCin_yuvTable.vg[i] = (long)((-t_vg * x) + (1 << 5));
00809         ogmCin_yuvTable.yy[i] = (long)((i << 6) | (i >> 2));
00810     }
00811 }

Generated by  doxygen 1.6.2