]> icculus.org git repositories - divverent/darkplaces.git/blob - cap_ogg.c
increase default theora quality from 16 to 32; this about matches the compression...
[divverent/darkplaces.git] / cap_ogg.c
1 #include <sys/types.h>
2
3 #include "quakedef.h"
4 #include "client.h"
5 #include "cap_ogg.h"
6
7 // video capture cvars
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"};
17
18 // ogg.h stuff
19 typedef int16_t ogg_int16_t;
20 typedef u_int16_t ogg_uint16_t;
21 typedef int32_t ogg_int32_t;
22 typedef u_int32_t ogg_uint32_t;
23 typedef int64_t ogg_int64_t;
24
25 typedef struct {
26   long endbyte;
27   int  endbit;
28
29   unsigned char *buffer;
30   unsigned char *ptr;
31   long storage;
32 } oggpack_buffer;
33
34 /* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
35
36 typedef struct {
37   unsigned char *header;
38   long header_len;
39   unsigned char *body;
40   long body_len;
41 } ogg_page;
42
43 /* ogg_stream_state contains the current encode/decode state of a logical
44    Ogg bitstream **********************************************************/
45
46 typedef struct {
47   unsigned char   *body_data;    /* bytes from packet bodies */
48   long    body_storage;          /* storage elements allocated */
49   long    body_fill;             /* elements stored; fill mark */
50   long    body_returned;         /* elements of fill returned */
51
52
53   int     *lacing_vals;      /* The values that will go to the segment table */
54   ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
55                                 this way, but it is simple coupled to the
56                                 lacing fifo */
57   long    lacing_storage;
58   long    lacing_fill;
59   long    lacing_packet;
60   long    lacing_returned;
61
62   unsigned char    header[282];      /* working space for header encode */
63   int              header_fill;
64
65   int     e_o_s;          /* set when we have buffered the last packet in the
66                              logical bitstream */
67   int     b_o_s;          /* set after we've written the initial page
68                              of a logical bitstream */
69   long    serialno;
70   long    pageno;
71   ogg_int64_t  packetno;      /* sequence number for decode; the framing
72                              knows where there's a hole in the data,
73                              but we need coupling so that the codec
74                              (which is in a seperate abstraction
75                              layer) also knows about the gap */
76   ogg_int64_t   granulepos;
77
78 } ogg_stream_state;
79
80 /* ogg_packet is used to encapsulate the data and metadata belonging
81    to a single raw Ogg/Vorbis packet *************************************/
82
83 typedef struct {
84   unsigned char *packet;
85   long  bytes;
86   long  b_o_s;
87   long  e_o_s;
88
89   ogg_int64_t  granulepos;
90   
91   ogg_int64_t  packetno;     /* sequence number for decode; the framing
92                                 knows where there's a hole in the data,
93                                 but we need coupling so that the codec
94                                 (which is in a seperate abstraction
95                                 layer) also knows about the gap */
96 } ogg_packet;
97
98 typedef struct {
99   unsigned char *data;
100   int storage;
101   int fill;
102   int returned;
103
104   int unsynced;
105   int headerbytes;
106   int bodybytes;
107 } ogg_sync_state;
108
109 /* Ogg BITSTREAM PRIMITIVES: encoding **************************/
110
111 static int      (*qogg_stream_packetin) (ogg_stream_state *os, ogg_packet *op);
112 static int      (*qogg_stream_pageout) (ogg_stream_state *os, ogg_page *og);
113 static int      (*qogg_stream_flush) (ogg_stream_state *os, ogg_page *og);
114
115 /* Ogg BITSTREAM PRIMITIVES: general ***************************/
116
117 static int      (*qogg_stream_init) (ogg_stream_state *os,int serialno);
118 static int      (*qogg_stream_clear) (ogg_stream_state *os);
119
120 // end of ogg.h stuff
121
122 // vorbis/codec.h stuff
123 typedef struct vorbis_info{
124   int version;
125   int channels;
126   long rate;
127
128   /* The below bitrate declarations are *hints*.
129      Combinations of the three values carry the following implications:
130
131      all three set to the same value:
132        implies a fixed rate bitstream
133      only nominal set:
134        implies a VBR stream that averages the nominal bitrate.  No hard
135        upper/lower limit
136      upper and or lower set:
137        implies a VBR bitstream that obeys the bitrate limits. nominal
138        may also be set to give a nominal rate.
139      none set:
140        the coder does not care to speculate.
141   */
142
143   long bitrate_upper;
144   long bitrate_nominal;
145   long bitrate_lower;
146   long bitrate_window;
147
148   void *codec_setup;
149 } vorbis_info;
150
151 /* vorbis_dsp_state buffers the current vorbis audio
152    analysis/synthesis state.  The DSP state belongs to a specific
153    logical bitstream ****************************************************/
154 typedef struct vorbis_dsp_state{
155   int analysisp;
156   vorbis_info *vi;
157
158   float **pcm;
159   float **pcmret;
160   int      pcm_storage;
161   int      pcm_current;
162   int      pcm_returned;
163
164   int  preextrapolate;
165   int  eofflag;
166
167   long lW;
168   long W;
169   long nW;
170   long centerW;
171
172   ogg_int64_t granulepos;
173   ogg_int64_t sequence;
174
175   ogg_int64_t glue_bits;
176   ogg_int64_t time_bits;
177   ogg_int64_t floor_bits;
178   ogg_int64_t res_bits;
179
180   void       *backend_state;
181 } vorbis_dsp_state;
182
183 typedef struct vorbis_block{
184   /* necessary stream state for linking to the framing abstraction */
185   float  **pcm;       /* this is a pointer into local storage */
186   oggpack_buffer opb;
187
188   long  lW;
189   long  W;
190   long  nW;
191   int   pcmend;
192   int   mode;
193
194   int         eofflag;
195   ogg_int64_t granulepos;
196   ogg_int64_t sequence;
197   vorbis_dsp_state *vd; /* For read-only access of configuration */
198
199   /* local storage to avoid remallocing; it's up to the mapping to
200      structure it */
201   void               *localstore;
202   long                localtop;
203   long                localalloc;
204   long                totaluse;
205   struct alloc_chain *reap;
206
207   /* bitmetrics for the frame */
208   long glue_bits;
209   long time_bits;
210   long floor_bits;
211   long res_bits;
212
213   void *internal;
214
215 } vorbis_block;
216
217 /* vorbis_block is a single block of data to be processed as part of
218 the analysis/synthesis stream; it belongs to a specific logical
219 bitstream, but is independant from other vorbis_blocks belonging to
220 that logical bitstream. *************************************************/
221
222 struct alloc_chain{
223   void *ptr;
224   struct alloc_chain *next;
225 };
226
227 /* vorbis_info contains all the setup information specific to the
228    specific compression/decompression mode in progress (eg,
229    psychoacoustic settings, channel setup, options, codebook
230    etc). vorbis_info and substructures are in backends.h.
231 *********************************************************************/
232
233 /* the comments are not part of vorbis_info so that vorbis_info can be
234    static storage */
235 typedef struct vorbis_comment{
236   /* unlimited user comment fields.  libvorbis writes 'libvorbis'
237      whatever vendor is set to in encode */
238   char **user_comments;
239   int   *comment_lengths;
240   int    comments;
241   char  *vendor;
242
243 } vorbis_comment;
244
245
246 /* libvorbis encodes in two abstraction layers; first we perform DSP
247    and produce a packet (see docs/analysis.txt).  The packet is then
248    coded into a framed OggSquish bitstream by the second layer (see
249    docs/framing.txt).  Decode is the reverse process; we sync/frame
250    the bitstream and extract individual packets, then decode the
251    packet back into PCM audio.
252
253    The extra framing/packetizing is used in streaming formats, such as
254    files.  Over the net (such as with UDP), the framing and
255    packetization aren't necessary as they're provided by the transport
256    and the streaming layer is not used */
257
258 /* Vorbis PRIMITIVES: general ***************************************/
259
260 static void     (*qvorbis_info_init) (vorbis_info *vi);
261 static void     (*qvorbis_info_clear) (vorbis_info *vi);
262 static void     (*qvorbis_comment_init) (vorbis_comment *vc);
263 static void     (*qvorbis_comment_clear) (vorbis_comment *vc);
264
265 static int      (*qvorbis_block_init) (vorbis_dsp_state *v, vorbis_block *vb);
266 static int      (*qvorbis_block_clear) (vorbis_block *vb);
267 static void     (*qvorbis_dsp_clear) (vorbis_dsp_state *v);
268
269 /* Vorbis PRIMITIVES: analysis/DSP layer ****************************/
270
271 static int      (*qvorbis_analysis_init) (vorbis_dsp_state *v,vorbis_info *vi);
272 static int      (*qvorbis_commentheader_out) (vorbis_comment *vc, ogg_packet *op);
273 static int      (*qvorbis_analysis_headerout) (vorbis_dsp_state *v,
274                                           vorbis_comment *vc,
275                                           ogg_packet *op,
276                                           ogg_packet *op_comm,
277                                           ogg_packet *op_code);
278 static float ** (*qvorbis_analysis_buffer) (vorbis_dsp_state *v,int vals);
279 static int      (*qvorbis_analysis_wrote) (vorbis_dsp_state *v,int vals);
280 static int      (*qvorbis_analysis_blockout) (vorbis_dsp_state *v,vorbis_block *vb);
281 static int      (*qvorbis_analysis) (vorbis_block *vb,ogg_packet *op);
282
283 static int      (*qvorbis_bitrate_addblock) (vorbis_block *vb);
284 static int      (*qvorbis_bitrate_flushpacket) (vorbis_dsp_state *vd,
285                                            ogg_packet *op);
286
287 // end of vorbis/codec.h stuff
288
289 // vorbisenc.h stuff
290 static int (*qvorbis_encode_init_vbr) (vorbis_info *vi,
291                                   long channels,
292                                   long rate,
293
294                                   float base_quality /* quality level from 0. (lo) to 1. (hi) */
295                                   );
296 // end of vorbisenc.h stuff
297
298 // theora.h stuff
299 typedef struct {
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 */
303
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 */
310
311 } yuv_buffer;
312
313 /**
314  * A Colorspace.
315  */
316 typedef enum {
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 */
321 } theora_colorspace;
322
323 /**
324  * A Chroma subsampling
325  *
326  * These enumerate the available chroma subsampling options supported
327  * by the theora format. See Section 4.4 of the specification for
328  * exact definitions.
329  */
330 typedef enum {
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;
336 /**
337  * Theora bitstream info.
338  * Contains the basic playback parameters for a stream,
339  * corresponding to the initial 'info' header packet.
340  * 
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.
347  *
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.
352  * 
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.
356  */
357 typedef struct {
358   ogg_uint32_t  width;      /**< encoded frame width  */
359   ogg_uint32_t  height;     /**< encoded frame height */
360   ogg_uint32_t  frame_width;    /**< display frame width  */
361   ogg_uint32_t  frame_height;   /**< display frame height */
362   ogg_uint32_t  offset_x;   /**< horizontal offset of the displayed frame */
363   ogg_uint32_t  offset_y;   /**< vertical offset of the displayed frame */
364   ogg_uint32_t  fps_numerator;      /**< frame rate numerator **/
365   ogg_uint32_t  fps_denominator;    /**< frame rate denominator **/
366   ogg_uint32_t  aspect_numerator;   /**< pixel aspect ratio numerator */
367   ogg_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 */
372
373   /* decode only */
374   unsigned char version_major;
375   unsigned char version_minor;
376   unsigned char version_subminor;
377
378   void *codec_setup;
379
380   /* encode only */
381   int           dropframes_p;
382   int           keyframe_auto_p;
383   ogg_uint32_t  keyframe_frequency;
384   ogg_uint32_t  keyframe_frequency_force;  /* also used for decode init to
385                                               get granpos shift correct */
386   ogg_uint32_t  keyframe_data_target_bitrate;
387   ogg_int32_t   keyframe_auto_threshold;
388   ogg_uint32_t  keyframe_mindistance;
389   ogg_int32_t   noise_sensitivity;
390   ogg_int32_t   sharpness;
391
392   theora_pixelformat pixelformat;   /**< chroma subsampling mode to expect */
393
394 } theora_info;
395
396 /** Codec internal state and context.
397  */
398 typedef struct{
399   theora_info *i;
400   ogg_int64_t granulepos;
401
402   void *internal_encode;
403   void *internal_decode;
404
405 } theora_state;
406
407 /** 
408  * Comment header metadata.
409  *
410  * This structure holds the in-stream metadata corresponding to
411  * the 'comment' header packet.
412  *
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.
419  *
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
424  * for their length.
425  */
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 */
431
432 } theora_comment;
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,
436                                     ogg_packet *op);
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 // end of theora.h stuff
446
447 static dllfunction_t oggfuncs[] =
448 {
449         {"ogg_stream_packetin", (void **) &qogg_stream_packetin},
450         {"ogg_stream_pageout", (void **) &qogg_stream_pageout},
451         {"ogg_stream_flush", (void **) &qogg_stream_flush},
452         {"ogg_stream_init", (void **) &qogg_stream_init},
453         {"ogg_stream_clear", (void **) &qogg_stream_clear},
454         {NULL, NULL}
455 };
456
457 static dllfunction_t vorbisencfuncs[] =
458 {
459         {"vorbis_encode_init_vbr", (void **) &qvorbis_encode_init_vbr},
460         {NULL, NULL}
461 };
462
463 static dllfunction_t vorbisfuncs[] =
464 {
465         {"vorbis_info_init", (void **) &qvorbis_info_init},
466         {"vorbis_info_clear", (void **) &qvorbis_info_clear},
467         {"vorbis_comment_init", (void **) &qvorbis_comment_init},
468         {"vorbis_comment_clear", (void **) &qvorbis_comment_clear},
469         {"vorbis_block_init", (void **) &qvorbis_block_init},
470         {"vorbis_block_clear", (void **) &qvorbis_block_clear},
471         {"vorbis_dsp_clear", (void **) &qvorbis_dsp_clear},
472         {"vorbis_analysis_init", (void **) &qvorbis_analysis_init},
473         {"vorbis_commentheader_out", (void **) &qvorbis_commentheader_out},
474         {"vorbis_analysis_headerout", (void **) &qvorbis_analysis_headerout},
475         {"vorbis_analysis_buffer", (void **) &qvorbis_analysis_buffer},
476         {"vorbis_analysis_wrote", (void **) &qvorbis_analysis_wrote},
477         {"vorbis_analysis_blockout", (void **) &qvorbis_analysis_blockout},
478         {"vorbis_analysis", (void **) &qvorbis_analysis},
479         {"vorbis_bitrate_addblock", (void **) &qvorbis_bitrate_addblock},
480         {"vorbis_bitrate_flushpacket", (void **) &qvorbis_bitrate_flushpacket},
481         {NULL, NULL}
482 };
483
484 static dllfunction_t theorafuncs[] =
485 {
486         {"theora_info_init", (void **) &qtheora_info_init},
487         {"theora_info_clear", (void **) &qtheora_info_clear},
488         {"theora_comment_init", (void **) &qtheora_comment_init},
489         {"theora_comment_clear", (void **) &qtheora_comment_clear},
490         {"theora_encode_init", (void **) &qtheora_encode_init},
491         {"theora_encode_YUVin", (void **) &qtheora_encode_YUVin},
492         {"theora_encode_packetout", (void **) &qtheora_encode_packetout},
493         {"theora_encode_header", (void **) &qtheora_encode_header},
494         {"theora_encode_comment", (void **) &qtheora_encode_comment},
495         {"theora_encode_tables", (void **) &qtheora_encode_tables},
496         {"theora_clear", (void **) &qtheora_clear},
497         {NULL, NULL}
498 };
499
500 static dllhandle_t og_dll = NULL, vo_dll = NULL, ve_dll = NULL, th_dll = NULL;
501
502 qboolean SCR_CaptureVideo_Ogg_OpenLibrary()
503 {
504         const char* dllnames_og [] =
505         {
506 #if defined(WIN64)
507                 "libogg64.dll",
508 #elif defined(WIN32)
509                 "libogg.dll",
510                 "ogg.dll",
511 #elif defined(MACOSX)
512                 "libogg.dylib",
513 #else
514                 "libogg.so.0",
515                 "libogg.so",
516 #endif
517                 NULL
518         };
519         const char* dllnames_vo [] =
520         {
521 #if defined(WIN64)
522                 "libvorbis64.dll",
523 #elif defined(WIN32)
524                 "libvorbis.dll",
525                 "vorbis.dll",
526 #elif defined(MACOSX)
527                 "libvorbis.dylib",
528 #else
529                 "libvorbis.so.0",
530                 "libvorbis.so",
531 #endif
532                 NULL
533         };
534         const char* dllnames_ve [] =
535         {
536 #if defined(WIN64)
537                 "libvorbisenc64.dll",
538 #elif defined(WIN32)
539                 "libvorbisenc.dll",
540                 "vorbisenc.dll",
541 #elif defined(MACOSX)
542                 "libvorbisenc.dylib",
543 #else
544                 "libvorbisenc.so.2",
545                 "libvorbisenc.so",
546 #endif
547                 NULL
548         };
549         const char* dllnames_th [] =
550         {
551 #if defined(WIN64)
552                 "libtheora64.dll",
553 #elif defined(WIN32)
554                 "libtheora.dll",
555                 "theora.dll",
556 #elif defined(MACOSX)
557                 "libtheora.dylib",
558 #else
559                 "libtheora.so.0",
560                 "libtheora.so",
561 #endif
562                 NULL
563         };
564
565         return
566                 Sys_LoadLibrary (dllnames_og, &og_dll, oggfuncs)
567                 &&
568                 Sys_LoadLibrary (dllnames_th, &th_dll, theorafuncs)
569                 &&
570                 Sys_LoadLibrary (dllnames_vo, &vo_dll, vorbisfuncs)
571                 &&
572                 Sys_LoadLibrary (dllnames_ve, &ve_dll, vorbisencfuncs);
573 }
574
575 void SCR_CaptureVideo_Ogg_Init()
576 {
577         SCR_CaptureVideo_Ogg_OpenLibrary();
578
579         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_quality);
580         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_bitrate);
581         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier);
582         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_frequency);
583         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_mindistance);
584         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_auto_threshold);
585         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_noise_sensitivity);
586         Cvar_RegisterVariable(&cl_capturevideo_ogg_vorbis_quality);
587 }
588
589 qboolean SCR_CaptureVideo_Ogg_Available()
590 {
591         return og_dll && th_dll && vo_dll && ve_dll;
592 }
593
594 void SCR_CaptureVideo_Ogg_CloseDLL()
595 {
596         Sys_UnloadLibrary (&ve_dll);
597         Sys_UnloadLibrary (&vo_dll);
598         Sys_UnloadLibrary (&th_dll);
599         Sys_UnloadLibrary (&og_dll);
600 }
601
602 typedef struct capturevideostate_ogg_formatspecific_s
603 {
604         ogg_stream_state to, vo;
605         int serial1, serial2;
606         theora_state ts;
607         vorbis_dsp_state vd;
608         vorbis_block vb;
609         vorbis_info vi;
610         yuv_buffer yuv;
611         int channels;
612 }
613 capturevideostate_ogg_formatspecific_t;
614 #define LOAD_FORMATSPECIFIC_OGG() capturevideostate_ogg_formatspecific_t *format = (capturevideostate_ogg_formatspecific_t *) cls.capturevideo.formatspecific
615
616 static void SCR_CaptureVideo_Ogg_EndVideo()
617 {
618         LOAD_FORMATSPECIFIC_OGG();
619         ogg_page pg;
620         ogg_packet pt;
621
622         // repeat the last frame so we can set the end-of-stream flag
623         qtheora_encode_YUVin(&format->ts, &format->yuv);
624         qtheora_encode_packetout(&format->ts, true, &pt);
625         qogg_stream_packetin(&format->to, &pt);
626
627         if(cls.capturevideo.soundrate)
628         {
629                 qvorbis_analysis_wrote(&format->vd, 0);
630                 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
631                 {
632                         qvorbis_analysis(&format->vb, NULL);
633                         qvorbis_bitrate_addblock(&format->vb);
634                         while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
635                                 qogg_stream_packetin(&format->vo, &pt);
636                 }
637         }
638
639         while(qogg_stream_pageout(&format->to, &pg) > 0)
640         {
641                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
642                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
643         }
644
645         if(cls.capturevideo.soundrate)
646         {
647                 while(qogg_stream_pageout(&format->vo, &pg) > 0)
648                 {
649                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
650                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
651                 }
652         }
653                 
654         while (1) {
655                 int result = qogg_stream_flush (&format->to, &pg);
656                 if (result < 0)
657                         fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
658                 if (result <= 0)
659                         break;
660                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
661                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
662         }
663
664         if(cls.capturevideo.soundrate)
665         {
666                 while (1) {
667                         int result = qogg_stream_flush (&format->vo, &pg);
668                         if (result < 0)
669                                 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
670                         if (result <= 0)
671                                 break;
672                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
673                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
674                 }
675
676                 qogg_stream_clear(&format->vo);
677                 qvorbis_block_clear(&format->vb);
678                 qvorbis_dsp_clear(&format->vd);
679         }
680
681         qogg_stream_clear(&format->to);
682         qtheora_clear(&format->ts);
683         qvorbis_info_clear(&format->vi);
684
685         Mem_Free(format->yuv.y);
686         Mem_Free(format->yuv.u);
687         Mem_Free(format->yuv.v);
688         Mem_Free(format);
689
690         FS_Close(cls.capturevideo.videofile);
691         cls.capturevideo.videofile = NULL;
692 }
693
694 static void SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV()
695 {
696         LOAD_FORMATSPECIFIC_OGG();
697         int x, y;
698         int blockr, blockg, blockb;
699         unsigned char *b = cls.capturevideo.outbuffer;
700         int w = cls.capturevideo.width;
701         int h = cls.capturevideo.height;
702         int inpitch = w*4;
703
704         for(y = 0; y < h; ++y)
705         {
706                 for(b = cls.capturevideo.outbuffer + (h-1-y)*w*4, x = 0; x < w; ++x)
707                 {
708                         blockr = b[2];
709                         blockg = b[1];
710                         blockb = b[0];
711                         format->yuv.y[x + format->yuv.y_stride * y] =
712                                 cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]];
713                         b += 4;
714                 }
715
716                 if((y & 1) == 0)
717                 {
718                         for(b = cls.capturevideo.outbuffer + (h-2-y)*w*4, x = 0; x < w/2; ++x)
719                         {
720                                 blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2;
721                                 blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2;
722                                 blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2;
723                                 format->yuv.u[x + format->yuv.uv_stride * (y/2)] =
724                                         cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128];
725                                 format->yuv.v[x + format->yuv.uv_stride * (y/2)] =
726                                         cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128];
727                                 b += 8;
728                         }
729                 }
730         }
731 }
732
733 static void SCR_CaptureVideo_Ogg_VideoFrames(int num)
734 {
735         LOAD_FORMATSPECIFIC_OGG();
736         ogg_page pg;
737         ogg_packet pt;
738
739         // data is in cls.capturevideo.outbuffer as BGRA and has size width*height
740
741         SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV();
742
743         while(num-- > 0)
744         {
745                 qtheora_encode_YUVin(&format->ts, &format->yuv);
746                 qtheora_encode_packetout(&format->ts, false, &pt);
747                 qogg_stream_packetin(&format->to, &pt);
748
749                 while(qogg_stream_pageout(&format->to, &pg) > 0)
750                 {
751                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
752                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
753                 }
754         }
755 }
756
757 static void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
758 {
759         LOAD_FORMATSPECIFIC_OGG();
760         float **vorbis_buffer;
761         size_t i;
762         int j;
763         ogg_page pg;
764         ogg_packet pt;
765
766         vorbis_buffer = qvorbis_analysis_buffer(&format->vd, length);
767         for(i = 0; i < length; ++i)
768         {
769                 for(j = 0; j < cls.capturevideo.soundchannels; ++j)
770                         vorbis_buffer[j][i] = paintbuffer[i].sample[j] / 32768.0f;
771         }
772         qvorbis_analysis_wrote(&format->vd, length);
773
774         while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
775         {
776                 qvorbis_analysis(&format->vb, NULL);
777                 qvorbis_bitrate_addblock(&format->vb);
778
779                 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
780                         qogg_stream_packetin(&format->vo, &pt);
781         }
782
783         while(qogg_stream_pageout(&format->vo, &pg) > 0)
784         {
785                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
786                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
787         }
788 }
789
790 void SCR_CaptureVideo_Ogg_BeginVideo()
791 {
792         cls.capturevideo.format = CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA;
793         cls.capturevideo.videofile = FS_OpenRealFile(va("%s.ogv", cls.capturevideo.basename), "wb", false);
794         cls.capturevideo.endvideo = SCR_CaptureVideo_Ogg_EndVideo;
795         cls.capturevideo.videoframes = SCR_CaptureVideo_Ogg_VideoFrames;
796         cls.capturevideo.soundframe = SCR_CaptureVideo_Ogg_SoundFrame;
797         cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_ogg_formatspecific_t));
798         {
799                 LOAD_FORMATSPECIFIC_OGG();
800                 int num, denom;
801                 ogg_page pg;
802                 ogg_packet pt, pt2, pt3;
803                 theora_comment tc;
804                 vorbis_comment vc;
805                 theora_info ti;
806
807                 format->serial1 = rand();
808                 qogg_stream_init(&format->to, format->serial1);
809
810                 if(cls.capturevideo.soundrate)
811                 {
812                         do
813                         {
814                                 format->serial2 = rand();
815                         }
816                         while(format->serial1 == format->serial2);
817                         qogg_stream_init(&format->vo, format->serial2);
818                 }
819
820                 qtheora_info_init(&ti);
821                 ti.frame_width = cls.capturevideo.width;
822                 ti.frame_height = cls.capturevideo.height;
823                 ti.width = (ti.frame_width + 15) & ~15;
824                 ti.height = (ti.frame_height + 15) & ~15;
825                 //ti.offset_x = ((ti.width - ti.frame_width) / 2) & ~1;
826                 //ti.offset_y = ((ti.height - ti.frame_height) / 2) & ~1;
827
828                 format->yuv.y_width = ti.width;
829                 format->yuv.y_height = ti.height;
830                 format->yuv.y_stride = ti.width;
831
832                 format->yuv.uv_width = ti.width / 2;
833                 format->yuv.uv_height = ti.height / 2;
834                 format->yuv.uv_stride = ti.width / 2;
835
836                 format->yuv.y = Mem_Alloc(tempmempool, format->yuv.y_stride * format->yuv.y_height);
837                 format->yuv.u = Mem_Alloc(tempmempool, format->yuv.uv_stride * format->yuv.uv_height);
838                 format->yuv.v = Mem_Alloc(tempmempool, format->yuv.uv_stride * format->yuv.uv_height);
839
840                 FindFraction(cls.capturevideo.framerate, &num, &denom, 1001);
841                 ti.fps_numerator = num;
842                 ti.fps_denominator = denom;
843
844                 FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000);
845                 ti.aspect_numerator = num;
846                 ti.aspect_denominator = denom;
847
848                 ti.colorspace = OC_CS_UNSPECIFIED;
849                 ti.pixelformat = OC_PF_420;
850
851                 ti.quick_p = true; // http://mlblog.osdir.com/multimedia.ogg.theora.general/2004-07/index.shtml
852                 ti.dropframes_p = false;
853
854                 ti.target_bitrate = cl_capturevideo_ogg_theora_bitrate.integer * 1000;
855                 ti.quality = cl_capturevideo_ogg_theora_quality.integer;
856
857                 if(ti.target_bitrate <= 0)
858                 {
859                         if(ti.quality < 0)
860                         {
861                                 ti.target_bitrate = -1;
862                                 ti.keyframe_data_target_bitrate = -1;
863                                 ti.quality = 63;
864                         }
865                         else
866                         {
867                                 ti.target_bitrate = -1;
868                                 ti.keyframe_data_target_bitrate = -1;
869                                 ti.quality = bound(0, ti.quality, 63);
870                         }
871                 }
872                 else
873                 {
874                         if(ti.quality < 0)
875                         {
876                                 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
877                                 ti.keyframe_data_target_bitrate = ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value);
878                                 ti.quality = -1;
879                         }
880                         else
881                         {
882                                 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
883                                 ti.keyframe_data_target_bitrate = ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value);
884                                 ti.quality = -1;
885                         }
886                 }
887
888                 ti.keyframe_frequency = bound(1, cl_capturevideo_ogg_theora_keyframe_frequency.integer, 1000);
889                 ti.keyframe_mindistance = bound(1, cl_capturevideo_ogg_theora_keyframe_mindistance.integer, (int) ti.keyframe_frequency);
890                 ti.noise_sensitivity = bound(0, cl_capturevideo_ogg_theora_noise_sensitivity.integer, 6);
891                 ti.sharpness = bound(0, cl_capturevideo_ogg_theora_sharpness.integer, 2);
892                 ti.keyframe_auto_threshold = bound(0, cl_capturevideo_ogg_theora_keyframe_auto_threshold.integer, 100);
893
894                 ti.keyframe_frequency_force = ti.keyframe_frequency;
895                 ti.keyframe_auto_p = (ti.keyframe_frequency != ti.keyframe_mindistance);
896
897                 qtheora_encode_init(&format->ts, &ti);
898                 qtheora_info_clear(&ti);
899
900                 // vorbis?
901                 if(cls.capturevideo.soundrate)
902                 {
903                         qvorbis_info_init(&format->vi);
904                         qvorbis_encode_init_vbr(&format->vi, cls.capturevideo.soundchannels, cls.capturevideo.soundrate, bound(-1, cl_capturevideo_ogg_vorbis_quality.value, 10) * 0.099);
905                         qvorbis_comment_init(&vc);
906                         qvorbis_analysis_init(&format->vd, &format->vi);
907                         qvorbis_block_init(&format->vd, &format->vb);
908                 }
909
910                 qtheora_comment_init(&tc);
911
912                 /* create the remaining theora headers */
913                 qtheora_encode_header(&format->ts, &pt);
914                 qogg_stream_packetin(&format->to, &pt);
915                 if (qogg_stream_pageout (&format->to, &pg) != 1)
916                         fprintf (stderr, "Internal Ogg library error.\n");
917                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
918                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
919
920                 qtheora_encode_comment(&tc, &pt);
921                 qogg_stream_packetin(&format->to, &pt);
922                 qtheora_encode_tables(&format->ts, &pt);
923                 qogg_stream_packetin (&format->to, &pt);
924
925                 qtheora_comment_clear(&tc);
926
927                 if(cls.capturevideo.soundrate)
928                 {
929                         qvorbis_analysis_headerout(&format->vd, &vc, &pt, &pt2, &pt3);
930                         qogg_stream_packetin(&format->vo, &pt);
931                         if (qogg_stream_pageout (&format->vo, &pg) != 1)
932                                 fprintf (stderr, "Internal Ogg library error.\n");
933                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
934                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
935
936                         qogg_stream_packetin(&format->vo, &pt2);
937                         qogg_stream_packetin(&format->vo, &pt3);
938
939                         qvorbis_comment_clear(&vc);
940                 }
941
942                 for(;;)
943                 {
944                         int result = qogg_stream_flush (&format->to, &pg);
945                         if (result < 0)
946                                 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
947                         if (result <= 0)
948                                 break;
949                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
950                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
951                 }
952
953                 if(cls.capturevideo.soundrate)
954                 for(;;)
955                 {
956                         int result = qogg_stream_flush (&format->vo, &pg);
957                         if (result < 0)
958                                 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
959                         if (result <= 0)
960                                 break;
961                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
962                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
963                 }
964         }
965 }