2 * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
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.
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.
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.
21 * SECTION:element-theoraenc
22 * @see_also: theoradec, oggmux
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.
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
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.
43 * <title>Example pipeline</title>
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
51 * Last reviewed on 2006-03-01 (0.10.4)
58 #include "gsttheoraenc.h"
61 #include <stdlib.h> /* free */
63 #include <gst/tag/tag.h>
64 #include <gst/video/video.h>
66 #define GST_CAT_DEFAULT theoraenc_debug
67 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
69 #define GST_TYPE_BORDER_MODE (gst_border_mode_get_type())
71 gst_border_mode_get_type (void)
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"},
81 if (!border_mode_type) {
83 g_enum_register_static ("GstTheoraEncBorderMode", border_mode);
85 return border_mode_type;
88 #define GST_TYPE_MULTIPASS_MODE (gst_multipass_mode_get_type())
90 gst_multipass_mode_get_type (void)
92 static GType multipass_mode_type = 0;
93 static const GEnumValue multipass_mode[] = {
94 {MULTIPASS_MODE_SINGLE_PASS, "Single pass", "single-pass"},
95 {MULTIPASS_MODE_FIRST_PASS, "First pass", "first-pass"},
96 {MULTIPASS_MODE_SECOND_PASS, "Second pass", "second-pass"},
100 if (!multipass_mode_type) {
101 multipass_mode_type =
102 g_enum_register_static ("GstTheoraEncMultipassMode", multipass_mode);
104 return multipass_mode_type;
107 /* taken from theora/lib/toplevel.c */
109 _ilog (unsigned int v)
120 #define THEORA_DEF_BITRATE 0
121 #define THEORA_DEF_QUALITY 48
122 #define THEORA_DEF_KEYFRAME_AUTO TRUE
123 #define THEORA_DEF_KEYFRAME_FREQ 64
124 #define THEORA_DEF_KEYFRAME_FREQ_FORCE 64
125 #define THEORA_DEF_SPEEDLEVEL 1
126 #define THEORA_DEF_VP3_COMPATIBLE FALSE
127 #define THEORA_DEF_DROP_FRAMES TRUE
128 #define THEORA_DEF_CAP_OVERFLOW TRUE
129 #define THEORA_DEF_CAP_UNDERFLOW FALSE
130 #define THEORA_DEF_RATE_BUFFER 0
131 #define THEORA_DEF_MULTIPASS_CACHE_FILE NULL
132 #define THEORA_DEF_MULTIPASS_MODE MULTIPASS_MODE_SINGLE_PASS
143 PROP_KEYFRAME_FREQ_FORCE,
144 PROP_KEYFRAME_THRESHOLD,
145 PROP_KEYFRAME_MINDISTANCE,
146 PROP_NOISE_SENSITIVITY,
154 PROP_MULTIPASS_CACHE_FILE,
159 /* this function does a straight granulepos -> timestamp conversion */
161 granulepos_to_timestamp (GstTheoraEnc * theoraenc, ogg_int64_t granulepos)
163 guint64 iframe, pframe;
164 int shift = theoraenc->info.keyframe_granule_shift;
167 return GST_CLOCK_TIME_NONE;
169 iframe = granulepos >> shift;
170 pframe = granulepos - (iframe << shift);
172 /* num and den are 32 bit, so we can safely multiply with GST_SECOND */
173 return gst_util_uint64_scale ((guint64) (iframe + pframe),
174 GST_SECOND * theoraenc->info.fps_denominator,
175 theoraenc->info.fps_numerator);
178 static GstStaticPadTemplate theora_enc_sink_factory =
179 GST_STATIC_PAD_TEMPLATE ("sink",
182 GST_STATIC_CAPS ("video/x-raw-yuv, "
183 "format = (fourcc) { I420, Y42B, Y444 }, "
184 "framerate = (fraction) [1/MAX, MAX], "
185 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
188 static GstStaticPadTemplate theora_enc_src_factory =
189 GST_STATIC_PAD_TEMPLATE ("src",
192 GST_STATIC_CAPS ("video/x-theora")
196 _do_init (GType object_type)
198 const GInterfaceInfo preset_interface_info = {
199 NULL, /* interface_init */
200 NULL, /* interface_finalize */
201 NULL /* interface_data */
204 g_type_add_interface_static (object_type, GST_TYPE_PRESET,
205 &preset_interface_info);
208 GST_BOILERPLATE_FULL (GstTheoraEnc, gst_theora_enc, GstElement,
209 GST_TYPE_ELEMENT, _do_init);
211 static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event);
212 static gboolean theora_enc_src_event (GstPad * pad, GstEvent * event);
213 static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
214 static GstStateChangeReturn theora_enc_change_state (GstElement * element,
215 GstStateChange transition);
216 static GstCaps *theora_enc_sink_getcaps (GstPad * pad);
217 static gboolean theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
218 static void theora_enc_get_property (GObject * object, guint prop_id,
219 GValue * value, GParamSpec * pspec);
220 static void theora_enc_set_property (GObject * object, guint prop_id,
221 const GValue * value, GParamSpec * pspec);
222 static void theora_enc_finalize (GObject * object);
225 gst_theora_enc_base_init (gpointer g_class)
227 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
229 gst_element_class_add_pad_template (element_class,
230 gst_static_pad_template_get (&theora_enc_src_factory));
231 gst_element_class_add_pad_template (element_class,
232 gst_static_pad_template_get (&theora_enc_sink_factory));
233 gst_element_class_set_details_simple (element_class,
234 "Theora video encoder", "Codec/Encoder/Video",
235 "encode raw YUV video to a theora stream",
236 "Wim Taymans <wim@fluendo.com>");
240 gst_theora_enc_class_init (GstTheoraEncClass * klass)
242 GObjectClass *gobject_class = (GObjectClass *) klass;
243 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
245 gobject_class->set_property = theora_enc_set_property;
246 gobject_class->get_property = theora_enc_get_property;
247 gobject_class->finalize = theora_enc_finalize;
249 g_object_class_install_property (gobject_class, PROP_CENTER,
250 g_param_spec_boolean ("center", "Center",
251 "ignored and kept for API compat only", TRUE,
252 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
253 g_object_class_install_property (gobject_class, PROP_BORDER,
254 g_param_spec_enum ("border", "Border",
255 "ignored and kept for API compat only",
256 GST_TYPE_BORDER_MODE, BORDER_BLACK,
257 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
258 /* general encoding stream options */
259 g_object_class_install_property (gobject_class, PROP_BITRATE,
260 g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
261 0, (1 << 24) - 1, THEORA_DEF_BITRATE,
262 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
263 GST_PARAM_MUTABLE_PLAYING));
264 g_object_class_install_property (gobject_class, PROP_QUALITY,
265 g_param_spec_int ("quality", "Quality", "Video quality", 0, 63,
267 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
268 GST_PARAM_MUTABLE_PLAYING));
269 g_object_class_install_property (gobject_class, PROP_QUICK,
270 g_param_spec_boolean ("quick", "Quick",
271 "ignored and kept for API compat only", TRUE,
272 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
273 g_object_class_install_property (gobject_class, PROP_KEYFRAME_AUTO,
274 g_param_spec_boolean ("keyframe-auto", "Keyframe Auto",
275 "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO,
276 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
277 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ,
278 g_param_spec_int ("keyframe-freq", "Keyframe frequency",
279 "Keyframe frequency", 1, 32768, THEORA_DEF_KEYFRAME_FREQ,
280 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
281 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ_FORCE,
282 g_param_spec_int ("keyframe-force", "Keyframe force",
283 "Force keyframe every N frames", 1, 32768,
284 THEORA_DEF_KEYFRAME_FREQ_FORCE,
285 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
286 g_object_class_install_property (gobject_class, PROP_KEYFRAME_THRESHOLD,
287 g_param_spec_int ("keyframe-threshold", "Keyframe threshold",
288 "ignored and kept for API compat only", 0, 32768, 80,
289 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
290 g_object_class_install_property (gobject_class, PROP_KEYFRAME_MINDISTANCE,
291 g_param_spec_int ("keyframe-mindistance", "Keyframe mindistance",
292 "ignored and kept for API compat only", 1, 32768, 8,
293 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
294 g_object_class_install_property (gobject_class, PROP_NOISE_SENSITIVITY,
295 g_param_spec_int ("noise-sensitivity", "Noise sensitivity",
296 "ignored and kept for API compat only", 0, 32768, 1,
297 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
298 g_object_class_install_property (gobject_class, PROP_SHARPNESS,
299 g_param_spec_int ("sharpness", "Sharpness",
300 "ignored and kept for API compat only", 0, 2, 0,
301 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
302 g_object_class_install_property (gobject_class, PROP_SPEEDLEVEL,
303 g_param_spec_int ("speed-level", "Speed level",
304 "Controls the amount of motion vector searching done while "
305 "encoding. This property requires libtheora version >= 1.0",
306 0, 3, THEORA_DEF_SPEEDLEVEL,
307 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
308 g_object_class_install_property (gobject_class, PROP_VP3_COMPATIBLE,
309 g_param_spec_boolean ("vp3-compatible", "VP3 Compatible",
310 "Disables non-VP3 compatible features."
311 " This property requires libtheora version >= 1.1",
312 THEORA_DEF_VP3_COMPATIBLE,
313 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
314 g_object_class_install_property (gobject_class, PROP_DROP_FRAMES,
315 g_param_spec_boolean ("drop-frames", "VP3 Compatible",
316 "Allow or disallow frame dropping."
317 " This property requires libtheora version >= 1.1",
318 THEORA_DEF_DROP_FRAMES,
319 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
320 g_object_class_install_property (gobject_class, PROP_CAP_OVERFLOW,
321 g_param_spec_boolean ("cap-overflow", "VP3 Compatible",
322 "Enable capping of bit reservoir overflows."
323 " This property requires libtheora version >= 1.1",
324 THEORA_DEF_CAP_OVERFLOW,
325 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
326 g_object_class_install_property (gobject_class, PROP_CAP_UNDERFLOW,
327 g_param_spec_boolean ("cap-underflow", "VP3 Compatible",
328 "Enable capping of bit reservoir underflows."
329 " This property requires libtheora version >= 1.1",
330 THEORA_DEF_CAP_UNDERFLOW,
331 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
332 g_object_class_install_property (gobject_class, PROP_RATE_BUFFER,
333 g_param_spec_int ("rate-buffer", "Rate Control Buffer",
334 "Sets the size of the rate control buffer, in units of frames. "
335 "The default value of 0 instructs the encoder to automatically "
336 "select an appropriate value."
337 " This property requires libtheora version >= 1.1",
338 0, 1000, THEORA_DEF_RATE_BUFFER,
339 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
340 g_object_class_install_property (gobject_class, PROP_MULTIPASS_CACHE_FILE,
341 g_param_spec_string ("multipass-cache-file", "Multipass Cache File",
342 "Multipass cache file", THEORA_DEF_MULTIPASS_CACHE_FILE,
343 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
344 g_object_class_install_property (gobject_class, PROP_MULTIPASS_MODE,
345 g_param_spec_enum ("multipass-mode", "Multipass mode",
346 "Single pass or first/second pass", GST_TYPE_MULTIPASS_MODE,
347 THEORA_DEF_MULTIPASS_MODE,
348 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
350 gstelement_class->change_state = theora_enc_change_state;
351 GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
355 gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class)
358 gst_pad_new_from_static_template (&theora_enc_sink_factory, "sink");
359 gst_pad_set_chain_function (enc->sinkpad, theora_enc_chain);
360 gst_pad_set_event_function (enc->sinkpad, theora_enc_sink_event);
361 gst_pad_set_getcaps_function (enc->sinkpad, theora_enc_sink_getcaps);
362 gst_pad_set_setcaps_function (enc->sinkpad, theora_enc_sink_setcaps);
363 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
366 gst_pad_new_from_static_template (&theora_enc_src_factory, "src");
367 gst_pad_set_event_function (enc->srcpad, theora_enc_src_event);
368 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
370 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
372 enc->video_bitrate = THEORA_DEF_BITRATE;
373 enc->video_quality = THEORA_DEF_QUALITY;
374 enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
375 enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ;
376 enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE;
378 enc->expected_ts = GST_CLOCK_TIME_NONE;
380 enc->speed_level = THEORA_DEF_SPEEDLEVEL;
381 enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE;
382 enc->drop_frames = THEORA_DEF_DROP_FRAMES;
383 enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW;
384 enc->cap_underflow = THEORA_DEF_CAP_UNDERFLOW;
385 enc->rate_buffer = THEORA_DEF_RATE_BUFFER;
387 enc->multipass_mode = THEORA_DEF_MULTIPASS_MODE;
388 enc->multipass_cache_file = THEORA_DEF_MULTIPASS_CACHE_FILE;
392 theora_enc_clear_multipass_cache (GstTheoraEnc * enc)
394 if (enc->multipass_cache_fd) {
395 g_io_channel_shutdown (enc->multipass_cache_fd, TRUE, NULL);
396 g_io_channel_unref (enc->multipass_cache_fd);
397 enc->multipass_cache_fd = NULL;
400 if (enc->multipass_cache_adapter) {
401 gst_object_unref (enc->multipass_cache_adapter);
402 enc->multipass_cache_adapter = NULL;
407 theora_enc_finalize (GObject * object)
409 GstTheoraEnc *enc = GST_THEORA_ENC (object);
411 GST_DEBUG_OBJECT (enc, "Finalizing");
413 th_encode_free (enc->encoder);
414 th_comment_clear (&enc->comment);
415 th_info_clear (&enc->info);
416 g_free (enc->multipass_cache_file);
418 theora_enc_clear_multipass_cache (enc);
420 G_OBJECT_CLASS (parent_class)->finalize (object);
424 theora_enc_write_multipass_cache_beginning (GstTheoraEnc * enc, gboolean eos)
429 gsize bytes_written = 0;
433 g_io_channel_seek_position (enc->multipass_cache_fd, 0, G_SEEK_SET, &err);
434 if (stat != G_IO_STATUS_ERROR) {
437 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_OUT, &buf, sizeof (buf));
439 g_io_channel_write_chars (enc->multipass_cache_fd, buf, bytes_read,
440 &bytes_written, NULL);
441 } while (bytes_read > 0 && bytes_written > 0);
445 if (stat == G_IO_STATUS_ERROR || bytes_read < 0 || bytes_written < 0) {
447 GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL),
448 ("Failed to seek to beginning of multipass cache file: %s",
451 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
452 ("Failed to seek to beginning of multipass cache file: %s",
462 theora_enc_reset (GstTheoraEnc * enc)
464 ogg_uint32_t keyframe_force;
467 GST_OBJECT_LOCK (enc);
468 enc->info.target_bitrate = enc->video_bitrate;
469 enc->info.quality = enc->video_quality;
470 enc->bitrate_changed = FALSE;
471 enc->quality_changed = FALSE;
472 GST_OBJECT_UNLOCK (enc);
475 th_encode_free (enc->encoder);
476 enc->encoder = th_encode_alloc (&enc->info);
477 /* We ensure this function cannot fail. */
478 g_assert (enc->encoder != NULL);
479 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
480 sizeof (enc->speed_level));
481 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_VP3_COMPATIBLE,
482 &enc->vp3_compatible, sizeof (enc->vp3_compatible));
485 if (enc->drop_frames)
486 rate_flags |= TH_RATECTL_DROP_FRAMES;
487 if (enc->drop_frames)
488 rate_flags |= TH_RATECTL_CAP_OVERFLOW;
489 if (enc->drop_frames)
490 rate_flags |= TH_RATECTL_CAP_UNDERFLOW;
491 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_FLAGS,
492 &rate_flags, sizeof (rate_flags));
494 if (enc->rate_buffer) {
495 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_BUFFER,
496 &enc->rate_buffer, sizeof (enc->rate_buffer));
501 keyframe_force = enc->keyframe_auto ?
502 enc->keyframe_force : enc->keyframe_freq;
503 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
504 &keyframe_force, sizeof (keyframe_force));
506 /* Get placeholder data */
507 if (enc->multipass_cache_fd
508 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
509 theora_enc_write_multipass_cache_beginning (enc, FALSE);
513 theora_enc_clear (GstTheoraEnc * enc)
517 enc->granulepos_offset = 0;
518 enc->timestamp_offset = 0;
520 enc->next_ts = GST_CLOCK_TIME_NONE;
521 enc->next_discont = FALSE;
522 enc->expected_ts = GST_CLOCK_TIME_NONE;
526 theora_enc_get_supported_formats (void)
532 th_pixel_fmt pixelformat;
536 TH_PF_420, "I420"}, {
537 TH_PF_422, "Y42B"}, {
540 GString *string = NULL;
543 th_info_init (&info);
544 info.frame_width = 16;
545 info.frame_height = 16;
546 info.fps_numerator = 25;
547 info.fps_denominator = 1;
548 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
549 info.pixel_fmt = formats[i].pixelformat;
551 encoder = th_encode_alloc (&info);
555 GST_LOG ("format %s is supported", formats[i].fourcc);
556 th_encode_free (encoder);
558 if (string == NULL) {
559 string = g_string_new (formats[i].fourcc);
561 g_string_append (string, ", ");
562 g_string_append (string, formats[i].fourcc);
565 th_info_clear (&info);
567 return string == NULL ? NULL : g_string_free (string, FALSE);
571 theora_enc_sink_getcaps (GstPad * pad)
574 char *supported_formats, *caps_string;
576 supported_formats = theora_enc_get_supported_formats ();
577 if (!supported_formats) {
578 GST_WARNING ("no supported formats found. Encoder disabled?");
579 return gst_caps_new_empty ();
582 caps_string = g_strdup_printf ("video/x-raw-yuv, "
583 "format = (fourcc) { %s }, "
584 "framerate = (fraction) [1/MAX, MAX], "
585 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]",
587 caps = gst_caps_from_string (caps_string);
588 g_free (caps_string);
589 g_free (supported_formats);
590 GST_DEBUG ("Supported caps: %" GST_PTR_FORMAT, caps);
596 theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
598 GstStructure *structure = gst_caps_get_structure (caps, 0);
599 GstTheoraEnc *enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
604 gst_structure_get_fourcc (structure, "format", &fourcc);
605 gst_structure_get_int (structure, "width", &enc->width);
606 gst_structure_get_int (structure, "height", &enc->height);
607 gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d);
608 par = gst_structure_get_value (structure, "pixel-aspect-ratio");
610 th_info_clear (&enc->info);
611 th_info_init (&enc->info);
612 /* Theora has a divisible-by-sixteen restriction for the encoded video size but
613 * we can define a picture area using pic_width/pic_height */
614 enc->info.frame_width = GST_ROUND_UP_16 (enc->width);
615 enc->info.frame_height = GST_ROUND_UP_16 (enc->height);
616 enc->info.pic_width = enc->width;
617 enc->info.pic_height = enc->height;
619 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
620 enc->info.pixel_fmt = TH_PF_420;
622 case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
623 enc->info.pixel_fmt = TH_PF_422;
625 case GST_MAKE_FOURCC ('Y', '4', '4', '4'):
626 enc->info.pixel_fmt = TH_PF_444;
629 g_assert_not_reached ();
632 enc->info.fps_numerator = enc->fps_n = fps_n;
633 enc->info.fps_denominator = enc->fps_d = fps_d;
635 enc->info.aspect_numerator = gst_value_get_fraction_numerator (par);
636 enc->info.aspect_denominator = gst_value_get_fraction_denominator (par);
638 /* setting them to 0 indicates that the decoder can chose a good aspect
639 * ratio, defaulting to 1/1 */
640 enc->info.aspect_numerator = 0;
641 enc->info.aspect_denominator = 0;
644 enc->info.colorspace = TH_CS_UNSPECIFIED;
646 /* as done in theora */
647 enc->info.keyframe_granule_shift = _ilog (enc->keyframe_force - 1);
648 GST_DEBUG_OBJECT (enc,
649 "keyframe_frequency_force is %d, granule shift is %d",
650 enc->keyframe_force, enc->info.keyframe_granule_shift);
652 theora_enc_reset (enc);
653 enc->initialised = TRUE;
655 gst_object_unref (enc);
661 granulepos_add (guint64 granulepos, guint64 addend, gint shift)
663 guint64 iframe, pframe;
665 iframe = granulepos >> shift;
666 pframe = granulepos - (iframe << shift);
669 return (iframe << shift) + pframe;
672 /* prepare a buffer for transmission by passing data through libtheora */
674 theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
675 GstClockTime timestamp, GstClockTime running_time,
676 GstClockTime duration, GstBuffer ** buffer)
679 GstFlowReturn ret = GST_FLOW_OK;
681 buf = gst_buffer_new_and_alloc (packet->bytes);
683 GST_WARNING_OBJECT (enc, "Could not allocate buffer");
684 ret = GST_FLOW_ERROR;
688 memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
689 gst_buffer_set_caps (buf, GST_PAD_CAPS (enc->srcpad));
690 /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
691 * time representation */
692 GST_BUFFER_OFFSET_END (buf) =
693 granulepos_add (packet->granulepos, enc->granulepos_offset,
694 enc->info.keyframe_granule_shift);
695 GST_BUFFER_OFFSET (buf) = granulepos_to_timestamp (enc,
696 GST_BUFFER_OFFSET_END (buf));
698 GST_BUFFER_TIMESTAMP (buf) = timestamp;
699 GST_BUFFER_DURATION (buf) = duration;
701 if (enc->next_discont) {
702 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
703 enc->next_discont = FALSE;
706 /* the second most significant bit of the first data byte is cleared
708 if (packet->bytes > 0 && (packet->packet[0] & 0x40) == 0) {
709 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
711 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
720 /* push out the buffer and do internal bookkeeping */
722 theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
726 enc->bytes_out += GST_BUFFER_SIZE (buffer);
728 ret = gst_pad_push (enc->srcpad, buffer);
734 theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet,
735 GstClockTime timestamp, GstClockTime running_time, GstClockTime duration)
741 theora_buffer_from_packet (enc, packet, timestamp, running_time, duration,
743 if (ret == GST_FLOW_OK)
744 ret = theora_push_buffer (enc, buf);
750 theora_set_header_on_caps (GstCaps * caps, GSList * buffers)
752 GstStructure *structure;
753 GValue array = { 0 };
754 GValue value = { 0 };
758 caps = gst_caps_make_writable (caps);
759 structure = gst_caps_get_structure (caps, 0);
761 /* put copies of the buffers in a fixed list */
762 g_value_init (&array, GST_TYPE_ARRAY);
764 for (walk = buffers; walk; walk = walk->next) {
768 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
770 /* Copy buffer, because we can't use the original -
771 * it creates a circular refcount with the caps<->buffers */
772 buffer = gst_buffer_copy (buffer);
774 g_value_init (&value, GST_TYPE_BUFFER);
775 gst_value_set_buffer (&value, buffer);
776 gst_value_array_append_value (&array, &value);
777 g_value_unset (&value);
780 gst_buffer_unref (buffer);
783 gst_structure_set_value (structure, "streamheader", &array);
784 g_value_unset (&array);
790 theora_enc_force_keyframe (GstTheoraEnc * enc)
792 GstClockTime next_ts;
794 /* make sure timestamps increment after resetting the decoder */
795 next_ts = enc->next_ts + enc->timestamp_offset;
797 theora_enc_reset (enc);
798 enc->granulepos_offset =
799 gst_util_uint64_scale (next_ts, enc->fps_n, GST_SECOND * enc->fps_d);
800 enc->timestamp_offset = next_ts;
805 theora_enc_sink_event (GstPad * pad, GstEvent * event)
811 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
813 switch (GST_EVENT_TYPE (event)) {
814 case GST_EVENT_NEWSEGMENT:
817 gdouble rate, applied_rate;
819 gint64 start, stop, time;
821 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
822 &format, &start, &stop, &time);
824 gst_segment_set_newsegment_full (&enc->segment, update, rate,
825 applied_rate, format, start, stop, time);
827 res = gst_pad_push_event (enc->srcpad, event);
831 if (enc->initialised) {
832 /* push last packet with eos flag, should not be called */
833 while (th_encode_packetout (enc->encoder, 1, &op)) {
834 GstClockTime next_time =
835 th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
837 theora_push_packet (enc, &op, GST_CLOCK_TIME_NONE, enc->next_ts,
838 next_time - enc->next_ts);
839 enc->next_ts = next_time;
842 if (enc->initialised && enc->multipass_cache_fd
843 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
844 theora_enc_write_multipass_cache_beginning (enc, TRUE);
846 theora_enc_clear_multipass_cache (enc);
848 res = gst_pad_push_event (enc->srcpad, event);
850 case GST_EVENT_FLUSH_STOP:
851 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
852 res = gst_pad_push_event (enc->srcpad, event);
854 case GST_EVENT_CUSTOM_DOWNSTREAM:
856 const GstStructure *s;
858 s = gst_event_get_structure (event);
860 if (gst_structure_has_name (s, "GstForceKeyUnit"))
861 theora_enc_force_keyframe (enc);
862 res = gst_pad_push_event (enc->srcpad, event);
866 res = gst_pad_push_event (enc->srcpad, event);
873 theora_enc_src_event (GstPad * pad, GstEvent * event)
878 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
880 switch (GST_EVENT_TYPE (event)) {
881 case GST_EVENT_CUSTOM_UPSTREAM:
883 const GstStructure *s;
885 s = gst_event_get_structure (event);
887 if (gst_structure_has_name (s, "GstForceKeyUnit")) {
888 GST_OBJECT_LOCK (enc);
889 enc->force_keyframe = TRUE;
890 GST_OBJECT_UNLOCK (enc);
891 /* consume the event */
893 gst_event_unref (event);
895 res = gst_pad_push_event (enc->sinkpad, event);
900 res = gst_pad_push_event (enc->sinkpad, event);
908 theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp,
909 GstClockTime duration)
911 GstClockTimeDiff max_diff;
912 gboolean ret = FALSE;
914 /* Allow 3/4 a frame off */
915 max_diff = (enc->info.fps_denominator * GST_SECOND * 3) /
916 (enc->info.fps_numerator * 4);
918 if (timestamp != GST_CLOCK_TIME_NONE
919 && enc->expected_ts != GST_CLOCK_TIME_NONE) {
920 if ((GstClockTimeDiff) (timestamp - enc->expected_ts) > max_diff) {
921 GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT
922 " exceeds expected value %" GST_TIME_FORMAT
923 " by too much, marking discontinuity",
924 GST_TIME_ARGS (timestamp), GST_TIME_ARGS (enc->expected_ts));
929 if (GST_CLOCK_TIME_IS_VALID (duration))
930 enc->expected_ts = timestamp + duration;
932 enc->expected_ts = GST_CLOCK_TIME_NONE;
938 theora_enc_init_buffer (th_ycbcr_buffer buf, th_info * info, guint8 * data)
940 GstVideoFormat format;
943 switch (info->pixel_fmt) {
945 format = GST_VIDEO_FORMAT_Y444;
948 format = GST_VIDEO_FORMAT_I420;
951 format = GST_VIDEO_FORMAT_Y42B;
954 g_assert_not_reached ();
957 /* According to Theora developer Timothy Terriberry, the Theora
958 * encoder will not use memory outside of pic_width/height, even when
959 * the frame size is bigger. The values outside this region will be encoded
961 * Due to this, setting the frame's width/height as the buffer width/height
962 * is perfectly ok, even though it does not strictly look ok.
964 for (i = 0; i < 3; i++) {
966 gst_video_format_get_component_width (format, i, info->frame_width);
968 gst_video_format_get_component_height (format, i, info->frame_height);
971 data + gst_video_format_get_component_offset (format, i,
972 info->pic_width, info->pic_height);
974 gst_video_format_get_row_stride (format, i, info->pic_width);
979 theora_enc_read_multipass_cache (GstTheoraEnc * enc)
981 GstBuffer *cache_buf;
982 const guint8 *cache_data;
983 gsize bytes_read = 0, bytes_consumed = 0;
984 GIOStatus stat = G_IO_STATUS_NORMAL;
985 gboolean done = FALSE;
988 if (gst_adapter_available (enc->multipass_cache_adapter) == 0) {
989 cache_buf = gst_buffer_new_and_alloc (512);
990 stat = g_io_channel_read_chars (enc->multipass_cache_fd,
991 (gchar *) GST_BUFFER_DATA (cache_buf), GST_BUFFER_SIZE (cache_buf),
994 if (bytes_read <= 0) {
995 gst_buffer_unref (cache_buf);
998 GST_BUFFER_SIZE (cache_buf) = bytes_read;
1000 gst_adapter_push (enc->multipass_cache_adapter, cache_buf);
1003 if (gst_adapter_available (enc->multipass_cache_adapter) == 0)
1007 MIN (gst_adapter_available (enc->multipass_cache_adapter), 512);
1009 cache_data = gst_adapter_peek (enc->multipass_cache_adapter, bytes_read);
1012 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data,
1014 done = bytes_consumed <= 0;
1015 if (bytes_consumed > 0)
1016 gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed);
1019 if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_EOF && bytes_read == 0)
1020 || bytes_consumed < 0) {
1021 GST_ELEMENT_ERROR (enc, RESOURCE, READ, (NULL),
1022 ("Failed to read multipass cache file"));
1029 theora_enc_write_multipass_cache (GstTheoraEnc * enc)
1033 gsize bytes_written = 0;
1037 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_OUT, &buf, sizeof (buf));
1039 g_io_channel_write_chars (enc->multipass_cache_fd, buf, bytes_read,
1040 &bytes_written, NULL);
1041 } while (bytes_read > 0 && bytes_written > 0);
1043 if (bytes_read < 0 || bytes_written < 0) {
1044 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1045 ("Failed to write multipass cache file"));
1051 static GstFlowReturn
1052 theora_enc_chain (GstPad * pad, GstBuffer * buffer)
1056 GstClockTime timestamp, duration, running_time;
1058 gboolean force_keyframe;
1060 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
1062 /* we keep track of two timelines.
1063 * - The timestamps from the incomming buffers, which we copy to the outgoing
1064 * encoded buffers as-is. We need to do this as we simply forward the
1065 * newsegment events.
1066 * - The running_time of the buffers, which we use to construct the granulepos
1069 timestamp = GST_BUFFER_TIMESTAMP (buffer);
1070 duration = GST_BUFFER_DURATION (buffer);
1073 gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
1074 if ((gint64) running_time < 0) {
1075 GST_DEBUG_OBJECT (enc, "Dropping buffer, timestamp: %" GST_TIME_FORMAT,
1076 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
1077 gst_buffer_unref (buffer);
1081 GST_OBJECT_LOCK (enc);
1082 if (enc->bitrate_changed) {
1083 long int bitrate = enc->video_bitrate;
1085 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
1087 enc->bitrate_changed = FALSE;
1090 if (enc->quality_changed) {
1091 long int quality = enc->video_quality;
1093 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
1095 enc->quality_changed = FALSE;
1098 /* see if we need to schedule a keyframe */
1099 force_keyframe = enc->force_keyframe;
1100 enc->force_keyframe = FALSE;
1101 GST_OBJECT_UNLOCK (enc);
1103 if (force_keyframe) {
1104 GstClockTime stream_time;
1107 stream_time = gst_segment_to_stream_time (&enc->segment,
1108 GST_FORMAT_TIME, timestamp);
1110 s = gst_structure_new ("GstForceKeyUnit",
1111 "timestamp", G_TYPE_UINT64, timestamp,
1112 "stream-time", G_TYPE_UINT64, stream_time,
1113 "running-time", G_TYPE_UINT64, running_time, NULL);
1115 theora_enc_force_keyframe (enc);
1117 gst_pad_push_event (enc->srcpad,
1118 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
1121 /* make sure we copy the discont flag to the next outgoing buffer when it's
1122 * set on the incomming buffer */
1123 if (GST_BUFFER_IS_DISCONT (buffer)) {
1124 enc->next_discont = TRUE;
1127 if (enc->packetno == 0) {
1128 /* no packets written yet, setup headers */
1131 GSList *buffers = NULL;
1134 enc->granulepos_offset = 0;
1135 enc->timestamp_offset = 0;
1137 GST_DEBUG_OBJECT (enc, "output headers");
1138 /* Theora streams begin with three headers; the initial header (with
1139 most of the codec setup parameters) which is mandated by the Ogg
1140 bitstream spec. The second header holds any comment fields. The
1141 third header holds the bitstream codebook. We merely need to
1142 make the headers, then pass them to libtheora one at a time;
1143 libtheora handles the additional Ogg bitstream constraints */
1145 /* create the remaining theora headers */
1146 th_comment_clear (&enc->comment);
1147 th_comment_init (&enc->comment);
1150 th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
1152 theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
1153 GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf);
1154 if (ret != GST_FLOW_OK) {
1155 goto header_buffer_alloc;
1157 buffers = g_slist_prepend (buffers, buf);
1160 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1161 g_slist_free (buffers);
1162 goto encoder_disabled;
1165 buffers = g_slist_reverse (buffers);
1167 /* mark buffers and put on caps */
1168 caps = gst_pad_get_caps (enc->srcpad);
1169 caps = theora_set_header_on_caps (caps, buffers);
1170 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
1171 gst_pad_set_caps (enc->srcpad, caps);
1173 g_slist_foreach (buffers, (GFunc) gst_buffer_set_caps, caps);
1175 gst_caps_unref (caps);
1177 /* push out the header buffers */
1179 buf = buffers->data;
1180 buffers = g_slist_delete_link (buffers, buffers);
1181 if ((ret = theora_push_buffer (enc, buf)) != GST_FLOW_OK) {
1182 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1183 g_slist_free (buffers);
1188 enc->granulepos_offset =
1189 gst_util_uint64_scale (running_time, enc->fps_n,
1190 GST_SECOND * enc->fps_d);
1191 enc->timestamp_offset = running_time;
1196 th_ycbcr_buffer ycbcr;
1199 theora_enc_init_buffer (ycbcr, &enc->info, GST_BUFFER_DATA (buffer));
1201 if (theora_enc_is_discontinuous (enc, running_time, duration)) {
1202 theora_enc_reset (enc);
1203 enc->granulepos_offset =
1204 gst_util_uint64_scale (running_time, enc->fps_n,
1205 GST_SECOND * enc->fps_d);
1206 enc->timestamp_offset = running_time;
1208 enc->next_discont = TRUE;
1211 if (enc->multipass_cache_fd
1212 && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
1213 if (!theora_enc_read_multipass_cache (enc)) {
1214 ret = GST_FLOW_ERROR;
1215 goto multipass_read_failed;
1219 res = th_encode_ycbcr_in (enc->encoder, ycbcr);
1220 /* none of the failure cases can happen here */
1221 g_assert (res == 0);
1223 if (enc->multipass_cache_fd
1224 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
1225 if (!theora_enc_write_multipass_cache (enc)) {
1226 ret = GST_FLOW_ERROR;
1227 goto multipass_write_failed;
1232 while (th_encode_packetout (enc->encoder, 0, &op)) {
1233 GstClockTime next_time;
1235 next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
1238 theora_push_packet (enc, &op, timestamp, enc->next_ts,
1239 next_time - enc->next_ts);
1241 enc->next_ts = next_time;
1242 if (ret != GST_FLOW_OK)
1245 gst_buffer_unref (buffer);
1251 multipass_read_failed:
1253 gst_buffer_unref (buffer);
1256 multipass_write_failed:
1258 gst_buffer_unref (buffer);
1261 header_buffer_alloc:
1263 gst_buffer_unref (buffer);
1268 gst_buffer_unref (buffer);
1273 gst_buffer_unref (buffer);
1278 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1279 ("libtheora has been compiled with the encoder disabled"));
1280 gst_buffer_unref (buffer);
1281 return GST_FLOW_ERROR;
1285 static GstStateChangeReturn
1286 theora_enc_change_state (GstElement * element, GstStateChange transition)
1289 GstStateChangeReturn ret;
1291 enc = GST_THEORA_ENC (element);
1293 switch (transition) {
1294 case GST_STATE_CHANGE_NULL_TO_READY:
1296 case GST_STATE_CHANGE_READY_TO_PAUSED:
1297 GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state");
1298 th_info_init (&enc->info);
1299 th_comment_init (&enc->comment);
1301 enc->force_keyframe = FALSE;
1303 if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) {
1306 if (!enc->multipass_cache_file) {
1307 ret = GST_STATE_CHANGE_FAILURE;
1308 GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
1311 enc->multipass_cache_fd =
1312 g_io_channel_new_file (enc->multipass_cache_file,
1313 (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"),
1316 if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS)
1317 enc->multipass_cache_adapter = gst_adapter_new ();
1319 if (!enc->multipass_cache_fd) {
1320 ret = GST_STATE_CHANGE_FAILURE;
1321 GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL),
1322 ("Failed to open multipass cache file: %s", err->message));
1327 g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL);
1330 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1336 ret = parent_class->change_state (element, transition);
1338 switch (transition) {
1339 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1341 case GST_STATE_CHANGE_PAUSED_TO_READY:
1342 GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state");
1344 th_encode_free (enc->encoder);
1345 enc->encoder = NULL;
1347 th_comment_clear (&enc->comment);
1348 th_info_clear (&enc->info);
1350 theora_enc_clear (enc);
1351 enc->initialised = FALSE;
1353 case GST_STATE_CHANGE_READY_TO_NULL:
1363 theora_enc_set_property (GObject * object, guint prop_id,
1364 const GValue * value, GParamSpec * pspec)
1366 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1372 case PROP_KEYFRAME_THRESHOLD:
1373 case PROP_KEYFRAME_MINDISTANCE:
1374 case PROP_NOISE_SENSITIVITY:
1375 case PROP_SHARPNESS:
1376 /* kept for API compat, but ignored */
1379 GST_OBJECT_LOCK (enc);
1380 enc->video_bitrate = g_value_get_int (value) * 1000;
1381 enc->video_quality = 0;
1382 enc->bitrate_changed = TRUE;
1383 GST_OBJECT_UNLOCK (enc);
1386 GST_OBJECT_LOCK (enc);
1387 if (GST_STATE (enc) >= GST_STATE_PAUSED && enc->video_quality == 0) {
1388 GST_WARNING_OBJECT (object, "Can't change from bitrate to quality mode"
1391 enc->video_quality = g_value_get_int (value);
1392 enc->video_bitrate = 0;
1393 enc->quality_changed = TRUE;
1395 GST_OBJECT_UNLOCK (enc);
1397 case PROP_KEYFRAME_AUTO:
1398 enc->keyframe_auto = g_value_get_boolean (value);
1400 case PROP_KEYFRAME_FREQ:
1401 enc->keyframe_freq = g_value_get_int (value);
1403 case PROP_KEYFRAME_FREQ_FORCE:
1404 enc->keyframe_force = g_value_get_int (value);
1406 case PROP_SPEEDLEVEL:
1407 enc->speed_level = g_value_get_int (value);
1409 case PROP_VP3_COMPATIBLE:
1410 enc->vp3_compatible = g_value_get_boolean (value);
1412 case PROP_DROP_FRAMES:
1413 enc->drop_frames = g_value_get_boolean (value);
1415 case PROP_CAP_OVERFLOW:
1416 enc->cap_overflow = g_value_get_boolean (value);
1418 case PROP_CAP_UNDERFLOW:
1419 enc->cap_underflow = g_value_get_boolean (value);
1421 case PROP_RATE_BUFFER:
1422 enc->rate_buffer = g_value_get_int (value);
1424 case PROP_MULTIPASS_CACHE_FILE:
1425 enc->multipass_cache_file = g_value_dup_string (value);
1427 case PROP_MULTIPASS_MODE:
1428 enc->multipass_mode = g_value_get_enum (value);
1431 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1437 theora_enc_get_property (GObject * object, guint prop_id,
1438 GValue * value, GParamSpec * pspec)
1440 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1444 g_value_set_boolean (value, TRUE);
1447 g_value_set_enum (value, BORDER_BLACK);
1450 GST_OBJECT_LOCK (enc);
1451 g_value_set_int (value, enc->video_bitrate / 1000);
1452 GST_OBJECT_UNLOCK (enc);
1455 GST_OBJECT_LOCK (enc);
1456 g_value_set_int (value, enc->video_quality);
1457 GST_OBJECT_UNLOCK (enc);
1460 g_value_set_boolean (value, TRUE);
1462 case PROP_KEYFRAME_AUTO:
1463 g_value_set_boolean (value, enc->keyframe_auto);
1465 case PROP_KEYFRAME_FREQ:
1466 g_value_set_int (value, enc->keyframe_freq);
1468 case PROP_KEYFRAME_FREQ_FORCE:
1469 g_value_set_int (value, enc->keyframe_force);
1471 case PROP_KEYFRAME_THRESHOLD:
1472 g_value_set_int (value, 80);
1474 case PROP_KEYFRAME_MINDISTANCE:
1475 g_value_set_int (value, 8);
1477 case PROP_NOISE_SENSITIVITY:
1478 g_value_set_int (value, 1);
1480 case PROP_SHARPNESS:
1481 g_value_set_int (value, 0);
1483 case PROP_SPEEDLEVEL:
1484 g_value_set_int (value, enc->speed_level);
1486 case PROP_VP3_COMPATIBLE:
1487 g_value_set_boolean (value, enc->vp3_compatible);
1489 case PROP_DROP_FRAMES:
1490 g_value_set_boolean (value, enc->drop_frames);
1492 case PROP_CAP_OVERFLOW:
1493 g_value_set_boolean (value, enc->cap_overflow);
1495 case PROP_CAP_UNDERFLOW:
1496 g_value_set_boolean (value, enc->cap_underflow);
1498 case PROP_RATE_BUFFER:
1499 g_value_set_int (value, enc->rate_buffer);
1501 case PROP_MULTIPASS_CACHE_FILE:
1502 g_value_set_string (value, enc->multipass_cache_file);
1504 case PROP_MULTIPASS_MODE:
1505 g_value_set_enum (value, enc->multipass_mode);
1508 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);