theora: Rename source files to have the same name as the headers
[platform/upstream/gstreamer.git] / ext / theora / gsttheoraenc.c
1 /* GStreamer
2  * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:element-theoraenc
22  * @see_also: theoradec, oggmux
23  *
24  * This element encodes raw video into a Theora stream.
25  * <ulink url="http://www.theora.org/">Theora</ulink> is a royalty-free
26  * video codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
27  * Foundation</ulink>, based on the VP3 codec.
28  *
29  * The theora codec internally only supports encoding of images that are a
30  * multiple of 16 pixels in both X and Y direction. It is however perfectly
31  * possible to encode images with other dimensions because an arbitrary
32  * rectangular cropping region can be set up. This element will automatically
33  * set up a correct cropping region if the dimensions are not multiples of 16
34  * pixels.
35  *
36  * To control the quality of the encoding, the #GstTheoraEnc::bitrate and
37  * #GstTheoraEnc::quality properties can be used. These two properties are
38  * mutualy exclusive. Setting the bitrate property will produce a constant
39  * bitrate (CBR) stream while setting the quality property will produce a
40  * variable bitrate (VBR) stream.
41  *
42  * <refsect2>
43  * <title>Example pipeline</title>
44  * |[
45  * gst-launch -v videotestsrc num-buffers=1000 ! theoraenc ! oggmux ! filesink location=videotestsrc.ogg
46  * ]| This example pipeline will encode a test video source to theora muxed in an
47  * ogg container. Refer to the theoradec documentation to decode the create
48  * stream.
49  * </refsect2>
50  *
51  * Last reviewed on 2006-03-01 (0.10.4)
52  */
53
54 #ifdef HAVE_CONFIG_H
55 #  include "config.h"
56 #endif
57
58 #include "gsttheoraenc.h"
59
60 #include <string.h>
61 #include <stdlib.h>             /* free */
62
63 #include <gst/tag/tag.h>
64 #include <gst/video/video.h>
65
66 #define GST_CAT_DEFAULT theoraenc_debug
67 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
68
69 #define GST_TYPE_BORDER_MODE (gst_border_mode_get_type())
70 static GType
71 gst_border_mode_get_type (void)
72 {
73   static GType border_mode_type = 0;
74   static const GEnumValue border_mode[] = {
75     {BORDER_NONE, "No Border", "none"},
76     {BORDER_BLACK, "Black Border", "black"},
77     {BORDER_MIRROR, "Mirror image in borders", "mirror"},
78     {0, NULL, NULL},
79   };
80
81   if (!border_mode_type) {
82     border_mode_type =
83         g_enum_register_static ("GstTheoraEncBorderMode", border_mode);
84   }
85   return border_mode_type;
86 }
87
88 /* taken from theora/lib/toplevel.c */
89 static int
90 _ilog (unsigned int v)
91 {
92   int ret = 0;
93
94   while (v) {
95     ret++;
96     v >>= 1;
97   }
98   return (ret);
99 }
100
101 #define THEORA_DEF_BITRATE              0
102 #define THEORA_DEF_QUALITY              48
103 #define THEORA_DEF_KEYFRAME_AUTO        TRUE
104 #define THEORA_DEF_KEYFRAME_FREQ        64
105 #define THEORA_DEF_KEYFRAME_FREQ_FORCE  64
106 #define THEORA_DEF_SPEEDLEVEL           1
107 #define THEORA_DEF_VP3_COMPATIBLE       FALSE
108 #define THEORA_DEF_DROP_FRAMES          TRUE
109 #define THEORA_DEF_CAP_OVERFLOW         TRUE
110 #define THEORA_DEF_CAP_UNDERFLOW        FALSE
111 #define THEORA_DEF_RATE_BUFFER          0
112 enum
113 {
114   ARG_0,
115   ARG_CENTER,
116   ARG_BORDER,
117   ARG_BITRATE,
118   ARG_QUALITY,
119   ARG_QUICK,
120   ARG_KEYFRAME_AUTO,
121   ARG_KEYFRAME_FREQ,
122   ARG_KEYFRAME_FREQ_FORCE,
123   ARG_KEYFRAME_THRESHOLD,
124   ARG_KEYFRAME_MINDISTANCE,
125   ARG_NOISE_SENSITIVITY,
126   ARG_SHARPNESS,
127   ARG_SPEEDLEVEL,
128   ARG_VP3_COMPATIBLE,
129   ARG_DROP_FRAMES,
130   ARG_CAP_OVERFLOW,
131   ARG_CAP_UNDERFLOW,
132   ARG_RATE_BUFFER,
133   /* FILL ME */
134 };
135
136 /* this function does a straight granulepos -> timestamp conversion */
137 static GstClockTime
138 granulepos_to_timestamp (GstTheoraEnc * theoraenc, ogg_int64_t granulepos)
139 {
140   guint64 iframe, pframe;
141   int shift = theoraenc->info.keyframe_granule_shift;
142
143   if (granulepos < 0)
144     return GST_CLOCK_TIME_NONE;
145
146   iframe = granulepos >> shift;
147   pframe = granulepos - (iframe << shift);
148
149   /* num and den are 32 bit, so we can safely multiply with GST_SECOND */
150   return gst_util_uint64_scale ((guint64) (iframe + pframe),
151       GST_SECOND * theoraenc->info.fps_denominator,
152       theoraenc->info.fps_numerator);
153 }
154
155 static const GstElementDetails theora_enc_details =
156 GST_ELEMENT_DETAILS ("Theora video encoder",
157     "Codec/Encoder/Video",
158     "encode raw YUV video to a theora stream",
159     "Wim Taymans <wim@fluendo.com>");
160
161 static GstStaticPadTemplate theora_enc_sink_factory =
162 GST_STATIC_PAD_TEMPLATE ("sink",
163     GST_PAD_SINK,
164     GST_PAD_ALWAYS,
165     GST_STATIC_CAPS ("video/x-raw-yuv, "
166         "format = (fourcc) { I420, Y42B, Y444 }, "
167         "framerate = (fraction) [0/1, MAX], "
168         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
169     );
170
171 static GstStaticPadTemplate theora_enc_src_factory =
172 GST_STATIC_PAD_TEMPLATE ("src",
173     GST_PAD_SRC,
174     GST_PAD_ALWAYS,
175     GST_STATIC_CAPS ("video/x-theora")
176     );
177
178 static void
179 _do_init (GType object_type)
180 {
181   const GInterfaceInfo preset_interface_info = {
182     NULL,                       /* interface_init */
183     NULL,                       /* interface_finalize */
184     NULL                        /* interface_data */
185   };
186
187   g_type_add_interface_static (object_type, GST_TYPE_PRESET,
188       &preset_interface_info);
189 }
190
191 GST_BOILERPLATE_FULL (GstTheoraEnc, gst_theora_enc, GstElement,
192     GST_TYPE_ELEMENT, _do_init);
193
194 static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event);
195 static gboolean theora_enc_src_event (GstPad * pad, GstEvent * event);
196 static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
197 static GstStateChangeReturn theora_enc_change_state (GstElement * element,
198     GstStateChange transition);
199 static GstCaps *theora_enc_sink_getcaps (GstPad * pad);
200 static gboolean theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
201 static void theora_enc_get_property (GObject * object, guint prop_id,
202     GValue * value, GParamSpec * pspec);
203 static void theora_enc_set_property (GObject * object, guint prop_id,
204     const GValue * value, GParamSpec * pspec);
205 static void theora_enc_finalize (GObject * object);
206
207 static void
208 gst_theora_enc_base_init (gpointer g_class)
209 {
210   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
211
212   gst_element_class_add_pad_template (element_class,
213       gst_static_pad_template_get (&theora_enc_src_factory));
214   gst_element_class_add_pad_template (element_class,
215       gst_static_pad_template_get (&theora_enc_sink_factory));
216   gst_element_class_set_details (element_class, &theora_enc_details);
217 }
218
219 static void
220 gst_theora_enc_class_init (GstTheoraEncClass * klass)
221 {
222   GObjectClass *gobject_class = (GObjectClass *) klass;
223   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
224
225   gobject_class->set_property = theora_enc_set_property;
226   gobject_class->get_property = theora_enc_get_property;
227   gobject_class->finalize = theora_enc_finalize;
228
229   g_object_class_install_property (gobject_class, ARG_CENTER,
230       g_param_spec_boolean ("center", "Center",
231           "ignored and kept for API compat only", TRUE,
232           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
233   g_object_class_install_property (gobject_class, ARG_BORDER,
234       g_param_spec_enum ("border", "Border",
235           "ignored and kept for API compat only",
236           GST_TYPE_BORDER_MODE, BORDER_BLACK,
237           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
238   /* general encoding stream options */
239   g_object_class_install_property (gobject_class, ARG_BITRATE,
240       g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
241           0, (1 << 24) - 1, THEORA_DEF_BITRATE,
242           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
243   g_object_class_install_property (gobject_class, ARG_QUALITY,
244       g_param_spec_int ("quality", "Quality", "Video quality", 0, 63,
245           THEORA_DEF_QUALITY,
246           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
247   g_object_class_install_property (gobject_class, ARG_QUICK,
248       g_param_spec_boolean ("quick", "Quick",
249           "ignored and kept for API compat only", TRUE,
250           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
251   g_object_class_install_property (gobject_class, ARG_KEYFRAME_AUTO,
252       g_param_spec_boolean ("keyframe-auto", "Keyframe Auto",
253           "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO,
254           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
255   g_object_class_install_property (gobject_class, ARG_KEYFRAME_FREQ,
256       g_param_spec_int ("keyframe-freq", "Keyframe frequency",
257           "Keyframe frequency", 1, 32768, THEORA_DEF_KEYFRAME_FREQ,
258           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
259   g_object_class_install_property (gobject_class, ARG_KEYFRAME_FREQ_FORCE,
260       g_param_spec_int ("keyframe-force", "Keyframe force",
261           "Force keyframe every N frames", 1, 32768,
262           THEORA_DEF_KEYFRAME_FREQ_FORCE,
263           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
264   g_object_class_install_property (gobject_class, ARG_KEYFRAME_THRESHOLD,
265       g_param_spec_int ("keyframe-threshold", "Keyframe threshold",
266           "ignored and kept for API compat only", 0, 32768, 80,
267           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
268   g_object_class_install_property (gobject_class, ARG_KEYFRAME_MINDISTANCE,
269       g_param_spec_int ("keyframe-mindistance", "Keyframe mindistance",
270           "ignored and kept for API compat only", 1, 32768, 8,
271           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
272   g_object_class_install_property (gobject_class, ARG_NOISE_SENSITIVITY,
273       g_param_spec_int ("noise-sensitivity", "Noise sensitivity",
274           "ignored and kept for API compat only", 0, 32768, 1,
275           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
276   g_object_class_install_property (gobject_class, ARG_SHARPNESS,
277       g_param_spec_int ("sharpness", "Sharpness",
278           "ignored and kept for API compat only", 0, 2, 0,
279           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
280   g_object_class_install_property (gobject_class, ARG_SPEEDLEVEL,
281       g_param_spec_int ("speed-level", "Speed level",
282           "Controls the amount of motion vector searching done while "
283           "encoding.  This property requires libtheora version >= 1.0",
284           0, 2, THEORA_DEF_SPEEDLEVEL,
285           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
286   g_object_class_install_property (gobject_class, ARG_VP3_COMPATIBLE,
287       g_param_spec_boolean ("vp3-compatible", "VP3 Compatible",
288           "Disables non-VP3 compatible features."
289           "  This property requires libtheora version >= 1.1",
290           THEORA_DEF_VP3_COMPATIBLE,
291           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
292   g_object_class_install_property (gobject_class, ARG_DROP_FRAMES,
293       g_param_spec_boolean ("drop-frames", "VP3 Compatible",
294           "Allow or disallow frame dropping."
295           "  This property requires libtheora version >= 1.1",
296           THEORA_DEF_DROP_FRAMES,
297           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
298   g_object_class_install_property (gobject_class, ARG_CAP_OVERFLOW,
299       g_param_spec_boolean ("cap-overflow", "VP3 Compatible",
300           "Enable capping of bit reservoir overflows."
301           "  This property requires libtheora version >= 1.1",
302           THEORA_DEF_CAP_OVERFLOW,
303           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
304   g_object_class_install_property (gobject_class, ARG_CAP_UNDERFLOW,
305       g_param_spec_boolean ("cap-underflow", "VP3 Compatible",
306           "Enable capping of bit reservoir underflows."
307           "  This property requires libtheora version >= 1.1",
308           THEORA_DEF_CAP_UNDERFLOW,
309           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
310   g_object_class_install_property (gobject_class, ARG_RATE_BUFFER,
311       g_param_spec_int ("rate-buffer", "Rate Control Buffer",
312           "Sets the size of the rate control buffer, in units of frames.  "
313           "The default value of 0 instructs the encoder to automatically "
314           "select an appropriate value."
315           "  This property requires libtheora version >= 1.1",
316           0, 1000, THEORA_DEF_RATE_BUFFER,
317           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
318
319   gstelement_class->change_state = theora_enc_change_state;
320   GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
321 }
322
323 static void
324 gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class)
325 {
326   enc->sinkpad =
327       gst_pad_new_from_static_template (&theora_enc_sink_factory, "sink");
328   gst_pad_set_chain_function (enc->sinkpad, theora_enc_chain);
329   gst_pad_set_event_function (enc->sinkpad, theora_enc_sink_event);
330   gst_pad_set_getcaps_function (enc->sinkpad, theora_enc_sink_getcaps);
331   gst_pad_set_setcaps_function (enc->sinkpad, theora_enc_sink_setcaps);
332   gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
333
334   enc->srcpad =
335       gst_pad_new_from_static_template (&theora_enc_src_factory, "src");
336   gst_pad_set_event_function (enc->srcpad, theora_enc_src_event);
337   gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
338
339   gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
340
341   enc->video_bitrate = THEORA_DEF_BITRATE;
342   enc->video_quality = THEORA_DEF_QUALITY;
343   enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
344   enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ;
345   enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE;
346
347   enc->expected_ts = GST_CLOCK_TIME_NONE;
348
349   enc->speed_level = THEORA_DEF_SPEEDLEVEL;
350   enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE;
351   enc->drop_frames = THEORA_DEF_DROP_FRAMES;
352   enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW;
353   enc->cap_underflow = THEORA_DEF_CAP_UNDERFLOW;
354   enc->rate_buffer = THEORA_DEF_RATE_BUFFER;
355 }
356
357 static void
358 theora_enc_finalize (GObject * object)
359 {
360   GstTheoraEnc *enc = GST_THEORA_ENC (object);
361
362   GST_DEBUG_OBJECT (enc, "Finalizing");
363   if (enc->encoder)
364     th_encode_free (enc->encoder);
365   th_comment_clear (&enc->comment);
366   th_info_clear (&enc->info);
367
368   G_OBJECT_CLASS (parent_class)->finalize (object);
369 }
370
371 static void
372 theora_enc_reset (GstTheoraEnc * enc)
373 {
374   ogg_uint32_t keyframe_force;
375   int rate_flags;
376
377   if (enc->encoder)
378     th_encode_free (enc->encoder);
379   enc->encoder = th_encode_alloc (&enc->info);
380   /* We ensure this function cannot fail. */
381   g_assert (enc->encoder != NULL);
382 #ifdef TH_ENCCTL_SET_SPLEVEL
383   th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
384       sizeof (enc->speed_level));
385 #endif
386 #ifdef TH_ENCCTL_SET_VP3_COMPATIBLE
387   th_encode_ctl (enc->encoder, TH_ENCCTL_SET_VP3_COMPATIBLE,
388       &enc->vp3_compatible, sizeof (enc->vp3_compatible));
389 #endif
390
391   rate_flags = 0;
392 #ifdef TH_ENCCTL_SET_RATE_FLAGS
393   if (enc->drop_frames)
394     rate_flags |= TH_RATECTL_DROP_FRAMES;
395   if (enc->drop_frames)
396     rate_flags |= TH_RATECTL_CAP_OVERFLOW;
397   if (enc->drop_frames)
398     rate_flags |= TH_RATECTL_CAP_UNDERFLOW;
399   th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_FLAGS,
400       &rate_flags, sizeof (rate_flags));
401 #endif
402
403 #ifdef TH_ENCCTL_SET_RATE_BUFFER
404   if (enc->rate_buffer) {
405     th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_BUFFER,
406         &enc->rate_buffer, sizeof (enc->rate_buffer));
407   } else {
408     /* FIXME */
409   }
410 #endif
411
412   keyframe_force = enc->keyframe_auto ?
413       enc->keyframe_force : enc->keyframe_freq;
414   th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
415       &keyframe_force, sizeof (keyframe_force));
416 }
417
418 static void
419 theora_enc_clear (GstTheoraEnc * enc)
420 {
421   enc->packetno = 0;
422   enc->bytes_out = 0;
423   enc->granulepos_offset = 0;
424   enc->timestamp_offset = 0;
425
426   enc->next_ts = GST_CLOCK_TIME_NONE;
427   enc->next_discont = FALSE;
428   enc->expected_ts = GST_CLOCK_TIME_NONE;
429 }
430
431 static char *
432 theora_enc_get_supported_formats (void)
433 {
434   th_enc_ctx *encoder;
435   th_info info;
436   struct
437   {
438     th_pixel_fmt pixelformat;
439     char *fourcc;
440   } formats[] = {
441     {
442     TH_PF_420, "I420"}, {
443     TH_PF_422, "Y42B"}, {
444     TH_PF_444, "Y444"}
445   };
446   GString *string = NULL;
447   guint i;
448
449   th_info_init (&info);
450   info.frame_width = 16;
451   info.frame_height = 16;
452   info.fps_numerator = 25;
453   info.fps_denominator = 1;
454   for (i = 0; i < G_N_ELEMENTS (formats); i++) {
455     info.pixel_fmt = formats[i].pixelformat;
456
457     encoder = th_encode_alloc (&info);
458     if (encoder == NULL)
459       continue;
460
461     GST_LOG ("format %s is supported", formats[i].fourcc);
462     th_encode_free (encoder);
463
464     if (string == NULL) {
465       string = g_string_new (formats[i].fourcc);
466     } else {
467       g_string_append (string, ", ");
468       g_string_append (string, formats[i].fourcc);
469     }
470   }
471   th_info_clear (&info);
472
473   return string == NULL ? NULL : g_string_free (string, FALSE);
474 }
475
476 static GstCaps *
477 theora_enc_sink_getcaps (GstPad * pad)
478 {
479   GstCaps *caps;
480   char *supported_formats, *caps_string;
481
482   supported_formats = theora_enc_get_supported_formats ();
483   if (!supported_formats) {
484     GST_WARNING ("no supported formats found. Encoder disabled?");
485     return gst_caps_new_empty ();
486   }
487
488   caps_string = g_strdup_printf ("video/x-raw-yuv, "
489       "format = (fourcc) { %s }, "
490       "framerate = (fraction) [0/1, MAX], "
491       "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]",
492       supported_formats);
493   caps = gst_caps_from_string (caps_string);
494   g_free (caps_string);
495   g_free (supported_formats);
496   GST_DEBUG ("Supported caps: %" GST_PTR_FORMAT, caps);
497
498   return caps;
499 }
500
501 static gboolean
502 theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
503 {
504   GstStructure *structure = gst_caps_get_structure (caps, 0);
505   GstTheoraEnc *enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
506   guint32 fourcc;
507   const GValue *par;
508   gint fps_n, fps_d;
509
510   gst_structure_get_fourcc (structure, "format", &fourcc);
511   gst_structure_get_int (structure, "width", &enc->width);
512   gst_structure_get_int (structure, "height", &enc->height);
513   gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d);
514   par = gst_structure_get_value (structure, "pixel-aspect-ratio");
515
516   th_info_clear (&enc->info);
517   th_info_init (&enc->info);
518   /* Theora has a divisible-by-sixteen restriction for the encoded video size but
519    * we can define a picture area using pic_width/pic_height */
520   enc->info.frame_width = GST_ROUND_UP_16 (enc->width);
521   enc->info.frame_height = GST_ROUND_UP_16 (enc->height);
522   enc->info.pic_width = enc->width;
523   enc->info.pic_height = enc->height;
524   switch (fourcc) {
525     case GST_MAKE_FOURCC ('I', '4', '2', '0'):
526       enc->info.pixel_fmt = TH_PF_420;
527       break;
528     case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
529       enc->info.pixel_fmt = TH_PF_422;
530       break;
531     case GST_MAKE_FOURCC ('Y', '4', '4', '4'):
532       enc->info.pixel_fmt = TH_PF_444;
533       break;
534     default:
535       g_assert_not_reached ();
536   }
537
538   enc->info.fps_numerator = enc->fps_n = fps_n;
539   enc->info.fps_denominator = enc->fps_d = fps_d;
540   if (par) {
541     enc->info.aspect_numerator = gst_value_get_fraction_numerator (par);
542     enc->info.aspect_denominator = gst_value_get_fraction_denominator (par);
543   } else {
544     /* setting them to 0 indicates that the decoder can chose a good aspect
545      * ratio, defaulting to 1/1 */
546     enc->info.aspect_numerator = 0;
547     enc->info.aspect_denominator = 0;
548   }
549
550   enc->info.colorspace = TH_CS_UNSPECIFIED;
551   enc->info.target_bitrate = enc->video_bitrate;
552   enc->info.quality = enc->video_quality;
553
554   /* as done in theora */
555   enc->info.keyframe_granule_shift = _ilog (enc->keyframe_force - 1);
556   GST_DEBUG_OBJECT (enc,
557       "keyframe_frequency_force is %d, granule shift is %d",
558       enc->keyframe_force, enc->info.keyframe_granule_shift);
559
560   theora_enc_reset (enc);
561   enc->initialised = TRUE;
562
563   gst_object_unref (enc);
564
565   return TRUE;
566 }
567
568 static guint64
569 granulepos_add (guint64 granulepos, guint64 addend, gint shift)
570 {
571   guint64 iframe, pframe;
572
573   iframe = granulepos >> shift;
574   pframe = granulepos - (iframe << shift);
575   iframe += addend;
576
577   return (iframe << shift) + pframe;
578 }
579
580 /* prepare a buffer for transmission by passing data through libtheora */
581 static GstFlowReturn
582 theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
583     GstClockTime timestamp, GstClockTime running_time,
584     GstClockTime duration, GstBuffer ** buffer)
585 {
586   GstBuffer *buf;
587   GstFlowReturn ret = GST_FLOW_OK;
588
589   buf = gst_buffer_new_and_alloc (packet->bytes);
590   if (!buf) {
591     GST_WARNING_OBJECT (enc, "Could not allocate buffer");
592     ret = GST_FLOW_ERROR;
593     goto done;
594   }
595
596   memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
597   gst_buffer_set_caps (buf, GST_PAD_CAPS (enc->srcpad));
598   /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
599    * time representation */
600   GST_BUFFER_OFFSET_END (buf) =
601       granulepos_add (packet->granulepos, enc->granulepos_offset,
602       enc->info.keyframe_granule_shift);
603   GST_BUFFER_OFFSET (buf) = granulepos_to_timestamp (enc,
604       GST_BUFFER_OFFSET_END (buf));
605
606   GST_BUFFER_TIMESTAMP (buf) = timestamp;
607   GST_BUFFER_DURATION (buf) = duration;
608
609   if (enc->next_discont) {
610     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
611     enc->next_discont = FALSE;
612   }
613
614   /* the second most significant bit of the first data byte is cleared
615    * for keyframes */
616   if ((packet->packet[0] & 0x40) == 0) {
617     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
618   } else {
619     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
620   }
621   enc->packetno++;
622
623 done:
624   *buffer = buf;
625   return ret;
626 }
627
628 /* push out the buffer and do internal bookkeeping */
629 static GstFlowReturn
630 theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
631 {
632   GstFlowReturn ret;
633
634   enc->bytes_out += GST_BUFFER_SIZE (buffer);
635
636   ret = gst_pad_push (enc->srcpad, buffer);
637
638   return ret;
639 }
640
641 static GstFlowReturn
642 theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet,
643     GstClockTime timestamp, GstClockTime running_time, GstClockTime duration)
644 {
645   GstBuffer *buf;
646   GstFlowReturn ret;
647
648   ret =
649       theora_buffer_from_packet (enc, packet, timestamp, running_time, duration,
650       &buf);
651   if (ret == GST_FLOW_OK)
652     ret = theora_push_buffer (enc, buf);
653
654   return ret;
655 }
656
657 static GstCaps *
658 theora_set_header_on_caps (GstCaps * caps, GSList * buffers)
659 {
660   GstStructure *structure;
661   GValue array = { 0 };
662   GValue value = { 0 };
663   GstBuffer *buffer;
664   GSList *walk;
665
666   caps = gst_caps_make_writable (caps);
667   structure = gst_caps_get_structure (caps, 0);
668
669   /* put copies of the buffers in a fixed list */
670   g_value_init (&array, GST_TYPE_ARRAY);
671
672   for (walk = buffers; walk; walk = walk->next) {
673     buffer = walk->data;
674
675     /* mark buffer */
676     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
677
678     /* Copy buffer, because we can't use the original -
679      * it creates a circular refcount with the caps<->buffers */
680     buffer = gst_buffer_copy (buffer);
681
682     g_value_init (&value, GST_TYPE_BUFFER);
683     gst_value_set_buffer (&value, buffer);
684     gst_value_array_append_value (&array, &value);
685     g_value_unset (&value);
686
687     /* Unref our copy */
688     gst_buffer_unref (buffer);
689   }
690
691   gst_structure_set_value (structure, "streamheader", &array);
692   g_value_unset (&array);
693
694   return caps;
695 }
696
697 static void
698 theora_enc_force_keyframe (GstTheoraEnc * enc)
699 {
700   GstClockTime next_ts;
701
702   /* make sure timestamps increment after resetting the decoder */
703   next_ts = enc->next_ts + enc->timestamp_offset;
704
705   theora_enc_reset (enc);
706   enc->granulepos_offset =
707       gst_util_uint64_scale (next_ts, enc->fps_n, GST_SECOND * enc->fps_d);
708   enc->timestamp_offset = next_ts;
709   enc->next_ts = 0;
710 }
711
712 static gboolean
713 theora_enc_sink_event (GstPad * pad, GstEvent * event)
714 {
715   GstTheoraEnc *enc;
716   ogg_packet op;
717   gboolean res;
718
719   enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
720
721   switch (GST_EVENT_TYPE (event)) {
722     case GST_EVENT_NEWSEGMENT:
723     {
724       gboolean update;
725       gdouble rate, applied_rate;
726       GstFormat format;
727       gint64 start, stop, time;
728
729       gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
730           &format, &start, &stop, &time);
731
732       gst_segment_set_newsegment_full (&enc->segment, update, rate,
733           applied_rate, format, start, stop, time);
734
735       res = gst_pad_push_event (enc->srcpad, event);
736       break;
737     }
738     case GST_EVENT_EOS:
739       if (enc->initialised) {
740         /* push last packet with eos flag, should not be called */
741         while (th_encode_packetout (enc->encoder, 1, &op)) {
742           GstClockTime next_time =
743               th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
744
745           theora_push_packet (enc, &op, GST_CLOCK_TIME_NONE, enc->next_ts,
746               next_time - enc->next_ts);
747           enc->next_ts = next_time;
748         }
749       }
750       res = gst_pad_push_event (enc->srcpad, event);
751       break;
752     case GST_EVENT_FLUSH_STOP:
753       gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
754       res = gst_pad_push_event (enc->srcpad, event);
755       break;
756     case GST_EVENT_CUSTOM_DOWNSTREAM:
757     {
758       const GstStructure *s;
759
760       s = gst_event_get_structure (event);
761
762       if (gst_structure_has_name (s, "GstForceKeyUnit"))
763         theora_enc_force_keyframe (enc);
764       res = gst_pad_push_event (enc->srcpad, event);
765       break;
766     }
767     default:
768       res = gst_pad_push_event (enc->srcpad, event);
769       break;
770   }
771   return res;
772 }
773
774 static gboolean
775 theora_enc_src_event (GstPad * pad, GstEvent * event)
776 {
777   GstTheoraEnc *enc;
778   gboolean res = TRUE;
779
780   enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
781
782   switch (GST_EVENT_TYPE (event)) {
783     case GST_EVENT_CUSTOM_UPSTREAM:
784     {
785       const GstStructure *s;
786
787       s = gst_event_get_structure (event);
788
789       if (gst_structure_has_name (s, "GstForceKeyUnit")) {
790         GST_OBJECT_LOCK (enc);
791         enc->force_keyframe = TRUE;
792         GST_OBJECT_UNLOCK (enc);
793         /* consume the event */
794         res = TRUE;
795         gst_event_unref (event);
796       } else {
797         res = gst_pad_push_event (enc->sinkpad, event);
798       }
799       break;
800     }
801     default:
802       res = gst_pad_push_event (enc->sinkpad, event);
803       break;
804   }
805
806   return res;
807 }
808
809 static gboolean
810 theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp,
811     GstClockTime duration)
812 {
813   GstClockTimeDiff max_diff;
814   gboolean ret = FALSE;
815
816   /* Allow 3/4 a frame off */
817   max_diff = (enc->info.fps_denominator * GST_SECOND * 3) /
818       (enc->info.fps_numerator * 4);
819
820   if (timestamp != GST_CLOCK_TIME_NONE
821       && enc->expected_ts != GST_CLOCK_TIME_NONE) {
822     if ((GstClockTimeDiff) (timestamp - enc->expected_ts) > max_diff) {
823       GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT
824           " exceeds expected value %" GST_TIME_FORMAT
825           " by too much, marking discontinuity",
826           GST_TIME_ARGS (timestamp), GST_TIME_ARGS (enc->expected_ts));
827       ret = TRUE;
828     }
829   }
830
831   if (GST_CLOCK_TIME_IS_VALID (duration))
832     enc->expected_ts = timestamp + duration;
833   else
834     enc->expected_ts = GST_CLOCK_TIME_NONE;
835
836   return ret;
837 }
838
839 static void
840 theora_enc_init_buffer (th_ycbcr_buffer buf, th_info * info, guint8 * data)
841 {
842   GstVideoFormat format;
843   guint i;
844
845   switch (info->pixel_fmt) {
846     case TH_PF_444:
847       format = GST_VIDEO_FORMAT_Y444;
848       break;
849     case TH_PF_420:
850       format = GST_VIDEO_FORMAT_I420;
851       break;
852     case TH_PF_422:
853       format = GST_VIDEO_FORMAT_Y42B;
854       break;
855     default:
856       g_assert_not_reached ();
857   }
858
859   /* According to Theora developer Timothy Terriberry, the Theora 
860    * encoder will not use memory outside of pic_width/height, even when
861    * the frame size is bigger. The values outside this region will be encoded
862    * to default values.
863    * Due to this, setting the frame's width/height as the buffer width/height
864    * is perfectly ok, even though it does not strictly look ok.
865    */
866   for (i = 0; i < 3; i++) {
867     buf[i].width =
868         gst_video_format_get_component_width (format, i, info->frame_width);
869     buf[i].height =
870         gst_video_format_get_component_height (format, i, info->frame_height);
871
872     buf[i].data =
873         data + gst_video_format_get_component_offset (format, i,
874         info->pic_width, info->pic_height);
875     buf[i].stride =
876         gst_video_format_get_row_stride (format, i, info->pic_width);
877   }
878 }
879
880 static GstFlowReturn
881 theora_enc_chain (GstPad * pad, GstBuffer * buffer)
882 {
883   GstTheoraEnc *enc;
884   ogg_packet op;
885   GstClockTime timestamp, duration, running_time;
886   GstFlowReturn ret;
887   gboolean force_keyframe;
888
889   enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
890
891   /* we keep track of two timelines.
892    * - The timestamps from the incomming buffers, which we copy to the outgoing
893    *   encoded buffers as-is. We need to do this as we simply forward the
894    *   newsegment events.
895    * - The running_time of the buffers, which we use to construct the granulepos
896    *   in the packets.
897    */
898   timestamp = GST_BUFFER_TIMESTAMP (buffer);
899   duration = GST_BUFFER_DURATION (buffer);
900
901   running_time =
902       gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
903   if ((gint64) running_time < 0) {
904     GST_DEBUG_OBJECT (enc, "Dropping buffer, timestamp: %" GST_TIME_FORMAT,
905         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
906     gst_buffer_unref (buffer);
907     return GST_FLOW_OK;
908   }
909
910   /* see if we need to schedule a keyframe */
911   GST_OBJECT_LOCK (enc);
912   force_keyframe = enc->force_keyframe;
913   enc->force_keyframe = FALSE;
914   GST_OBJECT_UNLOCK (enc);
915
916   if (force_keyframe) {
917     GstClockTime stream_time;
918     GstStructure *s;
919
920     stream_time = gst_segment_to_stream_time (&enc->segment,
921         GST_FORMAT_TIME, timestamp);
922
923     s = gst_structure_new ("GstForceKeyUnit",
924         "timestamp", G_TYPE_UINT64, timestamp,
925         "stream-time", G_TYPE_UINT64, stream_time,
926         "running-time", G_TYPE_UINT64, running_time, NULL);
927
928     theora_enc_force_keyframe (enc);
929
930     gst_pad_push_event (enc->srcpad,
931         gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
932   }
933
934   /* make sure we copy the discont flag to the next outgoing buffer when it's
935    * set on the incomming buffer */
936   if (GST_BUFFER_IS_DISCONT (buffer)) {
937     enc->next_discont = TRUE;
938   }
939
940   if (enc->packetno == 0) {
941     /* no packets written yet, setup headers */
942     GstCaps *caps;
943     GstBuffer *buf;
944     GSList *buffers = NULL;
945     int result;
946
947     enc->granulepos_offset = 0;
948     enc->timestamp_offset = 0;
949
950     GST_DEBUG_OBJECT (enc, "output headers");
951     /* Theora streams begin with three headers; the initial header (with
952        most of the codec setup parameters) which is mandated by the Ogg
953        bitstream spec.  The second header holds any comment fields.  The
954        third header holds the bitstream codebook.  We merely need to
955        make the headers, then pass them to libtheora one at a time;
956        libtheora handles the additional Ogg bitstream constraints */
957
958     /* create the remaining theora headers */
959     th_comment_clear (&enc->comment);
960     th_comment_init (&enc->comment);
961
962     while ((result =
963             th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
964       ret =
965           theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
966           GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf);
967       if (ret != GST_FLOW_OK) {
968         goto header_buffer_alloc;
969       }
970       buffers = g_slist_prepend (buffers, buf);
971     }
972     if (result < 0) {
973       g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
974       g_slist_free (buffers);
975       goto encoder_disabled;
976     }
977
978     buffers = g_slist_reverse (buffers);
979
980     /* mark buffers and put on caps */
981     caps = gst_pad_get_caps (enc->srcpad);
982     caps = theora_set_header_on_caps (caps, buffers);
983     GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
984     gst_pad_set_caps (enc->srcpad, caps);
985
986     g_slist_foreach (buffers, (GFunc) gst_buffer_set_caps, caps);
987
988     gst_caps_unref (caps);
989
990     /* push out the header buffers */
991     while (buffers) {
992       buf = buffers->data;
993       buffers = g_slist_delete_link (buffers, buffers);
994       if ((ret = theora_push_buffer (enc, buf)) != GST_FLOW_OK) {
995         g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
996         g_slist_free (buffers);
997         goto header_push;
998       }
999     }
1000
1001     enc->granulepos_offset =
1002         gst_util_uint64_scale (running_time, enc->fps_n,
1003         GST_SECOND * enc->fps_d);
1004     enc->timestamp_offset = running_time;
1005     enc->next_ts = 0;
1006   }
1007
1008   {
1009     th_ycbcr_buffer ycbcr;
1010     gint res;
1011
1012     theora_enc_init_buffer (ycbcr, &enc->info, GST_BUFFER_DATA (buffer));
1013
1014     if (theora_enc_is_discontinuous (enc, running_time, duration)) {
1015       theora_enc_reset (enc);
1016       enc->granulepos_offset =
1017           gst_util_uint64_scale (running_time, enc->fps_n,
1018           GST_SECOND * enc->fps_d);
1019       enc->timestamp_offset = running_time;
1020       enc->next_ts = 0;
1021       enc->next_discont = TRUE;
1022     }
1023
1024     res = th_encode_ycbcr_in (enc->encoder, ycbcr);
1025     /* none of the failure cases can happen here */
1026     g_assert (res == 0);
1027
1028     ret = GST_FLOW_OK;
1029     while (th_encode_packetout (enc->encoder, 0, &op)) {
1030       GstClockTime next_time;
1031
1032       next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
1033
1034       ret =
1035           theora_push_packet (enc, &op, timestamp, enc->next_ts,
1036           next_time - enc->next_ts);
1037
1038       enc->next_ts = next_time;
1039       if (ret != GST_FLOW_OK)
1040         goto data_push;
1041     }
1042     gst_buffer_unref (buffer);
1043   }
1044
1045   return ret;
1046
1047   /* ERRORS */
1048 header_buffer_alloc:
1049   {
1050     gst_buffer_unref (buffer);
1051     return ret;
1052   }
1053 header_push:
1054   {
1055     gst_buffer_unref (buffer);
1056     return ret;
1057   }
1058 data_push:
1059   {
1060     gst_buffer_unref (buffer);
1061     return ret;
1062   }
1063 encoder_disabled:
1064   {
1065     GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1066         ("libtheora has been compiled with the encoder disabled"));
1067     gst_buffer_unref (buffer);
1068     return GST_FLOW_ERROR;
1069   }
1070 }
1071
1072 static GstStateChangeReturn
1073 theora_enc_change_state (GstElement * element, GstStateChange transition)
1074 {
1075   GstTheoraEnc *enc;
1076   GstStateChangeReturn ret;
1077
1078   enc = GST_THEORA_ENC (element);
1079
1080   switch (transition) {
1081     case GST_STATE_CHANGE_NULL_TO_READY:
1082       break;
1083     case GST_STATE_CHANGE_READY_TO_PAUSED:
1084       GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state");
1085       th_info_init (&enc->info);
1086       th_comment_init (&enc->comment);
1087       enc->packetno = 0;
1088       enc->force_keyframe = FALSE;
1089       break;
1090     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1091       break;
1092     default:
1093       break;
1094   }
1095
1096   ret = parent_class->change_state (element, transition);
1097
1098   switch (transition) {
1099     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1100       break;
1101     case GST_STATE_CHANGE_PAUSED_TO_READY:
1102       GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state");
1103       if (enc->encoder) {
1104         th_encode_free (enc->encoder);
1105         enc->encoder = NULL;
1106       }
1107       th_comment_clear (&enc->comment);
1108       th_info_clear (&enc->info);
1109
1110       theora_enc_clear (enc);
1111       enc->initialised = FALSE;
1112       break;
1113     case GST_STATE_CHANGE_READY_TO_NULL:
1114       break;
1115     default:
1116       break;
1117   }
1118
1119   return ret;
1120 }
1121
1122 static void
1123 theora_enc_set_property (GObject * object, guint prop_id,
1124     const GValue * value, GParamSpec * pspec)
1125 {
1126   GstTheoraEnc *enc = GST_THEORA_ENC (object);
1127
1128   switch (prop_id) {
1129     case ARG_CENTER:
1130     case ARG_BORDER:
1131     case ARG_QUICK:
1132     case ARG_KEYFRAME_THRESHOLD:
1133     case ARG_KEYFRAME_MINDISTANCE:
1134     case ARG_NOISE_SENSITIVITY:
1135     case ARG_SHARPNESS:
1136       /* kept for API compat, but ignored */
1137       break;
1138     case ARG_BITRATE:
1139       enc->video_bitrate = g_value_get_int (value) * 1000;
1140       enc->video_quality = 0;
1141       break;
1142     case ARG_QUALITY:
1143       enc->video_quality = g_value_get_int (value);
1144       enc->video_bitrate = 0;
1145       break;
1146     case ARG_KEYFRAME_AUTO:
1147       enc->keyframe_auto = g_value_get_boolean (value);
1148       break;
1149     case ARG_KEYFRAME_FREQ:
1150       enc->keyframe_freq = g_value_get_int (value);
1151       break;
1152     case ARG_KEYFRAME_FREQ_FORCE:
1153       enc->keyframe_force = g_value_get_int (value);
1154       break;
1155     case ARG_SPEEDLEVEL:
1156 #ifdef TH_ENCCTL_SET_SPLEVEL
1157       enc->speed_level = g_value_get_int (value);
1158 #endif
1159       break;
1160     case ARG_VP3_COMPATIBLE:
1161 #ifdef TH_ENCCTL_SET_VP3_COMPATIBLE
1162       enc->vp3_compatible = g_value_get_boolean (value);
1163 #endif
1164       break;
1165     case ARG_DROP_FRAMES:
1166 #ifdef TH_ENCCTL_SET_RATE_FLAGS
1167       enc->drop_frames = g_value_get_boolean (value);
1168 #endif
1169       break;
1170     case ARG_CAP_OVERFLOW:
1171 #ifdef TH_ENCCTL_SET_RATE_FLAGS
1172       enc->cap_overflow = g_value_get_boolean (value);
1173 #endif
1174       break;
1175     case ARG_CAP_UNDERFLOW:
1176 #ifdef TH_ENCCTL_SET_RATE_FLAGS
1177       enc->cap_underflow = g_value_get_boolean (value);
1178 #endif
1179       break;
1180     case ARG_RATE_BUFFER:
1181 #ifdef TH_ENCCTL_SET_RATE_BUFFER
1182       enc->rate_buffer = g_value_get_int (value);
1183 #endif
1184       break;
1185     default:
1186       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1187       break;
1188   }
1189 }
1190
1191 static void
1192 theora_enc_get_property (GObject * object, guint prop_id,
1193     GValue * value, GParamSpec * pspec)
1194 {
1195   GstTheoraEnc *enc = GST_THEORA_ENC (object);
1196
1197   switch (prop_id) {
1198     case ARG_CENTER:
1199       g_value_set_boolean (value, TRUE);
1200       break;
1201     case ARG_BORDER:
1202       g_value_set_enum (value, BORDER_BLACK);
1203       break;
1204     case ARG_BITRATE:
1205       g_value_set_int (value, enc->video_bitrate / 1000);
1206       break;
1207     case ARG_QUALITY:
1208       g_value_set_int (value, enc->video_quality);
1209       break;
1210     case ARG_QUICK:
1211       g_value_set_boolean (value, TRUE);
1212       break;
1213     case ARG_KEYFRAME_AUTO:
1214       g_value_set_boolean (value, enc->keyframe_auto);
1215       break;
1216     case ARG_KEYFRAME_FREQ:
1217       g_value_set_int (value, enc->keyframe_freq);
1218       break;
1219     case ARG_KEYFRAME_FREQ_FORCE:
1220       g_value_set_int (value, enc->keyframe_force);
1221       break;
1222     case ARG_KEYFRAME_THRESHOLD:
1223       g_value_set_int (value, 80);
1224       break;
1225     case ARG_KEYFRAME_MINDISTANCE:
1226       g_value_set_int (value, 8);
1227       break;
1228     case ARG_NOISE_SENSITIVITY:
1229       g_value_set_int (value, 1);
1230       break;
1231     case ARG_SHARPNESS:
1232       g_value_set_int (value, 0);
1233       break;
1234     case ARG_SPEEDLEVEL:
1235       g_value_set_int (value, enc->speed_level);
1236       break;
1237     case ARG_VP3_COMPATIBLE:
1238       g_value_set_boolean (value, enc->vp3_compatible);
1239       break;
1240     case ARG_DROP_FRAMES:
1241       g_value_set_boolean (value, enc->drop_frames);
1242       break;
1243     case ARG_CAP_OVERFLOW:
1244       g_value_set_boolean (value, enc->cap_overflow);
1245       break;
1246     case ARG_CAP_UNDERFLOW:
1247       g_value_set_boolean (value, enc->cap_underflow);
1248       break;
1249     case ARG_RATE_BUFFER:
1250       g_value_set_int (value, enc->rate_buffer);
1251       break;
1252     default:
1253       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1254       break;
1255   }
1256 }