subparse: Send timestamp map custom event for HLS webvtt
[platform/upstream/gstreamer.git] / ext / theora / gsttheoraenc.c
1 /* GStreamer
2  * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
3  * Copyright (c) 2012 Collabora Ltd.
4  *      Author : Edward Hervey <edward@collabora.com>
5  *      Author : Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 /**
24  * SECTION:element-theoraenc
25  * @title: theoraenc
26  * @see_also: theoradec, oggmux
27  *
28  * This element encodes raw video into a Theora stream.
29  * <ulink url="http://www.theora.org/">Theora</ulink> is a royalty-free
30  * video codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
31  * Foundation</ulink>, based on the VP3 codec.
32  *
33  * The theora codec internally only supports encoding of images that are a
34  * multiple of 16 pixels in both X and Y direction. It is however perfectly
35  * possible to encode images with other dimensions because an arbitrary
36  * rectangular cropping region can be set up. This element will automatically
37  * set up a correct cropping region if the dimensions are not multiples of 16
38  * pixels.
39  *
40  * To control the quality of the encoding, the #GstTheoraEnc::bitrate and
41  * #GstTheoraEnc::quality properties can be used. These two properties are
42  * mutualy exclusive. Setting the bitrate property will produce a constant
43  * bitrate (CBR) stream while setting the quality property will produce a
44  * variable bitrate (VBR) stream.
45  *
46  * A videorate element is often required in front of theoraenc, especially
47  * when transcoding and when putting Theora into the Ogg container.
48  *
49  * ## Example pipeline
50  * |[
51  * gst-launch-1.0 -v videotestsrc num-buffers=500 ! video/x-raw,width=1280,height=720 ! queue ! progressreport ! theoraenc ! oggmux ! filesink location=videotestsrc.ogg
52  * ]|
53  *  This example pipeline will encode a test video source to theora muxed in an
54  * ogg container. Refer to the theoradec documentation to decode the create
55  * stream.
56  *
57  */
58
59 #ifdef HAVE_CONFIG_H
60 #include "config.h"
61 #endif
62
63 #include <string.h>
64 #include <stdlib.h>             /* free */
65
66 #include <gst/tag/tag.h>
67 #include <gst/video/video.h>
68 #include <gst/video/gstvideometa.h>
69
70 #include "gsttheoraenc.h"
71
72 #define GST_CAT_DEFAULT theoraenc_debug
73 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
74
75 #define GST_TYPE_MULTIPASS_MODE (gst_multipass_mode_get_type())
76 static GType
77 gst_multipass_mode_get_type (void)
78 {
79   static GType multipass_mode_type = 0;
80   static const GEnumValue multipass_mode[] = {
81     {MULTIPASS_MODE_SINGLE_PASS, "Single pass", "single-pass"},
82     {MULTIPASS_MODE_FIRST_PASS, "First pass", "first-pass"},
83     {MULTIPASS_MODE_SECOND_PASS, "Second pass", "second-pass"},
84     {0, NULL, NULL},
85   };
86
87   if (!multipass_mode_type) {
88     multipass_mode_type =
89         g_enum_register_static ("GstTheoraEncMultipassMode", multipass_mode);
90   }
91   return multipass_mode_type;
92 }
93
94 /* taken from theora/lib/toplevel.c */
95 static int
96 _ilog (unsigned int v)
97 {
98   int ret = 0;
99
100   while (v) {
101     ret++;
102     v >>= 1;
103   }
104   return (ret);
105 }
106
107 #define THEORA_DEF_BITRATE              0
108 #define THEORA_DEF_QUALITY              48
109 #define THEORA_DEF_KEYFRAME_AUTO        TRUE
110 #define THEORA_DEF_KEYFRAME_FREQ        64
111 #define THEORA_DEF_KEYFRAME_FREQ_FORCE  64
112 #define THEORA_DEF_SPEEDLEVEL           1
113 #define THEORA_DEF_VP3_COMPATIBLE       FALSE
114 #define THEORA_DEF_DROP_FRAMES          TRUE
115 #define THEORA_DEF_CAP_OVERFLOW         TRUE
116 #define THEORA_DEF_CAP_UNDERFLOW        FALSE
117 #define THEORA_DEF_RATE_BUFFER          0
118 #define THEORA_DEF_MULTIPASS_CACHE_FILE NULL
119 #define THEORA_DEF_MULTIPASS_MODE       MULTIPASS_MODE_SINGLE_PASS
120 enum
121 {
122   PROP_0,
123   PROP_BITRATE,
124   PROP_QUALITY,
125   PROP_KEYFRAME_AUTO,
126   PROP_KEYFRAME_FREQ,
127   PROP_KEYFRAME_FREQ_FORCE,
128   PROP_SPEEDLEVEL,
129   PROP_VP3_COMPATIBLE,
130   PROP_DROP_FRAMES,
131   PROP_CAP_OVERFLOW,
132   PROP_CAP_UNDERFLOW,
133   PROP_RATE_BUFFER,
134   PROP_MULTIPASS_CACHE_FILE,
135   PROP_MULTIPASS_MODE
136       /* FILL ME */
137 };
138
139 /* this function does a straight granulepos -> timestamp conversion */
140 static GstClockTime
141 granulepos_to_timestamp (GstTheoraEnc * theoraenc, ogg_int64_t granulepos)
142 {
143   guint64 iframe, pframe;
144   int shift = theoraenc->info.keyframe_granule_shift;
145
146   if (granulepos < 0)
147     return GST_CLOCK_TIME_NONE;
148
149   iframe = granulepos >> shift;
150   pframe = granulepos - (iframe << shift);
151
152   /* num and den are 32 bit, so we can safely multiply with GST_SECOND */
153   return gst_util_uint64_scale ((guint64) (iframe + pframe),
154       GST_SECOND * theoraenc->info.fps_denominator,
155       theoraenc->info.fps_numerator);
156 }
157
158 static GstStaticPadTemplate theora_enc_sink_factory =
159 GST_STATIC_PAD_TEMPLATE ("sink",
160     GST_PAD_SINK,
161     GST_PAD_ALWAYS,
162     GST_STATIC_CAPS ("video/x-raw, "
163         "format = (string) { I420, Y42B, Y444 }, "
164         "framerate = (fraction) [1/MAX, MAX], "
165         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
166     );
167
168 static GstStaticPadTemplate theora_enc_src_factory =
169 GST_STATIC_PAD_TEMPLATE ("src",
170     GST_PAD_SRC,
171     GST_PAD_ALWAYS,
172     GST_STATIC_CAPS ("video/x-theora, "
173         "framerate = (fraction) [1/MAX, MAX], "
174         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
175     );
176
177 #define gst_theora_enc_parent_class parent_class
178 G_DEFINE_TYPE (GstTheoraEnc, gst_theora_enc, GST_TYPE_VIDEO_ENCODER);
179
180 static gboolean theora_enc_start (GstVideoEncoder * enc);
181 static gboolean theora_enc_stop (GstVideoEncoder * enc);
182 static gboolean theora_enc_flush (GstVideoEncoder * enc);
183 static gboolean theora_enc_set_format (GstVideoEncoder * enc,
184     GstVideoCodecState * state);
185 static GstFlowReturn theora_enc_handle_frame (GstVideoEncoder * enc,
186     GstVideoCodecFrame * frame);
187 static GstFlowReturn theora_enc_pre_push (GstVideoEncoder * benc,
188     GstVideoCodecFrame * frame);
189 static GstFlowReturn theora_enc_finish (GstVideoEncoder * enc);
190 static gboolean theora_enc_propose_allocation (GstVideoEncoder * encoder,
191     GstQuery * query);
192
193 static GstCaps *theora_enc_getcaps (GstVideoEncoder * encoder,
194     GstCaps * filter);
195 static void theora_enc_get_property (GObject * object, guint prop_id,
196     GValue * value, GParamSpec * pspec);
197 static void theora_enc_set_property (GObject * object, guint prop_id,
198     const GValue * value, GParamSpec * pspec);
199 static void theora_enc_finalize (GObject * object);
200
201 static gboolean theora_enc_write_multipass_cache (GstTheoraEnc * enc,
202     gboolean begin, gboolean eos);
203
204 static void
205 gst_theora_enc_class_init (GstTheoraEncClass * klass)
206 {
207   GObjectClass *gobject_class = (GObjectClass *) klass;
208   GstElementClass *element_class = (GstElementClass *) klass;
209   GstVideoEncoderClass *gstvideo_encoder_class =
210       GST_VIDEO_ENCODER_CLASS (klass);
211
212   gobject_class->set_property = theora_enc_set_property;
213   gobject_class->get_property = theora_enc_get_property;
214   gobject_class->finalize = theora_enc_finalize;
215
216   gst_element_class_add_static_pad_template (element_class,
217       &theora_enc_src_factory);
218   gst_element_class_add_static_pad_template (element_class,
219       &theora_enc_sink_factory);
220   gst_element_class_set_static_metadata (element_class, "Theora video encoder",
221       "Codec/Encoder/Video", "encode raw YUV video to a theora stream",
222       "Wim Taymans <wim@fluendo.com>");
223
224   gstvideo_encoder_class->start = GST_DEBUG_FUNCPTR (theora_enc_start);
225   gstvideo_encoder_class->stop = GST_DEBUG_FUNCPTR (theora_enc_stop);
226   gstvideo_encoder_class->flush = GST_DEBUG_FUNCPTR (theora_enc_flush);
227   gstvideo_encoder_class->set_format =
228       GST_DEBUG_FUNCPTR (theora_enc_set_format);
229   gstvideo_encoder_class->handle_frame =
230       GST_DEBUG_FUNCPTR (theora_enc_handle_frame);
231   gstvideo_encoder_class->pre_push = GST_DEBUG_FUNCPTR (theora_enc_pre_push);
232   gstvideo_encoder_class->finish = GST_DEBUG_FUNCPTR (theora_enc_finish);
233   gstvideo_encoder_class->getcaps = GST_DEBUG_FUNCPTR (theora_enc_getcaps);
234   gstvideo_encoder_class->propose_allocation =
235       GST_DEBUG_FUNCPTR (theora_enc_propose_allocation);
236
237   /* general encoding stream options */
238   g_object_class_install_property (gobject_class, PROP_BITRATE,
239       g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
240           0, (1 << 24) - 1, THEORA_DEF_BITRATE,
241           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
242           GST_PARAM_MUTABLE_PLAYING));
243   g_object_class_install_property (gobject_class, PROP_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           GST_PARAM_MUTABLE_PLAYING));
248   g_object_class_install_property (gobject_class, PROP_KEYFRAME_AUTO,
249       g_param_spec_boolean ("keyframe-auto", "Keyframe Auto",
250           "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO,
251           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
252   g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ,
253       g_param_spec_int ("keyframe-freq", "Keyframe frequency",
254           "Keyframe frequency", 1, 32768, THEORA_DEF_KEYFRAME_FREQ,
255           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
256   g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ_FORCE,
257       g_param_spec_int ("keyframe-force", "Keyframe force",
258           "Force keyframe every N frames", 1, 32768,
259           THEORA_DEF_KEYFRAME_FREQ_FORCE,
260           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
261   g_object_class_install_property (gobject_class, PROP_SPEEDLEVEL,
262       g_param_spec_int ("speed-level", "Speed level",
263           "Controls the amount of motion vector searching done while encoding",
264           0, 3, THEORA_DEF_SPEEDLEVEL,
265           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
266   g_object_class_install_property (gobject_class, PROP_VP3_COMPATIBLE,
267       g_param_spec_boolean ("vp3-compatible", "VP3 compatible",
268           "Disables non-VP3 compatible features",
269           THEORA_DEF_VP3_COMPATIBLE,
270           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
271   g_object_class_install_property (gobject_class, PROP_DROP_FRAMES,
272       g_param_spec_boolean ("drop-frames", "Drop frames",
273           "Allow or disallow frame dropping",
274           THEORA_DEF_DROP_FRAMES,
275           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
276   g_object_class_install_property (gobject_class, PROP_CAP_OVERFLOW,
277       g_param_spec_boolean ("cap-overflow", "Cap overflow",
278           "Enable capping of bit reservoir overflows",
279           THEORA_DEF_CAP_OVERFLOW,
280           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
281   g_object_class_install_property (gobject_class, PROP_CAP_UNDERFLOW,
282       g_param_spec_boolean ("cap-underflow", "Cap underflow",
283           "Enable capping of bit reservoir underflows",
284           THEORA_DEF_CAP_UNDERFLOW,
285           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
286   g_object_class_install_property (gobject_class, PROP_RATE_BUFFER,
287       g_param_spec_int ("rate-buffer", "Rate Control Buffer",
288           "Sets the size of the rate control buffer, in units of frames.  "
289           "The default value of 0 instructs the encoder to automatically "
290           "select an appropriate value",
291           0, 1000, THEORA_DEF_RATE_BUFFER,
292           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
293   g_object_class_install_property (gobject_class, PROP_MULTIPASS_CACHE_FILE,
294       g_param_spec_string ("multipass-cache-file", "Multipass Cache File",
295           "Multipass cache file", THEORA_DEF_MULTIPASS_CACHE_FILE,
296           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
297   g_object_class_install_property (gobject_class, PROP_MULTIPASS_MODE,
298       g_param_spec_enum ("multipass-mode", "Multipass mode",
299           "Single pass or first/second pass", GST_TYPE_MULTIPASS_MODE,
300           THEORA_DEF_MULTIPASS_MODE,
301           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
302
303   GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
304 }
305
306 static void
307 gst_theora_enc_init (GstTheoraEnc * enc)
308 {
309   GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (enc));
310
311   enc->video_bitrate = THEORA_DEF_BITRATE;
312   enc->video_quality = THEORA_DEF_QUALITY;
313   enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
314   enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ;
315   enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE;
316
317   enc->speed_level = THEORA_DEF_SPEEDLEVEL;
318   enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE;
319   enc->drop_frames = THEORA_DEF_DROP_FRAMES;
320   enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW;
321   enc->cap_underflow = THEORA_DEF_CAP_UNDERFLOW;
322   enc->rate_buffer = THEORA_DEF_RATE_BUFFER;
323
324   enc->multipass_mode = THEORA_DEF_MULTIPASS_MODE;
325   enc->multipass_cache_file = THEORA_DEF_MULTIPASS_CACHE_FILE;
326 }
327
328 static void
329 theora_enc_clear_multipass_cache (GstTheoraEnc * enc)
330 {
331   if (enc->multipass_cache_fd) {
332     g_io_channel_shutdown (enc->multipass_cache_fd, TRUE, NULL);
333     g_io_channel_unref (enc->multipass_cache_fd);
334     enc->multipass_cache_fd = NULL;
335   }
336
337   if (enc->multipass_cache_adapter) {
338     gst_object_unref (enc->multipass_cache_adapter);
339     enc->multipass_cache_adapter = NULL;
340   }
341 }
342
343 static void
344 theora_enc_finalize (GObject * object)
345 {
346   GstTheoraEnc *enc = GST_THEORA_ENC (object);
347
348   GST_DEBUG_OBJECT (enc, "Finalizing");
349   if (enc->encoder)
350     th_encode_free (enc->encoder);
351   th_comment_clear (&enc->comment);
352   th_info_clear (&enc->info);
353   g_free (enc->multipass_cache_file);
354
355   theora_enc_clear_multipass_cache (enc);
356
357   if (enc->input_state)
358     gst_video_codec_state_unref (enc->input_state);
359
360   G_OBJECT_CLASS (parent_class)->finalize (object);
361 }
362
363 static gboolean
364 theora_enc_flush (GstVideoEncoder * encoder)
365 {
366   GstTheoraEnc *enc = GST_THEORA_ENC (encoder);
367   ogg_uint32_t keyframe_force;
368   int rate_flags;
369
370
371   if (enc->input_state == NULL) {
372     GST_INFO_OBJECT (enc, "Not configured yet, returning FALSE");
373
374     return FALSE;
375   }
376
377   GST_OBJECT_LOCK (enc);
378   enc->info.target_bitrate = enc->video_bitrate;
379   enc->info.quality = enc->video_quality;
380   enc->bitrate_changed = FALSE;
381   enc->quality_changed = FALSE;
382   GST_OBJECT_UNLOCK (enc);
383
384   if (enc->encoder)
385     th_encode_free (enc->encoder);
386
387   enc->encoder = th_encode_alloc (&enc->info);
388   /* We ensure this function cannot fail. */
389   g_assert (enc->encoder != NULL);
390   th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
391       sizeof (enc->speed_level));
392   th_encode_ctl (enc->encoder, TH_ENCCTL_SET_VP3_COMPATIBLE,
393       &enc->vp3_compatible, sizeof (enc->vp3_compatible));
394
395   rate_flags = 0;
396   if (enc->drop_frames)
397     rate_flags |= TH_RATECTL_DROP_FRAMES;
398   if (enc->drop_frames)
399     rate_flags |= TH_RATECTL_CAP_OVERFLOW;
400   if (enc->drop_frames)
401     rate_flags |= TH_RATECTL_CAP_UNDERFLOW;
402   th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_FLAGS,
403       &rate_flags, sizeof (rate_flags));
404
405   if (enc->rate_buffer) {
406     th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_BUFFER,
407         &enc->rate_buffer, sizeof (enc->rate_buffer));
408   } else {
409     /* FIXME */
410   }
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   /* Get placeholder data */
418   if (enc->multipass_cache_fd
419       && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
420     theora_enc_write_multipass_cache (enc, TRUE, FALSE);
421
422   return TRUE;
423 }
424
425 static gboolean
426 theora_enc_start (GstVideoEncoder * benc)
427 {
428   GstTheoraEnc *enc;
429
430   GST_DEBUG_OBJECT (benc, "start: init theora");
431   enc = GST_THEORA_ENC (benc);
432
433   if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) {
434     GError *err = NULL;
435
436     if (!enc->multipass_cache_file) {
437       GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
438       return FALSE;
439     }
440     enc->multipass_cache_fd =
441         g_io_channel_new_file (enc->multipass_cache_file,
442         (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"), &err);
443
444     if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS)
445       enc->multipass_cache_adapter = gst_adapter_new ();
446
447     if (!enc->multipass_cache_fd) {
448       GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL),
449           ("Failed to open multipass cache file: %s", err->message));
450       g_error_free (err);
451       return FALSE;
452     }
453
454     g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL);
455   }
456
457   enc->packetno = 0;
458   enc->initialised = FALSE;
459
460   return TRUE;
461 }
462
463 static gboolean
464 theora_enc_stop (GstVideoEncoder * benc)
465 {
466   GstTheoraEnc *enc;
467
468   GST_DEBUG_OBJECT (benc, "stop: clearing theora state");
469   enc = GST_THEORA_ENC (benc);
470
471   if (enc->encoder)
472     th_encode_free (enc->encoder);
473   enc->encoder = NULL;
474   th_comment_clear (&enc->comment);
475   th_info_clear (&enc->info);
476
477   if (enc->input_state)
478     gst_video_codec_state_unref (enc->input_state);
479   enc->input_state = NULL;
480
481   /* Everything else is handled in reset() */
482   theora_enc_clear_multipass_cache (enc);
483
484   return TRUE;
485 }
486
487 static char *
488 theora_enc_get_supported_formats (void)
489 {
490   th_enc_ctx *encoder;
491   th_info info;
492   struct
493   {
494     th_pixel_fmt pixelformat;
495     const char *fourcc;
496   } formats[] = {
497     {
498     TH_PF_420, "I420"}, {
499     TH_PF_422, "Y42B"}, {
500     TH_PF_444, "Y444"}
501   };
502   GString *string = NULL;
503   guint i;
504
505   th_info_init (&info);
506   info.frame_width = 16;
507   info.frame_height = 16;
508   info.fps_numerator = 25;
509   info.fps_denominator = 1;
510   for (i = 0; i < G_N_ELEMENTS (formats); i++) {
511     info.pixel_fmt = formats[i].pixelformat;
512
513     encoder = th_encode_alloc (&info);
514     if (encoder == NULL)
515       continue;
516
517     GST_LOG ("format %s is supported", formats[i].fourcc);
518     th_encode_free (encoder);
519
520     if (string == NULL) {
521       string = g_string_new (formats[i].fourcc);
522     } else {
523       g_string_append (string, ", ");
524       g_string_append (string, formats[i].fourcc);
525     }
526   }
527   th_info_clear (&info);
528
529   return string == NULL ? NULL : g_string_free (string, FALSE);
530 }
531
532 static GstCaps *
533 theora_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
534 {
535   GstCaps *caps, *ret;
536   char *supported_formats, *caps_string;
537
538   supported_formats = theora_enc_get_supported_formats ();
539   if (!supported_formats) {
540     GST_WARNING ("no supported formats found. Encoder disabled?");
541     return gst_caps_new_empty ();
542   }
543
544   caps_string = g_strdup_printf ("video/x-raw, "
545       "format = (string) { %s }, "
546       "framerate = (fraction) [1/MAX, MAX], "
547       "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]",
548       supported_formats);
549   caps = gst_caps_from_string (caps_string);
550   g_free (caps_string);
551   g_free (supported_formats);
552   GST_DEBUG ("Supported caps: %" GST_PTR_FORMAT, caps);
553
554   ret = gst_video_encoder_proxy_getcaps (encoder, caps, filter);
555   gst_caps_unref (caps);
556
557   return ret;
558 }
559
560 static gboolean
561 theora_enc_set_format (GstVideoEncoder * benc, GstVideoCodecState * state)
562 {
563   GstTheoraEnc *enc = GST_THEORA_ENC (benc);
564   GstVideoInfo *info = &state->info;
565
566   enc->width = GST_VIDEO_INFO_WIDTH (info);
567   enc->height = GST_VIDEO_INFO_HEIGHT (info);
568
569   th_info_clear (&enc->info);
570   th_info_init (&enc->info);
571   /* Theora has a divisible-by-sixteen restriction for the encoded video size but
572    * we can define a picture area using pic_width/pic_height */
573   enc->info.frame_width = GST_ROUND_UP_16 (enc->width);
574   enc->info.frame_height = GST_ROUND_UP_16 (enc->height);
575   enc->info.pic_width = enc->width;
576   enc->info.pic_height = enc->height;
577   switch (GST_VIDEO_INFO_FORMAT (info)) {
578     case GST_VIDEO_FORMAT_I420:
579       enc->info.pixel_fmt = TH_PF_420;
580       break;
581     case GST_VIDEO_FORMAT_Y42B:
582       enc->info.pixel_fmt = TH_PF_422;
583       break;
584     case GST_VIDEO_FORMAT_Y444:
585       enc->info.pixel_fmt = TH_PF_444;
586       break;
587     default:
588       g_assert_not_reached ();
589   }
590
591   enc->info.fps_numerator = enc->fps_n = GST_VIDEO_INFO_FPS_N (info);
592   enc->info.fps_denominator = enc->fps_d = GST_VIDEO_INFO_FPS_D (info);
593   enc->info.aspect_numerator = GST_VIDEO_INFO_PAR_N (info);
594   enc->info.aspect_denominator = GST_VIDEO_INFO_PAR_D (info);
595
596   enc->info.colorspace = TH_CS_UNSPECIFIED;
597
598   /* Save input state */
599   if (enc->input_state)
600     gst_video_codec_state_unref (enc->input_state);
601   enc->input_state = gst_video_codec_state_ref (state);
602
603   /* as done in theora */
604   enc->info.keyframe_granule_shift = _ilog (enc->keyframe_force - 1);
605   GST_DEBUG_OBJECT (enc,
606       "keyframe_frequency_force is %d, granule shift is %d",
607       enc->keyframe_force, enc->info.keyframe_granule_shift);
608
609   theora_enc_flush (benc);
610   enc->initialised = TRUE;
611
612   return TRUE;
613 }
614
615 static GstFlowReturn
616 theora_enc_pre_push (GstVideoEncoder * benc, GstVideoCodecFrame * frame)
617 {
618   GstTheoraEnc *enc = GST_THEORA_ENC (benc);
619   guint64 pfn;
620
621   /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
622    * time representation */
623   /* granulepos from sync frame */
624   pfn = frame->presentation_frame_number - frame->distance_from_sync;
625   /* correct to correspond to linear running time */
626   pfn -= enc->pfn_offset;
627   pfn += enc->granulepos_offset + 1;
628   /* granulepos */
629   GST_BUFFER_OFFSET_END (frame->output_buffer) =
630       (pfn << enc->info.keyframe_granule_shift) + frame->distance_from_sync;
631   GST_BUFFER_OFFSET (frame->output_buffer) = granulepos_to_timestamp (enc,
632       GST_BUFFER_OFFSET_END (frame->output_buffer));
633
634   return GST_FLOW_OK;
635 }
636
637 static GstFlowReturn
638 theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet)
639 {
640   GstVideoEncoder *benc;
641   GstFlowReturn ret;
642   GstVideoCodecFrame *frame;
643
644   benc = GST_VIDEO_ENCODER (enc);
645
646   frame = gst_video_encoder_get_oldest_frame (benc);
647   if (gst_video_encoder_allocate_output_frame (benc, frame,
648           packet->bytes) != GST_FLOW_OK) {
649     GST_WARNING_OBJECT (enc, "Could not allocate buffer");
650     gst_video_codec_frame_unref (frame);
651     ret = GST_FLOW_ERROR;
652     goto done;
653   }
654
655   if (packet->bytes > 0)
656     gst_buffer_fill (frame->output_buffer, 0, packet->packet, packet->bytes);
657
658   /* the second most significant bit of the first data byte is cleared
659    * for keyframes */
660   if (packet->bytes > 0 && (packet->packet[0] & 0x40) == 0) {
661     GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
662   } else {
663     GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
664   }
665   enc->packetno++;
666
667   ret = gst_video_encoder_finish_frame (benc, frame);
668
669 done:
670   return ret;
671 }
672
673 static GstCaps *
674 theora_set_header_on_caps (GstCaps * caps, GList * buffers)
675 {
676   GstStructure *structure;
677   GValue array = { 0 };
678   GValue value = { 0 };
679   GstBuffer *buffer;
680   GList *walk;
681
682   caps = gst_caps_make_writable (caps);
683   structure = gst_caps_get_structure (caps, 0);
684
685   /* put copies of the buffers in a fixed list */
686   g_value_init (&array, GST_TYPE_ARRAY);
687
688   for (walk = buffers; walk; walk = walk->next) {
689     buffer = walk->data;
690     g_value_init (&value, GST_TYPE_BUFFER);
691     gst_value_set_buffer (&value, buffer);
692     gst_value_array_append_value (&array, &value);
693     g_value_unset (&value);
694   }
695
696   gst_structure_take_value (structure, "streamheader", &array);
697
698   return caps;
699 }
700
701 static void
702 theora_enc_init_buffer (th_ycbcr_buffer buf, GstVideoFrame * frame)
703 {
704   GstVideoInfo vinfo;
705   guint i;
706
707   /* According to Theora developer Timothy Terriberry, the Theora 
708    * encoder will not use memory outside of pic_width/height, even when
709    * the frame size is bigger. The values outside this region will be encoded
710    * to default values.
711    * Due to this, setting the frame's width/height as the buffer width/height
712    * is perfectly ok, even though it does not strictly look ok.
713    */
714
715   gst_video_info_init (&vinfo);
716   gst_video_info_set_format (&vinfo, GST_VIDEO_FRAME_FORMAT (frame),
717       GST_ROUND_UP_16 (GST_VIDEO_FRAME_WIDTH (frame)),
718       GST_ROUND_UP_16 (GST_VIDEO_FRAME_HEIGHT (frame)));
719
720   for (i = 0; i < 3; i++) {
721     buf[i].width = GST_VIDEO_INFO_COMP_WIDTH (&vinfo, i);
722     buf[i].height = GST_VIDEO_INFO_COMP_HEIGHT (&vinfo, i);
723     buf[i].data = GST_VIDEO_FRAME_COMP_DATA (frame, i);
724     buf[i].stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
725   }
726 }
727
728 static gboolean
729 theora_enc_read_multipass_cache (GstTheoraEnc * enc)
730 {
731   GstBuffer *cache_buf;
732   const guint8 *cache_data;
733   gsize bytes_read = 0;
734   gssize bytes_consumed = 0;
735   GIOStatus stat = G_IO_STATUS_NORMAL;
736   gboolean done = FALSE;
737
738   while (!done) {
739     if (gst_adapter_available (enc->multipass_cache_adapter) == 0) {
740       GstMapInfo minfo;
741
742       cache_buf = gst_buffer_new_allocate (NULL, 512, NULL);
743
744       gst_buffer_map (cache_buf, &minfo, GST_MAP_WRITE);
745
746       stat = g_io_channel_read_chars (enc->multipass_cache_fd,
747           (gchar *) minfo.data, minfo.size, &bytes_read, NULL);
748
749       if (bytes_read <= 0) {
750         gst_buffer_unmap (cache_buf, &minfo);
751         gst_buffer_unref (cache_buf);
752         break;
753       } else {
754         gst_buffer_unmap (cache_buf, &minfo);
755         gst_buffer_resize (cache_buf, 0, bytes_read);
756
757         gst_adapter_push (enc->multipass_cache_adapter, cache_buf);
758       }
759     }
760     if (gst_adapter_available (enc->multipass_cache_adapter) == 0)
761       break;
762
763     bytes_read =
764         MIN (gst_adapter_available (enc->multipass_cache_adapter), 512);
765
766     cache_data = gst_adapter_map (enc->multipass_cache_adapter, bytes_read);
767
768     bytes_consumed =
769         th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data,
770         bytes_read);
771     gst_adapter_unmap (enc->multipass_cache_adapter);
772
773     done = bytes_consumed <= 0;
774     if (bytes_consumed > 0)
775       gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed);
776   }
777
778   if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_EOF && bytes_read == 0)
779       || bytes_consumed < 0) {
780     GST_ELEMENT_ERROR (enc, RESOURCE, READ, (NULL),
781         ("Failed to read multipass cache file"));
782     return FALSE;
783   }
784   return TRUE;
785 }
786
787 static gboolean
788 theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin,
789     gboolean eos)
790 {
791   GError *err = NULL;
792   GIOStatus stat = G_IO_STATUS_NORMAL;
793   gint bytes_read = 0;
794   gsize bytes_written = 0;
795   gchar *buf;
796
797   if (begin) {
798     stat = g_io_channel_seek_position (enc->multipass_cache_fd, 0, G_SEEK_SET,
799         &err);
800
801     if (stat == G_IO_STATUS_ERROR) {
802       if (eos)
803         GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL),
804             ("Failed to seek to beginning of multipass cache file: %s",
805                 err->message));
806       else
807         GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
808             ("Failed to seek to beginning of multipass cache file: %s",
809                 err->message));
810       g_error_free (err);
811       return FALSE;
812     }
813   }
814
815
816   do {
817     bytes_read =
818         th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_OUT, &buf, sizeof (buf));
819     if (bytes_read > 0)
820       g_io_channel_write_chars (enc->multipass_cache_fd, buf, bytes_read,
821           &bytes_written, &err);
822   } while (bytes_read > 0 && bytes_written > 0 && !err);
823
824   if (bytes_read < 0 || err) {
825     if (bytes_read < 0) {
826       GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
827           ("Failed to read multipass cache data: %d", bytes_read));
828     } else {
829       GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
830           ("Failed to write multipass cache file: %s", err->message));
831     }
832     if (err)
833       g_error_free (err);
834
835     return FALSE;
836   }
837
838   return TRUE;
839 }
840
841 static void
842 theora_enc_reset_ts (GstTheoraEnc * enc, GstClockTime running_time, gint pfn)
843 {
844   enc->granulepos_offset =
845       gst_util_uint64_scale (running_time, enc->fps_n, GST_SECOND * enc->fps_d);
846   enc->timestamp_offset = running_time;
847   enc->pfn_offset = pfn;
848 }
849
850 static GstBuffer *
851 theora_enc_buffer_from_header_packet (GstTheoraEnc * enc, ogg_packet * packet)
852 {
853   GstBuffer *outbuf;
854
855   outbuf =
856       gst_video_encoder_allocate_output_buffer (GST_VIDEO_ENCODER (enc),
857       packet->bytes);
858   gst_buffer_fill (outbuf, 0, packet->packet, packet->bytes);
859   GST_BUFFER_OFFSET (outbuf) = 0;
860   GST_BUFFER_OFFSET_END (outbuf) = 0;
861   GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
862   GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
863   GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_HEADER);
864
865   GST_DEBUG ("created header packet buffer, %u bytes",
866       (guint) gst_buffer_get_size (outbuf));
867   return outbuf;
868 }
869
870 static GstFlowReturn
871 theora_enc_handle_frame (GstVideoEncoder * benc, GstVideoCodecFrame * frame)
872 {
873   GstTheoraEnc *enc;
874   ogg_packet op;
875   GstClockTime timestamp, running_time;
876   GstFlowReturn ret;
877   gboolean force_keyframe;
878
879   enc = GST_THEORA_ENC (benc);
880
881   /* we keep track of two timelines.
882    * - The timestamps from the incomming buffers, which we copy to the outgoing
883    *   encoded buffers as-is. We need to do this as we simply forward the
884    *   newsegment events.
885    * - The running_time of the buffers, which we use to construct the granulepos
886    *   in the packets.
887    */
888   timestamp = frame->pts;
889
890   /* incoming buffers are clipped, so this should be positive */
891   running_time =
892       gst_segment_to_running_time (&GST_VIDEO_ENCODER_INPUT_SEGMENT (enc),
893       GST_FORMAT_TIME, timestamp);
894
895   GST_OBJECT_LOCK (enc);
896   if (enc->bitrate_changed) {
897     long int bitrate = enc->video_bitrate;
898
899     th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
900         sizeof (long int));
901     enc->bitrate_changed = FALSE;
902   }
903
904   if (enc->quality_changed) {
905     long int quality = enc->video_quality;
906
907     th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
908         sizeof (long int));
909     enc->quality_changed = FALSE;
910   }
911
912   /* see if we need to schedule a keyframe */
913   force_keyframe = GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame);
914   GST_OBJECT_UNLOCK (enc);
915
916   if (enc->packetno == 0) {
917     /* no packets written yet, setup headers */
918     GstCaps *caps;
919     GstBuffer *buf;
920     GList *buffers = NULL;
921     int result;
922     GstVideoCodecState *state;
923
924     enc->granulepos_offset = 0;
925     enc->timestamp_offset = 0;
926
927     GST_DEBUG_OBJECT (enc, "output headers");
928     /* Theora streams begin with three headers; the initial header (with
929        most of the codec setup parameters) which is mandated by the Ogg
930        bitstream spec.  The second header holds any comment fields.  The
931        third header holds the bitstream codebook.  We merely need to
932        make the headers, then pass them to libtheora one at a time;
933        libtheora handles the additional Ogg bitstream constraints */
934
935     /* create the remaining theora headers */
936     th_comment_clear (&enc->comment);
937     th_comment_init (&enc->comment);
938
939     while ((result =
940             th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
941       buf = theora_enc_buffer_from_header_packet (enc, &op);
942       buffers = g_list_prepend (buffers, buf);
943     }
944     if (result < 0) {
945       g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
946       g_list_free (buffers);
947       goto encoder_disabled;
948     }
949
950     buffers = g_list_reverse (buffers);
951
952     /* mark buffers and put on caps */
953     caps = gst_caps_new_empty_simple ("video/x-theora");
954     caps = theora_set_header_on_caps (caps, buffers);
955     state = gst_video_encoder_set_output_state (benc, caps, enc->input_state);
956
957     GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, state->caps);
958
959     gst_video_codec_state_unref (state);
960
961     gst_video_encoder_negotiate (GST_VIDEO_ENCODER (enc));
962
963     gst_video_encoder_set_headers (benc, buffers);
964
965     theora_enc_reset_ts (enc, running_time, frame->presentation_frame_number);
966   }
967
968   {
969     th_ycbcr_buffer ycbcr;
970     gint res, keyframe_interval;
971     GstVideoFrame vframe;
972
973     if (force_keyframe) {
974       /* if we want a keyframe, temporarily reset the max keyframe interval
975        * to 1, which will cause libtheora to emit one. There is no API to
976        * request a keyframe at the moment. */
977       keyframe_interval = 1;
978       th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
979           &keyframe_interval, sizeof (keyframe_interval));
980     }
981
982     if (enc->multipass_cache_fd
983         && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
984       if (!theora_enc_read_multipass_cache (enc)) {
985         ret = GST_FLOW_ERROR;
986         goto multipass_read_failed;
987       }
988     }
989
990     gst_video_frame_map (&vframe, &enc->input_state->info, frame->input_buffer,
991         GST_MAP_READ);
992     theora_enc_init_buffer (ycbcr, &vframe);
993
994     res = th_encode_ycbcr_in (enc->encoder, ycbcr);
995     gst_video_frame_unmap (&vframe);
996
997     /* none of the failure cases can happen here */
998     g_assert (res == 0);
999
1000     if (enc->multipass_cache_fd
1001         && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
1002       if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
1003         ret = GST_FLOW_ERROR;
1004         goto multipass_write_failed;
1005       }
1006     }
1007
1008     ret = GST_FLOW_OK;
1009     while (th_encode_packetout (enc->encoder, 0, &op)) {
1010       /* Reset the max keyframe interval to its original state, and reset
1011        * the flag so we don't create more keyframes if we loop */
1012       if (force_keyframe) {
1013         keyframe_interval =
1014             enc->keyframe_auto ? enc->keyframe_force : enc->keyframe_freq;
1015         th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
1016             &keyframe_interval, sizeof (keyframe_interval));
1017         force_keyframe = FALSE;
1018       }
1019
1020       ret = theora_push_packet (enc, &op);
1021       if (ret != GST_FLOW_OK)
1022         goto beach;
1023     }
1024   }
1025
1026 beach:
1027   gst_video_codec_frame_unref (frame);
1028   return ret;
1029
1030   /* ERRORS */
1031 multipass_read_failed:
1032   {
1033     gst_video_codec_frame_unref (frame);
1034     return ret;
1035   }
1036 multipass_write_failed:
1037   {
1038     gst_video_codec_frame_unref (frame);
1039     return ret;
1040   }
1041 encoder_disabled:
1042   {
1043     gst_video_codec_frame_unref (frame);
1044     GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1045         ("libtheora has been compiled with the encoder disabled"));
1046     return GST_FLOW_ERROR;
1047   }
1048 }
1049
1050 static gboolean
1051 theora_enc_finish (GstVideoEncoder * benc)
1052 {
1053   GstTheoraEnc *enc;
1054   ogg_packet op;
1055
1056   enc = GST_THEORA_ENC (benc);
1057
1058   if (enc->initialised) {
1059     /* push last packet with eos flag, should not be called */
1060     while (th_encode_packetout (enc->encoder, 1, &op)) {
1061       theora_push_packet (enc, &op);
1062     }
1063   }
1064   if (enc->initialised && enc->multipass_cache_fd
1065       && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
1066     theora_enc_write_multipass_cache (enc, TRUE, TRUE);
1067
1068   theora_enc_clear_multipass_cache (enc);
1069
1070   return TRUE;
1071 }
1072
1073 static gboolean
1074 theora_enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
1075 {
1076   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
1077
1078   return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
1079       query);
1080 }
1081
1082 static void
1083 theora_enc_set_property (GObject * object, guint prop_id,
1084     const GValue * value, GParamSpec * pspec)
1085 {
1086   GstTheoraEnc *enc = GST_THEORA_ENC (object);
1087
1088   switch (prop_id) {
1089     case PROP_BITRATE:
1090       GST_OBJECT_LOCK (enc);
1091       enc->video_bitrate = g_value_get_int (value) * 1000;
1092       enc->video_quality = 0;
1093       enc->bitrate_changed = TRUE;
1094       GST_OBJECT_UNLOCK (enc);
1095       break;
1096     case PROP_QUALITY:
1097       GST_OBJECT_LOCK (enc);
1098       if (GST_STATE (enc) >= GST_STATE_PAUSED && enc->video_quality == 0) {
1099         GST_WARNING_OBJECT (object, "Can't change from bitrate to quality mode"
1100             " while playing");
1101       } else {
1102         enc->video_quality = g_value_get_int (value);
1103         enc->video_bitrate = 0;
1104         enc->quality_changed = TRUE;
1105       }
1106       GST_OBJECT_UNLOCK (enc);
1107       break;
1108     case PROP_KEYFRAME_AUTO:
1109       enc->keyframe_auto = g_value_get_boolean (value);
1110       break;
1111     case PROP_KEYFRAME_FREQ:
1112       enc->keyframe_freq = g_value_get_int (value);
1113       break;
1114     case PROP_KEYFRAME_FREQ_FORCE:
1115       enc->keyframe_force = g_value_get_int (value);
1116       break;
1117     case PROP_SPEEDLEVEL:
1118       enc->speed_level = g_value_get_int (value);
1119       break;
1120     case PROP_VP3_COMPATIBLE:
1121       enc->vp3_compatible = g_value_get_boolean (value);
1122       break;
1123     case PROP_DROP_FRAMES:
1124       enc->drop_frames = g_value_get_boolean (value);
1125       break;
1126     case PROP_CAP_OVERFLOW:
1127       enc->cap_overflow = g_value_get_boolean (value);
1128       break;
1129     case PROP_CAP_UNDERFLOW:
1130       enc->cap_underflow = g_value_get_boolean (value);
1131       break;
1132     case PROP_RATE_BUFFER:
1133       enc->rate_buffer = g_value_get_int (value);
1134       break;
1135     case PROP_MULTIPASS_CACHE_FILE:
1136       enc->multipass_cache_file = g_value_dup_string (value);
1137       break;
1138     case PROP_MULTIPASS_MODE:
1139       enc->multipass_mode = g_value_get_enum (value);
1140       break;
1141     default:
1142       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1143       break;
1144   }
1145 }
1146
1147 static void
1148 theora_enc_get_property (GObject * object, guint prop_id,
1149     GValue * value, GParamSpec * pspec)
1150 {
1151   GstTheoraEnc *enc = GST_THEORA_ENC (object);
1152
1153   switch (prop_id) {
1154     case PROP_BITRATE:
1155       GST_OBJECT_LOCK (enc);
1156       g_value_set_int (value, enc->video_bitrate / 1000);
1157       GST_OBJECT_UNLOCK (enc);
1158       break;
1159     case PROP_QUALITY:
1160       GST_OBJECT_LOCK (enc);
1161       g_value_set_int (value, enc->video_quality);
1162       GST_OBJECT_UNLOCK (enc);
1163       break;
1164     case PROP_KEYFRAME_AUTO:
1165       g_value_set_boolean (value, enc->keyframe_auto);
1166       break;
1167     case PROP_KEYFRAME_FREQ:
1168       g_value_set_int (value, enc->keyframe_freq);
1169       break;
1170     case PROP_KEYFRAME_FREQ_FORCE:
1171       g_value_set_int (value, enc->keyframe_force);
1172       break;
1173     case PROP_SPEEDLEVEL:
1174       g_value_set_int (value, enc->speed_level);
1175       break;
1176     case PROP_VP3_COMPATIBLE:
1177       g_value_set_boolean (value, enc->vp3_compatible);
1178       break;
1179     case PROP_DROP_FRAMES:
1180       g_value_set_boolean (value, enc->drop_frames);
1181       break;
1182     case PROP_CAP_OVERFLOW:
1183       g_value_set_boolean (value, enc->cap_overflow);
1184       break;
1185     case PROP_CAP_UNDERFLOW:
1186       g_value_set_boolean (value, enc->cap_underflow);
1187       break;
1188     case PROP_RATE_BUFFER:
1189       g_value_set_int (value, enc->rate_buffer);
1190       break;
1191     case PROP_MULTIPASS_CACHE_FILE:
1192       g_value_set_string (value, enc->multipass_cache_file);
1193       break;
1194     case PROP_MULTIPASS_MODE:
1195       g_value_set_enum (value, enc->multipass_mode);
1196       break;
1197     default:
1198       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1199       break;
1200   }
1201 }