10 // video capture cvars
11 static cvar_t cl_capturevideo_ogg_theora_quality = {CVAR_SAVE, "cl_capturevideo_ogg_theora_quality", "32", "video quality factor (0 to 63), or -1 to use bitrate only; higher is better"};
12 static cvar_t cl_capturevideo_ogg_theora_bitrate = {CVAR_SAVE, "cl_capturevideo_ogg_theora_bitrate", "-1", "video bitrate (45 to 2000 kbps), or -1 to use quality only; higher is better"};
13 static cvar_t cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier", "1.5", "how much more bit rate to use for keyframes, specified as a factor of at least 1"};
14 static cvar_t cl_capturevideo_ogg_theora_keyframe_maxinterval = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_maxinterval", "64", "maximum keyframe interval (1 to 1000)"};
15 static cvar_t cl_capturevideo_ogg_theora_keyframe_mininterval = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_mininterval", "8", "minimum keyframe interval (1 to 1000)"};
16 static cvar_t cl_capturevideo_ogg_theora_keyframe_auto_threshold = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_auto_threshold", "80", "threshold for key frame decision (0 to 100)"};
17 static cvar_t cl_capturevideo_ogg_theora_noise_sensitivity = {CVAR_SAVE, "cl_capturevideo_ogg_theora_noise_sensitivity", "1", "video noise sensitivity (0 to 6); lower is better"};
18 static cvar_t cl_capturevideo_ogg_theora_sharpness = {CVAR_SAVE, "cl_capturevideo_ogg_theora_sharpness", "0", "sharpness (0 to 2); lower is sharper"};
19 static cvar_t cl_capturevideo_ogg_vorbis_quality = {CVAR_SAVE, "cl_capturevideo_ogg_vorbis_quality", "3", "audio quality (-1 to 10); higher is better"};
23 typedef __int16 ogg_int16_t;
24 typedef unsigned __int16 ogg_uint16_t;
25 typedef __int32 ogg_int32_t;
26 typedef unsigned __int32 ogg_uint32_t;
27 typedef __int64 ogg_int64_t;
29 typedef int16_t ogg_int16_t;
30 typedef uint16_t ogg_uint16_t;
31 typedef int32_t ogg_int32_t;
32 typedef uint32_t ogg_uint32_t;
33 typedef int64_t ogg_int64_t;
40 unsigned char *buffer;
45 /* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
48 unsigned char *header;
54 /* ogg_stream_state contains the current encode/decode state of a logical
55 Ogg bitstream **********************************************************/
58 unsigned char *body_data; /* bytes from packet bodies */
59 long body_storage; /* storage elements allocated */
60 long body_fill; /* elements stored; fill mark */
61 long body_returned; /* elements of fill returned */
64 int *lacing_vals; /* The values that will go to the segment table */
65 ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
66 this way, but it is simple coupled to the
73 unsigned char header[282]; /* working space for header encode */
76 int e_o_s; /* set when we have buffered the last packet in the
78 int b_o_s; /* set after we've written the initial page
79 of a logical bitstream */
82 ogg_int64_t packetno; /* sequence number for decode; the framing
83 knows where there's a hole in the data,
84 but we need coupling so that the codec
85 (which is in a seperate abstraction
86 layer) also knows about the gap */
87 ogg_int64_t granulepos;
91 /* ogg_packet is used to encapsulate the data and metadata belonging
92 to a single raw Ogg/Vorbis packet *************************************/
95 unsigned char *packet;
100 ogg_int64_t granulepos;
102 ogg_int64_t packetno; /* sequence number for decode; the framing
103 knows where there's a hole in the data,
104 but we need coupling so that the codec
105 (which is in a seperate abstraction
106 layer) also knows about the gap */
120 /* Ogg BITSTREAM PRIMITIVES: encoding **************************/
122 static int (*qogg_stream_packetin) (ogg_stream_state *os, ogg_packet *op);
123 static int (*qogg_stream_pageout) (ogg_stream_state *os, ogg_page *og);
124 static int (*qogg_stream_flush) (ogg_stream_state *os, ogg_page *og);
126 /* Ogg BITSTREAM PRIMITIVES: general ***************************/
128 static int (*qogg_stream_init) (ogg_stream_state *os,int serialno);
129 static int (*qogg_stream_clear) (ogg_stream_state *os);
130 static ogg_int64_t (*qogg_page_granulepos) (ogg_page *og);
132 // end of ogg.h stuff
134 // vorbis/codec.h stuff
135 typedef struct vorbis_info{
140 /* The below bitrate declarations are *hints*.
141 Combinations of the three values carry the following implications:
143 all three set to the same value:
144 implies a fixed rate bitstream
146 implies a VBR stream that averages the nominal bitrate. No hard
148 upper and or lower set:
149 implies a VBR bitstream that obeys the bitrate limits. nominal
150 may also be set to give a nominal rate.
152 the coder does not care to speculate.
156 long bitrate_nominal;
163 /* vorbis_dsp_state buffers the current vorbis audio
164 analysis/synthesis state. The DSP state belongs to a specific
165 logical bitstream ****************************************************/
166 typedef struct vorbis_dsp_state{
184 ogg_int64_t granulepos;
185 ogg_int64_t sequence;
187 ogg_int64_t glue_bits;
188 ogg_int64_t time_bits;
189 ogg_int64_t floor_bits;
190 ogg_int64_t res_bits;
195 typedef struct vorbis_block{
196 /* necessary stream state for linking to the framing abstraction */
197 float **pcm; /* this is a pointer into local storage */
207 ogg_int64_t granulepos;
208 ogg_int64_t sequence;
209 vorbis_dsp_state *vd; /* For read-only access of configuration */
211 /* local storage to avoid remallocing; it's up to the mapping to
217 struct alloc_chain *reap;
219 /* bitmetrics for the frame */
229 /* vorbis_block is a single block of data to be processed as part of
230 the analysis/synthesis stream; it belongs to a specific logical
231 bitstream, but is independant from other vorbis_blocks belonging to
232 that logical bitstream. *************************************************/
236 struct alloc_chain *next;
239 /* vorbis_info contains all the setup information specific to the
240 specific compression/decompression mode in progress (eg,
241 psychoacoustic settings, channel setup, options, codebook
242 etc). vorbis_info and substructures are in backends.h.
243 *********************************************************************/
245 /* the comments are not part of vorbis_info so that vorbis_info can be
247 typedef struct vorbis_comment{
248 /* unlimited user comment fields. libvorbis writes 'libvorbis'
249 whatever vendor is set to in encode */
250 char **user_comments;
251 int *comment_lengths;
258 /* libvorbis encodes in two abstraction layers; first we perform DSP
259 and produce a packet (see docs/analysis.txt). The packet is then
260 coded into a framed OggSquish bitstream by the second layer (see
261 docs/framing.txt). Decode is the reverse process; we sync/frame
262 the bitstream and extract individual packets, then decode the
263 packet back into PCM audio.
265 The extra framing/packetizing is used in streaming formats, such as
266 files. Over the net (such as with UDP), the framing and
267 packetization aren't necessary as they're provided by the transport
268 and the streaming layer is not used */
270 /* Vorbis PRIMITIVES: general ***************************************/
272 static void (*qvorbis_info_init) (vorbis_info *vi);
273 static void (*qvorbis_info_clear) (vorbis_info *vi);
274 static void (*qvorbis_comment_init) (vorbis_comment *vc);
275 static void (*qvorbis_comment_clear) (vorbis_comment *vc);
277 static int (*qvorbis_block_init) (vorbis_dsp_state *v, vorbis_block *vb);
278 static int (*qvorbis_block_clear) (vorbis_block *vb);
279 static void (*qvorbis_dsp_clear) (vorbis_dsp_state *v);
280 static double (*qvorbis_granule_time) (vorbis_dsp_state *v,
281 ogg_int64_t granulepos);
283 /* Vorbis PRIMITIVES: analysis/DSP layer ****************************/
285 static int (*qvorbis_analysis_init) (vorbis_dsp_state *v,vorbis_info *vi);
286 static int (*qvorbis_commentheader_out) (vorbis_comment *vc, ogg_packet *op);
287 static int (*qvorbis_analysis_headerout) (vorbis_dsp_state *v,
291 ogg_packet *op_code);
292 static float ** (*qvorbis_analysis_buffer) (vorbis_dsp_state *v,int vals);
293 static int (*qvorbis_analysis_wrote) (vorbis_dsp_state *v,int vals);
294 static int (*qvorbis_analysis_blockout) (vorbis_dsp_state *v,vorbis_block *vb);
295 static int (*qvorbis_analysis) (vorbis_block *vb,ogg_packet *op);
297 static int (*qvorbis_bitrate_addblock) (vorbis_block *vb);
298 static int (*qvorbis_bitrate_flushpacket) (vorbis_dsp_state *vd,
301 // end of vorbis/codec.h stuff
304 static int (*qvorbis_encode_init_vbr) (vorbis_info *vi,
308 float base_quality /* quality level from 0. (lo) to 1. (hi) */
310 // end of vorbisenc.h stuff
314 int y_width; /**< Width of the Y' luminance plane */
315 int y_height; /**< Height of the luminance plane */
316 int y_stride; /**< Offset in bytes between successive rows */
318 int uv_width; /**< Width of the Cb and Cr chroma planes */
319 int uv_height; /**< Height of the chroma planes */
320 int uv_stride; /**< Offset between successive chroma rows */
321 unsigned char *y; /**< Pointer to start of luminance data */
322 unsigned char *u; /**< Pointer to start of Cb data */
323 unsigned char *v; /**< Pointer to start of Cr data */
331 OC_CS_UNSPECIFIED, /**< The colorspace is unknown or unspecified */
332 OC_CS_ITU_REC_470M, /**< This is the best option for 'NTSC' content */
333 OC_CS_ITU_REC_470BG, /**< This is the best option for 'PAL' content */
334 OC_CS_NSPACES /**< This marks the end of the defined colorspaces */
338 * A Chroma subsampling
340 * These enumerate the available chroma subsampling options supported
341 * by the theora format. See Section 4.4 of the specification for
345 OC_PF_420, /**< Chroma subsampling by 2 in each direction (4:2:0) */
346 OC_PF_RSVD, /**< Reserved value */
347 OC_PF_422, /**< Horizonatal chroma subsampling by 2 (4:2:2) */
348 OC_PF_444 /**< No chroma subsampling at all (4:4:4) */
349 } theora_pixelformat;
351 * Theora bitstream info.
352 * Contains the basic playback parameters for a stream,
353 * corresponding to the initial 'info' header packet.
355 * Encoded theora frames must be a multiple of 16 in width and height.
356 * To handle other frame sizes, a crop rectangle is specified in
357 * frame_height and frame_width, offset_x and * offset_y. The offset
358 * and size should still be a multiple of 2 to avoid chroma sampling
359 * shifts. Offset values in this structure are measured from the
360 * upper left of the image.
362 * Frame rate, in frames per second, is stored as a rational
363 * fraction. Aspect ratio is also stored as a rational fraction, and
364 * refers to the aspect ratio of the frame pixels, not of the
365 * overall frame itself.
367 * See <a href="http://svn.xiph.org/trunk/theora/examples/encoder_example.c">
368 * examples/encoder_example.c</a> for usage examples of the
369 * other paramters and good default settings for the encoder parameters.
372 ogg_uint32_t width; /**< encoded frame width */
373 ogg_uint32_t height; /**< encoded frame height */
374 ogg_uint32_t frame_width; /**< display frame width */
375 ogg_uint32_t frame_height; /**< display frame height */
376 ogg_uint32_t offset_x; /**< horizontal offset of the displayed frame */
377 ogg_uint32_t offset_y; /**< vertical offset of the displayed frame */
378 ogg_uint32_t fps_numerator; /**< frame rate numerator **/
379 ogg_uint32_t fps_denominator; /**< frame rate denominator **/
380 ogg_uint32_t aspect_numerator; /**< pixel aspect ratio numerator */
381 ogg_uint32_t aspect_denominator; /**< pixel aspect ratio denominator */
382 theora_colorspace colorspace; /**< colorspace */
383 int target_bitrate; /**< nominal bitrate in bits per second */
384 int quality; /**< Nominal quality setting, 0-63 */
385 int quick_p; /**< Quick encode/decode */
388 unsigned char version_major;
389 unsigned char version_minor;
390 unsigned char version_subminor;
397 ogg_uint32_t keyframe_frequency;
398 ogg_uint32_t keyframe_frequency_force; /* also used for decode init to
399 get granpos shift correct */
400 ogg_uint32_t keyframe_data_target_bitrate;
401 ogg_int32_t keyframe_auto_threshold;
402 ogg_uint32_t keyframe_mindistance;
403 ogg_int32_t noise_sensitivity;
404 ogg_int32_t sharpness;
406 theora_pixelformat pixelformat; /**< chroma subsampling mode to expect */
410 /** Codec internal state and context.
414 ogg_int64_t granulepos;
416 void *internal_encode;
417 void *internal_decode;
422 * Comment header metadata.
424 * This structure holds the in-stream metadata corresponding to
425 * the 'comment' header packet.
427 * Meta data is stored as a series of (tag, value) pairs, in
428 * length-encoded string vectors. The first occurence of the
429 * '=' character delimits the tag and value. A particular tag
430 * may occur more than once. The character set encoding for
431 * the strings is always UTF-8, but the tag names are limited
432 * to case-insensitive ASCII. See the spec for details.
434 * In filling in this structure, qtheora_decode_header() will
435 * null-terminate the user_comment strings for safety. However,
436 * the bitstream format itself treats them as 8-bit clean,
437 * and so the length array should be treated as authoritative
440 typedef struct theora_comment{
441 char **user_comments; /**< An array of comment string vectors */
442 int *comment_lengths; /**< An array of corresponding string vector lengths in bytes */
443 int comments; /**< The total number of comment string vectors */
444 char *vendor; /**< The vendor string identifying the encoder, null terminated */
447 static int (*qtheora_encode_init) (theora_state *th, theora_info *ti);
448 static int (*qtheora_encode_YUVin) (theora_state *t, yuv_buffer *yuv);
449 static int (*qtheora_encode_packetout) ( theora_state *t, int last_p,
451 static int (*qtheora_encode_header) (theora_state *t, ogg_packet *op);
452 static int (*qtheora_encode_comment) (theora_comment *tc, ogg_packet *op);
453 static int (*qtheora_encode_tables) (theora_state *t, ogg_packet *op);
454 static void (*qtheora_info_init) (theora_info *c);
455 static void (*qtheora_info_clear) (theora_info *c);
456 static void (*qtheora_clear) (theora_state *t);
457 static void (*qtheora_comment_init) (theora_comment *tc);
458 static void (*qtheora_comment_clear) (theora_comment *tc);
459 static double (*qtheora_granule_time) (theora_state *th,ogg_int64_t granulepos);
460 // end of theora.h stuff
462 static dllfunction_t oggfuncs[] =
464 {"ogg_stream_packetin", (void **) &qogg_stream_packetin},
465 {"ogg_stream_pageout", (void **) &qogg_stream_pageout},
466 {"ogg_stream_flush", (void **) &qogg_stream_flush},
467 {"ogg_stream_init", (void **) &qogg_stream_init},
468 {"ogg_stream_clear", (void **) &qogg_stream_clear},
469 {"ogg_page_granulepos", (void **) &qogg_page_granulepos},
473 static dllfunction_t vorbisencfuncs[] =
475 {"vorbis_encode_init_vbr", (void **) &qvorbis_encode_init_vbr},
479 static dllfunction_t vorbisfuncs[] =
481 {"vorbis_info_init", (void **) &qvorbis_info_init},
482 {"vorbis_info_clear", (void **) &qvorbis_info_clear},
483 {"vorbis_comment_init", (void **) &qvorbis_comment_init},
484 {"vorbis_comment_clear", (void **) &qvorbis_comment_clear},
485 {"vorbis_block_init", (void **) &qvorbis_block_init},
486 {"vorbis_block_clear", (void **) &qvorbis_block_clear},
487 {"vorbis_dsp_clear", (void **) &qvorbis_dsp_clear},
488 {"vorbis_analysis_init", (void **) &qvorbis_analysis_init},
489 {"vorbis_commentheader_out", (void **) &qvorbis_commentheader_out},
490 {"vorbis_analysis_headerout", (void **) &qvorbis_analysis_headerout},
491 {"vorbis_analysis_buffer", (void **) &qvorbis_analysis_buffer},
492 {"vorbis_analysis_wrote", (void **) &qvorbis_analysis_wrote},
493 {"vorbis_analysis_blockout", (void **) &qvorbis_analysis_blockout},
494 {"vorbis_analysis", (void **) &qvorbis_analysis},
495 {"vorbis_bitrate_addblock", (void **) &qvorbis_bitrate_addblock},
496 {"vorbis_bitrate_flushpacket", (void **) &qvorbis_bitrate_flushpacket},
497 {"vorbis_granule_time", (void **) &qvorbis_granule_time},
501 static dllfunction_t theorafuncs[] =
503 {"theora_info_init", (void **) &qtheora_info_init},
504 {"theora_info_clear", (void **) &qtheora_info_clear},
505 {"theora_comment_init", (void **) &qtheora_comment_init},
506 {"theora_comment_clear", (void **) &qtheora_comment_clear},
507 {"theora_encode_init", (void **) &qtheora_encode_init},
508 {"theora_encode_YUVin", (void **) &qtheora_encode_YUVin},
509 {"theora_encode_packetout", (void **) &qtheora_encode_packetout},
510 {"theora_encode_header", (void **) &qtheora_encode_header},
511 {"theora_encode_comment", (void **) &qtheora_encode_comment},
512 {"theora_encode_tables", (void **) &qtheora_encode_tables},
513 {"theora_clear", (void **) &qtheora_clear},
514 {"theora_granule_time", (void **) &qtheora_granule_time},
518 static dllhandle_t og_dll = NULL, vo_dll = NULL, ve_dll = NULL, th_dll = NULL;
520 qboolean SCR_CaptureVideo_Ogg_OpenLibrary(void)
522 const char* dllnames_og [] =
528 #elif defined(MACOSX)
536 const char* dllnames_vo [] =
542 #elif defined(MACOSX)
550 const char* dllnames_ve [] =
553 "libvorbisenc-2.dll",
556 #elif defined(MACOSX)
557 "libvorbisenc.dylib",
564 const char* dllnames_th [] =
570 #elif defined(MACOSX)
580 Sys_LoadLibrary (dllnames_og, &og_dll, oggfuncs)
582 Sys_LoadLibrary (dllnames_th, &th_dll, theorafuncs)
584 Sys_LoadLibrary (dllnames_vo, &vo_dll, vorbisfuncs)
586 Sys_LoadLibrary (dllnames_ve, &ve_dll, vorbisencfuncs);
589 void SCR_CaptureVideo_Ogg_Init(void)
591 SCR_CaptureVideo_Ogg_OpenLibrary();
593 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_quality);
594 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_bitrate);
595 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier);
596 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_maxinterval);
597 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_mininterval);
598 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_auto_threshold);
599 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_noise_sensitivity);
600 Cvar_RegisterVariable(&cl_capturevideo_ogg_vorbis_quality);
603 qboolean SCR_CaptureVideo_Ogg_Available(void)
605 return og_dll && th_dll && vo_dll && ve_dll;
608 void SCR_CaptureVideo_Ogg_CloseDLL(void)
610 Sys_UnloadLibrary (&ve_dll);
611 Sys_UnloadLibrary (&vo_dll);
612 Sys_UnloadLibrary (&th_dll);
613 Sys_UnloadLibrary (&og_dll);
616 // this struct should not be needed
617 // however, libogg appears to pull the ogg_page's data element away from our
618 // feet before we get to write the data due to interleaving
619 // so this struct is used to keep the page data around until it actually gets
621 typedef struct allocatedoggpage_s
625 unsigned char data[65307];
626 // this number is from RFC 3533. In case libogg writes more, we'll have to increase this
627 // but we'll get a Host_Error in this case so we can track it down
631 typedef struct capturevideostate_ogg_formatspecific_s
633 ogg_stream_state to, vo;
634 int serial1, serial2;
644 allocatedoggpage_t videopage, audiopage;
646 capturevideostate_ogg_formatspecific_t;
647 #define LOAD_FORMATSPECIFIC_OGG() capturevideostate_ogg_formatspecific_t *format = (capturevideostate_ogg_formatspecific_t *) cls.capturevideo.formatspecific
649 static void SCR_CaptureVideo_Ogg_Interleave(void)
651 LOAD_FORMATSPECIFIC_OGG();
654 if(!cls.capturevideo.soundrate)
656 while(qogg_stream_pageout(&format->to, &pg) > 0)
658 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
659 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
666 // first: make sure we have a page of both types
667 if(!format->videopage.len)
668 if(qogg_stream_pageout(&format->to, &pg) > 0)
670 format->videopage.len = pg.header_len + pg.body_len;
671 format->videopage.time = qtheora_granule_time(&format->ts, qogg_page_granulepos(&pg));
672 if(format->videopage.len > sizeof(format->videopage.data))
673 Host_Error("video page too long");
674 memcpy(format->videopage.data, pg.header, pg.header_len);
675 memcpy(format->videopage.data + pg.header_len, pg.body, pg.body_len);
677 if(!format->audiopage.len)
678 if(qogg_stream_pageout(&format->vo, &pg) > 0)
680 format->audiopage.len = pg.header_len + pg.body_len;
681 format->audiopage.time = qvorbis_granule_time(&format->vd, qogg_page_granulepos(&pg));
682 if(format->audiopage.len > sizeof(format->audiopage.data))
683 Host_Error("audio page too long");
684 memcpy(format->audiopage.data, pg.header, pg.header_len);
685 memcpy(format->audiopage.data + pg.header_len, pg.body, pg.body_len);
688 if(format->videopage.len && format->audiopage.len)
690 // output the page that ends first
691 if(format->videopage.time < format->audiopage.time)
693 FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len);
694 format->videopage.len = 0;
698 FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len);
699 format->audiopage.len = 0;
707 static void SCR_CaptureVideo_Ogg_FlushInterleaving(void)
709 LOAD_FORMATSPECIFIC_OGG();
711 if(cls.capturevideo.soundrate)
712 if(format->audiopage.len)
714 FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len);
715 format->audiopage.len = 0;
718 if(format->videopage.len)
720 FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len);
721 format->videopage.len = 0;
725 static void SCR_CaptureVideo_Ogg_EndVideo(void)
727 LOAD_FORMATSPECIFIC_OGG();
731 if(format->yuvi >= 0)
733 // send the previous (and last) frame
734 while(format->lastnum-- > 0)
736 qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]);
738 while(qtheora_encode_packetout(&format->ts, !format->lastnum, &pt))
739 qogg_stream_packetin(&format->to, &pt);
741 SCR_CaptureVideo_Ogg_Interleave();
745 if(cls.capturevideo.soundrate)
747 qvorbis_analysis_wrote(&format->vd, 0);
748 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
750 qvorbis_analysis(&format->vb, NULL);
751 qvorbis_bitrate_addblock(&format->vb);
752 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
753 qogg_stream_packetin(&format->vo, &pt);
754 SCR_CaptureVideo_Ogg_Interleave();
758 SCR_CaptureVideo_Ogg_FlushInterleaving();
760 while(qogg_stream_pageout(&format->to, &pg) > 0)
762 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
763 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
766 if(cls.capturevideo.soundrate)
768 while(qogg_stream_pageout(&format->vo, &pg) > 0)
770 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
771 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
776 int result = qogg_stream_flush (&format->to, &pg);
778 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
781 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
782 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
785 if(cls.capturevideo.soundrate)
788 int result = qogg_stream_flush (&format->vo, &pg);
790 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
793 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
794 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
797 qogg_stream_clear(&format->vo);
798 qvorbis_block_clear(&format->vb);
799 qvorbis_dsp_clear(&format->vd);
802 qogg_stream_clear(&format->to);
803 qtheora_clear(&format->ts);
804 qvorbis_info_clear(&format->vi);
806 Mem_Free(format->yuv[0].y);
807 Mem_Free(format->yuv[0].u);
808 Mem_Free(format->yuv[0].v);
809 Mem_Free(format->yuv[1].y);
810 Mem_Free(format->yuv[1].u);
811 Mem_Free(format->yuv[1].v);
814 FS_Close(cls.capturevideo.videofile);
815 cls.capturevideo.videofile = NULL;
818 static void SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV(void)
820 LOAD_FORMATSPECIFIC_OGG();
823 int blockr, blockg, blockb;
824 unsigned char *b = cls.capturevideo.outbuffer;
825 int w = cls.capturevideo.width;
826 int h = cls.capturevideo.height;
829 yuv = &format->yuv[format->yuvi];
831 for(y = 0; y < h; ++y)
833 for(b = cls.capturevideo.outbuffer + (h-1-y)*w*4, x = 0; x < w; ++x)
838 yuv->y[x + yuv->y_stride * y] =
839 cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]];
845 for(b = cls.capturevideo.outbuffer + (h-2-y)*w*4, x = 0; x < w/2; ++x)
847 blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2;
848 blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2;
849 blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2;
850 yuv->u[x + yuv->uv_stride * (y/2)] =
851 cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128];
852 yuv->v[x + yuv->uv_stride * (y/2)] =
853 cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128];
860 static void SCR_CaptureVideo_Ogg_VideoFrames(int num)
862 LOAD_FORMATSPECIFIC_OGG();
865 // data is in cls.capturevideo.outbuffer as BGRA and has size width*height
867 if(format->yuvi >= 0)
869 // send the previous frame
870 while(format->lastnum-- > 0)
872 qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]);
874 while(qtheora_encode_packetout(&format->ts, false, &pt))
875 qogg_stream_packetin(&format->to, &pt);
877 SCR_CaptureVideo_Ogg_Interleave();
881 format->yuvi = (format->yuvi + 1) % 2;
882 SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV();
883 format->lastnum = num;
885 // TODO maybe send num-1 frames from here already
888 typedef int channelmapping_t[8];
889 channelmapping_t mapping[8] =
891 { 0, -1, -1, -1, -1, -1, -1, -1 }, // mono
892 { 0, 1, -1, -1, -1, -1, -1, -1 }, // stereo
893 { 0, 1, 2, -1, -1, -1, -1, -1 }, // L C R
894 { 0, 1, 2, 3, -1, -1, -1, -1 }, // surround40
895 { 0, 2, 3, 4, 1, -1, -1, -1 }, // FL FC FR RL RR
896 { 0, 2, 3, 4, 1, 5, -1, -1 }, // surround51
897 { 0, 2, 3, 4, 1, 5, 6, -1 }, // (not defined by vorbis spec)
898 { 0, 2, 3, 4, 1, 5, 6, 7 } // surround71 (not defined by vorbis spec)
901 static void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
903 LOAD_FORMATSPECIFIC_OGG();
904 float **vorbis_buffer;
908 int *map = mapping[bound(1, cls.capturevideo.soundchannels, 8) - 1];
910 vorbis_buffer = qvorbis_analysis_buffer(&format->vd, length);
911 for(j = 0; j < cls.capturevideo.soundchannels; ++j)
913 float *b = vorbis_buffer[map[j]];
914 for(i = 0; i < length; ++i)
915 b[i] = paintbuffer[i].sample[j] / 32768.0f;
917 qvorbis_analysis_wrote(&format->vd, length);
919 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
921 qvorbis_analysis(&format->vb, NULL);
922 qvorbis_bitrate_addblock(&format->vb);
924 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
925 qogg_stream_packetin(&format->vo, &pt);
928 SCR_CaptureVideo_Ogg_Interleave();
931 void SCR_CaptureVideo_Ogg_BeginVideo(void)
933 cls.capturevideo.format = CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA;
934 cls.capturevideo.formatextension = "ogv";
935 cls.capturevideo.videofile = FS_OpenRealFile(va("%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false);
936 cls.capturevideo.endvideo = SCR_CaptureVideo_Ogg_EndVideo;
937 cls.capturevideo.videoframes = SCR_CaptureVideo_Ogg_VideoFrames;
938 cls.capturevideo.soundframe = SCR_CaptureVideo_Ogg_SoundFrame;
939 cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_ogg_formatspecific_t));
941 LOAD_FORMATSPECIFIC_OGG();
944 ogg_packet pt, pt2, pt3;
949 format->serial1 = rand();
950 qogg_stream_init(&format->to, format->serial1);
952 if(cls.capturevideo.soundrate)
956 format->serial2 = rand();
958 while(format->serial1 == format->serial2);
959 qogg_stream_init(&format->vo, format->serial2);
962 format->videopage.len = format->audiopage.len = 0;
964 qtheora_info_init(&ti);
965 ti.frame_width = cls.capturevideo.width;
966 ti.frame_height = cls.capturevideo.height;
967 ti.width = (ti.frame_width + 15) & ~15;
968 ti.height = (ti.frame_height + 15) & ~15;
969 //ti.offset_x = ((ti.width - ti.frame_width) / 2) & ~1;
970 //ti.offset_y = ((ti.height - ti.frame_height) / 2) & ~1;
972 for(i = 0; i < 2; ++i)
974 format->yuv[i].y_width = ti.width;
975 format->yuv[i].y_height = ti.height;
976 format->yuv[i].y_stride = ti.width;
977 format->yuv[i].uv_width = ti.width / 2;
978 format->yuv[i].uv_height = ti.height / 2;
979 format->yuv[i].uv_stride = ti.width / 2;
980 format->yuv[i].y = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].y_stride * format->yuv[i].y_height);
981 format->yuv[i].u = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
982 format->yuv[i].v = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
984 format->yuvi = -1; // -1: no frame valid yet, write into 0
986 FindFraction(cls.capturevideo.framerate / cls.capturevideo.framestep, &num, &denom, 1001);
987 ti.fps_numerator = num;
988 ti.fps_denominator = denom;
990 FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000);
991 ti.aspect_numerator = num;
992 ti.aspect_denominator = denom;
994 ti.colorspace = OC_CS_UNSPECIFIED;
995 ti.pixelformat = OC_PF_420;
997 ti.quick_p = true; // http://mlblog.osdir.com/multimedia.ogg.theora.general/2004-07/index.shtml
998 ti.dropframes_p = false;
1000 ti.target_bitrate = cl_capturevideo_ogg_theora_bitrate.integer * 1000;
1001 ti.quality = cl_capturevideo_ogg_theora_quality.integer;
1003 if(ti.target_bitrate <= 0)
1007 ti.target_bitrate = -1;
1008 ti.keyframe_data_target_bitrate = (unsigned int)-1;
1013 ti.target_bitrate = -1;
1014 ti.keyframe_data_target_bitrate = (unsigned int)-1;
1015 ti.quality = bound(0, ti.quality, 63);
1022 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
1023 ti.keyframe_data_target_bitrate = (int) (ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value));
1028 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
1029 ti.keyframe_data_target_bitrate = (int) (ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value));
1034 // this -1 magic is because ti.keyframe_frequency and ti.keyframe_mindistance use different metrics
1035 ti.keyframe_frequency = bound(1, cl_capturevideo_ogg_theora_keyframe_maxinterval.integer, 1000);
1036 ti.keyframe_mindistance = bound(1, cl_capturevideo_ogg_theora_keyframe_mininterval.integer, (int) ti.keyframe_frequency) - 1;
1037 ti.noise_sensitivity = bound(0, cl_capturevideo_ogg_theora_noise_sensitivity.integer, 6);
1038 ti.sharpness = bound(0, cl_capturevideo_ogg_theora_sharpness.integer, 2);
1039 ti.keyframe_auto_threshold = bound(0, cl_capturevideo_ogg_theora_keyframe_auto_threshold.integer, 100);
1041 ti.keyframe_frequency_force = ti.keyframe_frequency;
1042 ti.keyframe_auto_p = (ti.keyframe_frequency != ti.keyframe_mindistance + 1);
1044 qtheora_encode_init(&format->ts, &ti);
1045 qtheora_info_clear(&ti);
1048 if(cls.capturevideo.soundrate)
1050 qvorbis_info_init(&format->vi);
1051 qvorbis_encode_init_vbr(&format->vi, cls.capturevideo.soundchannels, cls.capturevideo.soundrate, bound(-1, cl_capturevideo_ogg_vorbis_quality.value, 10) * 0.099);
1052 qvorbis_comment_init(&vc);
1053 qvorbis_analysis_init(&format->vd, &format->vi);
1054 qvorbis_block_init(&format->vd, &format->vb);
1057 qtheora_comment_init(&tc);
1059 /* create the remaining theora headers */
1060 qtheora_encode_header(&format->ts, &pt);
1061 qogg_stream_packetin(&format->to, &pt);
1062 if (qogg_stream_pageout (&format->to, &pg) != 1)
1063 fprintf (stderr, "Internal Ogg library error.\n");
1064 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1065 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1067 qtheora_encode_comment(&tc, &pt);
1068 qogg_stream_packetin(&format->to, &pt);
1069 qtheora_encode_tables(&format->ts, &pt);
1070 qogg_stream_packetin (&format->to, &pt);
1072 qtheora_comment_clear(&tc);
1074 if(cls.capturevideo.soundrate)
1076 qvorbis_analysis_headerout(&format->vd, &vc, &pt, &pt2, &pt3);
1077 qogg_stream_packetin(&format->vo, &pt);
1078 if (qogg_stream_pageout (&format->vo, &pg) != 1)
1079 fprintf (stderr, "Internal Ogg library error.\n");
1080 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1081 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1083 qogg_stream_packetin(&format->vo, &pt2);
1084 qogg_stream_packetin(&format->vo, &pt3);
1086 qvorbis_comment_clear(&vc);
1091 int result = qogg_stream_flush (&format->to, &pg);
1093 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
1096 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1097 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1100 if(cls.capturevideo.soundrate)
1103 int result = qogg_stream_flush (&format->vo, &pg);
1105 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
1108 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1109 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);