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