]> icculus.org git repositories - divverent/darkplaces.git/blob - cap_ogg.c
GLSL compiler variable declaration workaround
[divverent/darkplaces.git] / cap_ogg.c
1 #ifndef _MSC_VER
2 #include <stdint.h>
3 #endif
4 #include <sys/types.h>
5
6 #include "quakedef.h"
7 #include "client.h"
8 #include "cap_ogg.h"
9
10 // video capture cvars
11 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"};
12 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"};
13 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"};
14 static cvar_t cl_capturevideo_ogg_theora_keyframe_maxinterval = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_maxinterval", "64", "maximum keyframe interval (1 to 1000)"};
15 static cvar_t cl_capturevideo_ogg_theora_keyframe_mininterval = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_mininterval", "8", "minimum keyframe interval (1 to 1000)"};
16 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)"};
17 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"};
18 static cvar_t cl_capturevideo_ogg_theora_sharpness = {CVAR_SAVE, "cl_capturevideo_ogg_theora_sharpness", "0", "sharpness (0 to 2); lower is sharper"};
19 static cvar_t cl_capturevideo_ogg_vorbis_quality = {CVAR_SAVE, "cl_capturevideo_ogg_vorbis_quality", "3", "audio quality (-1 to 10); higher is better"};
20
21 // ogg.h stuff
22 #ifdef _MSC_VER
23 typedef __int16 ogg_int16_t;
24 typedef unsigned __int16 ogg_uint16_t;
25 typedef __int32 ogg_int32_t;
26 typedef unsigned __int32 ogg_uint32_t;
27 typedef __int64 ogg_int64_t;
28 #else
29 typedef int16_t ogg_int16_t;
30 typedef uint16_t ogg_uint16_t;
31 typedef int32_t ogg_int32_t;
32 typedef uint32_t ogg_uint32_t;
33 typedef int64_t ogg_int64_t;
34 #endif
35
36 typedef struct {
37   long endbyte;
38   int  endbit;
39
40   unsigned char *buffer;
41   unsigned char *ptr;
42   long storage;
43 } oggpack_buffer;
44
45 /* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
46
47 typedef struct {
48   unsigned char *header;
49   long header_len;
50   unsigned char *body;
51   long body_len;
52 } ogg_page;
53
54 /* ogg_stream_state contains the current encode/decode state of a logical
55    Ogg bitstream **********************************************************/
56
57 typedef struct {
58   unsigned char   *body_data;    /* bytes from packet bodies */
59   long    body_storage;          /* storage elements allocated */
60   long    body_fill;             /* elements stored; fill mark */
61   long    body_returned;         /* elements of fill returned */
62
63
64   int     *lacing_vals;      /* The values that will go to the segment table */
65   ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
66                                 this way, but it is simple coupled to the
67                                 lacing fifo */
68   long    lacing_storage;
69   long    lacing_fill;
70   long    lacing_packet;
71   long    lacing_returned;
72
73   unsigned char    header[282];      /* working space for header encode */
74   int              header_fill;
75
76   int     e_o_s;          /* set when we have buffered the last packet in the
77                              logical bitstream */
78   int     b_o_s;          /* set after we've written the initial page
79                              of a logical bitstream */
80   long    serialno;
81   long    pageno;
82   ogg_int64_t  packetno;      /* sequence number for decode; the framing
83                              knows where there's a hole in the data,
84                              but we need coupling so that the codec
85                              (which is in a seperate abstraction
86                              layer) also knows about the gap */
87   ogg_int64_t   granulepos;
88
89 } ogg_stream_state;
90
91 /* ogg_packet is used to encapsulate the data and metadata belonging
92    to a single raw Ogg/Vorbis packet *************************************/
93
94 typedef struct {
95   unsigned char *packet;
96   long  bytes;
97   long  b_o_s;
98   long  e_o_s;
99
100   ogg_int64_t  granulepos;
101   
102   ogg_int64_t  packetno;     /* sequence number for decode; the framing
103                                 knows where there's a hole in the data,
104                                 but we need coupling so that the codec
105                                 (which is in a seperate abstraction
106                                 layer) also knows about the gap */
107 } ogg_packet;
108
109 typedef struct {
110   unsigned char *data;
111   int storage;
112   int fill;
113   int returned;
114
115   int unsynced;
116   int headerbytes;
117   int bodybytes;
118 } ogg_sync_state;
119
120 /* Ogg BITSTREAM PRIMITIVES: encoding **************************/
121
122 static int      (*qogg_stream_packetin) (ogg_stream_state *os, ogg_packet *op);
123 static int      (*qogg_stream_pageout) (ogg_stream_state *os, ogg_page *og);
124 static int      (*qogg_stream_flush) (ogg_stream_state *os, ogg_page *og);
125
126 /* Ogg BITSTREAM PRIMITIVES: general ***************************/
127
128 static int      (*qogg_stream_init) (ogg_stream_state *os,int serialno);
129 static int      (*qogg_stream_clear) (ogg_stream_state *os);
130 static ogg_int64_t  (*qogg_page_granulepos) (ogg_page *og);
131
132 // end of ogg.h stuff
133
134 // vorbis/codec.h stuff
135 typedef struct vorbis_info{
136   int version;
137   int channels;
138   long rate;
139
140   /* The below bitrate declarations are *hints*.
141      Combinations of the three values carry the following implications:
142
143      all three set to the same value:
144        implies a fixed rate bitstream
145      only nominal set:
146        implies a VBR stream that averages the nominal bitrate.  No hard
147        upper/lower limit
148      upper and or lower set:
149        implies a VBR bitstream that obeys the bitrate limits. nominal
150        may also be set to give a nominal rate.
151      none set:
152        the coder does not care to speculate.
153   */
154
155   long bitrate_upper;
156   long bitrate_nominal;
157   long bitrate_lower;
158   long bitrate_window;
159
160   void *codec_setup;
161 } vorbis_info;
162
163 /* vorbis_dsp_state buffers the current vorbis audio
164    analysis/synthesis state.  The DSP state belongs to a specific
165    logical bitstream ****************************************************/
166 typedef struct vorbis_dsp_state{
167   int analysisp;
168   vorbis_info *vi;
169
170   float **pcm;
171   float **pcmret;
172   int      pcm_storage;
173   int      pcm_current;
174   int      pcm_returned;
175
176   int  preextrapolate;
177   int  eofflag;
178
179   long lW;
180   long W;
181   long nW;
182   long centerW;
183
184   ogg_int64_t granulepos;
185   ogg_int64_t sequence;
186
187   ogg_int64_t glue_bits;
188   ogg_int64_t time_bits;
189   ogg_int64_t floor_bits;
190   ogg_int64_t res_bits;
191
192   void       *backend_state;
193 } vorbis_dsp_state;
194
195 typedef struct vorbis_block{
196   /* necessary stream state for linking to the framing abstraction */
197   float  **pcm;       /* this is a pointer into local storage */
198   oggpack_buffer opb;
199
200   long  lW;
201   long  W;
202   long  nW;
203   int   pcmend;
204   int   mode;
205
206   int         eofflag;
207   ogg_int64_t granulepos;
208   ogg_int64_t sequence;
209   vorbis_dsp_state *vd; /* For read-only access of configuration */
210
211   /* local storage to avoid remallocing; it's up to the mapping to
212      structure it */
213   void               *localstore;
214   long                localtop;
215   long                localalloc;
216   long                totaluse;
217   struct alloc_chain *reap;
218
219   /* bitmetrics for the frame */
220   long glue_bits;
221   long time_bits;
222   long floor_bits;
223   long res_bits;
224
225   void *internal;
226
227 } vorbis_block;
228
229 /* vorbis_block is a single block of data to be processed as part of
230 the analysis/synthesis stream; it belongs to a specific logical
231 bitstream, but is independant from other vorbis_blocks belonging to
232 that logical bitstream. *************************************************/
233
234 struct alloc_chain{
235   void *ptr;
236   struct alloc_chain *next;
237 };
238
239 /* vorbis_info contains all the setup information specific to the
240    specific compression/decompression mode in progress (eg,
241    psychoacoustic settings, channel setup, options, codebook
242    etc). vorbis_info and substructures are in backends.h.
243 *********************************************************************/
244
245 /* the comments are not part of vorbis_info so that vorbis_info can be
246    static storage */
247 typedef struct vorbis_comment{
248   /* unlimited user comment fields.  libvorbis writes 'libvorbis'
249      whatever vendor is set to in encode */
250   char **user_comments;
251   int   *comment_lengths;
252   int    comments;
253   char  *vendor;
254
255 } vorbis_comment;
256
257
258 /* libvorbis encodes in two abstraction layers; first we perform DSP
259    and produce a packet (see docs/analysis.txt).  The packet is then
260    coded into a framed OggSquish bitstream by the second layer (see
261    docs/framing.txt).  Decode is the reverse process; we sync/frame
262    the bitstream and extract individual packets, then decode the
263    packet back into PCM audio.
264
265    The extra framing/packetizing is used in streaming formats, such as
266    files.  Over the net (such as with UDP), the framing and
267    packetization aren't necessary as they're provided by the transport
268    and the streaming layer is not used */
269
270 /* Vorbis PRIMITIVES: general ***************************************/
271
272 static void     (*qvorbis_info_init) (vorbis_info *vi);
273 static void     (*qvorbis_info_clear) (vorbis_info *vi);
274 static void     (*qvorbis_comment_init) (vorbis_comment *vc);
275 static void     (*qvorbis_comment_clear) (vorbis_comment *vc);
276
277 static int      (*qvorbis_block_init) (vorbis_dsp_state *v, vorbis_block *vb);
278 static int      (*qvorbis_block_clear) (vorbis_block *vb);
279 static void     (*qvorbis_dsp_clear) (vorbis_dsp_state *v);
280 static double   (*qvorbis_granule_time) (vorbis_dsp_state *v,
281                                     ogg_int64_t granulepos);
282
283 /* Vorbis PRIMITIVES: analysis/DSP layer ****************************/
284
285 static int      (*qvorbis_analysis_init) (vorbis_dsp_state *v,vorbis_info *vi);
286 static int      (*qvorbis_commentheader_out) (vorbis_comment *vc, ogg_packet *op);
287 static int      (*qvorbis_analysis_headerout) (vorbis_dsp_state *v,
288                                           vorbis_comment *vc,
289                                           ogg_packet *op,
290                                           ogg_packet *op_comm,
291                                           ogg_packet *op_code);
292 static float ** (*qvorbis_analysis_buffer) (vorbis_dsp_state *v,int vals);
293 static int      (*qvorbis_analysis_wrote) (vorbis_dsp_state *v,int vals);
294 static int      (*qvorbis_analysis_blockout) (vorbis_dsp_state *v,vorbis_block *vb);
295 static int      (*qvorbis_analysis) (vorbis_block *vb,ogg_packet *op);
296
297 static int      (*qvorbis_bitrate_addblock) (vorbis_block *vb);
298 static int      (*qvorbis_bitrate_flushpacket) (vorbis_dsp_state *vd,
299                                            ogg_packet *op);
300
301 // end of vorbis/codec.h stuff
302
303 // vorbisenc.h stuff
304 static int (*qvorbis_encode_init_vbr) (vorbis_info *vi,
305                                   long channels,
306                                   long rate,
307
308                                   float base_quality /* quality level from 0. (lo) to 1. (hi) */
309                                   );
310 // end of vorbisenc.h stuff
311
312 // theora.h stuff
313 typedef struct {
314     int   y_width;      /**< Width of the Y' luminance plane */
315     int   y_height;     /**< Height of the luminance plane */
316     int   y_stride;     /**< Offset in bytes between successive rows */
317
318     int   uv_width;     /**< Width of the Cb and Cr chroma planes */
319     int   uv_height;    /**< Height of the chroma planes */
320     int   uv_stride;    /**< Offset between successive chroma rows */
321     unsigned char *y;   /**< Pointer to start of luminance data */
322     unsigned char *u;   /**< Pointer to start of Cb data */
323     unsigned char *v;   /**< Pointer to start of Cr data */
324
325 } yuv_buffer;
326
327 /**
328  * A Colorspace.
329  */
330 typedef enum {
331   OC_CS_UNSPECIFIED,    /**< The colorspace is unknown or unspecified */
332   OC_CS_ITU_REC_470M,   /**< This is the best option for 'NTSC' content */
333   OC_CS_ITU_REC_470BG,  /**< This is the best option for 'PAL' content */
334   OC_CS_NSPACES         /**< This marks the end of the defined colorspaces */
335 } theora_colorspace;
336
337 /**
338  * A Chroma subsampling
339  *
340  * These enumerate the available chroma subsampling options supported
341  * by the theora format. See Section 4.4 of the specification for
342  * exact definitions.
343  */
344 typedef enum {
345   OC_PF_420,    /**< Chroma subsampling by 2 in each direction (4:2:0) */
346   OC_PF_RSVD,   /**< Reserved value */
347   OC_PF_422,    /**< Horizonatal chroma subsampling by 2 (4:2:2) */
348   OC_PF_444,    /**< No chroma subsampling at all (4:4:4) */
349 } theora_pixelformat;
350 /**
351  * Theora bitstream info.
352  * Contains the basic playback parameters for a stream,
353  * corresponding to the initial 'info' header packet.
354  * 
355  * Encoded theora frames must be a multiple of 16 in width and height.
356  * To handle other frame sizes, a crop rectangle is specified in
357  * frame_height and frame_width, offset_x and * offset_y. The offset
358  * and size should still be a multiple of 2 to avoid chroma sampling
359  * shifts. Offset values in this structure are measured from the
360  * upper left of the image.
361  *
362  * Frame rate, in frames per second, is stored as a rational
363  * fraction. Aspect ratio is also stored as a rational fraction, and
364  * refers to the aspect ratio of the frame pixels, not of the
365  * overall frame itself.
366  * 
367  * See <a href="http://svn.xiph.org/trunk/theora/examples/encoder_example.c">
368  * examples/encoder_example.c</a> for usage examples of the
369  * other paramters and good default settings for the encoder parameters.
370  */
371 typedef struct {
372   ogg_uint32_t  width;      /**< encoded frame width  */
373   ogg_uint32_t  height;     /**< encoded frame height */
374   ogg_uint32_t  frame_width;    /**< display frame width  */
375   ogg_uint32_t  frame_height;   /**< display frame height */
376   ogg_uint32_t  offset_x;   /**< horizontal offset of the displayed frame */
377   ogg_uint32_t  offset_y;   /**< vertical offset of the displayed frame */
378   ogg_uint32_t  fps_numerator;      /**< frame rate numerator **/
379   ogg_uint32_t  fps_denominator;    /**< frame rate denominator **/
380   ogg_uint32_t  aspect_numerator;   /**< pixel aspect ratio numerator */
381   ogg_uint32_t  aspect_denominator; /**< pixel aspect ratio denominator */
382   theora_colorspace colorspace;     /**< colorspace */
383   int           target_bitrate;     /**< nominal bitrate in bits per second */
384   int           quality;  /**< Nominal quality setting, 0-63 */
385   int           quick_p;  /**< Quick encode/decode */
386
387   /* decode only */
388   unsigned char version_major;
389   unsigned char version_minor;
390   unsigned char version_subminor;
391
392   void *codec_setup;
393
394   /* encode only */
395   int           dropframes_p;
396   int           keyframe_auto_p;
397   ogg_uint32_t  keyframe_frequency;
398   ogg_uint32_t  keyframe_frequency_force;  /* also used for decode init to
399                                               get granpos shift correct */
400   ogg_uint32_t  keyframe_data_target_bitrate;
401   ogg_int32_t   keyframe_auto_threshold;
402   ogg_uint32_t  keyframe_mindistance;
403   ogg_int32_t   noise_sensitivity;
404   ogg_int32_t   sharpness;
405
406   theora_pixelformat pixelformat;   /**< chroma subsampling mode to expect */
407
408 } theora_info;
409
410 /** Codec internal state and context.
411  */
412 typedef struct{
413   theora_info *i;
414   ogg_int64_t granulepos;
415
416   void *internal_encode;
417   void *internal_decode;
418
419 } theora_state;
420
421 /** 
422  * Comment header metadata.
423  *
424  * This structure holds the in-stream metadata corresponding to
425  * the 'comment' header packet.
426  *
427  * Meta data is stored as a series of (tag, value) pairs, in
428  * length-encoded string vectors. The first occurence of the 
429  * '=' character delimits the tag and value. A particular tag
430  * may occur more than once. The character set encoding for
431  * the strings is always UTF-8, but the tag names are limited
432  * to case-insensitive ASCII. See the spec for details.
433  *
434  * In filling in this structure, qtheora_decode_header() will
435  * null-terminate the user_comment strings for safety. However,
436  * the bitstream format itself treats them as 8-bit clean,
437  * and so the length array should be treated as authoritative
438  * for their length.
439  */
440 typedef struct theora_comment{
441   char **user_comments;         /**< An array of comment string vectors */
442   int   *comment_lengths;       /**< An array of corresponding string vector lengths in bytes */
443   int    comments;              /**< The total number of comment string vectors */
444   char  *vendor;                /**< The vendor string identifying the encoder, null terminated */
445
446 } theora_comment;
447 static int (*qtheora_encode_init) (theora_state *th, theora_info *ti);
448 static int (*qtheora_encode_YUVin) (theora_state *t, yuv_buffer *yuv);
449 static int (*qtheora_encode_packetout) ( theora_state *t, int last_p,
450                                     ogg_packet *op);
451 static int (*qtheora_encode_header) (theora_state *t, ogg_packet *op);
452 static int (*qtheora_encode_comment) (theora_comment *tc, ogg_packet *op);
453 static int (*qtheora_encode_tables) (theora_state *t, ogg_packet *op);
454 static void (*qtheora_info_init) (theora_info *c);
455 static void (*qtheora_info_clear) (theora_info *c);
456 static void (*qtheora_clear) (theora_state *t);
457 static void (*qtheora_comment_init) (theora_comment *tc);
458 static void  (*qtheora_comment_clear) (theora_comment *tc);
459 static double (*qtheora_granule_time) (theora_state *th,ogg_int64_t granulepos);
460 // end of theora.h stuff
461
462 static dllfunction_t oggfuncs[] =
463 {
464         {"ogg_stream_packetin", (void **) &qogg_stream_packetin},
465         {"ogg_stream_pageout", (void **) &qogg_stream_pageout},
466         {"ogg_stream_flush", (void **) &qogg_stream_flush},
467         {"ogg_stream_init", (void **) &qogg_stream_init},
468         {"ogg_stream_clear", (void **) &qogg_stream_clear},
469         {"ogg_page_granulepos", (void **) &qogg_page_granulepos},
470         {NULL, NULL}
471 };
472
473 static dllfunction_t vorbisencfuncs[] =
474 {
475         {"vorbis_encode_init_vbr", (void **) &qvorbis_encode_init_vbr},
476         {NULL, NULL}
477 };
478
479 static dllfunction_t vorbisfuncs[] =
480 {
481         {"vorbis_info_init", (void **) &qvorbis_info_init},
482         {"vorbis_info_clear", (void **) &qvorbis_info_clear},
483         {"vorbis_comment_init", (void **) &qvorbis_comment_init},
484         {"vorbis_comment_clear", (void **) &qvorbis_comment_clear},
485         {"vorbis_block_init", (void **) &qvorbis_block_init},
486         {"vorbis_block_clear", (void **) &qvorbis_block_clear},
487         {"vorbis_dsp_clear", (void **) &qvorbis_dsp_clear},
488         {"vorbis_analysis_init", (void **) &qvorbis_analysis_init},
489         {"vorbis_commentheader_out", (void **) &qvorbis_commentheader_out},
490         {"vorbis_analysis_headerout", (void **) &qvorbis_analysis_headerout},
491         {"vorbis_analysis_buffer", (void **) &qvorbis_analysis_buffer},
492         {"vorbis_analysis_wrote", (void **) &qvorbis_analysis_wrote},
493         {"vorbis_analysis_blockout", (void **) &qvorbis_analysis_blockout},
494         {"vorbis_analysis", (void **) &qvorbis_analysis},
495         {"vorbis_bitrate_addblock", (void **) &qvorbis_bitrate_addblock},
496         {"vorbis_bitrate_flushpacket", (void **) &qvorbis_bitrate_flushpacket},
497         {"vorbis_granule_time", (void **) &qvorbis_granule_time},
498         {NULL, NULL}
499 };
500
501 static dllfunction_t theorafuncs[] =
502 {
503         {"theora_info_init", (void **) &qtheora_info_init},
504         {"theora_info_clear", (void **) &qtheora_info_clear},
505         {"theora_comment_init", (void **) &qtheora_comment_init},
506         {"theora_comment_clear", (void **) &qtheora_comment_clear},
507         {"theora_encode_init", (void **) &qtheora_encode_init},
508         {"theora_encode_YUVin", (void **) &qtheora_encode_YUVin},
509         {"theora_encode_packetout", (void **) &qtheora_encode_packetout},
510         {"theora_encode_header", (void **) &qtheora_encode_header},
511         {"theora_encode_comment", (void **) &qtheora_encode_comment},
512         {"theora_encode_tables", (void **) &qtheora_encode_tables},
513         {"theora_clear", (void **) &qtheora_clear},
514         {"theora_granule_time", (void **) &qtheora_granule_time},
515         {NULL, NULL}
516 };
517
518 static dllhandle_t og_dll = NULL, vo_dll = NULL, ve_dll = NULL, th_dll = NULL;
519
520 qboolean SCR_CaptureVideo_Ogg_OpenLibrary(void)
521 {
522         const char* dllnames_og [] =
523         {
524 #if defined(WIN64)
525                 "libogg64.dll",
526 #elif defined(WIN32)
527                 "libogg.dll",
528                 "ogg.dll",
529 #elif defined(MACOSX)
530                 "libogg.dylib",
531 #else
532                 "libogg.so.0",
533                 "libogg.so",
534 #endif
535                 NULL
536         };
537         const char* dllnames_vo [] =
538         {
539 #if defined(WIN64)
540                 "libvorbis64.dll",
541 #elif defined(WIN32)
542                 "libvorbis.dll",
543                 "vorbis.dll",
544 #elif defined(MACOSX)
545                 "libvorbis.dylib",
546 #else
547                 "libvorbis.so.0",
548                 "libvorbis.so",
549 #endif
550                 NULL
551         };
552         const char* dllnames_ve [] =
553         {
554 #if defined(WIN64)
555                 "libvorbisenc64.dll",
556 #elif defined(WIN32)
557                 "libvorbisenc.dll",
558                 "vorbisenc.dll",
559 #elif defined(MACOSX)
560                 "libvorbisenc.dylib",
561 #else
562                 "libvorbisenc.so.2",
563                 "libvorbisenc.so",
564 #endif
565                 NULL
566         };
567         const char* dllnames_th [] =
568         {
569 #if defined(WIN64)
570                 "libtheora64.dll",
571 #elif defined(WIN32)
572                 "libtheora.dll",
573                 "theora.dll",
574 #elif defined(MACOSX)
575                 "libtheora.dylib",
576 #else
577                 "libtheora.so.0",
578                 "libtheora.so",
579 #endif
580                 NULL
581         };
582
583         return
584                 Sys_LoadLibrary (dllnames_og, &og_dll, oggfuncs)
585                 &&
586                 Sys_LoadLibrary (dllnames_th, &th_dll, theorafuncs)
587                 &&
588                 Sys_LoadLibrary (dllnames_vo, &vo_dll, vorbisfuncs)
589                 &&
590                 Sys_LoadLibrary (dllnames_ve, &ve_dll, vorbisencfuncs);
591 }
592
593 void SCR_CaptureVideo_Ogg_Init(void)
594 {
595         SCR_CaptureVideo_Ogg_OpenLibrary();
596
597         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_quality);
598         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_bitrate);
599         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier);
600         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_maxinterval);
601         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_mininterval);
602         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_auto_threshold);
603         Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_noise_sensitivity);
604         Cvar_RegisterVariable(&cl_capturevideo_ogg_vorbis_quality);
605 }
606
607 qboolean SCR_CaptureVideo_Ogg_Available(void)
608 {
609         return og_dll && th_dll && vo_dll && ve_dll;
610 }
611
612 void SCR_CaptureVideo_Ogg_CloseDLL(void)
613 {
614         Sys_UnloadLibrary (&ve_dll);
615         Sys_UnloadLibrary (&vo_dll);
616         Sys_UnloadLibrary (&th_dll);
617         Sys_UnloadLibrary (&og_dll);
618 }
619
620 // this struct should not be needed
621 // however, libogg appears to pull the ogg_page's data element away from our
622 // feet before we get to write the data due to interleaving
623 // so this struct is used to keep the page data around until it actually gets
624 // written
625 typedef struct allocatedoggpage_s
626 {
627         size_t len;
628         double time;
629         unsigned char data[65307];
630         // this number is from RFC 3533. In case libogg writes more, we'll have to increase this
631         // but we'll get a Host_Error in this case so we can track it down
632 }
633 allocatedoggpage_t;
634
635 typedef struct capturevideostate_ogg_formatspecific_s
636 {
637         ogg_stream_state to, vo;
638         int serial1, serial2;
639         theora_state ts;
640         vorbis_dsp_state vd;
641         vorbis_block vb;
642         vorbis_info vi;
643         yuv_buffer yuv[2];
644         int yuvi;
645         int lastnum;
646         int channels;
647
648         allocatedoggpage_t videopage, audiopage;
649 }
650 capturevideostate_ogg_formatspecific_t;
651 #define LOAD_FORMATSPECIFIC_OGG() capturevideostate_ogg_formatspecific_t *format = (capturevideostate_ogg_formatspecific_t *) cls.capturevideo.formatspecific
652
653 static void SCR_CaptureVideo_Ogg_Interleave(void)
654 {
655         LOAD_FORMATSPECIFIC_OGG();
656         ogg_page pg;
657
658         if(!cls.capturevideo.soundrate)
659         {
660                 while(qogg_stream_pageout(&format->to, &pg) > 0)
661                 {
662                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
663                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
664                 }
665                 return;
666         }
667
668         for(;;)
669         {
670                 // first: make sure we have a page of both types
671                 if(!format->videopage.len)
672                         if(qogg_stream_pageout(&format->to, &pg) > 0)
673                         {
674                                 format->videopage.len = pg.header_len + pg.body_len;
675                                 format->videopage.time = qtheora_granule_time(&format->ts, qogg_page_granulepos(&pg));
676                                 if(format->videopage.len > sizeof(format->videopage.data))
677                                         Host_Error("video page too long");
678                                 memcpy(format->videopage.data, pg.header, pg.header_len);
679                                 memcpy(format->videopage.data + pg.header_len, pg.body, pg.body_len);
680                         }
681                 if(!format->audiopage.len)
682                         if(qogg_stream_pageout(&format->vo, &pg) > 0)
683                         {
684                                 format->audiopage.len = pg.header_len + pg.body_len;
685                                 format->audiopage.time = qvorbis_granule_time(&format->vd, qogg_page_granulepos(&pg));
686                                 if(format->audiopage.len > sizeof(format->audiopage.data))
687                                         Host_Error("audio page too long");
688                                 memcpy(format->audiopage.data, pg.header, pg.header_len);
689                                 memcpy(format->audiopage.data + pg.header_len, pg.body, pg.body_len);
690                         }
691
692                 if(format->videopage.len && format->audiopage.len)
693                 {
694                         // output the page that ends first
695                         if(format->videopage.time < format->audiopage.time)
696                         {
697                                 FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len);
698                                 format->videopage.len = 0;
699                         }
700                         else
701                         {
702                                 FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len);
703                                 format->audiopage.len = 0;
704                         }
705                 }
706                 else
707                         break;
708         }
709 }
710
711 static void SCR_CaptureVideo_Ogg_FlushInterleaving(void)
712 {
713         LOAD_FORMATSPECIFIC_OGG();
714
715         if(cls.capturevideo.soundrate)
716         if(format->audiopage.len)
717         {
718                 FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len);
719                 format->audiopage.len = 0;
720         }
721
722         if(format->videopage.len)
723         {
724                 FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len);
725                 format->videopage.len = 0;
726         }
727 }
728
729 static void SCR_CaptureVideo_Ogg_EndVideo(void)
730 {
731         LOAD_FORMATSPECIFIC_OGG();
732         ogg_page pg;
733         ogg_packet pt;
734
735         if(format->yuvi >= 0)
736         {
737                 // send the previous (and last) frame
738                 while(format->lastnum-- > 0)
739                 {
740                         qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]);
741
742                         while(qtheora_encode_packetout(&format->ts, !format->lastnum, &pt))
743                                 qogg_stream_packetin(&format->to, &pt);
744
745                         SCR_CaptureVideo_Ogg_Interleave();
746                 }
747         }
748
749         if(cls.capturevideo.soundrate)
750         {
751                 qvorbis_analysis_wrote(&format->vd, 0);
752                 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
753                 {
754                         qvorbis_analysis(&format->vb, NULL);
755                         qvorbis_bitrate_addblock(&format->vb);
756                         while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
757                                 qogg_stream_packetin(&format->vo, &pt);
758                         SCR_CaptureVideo_Ogg_Interleave();
759                 }
760         }
761
762         SCR_CaptureVideo_Ogg_FlushInterleaving();
763
764         while(qogg_stream_pageout(&format->to, &pg) > 0)
765         {
766                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
767                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
768         }
769
770         if(cls.capturevideo.soundrate)
771         {
772                 while(qogg_stream_pageout(&format->vo, &pg) > 0)
773                 {
774                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
775                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
776                 }
777         }
778                 
779         while (1) {
780                 int result = qogg_stream_flush (&format->to, &pg);
781                 if (result < 0)
782                         fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
783                 if (result <= 0)
784                         break;
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         if(cls.capturevideo.soundrate)
790         {
791                 while (1) {
792                         int result = qogg_stream_flush (&format->vo, &pg);
793                         if (result < 0)
794                                 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
795                         if (result <= 0)
796                                 break;
797                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
798                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
799                 }
800
801                 qogg_stream_clear(&format->vo);
802                 qvorbis_block_clear(&format->vb);
803                 qvorbis_dsp_clear(&format->vd);
804         }
805
806         qogg_stream_clear(&format->to);
807         qtheora_clear(&format->ts);
808         qvorbis_info_clear(&format->vi);
809
810         Mem_Free(format->yuv[0].y);
811         Mem_Free(format->yuv[0].u);
812         Mem_Free(format->yuv[0].v);
813         Mem_Free(format->yuv[1].y);
814         Mem_Free(format->yuv[1].u);
815         Mem_Free(format->yuv[1].v);
816         Mem_Free(format);
817
818         FS_Close(cls.capturevideo.videofile);
819         cls.capturevideo.videofile = NULL;
820 }
821
822 static void SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV(void)
823 {
824         LOAD_FORMATSPECIFIC_OGG();
825         yuv_buffer *yuv;
826         int x, y;
827         int blockr, blockg, blockb;
828         unsigned char *b = cls.capturevideo.outbuffer;
829         int w = cls.capturevideo.width;
830         int h = cls.capturevideo.height;
831         int inpitch = w*4;
832
833         yuv = &format->yuv[format->yuvi];
834
835         for(y = 0; y < h; ++y)
836         {
837                 for(b = cls.capturevideo.outbuffer + (h-1-y)*w*4, x = 0; x < w; ++x)
838                 {
839                         blockr = b[2];
840                         blockg = b[1];
841                         blockb = b[0];
842                         yuv->y[x + yuv->y_stride * y] =
843                                 cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]];
844                         b += 4;
845                 }
846
847                 if((y & 1) == 0)
848                 {
849                         for(b = cls.capturevideo.outbuffer + (h-2-y)*w*4, x = 0; x < w/2; ++x)
850                         {
851                                 blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2;
852                                 blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2;
853                                 blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2;
854                                 yuv->u[x + yuv->uv_stride * (y/2)] =
855                                         cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128];
856                                 yuv->v[x + yuv->uv_stride * (y/2)] =
857                                         cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128];
858                                 b += 8;
859                         }
860                 }
861         }
862 }
863
864 static void SCR_CaptureVideo_Ogg_VideoFrames(int num)
865 {
866         LOAD_FORMATSPECIFIC_OGG();
867         ogg_packet pt;
868
869         // data is in cls.capturevideo.outbuffer as BGRA and has size width*height
870
871         if(format->yuvi >= 0)
872         {
873                 // send the previous frame
874                 while(format->lastnum-- > 0)
875                 {
876                         qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]);
877
878                         while(qtheora_encode_packetout(&format->ts, false, &pt))
879                                 qogg_stream_packetin(&format->to, &pt);
880
881                         SCR_CaptureVideo_Ogg_Interleave();
882                 }
883         }
884
885         format->yuvi = (format->yuvi + 1) % 2;
886         SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV();
887         format->lastnum = num;
888
889         // TODO maybe send num-1 frames from here already
890 }
891
892 typedef int channelmapping_t[8];
893 channelmapping_t mapping[8] =
894 {
895         { 0, -1, -1, -1, -1, -1, -1, -1 }, // mono
896         { 0, 1, -1, -1, -1, -1, -1, -1 }, // stereo
897         { 0, 1, 2, -1, -1, -1, -1, -1 }, // L C R
898         { 0, 1, 2, 3, -1, -1, -1, -1 }, // surround40
899         { 0, 2, 3, 4, 1, -1, -1, -1 }, // FL FC FR RL RR
900         { 0, 2, 3, 4, 1, 5, -1, -1 }, // surround51
901         { 0, 2, 3, 4, 1, 5, 6, -1 }, // (not defined by vorbis spec)
902         { 0, 2, 3, 4, 1, 5, 6, 7 } // surround71 (not defined by vorbis spec)
903 };
904
905 static void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
906 {
907         LOAD_FORMATSPECIFIC_OGG();
908         float **vorbis_buffer;
909         size_t i;
910         int j;
911         ogg_packet pt;
912         int *map = mapping[bound(1, cls.capturevideo.soundchannels, 8) - 1];
913
914         vorbis_buffer = qvorbis_analysis_buffer(&format->vd, length);
915         for(j = 0; j < cls.capturevideo.soundchannels; ++j)
916         {
917                 float *b = vorbis_buffer[map[j]];
918                 for(i = 0; i < length; ++i)
919                         b[i] = paintbuffer[i].sample[j] / 32768.0f;
920         }
921         qvorbis_analysis_wrote(&format->vd, length);
922
923         while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
924         {
925                 qvorbis_analysis(&format->vb, NULL);
926                 qvorbis_bitrate_addblock(&format->vb);
927
928                 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
929                         qogg_stream_packetin(&format->vo, &pt);
930         }
931
932         SCR_CaptureVideo_Ogg_Interleave();
933 }
934
935 void SCR_CaptureVideo_Ogg_BeginVideo(void)
936 {
937         cls.capturevideo.format = CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA;
938         cls.capturevideo.formatextension = "ogv";
939         cls.capturevideo.videofile = FS_OpenRealFile(va("%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false);
940         cls.capturevideo.endvideo = SCR_CaptureVideo_Ogg_EndVideo;
941         cls.capturevideo.videoframes = SCR_CaptureVideo_Ogg_VideoFrames;
942         cls.capturevideo.soundframe = SCR_CaptureVideo_Ogg_SoundFrame;
943         cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_ogg_formatspecific_t));
944         {
945                 LOAD_FORMATSPECIFIC_OGG();
946                 int num, denom, i;
947                 ogg_page pg;
948                 ogg_packet pt, pt2, pt3;
949                 theora_comment tc;
950                 vorbis_comment vc;
951                 theora_info ti;
952
953                 format->serial1 = rand();
954                 qogg_stream_init(&format->to, format->serial1);
955
956                 if(cls.capturevideo.soundrate)
957                 {
958                         do
959                         {
960                                 format->serial2 = rand();
961                         }
962                         while(format->serial1 == format->serial2);
963                         qogg_stream_init(&format->vo, format->serial2);
964                 }
965
966                 format->videopage.len = format->audiopage.len = 0;
967
968                 qtheora_info_init(&ti);
969                 ti.frame_width = cls.capturevideo.width;
970                 ti.frame_height = cls.capturevideo.height;
971                 ti.width = (ti.frame_width + 15) & ~15;
972                 ti.height = (ti.frame_height + 15) & ~15;
973                 //ti.offset_x = ((ti.width - ti.frame_width) / 2) & ~1;
974                 //ti.offset_y = ((ti.height - ti.frame_height) / 2) & ~1;
975
976                 for(i = 0; i < 2; ++i)
977                 {
978                         format->yuv[i].y_width = ti.width;
979                         format->yuv[i].y_height = ti.height;
980                         format->yuv[i].y_stride = ti.width;
981                         format->yuv[i].uv_width = ti.width / 2;
982                         format->yuv[i].uv_height = ti.height / 2;
983                         format->yuv[i].uv_stride = ti.width / 2;
984                         format->yuv[i].y = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].y_stride * format->yuv[i].y_height);
985                         format->yuv[i].u = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
986                         format->yuv[i].v = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
987                 }
988                 format->yuvi = -1; // -1: no frame valid yet, write into 0
989
990                 FindFraction(cls.capturevideo.framerate / cls.capturevideo.framestep, &num, &denom, 1001);
991                 ti.fps_numerator = num;
992                 ti.fps_denominator = denom;
993
994                 FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000);
995                 ti.aspect_numerator = num;
996                 ti.aspect_denominator = denom;
997
998                 ti.colorspace = OC_CS_UNSPECIFIED;
999                 ti.pixelformat = OC_PF_420;
1000
1001                 ti.quick_p = true; // http://mlblog.osdir.com/multimedia.ogg.theora.general/2004-07/index.shtml
1002                 ti.dropframes_p = false;
1003
1004                 ti.target_bitrate = cl_capturevideo_ogg_theora_bitrate.integer * 1000;
1005                 ti.quality = cl_capturevideo_ogg_theora_quality.integer;
1006
1007                 if(ti.target_bitrate <= 0)
1008                 {
1009                         if(ti.quality < 0)
1010                         {
1011                                 ti.target_bitrate = -1;
1012                                 ti.keyframe_data_target_bitrate = (unsigned int)-1;
1013                                 ti.quality = 63;
1014                         }
1015                         else
1016                         {
1017                                 ti.target_bitrate = -1;
1018                                 ti.keyframe_data_target_bitrate = (unsigned int)-1;
1019                                 ti.quality = bound(0, ti.quality, 63);
1020                         }
1021                 }
1022                 else
1023                 {
1024                         if(ti.quality < 0)
1025                         {
1026                                 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
1027                                 ti.keyframe_data_target_bitrate = (int) (ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value));
1028                                 ti.quality = -1;
1029                         }
1030                         else
1031                         {
1032                                 ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
1033                                 ti.keyframe_data_target_bitrate = (int) (ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value));
1034                                 ti.quality = -1;
1035                         }
1036                 }
1037
1038                 // this -1 magic is because ti.keyframe_frequency and ti.keyframe_mindistance use different metrics
1039                 ti.keyframe_frequency = bound(1, cl_capturevideo_ogg_theora_keyframe_maxinterval.integer, 1000);
1040                 ti.keyframe_mindistance = bound(1, cl_capturevideo_ogg_theora_keyframe_mininterval.integer, (int) ti.keyframe_frequency) - 1;
1041                 ti.noise_sensitivity = bound(0, cl_capturevideo_ogg_theora_noise_sensitivity.integer, 6);
1042                 ti.sharpness = bound(0, cl_capturevideo_ogg_theora_sharpness.integer, 2);
1043                 ti.keyframe_auto_threshold = bound(0, cl_capturevideo_ogg_theora_keyframe_auto_threshold.integer, 100);
1044
1045                 ti.keyframe_frequency_force = ti.keyframe_frequency;
1046                 ti.keyframe_auto_p = (ti.keyframe_frequency != ti.keyframe_mindistance + 1);
1047
1048                 qtheora_encode_init(&format->ts, &ti);
1049                 qtheora_info_clear(&ti);
1050
1051                 // vorbis?
1052                 if(cls.capturevideo.soundrate)
1053                 {
1054                         qvorbis_info_init(&format->vi);
1055                         qvorbis_encode_init_vbr(&format->vi, cls.capturevideo.soundchannels, cls.capturevideo.soundrate, bound(-1, cl_capturevideo_ogg_vorbis_quality.value, 10) * 0.099);
1056                         qvorbis_comment_init(&vc);
1057                         qvorbis_analysis_init(&format->vd, &format->vi);
1058                         qvorbis_block_init(&format->vd, &format->vb);
1059                 }
1060
1061                 qtheora_comment_init(&tc);
1062
1063                 /* create the remaining theora headers */
1064                 qtheora_encode_header(&format->ts, &pt);
1065                 qogg_stream_packetin(&format->to, &pt);
1066                 if (qogg_stream_pageout (&format->to, &pg) != 1)
1067                         fprintf (stderr, "Internal Ogg library error.\n");
1068                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1069                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1070
1071                 qtheora_encode_comment(&tc, &pt);
1072                 qogg_stream_packetin(&format->to, &pt);
1073                 qtheora_encode_tables(&format->ts, &pt);
1074                 qogg_stream_packetin (&format->to, &pt);
1075
1076                 qtheora_comment_clear(&tc);
1077
1078                 if(cls.capturevideo.soundrate)
1079                 {
1080                         qvorbis_analysis_headerout(&format->vd, &vc, &pt, &pt2, &pt3);
1081                         qogg_stream_packetin(&format->vo, &pt);
1082                         if (qogg_stream_pageout (&format->vo, &pg) != 1)
1083                                 fprintf (stderr, "Internal Ogg library error.\n");
1084                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1085                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1086
1087                         qogg_stream_packetin(&format->vo, &pt2);
1088                         qogg_stream_packetin(&format->vo, &pt3);
1089
1090                         qvorbis_comment_clear(&vc);
1091                 }
1092
1093                 for(;;)
1094                 {
1095                         int result = qogg_stream_flush (&format->to, &pg);
1096                         if (result < 0)
1097                                 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
1098                         if (result <= 0)
1099                                 break;
1100                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1101                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1102                 }
1103
1104                 if(cls.capturevideo.soundrate)
1105                 for(;;)
1106                 {
1107                         int result = qogg_stream_flush (&format->vo, &pg);
1108                         if (result < 0)
1109                                 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
1110                         if (result <= 0)
1111                                 break;
1112                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1113                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1114                 }
1115         }
1116 }