UFO: Alien Invasion
Loading...
Searching...
No Matches
cl_cinematic_ogm.cpp
Go to the documentation of this file.
1
9
10#include "cl_cinematic_ogm.h"
11#ifndef NO_OGG
12#include "cl_cinematic.h"
13#include "../client.h"
14#include "../renderer/r_draw.h"
15#include "../sound/s_main.h"
16#include "../sound/s_music.h"
17
18#include <ogg/ogg.h>
19#include <vorbis/codec.h>
20
21#ifdef HAVE_XVID_H
22#include <xvid.h>
23#endif
24#ifdef HAVE_THEORA_THEORA_H
25#include <theora/theora.h>
26#endif
27
28
29typedef struct {
30 long vr[256];
31 long ug[256];
32 long vg[256];
33 long ub[256];
34 long yy[256];
36
37#define OGG_BUFFER_SIZE (8 * 1024)
38
39typedef struct
40{
42
43 ogg_sync_state oy;
44 ogg_stream_state os_audio;
45 ogg_stream_state os_video;
46
47 vorbis_dsp_state vd;
48 vorbis_info vi;
49 vorbis_comment vc;
50
54#ifdef HAVE_XVID_H
55 xvid_dec_stats_t xvidDecodeStats;
56 void* xvidDecodeHandle;
57#endif
59#ifdef HAVE_THEORA_THEORA_H
60 theora_info th_info;
61 theora_comment th_comment;
62 theora_state th_state;
63
64 yuv_buffer th_yuvbuffer;
65#endif
66
67 unsigned* outputBuffer;
72 ogg_int64_t Vtime_unit;
75
78
80
81#define OGMCIN (*((ogmCinematic_t*)cin->codecData))
82
83#ifdef HAVE_XVID_H
84
85static int CIN_XVID_Init (cinematic_t* cin)
86{
87 xvid_gbl_init_t xvid_gbl_init;
88 xvid_dec_create_t xvid_dec_create;
89
90 /* Reset the structure with zeros */
91 OBJZERO(xvid_gbl_init);
92 OBJZERO(xvid_dec_create);
93
94 /* Version */
95 xvid_gbl_init.version = XVID_VERSION;
96
97 xvid_gbl_init.cpu_flags = 0;
98 xvid_gbl_init.debug = 0;
99
100 xvid_global(nullptr, 0, &xvid_gbl_init, nullptr);
101
102 /* Version */
103 xvid_dec_create.version = XVID_VERSION;
104
105 /* Image dimensions -- set to 0, xvidcore will resize when ever it is needed */
106 xvid_dec_create.width = 0;
107 xvid_dec_create.height = 0;
108
109 const int ret = xvid_decore(nullptr, XVID_DEC_CREATE, &xvid_dec_create, nullptr);
110
111 OGMCIN.xvidDecodeHandle = xvid_dec_create.handle;
112
113 return ret;
114}
115
116static int CIN_XVID_Decode (cinematic_t* cin, unsigned char* input, int inputSize)
117{
118 xvid_dec_frame_t xvid_dec_frame;
119
120 /* Reset all structures */
121 OBJZERO(xvid_dec_frame);
122 OBJZERO(OGMCIN.xvidDecodeStats);
123
124 /* Set version */
125 xvid_dec_frame.version = XVID_VERSION;
126 OGMCIN.xvidDecodeStats.version = XVID_VERSION;
127
128 /* No general flags to set */
129 xvid_dec_frame.general = XVID_LOWDELAY;
130
131 /* Input stream */
132 xvid_dec_frame.bitstream = input;
133 xvid_dec_frame.length = inputSize;
134
135 /* Output frame structure */
136 xvid_dec_frame.output.plane[0] = OGMCIN.outputBuffer;
137 xvid_dec_frame.output.stride[0] = OGMCIN.outputWidth * sizeof(*OGMCIN.outputBuffer);
138 if (OGMCIN.outputBuffer == nullptr)
139 xvid_dec_frame.output.csp = XVID_CSP_NULL;
140 else
141 xvid_dec_frame.output.csp = XVID_CSP_RGBA;
142
143 const int ret = xvid_decore(OGMCIN.xvidDecodeHandle, XVID_DEC_DECODE, &xvid_dec_frame, &OGMCIN.xvidDecodeStats);
144
145 return ret;
146}
147
148static int CIN_XVID_Shutdown (cinematic_t* cin)
149{
150 int ret = 0;
151
152 if (OGMCIN.xvidDecodeHandle)
153 ret = xvid_decore(OGMCIN.xvidDecodeHandle, XVID_DEC_DESTROY, nullptr, nullptr);
154
155 return ret;
156}
157#endif
158
163{
164 int r = -1;
165
166 if (OGMCIN.ogmFile.f || OGMCIN.ogmFile.z) {
167 char* buffer = ogg_sync_buffer(&OGMCIN.oy, OGG_BUFFER_SIZE);
168 const int bytes = FS_Read(buffer, OGG_BUFFER_SIZE, &OGMCIN.ogmFile);
169 if (bytes > 0)
170 ogg_sync_wrote(&OGMCIN.oy, bytes);
171
172 r = (bytes == 0);
173 }
174
175 return r;
176}
177
182{
183 int r = -1;
184 int audioPages = 0;
185 int videoPages = 0;
186 ogg_stream_state* osptr = nullptr;
187 ogg_page og;
188
189 while (!audioPages || !videoPages) {
190 if (ogg_sync_pageout(&OGMCIN.oy, &og) != 1)
191 break;
192
193 if (OGMCIN.os_audio.serialno == ogg_page_serialno(&og)) {
194 osptr = &OGMCIN.os_audio;
195 ++audioPages;
196 }
197 if (OGMCIN.os_video.serialno == ogg_page_serialno(&og)) {
198 osptr = &OGMCIN.os_video;
199 ++videoPages;
200 }
201
202 if (osptr != nullptr) {
203 ogg_stream_pagein(osptr, &og);
204 }
205 }
206
207 if (audioPages && videoPages)
208 r = 0;
209
210 return r;
211}
212
213#define SIZEOF_RAWBUFF SAMPLE_SIZE * 1024
215
220{
221 vorbis_block vb;
222
223 OBJZERO(vb);
224 vorbis_block_init(&OGMCIN.vd, &vb);
225
226 while (OGMCIN.currentTime > (int) (OGMCIN.vd.granulepos * 1000 / OGMCIN.vi.rate)) {
227 float** pcm;
228 const int samples = vorbis_synthesis_pcmout(&OGMCIN.vd, &pcm);
229
230 if (samples > 0) {
231 /* vorbis -> raw */
232 const int width = 2;
233 const int channel = 2;
234 int samplesNeeded = sizeof(rawBuffer) / (width * channel);
235 const float* left = pcm[0];
236 const float* right = (OGMCIN.vi.channels > 1) ? pcm[1] : pcm[0];
237 short* ptr = (short*)rawBuffer;
238 int i;
239
240 if (samples < samplesNeeded)
241 samplesNeeded = samples;
242
243 for (i = 0; i < samplesNeeded; ++i, ptr += channel) {
244 ptr[0] = (left[i] >= -1.0f && left[i] <= 1.0f) ? left[i] * 32767.f : 32767 * ((left[i] > 0.0f) - (left[i] < 0.0f));
245 ptr[1] = (right[i] >= -1.0f && right[i] <= 1.0f) ? right[i] * 32767.f : 32767 * ((right[i] > 0.0f) - (right[i] < 0.0f));
246 }
247
248 /* tell libvorbis how many samples we actually consumed */
249 vorbis_synthesis_read(&OGMCIN.vd, i);
250
251 if (!cin->noSound)
252 M_AddToSampleBuffer(&OGMCIN.musicStream, OGMCIN.vi.rate, i, rawBuffer);
253 } else {
254 ogg_packet op;
255 /* op -> vorbis */
256 if (ogg_stream_packetout(&OGMCIN.os_audio, &op)) {
257 if (vorbis_synthesis(&vb, &op) == 0)
258 vorbis_synthesis_blockin(&OGMCIN.vd, &vb);
259 } else
260 break;
261 }
262 }
263
264 vorbis_block_clear(&vb);
265
266 return OGMCIN.currentTime > (int)(OGMCIN.vd.granulepos * 1000 / OGMCIN.vi.rate);
267}
268
273#ifdef HAVE_XVID_H
274static int CIN_XVID_LoadVideoFrame (cinematic_t* cin)
275{
276 int r = 0;
277 ogg_packet op;
278
279 OBJZERO(op);
280
281 while (!r && (ogg_stream_packetout(&OGMCIN.os_video, &op))) {
282 const int usedBytes = CIN_XVID_Decode(cin, op.packet, op.bytes);
283 if (OGMCIN.xvidDecodeStats.type == XVID_TYPE_VOL) {
284 if (OGMCIN.outputWidth != OGMCIN.xvidDecodeStats.data.vol.width || OGMCIN.outputHeight
285 != OGMCIN.xvidDecodeStats.data.vol.height) {
286 OGMCIN.outputWidth = OGMCIN.xvidDecodeStats.data.vol.width;
287 OGMCIN.outputHeight = OGMCIN.xvidDecodeStats.data.vol.height;
288 Com_DPrintf(DEBUG_CLIENT, "[XVID]new resolution %dx%d\n", OGMCIN.outputWidth, OGMCIN.outputHeight);
289 }
290
291 if (OGMCIN.outputBufferSize < OGMCIN.xvidDecodeStats.data.vol.width * OGMCIN.xvidDecodeStats.data.vol.height) {
292 OGMCIN.outputBufferSize = OGMCIN.xvidDecodeStats.data.vol.width * OGMCIN.xvidDecodeStats.data.vol.height;
293
294 /* Free old output buffer*/
295 Mem_Free(OGMCIN.outputBuffer);
296
297 /* Allocate the new buffer */
298 OGMCIN.outputBuffer = Mem_PoolAllocTypeN(unsigned, OGMCIN.outputBufferSize, cl_genericPool);
299 if (OGMCIN.outputBuffer == nullptr) {
300 OGMCIN.outputBufferSize = 0;
301 r = -2;
302 break;
303 }
304 }
305
306 /* use the rest of this packet */
307 CIN_XVID_Decode(cin, op.packet + usedBytes, op.bytes - usedBytes);
308 }
309
310 /* we got a real output frame ... */
311 if (OGMCIN.xvidDecodeStats.type > 0) {
312 r = 1;
313
314 ++OGMCIN.videoFrameCount;
315 }
316 }
317
318 return r;
319}
320#endif
321
322#ifdef HAVE_THEORA_THEORA_H
327static int CIN_THEORA_FindSizeShift (int x, int y)
328{
329 for (int i = 0; (y >> i); ++i)
330 if (x == (y >> i))
331 return i;
332
333 return -1;
334}
335
336
340static inline byte CIN_THEORA_ClampByte (int value)
341{
342 if (value < 0)
343 return 0;
344
345 if (value > 255)
346 return 255;
347
348 return value;
349}
350
351static void CIN_THEORA_FrameYUVtoRGB24 (const unsigned char* y, const unsigned char* u, const unsigned char* v, int width,
352 int height, int y_stride, int uv_stride, int yWShift, int uvWShift, int yHShift, int uvHShift,
353 uint32_t* output)
354{
355 for (int j = 0; j < height; ++j) {
356 for (int i = 0; i < width; ++i) {
357 const long YY = (long) (ogmCin_yuvTable.yy[(y[(i >> yWShift) + (j >> yHShift) * y_stride])]);
358 const int uvI = (i >> uvWShift) + (j >> uvHShift) * uv_stride;
359
360 const byte r = CIN_THEORA_ClampByte((YY + ogmCin_yuvTable.vr[v[uvI]]) >> 6);
361 const byte g = CIN_THEORA_ClampByte((YY + ogmCin_yuvTable.ug[u[uvI]] + ogmCin_yuvTable.vg[v[uvI]]) >> 6);
362 const byte b = CIN_THEORA_ClampByte((YY + ogmCin_yuvTable.ub[u[uvI]]) >> 6);
363
364 const uint32_t rgb24 = LittleLong(r | (g << 8) | (b << 16) | (255 << 24));
365 *output++ = rgb24;
366 }
367 }
368}
369
370static int CIN_THEORA_NextNeededFrame (cinematic_t* cin)
371{
372 return (int) (OGMCIN.currentTime * (ogg_int64_t) 10000 / OGMCIN.Vtime_unit);
373}
374
379static int CIN_THEORA_LoadVideoFrame (cinematic_t* cin)
380{
381 int r = 0;
382 ogg_packet op;
383
384 OBJZERO(op);
385
386 while (!r && (ogg_stream_packetout(&OGMCIN.os_video, &op))) {
387 ogg_int64_t th_frame;
388 theora_decode_packetin(&OGMCIN.th_state, &op);
389
390 th_frame = theora_granule_frame(&OGMCIN.th_state, OGMCIN.th_state.granulepos);
391
392 if ((OGMCIN.videoFrameCount < th_frame && th_frame >= CIN_THEORA_NextNeededFrame(cin)) || !OGMCIN.outputBuffer) {
393 int yWShift, uvWShift;
394 int yHShift, uvHShift;
395
396 if (theora_decode_YUVout(&OGMCIN.th_state, &OGMCIN.th_yuvbuffer))
397 continue;
398
399 if (OGMCIN.outputWidth != OGMCIN.th_info.width || OGMCIN.outputHeight != OGMCIN.th_info.height) {
400 OGMCIN.outputWidth = OGMCIN.th_info.width;
401 OGMCIN.outputHeight = OGMCIN.th_info.height;
402 Com_DPrintf(DEBUG_CLIENT, "[Theora(ogg)]new resolution %dx%d\n", OGMCIN.outputWidth, OGMCIN.outputHeight);
403 }
404
405 if (OGMCIN.outputBufferSize < OGMCIN.th_info.width * OGMCIN.th_info.height) {
406 OGMCIN.outputBufferSize = OGMCIN.th_info.width * OGMCIN.th_info.height;
407
408 /* Free old output buffer*/
409 Mem_Free(OGMCIN.outputBuffer);
410
411 /* Allocate the new buffer */
412 OGMCIN.outputBuffer = Mem_PoolAllocTypeN(unsigned, OGMCIN.outputBufferSize, cl_genericPool);
413 if (OGMCIN.outputBuffer == nullptr) {
414 OGMCIN.outputBufferSize = 0;
415 r = -2;
416 break;
417 }
418 }
419
420 yWShift = CIN_THEORA_FindSizeShift(OGMCIN.th_yuvbuffer.y_width, OGMCIN.th_info.width);
421 uvWShift = CIN_THEORA_FindSizeShift(OGMCIN.th_yuvbuffer.uv_width, OGMCIN.th_info.width);
422 yHShift = CIN_THEORA_FindSizeShift(OGMCIN.th_yuvbuffer.y_height, OGMCIN.th_info.height);
423 uvHShift = CIN_THEORA_FindSizeShift(OGMCIN.th_yuvbuffer.uv_height, OGMCIN.th_info.height);
424
425 if (yWShift < 0 || uvWShift < 0 || yHShift < 0 || uvHShift < 0) {
426 Com_Printf("[Theora] unexpected resolution in a yuv-frame\n");
427 r = -1;
428 } else {
429 CIN_THEORA_FrameYUVtoRGB24(OGMCIN.th_yuvbuffer.y, OGMCIN.th_yuvbuffer.u, OGMCIN.th_yuvbuffer.v,
430 OGMCIN.th_info.width, OGMCIN.th_info.height, OGMCIN.th_yuvbuffer.y_stride,
431 OGMCIN.th_yuvbuffer.uv_stride, yWShift, uvWShift, yHShift, uvHShift,
432 OGMCIN.outputBuffer);
433
434 r = 1;
435 OGMCIN.videoFrameCount = th_frame;
436 }
437 }
438 }
439
440 return r;
441}
442#endif
443
449{
450#ifdef HAVE_XVID_H
451 if (OGMCIN.videoStreamIsXvid)
452 return CIN_XVID_LoadVideoFrame(cin);
453#endif
454#ifdef HAVE_THEORA_THEORA_H
455 if (OGMCIN.videoStreamIsTheora)
456 return CIN_THEORA_LoadVideoFrame(cin);
457#endif
458
459 /* if we come to this point, there will be no codec that use the stream content ... */
460 if (OGMCIN.os_video.serialno) {
461 ogg_packet op;
462
463 while (ogg_stream_packetout(&OGMCIN.os_video, &op))
464 ;
465 }
466
467 return 1;
468}
469
474{
475 bool anyDataTransferred = true;
476 bool needVOutputData = true;
477 bool audioWantsMoreData = false;
478
479 while (anyDataTransferred && (needVOutputData || audioWantsMoreData)) {
480 int status;
481 anyDataTransferred = false;
482 if (needVOutputData && (status = CIN_OGM_LoadVideoFrame(cin))) {
483 needVOutputData = false;
484 if (status > 0)
485 anyDataTransferred = true;
486 else
487 /* error (we don't need any videodata and we had no transferred) */
488 anyDataTransferred = false;
489 }
490
491 if (needVOutputData || audioWantsMoreData) {
492 /* try to transfer Pages to the audio- and video-Stream */
494 /* try to load a datablock from file */
495 anyDataTransferred |= !CIN_OGM_LoadBlockToSync(cin);
496 else
497 /* successful loadPagesToStreams() */
498 anyDataTransferred = true;
499 }
500
501 /* load all audio after loading new pages ... */
502 if (OGMCIN.videoFrameCount > 1)
503 /* wait some videoframes (it's better to have some delay, than a laggy sound) */
504 audioWantsMoreData = CIN_OGM_LoadAudioFrame(cin);
505 }
506
507 return !anyDataTransferred;
508}
509
510#ifdef HAVE_XVID_H
512typedef struct
513{
514 char streamtype[8];
515 char subtype[4];
516
517 ogg_int32_t size; /* size of the structure */
518
519 /* in 10^-7 seconds (dT between frames) */
520 ogg_int64_t time_unit; /* in reference time */
521 ogg_int64_t samples_per_unit;
522 ogg_int32_t default_len; /* in media time */
523
524 ogg_int32_t buffersize;
525 ogg_int16_t bits_per_sample;
526 union
527 {
528 struct
529 {
530 ogg_int32_t width;
531 ogg_int32_t height;
532 } stream_header_video;
533
534 struct
535 {
536 ogg_int16_t channels;
537 ogg_int16_t blockalign;
538 ogg_int32_t avgbytespersec;
539 } stream_header_audio;
540 } sh;
541} stream_header_t;
542#endif
543
550{
551 if (cin->codecData && (OGMCIN.ogmFile.f || OGMCIN.ogmFile.z)) {
552 Com_Printf("WARNING: it seams there was already a ogm running, it will be killed to start %s\n", filename);
554 }
555
556 /* alloc memory for decoding of this video */
557 assert(cin->codecData == nullptr);
559
560 if (FS_OpenFile(filename, &OGMCIN.ogmFile, FILE_READ) == -1) {
561 Com_Printf("Can't open ogm-file for reading (%s)\n", filename);
562 return -1;
563 }
564
566 OGMCIN.startTime = CL_Milliseconds();
567
568 ogg_sync_init(&OGMCIN.oy); /* Now we can read pages */
569
572 ogg_page og;
573 while (!OGMCIN.os_audio.serialno || !OGMCIN.os_video.serialno) {
574 if (ogg_sync_pageout(&OGMCIN.oy, &og) == 1) {
575 if (og.body_len >= 7 && !memcmp(og.body, "\x01vorbis", 7)) {
576 if (OGMCIN.os_audio.serialno) {
577 Com_Printf("more than one audio stream, in ogm-file(%s) ... we will stay at the first one\n",
578 filename);
579 } else {
580 ogg_stream_init(&OGMCIN.os_audio, ogg_page_serialno(&og));
581 ogg_stream_pagein(&OGMCIN.os_audio, &og);
582 }
583 }
584#ifdef HAVE_THEORA_THEORA_H
585 else if (og.body_len >= 7 && !memcmp(og.body, "\x80theora", 7)) {
586 if (OGMCIN.os_video.serialno) {
587 Com_Printf("more than one video stream, in ogm-file(%s) ... we will stay at the first one\n",
588 filename);
589 } else {
590 OGMCIN.videoStreamIsTheora = true;
591 ogg_stream_init(&OGMCIN.os_video, ogg_page_serialno(&og));
592 ogg_stream_pagein(&OGMCIN.os_video, &og);
593 }
594 }
595#endif
596#ifdef HAVE_XVID_H
597 else if (strstr((const char*) (og.body + 1), "video")) {
598 if (OGMCIN.os_video.serialno) {
599 Com_Printf("more than one video stream, in ogm-file(%s) ... we will stay at the first one\n",
600 filename);
601 } else {
602 OGMCIN.videoStreamIsXvid = true;
603
604 stream_header_t* sh = (stream_header_t*) (og.body + 1);
605
606 OGMCIN.Vtime_unit = sh->time_unit;
607
608 ogg_stream_init(&OGMCIN.os_video, ogg_page_serialno(&og));
609 ogg_stream_pagein(&OGMCIN.os_video, &og);
610 }
611 }
612#endif
613 } else if (CIN_OGM_LoadBlockToSync(cin))
614 break;
615 }
616
617 if (OGMCIN.videoStreamIsXvid && OGMCIN.videoStreamIsTheora) {
618 Com_Printf("Found \"video\"- and \"theora\"-stream, ogm-file (%s)\n", filename);
619 return -2;
620 }
621
622 if (!OGMCIN.os_audio.serialno) {
623 Com_Printf("Haven't found an audio (vorbis) stream in ogm-file (%s)\n", filename);
624 return -2;
625 }
626 if (!OGMCIN.os_video.serialno) {
627 Com_Printf("Haven't found a video stream in ogm-file (%s)\n", filename);
628 return -3;
629 }
630
631 /* load vorbis header */
632 vorbis_info_init(&OGMCIN.vi);
633 vorbis_comment_init(&OGMCIN.vc);
634 int i = 0;
635 int status;
636 ogg_packet op;
637 while (i < 3) {
638 status = ogg_stream_packetout(&OGMCIN.os_audio, &op);
639 if (status < 0) {
640 Com_Printf("Corrupt ogg packet while loading vorbis-headers, ogm-file(%s)\n", filename);
641 return -8;
642 }
643 if (status > 0) {
644 status = vorbis_synthesis_headerin(&OGMCIN.vi, &OGMCIN.vc, &op);
645 if (i == 0 && status < 0) {
646 Com_Printf("This Ogg bitstream does not contain Vorbis audio data, ogm-file(%s)\n", filename);
647 return -9;
648 }
649 ++i;
650 } else if (CIN_OGM_LoadPagesToStream(cin)) {
651 if (CIN_OGM_LoadBlockToSync(cin)) {
652 Com_Printf("Couldn't find all vorbis headers before end of ogm-file (%s)\n", filename);
653 return -10;
654 }
655 }
656 }
657
658 vorbis_synthesis_init(&OGMCIN.vd, &OGMCIN.vi);
659
660#ifdef HAVE_XVID_H
661 status = CIN_XVID_Init(cin);
662 if (status) {
663 Com_Printf("[Xvid]Decore INIT problem, return value %d(ogm-file: %s)\n", status, filename);
664 return -4;
665 }
666#endif
667
668#ifdef HAVE_THEORA_THEORA_H
669 if (OGMCIN.videoStreamIsTheora) {
670 theora_info_init(&OGMCIN.th_info);
671 theora_comment_init(&OGMCIN.th_comment);
672
673 i = 0;
674 while (i < 3) {
675 status = ogg_stream_packetout(&OGMCIN.os_video, &op);
676 if (status < 0) {
677 Com_Printf("Corrupt ogg packet while loading theora-headers, ogm-file(%s)\n", filename);
678
679 return -8;
680 }
681 if (status > 0) {
682 status = theora_decode_header(&OGMCIN.th_info, &OGMCIN.th_comment, &op);
683 if (i == 0 && status != 0) {
684 Com_Printf("This Ogg bitstream does not contain theora data, ogm-file(%s)\n", filename);
685
686 return -9;
687 }
688 ++i;
689 } else if (CIN_OGM_LoadPagesToStream(cin)) {
690 if (CIN_OGM_LoadBlockToSync(cin)) {
691 Com_Printf("Couldn't find all theora headers before end of ogm-file (%s)\n", filename);
692
693 return -10;
694 }
695 }
696 }
697
698 theora_decode_init(&OGMCIN.th_state, &OGMCIN.th_info);
699 OGMCIN.Vtime_unit = ((ogg_int64_t) OGMCIN.th_info.fps_denominator * 1000 * 10000 / OGMCIN.th_info.fps_numerator);
700 }
701#endif
702
703 return 0;
704}
705
710{
711 assert(cin->status != CIN_STATUS_NONE);
712
713 if (!OGMCIN.outputBuffer)
714 return;
715 const int texnum = R_UploadData("***cinematic***", OGMCIN.outputBuffer, OGMCIN.outputWidth, OGMCIN.outputHeight);
716 R_DrawTexture(texnum, cin->x, cin->y, cin->w, cin->h);
717}
718
723{
724 /* no video stream found */
725 if (!OGMCIN.os_video.serialno)
726 return false;
727
728 OGMCIN.currentTime = CL_Milliseconds() - OGMCIN.startTime;
729
730 while (!OGMCIN.videoFrameCount || OGMCIN.currentTime + 20 >= (int) (OGMCIN.videoFrameCount * OGMCIN.Vtime_unit / 10000)) {
731 if (CIN_OGM_LoadFrame(cin))
732 return false;
733 }
734
736
737 return true;
738}
739
741{
742#ifdef HAVE_XVID_H
744 CIN_XVID_Shutdown(cin);
745#endif
746
747#ifdef HAVE_THEORA_THEORA_H
748 theora_clear(&OGMCIN.th_state);
749 theora_comment_clear(&OGMCIN.th_comment);
750 theora_info_clear(&OGMCIN.th_info);
751#endif
752
753 M_StopMusicStream(&OGMCIN.musicStream);
754
755 Mem_Free(OGMCIN.outputBuffer);
756 OGMCIN.outputBuffer = nullptr;
757
758 vorbis_dsp_clear(&OGMCIN.vd);
759 vorbis_comment_clear(&OGMCIN.vc);
760 vorbis_info_clear(&OGMCIN.vi); /* must be called last (comment from vorbis example code) */
761
762 ogg_stream_clear(&OGMCIN.os_audio);
763 ogg_stream_clear(&OGMCIN.os_video);
764
765 ogg_sync_clear(&OGMCIN.oy);
766
767 FS_CloseFile(&OGMCIN.ogmFile);
768
769 /* free data allocated for decodage */
770 Mem_Free(cin->codecData);
771 cin->codecData = nullptr;
772}
773
774void CIN_OGM_Init (void)
775{
776 const float t_ub = (1.77200f / 2.0f) * (float)(1 << 6) + 0.5f;
777 const float t_vr = (1.40200f / 2.0f) * (float)(1 << 6) + 0.5f;
778 const float t_ug = (0.34414f / 2.0f) * (float)(1 << 6) + 0.5f;
779 const float t_vg = (0.71414f / 2.0f) * (float)(1 << 6) + 0.5f;
780
781 for (long i = 0; i < 256; i++) {
782 const float x = (float)(2 * i - 255);
783
784 ogmCin_yuvTable.ub[i] = (long)(( t_ub * x) + (1 << 5));
785 ogmCin_yuvTable.vr[i] = (long)(( t_vr * x) + (1 << 5));
786 ogmCin_yuvTable.ug[i] = (long)((-t_ug * x));
787 ogmCin_yuvTable.vg[i] = (long)((-t_vg * x) + (1 << 5));
788 ogmCin_yuvTable.yy[i] = (long)((i << 6) | (i >> 2));
789 }
790}
791#else
792int CIN_OGM_OpenCinematic(struct cinematic_s* cin, const char* filename) {return 0;}
793void CIN_OGM_CloseCinematic(struct cinematic_s* cin) {}
794bool CIN_OGM_RunCinematic(struct cinematic_s* cin) {return false;}
795void CIN_OGM_Init(void) {}
796#endif
#define LittleLong(X)
Definition byte.h:37
Header file for cinematics.
@ CINEMATIC_TYPE_OGM
@ CIN_STATUS_NONE
#define SIZEOF_RAWBUFF
#define OGG_BUFFER_SIZE
static byte rawBuffer[SIZEOF_RAWBUFF]
static void CIN_OGM_DrawCinematic(cinematic_t *cin)
bool CIN_OGM_RunCinematic(cinematic_t *cin)
void CIN_OGM_Init(void)
void CIN_OGM_CloseCinematic(cinematic_t *cin)
int CIN_OGM_OpenCinematic(cinematic_t *cin, const char *filename)
static yuvTable_t ogmCin_yuvTable
#define OGMCIN
static bool CIN_OGM_LoadFrame(cinematic_t *cin)
static int CIN_OGM_LoadPagesToStream(cinematic_t *cin)
static bool CIN_OGM_LoadAudioFrame(cinematic_t *cin)
static int CIN_OGM_LoadBlockToSync(cinematic_t *cin)
static int CIN_OGM_LoadVideoFrame(cinematic_t *cin)
Header file for OGM cinematics.
void FS_CloseFile(qFILE *f)
memPool_t * vid_genericPool
Definition cl_main.cpp:87
memPool_t * cl_genericPool
Definition cl_main.cpp:86
int CL_Milliseconds(void)
Definition cl_main.cpp:1207
Primary header for client.
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition common.cpp:440
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define DEBUG_CLIENT
Definition defines.h:59
int FS_Read(void *buffer, int len, qFILE *f)
Definition files.cpp:371
int FS_OpenFile(const char *filename, qFILE *file, filemode_t mode)
Finds and opens the file in the search path.
Definition files.cpp:162
@ FILE_READ
Definition filesys.h:111
voidpf void uLong size
Definition ioapi.h:42
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
const char * filename
Definition ioapi.h:41
#define Mem_PoolAllocTypeN(type, n, pool)
Definition mem.h:42
#define Mem_Free(ptr)
Definition mem.h:35
#define Mem_PoolAllocType(type, pool)
Definition mem.h:43
void R_DrawTexture(int texnum, int x, int y, int w, int h)
Bind and draw a texture.
Definition r_draw.cpp:328
int R_UploadData(const char *name, unsigned *frame, int width, int height)
Uploads image data.
Definition r_draw.cpp:270
QGL_EXTERN int GLboolean GLfloat * v
Definition r_gl.h:120
QGL_EXTERN GLint i
Definition r_gl.h:113
Specifies sound API?
void M_StopMusicStream(musicStream_t *userdata)
Definition s_music.cpp:462
void M_AddToSampleBuffer(musicStream_t *userdata, int rate, int samples, const byte *data)
Add stereo samples with a 16 byte width to the stream buffer.
Definition s_music.cpp:428
Specifies music API.
#define OBJZERO(obj)
Definition shared.h:178
void * codecData
vorbis_comment vc
ogg_sync_state oy
ogg_stream_state os_video
ogg_int64_t Vtime_unit
musicStream_t musicStream
vorbis_dsp_state vd
unsigned * outputBuffer
ogg_stream_state os_audio