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
00097 memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init_t));
00098 memset(&xvid_dec_create, 0, sizeof(xvid_dec_create_t));
00099
00100
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
00109 xvid_dec_create.version = XVID_VERSION;
00110
00111
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
00129 memset(&xvid_dec_frame, 0, sizeof(xvid_dec_frame_t));
00130 memset(&OGMCIN.xvidDecodeStats, 0, sizeof(xvid_dec_stats_t));
00131
00132
00133 xvid_dec_frame.version = XVID_VERSION;
00134 OGMCIN.xvidDecodeStats.version = XVID_VERSION;
00135
00136
00137 xvid_dec_frame.general = XVID_LOWDELAY;
00138
00139
00140 xvid_dec_frame.bitstream = input;
00141 xvid_dec_frame.length = inputSize;
00142
00143
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
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
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
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
00303 if (OGMCIN.outputBuffer)
00304 Mem_Free(OGMCIN.outputBuffer);
00305
00306
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
00316 usedBytes += CIN_XVID_Decode(cin, op.packet + usedBytes, op.bytes - usedBytes);
00317 }
00318
00319
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
00422 if (OGMCIN.outputBuffer)
00423 Mem_Free(OGMCIN.outputBuffer);
00424
00425
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
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
00502 anyDataTransferred = qfalse;
00503 }
00504
00505 if (needVOutputData || audioWantsMoreData) {
00506
00507 if (CIN_OGM_LoadPagesToStream(cin))
00508
00509 anyDataTransferred |= !CIN_OGM_LoadBlockToSync(cin);
00510 else
00511
00512 anyDataTransferred = qtrue;
00513 }
00514
00515
00516 if (OGMCIN.videoFrameCount > 1)
00517
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;
00532
00533
00534 ogg_int64_t time_unit;
00535 ogg_int64_t samples_per_unit;
00536 ogg_int32_t default_len;
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
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);
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
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);
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
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 }