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