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