13 #include "../client.h"
14 #include "../renderer/r_draw.h"
15 #include "../sound/s_main.h"
16 #include "../sound/s_music.h"
19 #include <vorbis/codec.h>
24 #ifdef HAVE_THEORA_THEORA_H
25 #include <theora/theora.h>
37 #define OGG_BUFFER_SIZE (8 * 1024)
55 xvid_dec_stats_t xvidDecodeStats;
56 void* xvidDecodeHandle;
59 #ifdef HAVE_THEORA_THEORA_H
61 theora_comment th_comment;
62 theora_state th_state;
64 yuv_buffer th_yuvbuffer;
81 #define OGMCIN (*((ogmCinematic_t*)cin->codecData))
87 xvid_gbl_init_t xvid_gbl_init;
88 xvid_dec_create_t xvid_dec_create;
95 xvid_gbl_init.version = XVID_VERSION;
97 xvid_gbl_init.cpu_flags = 0;
98 xvid_gbl_init.debug = 0;
100 xvid_global(
nullptr, 0, &xvid_gbl_init,
nullptr);
103 xvid_dec_create.version = XVID_VERSION;
106 xvid_dec_create.width = 0;
107 xvid_dec_create.height = 0;
109 const int ret = xvid_decore(
nullptr, XVID_DEC_CREATE, &xvid_dec_create,
nullptr);
111 OGMCIN.xvidDecodeHandle = xvid_dec_create.handle;
116 static int CIN_XVID_Decode (
cinematic_t* cin,
unsigned char* input,
int inputSize)
118 xvid_dec_frame_t xvid_dec_frame;
125 xvid_dec_frame.version = XVID_VERSION;
126 OGMCIN.xvidDecodeStats.version = XVID_VERSION;
129 xvid_dec_frame.general = XVID_LOWDELAY;
132 xvid_dec_frame.bitstream = input;
133 xvid_dec_frame.length = inputSize;
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;
141 xvid_dec_frame.output.csp = XVID_CSP_RGBA;
143 const int ret = xvid_decore(
OGMCIN.xvidDecodeHandle, XVID_DEC_DECODE, &xvid_dec_frame, &
OGMCIN.xvidDecodeStats);
152 if (
OGMCIN.xvidDecodeHandle)
153 ret = xvid_decore(
OGMCIN.xvidDecodeHandle, XVID_DEC_DESTROY,
nullptr,
nullptr);
170 ogg_sync_wrote(&
OGMCIN.oy, bytes);
186 ogg_stream_state* osptr =
nullptr;
189 while (!audioPages || !videoPages) {
190 if (ogg_sync_pageout(&
OGMCIN.oy, &og) != 1)
193 if (
OGMCIN.os_audio.serialno == ogg_page_serialno(&og)) {
197 if (
OGMCIN.os_video.serialno == ogg_page_serialno(&og)) {
202 if (osptr !=
nullptr) {
203 ogg_stream_pagein(osptr, &og);
207 if (audioPages && videoPages)
213 #define SIZEOF_RAWBUFF SAMPLE_SIZE * 1024
224 vorbis_block_init(&
OGMCIN.vd, &vb);
228 const int samples = vorbis_synthesis_pcmout(&
OGMCIN.vd, &pcm);
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;
240 if (samples < samplesNeeded)
241 samplesNeeded = samples;
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.0
f) - (left[
i] < 0.0f));
245 ptr[1] = (right[
i] >= -1.0f && right[
i] <= 1.0f) ? right[i] * 32767.
f : 32767 * ((right[i] > 0.0
f) - (right[
i] < 0.0f));
249 vorbis_synthesis_read(&
OGMCIN.vd, i);
256 if (ogg_stream_packetout(&
OGMCIN.os_audio, &op)) {
257 if (vorbis_synthesis(&vb, &op) == 0)
258 vorbis_synthesis_blockin(&
OGMCIN.vd, &vb);
264 vorbis_block_clear(&vb);
274 static int CIN_XVID_LoadVideoFrame (
cinematic_t* cin)
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;
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;
299 if (
OGMCIN.outputBuffer ==
nullptr) {
300 OGMCIN.outputBufferSize = 0;
307 CIN_XVID_Decode(cin, op.packet + usedBytes, op.bytes - usedBytes);
311 if (
OGMCIN.xvidDecodeStats.type > 0) {
322 #ifdef HAVE_THEORA_THEORA_H
327 static int CIN_THEORA_FindSizeShift (
int x,
int y)
329 for (
int i = 0; (y >>
i); ++
i)
340 static inline byte CIN_THEORA_ClampByte (
int value)
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,
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;
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);
364 const uint32_t rgb24 =
LittleLong(r | (g << 8) | (b << 16) | (255 << 24));
370 static int CIN_THEORA_NextNeededFrame (
cinematic_t* cin)
372 return (
int) (
OGMCIN.currentTime * (ogg_int64_t) 10000 /
OGMCIN.Vtime_unit);
379 static int CIN_THEORA_LoadVideoFrame (
cinematic_t* cin)
386 while (!r && (ogg_stream_packetout(&
OGMCIN.os_video, &op))) {
387 ogg_int64_t th_frame;
388 theora_decode_packetin(&
OGMCIN.th_state, &op);
390 th_frame = theora_granule_frame(&
OGMCIN.th_state,
OGMCIN.th_state.granulepos);
392 if ((
OGMCIN.videoFrameCount < th_frame && th_frame >= CIN_THEORA_NextNeededFrame(cin)) || !
OGMCIN.outputBuffer) {
393 int yWShift, uvWShift;
394 int yHShift, uvHShift;
396 if (theora_decode_YUVout(&
OGMCIN.th_state, &
OGMCIN.th_yuvbuffer))
413 if (
OGMCIN.outputBuffer ==
nullptr) {
414 OGMCIN.outputBufferSize = 0;
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);
425 if (yWShift < 0 || uvWShift < 0 || yHShift < 0 || uvHShift < 0) {
426 Com_Printf(
"[Theora] unexpected resolution in a yuv-frame\n");
429 CIN_THEORA_FrameYUVtoRGB24(
OGMCIN.th_yuvbuffer.y,
OGMCIN.th_yuvbuffer.u,
OGMCIN.th_yuvbuffer.v,
431 OGMCIN.th_yuvbuffer.uv_stride, yWShift, uvWShift, yHShift, uvHShift,
435 OGMCIN.videoFrameCount = th_frame;
451 if (
OGMCIN.videoStreamIsXvid)
452 return CIN_XVID_LoadVideoFrame(cin);
454 #ifdef HAVE_THEORA_THEORA_H
455 if (
OGMCIN.videoStreamIsTheora)
456 return CIN_THEORA_LoadVideoFrame(cin);
460 if (
OGMCIN.os_video.serialno) {
463 while (ogg_stream_packetout(&
OGMCIN.os_video, &op))
475 bool anyDataTransferred =
true;
476 bool needVOutputData =
true;
477 bool audioWantsMoreData =
false;
479 while (anyDataTransferred && (needVOutputData || audioWantsMoreData)) {
481 anyDataTransferred =
false;
483 needVOutputData =
false;
485 anyDataTransferred =
true;
488 anyDataTransferred =
false;
491 if (needVOutputData || audioWantsMoreData) {
498 anyDataTransferred =
true;
502 if (
OGMCIN.videoFrameCount > 1)
507 return !anyDataTransferred;
520 ogg_int64_t time_unit;
521 ogg_int64_t samples_per_unit;
522 ogg_int32_t default_len;
524 ogg_int32_t buffersize;
525 ogg_int16_t bits_per_sample;
532 } stream_header_video;
536 ogg_int16_t channels;
537 ogg_int16_t blockalign;
538 ogg_int32_t avgbytespersec;
539 } stream_header_audio;
552 Com_Printf(
"WARNING: it seams there was already a ogm running, it will be killed to start %s\n", filename);
561 Com_Printf(
"Can't open ogm-file for reading (%s)\n", filename);
568 ogg_sync_init(&
OGMCIN.oy);
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",
580 ogg_stream_init(&
OGMCIN.os_audio, ogg_page_serialno(&og));
581 ogg_stream_pagein(&
OGMCIN.os_audio, &og);
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",
590 OGMCIN.videoStreamIsTheora =
true;
591 ogg_stream_init(&
OGMCIN.os_video, ogg_page_serialno(&og));
592 ogg_stream_pagein(&
OGMCIN.os_video, &og);
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",
602 OGMCIN.videoStreamIsXvid =
true;
604 stream_header_t* sh = (stream_header_t*) (og.body + 1);
606 OGMCIN.Vtime_unit = sh->time_unit;
608 ogg_stream_init(&
OGMCIN.os_video, ogg_page_serialno(&og));
609 ogg_stream_pagein(&
OGMCIN.os_video, &og);
617 if (
OGMCIN.videoStreamIsXvid &&
OGMCIN.videoStreamIsTheora) {
618 Com_Printf(
"Found \"video\"- and \"theora\"-stream, ogm-file (%s)\n", filename);
622 if (!
OGMCIN.os_audio.serialno) {
623 Com_Printf(
"Haven't found an audio (vorbis) stream in ogm-file (%s)\n", filename);
626 if (!
OGMCIN.os_video.serialno) {
627 Com_Printf(
"Haven't found a video stream in ogm-file (%s)\n", filename);
632 vorbis_info_init(&
OGMCIN.vi);
633 vorbis_comment_init(&
OGMCIN.vc);
638 status = ogg_stream_packetout(&
OGMCIN.os_audio, &op);
640 Com_Printf(
"Corrupt ogg packet while loading vorbis-headers, ogm-file(%s)\n", filename);
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);
652 Com_Printf(
"Couldn't find all vorbis headers before end of ogm-file (%s)\n", filename);
661 status = CIN_XVID_Init(cin);
663 Com_Printf(
"[Xvid]Decore INIT problem, return value %d(ogm-file: %s)\n", status, filename);
668 #ifdef HAVE_THEORA_THEORA_H
669 if (
OGMCIN.videoStreamIsTheora) {
670 theora_info_init(&
OGMCIN.th_info);
671 theora_comment_init(&
OGMCIN.th_comment);
675 status = ogg_stream_packetout(&
OGMCIN.os_video, &op);
677 Com_Printf(
"Corrupt ogg packet while loading theora-headers, ogm-file(%s)\n", filename);
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);
691 Com_Printf(
"Couldn't find all theora headers before end of ogm-file (%s)\n", filename);
699 OGMCIN.Vtime_unit = ((ogg_int64_t)
OGMCIN.th_info.fps_denominator * 1000 * 10000 /
OGMCIN.th_info.fps_numerator);
725 if (!
OGMCIN.os_video.serialno)
730 while (!
OGMCIN.videoFrameCount ||
OGMCIN.currentTime + 20 >= (
int) (
OGMCIN.videoFrameCount *
OGMCIN.Vtime_unit / 10000)) {
744 CIN_XVID_Shutdown(cin);
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);
756 OGMCIN.outputBuffer =
nullptr;
758 vorbis_dsp_clear(&
OGMCIN.vd);
759 vorbis_comment_clear(&
OGMCIN.vc);
760 vorbis_info_clear(&
OGMCIN.vi);
762 ogg_stream_clear(&
OGMCIN.os_audio);
763 ogg_stream_clear(&
OGMCIN.os_video);
765 ogg_sync_clear(&
OGMCIN.oy);
776 const float t_ub = (1.77200f / 2.0f) * (
float)(1 << 6) + 0.5
f;
777 const float t_vr = (1.40200f / 2.0f) * (
float)(1 << 6) + 0.5
f;
778 const float t_ug = (0.34414f / 2.0f) * (
float)(1 << 6) + 0.5
f;
779 const float t_vg = (0.71414f / 2.0f) * (
float)(1 << 6) + 0.5
f;
781 for (
long i = 0;
i < 256;
i++) {
782 const float x = (float)(2 *
i - 255);
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));
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.
static void CIN_OGM_DrawCinematic(cinematic_t *cin)
ogg_stream_state os_audio
memPool_t * vid_genericPool
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void Com_Printf(const char *const fmt,...)
static yuvTable_t ogmCin_yuvTable
memPool_t * cl_genericPool
void R_DrawTexture(int texnum, int x, int y, int w, int h)
Bind and draw a texture.
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
void M_StopMusicStream(musicStream_t *userdata)
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.
int R_UploadData(const char *name, unsigned *frame, int width, int height)
Uploads image data.
Header file for OGM cinematics.
int CIN_OGM_OpenCinematic(cinematic_t *cin, const char *filename)
#define Mem_PoolAllocTypeN(type, n, pool)
int FS_Read(void *buffer, int len, qFILE *f)
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.
static int CIN_OGM_LoadPagesToStream(cinematic_t *cin)
static int CIN_OGM_LoadVideoFrame(cinematic_t *cin)
ogg_stream_state os_video
bool CIN_OGM_RunCinematic(cinematic_t *cin)
#define Mem_PoolAllocType(type, pool)
QGL_EXTERN int GLboolean GLfloat * v
static byte rawBuffer[SIZEOF_RAWBUFF]
static bool CIN_OGM_LoadAudioFrame(cinematic_t *cin)
Header file for cinematics.
void CIN_OGM_CloseCinematic(cinematic_t *cin)
int CL_Milliseconds(void)
static bool CIN_OGM_LoadFrame(cinematic_t *cin)