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"};
20 typedef __int16 ogg_int16_t;
21 typedef unsigned __int16 ogg_uint16_t;
22 typedef __int32 ogg_int32_t;
23 typedef unsigned __int32 ogg_uint32_t;
24 typedef __int64 ogg_int64_t;
26 typedef int16_t ogg_int16_t;
27 typedef uint16_t ogg_uint16_t;
28 typedef int32_t ogg_int32_t;
29 typedef uint32_t ogg_uint32_t;
30 typedef int64_t ogg_int64_t;
37 unsigned char *buffer;
42 /* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
45 unsigned char *header;
51 /* ogg_stream_state contains the current encode/decode state of a logical
52 Ogg bitstream **********************************************************/
55 unsigned char *body_data; /* bytes from packet bodies */
56 long body_storage; /* storage elements allocated */
57 long body_fill; /* elements stored; fill mark */
58 long body_returned; /* elements of fill returned */
61 int *lacing_vals; /* The values that will go to the segment table */
62 ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
63 this way, but it is simple coupled to the
70 unsigned char header[282]; /* working space for header encode */
73 int e_o_s; /* set when we have buffered the last packet in the
75 int b_o_s; /* set after we've written the initial page
76 of a logical bitstream */
79 ogg_int64_t packetno; /* sequence number for decode; the framing
80 knows where there's a hole in the data,
81 but we need coupling so that the codec
82 (which is in a seperate abstraction
83 layer) also knows about the gap */
84 ogg_int64_t granulepos;
88 /* ogg_packet is used to encapsulate the data and metadata belonging
89 to a single raw Ogg/Vorbis packet *************************************/
92 unsigned char *packet;
97 ogg_int64_t granulepos;
99 ogg_int64_t packetno; /* sequence number for decode; the framing
100 knows where there's a hole in the data,
101 but we need coupling so that the codec
102 (which is in a seperate abstraction
103 layer) also knows about the gap */
117 /* Ogg BITSTREAM PRIMITIVES: encoding **************************/
119 static int (*qogg_stream_packetin) (ogg_stream_state *os, ogg_packet *op);
120 static int (*qogg_stream_pageout) (ogg_stream_state *os, ogg_page *og);
121 static int (*qogg_stream_flush) (ogg_stream_state *os, ogg_page *og);
123 /* Ogg BITSTREAM PRIMITIVES: general ***************************/
125 static int (*qogg_stream_init) (ogg_stream_state *os,int serialno);
126 static int (*qogg_stream_clear) (ogg_stream_state *os);
127 static ogg_int64_t (*qogg_page_granulepos) (ogg_page *og);
129 // end of ogg.h stuff
131 // vorbis/codec.h stuff
132 typedef struct vorbis_info{
137 /* The below bitrate declarations are *hints*.
138 Combinations of the three values carry the following implications:
140 all three set to the same value:
141 implies a fixed rate bitstream
143 implies a VBR stream that averages the nominal bitrate. No hard
145 upper and or lower set:
146 implies a VBR bitstream that obeys the bitrate limits. nominal
147 may also be set to give a nominal rate.
149 the coder does not care to speculate.
153 long bitrate_nominal;
160 /* vorbis_dsp_state buffers the current vorbis audio
161 analysis/synthesis state. The DSP state belongs to a specific
162 logical bitstream ****************************************************/
163 typedef struct vorbis_dsp_state{
181 ogg_int64_t granulepos;
182 ogg_int64_t sequence;
184 ogg_int64_t glue_bits;
185 ogg_int64_t time_bits;
186 ogg_int64_t floor_bits;
187 ogg_int64_t res_bits;
192 typedef struct vorbis_block{
193 /* necessary stream state for linking to the framing abstraction */
194 float **pcm; /* this is a pointer into local storage */
204 ogg_int64_t granulepos;
205 ogg_int64_t sequence;
206 vorbis_dsp_state *vd; /* For read-only access of configuration */
208 /* local storage to avoid remallocing; it's up to the mapping to
214 struct alloc_chain *reap;
216 /* bitmetrics for the frame */
226 /* vorbis_block is a single block of data to be processed as part of
227 the analysis/synthesis stream; it belongs to a specific logical
228 bitstream, but is independant from other vorbis_blocks belonging to
229 that logical bitstream. *************************************************/
233 struct alloc_chain *next;
236 /* vorbis_info contains all the setup information specific to the
237 specific compression/decompression mode in progress (eg,
238 psychoacoustic settings, channel setup, options, codebook
239 etc). vorbis_info and substructures are in backends.h.
240 *********************************************************************/
242 /* the comments are not part of vorbis_info so that vorbis_info can be
244 typedef struct vorbis_comment{
245 /* unlimited user comment fields. libvorbis writes 'libvorbis'
246 whatever vendor is set to in encode */
247 char **user_comments;
248 int *comment_lengths;
255 /* libvorbis encodes in two abstraction layers; first we perform DSP
256 and produce a packet (see docs/analysis.txt). The packet is then
257 coded into a framed OggSquish bitstream by the second layer (see
258 docs/framing.txt). Decode is the reverse process; we sync/frame
259 the bitstream and extract individual packets, then decode the
260 packet back into PCM audio.
262 The extra framing/packetizing is used in streaming formats, such as
263 files. Over the net (such as with UDP), the framing and
264 packetization aren't necessary as they're provided by the transport
265 and the streaming layer is not used */
267 /* Vorbis PRIMITIVES: general ***************************************/
269 static void (*qvorbis_info_init) (vorbis_info *vi);
270 static void (*qvorbis_info_clear) (vorbis_info *vi);
271 static void (*qvorbis_comment_init) (vorbis_comment *vc);
272 static void (*qvorbis_comment_clear) (vorbis_comment *vc);
274 static int (*qvorbis_block_init) (vorbis_dsp_state *v, vorbis_block *vb);
275 static int (*qvorbis_block_clear) (vorbis_block *vb);
276 static void (*qvorbis_dsp_clear) (vorbis_dsp_state *v);
277 static double (*qvorbis_granule_time) (vorbis_dsp_state *v,
278 ogg_int64_t granulepos);
280 /* Vorbis PRIMITIVES: analysis/DSP layer ****************************/
282 static int (*qvorbis_analysis_init) (vorbis_dsp_state *v,vorbis_info *vi);
283 static int (*qvorbis_commentheader_out) (vorbis_comment *vc, ogg_packet *op);
284 static int (*qvorbis_analysis_headerout) (vorbis_dsp_state *v,
288 ogg_packet *op_code);
289 static float ** (*qvorbis_analysis_buffer) (vorbis_dsp_state *v,int vals);
290 static int (*qvorbis_analysis_wrote) (vorbis_dsp_state *v,int vals);
291 static int (*qvorbis_analysis_blockout) (vorbis_dsp_state *v,vorbis_block *vb);
292 static int (*qvorbis_analysis) (vorbis_block *vb,ogg_packet *op);
294 static int (*qvorbis_bitrate_addblock) (vorbis_block *vb);
295 static int (*qvorbis_bitrate_flushpacket) (vorbis_dsp_state *vd,
298 // end of vorbis/codec.h stuff
301 static int (*qvorbis_encode_init_vbr) (vorbis_info *vi,
305 float base_quality /* quality level from 0. (lo) to 1. (hi) */
307 // end of vorbisenc.h stuff
311 int y_width; /**< Width of the Y' luminance plane */
312 int y_height; /**< Height of the luminance plane */
313 int y_stride; /**< Offset in bytes between successive rows */
315 int uv_width; /**< Width of the Cb and Cr chroma planes */
316 int uv_height; /**< Height of the chroma planes */
317 int uv_stride; /**< Offset between successive chroma rows */
318 unsigned char *y; /**< Pointer to start of luminance data */
319 unsigned char *u; /**< Pointer to start of Cb data */
320 unsigned char *v; /**< Pointer to start of Cr data */
328 OC_CS_UNSPECIFIED, /**< The colorspace is unknown or unspecified */
329 OC_CS_ITU_REC_470M, /**< This is the best option for 'NTSC' content */
330 OC_CS_ITU_REC_470BG, /**< This is the best option for 'PAL' content */
331 OC_CS_NSPACES /**< This marks the end of the defined colorspaces */
335 * A Chroma subsampling
337 * These enumerate the available chroma subsampling options supported
338 * by the theora format. See Section 4.4 of the specification for
342 OC_PF_420, /**< Chroma subsampling by 2 in each direction (4:2:0) */
343 OC_PF_RSVD, /**< Reserved value */
344 OC_PF_422, /**< Horizonatal chroma subsampling by 2 (4:2:2) */
345 OC_PF_444, /**< No chroma subsampling at all (4:4:4) */
346 } theora_pixelformat;
348 * Theora bitstream info.
349 * Contains the basic playback parameters for a stream,
350 * corresponding to the initial 'info' header packet.
352 * Encoded theora frames must be a multiple of 16 in width and height.
353 * To handle other frame sizes, a crop rectangle is specified in
354 * frame_height and frame_width, offset_x and * offset_y. The offset
355 * and size should still be a multiple of 2 to avoid chroma sampling
356 * shifts. Offset values in this structure are measured from the
357 * upper left of the image.
359 * Frame rate, in frames per second, is stored as a rational
360 * fraction. Aspect ratio is also stored as a rational fraction, and
361 * refers to the aspect ratio of the frame pixels, not of the
362 * overall frame itself.
364 * See <a href="http://svn.xiph.org/trunk/theora/examples/encoder_example.c">
365 * examples/encoder_example.c</a> for usage examples of the
366 * other paramters and good default settings for the encoder parameters.
369 ogg_uint32_t width; /**< encoded frame width */
370 ogg_uint32_t height; /**< encoded frame height */
371 ogg_uint32_t frame_width; /**< display frame width */
372 ogg_uint32_t frame_height; /**< display frame height */
373 ogg_uint32_t offset_x; /**< horizontal offset of the displayed frame */
374 ogg_uint32_t offset_y; /**< vertical offset of the displayed frame */
375 ogg_uint32_t fps_numerator; /**< frame rate numerator **/
376 ogg_uint32_t fps_denominator; /**< frame rate denominator **/
377 ogg_uint32_t aspect_numerator; /**< pixel aspect ratio numerator */
378 ogg_uint32_t aspect_denominator; /**< pixel aspect ratio denominator */
379 theora_colorspace colorspace; /**< colorspace */
380 int target_bitrate; /**< nominal bitrate in bits per second */
381 int quality; /**< Nominal quality setting, 0-63 */
382 int quick_p; /**< Quick encode/decode */
385 unsigned char version_major;
386 unsigned char version_minor;
387 unsigned char version_subminor;
394 ogg_uint32_t keyframe_frequency;
395 ogg_uint32_t keyframe_frequency_force; /* also used for decode init to
396 get granpos shift correct */
397 ogg_uint32_t keyframe_data_target_bitrate;
398 ogg_int32_t keyframe_auto_threshold;
399 ogg_uint32_t keyframe_mindistance;
400 ogg_int32_t noise_sensitivity;
401 ogg_int32_t sharpness;
403 theora_pixelformat pixelformat; /**< chroma subsampling mode to expect */
407 /** Codec internal state and context.
411 ogg_int64_t granulepos;
413 void *internal_encode;
414 void *internal_decode;
419 * Comment header metadata.
421 * This structure holds the in-stream metadata corresponding to
422 * the 'comment' header packet.
424 * Meta data is stored as a series of (tag, value) pairs, in
425 * length-encoded string vectors. The first occurence of the
426 * '=' character delimits the tag and value. A particular tag
427 * may occur more than once. The character set encoding for
428 * the strings is always UTF-8, but the tag names are limited
429 * to case-insensitive ASCII. See the spec for details.
431 * In filling in this structure, qtheora_decode_header() will
432 * null-terminate the user_comment strings for safety. However,
433 * the bitstream format itself treats them as 8-bit clean,
434 * and so the length array should be treated as authoritative
437 typedef struct theora_comment{
438 char **user_comments; /**< An array of comment string vectors */
439 int *comment_lengths; /**< An array of corresponding string vector lengths in bytes */
440 int comments; /**< The total number of comment string vectors */
441 char *vendor; /**< The vendor string identifying the encoder, null terminated */
444 static int (*qtheora_encode_init) (theora_state *th, theora_info *ti);
445 static int (*qtheora_encode_YUVin) (theora_state *t, yuv_buffer *yuv);
446 static int (*qtheora_encode_packetout) ( theora_state *t, int last_p,
448 static int (*qtheora_encode_header) (theora_state *t, ogg_packet *op);
449 static int (*qtheora_encode_comment) (theora_comment *tc, ogg_packet *op);
450 static int (*qtheora_encode_tables) (theora_state *t, ogg_packet *op);
451 static void (*qtheora_info_init) (theora_info *c);
452 static void (*qtheora_info_clear) (theora_info *c);
453 static void (*qtheora_clear) (theora_state *t);
454 static void (*qtheora_comment_init) (theora_comment *tc);
455 static void (*qtheora_comment_clear) (theora_comment *tc);
456 static double (*qtheora_granule_time) (theora_state *th,ogg_int64_t granulepos);
457 // end of theora.h stuff
459 static dllfunction_t oggfuncs[] =
461 {"ogg_stream_packetin", (void **) &qogg_stream_packetin},
462 {"ogg_stream_pageout", (void **) &qogg_stream_pageout},
463 {"ogg_stream_flush", (void **) &qogg_stream_flush},
464 {"ogg_stream_init", (void **) &qogg_stream_init},
465 {"ogg_stream_clear", (void **) &qogg_stream_clear},
466 {"ogg_page_granulepos", (void **) &qogg_page_granulepos},
470 static dllfunction_t vorbisencfuncs[] =
472 {"vorbis_encode_init_vbr", (void **) &qvorbis_encode_init_vbr},
476 static dllfunction_t vorbisfuncs[] =
478 {"vorbis_info_init", (void **) &qvorbis_info_init},
479 {"vorbis_info_clear", (void **) &qvorbis_info_clear},
480 {"vorbis_comment_init", (void **) &qvorbis_comment_init},
481 {"vorbis_comment_clear", (void **) &qvorbis_comment_clear},
482 {"vorbis_block_init", (void **) &qvorbis_block_init},
483 {"vorbis_block_clear", (void **) &qvorbis_block_clear},
484 {"vorbis_dsp_clear", (void **) &qvorbis_dsp_clear},
485 {"vorbis_analysis_init", (void **) &qvorbis_analysis_init},
486 {"vorbis_commentheader_out", (void **) &qvorbis_commentheader_out},
487 {"vorbis_analysis_headerout", (void **) &qvorbis_analysis_headerout},
488 {"vorbis_analysis_buffer", (void **) &qvorbis_analysis_buffer},
489 {"vorbis_analysis_wrote", (void **) &qvorbis_analysis_wrote},
490 {"vorbis_analysis_blockout", (void **) &qvorbis_analysis_blockout},
491 {"vorbis_analysis", (void **) &qvorbis_analysis},
492 {"vorbis_bitrate_addblock", (void **) &qvorbis_bitrate_addblock},
493 {"vorbis_bitrate_flushpacket", (void **) &qvorbis_bitrate_flushpacket},
494 {"vorbis_granule_time", (void **) &qvorbis_granule_time},
498 static dllfunction_t theorafuncs[] =
500 {"theora_info_init", (void **) &qtheora_info_init},
501 {"theora_info_clear", (void **) &qtheora_info_clear},
502 {"theora_comment_init", (void **) &qtheora_comment_init},
503 {"theora_comment_clear", (void **) &qtheora_comment_clear},
504 {"theora_encode_init", (void **) &qtheora_encode_init},
505 {"theora_encode_YUVin", (void **) &qtheora_encode_YUVin},
506 {"theora_encode_packetout", (void **) &qtheora_encode_packetout},
507 {"theora_encode_header", (void **) &qtheora_encode_header},
508 {"theora_encode_comment", (void **) &qtheora_encode_comment},
509 {"theora_encode_tables", (void **) &qtheora_encode_tables},
510 {"theora_clear", (void **) &qtheora_clear},
511 {"theora_granule_time", (void **) &qtheora_granule_time},
515 static dllhandle_t og_dll = NULL, vo_dll = NULL, ve_dll = NULL, th_dll = NULL;
517 qboolean SCR_CaptureVideo_Ogg_OpenLibrary()
519 const char* dllnames_og [] =
526 #elif defined(MACOSX)
534 const char* dllnames_vo [] =
541 #elif defined(MACOSX)
549 const char* dllnames_ve [] =
552 "libvorbisenc64.dll",
556 #elif defined(MACOSX)
557 "libvorbisenc.dylib",
564 const char* dllnames_th [] =
571 #elif defined(MACOSX)
581 Sys_LoadLibrary (dllnames_og, &og_dll, oggfuncs)
583 Sys_LoadLibrary (dllnames_th, &th_dll, theorafuncs)
585 Sys_LoadLibrary (dllnames_vo, &vo_dll, vorbisfuncs)
587 Sys_LoadLibrary (dllnames_ve, &ve_dll, vorbisencfuncs);
590 void SCR_CaptureVideo_Ogg_Init()
592 SCR_CaptureVideo_Ogg_OpenLibrary();
594 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_quality);
595 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_bitrate);
596 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier);
597 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_frequency);
598 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_mindistance);
599 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_auto_threshold);
600 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_noise_sensitivity);
601 Cvar_RegisterVariable(&cl_capturevideo_ogg_vorbis_quality);
604 qboolean SCR_CaptureVideo_Ogg_Available()
606 return og_dll && th_dll && vo_dll && ve_dll;
609 void SCR_CaptureVideo_Ogg_CloseDLL()
611 Sys_UnloadLibrary (&ve_dll);
612 Sys_UnloadLibrary (&vo_dll);
613 Sys_UnloadLibrary (&th_dll);
614 Sys_UnloadLibrary (&og_dll);
617 typedef struct capturevideostate_ogg_formatspecific_s
619 ogg_stream_state to, vo;
620 int serial1, serial2;
631 qboolean have_videopage;
632 qboolean have_audiopage;
634 capturevideostate_ogg_formatspecific_t;
635 #define LOAD_FORMATSPECIFIC_OGG() capturevideostate_ogg_formatspecific_t *format = (capturevideostate_ogg_formatspecific_t *) cls.capturevideo.formatspecific
637 static void SCR_CaptureVideo_Ogg_Interleave()
639 LOAD_FORMATSPECIFIC_OGG();
641 //fprintf(stderr, "<");
643 if(!cls.capturevideo.soundrate)
647 // first: make sure we have a page of both types
648 if(!format->have_videopage)
649 if(qogg_stream_pageout(&format->to, &format->videopage) > 0)
650 format->have_videopage = true;
651 if(format->have_videopage)
653 FS_Write(cls.capturevideo.videofile, format->videopage.header, format->videopage.header_len);
654 FS_Write(cls.capturevideo.videofile, format->videopage.body, format->videopage.body_len);
655 format->have_videopage = false;
663 // first: make sure we have a page of both types
664 if(!format->have_videopage)
665 if(qogg_stream_pageout(&format->to, &format->videopage) > 0)
667 //fprintf(stderr, "V");
668 format->have_videopage = true;
670 // why do I have to do this? the code should work without the
671 // following three lines, which turn this attempt at correct
672 // interleaving back into the old stupid one that oggz-validate
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;
678 if(!format->have_audiopage)
679 if(qogg_stream_pageout(&format->vo, &format->audiopage) > 0)
681 //fprintf(stderr, "A");
682 format->have_audiopage = true;
684 // why do I have to do this? the code should work without the
685 // following three lines, which turn this attempt at correct
686 // interleaving back into the old stupid one that oggz-validate
688 FS_Write(cls.capturevideo.videofile, format->audiopage.header, format->audiopage.header_len);
689 FS_Write(cls.capturevideo.videofile, format->audiopage.body, format->audiopage.body_len);
690 format->have_audiopage = false;
693 if(format->have_videopage && format->have_audiopage)
695 // output the page that ends first
696 double audiotime = qvorbis_granule_time(&format->vd, qogg_page_granulepos(&format->audiopage));
697 double videotime = qtheora_granule_time(&format->ts, qogg_page_granulepos(&format->videopage));
698 if(audiotime < videotime)
700 FS_Write(cls.capturevideo.videofile, format->audiopage.header, format->audiopage.header_len);
701 FS_Write(cls.capturevideo.videofile, format->audiopage.body, format->audiopage.body_len);
702 format->have_audiopage = false;
704 //fprintf(stderr, "a");
708 FS_Write(cls.capturevideo.videofile, format->videopage.header, format->videopage.header_len);
709 FS_Write(cls.capturevideo.videofile, format->videopage.body, format->videopage.body_len);
710 format->have_videopage = false;
712 //fprintf(stderr, "v");
719 //fprintf(stderr, ">");
722 static void SCR_CaptureVideo_Ogg_FlushInterleaving()
724 LOAD_FORMATSPECIFIC_OGG();
726 if(cls.capturevideo.soundrate)
727 if(format->have_audiopage)
729 FS_Write(cls.capturevideo.videofile, format->audiopage.header, format->audiopage.header_len);
730 FS_Write(cls.capturevideo.videofile, format->audiopage.body, format->audiopage.body_len);
731 format->have_audiopage = false;
734 if(format->have_videopage)
736 FS_Write(cls.capturevideo.videofile, format->videopage.header, format->videopage.header_len);
737 FS_Write(cls.capturevideo.videofile, format->videopage.body, format->videopage.body_len);
738 format->have_videopage = false;
742 static void SCR_CaptureVideo_Ogg_EndVideo()
744 LOAD_FORMATSPECIFIC_OGG();
748 // repeat the last frame so we can set the end-of-stream flag
749 qtheora_encode_YUVin(&format->ts, &format->yuv);
750 qtheora_encode_packetout(&format->ts, true, &pt);
751 qogg_stream_packetin(&format->to, &pt);
752 SCR_CaptureVideo_Ogg_Interleave();
754 if(cls.capturevideo.soundrate)
756 qvorbis_analysis_wrote(&format->vd, 0);
757 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
759 qvorbis_analysis(&format->vb, NULL);
760 qvorbis_bitrate_addblock(&format->vb);
761 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
762 qogg_stream_packetin(&format->vo, &pt);
763 SCR_CaptureVideo_Ogg_Interleave();
767 SCR_CaptureVideo_Ogg_FlushInterleaving();
769 while(qogg_stream_pageout(&format->to, &pg) > 0)
771 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
772 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
775 if(cls.capturevideo.soundrate)
777 while(qogg_stream_pageout(&format->vo, &pg) > 0)
779 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
780 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
785 int result = qogg_stream_flush (&format->to, &pg);
787 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
790 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
791 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
794 if(cls.capturevideo.soundrate)
797 int result = qogg_stream_flush (&format->vo, &pg);
799 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
802 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
803 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
806 qogg_stream_clear(&format->vo);
807 qvorbis_block_clear(&format->vb);
808 qvorbis_dsp_clear(&format->vd);
811 qogg_stream_clear(&format->to);
812 qtheora_clear(&format->ts);
813 qvorbis_info_clear(&format->vi);
815 Mem_Free(format->yuv.y);
816 Mem_Free(format->yuv.u);
817 Mem_Free(format->yuv.v);
820 FS_Close(cls.capturevideo.videofile);
821 cls.capturevideo.videofile = NULL;
824 static void SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV()
826 LOAD_FORMATSPECIFIC_OGG();
828 int blockr, blockg, blockb;
829 unsigned char *b = cls.capturevideo.outbuffer;
830 int w = cls.capturevideo.width;
831 int h = cls.capturevideo.height;
834 for(y = 0; y < h; ++y)
836 for(b = cls.capturevideo.outbuffer + (h-1-y)*w*4, x = 0; x < w; ++x)
841 format->yuv.y[x + format->yuv.y_stride * y] =
842 cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]];
848 for(b = cls.capturevideo.outbuffer + (h-2-y)*w*4, x = 0; x < w/2; ++x)
850 blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2;
851 blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2;
852 blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2;
853 format->yuv.u[x + format->yuv.uv_stride * (y/2)] =
854 cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128];
855 format->yuv.v[x + format->yuv.uv_stride * (y/2)] =
856 cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128];
863 static void SCR_CaptureVideo_Ogg_VideoFrames(int num)
865 LOAD_FORMATSPECIFIC_OGG();
868 // data is in cls.capturevideo.outbuffer as BGRA and has size width*height
870 SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV();
874 qtheora_encode_YUVin(&format->ts, &format->yuv);
876 while(qtheora_encode_packetout(&format->ts, false, &pt))
877 qogg_stream_packetin(&format->to, &pt);
879 SCR_CaptureVideo_Ogg_Interleave();
883 static void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
885 LOAD_FORMATSPECIFIC_OGG();
886 float **vorbis_buffer;
891 vorbis_buffer = qvorbis_analysis_buffer(&format->vd, length);
892 for(i = 0; i < length; ++i)
894 for(j = 0; j < cls.capturevideo.soundchannels; ++j)
895 vorbis_buffer[j][i] = paintbuffer[i].sample[j] / 32768.0f;
897 qvorbis_analysis_wrote(&format->vd, length);
899 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
901 qvorbis_analysis(&format->vb, NULL);
902 qvorbis_bitrate_addblock(&format->vb);
904 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
905 qogg_stream_packetin(&format->vo, &pt);
908 SCR_CaptureVideo_Ogg_Interleave();
911 void SCR_CaptureVideo_Ogg_BeginVideo()
913 cls.capturevideo.format = CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA;
914 cls.capturevideo.videofile = FS_OpenRealFile(va("%s.ogv", cls.capturevideo.basename), "wb", false);
915 cls.capturevideo.endvideo = SCR_CaptureVideo_Ogg_EndVideo;
916 cls.capturevideo.videoframes = SCR_CaptureVideo_Ogg_VideoFrames;
917 cls.capturevideo.soundframe = SCR_CaptureVideo_Ogg_SoundFrame;
918 cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_ogg_formatspecific_t));
920 LOAD_FORMATSPECIFIC_OGG();
923 ogg_packet pt, pt2, pt3;
928 format->serial1 = rand();
929 qogg_stream_init(&format->to, format->serial1);
931 if(cls.capturevideo.soundrate)
935 format->serial2 = rand();
937 while(format->serial1 == format->serial2);
938 qogg_stream_init(&format->vo, format->serial2);
941 format->have_videopage = format->have_audiopage = false;
943 qtheora_info_init(&ti);
944 ti.frame_width = cls.capturevideo.width;
945 ti.frame_height = cls.capturevideo.height;
946 ti.width = (ti.frame_width + 15) & ~15;
947 ti.height = (ti.frame_height + 15) & ~15;
948 //ti.offset_x = ((ti.width - ti.frame_width) / 2) & ~1;
949 //ti.offset_y = ((ti.height - ti.frame_height) / 2) & ~1;
951 format->yuv.y_width = ti.width;
952 format->yuv.y_height = ti.height;
953 format->yuv.y_stride = ti.width;
955 format->yuv.uv_width = ti.width / 2;
956 format->yuv.uv_height = ti.height / 2;
957 format->yuv.uv_stride = ti.width / 2;
959 format->yuv.y = Mem_Alloc(tempmempool, format->yuv.y_stride * format->yuv.y_height);
960 format->yuv.u = Mem_Alloc(tempmempool, format->yuv.uv_stride * format->yuv.uv_height);
961 format->yuv.v = Mem_Alloc(tempmempool, format->yuv.uv_stride * format->yuv.uv_height);
963 FindFraction(cls.capturevideo.framerate, &num, &denom, 1001);
964 ti.fps_numerator = num;
965 ti.fps_denominator = denom;
967 FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000);
968 ti.aspect_numerator = num;
969 ti.aspect_denominator = denom;
971 ti.colorspace = OC_CS_UNSPECIFIED;
972 ti.pixelformat = OC_PF_420;
974 ti.quick_p = true; // http://mlblog.osdir.com/multimedia.ogg.theora.general/2004-07/index.shtml
975 ti.dropframes_p = false;
977 ti.target_bitrate = cl_capturevideo_ogg_theora_bitrate.integer * 1000;
978 ti.quality = cl_capturevideo_ogg_theora_quality.integer;
980 if(ti.target_bitrate <= 0)
984 ti.target_bitrate = -1;
985 ti.keyframe_data_target_bitrate = -1;
990 ti.target_bitrate = -1;
991 ti.keyframe_data_target_bitrate = -1;
992 ti.quality = bound(0, ti.quality, 63);
999 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
1000 ti.keyframe_data_target_bitrate = ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value);
1005 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
1006 ti.keyframe_data_target_bitrate = ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value);
1011 ti.keyframe_frequency = bound(1, cl_capturevideo_ogg_theora_keyframe_frequency.integer, 1000);
1012 ti.keyframe_mindistance = bound(1, cl_capturevideo_ogg_theora_keyframe_mindistance.integer, (int) ti.keyframe_frequency);
1013 ti.noise_sensitivity = bound(0, cl_capturevideo_ogg_theora_noise_sensitivity.integer, 6);
1014 ti.sharpness = bound(0, cl_capturevideo_ogg_theora_sharpness.integer, 2);
1015 ti.keyframe_auto_threshold = bound(0, cl_capturevideo_ogg_theora_keyframe_auto_threshold.integer, 100);
1017 ti.keyframe_frequency_force = ti.keyframe_frequency;
1018 ti.keyframe_auto_p = (ti.keyframe_frequency != ti.keyframe_mindistance);
1020 qtheora_encode_init(&format->ts, &ti);
1021 qtheora_info_clear(&ti);
1024 if(cls.capturevideo.soundrate)
1026 qvorbis_info_init(&format->vi);
1027 qvorbis_encode_init_vbr(&format->vi, cls.capturevideo.soundchannels, cls.capturevideo.soundrate, bound(-1, cl_capturevideo_ogg_vorbis_quality.value, 10) * 0.099);
1028 qvorbis_comment_init(&vc);
1029 qvorbis_analysis_init(&format->vd, &format->vi);
1030 qvorbis_block_init(&format->vd, &format->vb);
1033 qtheora_comment_init(&tc);
1035 /* create the remaining theora headers */
1036 qtheora_encode_header(&format->ts, &pt);
1037 qogg_stream_packetin(&format->to, &pt);
1038 if (qogg_stream_pageout (&format->to, &pg) != 1)
1039 fprintf (stderr, "Internal Ogg library error.\n");
1040 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1041 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1043 qtheora_encode_comment(&tc, &pt);
1044 qogg_stream_packetin(&format->to, &pt);
1045 qtheora_encode_tables(&format->ts, &pt);
1046 qogg_stream_packetin (&format->to, &pt);
1048 qtheora_comment_clear(&tc);
1050 if(cls.capturevideo.soundrate)
1052 qvorbis_analysis_headerout(&format->vd, &vc, &pt, &pt2, &pt3);
1053 qogg_stream_packetin(&format->vo, &pt);
1054 if (qogg_stream_pageout (&format->vo, &pg) != 1)
1055 fprintf (stderr, "Internal Ogg library error.\n");
1056 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1057 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1059 qogg_stream_packetin(&format->vo, &pt2);
1060 qogg_stream_packetin(&format->vo, &pt3);
1062 qvorbis_comment_clear(&vc);
1067 int result = qogg_stream_flush (&format->to, &pg);
1069 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
1072 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1073 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1076 if(cls.capturevideo.soundrate)
1079 int result = qogg_stream_flush (&format->vo, &pg);
1081 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
1084 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1085 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);