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"};
23 unsigned char *buffer;
28 /* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
31 unsigned char *header;
37 /* ogg_stream_state contains the current encode/decode state of a logical
38 Ogg bitstream **********************************************************/
41 unsigned char *body_data; /* bytes from packet bodies */
42 long body_storage; /* storage elements allocated */
43 long body_fill; /* elements stored; fill mark */
44 long body_returned; /* elements of fill returned */
47 int *lacing_vals; /* The values that will go to the segment table */
48 int64_t *granule_vals; /* granulepos values for headers. Not compact
49 this way, but it is simple coupled to the
56 unsigned char header[282]; /* working space for header encode */
59 int e_o_s; /* set when we have buffered the last packet in the
61 int b_o_s; /* set after we've written the initial page
62 of a logical bitstream */
65 int64_t packetno; /* sequence number for decode; the framing
66 knows where there's a hole in the data,
67 but we need coupling so that the codec
68 (which is in a seperate abstraction
69 layer) also knows about the gap */
74 /* ogg_packet is used to encapsulate the data and metadata belonging
75 to a single raw Ogg/Vorbis packet *************************************/
78 unsigned char *packet;
85 int64_t packetno; /* sequence number for decode; the framing
86 knows where there's a hole in the data,
87 but we need coupling so that the codec
88 (which is in a seperate abstraction
89 layer) also knows about the gap */
103 /* Ogg BITSTREAM PRIMITIVES: encoding **************************/
105 static int (*qogg_stream_packetin) (ogg_stream_state *os, ogg_packet *op);
106 static int (*qogg_stream_pageout) (ogg_stream_state *os, ogg_page *og);
107 static int (*qogg_stream_flush) (ogg_stream_state *os, ogg_page *og);
109 /* Ogg BITSTREAM PRIMITIVES: general ***************************/
111 static int (*qogg_stream_init) (ogg_stream_state *os,int serialno);
112 static int (*qogg_stream_clear) (ogg_stream_state *os);
113 static int64_t (*qogg_page_granulepos) (ogg_page *og);
115 // end of ogg.h stuff
117 // vorbis/codec.h stuff
118 typedef struct vorbis_info{
123 /* The below bitrate declarations are *hints*.
124 Combinations of the three values carry the following implications:
126 all three set to the same value:
127 implies a fixed rate bitstream
129 implies a VBR stream that averages the nominal bitrate. No hard
131 upper and or lower set:
132 implies a VBR bitstream that obeys the bitrate limits. nominal
133 may also be set to give a nominal rate.
135 the coder does not care to speculate.
139 long bitrate_nominal;
146 /* vorbis_dsp_state buffers the current vorbis audio
147 analysis/synthesis state. The DSP state belongs to a specific
148 logical bitstream ****************************************************/
149 typedef struct vorbis_dsp_state{
178 typedef struct vorbis_block{
179 /* necessary stream state for linking to the framing abstraction */
180 float **pcm; /* this is a pointer into local storage */
192 vorbis_dsp_state *vd; /* For read-only access of configuration */
194 /* local storage to avoid remallocing; it's up to the mapping to
200 struct alloc_chain *reap;
202 /* bitmetrics for the frame */
212 /* vorbis_block is a single block of data to be processed as part of
213 the analysis/synthesis stream; it belongs to a specific logical
214 bitstream, but is independant from other vorbis_blocks belonging to
215 that logical bitstream. *************************************************/
219 struct alloc_chain *next;
222 /* vorbis_info contains all the setup information specific to the
223 specific compression/decompression mode in progress (eg,
224 psychoacoustic settings, channel setup, options, codebook
225 etc). vorbis_info and substructures are in backends.h.
226 *********************************************************************/
228 /* the comments are not part of vorbis_info so that vorbis_info can be
230 typedef struct vorbis_comment{
231 /* unlimited user comment fields. libvorbis writes 'libvorbis'
232 whatever vendor is set to in encode */
233 char **user_comments;
234 int *comment_lengths;
241 /* libvorbis encodes in two abstraction layers; first we perform DSP
242 and produce a packet (see docs/analysis.txt). The packet is then
243 coded into a framed OggSquish bitstream by the second layer (see
244 docs/framing.txt). Decode is the reverse process; we sync/frame
245 the bitstream and extract individual packets, then decode the
246 packet back into PCM audio.
248 The extra framing/packetizing is used in streaming formats, such as
249 files. Over the net (such as with UDP), the framing and
250 packetization aren't necessary as they're provided by the transport
251 and the streaming layer is not used */
253 /* Vorbis PRIMITIVES: general ***************************************/
255 static void (*qvorbis_info_init) (vorbis_info *vi);
256 static void (*qvorbis_info_clear) (vorbis_info *vi);
257 static void (*qvorbis_comment_init) (vorbis_comment *vc);
258 static void (*qvorbis_comment_clear) (vorbis_comment *vc);
260 static int (*qvorbis_block_init) (vorbis_dsp_state *v, vorbis_block *vb);
261 static int (*qvorbis_block_clear) (vorbis_block *vb);
262 static void (*qvorbis_dsp_clear) (vorbis_dsp_state *v);
263 static double (*qvorbis_granule_time) (vorbis_dsp_state *v,
266 /* Vorbis PRIMITIVES: analysis/DSP layer ****************************/
268 static int (*qvorbis_analysis_init) (vorbis_dsp_state *v,vorbis_info *vi);
269 static int (*qvorbis_commentheader_out) (vorbis_comment *vc, ogg_packet *op);
270 static int (*qvorbis_analysis_headerout) (vorbis_dsp_state *v,
274 ogg_packet *op_code);
275 static float ** (*qvorbis_analysis_buffer) (vorbis_dsp_state *v,int vals);
276 static int (*qvorbis_analysis_wrote) (vorbis_dsp_state *v,int vals);
277 static int (*qvorbis_analysis_blockout) (vorbis_dsp_state *v,vorbis_block *vb);
278 static int (*qvorbis_analysis) (vorbis_block *vb,ogg_packet *op);
280 static int (*qvorbis_bitrate_addblock) (vorbis_block *vb);
281 static int (*qvorbis_bitrate_flushpacket) (vorbis_dsp_state *vd,
284 // end of vorbis/codec.h stuff
287 static int (*qvorbis_encode_init_vbr) (vorbis_info *vi,
291 float base_quality /* quality level from 0. (lo) to 1. (hi) */
293 // end of vorbisenc.h stuff
297 #define TH_ENCCTL_SET_VP3_COMPATIBLE (10)
300 int y_width; /**< Width of the Y' luminance plane */
301 int y_height; /**< Height of the luminance plane */
302 int y_stride; /**< Offset in bytes between successive rows */
304 int uv_width; /**< Width of the Cb and Cr chroma planes */
305 int uv_height; /**< Height of the chroma planes */
306 int uv_stride; /**< Offset between successive chroma rows */
307 unsigned char *y; /**< Pointer to start of luminance data */
308 unsigned char *u; /**< Pointer to start of Cb data */
309 unsigned char *v; /**< Pointer to start of Cr data */
317 OC_CS_UNSPECIFIED, /**< The colorspace is unknown or unspecified */
318 OC_CS_ITU_REC_470M, /**< This is the best option for 'NTSC' content */
319 OC_CS_ITU_REC_470BG, /**< This is the best option for 'PAL' content */
320 OC_CS_NSPACES /**< This marks the end of the defined colorspaces */
324 * A Chroma subsampling
326 * These enumerate the available chroma subsampling options supported
327 * by the theora format. See Section 4.4 of the specification for
331 OC_PF_420, /**< Chroma subsampling by 2 in each direction (4:2:0) */
332 OC_PF_RSVD, /**< Reserved value */
333 OC_PF_422, /**< Horizonatal chroma subsampling by 2 (4:2:2) */
334 OC_PF_444 /**< No chroma subsampling at all (4:4:4) */
335 } theora_pixelformat;
337 * Theora bitstream info.
338 * Contains the basic playback parameters for a stream,
339 * corresponding to the initial 'info' header packet.
341 * Encoded theora frames must be a multiple of 16 in width and height.
342 * To handle other frame sizes, a crop rectangle is specified in
343 * frame_height and frame_width, offset_x and * offset_y. The offset
344 * and size should still be a multiple of 2 to avoid chroma sampling
345 * shifts. Offset values in this structure are measured from the
346 * upper left of the image.
348 * Frame rate, in frames per second, is stored as a rational
349 * fraction. Aspect ratio is also stored as a rational fraction, and
350 * refers to the aspect ratio of the frame pixels, not of the
351 * overall frame itself.
353 * See <a href="http://svn.xiph.org/trunk/theora/examples/encoder_example.c">
354 * examples/encoder_example.c</a> for usage examples of the
355 * other paramters and good default settings for the encoder parameters.
358 uint32_t width; /**< encoded frame width */
359 uint32_t height; /**< encoded frame height */
360 uint32_t frame_width; /**< display frame width */
361 uint32_t frame_height; /**< display frame height */
362 uint32_t offset_x; /**< horizontal offset of the displayed frame */
363 uint32_t offset_y; /**< vertical offset of the displayed frame */
364 uint32_t fps_numerator; /**< frame rate numerator **/
365 uint32_t fps_denominator; /**< frame rate denominator **/
366 uint32_t aspect_numerator; /**< pixel aspect ratio numerator */
367 uint32_t aspect_denominator; /**< pixel aspect ratio denominator */
368 theora_colorspace colorspace; /**< colorspace */
369 int target_bitrate; /**< nominal bitrate in bits per second */
370 int quality; /**< Nominal quality setting, 0-63 */
371 int quick_p; /**< Quick encode/decode */
374 unsigned char version_major;
375 unsigned char version_minor;
376 unsigned char version_subminor;
383 uint32_t keyframe_frequency;
384 uint32_t keyframe_frequency_force; /* also used for decode init to
385 get granpos shift correct */
386 uint32_t keyframe_data_target_bitrate;
387 int32_t keyframe_auto_threshold;
388 uint32_t keyframe_mindistance;
389 int32_t noise_sensitivity;
392 theora_pixelformat pixelformat; /**< chroma subsampling mode to expect */
396 /** Codec internal state and context.
402 void *internal_encode;
403 void *internal_decode;
408 * Comment header metadata.
410 * This structure holds the in-stream metadata corresponding to
411 * the 'comment' header packet.
413 * Meta data is stored as a series of (tag, value) pairs, in
414 * length-encoded string vectors. The first occurence of the
415 * '=' character delimits the tag and value. A particular tag
416 * may occur more than once. The character set encoding for
417 * the strings is always UTF-8, but the tag names are limited
418 * to case-insensitive ASCII. See the spec for details.
420 * In filling in this structure, qtheora_decode_header() will
421 * null-terminate the user_comment strings for safety. However,
422 * the bitstream format itself treats them as 8-bit clean,
423 * and so the length array should be treated as authoritative
426 typedef struct theora_comment{
427 char **user_comments; /**< An array of comment string vectors */
428 int *comment_lengths; /**< An array of corresponding string vector lengths in bytes */
429 int comments; /**< The total number of comment string vectors */
430 char *vendor; /**< The vendor string identifying the encoder, null terminated */
433 static int (*qtheora_encode_init) (theora_state *th, theora_info *ti);
434 static int (*qtheora_encode_YUVin) (theora_state *t, yuv_buffer *yuv);
435 static int (*qtheora_encode_packetout) ( theora_state *t, int last_p,
437 static int (*qtheora_encode_header) (theora_state *t, ogg_packet *op);
438 static int (*qtheora_encode_comment) (theora_comment *tc, ogg_packet *op);
439 static int (*qtheora_encode_tables) (theora_state *t, ogg_packet *op);
440 static void (*qtheora_info_init) (theora_info *c);
441 static void (*qtheora_info_clear) (theora_info *c);
442 static void (*qtheora_clear) (theora_state *t);
443 static void (*qtheora_comment_init) (theora_comment *tc);
444 static void (*qtheora_comment_clear) (theora_comment *tc);
445 static double (*qtheora_granule_time) (theora_state *th,int64_t granulepos);
446 static int (*qtheora_control) (theora_state *th,int req,void *buf,size_t buf_sz);
447 // end of theora.h stuff
449 static dllfunction_t oggfuncs[] =
451 {"ogg_stream_packetin", (void **) &qogg_stream_packetin},
452 {"ogg_stream_pageout", (void **) &qogg_stream_pageout},
453 {"ogg_stream_flush", (void **) &qogg_stream_flush},
454 {"ogg_stream_init", (void **) &qogg_stream_init},
455 {"ogg_stream_clear", (void **) &qogg_stream_clear},
456 {"ogg_page_granulepos", (void **) &qogg_page_granulepos},
460 static dllfunction_t vorbisencfuncs[] =
462 {"vorbis_encode_init_vbr", (void **) &qvorbis_encode_init_vbr},
466 static dllfunction_t vorbisfuncs[] =
468 {"vorbis_info_init", (void **) &qvorbis_info_init},
469 {"vorbis_info_clear", (void **) &qvorbis_info_clear},
470 {"vorbis_comment_init", (void **) &qvorbis_comment_init},
471 {"vorbis_comment_clear", (void **) &qvorbis_comment_clear},
472 {"vorbis_block_init", (void **) &qvorbis_block_init},
473 {"vorbis_block_clear", (void **) &qvorbis_block_clear},
474 {"vorbis_dsp_clear", (void **) &qvorbis_dsp_clear},
475 {"vorbis_analysis_init", (void **) &qvorbis_analysis_init},
476 {"vorbis_commentheader_out", (void **) &qvorbis_commentheader_out},
477 {"vorbis_analysis_headerout", (void **) &qvorbis_analysis_headerout},
478 {"vorbis_analysis_buffer", (void **) &qvorbis_analysis_buffer},
479 {"vorbis_analysis_wrote", (void **) &qvorbis_analysis_wrote},
480 {"vorbis_analysis_blockout", (void **) &qvorbis_analysis_blockout},
481 {"vorbis_analysis", (void **) &qvorbis_analysis},
482 {"vorbis_bitrate_addblock", (void **) &qvorbis_bitrate_addblock},
483 {"vorbis_bitrate_flushpacket", (void **) &qvorbis_bitrate_flushpacket},
484 {"vorbis_granule_time", (void **) &qvorbis_granule_time},
488 static dllfunction_t theorafuncs[] =
490 {"theora_info_init", (void **) &qtheora_info_init},
491 {"theora_info_clear", (void **) &qtheora_info_clear},
492 {"theora_comment_init", (void **) &qtheora_comment_init},
493 {"theora_comment_clear", (void **) &qtheora_comment_clear},
494 {"theora_encode_init", (void **) &qtheora_encode_init},
495 {"theora_encode_YUVin", (void **) &qtheora_encode_YUVin},
496 {"theora_encode_packetout", (void **) &qtheora_encode_packetout},
497 {"theora_encode_header", (void **) &qtheora_encode_header},
498 {"theora_encode_comment", (void **) &qtheora_encode_comment},
499 {"theora_encode_tables", (void **) &qtheora_encode_tables},
500 {"theora_clear", (void **) &qtheora_clear},
501 {"theora_granule_time", (void **) &qtheora_granule_time},
502 {"theora_control", (void **) &qtheora_control},
506 static dllhandle_t og_dll = NULL, vo_dll = NULL, ve_dll = NULL, th_dll = NULL;
508 static qbool SCR_CaptureVideo_Ogg_OpenLibrary(void)
510 const char* dllnames_og [] =
516 #elif defined(MACOSX)
524 const char* dllnames_vo [] =
530 #elif defined(MACOSX)
538 const char* dllnames_ve [] =
541 "libvorbisenc-2.dll",
544 #elif defined(MACOSX)
545 "libvorbisenc.dylib",
552 const char* dllnames_th [] =
558 #elif defined(MACOSX)
568 Sys_LoadDependency (dllnames_og, &og_dll, oggfuncs)
570 Sys_LoadDependency (dllnames_th, &th_dll, theorafuncs)
572 Sys_LoadDependency (dllnames_vo, &vo_dll, vorbisfuncs)
574 Sys_LoadDependency (dllnames_ve, &ve_dll, vorbisencfuncs);
577 void SCR_CaptureVideo_Ogg_Init(void)
579 SCR_CaptureVideo_Ogg_OpenLibrary();
581 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_vp3compat);
582 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_quality);
583 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_bitrate);
584 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier);
585 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_maxinterval);
586 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_mininterval);
587 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_auto_threshold);
588 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_noise_sensitivity);
589 Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_sharpness);
590 Cvar_RegisterVariable(&cl_capturevideo_ogg_vorbis_quality);
593 qbool SCR_CaptureVideo_Ogg_Available(void)
595 return og_dll && th_dll && vo_dll && ve_dll;
598 void SCR_CaptureVideo_Ogg_CloseDLL(void)
600 Sys_FreeLibrary (&ve_dll);
601 Sys_FreeLibrary (&vo_dll);
602 Sys_FreeLibrary (&th_dll);
603 Sys_FreeLibrary (&og_dll);
606 // this struct should not be needed
607 // however, libogg appears to pull the ogg_page's data element away from our
608 // feet before we get to write the data due to interleaving
609 // so this struct is used to keep the page data around until it actually gets
611 typedef struct allocatedoggpage_s
615 unsigned char data[65307];
616 // this number is from RFC 3533. In case libogg writes more, we'll have to increase this
617 // but we'll get a Host_Error in this case so we can track it down
621 typedef struct capturevideostate_ogg_formatspecific_s
623 ogg_stream_state to, vo;
624 int serial1, serial2;
634 allocatedoggpage_t videopage, audiopage;
636 capturevideostate_ogg_formatspecific_t;
637 #define LOAD_FORMATSPECIFIC_OGG() capturevideostate_ogg_formatspecific_t *format = (capturevideostate_ogg_formatspecific_t *) cls.capturevideo.formatspecific
639 static void SCR_CaptureVideo_Ogg_Interleave(void)
641 LOAD_FORMATSPECIFIC_OGG();
644 if(!cls.capturevideo.soundrate)
646 while(qogg_stream_pageout(&format->to, &pg) > 0)
648 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
649 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
656 // first: make sure we have a page of both types
657 if(!format->videopage.len)
658 if(qogg_stream_pageout(&format->to, &pg) > 0)
660 format->videopage.len = pg.header_len + pg.body_len;
661 format->videopage.time = qtheora_granule_time(&format->ts, qogg_page_granulepos(&pg));
662 if(format->videopage.len > sizeof(format->videopage.data))
663 Sys_Error("video page too long");
664 memcpy(format->videopage.data, pg.header, pg.header_len);
665 memcpy(format->videopage.data + pg.header_len, pg.body, pg.body_len);
667 if(!format->audiopage.len)
668 if(qogg_stream_pageout(&format->vo, &pg) > 0)
670 format->audiopage.len = pg.header_len + pg.body_len;
671 format->audiopage.time = qvorbis_granule_time(&format->vd, qogg_page_granulepos(&pg));
672 if(format->audiopage.len > sizeof(format->audiopage.data))
673 Sys_Error("audio page too long");
674 memcpy(format->audiopage.data, pg.header, pg.header_len);
675 memcpy(format->audiopage.data + pg.header_len, pg.body, pg.body_len);
678 if(format->videopage.len && format->audiopage.len)
680 // output the page that ends first
681 if(format->videopage.time < format->audiopage.time)
683 FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len);
684 format->videopage.len = 0;
688 FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len);
689 format->audiopage.len = 0;
697 static void SCR_CaptureVideo_Ogg_FlushInterleaving(void)
699 LOAD_FORMATSPECIFIC_OGG();
701 if(cls.capturevideo.soundrate)
702 if(format->audiopage.len)
704 FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len);
705 format->audiopage.len = 0;
708 if(format->videopage.len)
710 FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len);
711 format->videopage.len = 0;
715 static void SCR_CaptureVideo_Ogg_EndVideo(void)
717 LOAD_FORMATSPECIFIC_OGG();
721 if(format->yuvi >= 0)
723 // send the previous (and last) frame
724 while(format->lastnum-- > 0)
726 qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]);
728 while(qtheora_encode_packetout(&format->ts, !format->lastnum, &pt))
729 qogg_stream_packetin(&format->to, &pt);
731 SCR_CaptureVideo_Ogg_Interleave();
735 if(cls.capturevideo.soundrate)
737 qvorbis_analysis_wrote(&format->vd, 0);
738 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
740 qvorbis_analysis(&format->vb, NULL);
741 qvorbis_bitrate_addblock(&format->vb);
742 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
743 qogg_stream_packetin(&format->vo, &pt);
744 SCR_CaptureVideo_Ogg_Interleave();
748 SCR_CaptureVideo_Ogg_FlushInterleaving();
750 while(qogg_stream_pageout(&format->to, &pg) > 0)
752 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
753 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
756 if(cls.capturevideo.soundrate)
758 while(qogg_stream_pageout(&format->vo, &pg) > 0)
760 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
761 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
766 int result = qogg_stream_flush (&format->to, &pg);
768 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
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)
778 int result = qogg_stream_flush (&format->vo, &pg);
780 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
783 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
784 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
787 qogg_stream_clear(&format->vo);
788 qvorbis_block_clear(&format->vb);
789 qvorbis_dsp_clear(&format->vd);
792 qogg_stream_clear(&format->to);
793 qtheora_clear(&format->ts);
794 qvorbis_info_clear(&format->vi);
796 Mem_Free(format->yuv[0].y);
797 Mem_Free(format->yuv[0].u);
798 Mem_Free(format->yuv[0].v);
799 Mem_Free(format->yuv[1].y);
800 Mem_Free(format->yuv[1].u);
801 Mem_Free(format->yuv[1].v);
804 FS_Close(cls.capturevideo.videofile);
805 cls.capturevideo.videofile = NULL;
808 static void SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV(void)
810 LOAD_FORMATSPECIFIC_OGG();
813 int blockr, blockg, blockb;
815 int w = cls.capturevideo.width;
816 int h = cls.capturevideo.height;
819 yuv = &format->yuv[format->yuvi];
821 for(y = 0; y < h; ++y)
823 for(b = cls.capturevideo.outbuffer + (h-1-y)*w*4, x = 0; x < w; ++x)
828 yuv->y[x + yuv->y_stride * y] =
829 cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]];
833 if ((y & 1) == 0 && y/2 < h/2) // if h is odd, this skips the last row
835 for(b = cls.capturevideo.outbuffer + (h-2-y)*w*4, x = 0; x < w/2; ++x)
837 blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2;
838 blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2;
839 blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2;
840 yuv->u[x + yuv->uv_stride * (y/2)] =
841 cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128];
842 yuv->v[x + yuv->uv_stride * (y/2)] =
843 cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128];
850 static void SCR_CaptureVideo_Ogg_VideoFrames(int num)
852 LOAD_FORMATSPECIFIC_OGG();
855 // data is in cls.capturevideo.outbuffer as BGRA and has size width*height
857 if(format->yuvi >= 0)
859 // send the previous frame
860 while(format->lastnum-- > 0)
862 qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]);
864 while(qtheora_encode_packetout(&format->ts, false, &pt))
865 qogg_stream_packetin(&format->to, &pt);
867 SCR_CaptureVideo_Ogg_Interleave();
871 format->yuvi = (format->yuvi + 1) % 2;
872 SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV();
873 format->lastnum = num;
875 // TODO maybe send num-1 frames from here already
878 typedef int channelmapping_t[8];
879 channelmapping_t mapping[8] =
881 { 0, -1, -1, -1, -1, -1, -1, -1 }, // mono
882 { 0, 1, -1, -1, -1, -1, -1, -1 }, // stereo
883 { 0, 1, 2, -1, -1, -1, -1, -1 }, // L C R
884 { 0, 1, 2, 3, -1, -1, -1, -1 }, // surround40
885 { 0, 2, 3, 4, 1, -1, -1, -1 }, // FL FC FR RL RR
886 { 0, 2, 3, 4, 1, 5, -1, -1 }, // surround51
887 { 0, 2, 3, 4, 1, 5, 6, -1 }, // (not defined by vorbis spec)
888 { 0, 2, 3, 4, 1, 5, 6, 7 } // surround71 (not defined by vorbis spec)
891 static void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
893 LOAD_FORMATSPECIFIC_OGG();
894 float **vorbis_buffer;
898 int *map = mapping[bound(1, cls.capturevideo.soundchannels, 8) - 1];
900 vorbis_buffer = qvorbis_analysis_buffer(&format->vd, (int)length);
901 for(j = 0; j < cls.capturevideo.soundchannels; ++j)
903 float *b = vorbis_buffer[map[j]];
904 for(i = 0; i < length; ++i)
905 b[i] = paintbuffer[i].sample[j];
907 qvorbis_analysis_wrote(&format->vd, (int)length);
909 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
911 qvorbis_analysis(&format->vb, NULL);
912 qvorbis_bitrate_addblock(&format->vb);
914 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
915 qogg_stream_packetin(&format->vo, &pt);
918 SCR_CaptureVideo_Ogg_Interleave();
921 void SCR_CaptureVideo_Ogg_BeginVideo(void)
924 cls.capturevideo.format = CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA;
925 cls.capturevideo.formatextension = "ogv";
926 cls.capturevideo.videofile = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false);
927 cls.capturevideo.endvideo = SCR_CaptureVideo_Ogg_EndVideo;
928 cls.capturevideo.videoframes = SCR_CaptureVideo_Ogg_VideoFrames;
929 cls.capturevideo.soundframe = SCR_CaptureVideo_Ogg_SoundFrame;
930 cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_ogg_formatspecific_t));
932 LOAD_FORMATSPECIFIC_OGG();
935 ogg_packet pt, pt2, pt3;
941 format->serial1 = rand();
942 qogg_stream_init(&format->to, format->serial1);
944 if(cls.capturevideo.soundrate)
948 format->serial2 = rand();
950 while(format->serial1 == format->serial2);
951 qogg_stream_init(&format->vo, format->serial2);
954 format->videopage.len = format->audiopage.len = 0;
956 qtheora_info_init(&ti);
957 ti.frame_width = cls.capturevideo.width;
958 ti.frame_height = cls.capturevideo.height;
959 ti.width = (ti.frame_width + 15) & ~15;
960 ti.height = (ti.frame_height + 15) & ~15;
961 //ti.offset_x = ((ti.width - ti.frame_width) / 2) & ~1;
962 //ti.offset_y = ((ti.height - ti.frame_height) / 2) & ~1;
964 for(i = 0; i < 2; ++i)
966 format->yuv[i].y_width = ti.width;
967 format->yuv[i].y_height = ti.height;
968 format->yuv[i].y_stride = ti.width;
969 format->yuv[i].uv_width = ti.width / 2;
970 format->yuv[i].uv_height = ti.height / 2;
971 format->yuv[i].uv_stride = ti.width / 2;
972 format->yuv[i].y = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].y_stride * format->yuv[i].y_height);
973 format->yuv[i].u = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
974 format->yuv[i].v = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
976 format->yuvi = -1; // -1: no frame valid yet, write into 0
978 FindFraction(cls.capturevideo.framerate / cls.capturevideo.framestep, &num, &denom, 1001);
979 ti.fps_numerator = num;
980 ti.fps_denominator = denom;
982 FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000);
983 ti.aspect_numerator = num;
984 ti.aspect_denominator = denom;
986 ti.colorspace = OC_CS_UNSPECIFIED;
987 ti.pixelformat = OC_PF_420;
989 ti.quick_p = true; // http://mlblog.osdir.com/multimedia.ogg.theora.general/2004-07/index.shtml
990 ti.dropframes_p = false;
992 ti.target_bitrate = cl_capturevideo_ogg_theora_bitrate.integer * 1000;
993 ti.quality = cl_capturevideo_ogg_theora_quality.integer;
995 if(ti.target_bitrate <= 0)
997 ti.target_bitrate = -1;
998 ti.keyframe_data_target_bitrate = (unsigned int)-1;
1002 ti.keyframe_data_target_bitrate = (int) (ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value));
1004 if(ti.target_bitrate < 45000 || ti.target_bitrate > 2000000)
1005 Con_DPrintf("WARNING: requesting an odd bitrate for theora (sensible values range from 45 to 2000 kbps)\n");
1008 if(ti.quality < 0 || ti.quality > 63)
1011 if(ti.target_bitrate <= 0)
1013 ti.target_bitrate = 0x7FFFFFFF;
1014 ti.keyframe_data_target_bitrate = 0x7FFFFFFF;
1018 // this -1 magic is because ti.keyframe_frequency and ti.keyframe_mindistance use different metrics
1019 ti.keyframe_frequency = bound(1, cl_capturevideo_ogg_theora_keyframe_maxinterval.integer, 1000);
1020 ti.keyframe_mindistance = bound(1, cl_capturevideo_ogg_theora_keyframe_mininterval.integer, (int) ti.keyframe_frequency) - 1;
1021 ti.noise_sensitivity = bound(0, cl_capturevideo_ogg_theora_noise_sensitivity.integer, 6);
1022 ti.sharpness = bound(0, cl_capturevideo_ogg_theora_sharpness.integer, 2);
1023 ti.keyframe_auto_threshold = bound(0, cl_capturevideo_ogg_theora_keyframe_auto_threshold.integer, 100);
1025 ti.keyframe_frequency_force = ti.keyframe_frequency;
1026 ti.keyframe_auto_p = (ti.keyframe_frequency != ti.keyframe_mindistance + 1);
1028 qtheora_encode_init(&format->ts, &ti);
1029 qtheora_info_clear(&ti);
1031 if(cl_capturevideo_ogg_theora_vp3compat.integer)
1034 qtheora_control(&format->ts, TH_ENCCTL_SET_VP3_COMPATIBLE, &vp3compat, sizeof(vp3compat));
1036 Con_DPrintf("Warning: theora stream is not fully VP3 compatible\n");
1040 if(cls.capturevideo.soundrate)
1042 qvorbis_info_init(&format->vi);
1043 qvorbis_encode_init_vbr(&format->vi, cls.capturevideo.soundchannels, cls.capturevideo.soundrate, bound(-1, cl_capturevideo_ogg_vorbis_quality.value, 10) * 0.099);
1044 qvorbis_comment_init(&vc);
1045 qvorbis_analysis_init(&format->vd, &format->vi);
1046 qvorbis_block_init(&format->vd, &format->vb);
1049 qtheora_comment_init(&tc);
1051 /* create the remaining theora headers */
1052 qtheora_encode_header(&format->ts, &pt);
1053 qogg_stream_packetin(&format->to, &pt);
1054 if (qogg_stream_pageout (&format->to, &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 qtheora_encode_comment(&tc, &pt);
1060 qogg_stream_packetin(&format->to, &pt);
1061 qtheora_encode_tables(&format->ts, &pt);
1062 qogg_stream_packetin (&format->to, &pt);
1064 qtheora_comment_clear(&tc);
1066 if(cls.capturevideo.soundrate)
1068 qvorbis_analysis_headerout(&format->vd, &vc, &pt, &pt2, &pt3);
1069 qogg_stream_packetin(&format->vo, &pt);
1070 if (qogg_stream_pageout (&format->vo, &pg) != 1)
1071 fprintf (stderr, "Internal Ogg library error.\n");
1072 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1073 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1075 qogg_stream_packetin(&format->vo, &pt2);
1076 qogg_stream_packetin(&format->vo, &pt3);
1078 qvorbis_comment_clear(&vc);
1083 int result = qogg_stream_flush (&format->to, &pg);
1085 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
1088 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1089 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1092 if(cls.capturevideo.soundrate)
1095 int result = qogg_stream_flush (&format->vo, &pg);
1097 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
1100 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1101 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);