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