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 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 Host_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 Host_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 Host_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 Host_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] / 32768.0f;
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)
940 cls.capturevideo.format = CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA;
941 cls.capturevideo.formatextension = "ogv";
942 cls.capturevideo.videofile = FS_OpenRealFile(va("%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false);
943 cls.capturevideo.endvideo = SCR_CaptureVideo_Ogg_EndVideo;
944 cls.capturevideo.videoframes = SCR_CaptureVideo_Ogg_VideoFrames;
945 cls.capturevideo.soundframe = SCR_CaptureVideo_Ogg_SoundFrame;
946 cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_ogg_formatspecific_t));
948 LOAD_FORMATSPECIFIC_OGG();
951 ogg_packet pt, pt2, pt3;
957 format->serial1 = rand();
958 qogg_stream_init(&format->to, format->serial1);
960 if(cls.capturevideo.soundrate)
964 format->serial2 = rand();
966 while(format->serial1 == format->serial2);
967 qogg_stream_init(&format->vo, format->serial2);
970 format->videopage.len = format->audiopage.len = 0;
972 qtheora_info_init(&ti);
973 ti.frame_width = cls.capturevideo.width;
974 ti.frame_height = cls.capturevideo.height;
975 ti.width = (ti.frame_width + 15) & ~15;
976 ti.height = (ti.frame_height + 15) & ~15;
977 //ti.offset_x = ((ti.width - ti.frame_width) / 2) & ~1;
978 //ti.offset_y = ((ti.height - ti.frame_height) / 2) & ~1;
980 for(i = 0; i < 2; ++i)
982 format->yuv[i].y_width = ti.width;
983 format->yuv[i].y_height = ti.height;
984 format->yuv[i].y_stride = ti.width;
985 format->yuv[i].uv_width = ti.width / 2;
986 format->yuv[i].uv_height = ti.height / 2;
987 format->yuv[i].uv_stride = ti.width / 2;
988 format->yuv[i].y = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].y_stride * format->yuv[i].y_height);
989 format->yuv[i].u = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
990 format->yuv[i].v = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
992 format->yuvi = -1; // -1: no frame valid yet, write into 0
994 FindFraction(cls.capturevideo.framerate / cls.capturevideo.framestep, &num, &denom, 1001);
995 ti.fps_numerator = num;
996 ti.fps_denominator = denom;
998 FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000);
999 ti.aspect_numerator = num;
1000 ti.aspect_denominator = denom;
1002 ti.colorspace = OC_CS_UNSPECIFIED;
1003 ti.pixelformat = OC_PF_420;
1005 ti.quick_p = true; // http://mlblog.osdir.com/multimedia.ogg.theora.general/2004-07/index.shtml
1006 ti.dropframes_p = false;
1008 ti.target_bitrate = cl_capturevideo_ogg_theora_bitrate.integer * 1000;
1009 ti.quality = cl_capturevideo_ogg_theora_quality.integer;
1011 if(ti.target_bitrate <= 0)
1013 ti.target_bitrate = -1;
1014 ti.keyframe_data_target_bitrate = (unsigned int)-1;
1018 ti.keyframe_data_target_bitrate = (int) (ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value));
1020 if(ti.target_bitrate < 45000 || ti.target_bitrate > 2000000)
1021 Con_DPrintf("WARNING: requesting an odd bitrate for theora (sensible values range from 45 to 2000 kbps)\n");
1024 if(ti.quality < 0 || ti.quality > 63)
1027 if(ti.target_bitrate <= 0)
1029 ti.target_bitrate = 0x7FFFFFFF;
1030 ti.keyframe_data_target_bitrate = 0x7FFFFFFF;
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);
1047 if(cl_capturevideo_ogg_theora_vp3compat.integer)
1050 qtheora_control(&format->ts, TH_ENCCTL_SET_VP3_COMPATIBLE, &vp3compat, sizeof(vp3compat));
1052 Con_DPrintf("Warning: theora stream is not fully VP3 compatible\n");
1056 if(cls.capturevideo.soundrate)
1058 qvorbis_info_init(&format->vi);
1059 qvorbis_encode_init_vbr(&format->vi, cls.capturevideo.soundchannels, cls.capturevideo.soundrate, bound(-1, cl_capturevideo_ogg_vorbis_quality.value, 10) * 0.099);
1060 qvorbis_comment_init(&vc);
1061 qvorbis_analysis_init(&format->vd, &format->vi);
1062 qvorbis_block_init(&format->vd, &format->vb);
1065 qtheora_comment_init(&tc);
1067 /* create the remaining theora headers */
1068 qtheora_encode_header(&format->ts, &pt);
1069 qogg_stream_packetin(&format->to, &pt);
1070 if (qogg_stream_pageout (&format->to, &pg) != 1)
1071 fprintf (stderr, "Internal Ogg library error.\n");
1072 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1073 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1075 qtheora_encode_comment(&tc, &pt);
1076 qogg_stream_packetin(&format->to, &pt);
1077 qtheora_encode_tables(&format->ts, &pt);
1078 qogg_stream_packetin (&format->to, &pt);
1080 qtheora_comment_clear(&tc);
1082 if(cls.capturevideo.soundrate)
1084 qvorbis_analysis_headerout(&format->vd, &vc, &pt, &pt2, &pt3);
1085 qogg_stream_packetin(&format->vo, &pt);
1086 if (qogg_stream_pageout (&format->vo, &pg) != 1)
1087 fprintf (stderr, "Internal Ogg library error.\n");
1088 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1089 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1091 qogg_stream_packetin(&format->vo, &pt2);
1092 qogg_stream_packetin(&format->vo, &pt3);
1094 qvorbis_comment_clear(&vc);
1099 int result = qogg_stream_flush (&format->to, &pg);
1101 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
1104 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1105 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1108 if(cls.capturevideo.soundrate)
1111 int result = qogg_stream_flush (&format->vo, &pg);
1113 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
1116 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1117 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);