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