10 // video capture cvars
11 static cvar_t cl_capturevideo_ogg_theora_vp3compat = {CVAR_SAVE, "cl_capturevideo_ogg_theora_vp3compat", "1", "make VP3 compatible theora streams"};
12 static cvar_t cl_capturevideo_ogg_theora_quality = {CVAR_SAVE, "cl_capturevideo_ogg_theora_quality", "48", "video quality factor (0 to 63), or -1 to use bitrate only; higher is better; setting both to -1 achieves unlimited quality"};
13 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; setting both to -1 achieves unlimited quality"};
14 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"};
15 static cvar_t cl_capturevideo_ogg_theora_keyframe_maxinterval = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_maxinterval", "64", "maximum keyframe interval (1 to 1000)"};
16 static cvar_t cl_capturevideo_ogg_theora_keyframe_mininterval = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_mininterval", "8", "minimum keyframe interval (1 to 1000)"};
17 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)"};
18 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"};
19 static cvar_t cl_capturevideo_ogg_theora_sharpness = {CVAR_SAVE, "cl_capturevideo_ogg_theora_sharpness", "0", "sharpness (0 to 2); lower is sharper"};
20 static cvar_t cl_capturevideo_ogg_vorbis_quality = {CVAR_SAVE, "cl_capturevideo_ogg_vorbis_quality", "3", "audio quality (-1 to 10); higher is better"};
24 typedef __int16 ogg_int16_t;
25 typedef unsigned __int16 ogg_uint16_t;
26 typedef __int32 ogg_int32_t;
27 typedef unsigned __int32 ogg_uint32_t;
28 typedef __int64 ogg_int64_t;
30 typedef int16_t ogg_int16_t;
31 typedef uint16_t ogg_uint16_t;
32 typedef int32_t ogg_int32_t;
33 typedef uint32_t ogg_uint32_t;
34 typedef int64_t ogg_int64_t;
41 unsigned char *buffer;
46 /* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
49 unsigned char *header;
55 /* ogg_stream_state contains the current encode/decode state of a logical
56 Ogg bitstream **********************************************************/
59 unsigned char *body_data; /* bytes from packet bodies */
60 long body_storage; /* storage elements allocated */
61 long body_fill; /* elements stored; fill mark */
62 long body_returned; /* elements of fill returned */
65 int *lacing_vals; /* The values that will go to the segment table */
66 ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
67 this way, but it is simple coupled to the
74 unsigned char header[282]; /* working space for header encode */
77 int e_o_s; /* set when we have buffered the last packet in the
79 int b_o_s; /* set after we've written the initial page
80 of a logical bitstream */
83 ogg_int64_t packetno; /* sequence number for decode; the framing
84 knows where there's a hole in the data,
85 but we need coupling so that the codec
86 (which is in a seperate abstraction
87 layer) also knows about the gap */
88 ogg_int64_t granulepos;
92 /* ogg_packet is used to encapsulate the data and metadata belonging
93 to a single raw Ogg/Vorbis packet *************************************/
96 unsigned char *packet;
101 ogg_int64_t granulepos;
103 ogg_int64_t packetno; /* sequence number for decode; the framing
104 knows where there's a hole in the data,
105 but we need coupling so that the codec
106 (which is in a seperate abstraction
107 layer) also knows about the gap */
121 /* Ogg BITSTREAM PRIMITIVES: encoding **************************/
123 static int (*qogg_stream_packetin) (ogg_stream_state *os, ogg_packet *op);
124 static int (*qogg_stream_pageout) (ogg_stream_state *os, ogg_page *og);
125 static int (*qogg_stream_flush) (ogg_stream_state *os, ogg_page *og);
127 /* Ogg BITSTREAM PRIMITIVES: general ***************************/
129 static int (*qogg_stream_init) (ogg_stream_state *os,int serialno);
130 static int (*qogg_stream_clear) (ogg_stream_state *os);
131 static ogg_int64_t (*qogg_page_granulepos) (ogg_page *og);
133 // end of ogg.h stuff
135 // vorbis/codec.h stuff
136 typedef struct vorbis_info{
141 /* The below bitrate declarations are *hints*.
142 Combinations of the three values carry the following implications:
144 all three set to the same value:
145 implies a fixed rate bitstream
147 implies a VBR stream that averages the nominal bitrate. No hard
149 upper and or lower set:
150 implies a VBR bitstream that obeys the bitrate limits. nominal
151 may also be set to give a nominal rate.
153 the coder does not care to speculate.
157 long bitrate_nominal;
164 /* vorbis_dsp_state buffers the current vorbis audio
165 analysis/synthesis state. The DSP state belongs to a specific
166 logical bitstream ****************************************************/
167 typedef struct vorbis_dsp_state{
185 ogg_int64_t granulepos;
186 ogg_int64_t sequence;
188 ogg_int64_t glue_bits;
189 ogg_int64_t time_bits;
190 ogg_int64_t floor_bits;
191 ogg_int64_t res_bits;
196 typedef struct vorbis_block{
197 /* necessary stream state for linking to the framing abstraction */
198 float **pcm; /* this is a pointer into local storage */
208 ogg_int64_t granulepos;
209 ogg_int64_t sequence;
210 vorbis_dsp_state *vd; /* For read-only access of configuration */
212 /* local storage to avoid remallocing; it's up to the mapping to
218 struct alloc_chain *reap;
220 /* bitmetrics for the frame */
230 /* vorbis_block is a single block of data to be processed as part of
231 the analysis/synthesis stream; it belongs to a specific logical
232 bitstream, but is independant from other vorbis_blocks belonging to
233 that logical bitstream. *************************************************/
237 struct alloc_chain *next;
240 /* vorbis_info contains all the setup information specific to the
241 specific compression/decompression mode in progress (eg,
242 psychoacoustic settings, channel setup, options, codebook
243 etc). vorbis_info and substructures are in backends.h.
244 *********************************************************************/
246 /* the comments are not part of vorbis_info so that vorbis_info can be
248 typedef struct vorbis_comment{
249 /* unlimited user comment fields. libvorbis writes 'libvorbis'
250 whatever vendor is set to in encode */
251 char **user_comments;
252 int *comment_lengths;
259 /* libvorbis encodes in two abstraction layers; first we perform DSP
260 and produce a packet (see docs/analysis.txt). The packet is then
261 coded into a framed OggSquish bitstream by the second layer (see
262 docs/framing.txt). Decode is the reverse process; we sync/frame
263 the bitstream and extract individual packets, then decode the
264 packet back into PCM audio.
266 The extra framing/packetizing is used in streaming formats, such as
267 files. Over the net (such as with UDP), the framing and
268 packetization aren't necessary as they're provided by the transport
269 and the streaming layer is not used */
271 /* Vorbis PRIMITIVES: general ***************************************/
273 static void (*qvorbis_info_init) (vorbis_info *vi);
274 static void (*qvorbis_info_clear) (vorbis_info *vi);
275 static void (*qvorbis_comment_init) (vorbis_comment *vc);
276 static void (*qvorbis_comment_clear) (vorbis_comment *vc);
278 static int (*qvorbis_block_init) (vorbis_dsp_state *v, vorbis_block *vb);
279 static int (*qvorbis_block_clear) (vorbis_block *vb);
280 static void (*qvorbis_dsp_clear) (vorbis_dsp_state *v);
281 static double (*qvorbis_granule_time) (vorbis_dsp_state *v,
282 ogg_int64_t granulepos);
284 /* Vorbis PRIMITIVES: analysis/DSP layer ****************************/
286 static int (*qvorbis_analysis_init) (vorbis_dsp_state *v,vorbis_info *vi);
287 static int (*qvorbis_commentheader_out) (vorbis_comment *vc, ogg_packet *op);
288 static int (*qvorbis_analysis_headerout) (vorbis_dsp_state *v,
292 ogg_packet *op_code);
293 static float ** (*qvorbis_analysis_buffer) (vorbis_dsp_state *v,int vals);
294 static int (*qvorbis_analysis_wrote) (vorbis_dsp_state *v,int vals);
295 static int (*qvorbis_analysis_blockout) (vorbis_dsp_state *v,vorbis_block *vb);
296 static int (*qvorbis_analysis) (vorbis_block *vb,ogg_packet *op);
298 static int (*qvorbis_bitrate_addblock) (vorbis_block *vb);
299 static int (*qvorbis_bitrate_flushpacket) (vorbis_dsp_state *vd,
302 // end of vorbis/codec.h stuff
305 static int (*qvorbis_encode_init_vbr) (vorbis_info *vi,
309 float base_quality /* quality level from 0. (lo) to 1. (hi) */
311 // end of vorbisenc.h stuff
315 #define TH_ENCCTL_SET_VP3_COMPATIBLE (10)
318 int y_width; /**< Width of the Y' luminance plane */
319 int y_height; /**< Height of the luminance plane */
320 int y_stride; /**< Offset in bytes between successive rows */
322 int uv_width; /**< Width of the Cb and Cr chroma planes */
323 int uv_height; /**< Height of the chroma planes */
324 int uv_stride; /**< Offset between successive chroma rows */
325 unsigned char *y; /**< Pointer to start of luminance data */
326 unsigned char *u; /**< Pointer to start of Cb data */
327 unsigned char *v; /**< Pointer to start of Cr data */
335 OC_CS_UNSPECIFIED, /**< The colorspace is unknown or unspecified */
336 OC_CS_ITU_REC_470M, /**< This is the best option for 'NTSC' content */
337 OC_CS_ITU_REC_470BG, /**< This is the best option for 'PAL' content */
338 OC_CS_NSPACES /**< This marks the end of the defined colorspaces */
342 * A Chroma subsampling
344 * These enumerate the available chroma subsampling options supported
345 * by the theora format. See Section 4.4 of the specification for
349 OC_PF_420, /**< Chroma subsampling by 2 in each direction (4:2:0) */
350 OC_PF_RSVD, /**< Reserved value */
351 OC_PF_422, /**< Horizonatal chroma subsampling by 2 (4:2:2) */
352 OC_PF_444 /**< No chroma subsampling at all (4:4:4) */
353 } theora_pixelformat;
355 * Theora bitstream info.
356 * Contains the basic playback parameters for a stream,
357 * corresponding to the initial 'info' header packet.
359 * Encoded theora frames must be a multiple of 16 in width and height.
360 * To handle other frame sizes, a crop rectangle is specified in
361 * frame_height and frame_width, offset_x and * offset_y. The offset
362 * and size should still be a multiple of 2 to avoid chroma sampling
363 * shifts. Offset values in this structure are measured from the
364 * upper left of the image.
366 * Frame rate, in frames per second, is stored as a rational
367 * fraction. Aspect ratio is also stored as a rational fraction, and
368 * refers to the aspect ratio of the frame pixels, not of the
369 * overall frame itself.
371 * See <a href="http://svn.xiph.org/trunk/theora/examples/encoder_example.c">
372 * examples/encoder_example.c</a> for usage examples of the
373 * other paramters and good default settings for the encoder parameters.
376 ogg_uint32_t width; /**< encoded frame width */
377 ogg_uint32_t height; /**< encoded frame height */
378 ogg_uint32_t frame_width; /**< display frame width */
379 ogg_uint32_t frame_height; /**< display frame height */
380 ogg_uint32_t offset_x; /**< horizontal offset of the displayed frame */
381 ogg_uint32_t offset_y; /**< vertical offset of the displayed frame */
382 ogg_uint32_t fps_numerator; /**< frame rate numerator **/
383 ogg_uint32_t fps_denominator; /**< frame rate denominator **/
384 ogg_uint32_t aspect_numerator; /**< pixel aspect ratio numerator */
385 ogg_uint32_t aspect_denominator; /**< pixel aspect ratio denominator */
386 theora_colorspace colorspace; /**< colorspace */
387 int target_bitrate; /**< nominal bitrate in bits per second */
388 int quality; /**< Nominal quality setting, 0-63 */
389 int quick_p; /**< Quick encode/decode */
392 unsigned char version_major;
393 unsigned char version_minor;
394 unsigned char version_subminor;
401 ogg_uint32_t keyframe_frequency;
402 ogg_uint32_t keyframe_frequency_force; /* also used for decode init to
403 get granpos shift correct */
404 ogg_uint32_t keyframe_data_target_bitrate;
405 ogg_int32_t keyframe_auto_threshold;
406 ogg_uint32_t keyframe_mindistance;
407 ogg_int32_t noise_sensitivity;
408 ogg_int32_t sharpness;
410 theora_pixelformat pixelformat; /**< chroma subsampling mode to expect */
414 /** Codec internal state and context.
418 ogg_int64_t granulepos;
420 void *internal_encode;
421 void *internal_decode;
426 * Comment header metadata.
428 * This structure holds the in-stream metadata corresponding to
429 * the 'comment' header packet.
431 * Meta data is stored as a series of (tag, value) pairs, in
432 * length-encoded string vectors. The first occurence of the
433 * '=' character delimits the tag and value. A particular tag
434 * may occur more than once. The character set encoding for
435 * the strings is always UTF-8, but the tag names are limited
436 * to case-insensitive ASCII. See the spec for details.
438 * In filling in this structure, qtheora_decode_header() will
439 * null-terminate the user_comment strings for safety. However,
440 * the bitstream format itself treats them as 8-bit clean,
441 * and so the length array should be treated as authoritative
444 typedef struct theora_comment{
445 char **user_comments; /**< An array of comment string vectors */
446 int *comment_lengths; /**< An array of corresponding string vector lengths in bytes */
447 int comments; /**< The total number of comment string vectors */
448 char *vendor; /**< The vendor string identifying the encoder, null terminated */
451 static int (*qtheora_encode_init) (theora_state *th, theora_info *ti);
452 static int (*qtheora_encode_YUVin) (theora_state *t, yuv_buffer *yuv);
453 static int (*qtheora_encode_packetout) ( theora_state *t, int last_p,
455 static int (*qtheora_encode_header) (theora_state *t, ogg_packet *op);
456 static int (*qtheora_encode_comment) (theora_comment *tc, ogg_packet *op);
457 static int (*qtheora_encode_tables) (theora_state *t, ogg_packet *op);
458 static void (*qtheora_info_init) (theora_info *c);
459 static void (*qtheora_info_clear) (theora_info *c);
460 static void (*qtheora_clear) (theora_state *t);
461 static void (*qtheora_comment_init) (theora_comment *tc);
462 static void (*qtheora_comment_clear) (theora_comment *tc);
463 static double (*qtheora_granule_time) (theora_state *th,ogg_int64_t granulepos);
464 static int (*qtheora_control) (theora_state *th,int req,void *buf,size_t buf_sz);
465 // end of theora.h stuff
467 static dllfunction_t oggfuncs[] =
469 {"ogg_stream_packetin", (void **) &qogg_stream_packetin},
470 {"ogg_stream_pageout", (void **) &qogg_stream_pageout},
471 {"ogg_stream_flush", (void **) &qogg_stream_flush},
472 {"ogg_stream_init", (void **) &qogg_stream_init},
473 {"ogg_stream_clear", (void **) &qogg_stream_clear},
474 {"ogg_page_granulepos", (void **) &qogg_page_granulepos},
478 static dllfunction_t vorbisencfuncs[] =
480 {"vorbis_encode_init_vbr", (void **) &qvorbis_encode_init_vbr},
484 static dllfunction_t vorbisfuncs[] =
486 {"vorbis_info_init", (void **) &qvorbis_info_init},
487 {"vorbis_info_clear", (void **) &qvorbis_info_clear},
488 {"vorbis_comment_init", (void **) &qvorbis_comment_init},
489 {"vorbis_comment_clear", (void **) &qvorbis_comment_clear},
490 {"vorbis_block_init", (void **) &qvorbis_block_init},
491 {"vorbis_block_clear", (void **) &qvorbis_block_clear},
492 {"vorbis_dsp_clear", (void **) &qvorbis_dsp_clear},
493 {"vorbis_analysis_init", (void **) &qvorbis_analysis_init},
494 {"vorbis_commentheader_out", (void **) &qvorbis_commentheader_out},
495 {"vorbis_analysis_headerout", (void **) &qvorbis_analysis_headerout},
496 {"vorbis_analysis_buffer", (void **) &qvorbis_analysis_buffer},
497 {"vorbis_analysis_wrote", (void **) &qvorbis_analysis_wrote},
498 {"vorbis_analysis_blockout", (void **) &qvorbis_analysis_blockout},
499 {"vorbis_analysis", (void **) &qvorbis_analysis},
500 {"vorbis_bitrate_addblock", (void **) &qvorbis_bitrate_addblock},
501 {"vorbis_bitrate_flushpacket", (void **) &qvorbis_bitrate_flushpacket},
502 {"vorbis_granule_time", (void **) &qvorbis_granule_time},
506 static dllfunction_t theorafuncs[] =
508 {"theora_info_init", (void **) &qtheora_info_init},
509 {"theora_info_clear", (void **) &qtheora_info_clear},
510 {"theora_comment_init", (void **) &qtheora_comment_init},
511 {"theora_comment_clear", (void **) &qtheora_comment_clear},
512 {"theora_encode_init", (void **) &qtheora_encode_init},
513 {"theora_encode_YUVin", (void **) &qtheora_encode_YUVin},
514 {"theora_encode_packetout", (void **) &qtheora_encode_packetout},
515 {"theora_encode_header", (void **) &qtheora_encode_header},
516 {"theora_encode_comment", (void **) &qtheora_encode_comment},
517 {"theora_encode_tables", (void **) &qtheora_encode_tables},
518 {"theora_clear", (void **) &qtheora_clear},
519 {"theora_granule_time", (void **) &qtheora_granule_time},
520 {"theora_control", (void **) &qtheora_control},
524 static dllhandle_t og_dll = NULL, vo_dll = NULL, ve_dll = NULL, th_dll = NULL;
526 static qboolean SCR_CaptureVideo_Ogg_OpenLibrary(void)
528 const char* dllnames_og [] =
534 #elif defined(MACOSX)
542 const char* dllnames_vo [] =
548 #elif defined(MACOSX)
556 const char* dllnames_ve [] =
559 "libvorbisenc-2.dll",
562 #elif defined(MACOSX)
563 "libvorbisenc.dylib",
570 const char* dllnames_th [] =
576 #elif defined(MACOSX)
586 Sys_LoadLibrary (dllnames_og, &og_dll, oggfuncs)
588 Sys_LoadLibrary (dllnames_th, &th_dll, theorafuncs)
590 Sys_LoadLibrary (dllnames_vo, &vo_dll, vorbisfuncs)
592 Sys_LoadLibrary (dllnames_ve, &ve_dll, vorbisencfuncs);
595 void SCR_CaptureVideo_Ogg_Init(void)
597 SCR_CaptureVideo_Ogg_OpenLibrary();
599 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_vp3compat);
600 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_quality);
601 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_bitrate);
602 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier);
603 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_maxinterval);
604 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_mininterval);
605 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_auto_threshold);
606 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_noise_sensitivity);
607 Cvar_RegisterVariable(&cl_capturevideo_ogg_vorbis_quality);
610 qboolean SCR_CaptureVideo_Ogg_Available(void)
612 return og_dll && th_dll && vo_dll && ve_dll;
615 void SCR_CaptureVideo_Ogg_CloseDLL(void)
617 Sys_UnloadLibrary (&ve_dll);
618 Sys_UnloadLibrary (&vo_dll);
619 Sys_UnloadLibrary (&th_dll);
620 Sys_UnloadLibrary (&og_dll);
623 // this struct should not be needed
624 // however, libogg appears to pull the ogg_page's data element away from our
625 // feet before we get to write the data due to interleaving
626 // so this struct is used to keep the page data around until it actually gets
628 typedef struct allocatedoggpage_s
632 unsigned char data[65307];
633 // this number is from RFC 3533. In case libogg writes more, we'll have to increase this
634 // but we'll get a Host_Error in this case so we can track it down
638 typedef struct capturevideostate_ogg_formatspecific_s
640 ogg_stream_state to, vo;
641 int serial1, serial2;
651 allocatedoggpage_t videopage, audiopage;
653 capturevideostate_ogg_formatspecific_t;
654 #define LOAD_FORMATSPECIFIC_OGG() capturevideostate_ogg_formatspecific_t *format = (capturevideostate_ogg_formatspecific_t *) cls.capturevideo.formatspecific
656 static void SCR_CaptureVideo_Ogg_Interleave(void)
658 LOAD_FORMATSPECIFIC_OGG();
661 if(!cls.capturevideo.soundrate)
663 while(qogg_stream_pageout(&format->to, &pg) > 0)
665 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
666 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
673 // first: make sure we have a page of both types
674 if(!format->videopage.len)
675 if(qogg_stream_pageout(&format->to, &pg) > 0)
677 format->videopage.len = pg.header_len + pg.body_len;
678 format->videopage.time = qtheora_granule_time(&format->ts, qogg_page_granulepos(&pg));
679 if(format->videopage.len > sizeof(format->videopage.data))
680 Sys_Error("video page too long");
681 memcpy(format->videopage.data, pg.header, pg.header_len);
682 memcpy(format->videopage.data + pg.header_len, pg.body, pg.body_len);
684 if(!format->audiopage.len)
685 if(qogg_stream_pageout(&format->vo, &pg) > 0)
687 format->audiopage.len = pg.header_len + pg.body_len;
688 format->audiopage.time = qvorbis_granule_time(&format->vd, qogg_page_granulepos(&pg));
689 if(format->audiopage.len > sizeof(format->audiopage.data))
690 Sys_Error("audio page too long");
691 memcpy(format->audiopage.data, pg.header, pg.header_len);
692 memcpy(format->audiopage.data + pg.header_len, pg.body, pg.body_len);
695 if(format->videopage.len && format->audiopage.len)
697 // output the page that ends first
698 if(format->videopage.time < format->audiopage.time)
700 FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len);
701 format->videopage.len = 0;
705 FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len);
706 format->audiopage.len = 0;
714 static void SCR_CaptureVideo_Ogg_FlushInterleaving(void)
716 LOAD_FORMATSPECIFIC_OGG();
718 if(cls.capturevideo.soundrate)
719 if(format->audiopage.len)
721 FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len);
722 format->audiopage.len = 0;
725 if(format->videopage.len)
727 FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len);
728 format->videopage.len = 0;
732 static void SCR_CaptureVideo_Ogg_EndVideo(void)
734 LOAD_FORMATSPECIFIC_OGG();
738 if(format->yuvi >= 0)
740 // send the previous (and last) frame
741 while(format->lastnum-- > 0)
743 qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]);
745 while(qtheora_encode_packetout(&format->ts, !format->lastnum, &pt))
746 qogg_stream_packetin(&format->to, &pt);
748 SCR_CaptureVideo_Ogg_Interleave();
752 if(cls.capturevideo.soundrate)
754 qvorbis_analysis_wrote(&format->vd, 0);
755 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
757 qvorbis_analysis(&format->vb, NULL);
758 qvorbis_bitrate_addblock(&format->vb);
759 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
760 qogg_stream_packetin(&format->vo, &pt);
761 SCR_CaptureVideo_Ogg_Interleave();
765 SCR_CaptureVideo_Ogg_FlushInterleaving();
767 while(qogg_stream_pageout(&format->to, &pg) > 0)
769 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
770 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
773 if(cls.capturevideo.soundrate)
775 while(qogg_stream_pageout(&format->vo, &pg) > 0)
777 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
778 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
783 int result = qogg_stream_flush (&format->to, &pg);
785 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
788 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
789 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
792 if(cls.capturevideo.soundrate)
795 int result = qogg_stream_flush (&format->vo, &pg);
797 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
800 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
801 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
804 qogg_stream_clear(&format->vo);
805 qvorbis_block_clear(&format->vb);
806 qvorbis_dsp_clear(&format->vd);
809 qogg_stream_clear(&format->to);
810 qtheora_clear(&format->ts);
811 qvorbis_info_clear(&format->vi);
813 Mem_Free(format->yuv[0].y);
814 Mem_Free(format->yuv[0].u);
815 Mem_Free(format->yuv[0].v);
816 Mem_Free(format->yuv[1].y);
817 Mem_Free(format->yuv[1].u);
818 Mem_Free(format->yuv[1].v);
821 FS_Close(cls.capturevideo.videofile);
822 cls.capturevideo.videofile = NULL;
825 static void SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV(void)
827 LOAD_FORMATSPECIFIC_OGG();
830 int blockr, blockg, blockb;
831 unsigned char *b = cls.capturevideo.outbuffer;
832 int w = cls.capturevideo.width;
833 int h = cls.capturevideo.height;
836 yuv = &format->yuv[format->yuvi];
838 for(y = 0; y < h; ++y)
840 for(b = cls.capturevideo.outbuffer + (h-1-y)*w*4, x = 0; x < w; ++x)
845 yuv->y[x + yuv->y_stride * y] =
846 cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]];
850 if ((y & 1) == 0 && y/2 < h/2) // if h is odd, this skips the last row
852 for(b = cls.capturevideo.outbuffer + (h-2-y)*w*4, x = 0; x < w/2; ++x)
854 blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2;
855 blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2;
856 blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2;
857 yuv->u[x + yuv->uv_stride * (y/2)] =
858 cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128];
859 yuv->v[x + yuv->uv_stride * (y/2)] =
860 cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128];
867 static void SCR_CaptureVideo_Ogg_VideoFrames(int num)
869 LOAD_FORMATSPECIFIC_OGG();
872 // data is in cls.capturevideo.outbuffer as BGRA and has size width*height
874 if(format->yuvi >= 0)
876 // send the previous frame
877 while(format->lastnum-- > 0)
879 qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]);
881 while(qtheora_encode_packetout(&format->ts, false, &pt))
882 qogg_stream_packetin(&format->to, &pt);
884 SCR_CaptureVideo_Ogg_Interleave();
888 format->yuvi = (format->yuvi + 1) % 2;
889 SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV();
890 format->lastnum = num;
892 // TODO maybe send num-1 frames from here already
895 typedef int channelmapping_t[8];
896 channelmapping_t mapping[8] =
898 { 0, -1, -1, -1, -1, -1, -1, -1 }, // mono
899 { 0, 1, -1, -1, -1, -1, -1, -1 }, // stereo
900 { 0, 1, 2, -1, -1, -1, -1, -1 }, // L C R
901 { 0, 1, 2, 3, -1, -1, -1, -1 }, // surround40
902 { 0, 2, 3, 4, 1, -1, -1, -1 }, // FL FC FR RL RR
903 { 0, 2, 3, 4, 1, 5, -1, -1 }, // surround51
904 { 0, 2, 3, 4, 1, 5, 6, -1 }, // (not defined by vorbis spec)
905 { 0, 2, 3, 4, 1, 5, 6, 7 } // surround71 (not defined by vorbis spec)
908 static void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
910 LOAD_FORMATSPECIFIC_OGG();
911 float **vorbis_buffer;
915 int *map = mapping[bound(1, cls.capturevideo.soundchannels, 8) - 1];
917 vorbis_buffer = qvorbis_analysis_buffer(&format->vd, length);
918 for(j = 0; j < cls.capturevideo.soundchannels; ++j)
920 float *b = vorbis_buffer[map[j]];
921 for(i = 0; i < length; ++i)
922 b[i] = paintbuffer[i].sample[j];
924 qvorbis_analysis_wrote(&format->vd, length);
926 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
928 qvorbis_analysis(&format->vb, NULL);
929 qvorbis_bitrate_addblock(&format->vb);
931 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
932 qogg_stream_packetin(&format->vo, &pt);
935 SCR_CaptureVideo_Ogg_Interleave();
938 void SCR_CaptureVideo_Ogg_BeginVideo(void)
941 cls.capturevideo.format = CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA;
942 cls.capturevideo.formatextension = "ogv";
943 cls.capturevideo.videofile = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false);
944 cls.capturevideo.endvideo = SCR_CaptureVideo_Ogg_EndVideo;
945 cls.capturevideo.videoframes = SCR_CaptureVideo_Ogg_VideoFrames;
946 cls.capturevideo.soundframe = SCR_CaptureVideo_Ogg_SoundFrame;
947 cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_ogg_formatspecific_t));
949 LOAD_FORMATSPECIFIC_OGG();
952 ogg_packet pt, pt2, pt3;
958 format->serial1 = rand();
959 qogg_stream_init(&format->to, format->serial1);
961 if(cls.capturevideo.soundrate)
965 format->serial2 = rand();
967 while(format->serial1 == format->serial2);
968 qogg_stream_init(&format->vo, format->serial2);
971 format->videopage.len = format->audiopage.len = 0;
973 qtheora_info_init(&ti);
974 ti.frame_width = cls.capturevideo.width;
975 ti.frame_height = cls.capturevideo.height;
976 ti.width = (ti.frame_width + 15) & ~15;
977 ti.height = (ti.frame_height + 15) & ~15;
978 //ti.offset_x = ((ti.width - ti.frame_width) / 2) & ~1;
979 //ti.offset_y = ((ti.height - ti.frame_height) / 2) & ~1;
981 for(i = 0; i < 2; ++i)
983 format->yuv[i].y_width = ti.width;
984 format->yuv[i].y_height = ti.height;
985 format->yuv[i].y_stride = ti.width;
986 format->yuv[i].uv_width = ti.width / 2;
987 format->yuv[i].uv_height = ti.height / 2;
988 format->yuv[i].uv_stride = ti.width / 2;
989 format->yuv[i].y = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].y_stride * format->yuv[i].y_height);
990 format->yuv[i].u = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
991 format->yuv[i].v = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
993 format->yuvi = -1; // -1: no frame valid yet, write into 0
995 FindFraction(cls.capturevideo.framerate / cls.capturevideo.framestep, &num, &denom, 1001);
996 ti.fps_numerator = num;
997 ti.fps_denominator = denom;
999 FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000);
1000 ti.aspect_numerator = num;
1001 ti.aspect_denominator = denom;
1003 ti.colorspace = OC_CS_UNSPECIFIED;
1004 ti.pixelformat = OC_PF_420;
1006 ti.quick_p = true; // http://mlblog.osdir.com/multimedia.ogg.theora.general/2004-07/index.shtml
1007 ti.dropframes_p = false;
1009 ti.target_bitrate = cl_capturevideo_ogg_theora_bitrate.integer * 1000;
1010 ti.quality = cl_capturevideo_ogg_theora_quality.integer;
1012 if(ti.target_bitrate <= 0)
1014 ti.target_bitrate = -1;
1015 ti.keyframe_data_target_bitrate = (unsigned int)-1;
1019 ti.keyframe_data_target_bitrate = (int) (ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value));
1021 if(ti.target_bitrate < 45000 || ti.target_bitrate > 2000000)
1022 Con_DPrintf("WARNING: requesting an odd bitrate for theora (sensible values range from 45 to 2000 kbps)\n");
1025 if(ti.quality < 0 || ti.quality > 63)
1028 if(ti.target_bitrate <= 0)
1030 ti.target_bitrate = 0x7FFFFFFF;
1031 ti.keyframe_data_target_bitrate = 0x7FFFFFFF;
1035 // this -1 magic is because ti.keyframe_frequency and ti.keyframe_mindistance use different metrics
1036 ti.keyframe_frequency = bound(1, cl_capturevideo_ogg_theora_keyframe_maxinterval.integer, 1000);
1037 ti.keyframe_mindistance = bound(1, cl_capturevideo_ogg_theora_keyframe_mininterval.integer, (int) ti.keyframe_frequency) - 1;
1038 ti.noise_sensitivity = bound(0, cl_capturevideo_ogg_theora_noise_sensitivity.integer, 6);
1039 ti.sharpness = bound(0, cl_capturevideo_ogg_theora_sharpness.integer, 2);
1040 ti.keyframe_auto_threshold = bound(0, cl_capturevideo_ogg_theora_keyframe_auto_threshold.integer, 100);
1042 ti.keyframe_frequency_force = ti.keyframe_frequency;
1043 ti.keyframe_auto_p = (ti.keyframe_frequency != ti.keyframe_mindistance + 1);
1045 qtheora_encode_init(&format->ts, &ti);
1046 qtheora_info_clear(&ti);
1048 if(cl_capturevideo_ogg_theora_vp3compat.integer)
1051 qtheora_control(&format->ts, TH_ENCCTL_SET_VP3_COMPATIBLE, &vp3compat, sizeof(vp3compat));
1053 Con_DPrintf("Warning: theora stream is not fully VP3 compatible\n");
1057 if(cls.capturevideo.soundrate)
1059 qvorbis_info_init(&format->vi);
1060 qvorbis_encode_init_vbr(&format->vi, cls.capturevideo.soundchannels, cls.capturevideo.soundrate, bound(-1, cl_capturevideo_ogg_vorbis_quality.value, 10) * 0.099);
1061 qvorbis_comment_init(&vc);
1062 qvorbis_analysis_init(&format->vd, &format->vi);
1063 qvorbis_block_init(&format->vd, &format->vb);
1066 qtheora_comment_init(&tc);
1068 /* create the remaining theora headers */
1069 qtheora_encode_header(&format->ts, &pt);
1070 qogg_stream_packetin(&format->to, &pt);
1071 if (qogg_stream_pageout (&format->to, &pg) != 1)
1072 fprintf (stderr, "Internal Ogg library error.\n");
1073 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1074 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1076 qtheora_encode_comment(&tc, &pt);
1077 qogg_stream_packetin(&format->to, &pt);
1078 qtheora_encode_tables(&format->ts, &pt);
1079 qogg_stream_packetin (&format->to, &pt);
1081 qtheora_comment_clear(&tc);
1083 if(cls.capturevideo.soundrate)
1085 qvorbis_analysis_headerout(&format->vd, &vc, &pt, &pt2, &pt3);
1086 qogg_stream_packetin(&format->vo, &pt);
1087 if (qogg_stream_pageout (&format->vo, &pg) != 1)
1088 fprintf (stderr, "Internal Ogg library error.\n");
1089 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1090 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1092 qogg_stream_packetin(&format->vo, &pt2);
1093 qogg_stream_packetin(&format->vo, &pt3);
1095 qvorbis_comment_clear(&vc);
1100 int result = qogg_stream_flush (&format->to, &pg);
1102 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
1105 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1106 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1109 if(cls.capturevideo.soundrate)
1112 int result = qogg_stream_flush (&format->vo, &pg);
1114 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
1117 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1118 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);