8 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"};
9 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"};
10 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"};
11 static cvar_t cl_capturevideo_ogg_theora_keyframe_frequency = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_frequency", "64", "maximum number of frames between two key frames (1 to 1000)"};
12 static cvar_t cl_capturevideo_ogg_theora_keyframe_mindistance = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_mindistance", "8", "minimum number of frames between two key frames (1 to 1000)"};
13 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)"};
14 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"};
15 static cvar_t cl_capturevideo_ogg_theora_sharpness = {CVAR_SAVE, "cl_capturevideo_ogg_theora_sharpness", "0", "sharpness (0 to 2); lower is sharper"};
16 static cvar_t cl_capturevideo_ogg_vorbis_quality = {CVAR_SAVE, "cl_capturevideo_ogg_vorbis_quality", "1", "audio quality (-1 to 10); higher is better"};
19 typedef int16_t ogg_int16_t;
20 typedef u_int16_t ogg_uint16_t;
21 typedef int32_t ogg_int32_t;
22 typedef u_int32_t ogg_uint32_t;
23 typedef int64_t ogg_int64_t;
29 unsigned char *buffer;
34 /* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
37 unsigned char *header;
43 /* ogg_stream_state contains the current encode/decode state of a logical
44 Ogg bitstream **********************************************************/
47 unsigned char *body_data; /* bytes from packet bodies */
48 long body_storage; /* storage elements allocated */
49 long body_fill; /* elements stored; fill mark */
50 long body_returned; /* elements of fill returned */
53 int *lacing_vals; /* The values that will go to the segment table */
54 ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
55 this way, but it is simple coupled to the
62 unsigned char header[282]; /* working space for header encode */
65 int e_o_s; /* set when we have buffered the last packet in the
67 int b_o_s; /* set after we've written the initial page
68 of a logical bitstream */
71 ogg_int64_t packetno; /* sequence number for decode; the framing
72 knows where there's a hole in the data,
73 but we need coupling so that the codec
74 (which is in a seperate abstraction
75 layer) also knows about the gap */
76 ogg_int64_t granulepos;
80 /* ogg_packet is used to encapsulate the data and metadata belonging
81 to a single raw Ogg/Vorbis packet *************************************/
84 unsigned char *packet;
89 ogg_int64_t granulepos;
91 ogg_int64_t packetno; /* sequence number for decode; the framing
92 knows where there's a hole in the data,
93 but we need coupling so that the codec
94 (which is in a seperate abstraction
95 layer) also knows about the gap */
109 /* Ogg BITSTREAM PRIMITIVES: encoding **************************/
111 static int (*qogg_stream_packetin) (ogg_stream_state *os, ogg_packet *op);
112 static int (*qogg_stream_pageout) (ogg_stream_state *os, ogg_page *og);
113 static int (*qogg_stream_flush) (ogg_stream_state *os, ogg_page *og);
115 /* Ogg BITSTREAM PRIMITIVES: general ***************************/
117 static int (*qogg_stream_init) (ogg_stream_state *os,int serialno);
118 static int (*qogg_stream_clear) (ogg_stream_state *os);
119 static ogg_int64_t (*qogg_page_granulepos) (ogg_page *og);
121 // end of ogg.h stuff
123 // vorbis/codec.h stuff
124 typedef struct vorbis_info{
129 /* The below bitrate declarations are *hints*.
130 Combinations of the three values carry the following implications:
132 all three set to the same value:
133 implies a fixed rate bitstream
135 implies a VBR stream that averages the nominal bitrate. No hard
137 upper and or lower set:
138 implies a VBR bitstream that obeys the bitrate limits. nominal
139 may also be set to give a nominal rate.
141 the coder does not care to speculate.
145 long bitrate_nominal;
152 /* vorbis_dsp_state buffers the current vorbis audio
153 analysis/synthesis state. The DSP state belongs to a specific
154 logical bitstream ****************************************************/
155 typedef struct vorbis_dsp_state{
173 ogg_int64_t granulepos;
174 ogg_int64_t sequence;
176 ogg_int64_t glue_bits;
177 ogg_int64_t time_bits;
178 ogg_int64_t floor_bits;
179 ogg_int64_t res_bits;
184 typedef struct vorbis_block{
185 /* necessary stream state for linking to the framing abstraction */
186 float **pcm; /* this is a pointer into local storage */
196 ogg_int64_t granulepos;
197 ogg_int64_t sequence;
198 vorbis_dsp_state *vd; /* For read-only access of configuration */
200 /* local storage to avoid remallocing; it's up to the mapping to
206 struct alloc_chain *reap;
208 /* bitmetrics for the frame */
218 /* vorbis_block is a single block of data to be processed as part of
219 the analysis/synthesis stream; it belongs to a specific logical
220 bitstream, but is independant from other vorbis_blocks belonging to
221 that logical bitstream. *************************************************/
225 struct alloc_chain *next;
228 /* vorbis_info contains all the setup information specific to the
229 specific compression/decompression mode in progress (eg,
230 psychoacoustic settings, channel setup, options, codebook
231 etc). vorbis_info and substructures are in backends.h.
232 *********************************************************************/
234 /* the comments are not part of vorbis_info so that vorbis_info can be
236 typedef struct vorbis_comment{
237 /* unlimited user comment fields. libvorbis writes 'libvorbis'
238 whatever vendor is set to in encode */
239 char **user_comments;
240 int *comment_lengths;
247 /* libvorbis encodes in two abstraction layers; first we perform DSP
248 and produce a packet (see docs/analysis.txt). The packet is then
249 coded into a framed OggSquish bitstream by the second layer (see
250 docs/framing.txt). Decode is the reverse process; we sync/frame
251 the bitstream and extract individual packets, then decode the
252 packet back into PCM audio.
254 The extra framing/packetizing is used in streaming formats, such as
255 files. Over the net (such as with UDP), the framing and
256 packetization aren't necessary as they're provided by the transport
257 and the streaming layer is not used */
259 /* Vorbis PRIMITIVES: general ***************************************/
261 static void (*qvorbis_info_init) (vorbis_info *vi);
262 static void (*qvorbis_info_clear) (vorbis_info *vi);
263 static void (*qvorbis_comment_init) (vorbis_comment *vc);
264 static void (*qvorbis_comment_clear) (vorbis_comment *vc);
266 static int (*qvorbis_block_init) (vorbis_dsp_state *v, vorbis_block *vb);
267 static int (*qvorbis_block_clear) (vorbis_block *vb);
268 static void (*qvorbis_dsp_clear) (vorbis_dsp_state *v);
269 static double (*qvorbis_granule_time) (vorbis_dsp_state *v,
270 ogg_int64_t granulepos);
272 /* Vorbis PRIMITIVES: analysis/DSP layer ****************************/
274 static int (*qvorbis_analysis_init) (vorbis_dsp_state *v,vorbis_info *vi);
275 static int (*qvorbis_commentheader_out) (vorbis_comment *vc, ogg_packet *op);
276 static int (*qvorbis_analysis_headerout) (vorbis_dsp_state *v,
280 ogg_packet *op_code);
281 static float ** (*qvorbis_analysis_buffer) (vorbis_dsp_state *v,int vals);
282 static int (*qvorbis_analysis_wrote) (vorbis_dsp_state *v,int vals);
283 static int (*qvorbis_analysis_blockout) (vorbis_dsp_state *v,vorbis_block *vb);
284 static int (*qvorbis_analysis) (vorbis_block *vb,ogg_packet *op);
286 static int (*qvorbis_bitrate_addblock) (vorbis_block *vb);
287 static int (*qvorbis_bitrate_flushpacket) (vorbis_dsp_state *vd,
290 // end of vorbis/codec.h stuff
293 static int (*qvorbis_encode_init_vbr) (vorbis_info *vi,
297 float base_quality /* quality level from 0. (lo) to 1. (hi) */
299 // end of vorbisenc.h stuff
303 int y_width; /**< Width of the Y' luminance plane */
304 int y_height; /**< Height of the luminance plane */
305 int y_stride; /**< Offset in bytes between successive rows */
307 int uv_width; /**< Width of the Cb and Cr chroma planes */
308 int uv_height; /**< Height of the chroma planes */
309 int uv_stride; /**< Offset between successive chroma rows */
310 unsigned char *y; /**< Pointer to start of luminance data */
311 unsigned char *u; /**< Pointer to start of Cb data */
312 unsigned char *v; /**< Pointer to start of Cr data */
320 OC_CS_UNSPECIFIED, /**< The colorspace is unknown or unspecified */
321 OC_CS_ITU_REC_470M, /**< This is the best option for 'NTSC' content */
322 OC_CS_ITU_REC_470BG, /**< This is the best option for 'PAL' content */
323 OC_CS_NSPACES /**< This marks the end of the defined colorspaces */
327 * A Chroma subsampling
329 * These enumerate the available chroma subsampling options supported
330 * by the theora format. See Section 4.4 of the specification for
334 OC_PF_420, /**< Chroma subsampling by 2 in each direction (4:2:0) */
335 OC_PF_RSVD, /**< Reserved value */
336 OC_PF_422, /**< Horizonatal chroma subsampling by 2 (4:2:2) */
337 OC_PF_444, /**< No chroma subsampling at all (4:4:4) */
338 } theora_pixelformat;
340 * Theora bitstream info.
341 * Contains the basic playback parameters for a stream,
342 * corresponding to the initial 'info' header packet.
344 * Encoded theora frames must be a multiple of 16 in width and height.
345 * To handle other frame sizes, a crop rectangle is specified in
346 * frame_height and frame_width, offset_x and * offset_y. The offset
347 * and size should still be a multiple of 2 to avoid chroma sampling
348 * shifts. Offset values in this structure are measured from the
349 * upper left of the image.
351 * Frame rate, in frames per second, is stored as a rational
352 * fraction. Aspect ratio is also stored as a rational fraction, and
353 * refers to the aspect ratio of the frame pixels, not of the
354 * overall frame itself.
356 * See <a href="http://svn.xiph.org/trunk/theora/examples/encoder_example.c">
357 * examples/encoder_example.c</a> for usage examples of the
358 * other paramters and good default settings for the encoder parameters.
361 ogg_uint32_t width; /**< encoded frame width */
362 ogg_uint32_t height; /**< encoded frame height */
363 ogg_uint32_t frame_width; /**< display frame width */
364 ogg_uint32_t frame_height; /**< display frame height */
365 ogg_uint32_t offset_x; /**< horizontal offset of the displayed frame */
366 ogg_uint32_t offset_y; /**< vertical offset of the displayed frame */
367 ogg_uint32_t fps_numerator; /**< frame rate numerator **/
368 ogg_uint32_t fps_denominator; /**< frame rate denominator **/
369 ogg_uint32_t aspect_numerator; /**< pixel aspect ratio numerator */
370 ogg_uint32_t aspect_denominator; /**< pixel aspect ratio denominator */
371 theora_colorspace colorspace; /**< colorspace */
372 int target_bitrate; /**< nominal bitrate in bits per second */
373 int quality; /**< Nominal quality setting, 0-63 */
374 int quick_p; /**< Quick encode/decode */
377 unsigned char version_major;
378 unsigned char version_minor;
379 unsigned char version_subminor;
386 ogg_uint32_t keyframe_frequency;
387 ogg_uint32_t keyframe_frequency_force; /* also used for decode init to
388 get granpos shift correct */
389 ogg_uint32_t keyframe_data_target_bitrate;
390 ogg_int32_t keyframe_auto_threshold;
391 ogg_uint32_t keyframe_mindistance;
392 ogg_int32_t noise_sensitivity;
393 ogg_int32_t sharpness;
395 theora_pixelformat pixelformat; /**< chroma subsampling mode to expect */
399 /** Codec internal state and context.
403 ogg_int64_t granulepos;
405 void *internal_encode;
406 void *internal_decode;
411 * Comment header metadata.
413 * This structure holds the in-stream metadata corresponding to
414 * the 'comment' header packet.
416 * Meta data is stored as a series of (tag, value) pairs, in
417 * length-encoded string vectors. The first occurence of the
418 * '=' character delimits the tag and value. A particular tag
419 * may occur more than once. The character set encoding for
420 * the strings is always UTF-8, but the tag names are limited
421 * to case-insensitive ASCII. See the spec for details.
423 * In filling in this structure, qtheora_decode_header() will
424 * null-terminate the user_comment strings for safety. However,
425 * the bitstream format itself treats them as 8-bit clean,
426 * and so the length array should be treated as authoritative
429 typedef struct theora_comment{
430 char **user_comments; /**< An array of comment string vectors */
431 int *comment_lengths; /**< An array of corresponding string vector lengths in bytes */
432 int comments; /**< The total number of comment string vectors */
433 char *vendor; /**< The vendor string identifying the encoder, null terminated */
436 static int (*qtheora_encode_init) (theora_state *th, theora_info *ti);
437 static int (*qtheora_encode_YUVin) (theora_state *t, yuv_buffer *yuv);
438 static int (*qtheora_encode_packetout) ( theora_state *t, int last_p,
440 static int (*qtheora_encode_header) (theora_state *t, ogg_packet *op);
441 static int (*qtheora_encode_comment) (theora_comment *tc, ogg_packet *op);
442 static int (*qtheora_encode_tables) (theora_state *t, ogg_packet *op);
443 static void (*qtheora_info_init) (theora_info *c);
444 static void (*qtheora_info_clear) (theora_info *c);
445 static void (*qtheora_clear) (theora_state *t);
446 static void (*qtheora_comment_init) (theora_comment *tc);
447 static void (*qtheora_comment_clear) (theora_comment *tc);
448 static double (*qtheora_granule_time) (theora_state *th,ogg_int64_t granulepos);
449 // end of theora.h stuff
451 static dllfunction_t oggfuncs[] =
453 {"ogg_stream_packetin", (void **) &qogg_stream_packetin},
454 {"ogg_stream_pageout", (void **) &qogg_stream_pageout},
455 {"ogg_stream_flush", (void **) &qogg_stream_flush},
456 {"ogg_stream_init", (void **) &qogg_stream_init},
457 {"ogg_stream_clear", (void **) &qogg_stream_clear},
458 {"ogg_page_granulepos", (void **) &qogg_page_granulepos},
462 static dllfunction_t vorbisencfuncs[] =
464 {"vorbis_encode_init_vbr", (void **) &qvorbis_encode_init_vbr},
468 static dllfunction_t vorbisfuncs[] =
470 {"vorbis_info_init", (void **) &qvorbis_info_init},
471 {"vorbis_info_clear", (void **) &qvorbis_info_clear},
472 {"vorbis_comment_init", (void **) &qvorbis_comment_init},
473 {"vorbis_comment_clear", (void **) &qvorbis_comment_clear},
474 {"vorbis_block_init", (void **) &qvorbis_block_init},
475 {"vorbis_block_clear", (void **) &qvorbis_block_clear},
476 {"vorbis_dsp_clear", (void **) &qvorbis_dsp_clear},
477 {"vorbis_analysis_init", (void **) &qvorbis_analysis_init},
478 {"vorbis_commentheader_out", (void **) &qvorbis_commentheader_out},
479 {"vorbis_analysis_headerout", (void **) &qvorbis_analysis_headerout},
480 {"vorbis_analysis_buffer", (void **) &qvorbis_analysis_buffer},
481 {"vorbis_analysis_wrote", (void **) &qvorbis_analysis_wrote},
482 {"vorbis_analysis_blockout", (void **) &qvorbis_analysis_blockout},
483 {"vorbis_analysis", (void **) &qvorbis_analysis},
484 {"vorbis_bitrate_addblock", (void **) &qvorbis_bitrate_addblock},
485 {"vorbis_bitrate_flushpacket", (void **) &qvorbis_bitrate_flushpacket},
486 {"vorbis_granule_time", (void **) &qvorbis_granule_time},
490 static dllfunction_t theorafuncs[] =
492 {"theora_info_init", (void **) &qtheora_info_init},
493 {"theora_info_clear", (void **) &qtheora_info_clear},
494 {"theora_comment_init", (void **) &qtheora_comment_init},
495 {"theora_comment_clear", (void **) &qtheora_comment_clear},
496 {"theora_encode_init", (void **) &qtheora_encode_init},
497 {"theora_encode_YUVin", (void **) &qtheora_encode_YUVin},
498 {"theora_encode_packetout", (void **) &qtheora_encode_packetout},
499 {"theora_encode_header", (void **) &qtheora_encode_header},
500 {"theora_encode_comment", (void **) &qtheora_encode_comment},
501 {"theora_encode_tables", (void **) &qtheora_encode_tables},
502 {"theora_clear", (void **) &qtheora_clear},
503 {"theora_granule_time", (void **) &qtheora_granule_time},
507 static dllhandle_t og_dll = NULL, vo_dll = NULL, ve_dll = NULL, th_dll = NULL;
509 qboolean SCR_CaptureVideo_Ogg_OpenLibrary()
511 const char* dllnames_og [] =
518 #elif defined(MACOSX)
526 const char* dllnames_vo [] =
533 #elif defined(MACOSX)
541 const char* dllnames_ve [] =
544 "libvorbisenc64.dll",
548 #elif defined(MACOSX)
549 "libvorbisenc.dylib",
556 const char* dllnames_th [] =
563 #elif defined(MACOSX)
573 Sys_LoadLibrary (dllnames_og, &og_dll, oggfuncs)
575 Sys_LoadLibrary (dllnames_th, &th_dll, theorafuncs)
577 Sys_LoadLibrary (dllnames_vo, &vo_dll, vorbisfuncs)
579 Sys_LoadLibrary (dllnames_ve, &ve_dll, vorbisencfuncs);
582 void SCR_CaptureVideo_Ogg_Init()
584 SCR_CaptureVideo_Ogg_OpenLibrary();
586 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_quality);
587 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_bitrate);
588 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier);
589 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_frequency);
590 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_mindistance);
591 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_auto_threshold);
592 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_noise_sensitivity);
593 Cvar_RegisterVariable(&cl_capturevideo_ogg_vorbis_quality);
596 qboolean SCR_CaptureVideo_Ogg_Available()
598 return og_dll && th_dll && vo_dll && ve_dll;
601 void SCR_CaptureVideo_Ogg_CloseDLL()
603 Sys_UnloadLibrary (&ve_dll);
604 Sys_UnloadLibrary (&vo_dll);
605 Sys_UnloadLibrary (&th_dll);
606 Sys_UnloadLibrary (&og_dll);
609 typedef struct capturevideostate_ogg_formatspecific_s
611 ogg_stream_state to, vo;
612 int serial1, serial2;
623 qboolean have_videopage;
624 qboolean have_audiopage;
626 capturevideostate_ogg_formatspecific_t;
627 #define LOAD_FORMATSPECIFIC_OGG() capturevideostate_ogg_formatspecific_t *format = (capturevideostate_ogg_formatspecific_t *) cls.capturevideo.formatspecific
629 static void SCR_CaptureVideo_Ogg_Interleave()
631 LOAD_FORMATSPECIFIC_OGG();
633 if(!cls.capturevideo.soundrate)
637 // first: make sure we have a page of both types
638 if(!format->have_videopage)
639 if(qogg_stream_pageout(&format->to, &format->videopage) > 0)
640 format->have_videopage = true;
641 if(format->have_videopage)
643 FS_Write(cls.capturevideo.videofile, format->videopage.header, format->videopage.header_len);
644 FS_Write(cls.capturevideo.videofile, format->videopage.body, format->videopage.body_len);
645 format->have_videopage = false;
653 // first: make sure we have a page of both types
654 if(!format->have_videopage)
655 if(qogg_stream_pageout(&format->to, &format->videopage) > 0)
656 format->have_videopage = true;
657 if(!format->have_audiopage)
658 if(qogg_stream_pageout(&format->vo, &format->audiopage) > 0)
659 format->have_audiopage = true;
661 if(format->have_videopage && format->have_audiopage)
663 // output the page that ends first
664 double audiotime = qvorbis_granule_time(&format->vd, qogg_page_granulepos(&format->audiopage));
665 double videotime = qtheora_granule_time(&format->ts, qogg_page_granulepos(&format->videopage));
666 if(audiotime < videotime)
668 FS_Write(cls.capturevideo.videofile, format->audiopage.header, format->audiopage.header_len);
669 FS_Write(cls.capturevideo.videofile, format->audiopage.body, format->audiopage.body_len);
670 format->have_audiopage = false;
674 FS_Write(cls.capturevideo.videofile, format->videopage.header, format->videopage.header_len);
675 FS_Write(cls.capturevideo.videofile, format->videopage.body, format->videopage.body_len);
676 format->have_videopage = false;
684 static void SCR_CaptureVideo_Ogg_FlushInterleaving()
686 LOAD_FORMATSPECIFIC_OGG();
688 if(cls.capturevideo.soundrate)
689 if(format->have_audiopage)
691 FS_Write(cls.capturevideo.videofile, format->audiopage.header, format->audiopage.header_len);
692 FS_Write(cls.capturevideo.videofile, format->audiopage.body, format->audiopage.body_len);
693 format->have_audiopage = false;
696 if(format->have_videopage)
698 FS_Write(cls.capturevideo.videofile, format->videopage.header, format->videopage.header_len);
699 FS_Write(cls.capturevideo.videofile, format->videopage.body, format->videopage.body_len);
700 format->have_videopage = false;
704 static void SCR_CaptureVideo_Ogg_EndVideo()
706 LOAD_FORMATSPECIFIC_OGG();
710 // repeat the last frame so we can set the end-of-stream flag
711 qtheora_encode_YUVin(&format->ts, &format->yuv);
712 qtheora_encode_packetout(&format->ts, true, &pt);
713 qogg_stream_packetin(&format->to, &pt);
714 SCR_CaptureVideo_Ogg_Interleave();
716 if(cls.capturevideo.soundrate)
718 qvorbis_analysis_wrote(&format->vd, 0);
719 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
721 qvorbis_analysis(&format->vb, NULL);
722 qvorbis_bitrate_addblock(&format->vb);
723 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
724 qogg_stream_packetin(&format->vo, &pt);
725 SCR_CaptureVideo_Ogg_Interleave();
729 SCR_CaptureVideo_Ogg_FlushInterleaving();
731 while(qogg_stream_pageout(&format->to, &pg) > 0)
733 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
734 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
737 if(cls.capturevideo.soundrate)
739 while(qogg_stream_pageout(&format->vo, &pg) > 0)
741 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
742 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
747 int result = qogg_stream_flush (&format->to, &pg);
749 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
752 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
753 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
756 if(cls.capturevideo.soundrate)
759 int result = qogg_stream_flush (&format->vo, &pg);
761 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
764 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
765 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
768 qogg_stream_clear(&format->vo);
769 qvorbis_block_clear(&format->vb);
770 qvorbis_dsp_clear(&format->vd);
773 qogg_stream_clear(&format->to);
774 qtheora_clear(&format->ts);
775 qvorbis_info_clear(&format->vi);
777 Mem_Free(format->yuv.y);
778 Mem_Free(format->yuv.u);
779 Mem_Free(format->yuv.v);
782 FS_Close(cls.capturevideo.videofile);
783 cls.capturevideo.videofile = NULL;
786 static void SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV()
788 LOAD_FORMATSPECIFIC_OGG();
790 int blockr, blockg, blockb;
791 unsigned char *b = cls.capturevideo.outbuffer;
792 int w = cls.capturevideo.width;
793 int h = cls.capturevideo.height;
796 for(y = 0; y < h; ++y)
798 for(b = cls.capturevideo.outbuffer + (h-1-y)*w*4, x = 0; x < w; ++x)
803 format->yuv.y[x + format->yuv.y_stride * y] =
804 cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]];
810 for(b = cls.capturevideo.outbuffer + (h-2-y)*w*4, x = 0; x < w/2; ++x)
812 blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2;
813 blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2;
814 blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2;
815 format->yuv.u[x + format->yuv.uv_stride * (y/2)] =
816 cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128];
817 format->yuv.v[x + format->yuv.uv_stride * (y/2)] =
818 cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128];
825 static void SCR_CaptureVideo_Ogg_VideoFrames(int num)
827 LOAD_FORMATSPECIFIC_OGG();
830 // data is in cls.capturevideo.outbuffer as BGRA and has size width*height
832 SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV();
836 qtheora_encode_YUVin(&format->ts, &format->yuv);
837 qtheora_encode_packetout(&format->ts, false, &pt);
838 qogg_stream_packetin(&format->to, &pt);
840 SCR_CaptureVideo_Ogg_Interleave();
844 static void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
846 LOAD_FORMATSPECIFIC_OGG();
847 float **vorbis_buffer;
852 vorbis_buffer = qvorbis_analysis_buffer(&format->vd, length);
853 for(i = 0; i < length; ++i)
855 for(j = 0; j < cls.capturevideo.soundchannels; ++j)
856 vorbis_buffer[j][i] = paintbuffer[i].sample[j] / 32768.0f;
858 qvorbis_analysis_wrote(&format->vd, length);
860 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
862 qvorbis_analysis(&format->vb, NULL);
863 qvorbis_bitrate_addblock(&format->vb);
865 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
866 qogg_stream_packetin(&format->vo, &pt);
868 SCR_CaptureVideo_Ogg_Interleave();
872 void SCR_CaptureVideo_Ogg_BeginVideo()
874 cls.capturevideo.format = CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA;
875 cls.capturevideo.videofile = FS_OpenRealFile(va("%s.ogv", cls.capturevideo.basename), "wb", false);
876 cls.capturevideo.endvideo = SCR_CaptureVideo_Ogg_EndVideo;
877 cls.capturevideo.videoframes = SCR_CaptureVideo_Ogg_VideoFrames;
878 cls.capturevideo.soundframe = SCR_CaptureVideo_Ogg_SoundFrame;
879 cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_ogg_formatspecific_t));
881 LOAD_FORMATSPECIFIC_OGG();
884 ogg_packet pt, pt2, pt3;
889 format->serial1 = rand();
890 qogg_stream_init(&format->to, format->serial1);
892 if(cls.capturevideo.soundrate)
896 format->serial2 = rand();
898 while(format->serial1 == format->serial2);
899 qogg_stream_init(&format->vo, format->serial2);
902 format->have_videopage = format->have_audiopage = false;
904 qtheora_info_init(&ti);
905 ti.frame_width = cls.capturevideo.width;
906 ti.frame_height = cls.capturevideo.height;
907 ti.width = (ti.frame_width + 15) & ~15;
908 ti.height = (ti.frame_height + 15) & ~15;
909 //ti.offset_x = ((ti.width - ti.frame_width) / 2) & ~1;
910 //ti.offset_y = ((ti.height - ti.frame_height) / 2) & ~1;
912 format->yuv.y_width = ti.width;
913 format->yuv.y_height = ti.height;
914 format->yuv.y_stride = ti.width;
916 format->yuv.uv_width = ti.width / 2;
917 format->yuv.uv_height = ti.height / 2;
918 format->yuv.uv_stride = ti.width / 2;
920 format->yuv.y = Mem_Alloc(tempmempool, format->yuv.y_stride * format->yuv.y_height);
921 format->yuv.u = Mem_Alloc(tempmempool, format->yuv.uv_stride * format->yuv.uv_height);
922 format->yuv.v = Mem_Alloc(tempmempool, format->yuv.uv_stride * format->yuv.uv_height);
924 FindFraction(cls.capturevideo.framerate, &num, &denom, 1001);
925 ti.fps_numerator = num;
926 ti.fps_denominator = denom;
928 FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000);
929 ti.aspect_numerator = num;
930 ti.aspect_denominator = denom;
932 ti.colorspace = OC_CS_UNSPECIFIED;
933 ti.pixelformat = OC_PF_420;
935 ti.quick_p = true; // http://mlblog.osdir.com/multimedia.ogg.theora.general/2004-07/index.shtml
936 ti.dropframes_p = false;
938 ti.target_bitrate = cl_capturevideo_ogg_theora_bitrate.integer * 1000;
939 ti.quality = cl_capturevideo_ogg_theora_quality.integer;
941 if(ti.target_bitrate <= 0)
945 ti.target_bitrate = -1;
946 ti.keyframe_data_target_bitrate = -1;
951 ti.target_bitrate = -1;
952 ti.keyframe_data_target_bitrate = -1;
953 ti.quality = bound(0, ti.quality, 63);
960 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
961 ti.keyframe_data_target_bitrate = ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value);
966 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
967 ti.keyframe_data_target_bitrate = ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value);
972 ti.keyframe_frequency = bound(1, cl_capturevideo_ogg_theora_keyframe_frequency.integer, 1000);
973 ti.keyframe_mindistance = bound(1, cl_capturevideo_ogg_theora_keyframe_mindistance.integer, (int) ti.keyframe_frequency);
974 ti.noise_sensitivity = bound(0, cl_capturevideo_ogg_theora_noise_sensitivity.integer, 6);
975 ti.sharpness = bound(0, cl_capturevideo_ogg_theora_sharpness.integer, 2);
976 ti.keyframe_auto_threshold = bound(0, cl_capturevideo_ogg_theora_keyframe_auto_threshold.integer, 100);
978 ti.keyframe_frequency_force = ti.keyframe_frequency;
979 ti.keyframe_auto_p = (ti.keyframe_frequency != ti.keyframe_mindistance);
981 qtheora_encode_init(&format->ts, &ti);
982 qtheora_info_clear(&ti);
985 if(cls.capturevideo.soundrate)
987 qvorbis_info_init(&format->vi);
988 qvorbis_encode_init_vbr(&format->vi, cls.capturevideo.soundchannels, cls.capturevideo.soundrate, bound(-1, cl_capturevideo_ogg_vorbis_quality.value, 10) * 0.099);
989 qvorbis_comment_init(&vc);
990 qvorbis_analysis_init(&format->vd, &format->vi);
991 qvorbis_block_init(&format->vd, &format->vb);
994 qtheora_comment_init(&tc);
996 /* create the remaining theora headers */
997 qtheora_encode_header(&format->ts, &pt);
998 qogg_stream_packetin(&format->to, &pt);
999 if (qogg_stream_pageout (&format->to, &pg) != 1)
1000 fprintf (stderr, "Internal Ogg library error.\n");
1001 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1002 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1004 qtheora_encode_comment(&tc, &pt);
1005 qogg_stream_packetin(&format->to, &pt);
1006 qtheora_encode_tables(&format->ts, &pt);
1007 qogg_stream_packetin (&format->to, &pt);
1009 qtheora_comment_clear(&tc);
1011 if(cls.capturevideo.soundrate)
1013 qvorbis_analysis_headerout(&format->vd, &vc, &pt, &pt2, &pt3);
1014 qogg_stream_packetin(&format->vo, &pt);
1015 if (qogg_stream_pageout (&format->vo, &pg) != 1)
1016 fprintf (stderr, "Internal Ogg library error.\n");
1017 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1018 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1020 qogg_stream_packetin(&format->vo, &pt2);
1021 qogg_stream_packetin(&format->vo, &pt3);
1023 qvorbis_comment_clear(&vc);
1028 int result = qogg_stream_flush (&format->to, &pg);
1030 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
1033 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1034 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1037 if(cls.capturevideo.soundrate)
1040 int result = qogg_stream_flush (&format->vo, &pg);
1042 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
1045 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1046 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);