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 gst_buffer_fill (buf, 0, 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_get_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) {
1020 cache_buf = gst_buffer_new_and_alloc (512);
1022 data = gst_buffer_map (cache_buf, &size, NULL, GST_MAP_READ);
1023 stat = g_io_channel_read_chars (enc->multipass_cache_fd,
1024 (gchar *) data, size, &bytes_read, NULL);
1026 if (bytes_read <= 0) {
1027 gst_buffer_unmap (cache_buf, data, 0);
1028 gst_buffer_unref (cache_buf);
1031 gst_buffer_unmap (cache_buf, data, bytes_read);
1032 gst_adapter_push (enc->multipass_cache_adapter, cache_buf);
1035 if (gst_adapter_available (enc->multipass_cache_adapter) == 0)
1039 MIN (gst_adapter_available (enc->multipass_cache_adapter), 512);
1041 cache_data = gst_adapter_map (enc->multipass_cache_adapter, bytes_read);
1044 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data,
1046 gst_adapter_unmap (enc->multipass_cache_adapter, 0);
1048 done = bytes_consumed <= 0;
1049 if (bytes_consumed > 0)
1050 gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed);
1053 if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_EOF && bytes_read == 0)
1054 || bytes_consumed < 0) {
1055 GST_ELEMENT_ERROR (enc, RESOURCE, READ, (NULL),
1056 ("Failed to read multipass cache file"));
1063 theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin,
1067 GIOStatus stat = G_IO_STATUS_NORMAL;
1068 gint bytes_read = 0;
1069 gsize bytes_written = 0;
1073 stat = g_io_channel_seek_position (enc->multipass_cache_fd, 0, G_SEEK_SET,
1075 if (stat != G_IO_STATUS_ERROR) {
1078 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_OUT, &buf, sizeof (buf));
1080 g_io_channel_write_chars (enc->multipass_cache_fd, buf, bytes_read,
1081 &bytes_written, NULL);
1082 } while (bytes_read > 0 && bytes_written > 0);
1086 if (stat == G_IO_STATUS_ERROR || bytes_read < 0 || bytes_written < 0) {
1089 GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL),
1090 ("Failed to seek to beginning of multipass cache file: %s",
1093 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1094 ("Failed to seek to beginning of multipass cache file: %s",
1097 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1098 ("Failed to write multipass cache file"));
1108 static GstFlowReturn
1109 theora_enc_chain (GstPad * pad, GstBuffer * buffer)
1113 GstClockTime timestamp, duration, running_time;
1115 gboolean force_keyframe;
1117 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
1119 /* we keep track of two timelines.
1120 * - The timestamps from the incomming buffers, which we copy to the outgoing
1121 * encoded buffers as-is. We need to do this as we simply forward the
1122 * newsegment events.
1123 * - The running_time of the buffers, which we use to construct the granulepos
1126 timestamp = GST_BUFFER_TIMESTAMP (buffer);
1127 duration = GST_BUFFER_DURATION (buffer);
1130 gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
1131 if ((gint64) running_time < 0) {
1132 GST_DEBUG_OBJECT (enc, "Dropping buffer, timestamp: %" GST_TIME_FORMAT,
1133 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
1134 gst_buffer_unref (buffer);
1138 GST_OBJECT_LOCK (enc);
1139 if (enc->bitrate_changed) {
1140 long int bitrate = enc->video_bitrate;
1142 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
1144 enc->bitrate_changed = FALSE;
1147 if (enc->quality_changed) {
1148 long int quality = enc->video_quality;
1150 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
1152 enc->quality_changed = FALSE;
1155 /* see if we need to schedule a keyframe */
1156 force_keyframe = enc->force_keyframe;
1157 enc->force_keyframe = FALSE;
1158 GST_OBJECT_UNLOCK (enc);
1160 if (force_keyframe) {
1161 GstClockTime stream_time;
1164 stream_time = gst_segment_to_stream_time (&enc->segment,
1165 GST_FORMAT_TIME, timestamp);
1167 s = gst_structure_new ("GstForceKeyUnit",
1168 "timestamp", G_TYPE_UINT64, timestamp,
1169 "stream-time", G_TYPE_UINT64, stream_time,
1170 "running-time", G_TYPE_UINT64, running_time, NULL);
1172 theora_enc_force_keyframe (enc);
1174 gst_pad_push_event (enc->srcpad,
1175 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
1178 /* make sure we copy the discont flag to the next outgoing buffer when it's
1179 * set on the incomming buffer */
1180 if (GST_BUFFER_IS_DISCONT (buffer)) {
1181 enc->next_discont = TRUE;
1184 if (enc->packetno == 0) {
1185 /* no packets written yet, setup headers */
1188 GSList *buffers = NULL;
1191 enc->granulepos_offset = 0;
1192 enc->timestamp_offset = 0;
1194 GST_DEBUG_OBJECT (enc, "output headers");
1195 /* Theora streams begin with three headers; the initial header (with
1196 most of the codec setup parameters) which is mandated by the Ogg
1197 bitstream spec. The second header holds any comment fields. The
1198 third header holds the bitstream codebook. We merely need to
1199 make the headers, then pass them to libtheora one at a time;
1200 libtheora handles the additional Ogg bitstream constraints */
1202 /* create the remaining theora headers */
1203 th_comment_clear (&enc->comment);
1204 th_comment_init (&enc->comment);
1207 th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
1209 theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
1210 GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf);
1211 if (ret != GST_FLOW_OK) {
1212 goto header_buffer_alloc;
1214 buffers = g_slist_prepend (buffers, buf);
1217 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1218 g_slist_free (buffers);
1219 goto encoder_disabled;
1222 buffers = g_slist_reverse (buffers);
1224 /* mark buffers and put on caps */
1225 caps = gst_pad_get_caps (enc->srcpad);
1226 caps = theora_set_header_on_caps (caps, buffers);
1227 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
1228 gst_pad_set_caps (enc->srcpad, caps);
1230 g_slist_foreach (buffers, (GFunc) gst_buffer_set_caps, caps);
1232 gst_caps_unref (caps);
1234 /* push out the header buffers */
1236 buf = buffers->data;
1237 buffers = g_slist_delete_link (buffers, buffers);
1238 if ((ret = theora_push_buffer (enc, buf)) != GST_FLOW_OK) {
1239 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1240 g_slist_free (buffers);
1245 enc->granulepos_offset =
1246 gst_util_uint64_scale (running_time, enc->fps_n,
1247 GST_SECOND * enc->fps_d);
1248 enc->timestamp_offset = running_time;
1253 th_ycbcr_buffer ycbcr;
1258 data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
1259 theora_enc_init_buffer (ycbcr, &enc->info, data);
1261 if (theora_enc_is_discontinuous (enc, running_time, duration)) {
1262 theora_enc_reset (enc);
1263 enc->granulepos_offset =
1264 gst_util_uint64_scale (running_time, enc->fps_n,
1265 GST_SECOND * enc->fps_d);
1266 enc->timestamp_offset = running_time;
1268 enc->next_discont = TRUE;
1271 if (enc->multipass_cache_fd
1272 && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
1273 if (!theora_enc_read_multipass_cache (enc)) {
1274 gst_buffer_unmap (buffer, data, size);
1275 ret = GST_FLOW_ERROR;
1276 goto multipass_read_failed;
1280 res = th_encode_ycbcr_in (enc->encoder, ycbcr);
1281 /* none of the failure cases can happen here */
1282 g_assert (res == 0);
1284 if (enc->multipass_cache_fd
1285 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
1286 if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
1287 gst_buffer_unmap (buffer, data, size);
1288 ret = GST_FLOW_ERROR;
1289 goto multipass_write_failed;
1294 while (th_encode_packetout (enc->encoder, 0, &op)) {
1295 GstClockTime next_time;
1297 next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
1300 theora_push_packet (enc, &op, timestamp, enc->next_ts,
1301 next_time - enc->next_ts);
1303 enc->next_ts = next_time;
1304 if (ret != GST_FLOW_OK) {
1305 gst_buffer_unmap (buffer, data, size);
1309 gst_buffer_unmap (buffer, data, size);
1310 gst_buffer_unref (buffer);
1316 multipass_read_failed:
1318 gst_buffer_unref (buffer);
1321 multipass_write_failed:
1323 gst_buffer_unref (buffer);
1326 header_buffer_alloc:
1328 gst_buffer_unref (buffer);
1333 gst_buffer_unref (buffer);
1338 gst_buffer_unref (buffer);
1343 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1344 ("libtheora has been compiled with the encoder disabled"));
1345 gst_buffer_unref (buffer);
1346 return GST_FLOW_ERROR;
1350 static GstStateChangeReturn
1351 theora_enc_change_state (GstElement * element, GstStateChange transition)
1354 GstStateChangeReturn ret;
1356 enc = GST_THEORA_ENC (element);
1358 switch (transition) {
1359 case GST_STATE_CHANGE_NULL_TO_READY:
1361 case GST_STATE_CHANGE_READY_TO_PAUSED:
1362 GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state");
1363 th_info_init (&enc->info);
1364 th_comment_init (&enc->comment);
1366 enc->force_keyframe = FALSE;
1368 if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) {
1371 if (!enc->multipass_cache_file) {
1372 ret = GST_STATE_CHANGE_FAILURE;
1373 GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
1376 enc->multipass_cache_fd =
1377 g_io_channel_new_file (enc->multipass_cache_file,
1378 (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"),
1381 if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS)
1382 enc->multipass_cache_adapter = gst_adapter_new ();
1384 if (!enc->multipass_cache_fd) {
1385 ret = GST_STATE_CHANGE_FAILURE;
1386 GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL),
1387 ("Failed to open multipass cache file: %s", err->message));
1392 g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL);
1395 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1401 ret = parent_class->change_state (element, transition);
1403 switch (transition) {
1404 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1406 case GST_STATE_CHANGE_PAUSED_TO_READY:
1407 GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state");
1409 th_encode_free (enc->encoder);
1410 enc->encoder = NULL;
1412 th_comment_clear (&enc->comment);
1413 th_info_clear (&enc->info);
1415 theora_enc_clear (enc);
1416 enc->initialised = FALSE;
1418 case GST_STATE_CHANGE_READY_TO_NULL:
1428 theora_enc_set_property (GObject * object, guint prop_id,
1429 const GValue * value, GParamSpec * pspec)
1431 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1437 case PROP_KEYFRAME_THRESHOLD:
1438 case PROP_KEYFRAME_MINDISTANCE:
1439 case PROP_NOISE_SENSITIVITY:
1440 case PROP_SHARPNESS:
1441 /* kept for API compat, but ignored */
1444 GST_OBJECT_LOCK (enc);
1445 enc->video_bitrate = g_value_get_int (value) * 1000;
1446 enc->bitrate_changed = TRUE;
1447 GST_OBJECT_UNLOCK (enc);
1450 GST_OBJECT_LOCK (enc);
1451 if (GST_STATE (enc) >= GST_STATE_PAUSED && enc->video_bitrate > 0) {
1452 GST_WARNING_OBJECT (object, "Can't change from bitrate to quality mode"
1455 enc->video_quality = g_value_get_int (value);
1456 enc->video_bitrate = 0;
1457 enc->quality_changed = TRUE;
1459 GST_OBJECT_UNLOCK (enc);
1461 case PROP_KEYFRAME_AUTO:
1462 enc->keyframe_auto = g_value_get_boolean (value);
1464 case PROP_KEYFRAME_FREQ:
1465 enc->keyframe_freq = g_value_get_int (value);
1467 case PROP_KEYFRAME_FREQ_FORCE:
1468 enc->keyframe_force = g_value_get_int (value);
1470 case PROP_SPEEDLEVEL:
1471 enc->speed_level = g_value_get_int (value);
1473 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
1474 sizeof (enc->speed_level));
1477 case PROP_VP3_COMPATIBLE:
1478 enc->vp3_compatible = g_value_get_boolean (value);
1480 case PROP_DROP_FRAMES:
1481 enc->drop_frames = g_value_get_boolean (value);
1483 case PROP_CAP_OVERFLOW:
1484 enc->cap_overflow = g_value_get_boolean (value);
1486 case PROP_CAP_UNDERFLOW:
1487 enc->cap_underflow = g_value_get_boolean (value);
1489 case PROP_RATE_BUFFER:
1490 enc->rate_buffer = g_value_get_int (value);
1492 case PROP_MULTIPASS_CACHE_FILE:
1493 enc->multipass_cache_file = g_value_dup_string (value);
1495 case PROP_MULTIPASS_MODE:
1496 enc->multipass_mode = g_value_get_enum (value);
1499 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1505 theora_enc_get_property (GObject * object, guint prop_id,
1506 GValue * value, GParamSpec * pspec)
1508 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1512 g_value_set_boolean (value, TRUE);
1515 g_value_set_enum (value, BORDER_BLACK);
1518 GST_OBJECT_LOCK (enc);
1519 g_value_set_int (value, enc->video_bitrate / 1000);
1520 GST_OBJECT_UNLOCK (enc);
1523 GST_OBJECT_LOCK (enc);
1524 g_value_set_int (value, enc->video_quality);
1525 GST_OBJECT_UNLOCK (enc);
1528 g_value_set_boolean (value, TRUE);
1530 case PROP_KEYFRAME_AUTO:
1531 g_value_set_boolean (value, enc->keyframe_auto);
1533 case PROP_KEYFRAME_FREQ:
1534 g_value_set_int (value, enc->keyframe_freq);
1536 case PROP_KEYFRAME_FREQ_FORCE:
1537 g_value_set_int (value, enc->keyframe_force);
1539 case PROP_KEYFRAME_THRESHOLD:
1540 g_value_set_int (value, 80);
1542 case PROP_KEYFRAME_MINDISTANCE:
1543 g_value_set_int (value, 8);
1545 case PROP_NOISE_SENSITIVITY:
1546 g_value_set_int (value, 1);
1548 case PROP_SHARPNESS:
1549 g_value_set_int (value, 0);
1551 case PROP_SPEEDLEVEL:
1552 g_value_set_int (value, enc->speed_level);
1554 case PROP_VP3_COMPATIBLE:
1555 g_value_set_boolean (value, enc->vp3_compatible);
1557 case PROP_DROP_FRAMES:
1558 g_value_set_boolean (value, enc->drop_frames);
1560 case PROP_CAP_OVERFLOW:
1561 g_value_set_boolean (value, enc->cap_overflow);
1563 case PROP_CAP_UNDERFLOW:
1564 g_value_set_boolean (value, enc->cap_underflow);
1566 case PROP_RATE_BUFFER:
1567 g_value_set_int (value, enc->rate_buffer);
1569 case PROP_MULTIPASS_CACHE_FILE:
1570 g_value_set_string (value, enc->multipass_cache_file);
1572 case PROP_MULTIPASS_MODE:
1573 g_value_set_enum (value, enc->multipass_mode);
1576 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);