8 static cvar_t cl_capturevideo_ogg_theora_vp3compat = {CF_CLIENT | CF_ARCHIVE, "cl_capturevideo_ogg_theora_vp3compat", "1", "make VP3 compatible theora streams"};
9 static cvar_t cl_capturevideo_ogg_theora_quality = {CF_CLIENT | CF_ARCHIVE, "cl_capturevideo_ogg_theora_quality", "48", "video quality factor (0 to 63), or -1 to use bitrate only; higher is better; setting both to -1 achieves unlimited quality"};
10 static cvar_t cl_capturevideo_ogg_theora_bitrate = {CF_CLIENT | CF_ARCHIVE, "cl_capturevideo_ogg_theora_bitrate", "-1", "video bitrate (45 to 2000 kbps), or -1 to use quality only; higher is better; setting both to -1 achieves unlimited quality"};
11 static cvar_t cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier = {CF_CLIENT | CF_ARCHIVE, "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"};
12 static cvar_t cl_capturevideo_ogg_theora_keyframe_maxinterval = {CF_CLIENT | CF_ARCHIVE, "cl_capturevideo_ogg_theora_keyframe_maxinterval", "64", "maximum keyframe interval (1 to 1000)"};
13 static cvar_t cl_capturevideo_ogg_theora_keyframe_mininterval = {CF_CLIENT | CF_ARCHIVE, "cl_capturevideo_ogg_theora_keyframe_mininterval", "8", "minimum keyframe interval (1 to 1000)"};
14 static cvar_t cl_capturevideo_ogg_theora_keyframe_auto_threshold = {CF_CLIENT | CF_ARCHIVE, "cl_capturevideo_ogg_theora_keyframe_auto_threshold", "80", "threshold for key frame decision (0 to 100)"};
15 static cvar_t cl_capturevideo_ogg_theora_noise_sensitivity = {CF_CLIENT | CF_ARCHIVE, "cl_capturevideo_ogg_theora_noise_sensitivity", "1", "video noise sensitivity (0 to 6); lower is better"};
16 static cvar_t cl_capturevideo_ogg_theora_sharpness = {CF_CLIENT | CF_ARCHIVE, "cl_capturevideo_ogg_theora_sharpness", "0", "sharpness (0 to 2); lower is sharper"};
17 static cvar_t cl_capturevideo_ogg_vorbis_quality = {CF_CLIENT | CF_ARCHIVE, "cl_capturevideo_ogg_vorbis_quality", "3", "audio quality (-1 to 10); higher is better"};
20 typedef int16_t ogg_int16_t;
21 typedef uint16_t ogg_uint16_t;
22 typedef int32_t ogg_int32_t;
23 typedef uint32_t ogg_uint32_t;
24 typedef int64_t ogg_int64_t;
30 unsigned char *buffer;
35 /* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
38 unsigned char *header;
44 /* ogg_stream_state contains the current encode/decode state of a logical
45 Ogg bitstream **********************************************************/
48 unsigned char *body_data; /* bytes from packet bodies */
49 long body_storage; /* storage elements allocated */
50 long body_fill; /* elements stored; fill mark */
51 long body_returned; /* elements of fill returned */
54 int *lacing_vals; /* The values that will go to the segment table */
55 ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
56 this way, but it is simple coupled to the
63 unsigned char header[282]; /* working space for header encode */
66 int e_o_s; /* set when we have buffered the last packet in the
68 int b_o_s; /* set after we've written the initial page
69 of a logical bitstream */
72 ogg_int64_t packetno; /* sequence number for decode; the framing
73 knows where there's a hole in the data,
74 but we need coupling so that the codec
75 (which is in a seperate abstraction
76 layer) also knows about the gap */
77 ogg_int64_t granulepos;
81 /* ogg_packet is used to encapsulate the data and metadata belonging
82 to a single raw Ogg/Vorbis packet *************************************/
85 unsigned char *packet;
90 ogg_int64_t granulepos;
92 ogg_int64_t packetno; /* sequence number for decode; the framing
93 knows where there's a hole in the data,
94 but we need coupling so that the codec
95 (which is in a seperate abstraction
96 layer) also knows about the gap */
110 /* Ogg BITSTREAM PRIMITIVES: encoding **************************/
112 static int (*qogg_stream_packetin) (ogg_stream_state *os, ogg_packet *op);
113 static int (*qogg_stream_pageout) (ogg_stream_state *os, ogg_page *og);
114 static int (*qogg_stream_flush) (ogg_stream_state *os, ogg_page *og);
116 /* Ogg BITSTREAM PRIMITIVES: general ***************************/
118 static int (*qogg_stream_init) (ogg_stream_state *os,int serialno);
119 static int (*qogg_stream_clear) (ogg_stream_state *os);
120 static ogg_int64_t (*qogg_page_granulepos) (ogg_page *og);
122 // end of ogg.h stuff
124 // vorbis/codec.h stuff
125 typedef struct vorbis_info{
130 /* The below bitrate declarations are *hints*.
131 Combinations of the three values carry the following implications:
133 all three set to the same value:
134 implies a fixed rate bitstream
136 implies a VBR stream that averages the nominal bitrate. No hard
138 upper and or lower set:
139 implies a VBR bitstream that obeys the bitrate limits. nominal
140 may also be set to give a nominal rate.
142 the coder does not care to speculate.
146 long bitrate_nominal;
153 /* vorbis_dsp_state buffers the current vorbis audio
154 analysis/synthesis state. The DSP state belongs to a specific
155 logical bitstream ****************************************************/
156 typedef struct vorbis_dsp_state{
174 ogg_int64_t granulepos;
175 ogg_int64_t sequence;
177 ogg_int64_t glue_bits;
178 ogg_int64_t time_bits;
179 ogg_int64_t floor_bits;
180 ogg_int64_t res_bits;
185 typedef struct vorbis_block{
186 /* necessary stream state for linking to the framing abstraction */
187 float **pcm; /* this is a pointer into local storage */
197 ogg_int64_t granulepos;
198 ogg_int64_t sequence;
199 vorbis_dsp_state *vd; /* For read-only access of configuration */
201 /* local storage to avoid remallocing; it's up to the mapping to
207 struct alloc_chain *reap;
209 /* bitmetrics for the frame */
219 /* vorbis_block is a single block of data to be processed as part of
220 the analysis/synthesis stream; it belongs to a specific logical
221 bitstream, but is independant from other vorbis_blocks belonging to
222 that logical bitstream. *************************************************/
226 struct alloc_chain *next;
229 /* vorbis_info contains all the setup information specific to the
230 specific compression/decompression mode in progress (eg,
231 psychoacoustic settings, channel setup, options, codebook
232 etc). vorbis_info and substructures are in backends.h.
233 *********************************************************************/
235 /* the comments are not part of vorbis_info so that vorbis_info can be
237 typedef struct vorbis_comment{
238 /* unlimited user comment fields. libvorbis writes 'libvorbis'
239 whatever vendor is set to in encode */
240 char **user_comments;
241 int *comment_lengths;
248 /* libvorbis encodes in two abstraction layers; first we perform DSP
249 and produce a packet (see docs/analysis.txt). The packet is then
250 coded into a framed OggSquish bitstream by the second layer (see
251 docs/framing.txt). Decode is the reverse process; we sync/frame
252 the bitstream and extract individual packets, then decode the
253 packet back into PCM audio.
255 The extra framing/packetizing is used in streaming formats, such as
256 files. Over the net (such as with UDP), the framing and
257 packetization aren't necessary as they're provided by the transport
258 and the streaming layer is not used */
260 /* Vorbis PRIMITIVES: general ***************************************/
262 static void (*qvorbis_info_init) (vorbis_info *vi);
263 static void (*qvorbis_info_clear) (vorbis_info *vi);
264 static void (*qvorbis_comment_init) (vorbis_comment *vc);
265 static void (*qvorbis_comment_clear) (vorbis_comment *vc);
267 static int (*qvorbis_block_init) (vorbis_dsp_state *v, vorbis_block *vb);
268 static int (*qvorbis_block_clear) (vorbis_block *vb);
269 static void (*qvorbis_dsp_clear) (vorbis_dsp_state *v);
270 static double (*qvorbis_granule_time) (vorbis_dsp_state *v,
271 ogg_int64_t granulepos);
273 /* Vorbis PRIMITIVES: analysis/DSP layer ****************************/
275 static int (*qvorbis_analysis_init) (vorbis_dsp_state *v,vorbis_info *vi);
276 static int (*qvorbis_commentheader_out) (vorbis_comment *vc, ogg_packet *op);
277 static int (*qvorbis_analysis_headerout) (vorbis_dsp_state *v,
281 ogg_packet *op_code);
282 static float ** (*qvorbis_analysis_buffer) (vorbis_dsp_state *v,int vals);
283 static int (*qvorbis_analysis_wrote) (vorbis_dsp_state *v,int vals);
284 static int (*qvorbis_analysis_blockout) (vorbis_dsp_state *v,vorbis_block *vb);
285 static int (*qvorbis_analysis) (vorbis_block *vb,ogg_packet *op);
287 static int (*qvorbis_bitrate_addblock) (vorbis_block *vb);
288 static int (*qvorbis_bitrate_flushpacket) (vorbis_dsp_state *vd,
291 // end of vorbis/codec.h stuff
294 static int (*qvorbis_encode_init_vbr) (vorbis_info *vi,
298 float base_quality /* quality level from 0. (lo) to 1. (hi) */
300 // end of vorbisenc.h stuff
304 #define TH_ENCCTL_SET_VP3_COMPATIBLE (10)
307 int y_width; /**< Width of the Y' luminance plane */
308 int y_height; /**< Height of the luminance plane */
309 int y_stride; /**< Offset in bytes between successive rows */
311 int uv_width; /**< Width of the Cb and Cr chroma planes */
312 int uv_height; /**< Height of the chroma planes */
313 int uv_stride; /**< Offset between successive chroma rows */
314 unsigned char *y; /**< Pointer to start of luminance data */
315 unsigned char *u; /**< Pointer to start of Cb data */
316 unsigned char *v; /**< Pointer to start of Cr data */
324 OC_CS_UNSPECIFIED, /**< The colorspace is unknown or unspecified */
325 OC_CS_ITU_REC_470M, /**< This is the best option for 'NTSC' content */
326 OC_CS_ITU_REC_470BG, /**< This is the best option for 'PAL' content */
327 OC_CS_NSPACES /**< This marks the end of the defined colorspaces */
331 * A Chroma subsampling
333 * These enumerate the available chroma subsampling options supported
334 * by the theora format. See Section 4.4 of the specification for
338 OC_PF_420, /**< Chroma subsampling by 2 in each direction (4:2:0) */
339 OC_PF_RSVD, /**< Reserved value */
340 OC_PF_422, /**< Horizonatal chroma subsampling by 2 (4:2:2) */
341 OC_PF_444 /**< No chroma subsampling at all (4:4:4) */
342 } theora_pixelformat;
344 * Theora bitstream info.
345 * Contains the basic playback parameters for a stream,
346 * corresponding to the initial 'info' header packet.
348 * Encoded theora frames must be a multiple of 16 in width and height.
349 * To handle other frame sizes, a crop rectangle is specified in
350 * frame_height and frame_width, offset_x and * offset_y. The offset
351 * and size should still be a multiple of 2 to avoid chroma sampling
352 * shifts. Offset values in this structure are measured from the
353 * upper left of the image.
355 * Frame rate, in frames per second, is stored as a rational
356 * fraction. Aspect ratio is also stored as a rational fraction, and
357 * refers to the aspect ratio of the frame pixels, not of the
358 * overall frame itself.
360 * See <a href="http://svn.xiph.org/trunk/theora/examples/encoder_example.c">
361 * examples/encoder_example.c</a> for usage examples of the
362 * other paramters and good default settings for the encoder parameters.
365 ogg_uint32_t width; /**< encoded frame width */
366 ogg_uint32_t height; /**< encoded frame height */
367 ogg_uint32_t frame_width; /**< display frame width */
368 ogg_uint32_t frame_height; /**< display frame height */
369 ogg_uint32_t offset_x; /**< horizontal offset of the displayed frame */
370 ogg_uint32_t offset_y; /**< vertical offset of the displayed frame */
371 ogg_uint32_t fps_numerator; /**< frame rate numerator **/
372 ogg_uint32_t fps_denominator; /**< frame rate denominator **/
373 ogg_uint32_t aspect_numerator; /**< pixel aspect ratio numerator */
374 ogg_uint32_t aspect_denominator; /**< pixel aspect ratio denominator */
375 theora_colorspace colorspace; /**< colorspace */
376 int target_bitrate; /**< nominal bitrate in bits per second */
377 int quality; /**< Nominal quality setting, 0-63 */
378 int quick_p; /**< Quick encode/decode */
381 unsigned char version_major;
382 unsigned char version_minor;
383 unsigned char version_subminor;
390 ogg_uint32_t keyframe_frequency;
391 ogg_uint32_t keyframe_frequency_force; /* also used for decode init to
392 get granpos shift correct */
393 ogg_uint32_t keyframe_data_target_bitrate;
394 ogg_int32_t keyframe_auto_threshold;
395 ogg_uint32_t keyframe_mindistance;
396 ogg_int32_t noise_sensitivity;
397 ogg_int32_t sharpness;
399 theora_pixelformat pixelformat; /**< chroma subsampling mode to expect */
403 /** Codec internal state and context.
407 ogg_int64_t granulepos;
409 void *internal_encode;
410 void *internal_decode;
415 * Comment header metadata.
417 * This structure holds the in-stream metadata corresponding to
418 * the 'comment' header packet.
420 * Meta data is stored as a series of (tag, value) pairs, in
421 * length-encoded string vectors. The first occurence of the
422 * '=' character delimits the tag and value. A particular tag
423 * may occur more than once. The character set encoding for
424 * the strings is always UTF-8, but the tag names are limited
425 * to case-insensitive ASCII. See the spec for details.
427 * In filling in this structure, qtheora_decode_header() will
428 * null-terminate the user_comment strings for safety. However,
429 * the bitstream format itself treats them as 8-bit clean,
430 * and so the length array should be treated as authoritative
433 typedef struct theora_comment{
434 char **user_comments; /**< An array of comment string vectors */
435 int *comment_lengths; /**< An array of corresponding string vector lengths in bytes */
436 int comments; /**< The total number of comment string vectors */
437 char *vendor; /**< The vendor string identifying the encoder, null terminated */
440 static int (*qtheora_encode_init) (theora_state *th, theora_info *ti);
441 static int (*qtheora_encode_YUVin) (theora_state *t, yuv_buffer *yuv);
442 static int (*qtheora_encode_packetout) ( theora_state *t, int last_p,
444 static int (*qtheora_encode_header) (theora_state *t, ogg_packet *op);
445 static int (*qtheora_encode_comment) (theora_comment *tc, ogg_packet *op);
446 static int (*qtheora_encode_tables) (theora_state *t, ogg_packet *op);
447 static void (*qtheora_info_init) (theora_info *c);
448 static void (*qtheora_info_clear) (theora_info *c);
449 static void (*qtheora_clear) (theora_state *t);
450 static void (*qtheora_comment_init) (theora_comment *tc);
451 static void (*qtheora_comment_clear) (theora_comment *tc);
452 static double (*qtheora_granule_time) (theora_state *th,ogg_int64_t granulepos);
453 static int (*qtheora_control) (theora_state *th,int req,void *buf,size_t buf_sz);
454 // end of theora.h stuff
456 static dllfunction_t oggfuncs[] =
458 {"ogg_stream_packetin", (void **) &qogg_stream_packetin},
459 {"ogg_stream_pageout", (void **) &qogg_stream_pageout},
460 {"ogg_stream_flush", (void **) &qogg_stream_flush},
461 {"ogg_stream_init", (void **) &qogg_stream_init},
462 {"ogg_stream_clear", (void **) &qogg_stream_clear},
463 {"ogg_page_granulepos", (void **) &qogg_page_granulepos},
467 static dllfunction_t vorbisencfuncs[] =
469 {"vorbis_encode_init_vbr", (void **) &qvorbis_encode_init_vbr},
473 static dllfunction_t vorbisfuncs[] =
475 {"vorbis_info_init", (void **) &qvorbis_info_init},
476 {"vorbis_info_clear", (void **) &qvorbis_info_clear},
477 {"vorbis_comment_init", (void **) &qvorbis_comment_init},
478 {"vorbis_comment_clear", (void **) &qvorbis_comment_clear},
479 {"vorbis_block_init", (void **) &qvorbis_block_init},
480 {"vorbis_block_clear", (void **) &qvorbis_block_clear},
481 {"vorbis_dsp_clear", (void **) &qvorbis_dsp_clear},
482 {"vorbis_analysis_init", (void **) &qvorbis_analysis_init},
483 {"vorbis_commentheader_out", (void **) &qvorbis_commentheader_out},
484 {"vorbis_analysis_headerout", (void **) &qvorbis_analysis_headerout},
485 {"vorbis_analysis_buffer", (void **) &qvorbis_analysis_buffer},
486 {"vorbis_analysis_wrote", (void **) &qvorbis_analysis_wrote},
487 {"vorbis_analysis_blockout", (void **) &qvorbis_analysis_blockout},
488 {"vorbis_analysis", (void **) &qvorbis_analysis},
489 {"vorbis_bitrate_addblock", (void **) &qvorbis_bitrate_addblock},
490 {"vorbis_bitrate_flushpacket", (void **) &qvorbis_bitrate_flushpacket},
491 {"vorbis_granule_time", (void **) &qvorbis_granule_time},
495 static dllfunction_t theorafuncs[] =
497 {"theora_info_init", (void **) &qtheora_info_init},
498 {"theora_info_clear", (void **) &qtheora_info_clear},
499 {"theora_comment_init", (void **) &qtheora_comment_init},
500 {"theora_comment_clear", (void **) &qtheora_comment_clear},
501 {"theora_encode_init", (void **) &qtheora_encode_init},
502 {"theora_encode_YUVin", (void **) &qtheora_encode_YUVin},
503 {"theora_encode_packetout", (void **) &qtheora_encode_packetout},
504 {"theora_encode_header", (void **) &qtheora_encode_header},
505 {"theora_encode_comment", (void **) &qtheora_encode_comment},
506 {"theora_encode_tables", (void **) &qtheora_encode_tables},
507 {"theora_clear", (void **) &qtheora_clear},
508 {"theora_granule_time", (void **) &qtheora_granule_time},
509 {"theora_control", (void **) &qtheora_control},
513 static dllhandle_t og_dll = NULL, vo_dll = NULL, ve_dll = NULL, th_dll = NULL;
515 static qbool SCR_CaptureVideo_Ogg_OpenLibrary(void)
517 const char* dllnames_og [] =
523 #elif defined(MACOSX)
531 const char* dllnames_vo [] =
537 #elif defined(MACOSX)
545 const char* dllnames_ve [] =
548 "libvorbisenc-2.dll",
551 #elif defined(MACOSX)
552 "libvorbisenc.dylib",
559 const char* dllnames_th [] =
565 #elif defined(MACOSX)
575 Sys_LoadLibrary (dllnames_og, &og_dll, oggfuncs)
577 Sys_LoadLibrary (dllnames_th, &th_dll, theorafuncs)
579 Sys_LoadLibrary (dllnames_vo, &vo_dll, vorbisfuncs)
581 Sys_LoadLibrary (dllnames_ve, &ve_dll, vorbisencfuncs);
584 void SCR_CaptureVideo_Ogg_Init(void)
586 SCR_CaptureVideo_Ogg_OpenLibrary();
588 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_vp3compat);
589 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_quality);
590 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_bitrate);
591 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier);
592 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_maxinterval);
593 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_mininterval);
594 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_auto_threshold);
595 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_noise_sensitivity);
596 Cvar_RegisterVariable(&cl_capturevideo_ogg_vorbis_quality);
599 qbool SCR_CaptureVideo_Ogg_Available(void)
601 return og_dll && th_dll && vo_dll && ve_dll;
604 void SCR_CaptureVideo_Ogg_CloseDLL(void)
606 Sys_UnloadLibrary (&ve_dll);
607 Sys_UnloadLibrary (&vo_dll);
608 Sys_UnloadLibrary (&th_dll);
609 Sys_UnloadLibrary (&og_dll);
612 // this struct should not be needed
613 // however, libogg appears to pull the ogg_page's data element away from our
614 // feet before we get to write the data due to interleaving
615 // so this struct is used to keep the page data around until it actually gets
617 typedef struct allocatedoggpage_s
621 unsigned char data[65307];
622 // this number is from RFC 3533. In case libogg writes more, we'll have to increase this
623 // but we'll get a Host_Error in this case so we can track it down
627 typedef struct capturevideostate_ogg_formatspecific_s
629 ogg_stream_state to, vo;
630 int serial1, serial2;
640 allocatedoggpage_t videopage, audiopage;
642 capturevideostate_ogg_formatspecific_t;
643 #define LOAD_FORMATSPECIFIC_OGG() capturevideostate_ogg_formatspecific_t *format = (capturevideostate_ogg_formatspecific_t *) cls.capturevideo.formatspecific
645 static void SCR_CaptureVideo_Ogg_Interleave(void)
647 LOAD_FORMATSPECIFIC_OGG();
650 if(!cls.capturevideo.soundrate)
652 while(qogg_stream_pageout(&format->to, &pg) > 0)
654 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
655 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
662 // first: make sure we have a page of both types
663 if(!format->videopage.len)
664 if(qogg_stream_pageout(&format->to, &pg) > 0)
666 format->videopage.len = pg.header_len + pg.body_len;
667 format->videopage.time = qtheora_granule_time(&format->ts, qogg_page_granulepos(&pg));
668 if(format->videopage.len > sizeof(format->videopage.data))
669 Sys_Error("video page too long");
670 memcpy(format->videopage.data, pg.header, pg.header_len);
671 memcpy(format->videopage.data + pg.header_len, pg.body, pg.body_len);
673 if(!format->audiopage.len)
674 if(qogg_stream_pageout(&format->vo, &pg) > 0)
676 format->audiopage.len = pg.header_len + pg.body_len;
677 format->audiopage.time = qvorbis_granule_time(&format->vd, qogg_page_granulepos(&pg));
678 if(format->audiopage.len > sizeof(format->audiopage.data))
679 Sys_Error("audio page too long");
680 memcpy(format->audiopage.data, pg.header, pg.header_len);
681 memcpy(format->audiopage.data + pg.header_len, pg.body, pg.body_len);
684 if(format->videopage.len && format->audiopage.len)
686 // output the page that ends first
687 if(format->videopage.time < format->audiopage.time)
689 FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len);
690 format->videopage.len = 0;
694 FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len);
695 format->audiopage.len = 0;
703 static void SCR_CaptureVideo_Ogg_FlushInterleaving(void)
705 LOAD_FORMATSPECIFIC_OGG();
707 if(cls.capturevideo.soundrate)
708 if(format->audiopage.len)
710 FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len);
711 format->audiopage.len = 0;
714 if(format->videopage.len)
716 FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len);
717 format->videopage.len = 0;
721 static void SCR_CaptureVideo_Ogg_EndVideo(void)
723 LOAD_FORMATSPECIFIC_OGG();
727 if(format->yuvi >= 0)
729 // send the previous (and last) frame
730 while(format->lastnum-- > 0)
732 qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]);
734 while(qtheora_encode_packetout(&format->ts, !format->lastnum, &pt))
735 qogg_stream_packetin(&format->to, &pt);
737 SCR_CaptureVideo_Ogg_Interleave();
741 if(cls.capturevideo.soundrate)
743 qvorbis_analysis_wrote(&format->vd, 0);
744 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
746 qvorbis_analysis(&format->vb, NULL);
747 qvorbis_bitrate_addblock(&format->vb);
748 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
749 qogg_stream_packetin(&format->vo, &pt);
750 SCR_CaptureVideo_Ogg_Interleave();
754 SCR_CaptureVideo_Ogg_FlushInterleaving();
756 while(qogg_stream_pageout(&format->to, &pg) > 0)
758 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
759 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
762 if(cls.capturevideo.soundrate)
764 while(qogg_stream_pageout(&format->vo, &pg) > 0)
766 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
767 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
772 int result = qogg_stream_flush (&format->to, &pg);
774 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
777 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
778 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
781 if(cls.capturevideo.soundrate)
784 int result = qogg_stream_flush (&format->vo, &pg);
786 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
789 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
790 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
793 qogg_stream_clear(&format->vo);
794 qvorbis_block_clear(&format->vb);
795 qvorbis_dsp_clear(&format->vd);
798 qogg_stream_clear(&format->to);
799 qtheora_clear(&format->ts);
800 qvorbis_info_clear(&format->vi);
802 Mem_Free(format->yuv[0].y);
803 Mem_Free(format->yuv[0].u);
804 Mem_Free(format->yuv[0].v);
805 Mem_Free(format->yuv[1].y);
806 Mem_Free(format->yuv[1].u);
807 Mem_Free(format->yuv[1].v);
810 FS_Close(cls.capturevideo.videofile);
811 cls.capturevideo.videofile = NULL;
814 static void SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV(void)
816 LOAD_FORMATSPECIFIC_OGG();
819 int blockr, blockg, blockb;
821 int w = cls.capturevideo.width;
822 int h = cls.capturevideo.height;
825 yuv = &format->yuv[format->yuvi];
827 for(y = 0; y < h; ++y)
829 for(b = cls.capturevideo.outbuffer + (h-1-y)*w*4, x = 0; x < w; ++x)
834 yuv->y[x + yuv->y_stride * y] =
835 cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]];
839 if ((y & 1) == 0 && y/2 < h/2) // if h is odd, this skips the last row
841 for(b = cls.capturevideo.outbuffer + (h-2-y)*w*4, x = 0; x < w/2; ++x)
843 blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2;
844 blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2;
845 blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2;
846 yuv->u[x + yuv->uv_stride * (y/2)] =
847 cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128];
848 yuv->v[x + yuv->uv_stride * (y/2)] =
849 cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128];
856 static void SCR_CaptureVideo_Ogg_VideoFrames(int num)
858 LOAD_FORMATSPECIFIC_OGG();
861 // data is in cls.capturevideo.outbuffer as BGRA and has size width*height
863 if(format->yuvi >= 0)
865 // send the previous frame
866 while(format->lastnum-- > 0)
868 qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]);
870 while(qtheora_encode_packetout(&format->ts, false, &pt))
871 qogg_stream_packetin(&format->to, &pt);
873 SCR_CaptureVideo_Ogg_Interleave();
877 format->yuvi = (format->yuvi + 1) % 2;
878 SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV();
879 format->lastnum = num;
881 // TODO maybe send num-1 frames from here already
884 typedef int channelmapping_t[8];
885 channelmapping_t mapping[8] =
887 { 0, -1, -1, -1, -1, -1, -1, -1 }, // mono
888 { 0, 1, -1, -1, -1, -1, -1, -1 }, // stereo
889 { 0, 1, 2, -1, -1, -1, -1, -1 }, // L C R
890 { 0, 1, 2, 3, -1, -1, -1, -1 }, // surround40
891 { 0, 2, 3, 4, 1, -1, -1, -1 }, // FL FC FR RL RR
892 { 0, 2, 3, 4, 1, 5, -1, -1 }, // surround51
893 { 0, 2, 3, 4, 1, 5, 6, -1 }, // (not defined by vorbis spec)
894 { 0, 2, 3, 4, 1, 5, 6, 7 } // surround71 (not defined by vorbis spec)
897 static void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
899 LOAD_FORMATSPECIFIC_OGG();
900 float **vorbis_buffer;
904 int *map = mapping[bound(1, cls.capturevideo.soundchannels, 8) - 1];
906 vorbis_buffer = qvorbis_analysis_buffer(&format->vd, (int)length);
907 for(j = 0; j < cls.capturevideo.soundchannels; ++j)
909 float *b = vorbis_buffer[map[j]];
910 for(i = 0; i < length; ++i)
911 b[i] = paintbuffer[i].sample[j];
913 qvorbis_analysis_wrote(&format->vd, (int)length);
915 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
917 qvorbis_analysis(&format->vb, NULL);
918 qvorbis_bitrate_addblock(&format->vb);
920 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
921 qogg_stream_packetin(&format->vo, &pt);
924 SCR_CaptureVideo_Ogg_Interleave();
927 void SCR_CaptureVideo_Ogg_BeginVideo(void)
930 cls.capturevideo.format = CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA;
931 cls.capturevideo.formatextension = "ogv";
932 cls.capturevideo.videofile = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false);
933 cls.capturevideo.endvideo = SCR_CaptureVideo_Ogg_EndVideo;
934 cls.capturevideo.videoframes = SCR_CaptureVideo_Ogg_VideoFrames;
935 cls.capturevideo.soundframe = SCR_CaptureVideo_Ogg_SoundFrame;
936 cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_ogg_formatspecific_t));
938 LOAD_FORMATSPECIFIC_OGG();
941 ogg_packet pt, pt2, pt3;
947 format->serial1 = rand();
948 qogg_stream_init(&format->to, format->serial1);
950 if(cls.capturevideo.soundrate)
954 format->serial2 = rand();
956 while(format->serial1 == format->serial2);
957 qogg_stream_init(&format->vo, format->serial2);
960 format->videopage.len = format->audiopage.len = 0;
962 qtheora_info_init(&ti);
963 ti.frame_width = cls.capturevideo.width;
964 ti.frame_height = cls.capturevideo.height;
965 ti.width = (ti.frame_width + 15) & ~15;
966 ti.height = (ti.frame_height + 15) & ~15;
967 //ti.offset_x = ((ti.width - ti.frame_width) / 2) & ~1;
968 //ti.offset_y = ((ti.height - ti.frame_height) / 2) & ~1;
970 for(i = 0; i < 2; ++i)
972 format->yuv[i].y_width = ti.width;
973 format->yuv[i].y_height = ti.height;
974 format->yuv[i].y_stride = ti.width;
975 format->yuv[i].uv_width = ti.width / 2;
976 format->yuv[i].uv_height = ti.height / 2;
977 format->yuv[i].uv_stride = ti.width / 2;
978 format->yuv[i].y = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].y_stride * format->yuv[i].y_height);
979 format->yuv[i].u = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
980 format->yuv[i].v = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
982 format->yuvi = -1; // -1: no frame valid yet, write into 0
984 FindFraction(cls.capturevideo.framerate / cls.capturevideo.framestep, &num, &denom, 1001);
985 ti.fps_numerator = num;
986 ti.fps_denominator = denom;
988 FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000);
989 ti.aspect_numerator = num;
990 ti.aspect_denominator = denom;
992 ti.colorspace = OC_CS_UNSPECIFIED;
993 ti.pixelformat = OC_PF_420;
995 ti.quick_p = true; // http://mlblog.osdir.com/multimedia.ogg.theora.general/2004-07/index.shtml
996 ti.dropframes_p = false;
998 ti.target_bitrate = cl_capturevideo_ogg_theora_bitrate.integer * 1000;
999 ti.quality = cl_capturevideo_ogg_theora_quality.integer;
1001 if(ti.target_bitrate <= 0)
1003 ti.target_bitrate = -1;
1004 ti.keyframe_data_target_bitrate = (unsigned int)-1;
1008 ti.keyframe_data_target_bitrate = (int) (ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value));
1010 if(ti.target_bitrate < 45000 || ti.target_bitrate > 2000000)
1011 Con_DPrintf("WARNING: requesting an odd bitrate for theora (sensible values range from 45 to 2000 kbps)\n");
1014 if(ti.quality < 0 || ti.quality > 63)
1017 if(ti.target_bitrate <= 0)
1019 ti.target_bitrate = 0x7FFFFFFF;
1020 ti.keyframe_data_target_bitrate = 0x7FFFFFFF;
1024 // this -1 magic is because ti.keyframe_frequency and ti.keyframe_mindistance use different metrics
1025 ti.keyframe_frequency = bound(1, cl_capturevideo_ogg_theora_keyframe_maxinterval.integer, 1000);
1026 ti.keyframe_mindistance = bound(1, cl_capturevideo_ogg_theora_keyframe_mininterval.integer, (int) ti.keyframe_frequency) - 1;
1027 ti.noise_sensitivity = bound(0, cl_capturevideo_ogg_theora_noise_sensitivity.integer, 6);
1028 ti.sharpness = bound(0, cl_capturevideo_ogg_theora_sharpness.integer, 2);
1029 ti.keyframe_auto_threshold = bound(0, cl_capturevideo_ogg_theora_keyframe_auto_threshold.integer, 100);
1031 ti.keyframe_frequency_force = ti.keyframe_frequency;
1032 ti.keyframe_auto_p = (ti.keyframe_frequency != ti.keyframe_mindistance + 1);
1034 qtheora_encode_init(&format->ts, &ti);
1035 qtheora_info_clear(&ti);
1037 if(cl_capturevideo_ogg_theora_vp3compat.integer)
1040 qtheora_control(&format->ts, TH_ENCCTL_SET_VP3_COMPATIBLE, &vp3compat, sizeof(vp3compat));
1042 Con_DPrintf("Warning: theora stream is not fully VP3 compatible\n");
1046 if(cls.capturevideo.soundrate)
1048 qvorbis_info_init(&format->vi);
1049 qvorbis_encode_init_vbr(&format->vi, cls.capturevideo.soundchannels, cls.capturevideo.soundrate, bound(-1, cl_capturevideo_ogg_vorbis_quality.value, 10) * 0.099);
1050 qvorbis_comment_init(&vc);
1051 qvorbis_analysis_init(&format->vd, &format->vi);
1052 qvorbis_block_init(&format->vd, &format->vb);
1055 qtheora_comment_init(&tc);
1057 /* create the remaining theora headers */
1058 qtheora_encode_header(&format->ts, &pt);
1059 qogg_stream_packetin(&format->to, &pt);
1060 if (qogg_stream_pageout (&format->to, &pg) != 1)
1061 fprintf (stderr, "Internal Ogg library error.\n");
1062 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1063 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1065 qtheora_encode_comment(&tc, &pt);
1066 qogg_stream_packetin(&format->to, &pt);
1067 qtheora_encode_tables(&format->ts, &pt);
1068 qogg_stream_packetin (&format->to, &pt);
1070 qtheora_comment_clear(&tc);
1072 if(cls.capturevideo.soundrate)
1074 qvorbis_analysis_headerout(&format->vd, &vc, &pt, &pt2, &pt3);
1075 qogg_stream_packetin(&format->vo, &pt);
1076 if (qogg_stream_pageout (&format->vo, &pg) != 1)
1077 fprintf (stderr, "Internal Ogg library error.\n");
1078 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1079 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1081 qogg_stream_packetin(&format->vo, &pt2);
1082 qogg_stream_packetin(&format->vo, &pt3);
1084 qvorbis_comment_clear(&vc);
1089 int result = qogg_stream_flush (&format->to, &pg);
1091 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
1094 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1095 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1098 if(cls.capturevideo.soundrate)
1101 int result = qogg_stream_flush (&format->vo, &pg);
1103 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
1106 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1107 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);