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