]> git.xonotic.org Git - xonotic/darkplaces.git/blob - cap_ogg.c
sys: improve error and crash handling
[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_theora_sharpness);
590         Cvar_RegisterVariable(&cl_capturevideo_ogg_vorbis_quality);
591 }
592
593 qbool SCR_CaptureVideo_Ogg_Available(void)
594 {
595         return og_dll && th_dll && vo_dll && ve_dll;
596 }
597
598 void SCR_CaptureVideo_Ogg_CloseDLL(void)
599 {
600         Sys_FreeLibrary (&ve_dll);
601         Sys_FreeLibrary (&vo_dll);
602         Sys_FreeLibrary (&th_dll);
603         Sys_FreeLibrary (&og_dll);
604 }
605
606 // this struct should not be needed
607 // however, libogg appears to pull the ogg_page's data element away from our
608 // feet before we get to write the data due to interleaving
609 // so this struct is used to keep the page data around until it actually gets
610 // written
611 typedef struct allocatedoggpage_s
612 {
613         size_t len;
614         double time;
615         unsigned char data[65307];
616         // this number is from RFC 3533. In case libogg writes more, we'll have to increase this
617         // but we'll get a Host_Error in this case so we can track it down
618 }
619 allocatedoggpage_t;
620
621 typedef struct capturevideostate_ogg_formatspecific_s
622 {
623         ogg_stream_state to, vo;
624         int serial1, serial2;
625         theora_state ts;
626         vorbis_dsp_state vd;
627         vorbis_block vb;
628         vorbis_info vi;
629         yuv_buffer yuv[2];
630         int yuvi;
631         int lastnum;
632         int channels;
633
634         allocatedoggpage_t videopage, audiopage;
635 }
636 capturevideostate_ogg_formatspecific_t;
637 #define LOAD_FORMATSPECIFIC_OGG() capturevideostate_ogg_formatspecific_t *format = (capturevideostate_ogg_formatspecific_t *) cls.capturevideo.formatspecific
638
639 static void SCR_CaptureVideo_Ogg_Interleave(void)
640 {
641         LOAD_FORMATSPECIFIC_OGG();
642         ogg_page pg;
643
644         if(!cls.capturevideo.soundrate)
645         {
646                 while(qogg_stream_pageout(&format->to, &pg) > 0)
647                 {
648                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
649                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
650                 }
651                 return;
652         }
653
654         for(;;)
655         {
656                 // first: make sure we have a page of both types
657                 if(!format->videopage.len)
658                         if(qogg_stream_pageout(&format->to, &pg) > 0)
659                         {
660                                 format->videopage.len = pg.header_len + pg.body_len;
661                                 format->videopage.time = qtheora_granule_time(&format->ts, qogg_page_granulepos(&pg));
662                                 if(format->videopage.len > sizeof(format->videopage.data))
663                                         Sys_Abort("video page too long");
664                                 memcpy(format->videopage.data, pg.header, pg.header_len);
665                                 memcpy(format->videopage.data + pg.header_len, pg.body, pg.body_len);
666                         }
667                 if(!format->audiopage.len)
668                         if(qogg_stream_pageout(&format->vo, &pg) > 0)
669                         {
670                                 format->audiopage.len = pg.header_len + pg.body_len;
671                                 format->audiopage.time = qvorbis_granule_time(&format->vd, qogg_page_granulepos(&pg));
672                                 if(format->audiopage.len > sizeof(format->audiopage.data))
673                                         Sys_Abort("audio page too long");
674                                 memcpy(format->audiopage.data, pg.header, pg.header_len);
675                                 memcpy(format->audiopage.data + pg.header_len, pg.body, pg.body_len);
676                         }
677
678                 if(format->videopage.len && format->audiopage.len)
679                 {
680                         // output the page that ends first
681                         if(format->videopage.time < format->audiopage.time)
682                         {
683                                 FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len);
684                                 format->videopage.len = 0;
685                         }
686                         else
687                         {
688                                 FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len);
689                                 format->audiopage.len = 0;
690                         }
691                 }
692                 else
693                         break;
694         }
695 }
696
697 static void SCR_CaptureVideo_Ogg_FlushInterleaving(void)
698 {
699         LOAD_FORMATSPECIFIC_OGG();
700
701         if(cls.capturevideo.soundrate)
702         if(format->audiopage.len)
703         {
704                 FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len);
705                 format->audiopage.len = 0;
706         }
707
708         if(format->videopage.len)
709         {
710                 FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len);
711                 format->videopage.len = 0;
712         }
713 }
714
715 static void SCR_CaptureVideo_Ogg_EndVideo(void)
716 {
717         LOAD_FORMATSPECIFIC_OGG();
718         ogg_page pg;
719         ogg_packet pt;
720
721         if(format->yuvi >= 0)
722         {
723                 // send the previous (and last) frame
724                 while(format->lastnum-- > 0)
725                 {
726                         qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]);
727
728                         while(qtheora_encode_packetout(&format->ts, !format->lastnum, &pt))
729                                 qogg_stream_packetin(&format->to, &pt);
730
731                         SCR_CaptureVideo_Ogg_Interleave();
732                 }
733         }
734
735         if(cls.capturevideo.soundrate)
736         {
737                 qvorbis_analysis_wrote(&format->vd, 0);
738                 while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
739                 {
740                         qvorbis_analysis(&format->vb, NULL);
741                         qvorbis_bitrate_addblock(&format->vb);
742                         while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
743                                 qogg_stream_packetin(&format->vo, &pt);
744                         SCR_CaptureVideo_Ogg_Interleave();
745                 }
746         }
747
748         SCR_CaptureVideo_Ogg_FlushInterleaving();
749
750         while(qogg_stream_pageout(&format->to, &pg) > 0)
751         {
752                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
753                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
754         }
755
756         if(cls.capturevideo.soundrate)
757         {
758                 while(qogg_stream_pageout(&format->vo, &pg) > 0)
759                 {
760                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
761                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
762                 }
763         }
764                 
765         while (1) {
766                 int result = qogg_stream_flush (&format->to, &pg);
767                 if (result < 0)
768                         fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Abort
769                 if (result <= 0)
770                         break;
771                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
772                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
773         }
774
775         if(cls.capturevideo.soundrate)
776         {
777                 while (1) {
778                         int result = qogg_stream_flush (&format->vo, &pg);
779                         if (result < 0)
780                                 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Abort
781                         if (result <= 0)
782                                 break;
783                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
784                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
785                 }
786
787                 qogg_stream_clear(&format->vo);
788                 qvorbis_block_clear(&format->vb);
789                 qvorbis_dsp_clear(&format->vd);
790         }
791
792         qogg_stream_clear(&format->to);
793         qtheora_clear(&format->ts);
794         qvorbis_info_clear(&format->vi);
795
796         Mem_Free(format->yuv[0].y);
797         Mem_Free(format->yuv[0].u);
798         Mem_Free(format->yuv[0].v);
799         Mem_Free(format->yuv[1].y);
800         Mem_Free(format->yuv[1].u);
801         Mem_Free(format->yuv[1].v);
802         Mem_Free(format);
803
804         FS_Close(cls.capturevideo.videofile);
805         cls.capturevideo.videofile = NULL;
806 }
807
808 static void SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV(void)
809 {
810         LOAD_FORMATSPECIFIC_OGG();
811         yuv_buffer *yuv;
812         int x, y;
813         int blockr, blockg, blockb;
814         unsigned char *b;
815         int w = cls.capturevideo.width;
816         int h = cls.capturevideo.height;
817         int inpitch = w*4;
818
819         yuv = &format->yuv[format->yuvi];
820
821         for(y = 0; y < h; ++y)
822         {
823                 for(b = cls.capturevideo.outbuffer + (h-1-y)*w*4, x = 0; x < w; ++x)
824                 {
825                         blockr = b[2];
826                         blockg = b[1];
827                         blockb = b[0];
828                         yuv->y[x + yuv->y_stride * y] =
829                                 cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]];
830                         b += 4;
831                 }
832
833                 if ((y & 1) == 0 && y/2 < h/2) // if h is odd, this skips the last row
834                 {
835                         for(b = cls.capturevideo.outbuffer + (h-2-y)*w*4, x = 0; x < w/2; ++x)
836                         {
837                                 blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2;
838                                 blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2;
839                                 blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2;
840                                 yuv->u[x + yuv->uv_stride * (y/2)] =
841                                         cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128];
842                                 yuv->v[x + yuv->uv_stride * (y/2)] =
843                                         cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128];
844                                 b += 8;
845                         }
846                 }
847         }
848 }
849
850 static void SCR_CaptureVideo_Ogg_VideoFrames(int num)
851 {
852         LOAD_FORMATSPECIFIC_OGG();
853         ogg_packet pt;
854
855         // data is in cls.capturevideo.outbuffer as BGRA and has size width*height
856
857         if(format->yuvi >= 0)
858         {
859                 // send the previous frame
860                 while(format->lastnum-- > 0)
861                 {
862                         qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]);
863
864                         while(qtheora_encode_packetout(&format->ts, false, &pt))
865                                 qogg_stream_packetin(&format->to, &pt);
866
867                         SCR_CaptureVideo_Ogg_Interleave();
868                 }
869         }
870
871         format->yuvi = (format->yuvi + 1) % 2;
872         SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV();
873         format->lastnum = num;
874
875         // TODO maybe send num-1 frames from here already
876 }
877
878 typedef int channelmapping_t[8];
879 channelmapping_t mapping[8] =
880 {
881         { 0, -1, -1, -1, -1, -1, -1, -1 }, // mono
882         { 0, 1, -1, -1, -1, -1, -1, -1 }, // stereo
883         { 0, 1, 2, -1, -1, -1, -1, -1 }, // L C R
884         { 0, 1, 2, 3, -1, -1, -1, -1 }, // surround40
885         { 0, 2, 3, 4, 1, -1, -1, -1 }, // FL FC FR RL RR
886         { 0, 2, 3, 4, 1, 5, -1, -1 }, // surround51
887         { 0, 2, 3, 4, 1, 5, 6, -1 }, // (not defined by vorbis spec)
888         { 0, 2, 3, 4, 1, 5, 6, 7 } // surround71 (not defined by vorbis spec)
889 };
890
891 static void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
892 {
893         LOAD_FORMATSPECIFIC_OGG();
894         float **vorbis_buffer;
895         size_t i;
896         int j;
897         ogg_packet pt;
898         int *map = mapping[bound(1, cls.capturevideo.soundchannels, 8) - 1];
899
900         vorbis_buffer = qvorbis_analysis_buffer(&format->vd, (int)length);
901         for(j = 0; j < cls.capturevideo.soundchannels; ++j)
902         {
903                 float *b = vorbis_buffer[map[j]];
904                 for(i = 0; i < length; ++i)
905                         b[i] = paintbuffer[i].sample[j];
906         }
907         qvorbis_analysis_wrote(&format->vd, (int)length);
908
909         while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1)
910         {
911                 qvorbis_analysis(&format->vb, NULL);
912                 qvorbis_bitrate_addblock(&format->vb);
913
914                 while(qvorbis_bitrate_flushpacket(&format->vd, &pt))
915                         qogg_stream_packetin(&format->vo, &pt);
916         }
917
918         SCR_CaptureVideo_Ogg_Interleave();
919 }
920
921 void SCR_CaptureVideo_Ogg_BeginVideo(void)
922 {
923         char vabuf[1024];
924         cls.capturevideo.format = CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA;
925         cls.capturevideo.formatextension = "ogv";
926         cls.capturevideo.videofile = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false);
927         cls.capturevideo.endvideo = SCR_CaptureVideo_Ogg_EndVideo;
928         cls.capturevideo.videoframes = SCR_CaptureVideo_Ogg_VideoFrames;
929         cls.capturevideo.soundframe = SCR_CaptureVideo_Ogg_SoundFrame;
930         cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_ogg_formatspecific_t));
931         {
932                 LOAD_FORMATSPECIFIC_OGG();
933                 int num, denom, i;
934                 ogg_page pg;
935                 ogg_packet pt, pt2, pt3;
936                 theora_comment tc;
937                 vorbis_comment vc;
938                 theora_info ti;
939                 int vp3compat;
940
941                 format->serial1 = rand();
942                 qogg_stream_init(&format->to, format->serial1);
943
944                 if(cls.capturevideo.soundrate)
945                 {
946                         do
947                         {
948                                 format->serial2 = rand();
949                         }
950                         while(format->serial1 == format->serial2);
951                         qogg_stream_init(&format->vo, format->serial2);
952                 }
953
954                 format->videopage.len = format->audiopage.len = 0;
955
956                 qtheora_info_init(&ti);
957                 ti.frame_width = cls.capturevideo.width;
958                 ti.frame_height = cls.capturevideo.height;
959                 ti.width = (ti.frame_width + 15) & ~15;
960                 ti.height = (ti.frame_height + 15) & ~15;
961                 //ti.offset_x = ((ti.width - ti.frame_width) / 2) & ~1;
962                 //ti.offset_y = ((ti.height - ti.frame_height) / 2) & ~1;
963
964                 for(i = 0; i < 2; ++i)
965                 {
966                         format->yuv[i].y_width = ti.width;
967                         format->yuv[i].y_height = ti.height;
968                         format->yuv[i].y_stride = ti.width;
969                         format->yuv[i].uv_width = ti.width / 2;
970                         format->yuv[i].uv_height = ti.height / 2;
971                         format->yuv[i].uv_stride = ti.width / 2;
972                         format->yuv[i].y = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].y_stride * format->yuv[i].y_height);
973                         format->yuv[i].u = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
974                         format->yuv[i].v = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height);
975                 }
976                 format->yuvi = -1; // -1: no frame valid yet, write into 0
977
978                 FindFraction(cls.capturevideo.framerate / cls.capturevideo.framestep, &num, &denom, 1001);
979                 ti.fps_numerator = num;
980                 ti.fps_denominator = denom;
981
982                 FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000);
983                 ti.aspect_numerator = num;
984                 ti.aspect_denominator = denom;
985
986                 ti.colorspace = OC_CS_UNSPECIFIED;
987                 ti.pixelformat = OC_PF_420;
988
989                 ti.quick_p = true; // http://mlblog.osdir.com/multimedia.ogg.theora.general/2004-07/index.shtml
990                 ti.dropframes_p = false;
991
992                 ti.target_bitrate = cl_capturevideo_ogg_theora_bitrate.integer * 1000;
993                 ti.quality = cl_capturevideo_ogg_theora_quality.integer;
994
995                 if(ti.target_bitrate <= 0)
996                 {
997                         ti.target_bitrate = -1;
998                         ti.keyframe_data_target_bitrate = (unsigned int)-1;
999                 }
1000                 else
1001                 {
1002                         ti.keyframe_data_target_bitrate = (int) (ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value));
1003
1004                         if(ti.target_bitrate < 45000 || ti.target_bitrate > 2000000)
1005                                 Con_DPrintf("WARNING: requesting an odd bitrate for theora (sensible values range from 45 to 2000 kbps)\n");
1006                 }
1007
1008                 if(ti.quality < 0 || ti.quality > 63)
1009                 {
1010                         ti.quality = 63;
1011                         if(ti.target_bitrate <= 0)
1012                         {
1013                                 ti.target_bitrate = 0x7FFFFFFF;
1014                                 ti.keyframe_data_target_bitrate = 0x7FFFFFFF;
1015                         }
1016                 }
1017
1018                 // this -1 magic is because ti.keyframe_frequency and ti.keyframe_mindistance use different metrics
1019                 ti.keyframe_frequency = bound(1, cl_capturevideo_ogg_theora_keyframe_maxinterval.integer, 1000);
1020                 ti.keyframe_mindistance = bound(1, cl_capturevideo_ogg_theora_keyframe_mininterval.integer, (int) ti.keyframe_frequency) - 1;
1021                 ti.noise_sensitivity = bound(0, cl_capturevideo_ogg_theora_noise_sensitivity.integer, 6);
1022                 ti.sharpness = bound(0, cl_capturevideo_ogg_theora_sharpness.integer, 2);
1023                 ti.keyframe_auto_threshold = bound(0, cl_capturevideo_ogg_theora_keyframe_auto_threshold.integer, 100);
1024
1025                 ti.keyframe_frequency_force = ti.keyframe_frequency;
1026                 ti.keyframe_auto_p = (ti.keyframe_frequency != ti.keyframe_mindistance + 1);
1027
1028                 qtheora_encode_init(&format->ts, &ti);
1029                 qtheora_info_clear(&ti);
1030
1031                 if(cl_capturevideo_ogg_theora_vp3compat.integer)
1032                 {
1033                         vp3compat = 1;
1034                         qtheora_control(&format->ts, TH_ENCCTL_SET_VP3_COMPATIBLE, &vp3compat, sizeof(vp3compat));
1035                         if(!vp3compat)
1036                                 Con_DPrintf("Warning: theora stream is not fully VP3 compatible\n");
1037                 }
1038
1039                 // vorbis?
1040                 if(cls.capturevideo.soundrate)
1041                 {
1042                         qvorbis_info_init(&format->vi);
1043                         qvorbis_encode_init_vbr(&format->vi, cls.capturevideo.soundchannels, cls.capturevideo.soundrate, bound(-1, cl_capturevideo_ogg_vorbis_quality.value, 10) * 0.099);
1044                         qvorbis_comment_init(&vc);
1045                         qvorbis_analysis_init(&format->vd, &format->vi);
1046                         qvorbis_block_init(&format->vd, &format->vb);
1047                 }
1048
1049                 qtheora_comment_init(&tc);
1050
1051                 /* create the remaining theora headers */
1052                 qtheora_encode_header(&format->ts, &pt);
1053                 qogg_stream_packetin(&format->to, &pt);
1054                 if (qogg_stream_pageout (&format->to, &pg) != 1)
1055                         fprintf (stderr, "Internal Ogg library error.\n");
1056                 FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1057                 FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1058
1059                 qtheora_encode_comment(&tc, &pt);
1060                 qogg_stream_packetin(&format->to, &pt);
1061                 qtheora_encode_tables(&format->ts, &pt);
1062                 qogg_stream_packetin (&format->to, &pt);
1063
1064                 qtheora_comment_clear(&tc);
1065
1066                 if(cls.capturevideo.soundrate)
1067                 {
1068                         qvorbis_analysis_headerout(&format->vd, &vc, &pt, &pt2, &pt3);
1069                         qogg_stream_packetin(&format->vo, &pt);
1070                         if (qogg_stream_pageout (&format->vo, &pg) != 1)
1071                                 fprintf (stderr, "Internal Ogg library error.\n");
1072                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1073                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1074
1075                         qogg_stream_packetin(&format->vo, &pt2);
1076                         qogg_stream_packetin(&format->vo, &pt3);
1077
1078                         qvorbis_comment_clear(&vc);
1079                 }
1080
1081                 for(;;)
1082                 {
1083                         int result = qogg_stream_flush (&format->to, &pg);
1084                         if (result < 0)
1085                                 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Abort
1086                         if (result <= 0)
1087                                 break;
1088                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1089                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1090                 }
1091
1092                 if(cls.capturevideo.soundrate)
1093                 for(;;)
1094                 {
1095                         int result = qogg_stream_flush (&format->vo, &pg);
1096                         if (result < 0)
1097                                 fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Abort
1098                         if (result <= 0)
1099                                 break;
1100                         FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
1101                         FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len);
1102                 }
1103         }
1104 }