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 /* Generate a dummy encoder context for use in th_encode_ctl queries
179 Release with th_encode_free()
180 This and the next routine from theora/examples/libtheora_info.c */
182 dummy_encode_ctx (void)
187 /* set the minimal video parameters */
188 th_info_init (&info);
189 info.frame_width = 320;
190 info.frame_height = 240;
191 info.fps_numerator = 1;
192 info.fps_denominator = 1;
194 /* allocate and initialize a context object */
195 ctx = th_encode_alloc (&info);
197 GST_WARNING ("Failed to allocate dummy encoder context.");
199 /* clear the info struct */
200 th_info_clear (&info);
205 /* Query the current and maximum values for the 'speed level' setting.
206 This can be used to ask the encoder to trade off encoding quality
207 vs. performance cost, for example to adapt to realtime constraints. */
209 check_speed_level (th_enc_ctx * ctx, int *current, int *max)
213 /* query the current speed level */
214 ret = th_encode_ctl (ctx, TH_ENCCTL_GET_SPLEVEL, current, sizeof (int));
216 GST_WARNING ("Error %d getting current speed level.", ret);
219 /* query the maximum speed level, which varies by encoder version */
220 ret = th_encode_ctl (ctx, TH_ENCCTL_GET_SPLEVEL_MAX, max, sizeof (int));
222 GST_WARNING ("Error %d getting maximum speed level.", ret);
229 static GstStaticPadTemplate theora_enc_sink_factory =
230 GST_STATIC_PAD_TEMPLATE ("sink",
233 GST_STATIC_CAPS ("video/x-raw-yuv, "
234 "format = (fourcc) { I420, Y42B, Y444 }, "
235 "framerate = (fraction) [1/MAX, MAX], "
236 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
239 static GstStaticPadTemplate theora_enc_src_factory =
240 GST_STATIC_PAD_TEMPLATE ("src",
243 GST_STATIC_CAPS ("video/x-theora")
247 _do_init (GType object_type)
249 const GInterfaceInfo preset_interface_info = {
250 NULL, /* interface_init */
251 NULL, /* interface_finalize */
252 NULL /* interface_data */
255 g_type_add_interface_static (object_type, GST_TYPE_PRESET,
256 &preset_interface_info);
259 GST_BOILERPLATE_FULL (GstTheoraEnc, gst_theora_enc, GstElement,
260 GST_TYPE_ELEMENT, _do_init);
262 static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event);
263 static gboolean theora_enc_src_event (GstPad * pad, GstEvent * event);
264 static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
265 static GstStateChangeReturn theora_enc_change_state (GstElement * element,
266 GstStateChange transition);
267 static GstCaps *theora_enc_sink_getcaps (GstPad * pad);
268 static gboolean theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
269 static void theora_enc_get_property (GObject * object, guint prop_id,
270 GValue * value, GParamSpec * pspec);
271 static void theora_enc_set_property (GObject * object, guint prop_id,
272 const GValue * value, GParamSpec * pspec);
273 static void theora_enc_finalize (GObject * object);
275 static gboolean theora_enc_write_multipass_cache (GstTheoraEnc * enc,
276 gboolean begin, gboolean eos);
279 gst_theora_enc_base_init (gpointer g_class)
281 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
283 gst_element_class_add_pad_template (element_class,
284 gst_static_pad_template_get (&theora_enc_src_factory));
285 gst_element_class_add_pad_template (element_class,
286 gst_static_pad_template_get (&theora_enc_sink_factory));
287 gst_element_class_set_details_simple (element_class,
288 "Theora video encoder", "Codec/Encoder/Video",
289 "encode raw YUV video to a theora stream",
290 "Wim Taymans <wim@fluendo.com>");
294 gst_theora_enc_class_init (GstTheoraEncClass * klass)
296 GObjectClass *gobject_class = (GObjectClass *) klass;
297 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
299 /* query runtime encoder properties */
301 int default_speed_level = THEORA_DEF_SPEEDLEVEL;
302 int max_speed_level = default_speed_level;
304 GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
306 th_ctx = dummy_encode_ctx ();
308 if (!check_speed_level (th_ctx, &default_speed_level, &max_speed_level))
310 ("Failed to determine settings for the speed-level property.");
311 th_encode_free (th_ctx);
314 gobject_class->set_property = theora_enc_set_property;
315 gobject_class->get_property = theora_enc_get_property;
316 gobject_class->finalize = theora_enc_finalize;
318 g_object_class_install_property (gobject_class, PROP_CENTER,
319 g_param_spec_boolean ("center", "Center",
320 "ignored and kept for API compat only", TRUE,
321 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
322 g_object_class_install_property (gobject_class, PROP_BORDER,
323 g_param_spec_enum ("border", "Border",
324 "ignored and kept for API compat only",
325 GST_TYPE_BORDER_MODE, BORDER_BLACK,
326 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
327 /* general encoding stream options */
328 g_object_class_install_property (gobject_class, PROP_BITRATE,
329 g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
330 0, (1 << 24) - 1, THEORA_DEF_BITRATE,
331 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
332 GST_PARAM_MUTABLE_PLAYING));
333 g_object_class_install_property (gobject_class, PROP_QUALITY,
334 g_param_spec_int ("quality", "Quality", "Video quality", 0, 63,
336 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
337 GST_PARAM_MUTABLE_PLAYING));
338 g_object_class_install_property (gobject_class, PROP_QUICK,
339 g_param_spec_boolean ("quick", "Quick",
340 "ignored and kept for API compat only", TRUE,
341 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
342 g_object_class_install_property (gobject_class, PROP_KEYFRAME_AUTO,
343 g_param_spec_boolean ("keyframe-auto", "Keyframe Auto",
344 "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO,
345 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
346 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ,
347 g_param_spec_int ("keyframe-freq", "Keyframe frequency",
348 "Keyframe frequency", 1, 32768, THEORA_DEF_KEYFRAME_FREQ,
349 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
350 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ_FORCE,
351 g_param_spec_int ("keyframe-force", "Keyframe force",
352 "Force keyframe every N frames", 1, 32768,
353 THEORA_DEF_KEYFRAME_FREQ_FORCE,
354 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
355 g_object_class_install_property (gobject_class, PROP_KEYFRAME_THRESHOLD,
356 g_param_spec_int ("keyframe-threshold", "Keyframe threshold",
357 "ignored and kept for API compat only", 0, 32768, 80,
358 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
359 g_object_class_install_property (gobject_class, PROP_KEYFRAME_MINDISTANCE,
360 g_param_spec_int ("keyframe-mindistance", "Keyframe mindistance",
361 "ignored and kept for API compat only", 1, 32768, 8,
362 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
363 g_object_class_install_property (gobject_class, PROP_NOISE_SENSITIVITY,
364 g_param_spec_int ("noise-sensitivity", "Noise sensitivity",
365 "ignored and kept for API compat only", 0, 32768, 1,
366 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
367 g_object_class_install_property (gobject_class, PROP_SHARPNESS,
368 g_param_spec_int ("sharpness", "Sharpness",
369 "ignored and kept for API compat only", 0, 2, 0,
370 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
371 g_object_class_install_property (gobject_class, PROP_SPEEDLEVEL,
372 g_param_spec_int ("speed-level", "Speed level",
373 "Controls the amount of analysis performed when encoding."
374 " Higher values trade compression quality for speed."
375 " This property requires libtheora version >= 1.0"
376 ", and the maximum value may vary based on encoder version.",
377 0, max_speed_level, default_speed_level,
378 (GParamFlags) G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
379 G_PARAM_STATIC_STRINGS));
380 g_object_class_install_property (gobject_class, PROP_VP3_COMPATIBLE,
381 g_param_spec_boolean ("vp3-compatible", "VP3 Compatible",
382 "Disables non-VP3 compatible features",
383 THEORA_DEF_VP3_COMPATIBLE,
384 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
385 g_object_class_install_property (gobject_class, PROP_DROP_FRAMES,
386 g_param_spec_boolean ("drop-frames", "VP3 Compatible",
387 "Allow or disallow frame dropping",
388 THEORA_DEF_DROP_FRAMES,
389 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
390 g_object_class_install_property (gobject_class, PROP_CAP_OVERFLOW,
391 g_param_spec_boolean ("cap-overflow", "VP3 Compatible",
392 "Enable capping of bit reservoir overflows",
393 THEORA_DEF_CAP_OVERFLOW,
394 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
395 g_object_class_install_property (gobject_class, PROP_CAP_UNDERFLOW,
396 g_param_spec_boolean ("cap-underflow", "VP3 Compatible",
397 "Enable capping of bit reservoir underflows",
398 THEORA_DEF_CAP_UNDERFLOW,
399 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
400 g_object_class_install_property (gobject_class, PROP_RATE_BUFFER,
401 g_param_spec_int ("rate-buffer", "Rate Control Buffer",
402 "Sets the size of the rate control buffer, in units of frames. "
403 "The default value of 0 instructs the encoder to automatically "
404 "select an appropriate value",
405 0, 1000, THEORA_DEF_RATE_BUFFER,
406 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
407 g_object_class_install_property (gobject_class, PROP_MULTIPASS_CACHE_FILE,
408 g_param_spec_string ("multipass-cache-file", "Multipass Cache File",
409 "Multipass cache file", THEORA_DEF_MULTIPASS_CACHE_FILE,
410 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
411 g_object_class_install_property (gobject_class, PROP_MULTIPASS_MODE,
412 g_param_spec_enum ("multipass-mode", "Multipass mode",
413 "Single pass or first/second pass", GST_TYPE_MULTIPASS_MODE,
414 THEORA_DEF_MULTIPASS_MODE,
415 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
417 gstelement_class->change_state = theora_enc_change_state;
421 gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class)
424 gst_pad_new_from_static_template (&theora_enc_sink_factory, "sink");
425 gst_pad_set_chain_function (enc->sinkpad, theora_enc_chain);
426 gst_pad_set_event_function (enc->sinkpad, theora_enc_sink_event);
427 gst_pad_set_getcaps_function (enc->sinkpad, theora_enc_sink_getcaps);
428 gst_pad_set_setcaps_function (enc->sinkpad, theora_enc_sink_setcaps);
429 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
432 gst_pad_new_from_static_template (&theora_enc_src_factory, "src");
433 gst_pad_set_event_function (enc->srcpad, theora_enc_src_event);
434 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
436 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
438 enc->video_bitrate = THEORA_DEF_BITRATE;
439 enc->video_quality = THEORA_DEF_QUALITY;
440 enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
441 enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ;
442 enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE;
444 enc->expected_ts = GST_CLOCK_TIME_NONE;
446 /* enc->speed_level is set to the libtheora default by the constructor */
447 enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE;
448 enc->drop_frames = THEORA_DEF_DROP_FRAMES;
449 enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW;
450 enc->cap_underflow = THEORA_DEF_CAP_UNDERFLOW;
451 enc->rate_buffer = THEORA_DEF_RATE_BUFFER;
453 enc->multipass_mode = THEORA_DEF_MULTIPASS_MODE;
454 enc->multipass_cache_file = THEORA_DEF_MULTIPASS_CACHE_FILE;
458 theora_enc_clear_multipass_cache (GstTheoraEnc * enc)
460 if (enc->multipass_cache_fd) {
461 g_io_channel_shutdown (enc->multipass_cache_fd, TRUE, NULL);
462 g_io_channel_unref (enc->multipass_cache_fd);
463 enc->multipass_cache_fd = NULL;
466 if (enc->multipass_cache_adapter) {
467 gst_object_unref (enc->multipass_cache_adapter);
468 enc->multipass_cache_adapter = NULL;
473 theora_enc_finalize (GObject * object)
475 GstTheoraEnc *enc = GST_THEORA_ENC (object);
477 GST_DEBUG_OBJECT (enc, "Finalizing");
479 th_encode_free (enc->encoder);
480 th_comment_clear (&enc->comment);
481 th_info_clear (&enc->info);
482 g_free (enc->multipass_cache_file);
484 theora_enc_clear_multipass_cache (enc);
486 G_OBJECT_CLASS (parent_class)->finalize (object);
490 theora_enc_reset (GstTheoraEnc * enc)
492 ogg_uint32_t keyframe_force;
495 GST_OBJECT_LOCK (enc);
496 enc->info.target_bitrate = enc->video_bitrate;
497 enc->info.quality = enc->video_quality;
498 enc->bitrate_changed = FALSE;
499 enc->quality_changed = FALSE;
500 GST_OBJECT_UNLOCK (enc);
503 th_encode_free (enc->encoder);
504 enc->encoder = th_encode_alloc (&enc->info);
505 /* We ensure this function cannot fail. */
506 g_assert (enc->encoder != NULL);
507 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
508 sizeof (enc->speed_level));
509 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_VP3_COMPATIBLE,
510 &enc->vp3_compatible, sizeof (enc->vp3_compatible));
513 if (enc->drop_frames)
514 rate_flags |= TH_RATECTL_DROP_FRAMES;
515 if (enc->drop_frames)
516 rate_flags |= TH_RATECTL_CAP_OVERFLOW;
517 if (enc->drop_frames)
518 rate_flags |= TH_RATECTL_CAP_UNDERFLOW;
519 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_FLAGS,
520 &rate_flags, sizeof (rate_flags));
522 if (enc->rate_buffer) {
523 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_BUFFER,
524 &enc->rate_buffer, sizeof (enc->rate_buffer));
529 keyframe_force = enc->keyframe_auto ?
530 enc->keyframe_force : enc->keyframe_freq;
531 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
532 &keyframe_force, sizeof (keyframe_force));
534 /* Get placeholder data */
535 if (enc->multipass_cache_fd
536 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
537 theora_enc_write_multipass_cache (enc, TRUE, FALSE);
541 theora_enc_clear (GstTheoraEnc * enc)
545 enc->granulepos_offset = 0;
546 enc->timestamp_offset = 0;
548 enc->next_ts = GST_CLOCK_TIME_NONE;
549 enc->next_discont = FALSE;
550 enc->expected_ts = GST_CLOCK_TIME_NONE;
554 theora_enc_get_supported_formats (void)
560 th_pixel_fmt pixelformat;
564 TH_PF_420, "I420"}, {
565 TH_PF_422, "Y42B"}, {
568 GString *string = NULL;
571 th_info_init (&info);
572 info.frame_width = 16;
573 info.frame_height = 16;
574 info.fps_numerator = 25;
575 info.fps_denominator = 1;
576 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
577 info.pixel_fmt = formats[i].pixelformat;
579 encoder = th_encode_alloc (&info);
583 GST_LOG ("format %s is supported", formats[i].fourcc);
584 th_encode_free (encoder);
586 if (string == NULL) {
587 string = g_string_new (formats[i].fourcc);
589 g_string_append (string, ", ");
590 g_string_append (string, formats[i].fourcc);
593 th_info_clear (&info);
595 return string == NULL ? NULL : g_string_free (string, FALSE);
599 theora_enc_sink_getcaps (GstPad * pad)
602 char *supported_formats, *caps_string;
604 supported_formats = theora_enc_get_supported_formats ();
605 if (!supported_formats) {
606 GST_WARNING ("no supported formats found. Encoder disabled?");
607 return gst_caps_new_empty ();
610 caps_string = g_strdup_printf ("video/x-raw-yuv, "
611 "format = (fourcc) { %s }, "
612 "framerate = (fraction) [1/MAX, MAX], "
613 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]",
615 caps = gst_caps_from_string (caps_string);
616 g_free (caps_string);
617 g_free (supported_formats);
618 GST_DEBUG ("Supported caps: %" GST_PTR_FORMAT, caps);
624 theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
626 GstStructure *structure = gst_caps_get_structure (caps, 0);
627 GstTheoraEnc *enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
632 gst_structure_get_fourcc (structure, "format", &fourcc);
633 gst_structure_get_int (structure, "width", &enc->width);
634 gst_structure_get_int (structure, "height", &enc->height);
635 gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d);
636 par = gst_structure_get_value (structure, "pixel-aspect-ratio");
638 th_info_clear (&enc->info);
639 th_info_init (&enc->info);
640 /* Theora has a divisible-by-sixteen restriction for the encoded video size but
641 * we can define a picture area using pic_width/pic_height */
642 enc->info.frame_width = GST_ROUND_UP_16 (enc->width);
643 enc->info.frame_height = GST_ROUND_UP_16 (enc->height);
644 enc->info.pic_width = enc->width;
645 enc->info.pic_height = enc->height;
647 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
648 enc->info.pixel_fmt = TH_PF_420;
650 case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
651 enc->info.pixel_fmt = TH_PF_422;
653 case GST_MAKE_FOURCC ('Y', '4', '4', '4'):
654 enc->info.pixel_fmt = TH_PF_444;
657 g_assert_not_reached ();
660 enc->info.fps_numerator = enc->fps_n = fps_n;
661 enc->info.fps_denominator = enc->fps_d = fps_d;
663 enc->info.aspect_numerator = gst_value_get_fraction_numerator (par);
664 enc->info.aspect_denominator = gst_value_get_fraction_denominator (par);
666 /* setting them to 0 indicates that the decoder can chose a good aspect
667 * ratio, defaulting to 1/1 */
668 enc->info.aspect_numerator = 0;
669 enc->info.aspect_denominator = 0;
672 enc->info.colorspace = TH_CS_UNSPECIFIED;
674 /* as done in theora */
675 enc->info.keyframe_granule_shift = _ilog (enc->keyframe_force - 1);
676 GST_DEBUG_OBJECT (enc,
677 "keyframe_frequency_force is %d, granule shift is %d",
678 enc->keyframe_force, enc->info.keyframe_granule_shift);
680 theora_enc_reset (enc);
681 enc->initialised = TRUE;
683 gst_object_unref (enc);
689 granulepos_add (guint64 granulepos, guint64 addend, gint shift)
691 guint64 iframe, pframe;
693 iframe = granulepos >> shift;
694 pframe = granulepos - (iframe << shift);
697 return (iframe << shift) + pframe;
700 /* prepare a buffer for transmission by passing data through libtheora */
702 theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
703 GstClockTime timestamp, GstClockTime running_time,
704 GstClockTime duration, GstBuffer ** buffer)
707 GstFlowReturn ret = GST_FLOW_OK;
709 buf = gst_buffer_new_and_alloc (packet->bytes);
711 GST_WARNING_OBJECT (enc, "Could not allocate buffer");
712 ret = GST_FLOW_ERROR;
716 memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
717 gst_buffer_set_caps (buf, GST_PAD_CAPS (enc->srcpad));
718 /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
719 * time representation */
720 GST_BUFFER_OFFSET_END (buf) =
721 granulepos_add (packet->granulepos, enc->granulepos_offset,
722 enc->info.keyframe_granule_shift);
723 GST_BUFFER_OFFSET (buf) = granulepos_to_timestamp (enc,
724 GST_BUFFER_OFFSET_END (buf));
726 GST_BUFFER_TIMESTAMP (buf) = timestamp;
727 GST_BUFFER_DURATION (buf) = duration;
729 if (enc->next_discont) {
730 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
731 enc->next_discont = FALSE;
734 /* the second most significant bit of the first data byte is cleared
736 if (packet->bytes > 0 && (packet->packet[0] & 0x40) == 0) {
737 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
739 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
748 /* push out the buffer and do internal bookkeeping */
750 theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
754 enc->bytes_out += GST_BUFFER_SIZE (buffer);
756 ret = gst_pad_push (enc->srcpad, buffer);
762 theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet,
763 GstClockTime timestamp, GstClockTime running_time, GstClockTime duration)
769 theora_buffer_from_packet (enc, packet, timestamp, running_time, duration,
771 if (ret == GST_FLOW_OK)
772 ret = theora_push_buffer (enc, buf);
778 theora_set_header_on_caps (GstCaps * caps, GSList * buffers)
780 GstStructure *structure;
781 GValue array = { 0 };
782 GValue value = { 0 };
786 caps = gst_caps_make_writable (caps);
787 structure = gst_caps_get_structure (caps, 0);
789 /* put copies of the buffers in a fixed list */
790 g_value_init (&array, GST_TYPE_ARRAY);
792 for (walk = buffers; walk; walk = walk->next) {
796 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
798 /* Copy buffer, because we can't use the original -
799 * it creates a circular refcount with the caps<->buffers */
800 buffer = gst_buffer_copy (buffer);
802 g_value_init (&value, GST_TYPE_BUFFER);
803 gst_value_set_buffer (&value, buffer);
804 gst_value_array_append_value (&array, &value);
805 g_value_unset (&value);
808 gst_buffer_unref (buffer);
811 gst_structure_set_value (structure, "streamheader", &array);
812 g_value_unset (&array);
818 theora_enc_force_keyframe (GstTheoraEnc * enc)
820 GstClockTime next_ts;
822 /* make sure timestamps increment after resetting the decoder */
823 next_ts = enc->next_ts + enc->timestamp_offset;
825 theora_enc_reset (enc);
826 enc->granulepos_offset =
827 gst_util_uint64_scale (next_ts, enc->fps_n, GST_SECOND * enc->fps_d);
828 enc->timestamp_offset = next_ts;
833 theora_enc_sink_event (GstPad * pad, GstEvent * event)
839 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
841 switch (GST_EVENT_TYPE (event)) {
842 case GST_EVENT_NEWSEGMENT:
845 gdouble rate, applied_rate;
847 gint64 start, stop, time;
849 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
850 &format, &start, &stop, &time);
852 gst_segment_set_newsegment_full (&enc->segment, update, rate,
853 applied_rate, format, start, stop, time);
855 res = gst_pad_push_event (enc->srcpad, event);
859 if (enc->initialised) {
860 /* push last packet with eos flag, should not be called */
861 while (th_encode_packetout (enc->encoder, 1, &op)) {
862 GstClockTime next_time =
863 th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
865 theora_push_packet (enc, &op, GST_CLOCK_TIME_NONE, enc->next_ts,
866 next_time - enc->next_ts);
867 enc->next_ts = next_time;
870 if (enc->initialised && enc->multipass_cache_fd
871 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
872 theora_enc_write_multipass_cache (enc, TRUE, TRUE);
874 theora_enc_clear_multipass_cache (enc);
876 res = gst_pad_push_event (enc->srcpad, event);
878 case GST_EVENT_FLUSH_STOP:
879 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
880 res = gst_pad_push_event (enc->srcpad, event);
882 case GST_EVENT_CUSTOM_DOWNSTREAM:
884 const GstStructure *s;
886 s = gst_event_get_structure (event);
888 if (gst_structure_has_name (s, "GstForceKeyUnit"))
889 theora_enc_force_keyframe (enc);
890 res = gst_pad_push_event (enc->srcpad, event);
894 res = gst_pad_push_event (enc->srcpad, event);
901 theora_enc_src_event (GstPad * pad, GstEvent * event)
906 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
908 switch (GST_EVENT_TYPE (event)) {
909 case GST_EVENT_CUSTOM_UPSTREAM:
911 const GstStructure *s;
913 s = gst_event_get_structure (event);
915 if (gst_structure_has_name (s, "GstForceKeyUnit")) {
916 GST_OBJECT_LOCK (enc);
917 enc->force_keyframe = TRUE;
918 GST_OBJECT_UNLOCK (enc);
919 /* consume the event */
921 gst_event_unref (event);
923 res = gst_pad_push_event (enc->sinkpad, event);
928 res = gst_pad_push_event (enc->sinkpad, event);
936 theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp,
937 GstClockTime duration)
939 GstClockTimeDiff max_diff;
940 gboolean ret = FALSE;
942 /* Allow 3/4 a frame off */
943 max_diff = (enc->info.fps_denominator * GST_SECOND * 3) /
944 (enc->info.fps_numerator * 4);
946 if (timestamp != GST_CLOCK_TIME_NONE
947 && enc->expected_ts != GST_CLOCK_TIME_NONE) {
948 if ((GstClockTimeDiff) (timestamp - enc->expected_ts) > max_diff) {
949 GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT
950 " exceeds expected value %" GST_TIME_FORMAT
951 " by too much, marking discontinuity",
952 GST_TIME_ARGS (timestamp), GST_TIME_ARGS (enc->expected_ts));
957 if (GST_CLOCK_TIME_IS_VALID (duration))
958 enc->expected_ts = timestamp + duration;
960 enc->expected_ts = GST_CLOCK_TIME_NONE;
966 theora_enc_init_buffer (th_ycbcr_buffer buf, th_info * info, guint8 * data)
968 GstVideoFormat format;
971 switch (info->pixel_fmt) {
973 format = GST_VIDEO_FORMAT_Y444;
976 format = GST_VIDEO_FORMAT_I420;
979 format = GST_VIDEO_FORMAT_Y42B;
982 g_assert_not_reached ();
985 /* According to Theora developer Timothy Terriberry, the Theora
986 * encoder will not use memory outside of pic_width/height, even when
987 * the frame size is bigger. The values outside this region will be encoded
989 * Due to this, setting the frame's width/height as the buffer width/height
990 * is perfectly ok, even though it does not strictly look ok.
992 for (i = 0; i < 3; i++) {
994 gst_video_format_get_component_width (format, i, info->frame_width);
996 gst_video_format_get_component_height (format, i, info->frame_height);
999 data + gst_video_format_get_component_offset (format, i,
1000 info->pic_width, info->pic_height);
1002 gst_video_format_get_row_stride (format, i, info->pic_width);
1007 theora_enc_read_multipass_cache (GstTheoraEnc * enc)
1009 GstBuffer *cache_buf;
1010 const guint8 *cache_data;
1011 gsize bytes_read = 0, bytes_consumed = 0;
1012 GIOStatus stat = G_IO_STATUS_NORMAL;
1013 gboolean done = FALSE;
1016 if (gst_adapter_available (enc->multipass_cache_adapter) == 0) {
1017 cache_buf = gst_buffer_new_and_alloc (512);
1018 stat = g_io_channel_read_chars (enc->multipass_cache_fd,
1019 (gchar *) GST_BUFFER_DATA (cache_buf), GST_BUFFER_SIZE (cache_buf),
1022 if (bytes_read <= 0) {
1023 gst_buffer_unref (cache_buf);
1026 GST_BUFFER_SIZE (cache_buf) = bytes_read;
1028 gst_adapter_push (enc->multipass_cache_adapter, cache_buf);
1031 if (gst_adapter_available (enc->multipass_cache_adapter) == 0)
1035 MIN (gst_adapter_available (enc->multipass_cache_adapter), 512);
1037 cache_data = gst_adapter_peek (enc->multipass_cache_adapter, bytes_read);
1040 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data,
1042 done = bytes_consumed <= 0;
1043 if (bytes_consumed > 0)
1044 gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed);
1047 if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_EOF && bytes_read == 0)
1048 || bytes_consumed < 0) {
1049 GST_ELEMENT_ERROR (enc, RESOURCE, READ, (NULL),
1050 ("Failed to read multipass cache file"));
1057 theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin,
1061 GIOStatus stat = G_IO_STATUS_NORMAL;
1062 gint bytes_read = 0;
1063 gsize bytes_written = 0;
1067 stat = g_io_channel_seek_position (enc->multipass_cache_fd, 0, G_SEEK_SET,
1069 if (stat != G_IO_STATUS_ERROR) {
1072 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_OUT, &buf, sizeof (buf));
1074 g_io_channel_write_chars (enc->multipass_cache_fd, buf, bytes_read,
1075 &bytes_written, NULL);
1076 } while (bytes_read > 0 && bytes_written > 0);
1080 if (stat == G_IO_STATUS_ERROR || bytes_read < 0 || bytes_written < 0) {
1083 GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL),
1084 ("Failed to seek to beginning of multipass cache file: %s",
1087 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1088 ("Failed to seek to beginning of multipass cache file: %s",
1091 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1092 ("Failed to write multipass cache file"));
1102 static GstFlowReturn
1103 theora_enc_chain (GstPad * pad, GstBuffer * buffer)
1107 GstClockTime timestamp, duration, running_time;
1109 gboolean force_keyframe;
1111 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
1113 /* we keep track of two timelines.
1114 * - The timestamps from the incomming buffers, which we copy to the outgoing
1115 * encoded buffers as-is. We need to do this as we simply forward the
1116 * newsegment events.
1117 * - The running_time of the buffers, which we use to construct the granulepos
1120 timestamp = GST_BUFFER_TIMESTAMP (buffer);
1121 duration = GST_BUFFER_DURATION (buffer);
1124 gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
1125 if ((gint64) running_time < 0) {
1126 GST_DEBUG_OBJECT (enc, "Dropping buffer, timestamp: %" GST_TIME_FORMAT,
1127 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
1128 gst_buffer_unref (buffer);
1132 GST_OBJECT_LOCK (enc);
1133 if (enc->bitrate_changed) {
1134 long int bitrate = enc->video_bitrate;
1136 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
1138 enc->bitrate_changed = FALSE;
1141 if (enc->quality_changed) {
1142 long int quality = enc->video_quality;
1144 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
1146 enc->quality_changed = FALSE;
1149 /* see if we need to schedule a keyframe */
1150 force_keyframe = enc->force_keyframe;
1151 enc->force_keyframe = FALSE;
1152 GST_OBJECT_UNLOCK (enc);
1154 if (force_keyframe) {
1155 GstClockTime stream_time;
1158 stream_time = gst_segment_to_stream_time (&enc->segment,
1159 GST_FORMAT_TIME, timestamp);
1161 s = gst_structure_new ("GstForceKeyUnit",
1162 "timestamp", G_TYPE_UINT64, timestamp,
1163 "stream-time", G_TYPE_UINT64, stream_time,
1164 "running-time", G_TYPE_UINT64, running_time, NULL);
1166 theora_enc_force_keyframe (enc);
1168 gst_pad_push_event (enc->srcpad,
1169 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
1172 /* make sure we copy the discont flag to the next outgoing buffer when it's
1173 * set on the incomming buffer */
1174 if (GST_BUFFER_IS_DISCONT (buffer)) {
1175 enc->next_discont = TRUE;
1178 if (enc->packetno == 0) {
1179 /* no packets written yet, setup headers */
1182 GSList *buffers = NULL;
1185 enc->granulepos_offset = 0;
1186 enc->timestamp_offset = 0;
1188 GST_DEBUG_OBJECT (enc, "output headers");
1189 /* Theora streams begin with three headers; the initial header (with
1190 most of the codec setup parameters) which is mandated by the Ogg
1191 bitstream spec. The second header holds any comment fields. The
1192 third header holds the bitstream codebook. We merely need to
1193 make the headers, then pass them to libtheora one at a time;
1194 libtheora handles the additional Ogg bitstream constraints */
1196 /* create the remaining theora headers */
1197 th_comment_clear (&enc->comment);
1198 th_comment_init (&enc->comment);
1201 th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
1203 theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
1204 GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf);
1205 if (ret != GST_FLOW_OK) {
1206 goto header_buffer_alloc;
1208 buffers = g_slist_prepend (buffers, buf);
1211 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1212 g_slist_free (buffers);
1213 goto encoder_disabled;
1216 buffers = g_slist_reverse (buffers);
1218 /* mark buffers and put on caps */
1219 caps = gst_pad_get_caps (enc->srcpad);
1220 caps = theora_set_header_on_caps (caps, buffers);
1221 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
1222 gst_pad_set_caps (enc->srcpad, caps);
1224 g_slist_foreach (buffers, (GFunc) gst_buffer_set_caps, caps);
1226 gst_caps_unref (caps);
1228 /* push out the header buffers */
1230 buf = buffers->data;
1231 buffers = g_slist_delete_link (buffers, buffers);
1232 if ((ret = theora_push_buffer (enc, buf)) != GST_FLOW_OK) {
1233 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1234 g_slist_free (buffers);
1239 enc->granulepos_offset =
1240 gst_util_uint64_scale (running_time, enc->fps_n,
1241 GST_SECOND * enc->fps_d);
1242 enc->timestamp_offset = running_time;
1247 th_ycbcr_buffer ycbcr;
1250 theora_enc_init_buffer (ycbcr, &enc->info, GST_BUFFER_DATA (buffer));
1252 if (theora_enc_is_discontinuous (enc, running_time, duration)) {
1253 theora_enc_reset (enc);
1254 enc->granulepos_offset =
1255 gst_util_uint64_scale (running_time, enc->fps_n,
1256 GST_SECOND * enc->fps_d);
1257 enc->timestamp_offset = running_time;
1259 enc->next_discont = TRUE;
1262 if (enc->multipass_cache_fd
1263 && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
1264 if (!theora_enc_read_multipass_cache (enc)) {
1265 ret = GST_FLOW_ERROR;
1266 goto multipass_read_failed;
1270 res = th_encode_ycbcr_in (enc->encoder, ycbcr);
1271 /* none of the failure cases can happen here */
1272 g_assert (res == 0);
1274 if (enc->multipass_cache_fd
1275 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
1276 if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
1277 ret = GST_FLOW_ERROR;
1278 goto multipass_write_failed;
1283 while (th_encode_packetout (enc->encoder, 0, &op)) {
1284 GstClockTime next_time;
1286 next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
1289 theora_push_packet (enc, &op, timestamp, enc->next_ts,
1290 next_time - enc->next_ts);
1292 enc->next_ts = next_time;
1293 if (ret != GST_FLOW_OK)
1296 gst_buffer_unref (buffer);
1302 multipass_read_failed:
1304 gst_buffer_unref (buffer);
1307 multipass_write_failed:
1309 gst_buffer_unref (buffer);
1312 header_buffer_alloc:
1314 gst_buffer_unref (buffer);
1319 gst_buffer_unref (buffer);
1324 gst_buffer_unref (buffer);
1329 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1330 ("libtheora has been compiled with the encoder disabled"));
1331 gst_buffer_unref (buffer);
1332 return GST_FLOW_ERROR;
1336 static GstStateChangeReturn
1337 theora_enc_change_state (GstElement * element, GstStateChange transition)
1340 GstStateChangeReturn ret;
1342 enc = GST_THEORA_ENC (element);
1344 switch (transition) {
1345 case GST_STATE_CHANGE_NULL_TO_READY:
1347 case GST_STATE_CHANGE_READY_TO_PAUSED:
1348 GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state");
1349 th_info_init (&enc->info);
1350 th_comment_init (&enc->comment);
1352 enc->force_keyframe = FALSE;
1354 if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) {
1357 if (!enc->multipass_cache_file) {
1358 ret = GST_STATE_CHANGE_FAILURE;
1359 GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
1362 enc->multipass_cache_fd =
1363 g_io_channel_new_file (enc->multipass_cache_file,
1364 (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"),
1367 if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS)
1368 enc->multipass_cache_adapter = gst_adapter_new ();
1370 if (!enc->multipass_cache_fd) {
1371 ret = GST_STATE_CHANGE_FAILURE;
1372 GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL),
1373 ("Failed to open multipass cache file: %s", err->message));
1378 g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL);
1381 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1387 ret = parent_class->change_state (element, transition);
1389 switch (transition) {
1390 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1392 case GST_STATE_CHANGE_PAUSED_TO_READY:
1393 GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state");
1395 th_encode_free (enc->encoder);
1396 enc->encoder = NULL;
1398 th_comment_clear (&enc->comment);
1399 th_info_clear (&enc->info);
1401 theora_enc_clear (enc);
1402 enc->initialised = FALSE;
1404 case GST_STATE_CHANGE_READY_TO_NULL:
1414 theora_enc_set_property (GObject * object, guint prop_id,
1415 const GValue * value, GParamSpec * pspec)
1417 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1423 case PROP_KEYFRAME_THRESHOLD:
1424 case PROP_KEYFRAME_MINDISTANCE:
1425 case PROP_NOISE_SENSITIVITY:
1426 case PROP_SHARPNESS:
1427 /* kept for API compat, but ignored */
1430 GST_OBJECT_LOCK (enc);
1431 enc->video_bitrate = g_value_get_int (value) * 1000;
1432 enc->bitrate_changed = TRUE;
1433 GST_OBJECT_UNLOCK (enc);
1436 GST_OBJECT_LOCK (enc);
1437 if (GST_STATE (enc) >= GST_STATE_PAUSED && enc->video_bitrate > 0) {
1438 GST_WARNING_OBJECT (object, "Can't change from bitrate to quality mode"
1441 enc->video_quality = g_value_get_int (value);
1442 enc->video_bitrate = 0;
1443 enc->quality_changed = TRUE;
1445 GST_OBJECT_UNLOCK (enc);
1447 case PROP_KEYFRAME_AUTO:
1448 enc->keyframe_auto = g_value_get_boolean (value);
1450 case PROP_KEYFRAME_FREQ:
1451 enc->keyframe_freq = g_value_get_int (value);
1453 case PROP_KEYFRAME_FREQ_FORCE:
1454 enc->keyframe_force = g_value_get_int (value);
1456 case PROP_SPEEDLEVEL:
1457 enc->speed_level = g_value_get_int (value);
1459 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
1460 sizeof (enc->speed_level));
1463 case PROP_VP3_COMPATIBLE:
1464 enc->vp3_compatible = g_value_get_boolean (value);
1466 case PROP_DROP_FRAMES:
1467 enc->drop_frames = g_value_get_boolean (value);
1469 case PROP_CAP_OVERFLOW:
1470 enc->cap_overflow = g_value_get_boolean (value);
1472 case PROP_CAP_UNDERFLOW:
1473 enc->cap_underflow = g_value_get_boolean (value);
1475 case PROP_RATE_BUFFER:
1476 enc->rate_buffer = g_value_get_int (value);
1478 case PROP_MULTIPASS_CACHE_FILE:
1479 enc->multipass_cache_file = g_value_dup_string (value);
1481 case PROP_MULTIPASS_MODE:
1482 enc->multipass_mode = g_value_get_enum (value);
1485 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1491 theora_enc_get_property (GObject * object, guint prop_id,
1492 GValue * value, GParamSpec * pspec)
1494 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1498 g_value_set_boolean (value, TRUE);
1501 g_value_set_enum (value, BORDER_BLACK);
1504 GST_OBJECT_LOCK (enc);
1505 g_value_set_int (value, enc->video_bitrate / 1000);
1506 GST_OBJECT_UNLOCK (enc);
1509 GST_OBJECT_LOCK (enc);
1510 g_value_set_int (value, enc->video_quality);
1511 GST_OBJECT_UNLOCK (enc);
1514 g_value_set_boolean (value, TRUE);
1516 case PROP_KEYFRAME_AUTO:
1517 g_value_set_boolean (value, enc->keyframe_auto);
1519 case PROP_KEYFRAME_FREQ:
1520 g_value_set_int (value, enc->keyframe_freq);
1522 case PROP_KEYFRAME_FREQ_FORCE:
1523 g_value_set_int (value, enc->keyframe_force);
1525 case PROP_KEYFRAME_THRESHOLD:
1526 g_value_set_int (value, 80);
1528 case PROP_KEYFRAME_MINDISTANCE:
1529 g_value_set_int (value, 8);
1531 case PROP_NOISE_SENSITIVITY:
1532 g_value_set_int (value, 1);
1534 case PROP_SHARPNESS:
1535 g_value_set_int (value, 0);
1537 case PROP_SPEEDLEVEL:
1538 g_value_set_int (value, enc->speed_level);
1540 case PROP_VP3_COMPATIBLE:
1541 g_value_set_boolean (value, enc->vp3_compatible);
1543 case PROP_DROP_FRAMES:
1544 g_value_set_boolean (value, enc->drop_frames);
1546 case PROP_CAP_OVERFLOW:
1547 g_value_set_boolean (value, enc->cap_overflow);
1549 case PROP_CAP_UNDERFLOW:
1550 g_value_set_boolean (value, enc->cap_underflow);
1552 case PROP_RATE_BUFFER:
1553 g_value_set_int (value, enc->rate_buffer);
1555 case PROP_MULTIPASS_CACHE_FILE:
1556 g_value_set_string (value, enc->multipass_cache_file);
1558 case PROP_MULTIPASS_MODE:
1559 g_value_set_enum (value, enc->multipass_mode);
1562 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);