]> icculus.org git repositories - divverent/darkplaces.git/blob - cap_ogg.c
Add some cvars for vorbis/theora video encoding; their defaults match the defaults...
[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", "16", "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_quality", "-1", "video bitrate (45000 to 2000000 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", "5", "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         yuv_buffer yuv;
610         int channels;
611 }
612 capturevideostate_ogg_formatspecific_t;
613 #define LOAD_FORMATSPECIFIC() capturevideostate_ogg_formatspecific_t *format = (capturevideostate_ogg_formatspecific_t *) cls.capturevideo.formatspecific
614
615 void SCR_CaptureVideo_Ogg_Begin()
616 {
617         cls.capturevideo.videofile = FS_OpenRealFile(va("%s.ogv", cls.capturevideo.basename), "wb", false);
618         cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_ogg_formatspecific_t));
619         {
620                 LOAD_FORMATSPECIFIC();
621                 int num, denom;
622                 ogg_page pg;
623                 ogg_packet pt, pt2, pt3;
624                 theora_comment tc;
625                 vorbis_comment vc;
626                 theora_info ti;
627                 vorbis_info vi;
628
629                 format->serial1 = rand();
630                 qogg_stream_init(&format->to, format->serial1);
631
632                 if(cls.capturevideo.soundrate)
633                 {
634                         do
635                         {
636                                 format->serial2 = rand();
637                         }
638                         while(format->serial1 == format->serial2);
639                         qogg_stream_init(&format->vo, format->serial2);
640                 }
641
642                 qtheora_info_init(&ti);
643                 ti.frame_width = cls.capturevideo.width;
644                 ti.frame_height = cls.capturevideo.height;
645                 ti.width = (ti.frame_width + 15) & ~15;
646                 ti.height = (ti.frame_height + 15) & ~15;
647                 //ti.offset_x = ((ti.width - ti.frame_width) / 2) & ~1;
648                 //ti.offset_y = ((ti.height - ti.frame_height) / 2) & ~1;
649
650                 format->yuv.y_width = ti.width;
651                 format->yuv.y_height = ti.height;
652                 format->yuv.y_stride = ti.width;
653
654                 format->yuv.uv_width = ti.width / 2;
655                 format->yuv.uv_height = ti.height / 2;
656                 format->yuv.uv_stride = ti.width / 2;
657
658                 format->yuv.y = Mem_Alloc(tempmempool, format->yuv.y_stride * format->yuv.y_height);
659                 format->yuv.u = Mem_Alloc(tempmempool, format->yuv.uv_stride * format->yuv.uv_height);
660                 format->yuv.v = Mem_Alloc(tempmempool, format->yuv.uv_stride * format->yuv.uv_height);
661
662                 FindFraction(cls.capturevideo.framerate, &num, &denom, 1001);
663                 ti.fps_numerator = num;
664                 ti.fps_denominator = denom;
665
666                 FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000);
667                 ti.aspect_numerator = num;
668                 ti.aspect_denominator = denom;
669
670                 ti.colorspace = OC_CS_UNSPECIFIED;
671                 ti.pixelformat = OC_PF_420;
672
673                 ti.quick_p = true; // http://mlblog.osdir.com/multimedia.ogg.theora.general/2004-07/index.shtml
674                 ti.dropframes_p = false;
675
676                 ti.target_bitrate = cl_capturevideo_ogg_theora_bitrate.integer;
677                 ti.quality = cl_capturevideo_ogg_theora_quality.integer;
678
679                 if(ti.target_bitrate <= 0)
680                 {
681                         if(ti.quality < 0)
682                         {
683                                 ti.target_bitrate = -1;
684                                 ti.keyframe_data_target_bitrate = -1;
685                                 ti.quality = 63;
686                         }
687                         else
688                         {
689                                 ti.target_bitrate = -1;
690                                 ti.keyframe_data_target_bitrate = -1;
691                                 ti.quality = bound(0, ti.quality, 63);
692                         }
693                 }
694                 else
695                 {
696                         if(ti.quality < 0)
697                         {
698                                 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
699                                 ti.keyframe_data_target_bitrate = ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value);
700                                 ti.quality = -1;
701                         }
702                         else
703                         {
704                                 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
705                                 ti.keyframe_data_target_bitrate = ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value);
706                                 ti.quality = -1;
707                         }
708                 }
709
710                 ti.keyframe_frequency = bound(1, cl_capturevideo_ogg_theora_keyframe_frequency.integer, 1000);
711                 ti.keyframe_mindistance = bound(1, cl_capturevideo_ogg_theora_keyframe_mindistance.integer, (int) ti.keyframe_frequency);
712                 ti.noise_sensitivity = bound(0, cl_capturevideo_ogg_theora_noise_sensitivity.integer, 6);
713                 ti.sharpness = bound(0, cl_capturevideo_ogg_theora_sharpness.integer, 2);
714                 ti.keyframe_auto_threshold = bound(0, cl_capturevideo_ogg_theora_keyframe_auto_threshold.integer, 100);
715
716                 ti.keyframe_frequency_force = ti.keyframe_frequency;
717                 ti.keyframe_auto_p = (ti.keyframe_frequency != ti.keyframe_mindistance);
718
719                 qtheora_encode_init(&format->ts, &ti);
720                 qtheora_info_clear(&ti);
721
722                 // vorbis?
723                 if(cls.capturevideo.soundrate)
724                 {
725                         qvorbis_info_init(&vi);
726                         qvorbis_encode_init_vbr(&vi, cls.capturevideo.soundchannels, cls.capturevideo.soundrate, bound(-1, cl_capturevideo_ogg_vorbis_quality.value, 10) * 0.1);
727                         qvorbis_comment_init(&vc);
728                         qvorbis_analysis_init(&format->vd, &vi);
729                         qvorbis_block_init(&format->vd, &format->vb);
730                 }
731
732                 qtheora_comment_init(&tc);
733
734                 /* create the remaining theora headers */
735                 qtheora_encode_header(&format->ts, &pt);
736                 qogg_stream_packetin(&format->to, &pt);
737                 if (qogg_stream_pageout (&format->to, &pg) != 1)
738                         fprintf (stderr, "Internal Ogg library error.\n");
739                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
740                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
741
742                 qtheora_encode_comment(&tc, &pt);
743                 qogg_stream_packetin(&format->to, &pt);
744                 qtheora_encode_tables(&format->ts, &pt);
745                 qogg_stream_packetin (&format->to, &pt);
746
747                 qtheora_comment_clear(&tc);
748
749                 if(cls.capturevideo.soundrate)
750                 {
751                         qvorbis_analysis_headerout(&format->vd, &vc, &pt, &pt2, &pt3);
752                         qogg_stream_packetin(&format->vo, &pt);
753                         if (qogg_stream_pageout (&format->vo, &pg) != 1)
754                                 fprintf (stderr, "Internal Ogg library error.\n");
755                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
756                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
757
758                         qogg_stream_packetin(&format->vo, &pt2);
759                         qogg_stream_packetin(&format->vo, &pt3);
760
761                         qvorbis_comment_clear(&vc);
762                         qvorbis_info_clear(&vi);
763                 }
764
765                 for(;;)
766                 {
767                         int result = qogg_stream_flush (&format->to, &pg);
768                         if (result < 0)
769                                 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
770                         if (result <= 0)
771                                 break;
772                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
773                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
774                 }
775
776                 if(cls.capturevideo.soundrate)
777                 for(;;)
778                 {
779                         int result = qogg_stream_flush (&format->vo, &pg);
780                         if (result < 0)
781                                 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
782                         if (result <= 0)
783                                 break;
784                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
785                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
786                 }
787         }
788 }
789
790 void SCR_CaptureVideo_Ogg_EndVideo()
791 {
792         LOAD_FORMATSPECIFIC();
793         ogg_page pg;
794         ogg_packet pt;
795
796         // repeat the last frame so we can set the end-of-stream flag
797         qtheora_encode_YUVin(&format->ts, &format->yuv);
798         qtheora_encode_packetout(&format->ts, true, &pt);
799         qogg_stream_packetin(&format->to, &pt);
800
801         if(cls.capturevideo.soundrate)
802         {
803                 qvorbis_analysis_wrote(&format->vd, 0);
804                 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
805                 {
806                         qvorbis_analysis(&format->vb, NULL);
807                         qvorbis_bitrate_addblock(&format->vb);
808                         while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
809                                 qogg_stream_packetin(&format->vo, &pt);
810                 }
811         }
812
813         if(qogg_stream_pageout(&format->to, &pg) > 0)
814         {
815                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
816                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
817         }
818
819         if(cls.capturevideo.soundrate)
820         {
821                 if(qogg_stream_pageout(&format->vo, &pg) > 0)
822                 {
823                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
824                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
825                 }
826         }
827                 
828         while (1) {
829                 int result = qogg_stream_flush (&format->to, &pg);
830                 if (result < 0)
831                         fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
832                 if (result <= 0)
833                         break;
834                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
835                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
836         }
837
838         if(cls.capturevideo.soundrate)
839         {
840                 while (1) {
841                         int result = qogg_stream_flush (&format->vo, &pg);
842                         if (result < 0)
843                                 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
844                         if (result <= 0)
845                                 break;
846                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
847                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
848                 }
849
850                 qogg_stream_clear(&format->vo);
851                 qvorbis_block_clear(&format->vb);
852                 qvorbis_dsp_clear(&format->vd);
853         }
854
855         qogg_stream_clear(&format->to);
856         qtheora_clear(&format->ts);
857
858         Mem_Free(format->yuv.y);
859         Mem_Free(format->yuv.u);
860         Mem_Free(format->yuv.v);
861         Mem_Free(format);
862
863         // cl_screen.c does this
864         // FS_Close(cls.capturevideo.videofile);
865         // cls.capturevideo.videofile = NULL;
866 }
867
868 void SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV()
869 {
870         LOAD_FORMATSPECIFIC();
871         int x, y;
872         int blockr, blockg, blockb;
873         unsigned char *b = cls.capturevideo.outbuffer;
874         int w = cls.capturevideo.width;
875         int h = cls.capturevideo.height;
876         int inpitch = w*4;
877
878         for(y = 0; y < h; ++y)
879         {
880                 for(b = cls.capturevideo.outbuffer + (h-1-y)*w*4, x = 0; x < w; ++x)
881                 {
882                         blockr = b[2];
883                         blockg = b[1];
884                         blockb = b[0];
885                         format->yuv.y[x + format->yuv.y_stride * y] =
886                                 cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]];
887                         b += 4;
888                 }
889
890                 if((y & 1) == 0)
891                 {
892                         for(b = cls.capturevideo.outbuffer + (h-2-y)*w*4, x = 0; x < w/2; ++x)
893                         {
894                                 blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2;
895                                 blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2;
896                                 blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2;
897                                 format->yuv.u[x + format->yuv.uv_stride * (y/2)] =
898                                         cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128];
899                                 format->yuv.v[x + format->yuv.uv_stride * (y/2)] =
900                                         cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128];
901                                 b += 8;
902                         }
903                 }
904         }
905 }
906
907 void SCR_CaptureVideo_Ogg_VideoFrame()
908 {
909         LOAD_FORMATSPECIFIC();
910         ogg_page pg;
911         ogg_packet pt;
912
913         // data is in cls.capturevideo.outbuffer as BGRA and has size width*height
914
915         SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV();
916         qtheora_encode_YUVin(&format->ts, &format->yuv);
917         qtheora_encode_packetout(&format->ts, false, &pt);
918         qogg_stream_packetin(&format->to, &pt);
919
920         while(qogg_stream_pageout(&format->to, &pg) > 0)
921         {
922                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
923                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
924         }
925 }
926
927 void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
928 {
929         LOAD_FORMATSPECIFIC();
930         float **vorbis_buffer;
931         size_t i;
932         int j;
933         ogg_page pg;
934         ogg_packet pt;
935
936         vorbis_buffer = qvorbis_analysis_buffer(&format->vd, length);
937         for(i = 0; i < length; ++i)
938         {
939                 for(j = 0; j < cls.capturevideo.soundchannels; ++j)
940                         vorbis_buffer[j][i] = paintbuffer[i].sample[j] / 32768.0f;
941         }
942         qvorbis_analysis_wrote(&format->vd, length);
943
944         while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
945         {
946                 qvorbis_analysis(&format->vb, NULL);
947                 qvorbis_bitrate_addblock(&format->vb);
948
949                 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
950                         qogg_stream_packetin(&format->vo, &pt);
951         }
952
953         while(qogg_stream_pageout(&format->vo, &pg) > 0)
954         {
955                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
956                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
957         }
958 }