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 u_int16_t ogg_uint16_t;
28 typedef int32_t ogg_int32_t;
29 typedef u_int32_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, ">");
723 static void SCR_CaptureVideo_Ogg_FlushInterleaving()
725 LOAD_FORMATSPECIFIC_OGG();
727 if(cls.capturevideo.soundrate)
728 if(format->have_audiopage)
730 FS_Write(cls.capturevideo.videofile, format->audiopage.header, format->audiopage.header_len);
731 FS_Write(cls.capturevideo.videofile, format->audiopage.body, format->audiopage.body_len);
732 format->have_audiopage = false;
735 if(format->have_videopage)
737 FS_Write(cls.capturevideo.videofile, format->videopage.header, format->videopage.header_len);
738 FS_Write(cls.capturevideo.videofile, format->videopage.body, format->videopage.body_len);
739 format->have_videopage = false;
743 static void SCR_CaptureVideo_Ogg_EndVideo()
745 LOAD_FORMATSPECIFIC_OGG();
749 // repeat the last frame so we can set the end-of-stream flag
750 qtheora_encode_YUVin(&format->ts, &format->yuv);
751 qtheora_encode_packetout(&format->ts, true, &pt);
752 qogg_stream_packetin(&format->to, &pt);
753 SCR_CaptureVideo_Ogg_Interleave();
755 if(cls.capturevideo.soundrate)
757 qvorbis_analysis_wrote(&format->vd, 0);
758 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
760 qvorbis_analysis(&format->vb, NULL);
761 qvorbis_bitrate_addblock(&format->vb);
762 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
763 qogg_stream_packetin(&format->vo, &pt);
764 SCR_CaptureVideo_Ogg_Interleave();
768 SCR_CaptureVideo_Ogg_FlushInterleaving();
770 while(qogg_stream_pageout(&format->to, &pg) > 0)
772 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
773 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
776 if(cls.capturevideo.soundrate)
778 while(qogg_stream_pageout(&format->vo, &pg) > 0)
780 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
781 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
786 int result = qogg_stream_flush (&format->to, &pg);
788 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
791 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
792 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
795 if(cls.capturevideo.soundrate)
798 int result = qogg_stream_flush (&format->vo, &pg);
800 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
803 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
804 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
807 qogg_stream_clear(&format->vo);
808 qvorbis_block_clear(&format->vb);
809 qvorbis_dsp_clear(&format->vd);
812 qogg_stream_clear(&format->to);
813 qtheora_clear(&format->ts);
814 qvorbis_info_clear(&format->vi);
816 Mem_Free(format->yuv.y);
817 Mem_Free(format->yuv.u);
818 Mem_Free(format->yuv.v);
821 FS_Close(cls.capturevideo.videofile);
822 cls.capturevideo.videofile = NULL;
825 static void SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV()
827 LOAD_FORMATSPECIFIC_OGG();
829 int blockr, blockg, blockb;
830 unsigned char *b = cls.capturevideo.outbuffer;
831 int w = cls.capturevideo.width;
832 int h = cls.capturevideo.height;
835 for(y = 0; y < h; ++y)
837 for(b = cls.capturevideo.outbuffer + (h-1-y)*w*4, x = 0; x < w; ++x)
842 format->yuv.y[x + format->yuv.y_stride * y] =
843 cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]];
849 for(b = cls.capturevideo.outbuffer + (h-2-y)*w*4, x = 0; x < w/2; ++x)
851 blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2;
852 blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2;
853 blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2;
854 format->yuv.u[x + format->yuv.uv_stride * (y/2)] =
855 cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128];
856 format->yuv.v[x + format->yuv.uv_stride * (y/2)] =
857 cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128];
864 static void SCR_CaptureVideo_Ogg_VideoFrames(int num)
866 LOAD_FORMATSPECIFIC_OGG();
869 // data is in cls.capturevideo.outbuffer as BGRA and has size width*height
871 SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV();
875 qtheora_encode_YUVin(&format->ts, &format->yuv);
877 while(qtheora_encode_packetout(&format->ts, false, &pt))
878 qogg_stream_packetin(&format->to, &pt);
880 SCR_CaptureVideo_Ogg_Interleave();
884 static void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
886 LOAD_FORMATSPECIFIC_OGG();
887 float **vorbis_buffer;
892 vorbis_buffer = qvorbis_analysis_buffer(&format->vd, length);
893 for(i = 0; i < length; ++i)
895 for(j = 0; j < cls.capturevideo.soundchannels; ++j)
896 vorbis_buffer[j][i] = paintbuffer[i].sample[j] / 32768.0f;
898 qvorbis_analysis_wrote(&format->vd, length);
900 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
902 qvorbis_analysis(&format->vb, NULL);
903 qvorbis_bitrate_addblock(&format->vb);
905 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
906 qogg_stream_packetin(&format->vo, &pt);
909 SCR_CaptureVideo_Ogg_Interleave();
912 void SCR_CaptureVideo_Ogg_BeginVideo()
914 cls.capturevideo.format = CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA;
915 cls.capturevideo.videofile = FS_OpenRealFile(va("%s.ogv", cls.capturevideo.basename), "wb", false);
916 cls.capturevideo.endvideo = SCR_CaptureVideo_Ogg_EndVideo;
917 cls.capturevideo.videoframes = SCR_CaptureVideo_Ogg_VideoFrames;
918 cls.capturevideo.soundframe = SCR_CaptureVideo_Ogg_SoundFrame;
919 cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_ogg_formatspecific_t));
921 LOAD_FORMATSPECIFIC_OGG();
924 ogg_packet pt, pt2, pt3;
929 format->serial1 = rand();
930 qogg_stream_init(&format->to, format->serial1);
932 if(cls.capturevideo.soundrate)
936 format->serial2 = rand();
938 while(format->serial1 == format->serial2);
939 qogg_stream_init(&format->vo, format->serial2);
942 format->have_videopage = format->have_audiopage = false;
944 qtheora_info_init(&ti);
945 ti.frame_width = cls.capturevideo.width;
946 ti.frame_height = cls.capturevideo.height;
947 ti.width = (ti.frame_width + 15) & ~15;
948 ti.height = (ti.frame_height + 15) & ~15;
949 //ti.offset_x = ((ti.width - ti.frame_width) / 2) & ~1;
950 //ti.offset_y = ((ti.height - ti.frame_height) / 2) & ~1;
952 format->yuv.y_width = ti.width;
953 format->yuv.y_height = ti.height;
954 format->yuv.y_stride = ti.width;
956 format->yuv.uv_width = ti.width / 2;
957 format->yuv.uv_height = ti.height / 2;
958 format->yuv.uv_stride = ti.width / 2;
960 format->yuv.y = Mem_Alloc(tempmempool, format->yuv.y_stride * format->yuv.y_height);
961 format->yuv.u = Mem_Alloc(tempmempool, format->yuv.uv_stride * format->yuv.uv_height);
962 format->yuv.v = Mem_Alloc(tempmempool, format->yuv.uv_stride * format->yuv.uv_height);
964 FindFraction(cls.capturevideo.framerate, &num, &denom, 1001);
965 ti.fps_numerator = num;
966 ti.fps_denominator = denom;
968 FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000);
969 ti.aspect_numerator = num;
970 ti.aspect_denominator = denom;
972 ti.colorspace = OC_CS_UNSPECIFIED;
973 ti.pixelformat = OC_PF_420;
975 ti.quick_p = true; // http://mlblog.osdir.com/multimedia.ogg.theora.general/2004-07/index.shtml
976 ti.dropframes_p = false;
978 ti.target_bitrate = cl_capturevideo_ogg_theora_bitrate.integer * 1000;
979 ti.quality = cl_capturevideo_ogg_theora_quality.integer;
981 if(ti.target_bitrate <= 0)
985 ti.target_bitrate = -1;
986 ti.keyframe_data_target_bitrate = -1;
991 ti.target_bitrate = -1;
992 ti.keyframe_data_target_bitrate = -1;
993 ti.quality = bound(0, ti.quality, 63);
1000 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
1001 ti.keyframe_data_target_bitrate = ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value);
1006 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
1007 ti.keyframe_data_target_bitrate = ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value);
1012 ti.keyframe_frequency = bound(1, cl_capturevideo_ogg_theora_keyframe_frequency.integer, 1000);
1013 ti.keyframe_mindistance = bound(1, cl_capturevideo_ogg_theora_keyframe_mindistance.integer, (int) ti.keyframe_frequency);
1014 ti.noise_sensitivity = bound(0, cl_capturevideo_ogg_theora_noise_sensitivity.integer, 6);
1015 ti.sharpness = bound(0, cl_capturevideo_ogg_theora_sharpness.integer, 2);
1016 ti.keyframe_auto_threshold = bound(0, cl_capturevideo_ogg_theora_keyframe_auto_threshold.integer, 100);
1018 ti.keyframe_frequency_force = ti.keyframe_frequency;
1019 ti.keyframe_auto_p = (ti.keyframe_frequency != ti.keyframe_mindistance);
1021 qtheora_encode_init(&format->ts, &ti);
1022 qtheora_info_clear(&ti);
1025 if(cls.capturevideo.soundrate)
1027 qvorbis_info_init(&format->vi);
1028 qvorbis_encode_init_vbr(&format->vi, cls.capturevideo.soundchannels, cls.capturevideo.soundrate, bound(-1, cl_capturevideo_ogg_vorbis_quality.value, 10) * 0.099);
1029 qvorbis_comment_init(&vc);
1030 qvorbis_analysis_init(&format->vd, &format->vi);
1031 qvorbis_block_init(&format->vd, &format->vb);
1034 qtheora_comment_init(&tc);
1036 /* create the remaining theora headers */
1037 qtheora_encode_header(&format->ts, &pt);
1038 qogg_stream_packetin(&format->to, &pt);
1039 if (qogg_stream_pageout (&format->to, &pg) != 1)
1040 fprintf (stderr, "Internal Ogg library error.\n");
1041 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1042 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1044 qtheora_encode_comment(&tc, &pt);
1045 qogg_stream_packetin(&format->to, &pt);
1046 qtheora_encode_tables(&format->ts, &pt);
1047 qogg_stream_packetin (&format->to, &pt);
1049 qtheora_comment_clear(&tc);
1051 if(cls.capturevideo.soundrate)
1053 qvorbis_analysis_headerout(&format->vd, &vc, &pt, &pt2, &pt3);
1054 qogg_stream_packetin(&format->vo, &pt);
1055 if (qogg_stream_pageout (&format->vo, &pg) != 1)
1056 fprintf (stderr, "Internal Ogg library error.\n");
1057 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1058 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1060 qogg_stream_packetin(&format->vo, &pt2);
1061 qogg_stream_packetin(&format->vo, &pt3);
1063 qvorbis_comment_clear(&vc);
1068 int result = qogg_stream_flush (&format->to, &pg);
1070 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
1073 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1074 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1077 if(cls.capturevideo.soundrate)
1080 int result = qogg_stream_flush (&format->vo, &pg);
1082 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
1085 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1086 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);