UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cl_cinematic_ogm.cpp
Go to the documentation of this file.
1 
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 
29 typedef struct {
30  long vr[256];
31  long ug[256];
32  long vg[256];
33  long ub[256];
34  long yy[256];
35 } yuvTable_t;
36 
37 #define OGG_BUFFER_SIZE (8 * 1024)
38 
39 typedef 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;
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;
74  int startTime;
75 
78 
80 
81 #define OGMCIN (*((ogmCinematic_t*)cin->codecData))
82 
83 #ifdef HAVE_XVID_H
84 
85 static 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 
116 static 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 
148 static 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
274 static 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
323 
327 static 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 
340 static 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 
351 static 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 
370 static int CIN_THEORA_NextNeededFrame (cinematic_t* cin)
371 {
372  return (int) (OGMCIN.currentTime * (ogg_int64_t) 10000 / OGMCIN.Vtime_unit);
373 }
374 
379 static 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 
473 static bool CIN_OGM_LoadFrame (cinematic_t* cin)
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 */
493  if (CIN_OGM_LoadPagesToStream(cin))
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
511 
512 typedef 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
743 
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 
774 void 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
792 int CIN_OGM_OpenCinematic(struct cinematic_s* cin, const char* filename) {return 0;}
793 void CIN_OGM_CloseCinematic(struct cinematic_s* cin) {}
794 bool CIN_OGM_RunCinematic(struct cinematic_s* cin) {return false;}
795 void CIN_OGM_Init(void) {}
796 #endif
#define OGG_BUFFER_SIZE
musicStream_t musicStream
static int CIN_OGM_LoadBlockToSync(cinematic_t *cin)
int FS_OpenFile(const char *filename, qFILE *file, filemode_t mode)
Finds and opens the file in the search path.
Definition: files.cpp:162
static void CIN_OGM_DrawCinematic(cinematic_t *cin)
ogg_stream_state os_audio
const char * filename
Definition: ioapi.h:41
memPool_t * vid_genericPool
Definition: cl_main.cpp:87
unsigned * outputBuffer
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
ogg_sync_state oy
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
#define OGMCIN
static yuvTable_t ogmCin_yuvTable
ogg_int64_t Vtime_unit
memPool_t * cl_genericPool
Definition: cl_main.cpp:86
vorbis_dsp_state vd
#define DEBUG_CLIENT
Definition: defines.h:59
void R_DrawTexture(int texnum, int x, int y, int w, int h)
Bind and draw a texture.
Definition: r_draw.cpp:328
GLsizei size
Definition: r_gl.h:152
#define OBJZERO(obj)
Definition: shared.h:178
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
void M_StopMusicStream(musicStream_t *userdata)
Definition: s_music.cpp:465
void FS_CloseFile(qFILE *f)
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition: common.cpp:398
int R_UploadData(const char *name, unsigned *frame, int width, int height)
Uploads image data.
Definition: r_draw.cpp:270
Header file for OGM cinematics.
int CIN_OGM_OpenCinematic(cinematic_t *cin, const char *filename)
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define Mem_PoolAllocTypeN(type, n, pool)
Definition: mem.h:42
int FS_Read(void *buffer, int len, qFILE *f)
Definition: files.cpp:371
QGL_EXTERN GLint i
Definition: r_gl.h:113
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:431
void CIN_OGM_Init(void)
static int CIN_OGM_LoadPagesToStream(cinematic_t *cin)
static int CIN_OGM_LoadVideoFrame(cinematic_t *cin)
#define Mem_Free(ptr)
Definition: mem.h:35
ogg_stream_state os_video
bool CIN_OGM_RunCinematic(cinematic_t *cin)
vorbis_comment vc
#define Mem_PoolAllocType(type, pool)
Definition: mem.h:43
#define SIZEOF_RAWBUFF
uint8_t byte
Definition: ufotypes.h:34
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
static byte rawBuffer[SIZEOF_RAWBUFF]
static bool CIN_OGM_LoadAudioFrame(cinematic_t *cin)
void * codecData
Definition: cl_cinematic.h:50
Header file for cinematics.
int cinematicType
Definition: cl_cinematic.h:46
void CIN_OGM_CloseCinematic(cinematic_t *cin)
int CL_Milliseconds(void)
Definition: cl_main.cpp:1208
#define LittleLong(X)
Definition: byte.h:37
static bool CIN_OGM_LoadFrame(cinematic_t *cin)