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>
65 #define GST_CAT_DEFAULT theoraenc_debug
66 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
68 #define GST_TYPE_BORDER_MODE (gst_border_mode_get_type())
70 gst_border_mode_get_type (void)
72 static GType border_mode_type = 0;
73 static const GEnumValue border_mode[] = {
74 {BORDER_NONE, "No Border", "none"},
75 {BORDER_BLACK, "Black Border", "black"},
76 {BORDER_MIRROR, "Mirror image in borders", "mirror"},
80 if (!border_mode_type) {
82 g_enum_register_static ("GstTheoraEncBorderMode", border_mode);
84 return border_mode_type;
87 #define GST_TYPE_MULTIPASS_MODE (gst_multipass_mode_get_type())
89 gst_multipass_mode_get_type (void)
91 static GType multipass_mode_type = 0;
92 static const GEnumValue multipass_mode[] = {
93 {MULTIPASS_MODE_SINGLE_PASS, "Single pass", "single-pass"},
94 {MULTIPASS_MODE_FIRST_PASS, "First pass", "first-pass"},
95 {MULTIPASS_MODE_SECOND_PASS, "Second pass", "second-pass"},
99 if (!multipass_mode_type) {
100 multipass_mode_type =
101 g_enum_register_static ("GstTheoraEncMultipassMode", multipass_mode);
103 return multipass_mode_type;
106 /* taken from theora/lib/toplevel.c */
108 _ilog (unsigned int v)
119 #define THEORA_DEF_BITRATE 0
120 #define THEORA_DEF_QUALITY 48
121 #define THEORA_DEF_KEYFRAME_AUTO TRUE
122 #define THEORA_DEF_KEYFRAME_FREQ 64
123 #define THEORA_DEF_KEYFRAME_FREQ_FORCE 64
124 #define THEORA_DEF_SPEEDLEVEL 1
125 #define THEORA_DEF_VP3_COMPATIBLE FALSE
126 #define THEORA_DEF_DROP_FRAMES TRUE
127 #define THEORA_DEF_CAP_OVERFLOW TRUE
128 #define THEORA_DEF_CAP_UNDERFLOW FALSE
129 #define THEORA_DEF_RATE_BUFFER 0
130 #define THEORA_DEF_MULTIPASS_CACHE_FILE NULL
131 #define THEORA_DEF_MULTIPASS_MODE MULTIPASS_MODE_SINGLE_PASS
142 PROP_KEYFRAME_FREQ_FORCE,
143 PROP_KEYFRAME_THRESHOLD,
144 PROP_KEYFRAME_MINDISTANCE,
145 PROP_NOISE_SENSITIVITY,
153 PROP_MULTIPASS_CACHE_FILE,
158 /* this function does a straight granulepos -> timestamp conversion */
160 granulepos_to_timestamp (GstTheoraEnc * theoraenc, ogg_int64_t granulepos)
162 guint64 iframe, pframe;
163 int shift = theoraenc->info.keyframe_granule_shift;
166 return GST_CLOCK_TIME_NONE;
168 iframe = granulepos >> shift;
169 pframe = granulepos - (iframe << shift);
171 /* num and den are 32 bit, so we can safely multiply with GST_SECOND */
172 return gst_util_uint64_scale ((guint64) (iframe + pframe),
173 GST_SECOND * theoraenc->info.fps_denominator,
174 theoraenc->info.fps_numerator);
177 /* Generate a dummy encoder context for use in th_encode_ctl queries
178 Release with th_encode_free()
179 This and the next routine from theora/examples/libtheora_info.c */
181 dummy_encode_ctx (void)
186 /* set the minimal video parameters */
187 th_info_init (&info);
188 info.frame_width = 320;
189 info.frame_height = 240;
190 info.fps_numerator = 1;
191 info.fps_denominator = 1;
193 /* allocate and initialize a context object */
194 ctx = th_encode_alloc (&info);
196 GST_WARNING ("Failed to allocate dummy encoder context.");
198 /* clear the info struct */
199 th_info_clear (&info);
204 /* Query the current and maximum values for the 'speed level' setting.
205 This can be used to ask the encoder to trade off encoding quality
206 vs. performance cost, for example to adapt to realtime constraints. */
208 check_speed_level (th_enc_ctx * ctx, int *current, int *max)
212 /* query the current speed level */
213 ret = th_encode_ctl (ctx, TH_ENCCTL_GET_SPLEVEL, current, sizeof (int));
215 GST_WARNING ("Error %d getting current speed level.", ret);
218 /* query the maximum speed level, which varies by encoder version */
219 ret = th_encode_ctl (ctx, TH_ENCCTL_GET_SPLEVEL_MAX, max, sizeof (int));
221 GST_WARNING ("Error %d getting maximum speed level.", ret);
228 static GstStaticPadTemplate theora_enc_sink_factory =
229 GST_STATIC_PAD_TEMPLATE ("sink",
232 GST_STATIC_CAPS ("video/x-raw, "
233 "format = (string) { I420, Y42B, Y444 }, "
234 "framerate = (fraction) [1/MAX, MAX], "
235 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
238 static GstStaticPadTemplate theora_enc_src_factory =
239 GST_STATIC_PAD_TEMPLATE ("src",
242 GST_STATIC_CAPS ("video/x-theora")
245 #define gst_theora_enc_parent_class parent_class
246 G_DEFINE_TYPE_WITH_CODE (GstTheoraEnc, gst_theora_enc,
247 GST_TYPE_ELEMENT, G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
249 static GstCaps *theora_enc_src_caps;
251 static gboolean theora_enc_sink_event (GstPad * pad, GstObject * parent,
253 static gboolean theora_enc_src_event (GstPad * pad, GstObject * parent,
255 static GstFlowReturn theora_enc_chain (GstPad * pad, GstObject * parent,
257 static GstStateChangeReturn theora_enc_change_state (GstElement * element,
258 GstStateChange transition);
259 static gboolean theora_enc_sink_query (GstPad * pad, GstObject * parent,
261 static gboolean theora_enc_sink_setcaps (GstTheoraEnc * enc, GstCaps * caps);
262 static void theora_enc_get_property (GObject * object, guint prop_id,
263 GValue * value, GParamSpec * pspec);
264 static void theora_enc_set_property (GObject * object, guint prop_id,
265 const GValue * value, GParamSpec * pspec);
266 static void theora_enc_finalize (GObject * object);
268 static gboolean theora_enc_write_multipass_cache (GstTheoraEnc * enc,
269 gboolean begin, gboolean eos);
271 static char *theora_enc_get_supported_formats (void);
274 gst_theora_enc_class_init (GstTheoraEncClass * klass)
276 GObjectClass *gobject_class = (GObjectClass *) klass;
277 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
280 /* query runtime encoder properties */
282 int default_speed_level = THEORA_DEF_SPEEDLEVEL;
283 int max_speed_level = default_speed_level;
285 GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
287 th_ctx = dummy_encode_ctx ();
289 if (check_speed_level (th_ctx, &default_speed_level, &max_speed_level))
291 ("Failed to determine settings for the speed-level property.");
292 th_encode_free (th_ctx);
295 gobject_class->set_property = theora_enc_set_property;
296 gobject_class->get_property = theora_enc_get_property;
297 gobject_class->finalize = theora_enc_finalize;
299 g_object_class_install_property (gobject_class, PROP_CENTER,
300 g_param_spec_boolean ("center", "Center",
301 "ignored and kept for API compat only", TRUE,
302 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
303 g_object_class_install_property (gobject_class, PROP_BORDER,
304 g_param_spec_enum ("border", "Border",
305 "ignored and kept for API compat only",
306 GST_TYPE_BORDER_MODE, BORDER_BLACK,
307 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
308 /* general encoding stream options */
309 g_object_class_install_property (gobject_class, PROP_BITRATE,
310 g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
311 0, (1 << 24) - 1, THEORA_DEF_BITRATE,
312 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
313 GST_PARAM_MUTABLE_PLAYING));
314 g_object_class_install_property (gobject_class, PROP_QUALITY,
315 g_param_spec_int ("quality", "Quality", "Video quality", 0, 63,
317 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
318 GST_PARAM_MUTABLE_PLAYING));
319 g_object_class_install_property (gobject_class, PROP_QUICK,
320 g_param_spec_boolean ("quick", "Quick",
321 "ignored and kept for API compat only", TRUE,
322 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
323 g_object_class_install_property (gobject_class, PROP_KEYFRAME_AUTO,
324 g_param_spec_boolean ("keyframe-auto", "Keyframe Auto",
325 "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO,
326 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
327 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ,
328 g_param_spec_int ("keyframe-freq", "Keyframe frequency",
329 "Keyframe frequency", 1, 32768, THEORA_DEF_KEYFRAME_FREQ,
330 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
331 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ_FORCE,
332 g_param_spec_int ("keyframe-force", "Keyframe force",
333 "Force keyframe every N frames", 1, 32768,
334 THEORA_DEF_KEYFRAME_FREQ_FORCE,
335 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
336 g_object_class_install_property (gobject_class, PROP_KEYFRAME_THRESHOLD,
337 g_param_spec_int ("keyframe-threshold", "Keyframe threshold",
338 "ignored and kept for API compat only", 0, 32768, 80,
339 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
340 g_object_class_install_property (gobject_class, PROP_KEYFRAME_MINDISTANCE,
341 g_param_spec_int ("keyframe-mindistance", "Keyframe mindistance",
342 "ignored and kept for API compat only", 1, 32768, 8,
343 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
344 g_object_class_install_property (gobject_class, PROP_NOISE_SENSITIVITY,
345 g_param_spec_int ("noise-sensitivity", "Noise sensitivity",
346 "ignored and kept for API compat only", 0, 32768, 1,
347 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
348 g_object_class_install_property (gobject_class, PROP_SHARPNESS,
349 g_param_spec_int ("sharpness", "Sharpness",
350 "ignored and kept for API compat only", 0, 2, 0,
351 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
352 g_object_class_install_property (gobject_class, PROP_SPEEDLEVEL,
353 g_param_spec_int ("speed-level", "Speed level",
354 "Controls the amount of analysis performed when encoding."
355 " Higher values trade compression quality for speed."
356 " This property requires libtheora version >= 1.0"
357 ", and the maximum value may vary based on encoder version.",
358 0, max_speed_level, default_speed_level,
359 (GParamFlags) G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
360 G_PARAM_STATIC_STRINGS));
361 g_object_class_install_property (gobject_class, PROP_VP3_COMPATIBLE,
362 g_param_spec_boolean ("vp3-compatible", "VP3 Compatible",
363 "Disables non-VP3 compatible features",
364 THEORA_DEF_VP3_COMPATIBLE,
365 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
366 g_object_class_install_property (gobject_class, PROP_DROP_FRAMES,
367 g_param_spec_boolean ("drop-frames", "Drop Frames",
368 "Allow or disallow frame dropping",
369 THEORA_DEF_DROP_FRAMES,
370 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
371 g_object_class_install_property (gobject_class, PROP_CAP_OVERFLOW,
372 g_param_spec_boolean ("cap-overflow", "Cap Overflow",
373 "Enable capping of bit reservoir overflows",
374 THEORA_DEF_CAP_OVERFLOW,
375 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
376 g_object_class_install_property (gobject_class, PROP_CAP_UNDERFLOW,
377 g_param_spec_boolean ("cap-underflow", "Cap Underflow",
378 "Enable capping of bit reservoir underflows",
379 THEORA_DEF_CAP_UNDERFLOW,
380 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
381 g_object_class_install_property (gobject_class, PROP_RATE_BUFFER,
382 g_param_spec_int ("rate-buffer", "Rate Control Buffer",
383 "Sets the size of the rate control buffer, in units of frames. "
384 "The default value of 0 instructs the encoder to automatically "
385 "select an appropriate value",
386 0, 1000, THEORA_DEF_RATE_BUFFER,
387 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
388 g_object_class_install_property (gobject_class, PROP_MULTIPASS_CACHE_FILE,
389 g_param_spec_string ("multipass-cache-file", "Multipass Cache File",
390 "Multipass cache file", THEORA_DEF_MULTIPASS_CACHE_FILE,
391 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
392 g_object_class_install_property (gobject_class, PROP_MULTIPASS_MODE,
393 g_param_spec_enum ("multipass-mode", "Multipass mode",
394 "Single pass or first/second pass", GST_TYPE_MULTIPASS_MODE,
395 THEORA_DEF_MULTIPASS_MODE,
396 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
398 gst_element_class_add_pad_template (gstelement_class,
399 gst_static_pad_template_get (&theora_enc_src_factory));
400 gst_element_class_add_pad_template (gstelement_class,
401 gst_static_pad_template_get (&theora_enc_sink_factory));
402 gst_element_class_set_details_simple (gstelement_class,
403 "Theora video encoder", "Codec/Encoder/Video",
404 "encode raw YUV video to a theora stream",
405 "Wim Taymans <wim@fluendo.com>");
407 caps_string = g_strdup_printf ("video/x-raw, "
408 "format = (string) { %s }, "
409 "framerate = (fraction) [1/MAX, MAX], "
410 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]",
411 theora_enc_get_supported_formats ());
412 theora_enc_src_caps = gst_caps_from_string (caps_string);
413 g_free (caps_string);
415 gstelement_class->change_state = theora_enc_change_state;
419 gst_theora_enc_init (GstTheoraEnc * enc)
422 gst_pad_new_from_static_template (&theora_enc_sink_factory, "sink");
423 gst_pad_set_chain_function (enc->sinkpad, theora_enc_chain);
424 gst_pad_set_event_function (enc->sinkpad, theora_enc_sink_event);
425 gst_pad_set_query_function (enc->sinkpad, theora_enc_sink_query);
426 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
429 gst_pad_new_from_static_template (&theora_enc_src_factory, "src");
430 gst_pad_set_event_function (enc->srcpad, theora_enc_src_event);
431 gst_pad_use_fixed_caps (enc->srcpad);
432 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
434 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
436 enc->video_bitrate = THEORA_DEF_BITRATE;
437 enc->video_quality = THEORA_DEF_QUALITY;
438 enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
439 enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ;
440 enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE;
442 enc->expected_ts = GST_CLOCK_TIME_NONE;
444 /* enc->speed_level is set to the libtheora default by the constructor */
445 enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE;
446 enc->drop_frames = THEORA_DEF_DROP_FRAMES;
447 enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW;
448 enc->cap_underflow = THEORA_DEF_CAP_UNDERFLOW;
449 enc->rate_buffer = THEORA_DEF_RATE_BUFFER;
451 enc->multipass_mode = THEORA_DEF_MULTIPASS_MODE;
452 enc->multipass_cache_file = THEORA_DEF_MULTIPASS_CACHE_FILE;
456 theora_enc_clear_multipass_cache (GstTheoraEnc * enc)
458 if (enc->multipass_cache_fd) {
459 g_io_channel_shutdown (enc->multipass_cache_fd, TRUE, NULL);
460 g_io_channel_unref (enc->multipass_cache_fd);
461 enc->multipass_cache_fd = NULL;
464 if (enc->multipass_cache_adapter) {
465 gst_object_unref (enc->multipass_cache_adapter);
466 enc->multipass_cache_adapter = NULL;
471 theora_enc_finalize (GObject * object)
473 GstTheoraEnc *enc = GST_THEORA_ENC (object);
475 GST_DEBUG_OBJECT (enc, "Finalizing");
477 th_encode_free (enc->encoder);
478 th_comment_clear (&enc->comment);
479 th_info_clear (&enc->info);
480 g_free (enc->multipass_cache_file);
482 theora_enc_clear_multipass_cache (enc);
484 G_OBJECT_CLASS (parent_class)->finalize (object);
488 theora_enc_reset (GstTheoraEnc * enc)
490 ogg_uint32_t keyframe_force;
493 GST_OBJECT_LOCK (enc);
494 enc->info.target_bitrate = enc->video_bitrate;
495 if (enc->quality_changed) {
496 enc->info.quality = enc->video_quality;
498 if (enc->video_bitrate == 0) {
499 enc->info.quality = enc->video_quality;
502 enc->bitrate_changed = FALSE;
503 enc->quality_changed = FALSE;
504 GST_OBJECT_UNLOCK (enc);
507 th_encode_free (enc->encoder);
508 enc->encoder = th_encode_alloc (&enc->info);
509 /* We ensure this function cannot fail. */
510 g_assert (enc->encoder != NULL);
511 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
512 sizeof (enc->speed_level));
513 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_VP3_COMPATIBLE,
514 &enc->vp3_compatible, sizeof (enc->vp3_compatible));
517 if (enc->drop_frames)
518 rate_flags |= TH_RATECTL_DROP_FRAMES;
519 if (enc->drop_frames)
520 rate_flags |= TH_RATECTL_CAP_OVERFLOW;
521 if (enc->drop_frames)
522 rate_flags |= TH_RATECTL_CAP_UNDERFLOW;
523 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_FLAGS,
524 &rate_flags, sizeof (rate_flags));
526 if (enc->rate_buffer) {
527 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_BUFFER,
528 &enc->rate_buffer, sizeof (enc->rate_buffer));
533 keyframe_force = enc->keyframe_auto ?
534 enc->keyframe_force : enc->keyframe_freq;
535 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
536 &keyframe_force, sizeof (keyframe_force));
538 /* Get placeholder data */
539 if (enc->multipass_cache_fd
540 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
541 theora_enc_write_multipass_cache (enc, TRUE, FALSE);
545 theora_enc_clear (GstTheoraEnc * enc)
549 enc->granulepos_offset = 0;
550 enc->timestamp_offset = 0;
552 enc->next_ts = GST_CLOCK_TIME_NONE;
553 enc->next_discont = FALSE;
554 enc->expected_ts = GST_CLOCK_TIME_NONE;
558 theora_enc_get_supported_formats (void)
564 th_pixel_fmt pixelformat;
568 TH_PF_420, "I420"}, {
569 TH_PF_422, "Y42B"}, {
572 GString *string = NULL;
575 th_info_init (&info);
576 info.frame_width = 16;
577 info.frame_height = 16;
578 info.fps_numerator = 25;
579 info.fps_denominator = 1;
580 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
581 info.pixel_fmt = formats[i].pixelformat;
583 encoder = th_encode_alloc (&info);
587 GST_LOG ("format %s is supported", formats[i].fourcc);
588 th_encode_free (encoder);
590 if (string == NULL) {
591 string = g_string_new (formats[i].fourcc);
593 g_string_append (string, ", ");
594 g_string_append (string, formats[i].fourcc);
597 th_info_clear (&info);
599 return string == NULL ? NULL : g_string_free (string, FALSE);
603 theora_enc_sink_getcaps (GstPad * pad, GstCaps * filter)
605 GstTheoraEnc *encoder;
609 /* If we already have caps return them */
610 if ((caps = gst_pad_get_current_caps (pad)) != NULL)
613 encoder = GST_THEORA_ENC (gst_pad_get_parent (pad));
615 return gst_caps_new_empty ();
617 peer = gst_pad_get_peer (encoder->srcpad);
619 const GstCaps *templ_caps;
620 GstCaps *peer_caps, *tmp_caps;
624 peer_caps = gst_pad_query_caps (peer, NULL);
626 /* Translate peercaps to YUV */
627 peer_caps = gst_caps_make_writable (peer_caps);
628 n = gst_caps_get_size (peer_caps);
629 for (i = 0; i < n; i++) {
630 s = gst_caps_get_structure (peer_caps, i);
632 gst_structure_set_name (s, "video/x-raw");
633 gst_structure_remove_field (s, "streamheader");
636 templ_caps = gst_pad_get_pad_template_caps (pad);
638 tmp_caps = gst_caps_intersect (peer_caps, templ_caps);
639 caps = gst_caps_intersect (tmp_caps, theora_enc_src_caps);
640 gst_caps_unref (tmp_caps);
641 gst_caps_unref (peer_caps);
642 gst_object_unref (peer);
645 caps = gst_caps_ref (theora_enc_src_caps);
648 gst_object_unref (encoder);
651 GstCaps *intersection;
654 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
655 gst_caps_unref (caps);
663 theora_enc_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
665 gboolean res = FALSE;
667 switch (GST_QUERY_TYPE (query)) {
670 GstCaps *filter, *caps;
672 gst_query_parse_caps (query, &filter);
673 caps = theora_enc_sink_getcaps (pad, filter);
674 gst_query_set_caps_result (query, caps);
675 gst_caps_unref (caps);
680 res = gst_pad_query_default (pad, parent, query);
688 theora_enc_sink_setcaps (GstTheoraEnc * enc, GstCaps * caps)
692 th_info_clear (&enc->info);
693 th_info_init (&enc->info);
695 if (!gst_video_info_from_caps (&info, caps))
700 /* Theora has a divisible-by-sixteen restriction for the encoded video size but
701 * we can define a picture area using pic_width/pic_height */
702 enc->info.frame_width = GST_ROUND_UP_16 (info.width);
703 enc->info.frame_height = GST_ROUND_UP_16 (info.height);
704 enc->info.pic_width = info.width;
705 enc->info.pic_height = info.height;
707 switch (GST_VIDEO_INFO_FORMAT (&info)) {
708 case GST_VIDEO_FORMAT_I420:
709 enc->info.pixel_fmt = TH_PF_420;
711 case GST_VIDEO_FORMAT_Y42B:
712 enc->info.pixel_fmt = TH_PF_422;
714 case GST_VIDEO_FORMAT_Y444:
715 enc->info.pixel_fmt = TH_PF_444;
718 g_assert_not_reached ();
721 enc->info.fps_numerator = info.fps_n;
722 enc->info.fps_denominator = info.fps_d;
724 enc->info.aspect_numerator = info.par_n;
725 enc->info.aspect_denominator = info.par_d;
727 /* setting them to 0 indicates that the decoder can chose a good aspect
728 * ratio, defaulting to 1/1 */
729 enc->info.aspect_numerator = 0;
731 enc->info.aspect_denominator = 0;
735 enc->info.colorspace = TH_CS_UNSPECIFIED;
737 /* as done in theora */
738 enc->info.keyframe_granule_shift = _ilog (enc->keyframe_force - 1);
739 GST_DEBUG_OBJECT (enc,
740 "keyframe_frequency_force is %d, granule shift is %d",
741 enc->keyframe_force, enc->info.keyframe_granule_shift);
743 theora_enc_reset (enc);
744 enc->initialised = TRUE;
751 GST_DEBUG_OBJECT (enc, "could not parse caps");
757 granulepos_add (guint64 granulepos, guint64 addend, gint shift)
759 guint64 iframe, pframe;
761 iframe = granulepos >> shift;
762 pframe = granulepos - (iframe << shift);
765 return (iframe << shift) + pframe;
768 /* prepare a buffer for transmission by passing data through libtheora */
770 theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
771 GstClockTime timestamp, GstClockTime running_time,
772 GstClockTime duration, GstBuffer ** buffer)
775 GstFlowReturn ret = GST_FLOW_OK;
777 buf = gst_buffer_new_and_alloc (packet->bytes);
779 GST_WARNING_OBJECT (enc, "Could not allocate buffer");
780 ret = GST_FLOW_ERROR;
784 gst_buffer_fill (buf, 0, packet->packet, packet->bytes);
785 /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
786 * time representation */
787 GST_BUFFER_OFFSET_END (buf) =
788 granulepos_add (packet->granulepos, enc->granulepos_offset,
789 enc->info.keyframe_granule_shift);
790 GST_BUFFER_OFFSET (buf) = granulepos_to_timestamp (enc,
791 GST_BUFFER_OFFSET_END (buf));
793 GST_BUFFER_TIMESTAMP (buf) = timestamp;
794 GST_BUFFER_DURATION (buf) = duration;
796 if (enc->next_discont) {
797 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
798 enc->next_discont = FALSE;
801 /* th_packet_iskeyframe returns positive for keyframes */
802 if (th_packet_iskeyframe (packet) > 0) {
803 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
805 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
814 /* push out the buffer and do internal bookkeeping */
816 theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
820 enc->bytes_out += gst_buffer_get_size (buffer);
822 ret = gst_pad_push (enc->srcpad, buffer);
828 theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet,
829 GstClockTime timestamp, GstClockTime running_time, GstClockTime duration)
835 theora_buffer_from_packet (enc, packet, timestamp, running_time, duration,
837 if (ret == GST_FLOW_OK)
838 ret = theora_push_buffer (enc, buf);
844 theora_set_header_on_caps (GstCaps * caps, GSList * buffers)
846 GstStructure *structure;
847 GValue array = { 0 };
848 GValue value = { 0 };
852 caps = gst_caps_make_writable (caps);
853 structure = gst_caps_get_structure (caps, 0);
855 /* put copies of the buffers in a fixed list */
856 g_value_init (&array, GST_TYPE_ARRAY);
858 for (walk = buffers; walk; walk = walk->next) {
862 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
864 /* Copy buffer, because we can't use the original -
865 * it creates a circular refcount with the caps<->buffers */
866 buffer = gst_buffer_copy (buffer);
868 g_value_init (&value, GST_TYPE_BUFFER);
869 gst_value_set_buffer (&value, buffer);
870 gst_value_array_append_value (&array, &value);
871 g_value_unset (&value);
874 gst_buffer_unref (buffer);
877 gst_structure_set_value (structure, "streamheader", &array);
878 g_value_unset (&array);
884 theora_enc_force_keyframe (GstTheoraEnc * enc)
886 GstClockTime next_ts;
888 /* make sure timestamps increment after resetting the decoder */
889 next_ts = enc->next_ts + enc->timestamp_offset;
891 theora_enc_reset (enc);
892 enc->granulepos_offset =
893 gst_util_uint64_scale (next_ts, enc->vinfo.fps_n,
894 GST_SECOND * enc->vinfo.fps_d);
895 enc->timestamp_offset = next_ts;
900 theora_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
906 enc = GST_THEORA_ENC (parent);
908 switch (GST_EVENT_TYPE (event)) {
913 gst_event_parse_caps (event, &caps);
914 res = theora_enc_sink_setcaps (enc, caps);
915 gst_event_unref (event);
918 case GST_EVENT_SEGMENT:
920 gst_event_copy_segment (event, &enc->segment);
922 res = gst_pad_push_event (enc->srcpad, event);
926 if (enc->initialised) {
927 /* push last packet with eos flag, should not be called */
928 while (th_encode_packetout (enc->encoder, 1, &op)) {
929 GstClockTime next_time =
930 th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
932 theora_push_packet (enc, &op, GST_CLOCK_TIME_NONE, enc->next_ts,
933 next_time - enc->next_ts);
934 enc->next_ts = next_time;
937 if (enc->initialised && enc->multipass_cache_fd
938 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
939 theora_enc_write_multipass_cache (enc, TRUE, TRUE);
941 theora_enc_clear_multipass_cache (enc);
943 res = gst_pad_push_event (enc->srcpad, event);
945 case GST_EVENT_FLUSH_STOP:
946 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
947 res = gst_pad_push_event (enc->srcpad, event);
949 case GST_EVENT_CUSTOM_DOWNSTREAM:
951 const GstStructure *s;
953 s = gst_event_get_structure (event);
955 if (gst_structure_has_name (s, "GstForceKeyUnit"))
956 theora_enc_force_keyframe (enc);
957 res = gst_pad_push_event (enc->srcpad, event);
961 res = gst_pad_push_event (enc->srcpad, event);
968 theora_enc_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
973 enc = GST_THEORA_ENC (parent);
975 switch (GST_EVENT_TYPE (event)) {
976 case GST_EVENT_CUSTOM_UPSTREAM:
978 const GstStructure *s;
980 s = gst_event_get_structure (event);
982 if (gst_structure_has_name (s, "GstForceKeyUnit")) {
983 GST_OBJECT_LOCK (enc);
984 enc->force_keyframe = TRUE;
985 GST_OBJECT_UNLOCK (enc);
986 /* consume the event */
988 gst_event_unref (event);
990 res = gst_pad_push_event (enc->sinkpad, event);
995 res = gst_pad_push_event (enc->sinkpad, event);
1003 theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp,
1004 GstClockTime duration)
1006 GstClockTimeDiff max_diff;
1007 gboolean ret = FALSE;
1009 /* Allow 3/4 a frame off */
1010 max_diff = (enc->info.fps_denominator * GST_SECOND * 3) /
1011 (enc->info.fps_numerator * 4);
1013 if (timestamp != GST_CLOCK_TIME_NONE
1014 && enc->expected_ts != GST_CLOCK_TIME_NONE) {
1015 if ((GstClockTimeDiff) (timestamp - enc->expected_ts) > max_diff) {
1016 GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT
1017 " exceeds expected value %" GST_TIME_FORMAT
1018 " by too much, marking discontinuity",
1019 GST_TIME_ARGS (timestamp), GST_TIME_ARGS (enc->expected_ts));
1024 if (GST_CLOCK_TIME_IS_VALID (duration))
1025 enc->expected_ts = timestamp + duration;
1027 enc->expected_ts = GST_CLOCK_TIME_NONE;
1033 theora_enc_init_buffer (th_ycbcr_buffer buf, GstVideoFrame * frame)
1037 /* According to Theora developer Timothy Terriberry, the Theora
1038 * encoder will not use memory outside of pic_width/height, even when
1039 * the frame size is bigger. The values outside this region will be encoded
1040 * to default values.
1041 * Due to this, setting the frame's width/height as the buffer width/height
1042 * is perfectly ok, even though it does not strictly look ok.
1044 for (i = 0; i < 3; i++) {
1045 buf[i].width = GST_VIDEO_FRAME_COMP_WIDTH (frame, i);
1046 buf[i].height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, i);
1047 buf[i].data = GST_VIDEO_FRAME_COMP_DATA (frame, i);
1048 buf[i].stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
1053 theora_enc_read_multipass_cache (GstTheoraEnc * enc)
1055 GstBuffer *cache_buf;
1056 const guint8 *cache_data;
1057 gsize bytes_read = 0;
1058 gint bytes_consumed = 0;
1059 GIOStatus stat = G_IO_STATUS_NORMAL;
1060 gboolean done = FALSE;
1063 if (gst_adapter_available (enc->multipass_cache_adapter) == 0) {
1067 cache_buf = gst_buffer_new_and_alloc (512);
1069 data = gst_buffer_map (cache_buf, &size, NULL, GST_MAP_READ);
1070 stat = g_io_channel_read_chars (enc->multipass_cache_fd,
1071 (gchar *) data, size, &bytes_read, NULL);
1073 if (bytes_read <= 0) {
1074 gst_buffer_unmap (cache_buf, data, 0);
1075 gst_buffer_unref (cache_buf);
1078 gst_buffer_unmap (cache_buf, data, bytes_read);
1079 gst_adapter_push (enc->multipass_cache_adapter, cache_buf);
1082 if (gst_adapter_available (enc->multipass_cache_adapter) == 0)
1086 MIN (gst_adapter_available (enc->multipass_cache_adapter), 512);
1088 cache_data = gst_adapter_map (enc->multipass_cache_adapter, bytes_read);
1091 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data,
1093 gst_adapter_unmap (enc->multipass_cache_adapter);
1095 done = bytes_consumed <= 0;
1096 if (bytes_consumed > 0)
1097 gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed);
1100 if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_EOF && bytes_read == 0)
1101 || bytes_consumed < 0) {
1102 GST_ELEMENT_ERROR (enc, RESOURCE, READ, (NULL),
1103 ("Failed to read multipass cache file"));
1110 theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin,
1114 GIOStatus stat = G_IO_STATUS_NORMAL;
1115 gint bytes_read = 0;
1116 gsize bytes_written = 0;
1120 stat = g_io_channel_seek_position (enc->multipass_cache_fd, 0, G_SEEK_SET,
1122 if (stat != G_IO_STATUS_ERROR) {
1125 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_OUT, &buf, sizeof (buf));
1127 g_io_channel_write_chars (enc->multipass_cache_fd, buf, bytes_read,
1128 &bytes_written, NULL);
1129 } while (bytes_read > 0 && bytes_written > 0);
1133 if (stat == G_IO_STATUS_ERROR || bytes_read < 0) {
1136 GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL),
1137 ("Failed to seek to beginning of multipass cache file: %s",
1140 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1141 ("Failed to seek to beginning of multipass cache file: %s",
1144 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1145 ("Failed to write multipass cache file"));
1155 static GstFlowReturn
1156 theora_enc_encode_and_push (GstTheoraEnc * enc, ogg_packet op,
1157 GstClockTime timestamp, GstClockTime running_time,
1158 GstClockTime duration, GstBuffer * buffer)
1161 th_ycbcr_buffer ycbcr;
1163 GstVideoFrame frame;
1165 gst_video_frame_map (&frame, &enc->vinfo, buffer, GST_MAP_READ);
1166 theora_enc_init_buffer (ycbcr, &frame);
1168 if (theora_enc_is_discontinuous (enc, running_time, duration)) {
1169 theora_enc_reset (enc);
1170 enc->granulepos_offset =
1171 gst_util_uint64_scale (running_time, enc->vinfo.fps_n,
1172 GST_SECOND * enc->vinfo.fps_d);
1173 enc->timestamp_offset = running_time;
1175 enc->next_discont = TRUE;
1178 if (enc->multipass_cache_fd
1179 && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
1180 if (!theora_enc_read_multipass_cache (enc)) {
1181 ret = GST_FLOW_ERROR;
1182 goto multipass_read_failed;
1186 res = th_encode_ycbcr_in (enc->encoder, ycbcr);
1187 /* none of the failure cases can happen here */
1188 g_assert (res == 0);
1190 if (enc->multipass_cache_fd
1191 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
1192 if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
1193 ret = GST_FLOW_ERROR;
1194 goto multipass_write_failed;
1199 while (th_encode_packetout (enc->encoder, 0, &op)) {
1200 GstClockTime next_time;
1202 next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
1205 theora_push_packet (enc, &op, timestamp, enc->next_ts,
1206 next_time - enc->next_ts);
1208 enc->next_ts = next_time;
1209 if (ret != GST_FLOW_OK)
1214 gst_video_frame_unmap (&frame);
1215 gst_buffer_unref (buffer);
1220 multipass_read_failed:
1222 GST_DEBUG_OBJECT (enc, "multipass read failed");
1225 multipass_write_failed:
1227 GST_DEBUG_OBJECT (enc, "multipass write failed");
1232 GST_DEBUG_OBJECT (enc, "error pushing buffer: %s", gst_flow_get_name (ret));
1237 static GstFlowReturn
1238 theora_enc_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1242 GstClockTime timestamp, duration, running_time;
1244 gboolean force_keyframe;
1246 enc = GST_THEORA_ENC (parent);
1248 /* we keep track of two timelines.
1249 * - The timestamps from the incoming buffers, which we copy to the outgoing
1250 * encoded buffers as-is. We need to do this as we simply forward the
1251 * newsegment events.
1252 * - The running_time of the buffers, which we use to construct the granulepos
1255 timestamp = GST_BUFFER_TIMESTAMP (buffer);
1256 duration = GST_BUFFER_DURATION (buffer);
1259 gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
1260 if ((gint64) running_time < 0) {
1261 GST_DEBUG_OBJECT (enc, "Dropping buffer, timestamp: %" GST_TIME_FORMAT,
1262 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
1263 gst_buffer_unref (buffer);
1267 GST_OBJECT_LOCK (enc);
1268 if (enc->bitrate_changed) {
1269 long int bitrate = enc->video_bitrate;
1271 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
1273 enc->bitrate_changed = FALSE;
1276 if (enc->quality_changed) {
1277 long int quality = enc->video_quality;
1279 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
1281 enc->quality_changed = FALSE;
1284 /* see if we need to schedule a keyframe */
1285 force_keyframe = enc->force_keyframe;
1286 enc->force_keyframe = FALSE;
1287 GST_OBJECT_UNLOCK (enc);
1289 if (force_keyframe) {
1290 GstClockTime stream_time;
1293 stream_time = gst_segment_to_stream_time (&enc->segment,
1294 GST_FORMAT_TIME, timestamp);
1296 s = gst_structure_new ("GstForceKeyUnit",
1297 "timestamp", G_TYPE_UINT64, timestamp,
1298 "stream-time", G_TYPE_UINT64, stream_time,
1299 "running-time", G_TYPE_UINT64, running_time, NULL);
1301 theora_enc_force_keyframe (enc);
1303 gst_pad_push_event (enc->srcpad,
1304 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
1307 /* make sure we copy the discont flag to the next outgoing buffer when it's
1308 * set on the incoming buffer */
1309 if (GST_BUFFER_IS_DISCONT (buffer)) {
1310 enc->next_discont = TRUE;
1313 if (enc->packetno == 0) {
1314 /* no packets written yet, setup headers */
1317 GSList *buffers = NULL;
1320 enc->granulepos_offset = 0;
1321 enc->timestamp_offset = 0;
1323 GST_DEBUG_OBJECT (enc, "output headers");
1324 /* Theora streams begin with three headers; the initial header (with
1325 most of the codec setup parameters) which is mandated by the Ogg
1326 bitstream spec. The second header holds any comment fields. The
1327 third header holds the bitstream codebook. We merely need to
1328 make the headers, then pass them to libtheora one at a time;
1329 libtheora handles the additional Ogg bitstream constraints */
1331 /* create the remaining theora headers */
1332 th_comment_clear (&enc->comment);
1333 th_comment_init (&enc->comment);
1336 th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
1338 theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
1339 GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf);
1340 if (ret != GST_FLOW_OK) {
1341 goto header_buffer_alloc;
1343 buffers = g_slist_prepend (buffers, buf);
1346 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1347 g_slist_free (buffers);
1348 goto encoder_disabled;
1351 buffers = g_slist_reverse (buffers);
1353 /* mark buffers and put on caps */
1354 caps = gst_caps_new_simple ("video/x-theora",
1355 "width", G_TYPE_INT, enc->vinfo.width,
1356 "height", G_TYPE_INT, enc->vinfo.height,
1357 "framerate", GST_TYPE_FRACTION, enc->vinfo.fps_n, enc->vinfo.fps_d,
1358 "pixel-aspect-ratio", GST_TYPE_FRACTION, enc->vinfo.par_n,
1359 enc->vinfo.par_d, NULL);
1360 caps = theora_set_header_on_caps (caps, buffers);
1361 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
1362 gst_pad_set_caps (enc->srcpad, caps);
1363 gst_caps_unref (caps);
1365 /* push out the header buffers */
1367 buf = buffers->data;
1368 buffers = g_slist_delete_link (buffers, buffers);
1369 if ((ret = theora_push_buffer (enc, buf)) != GST_FLOW_OK) {
1370 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1371 g_slist_free (buffers);
1376 enc->granulepos_offset =
1377 gst_util_uint64_scale (running_time, enc->vinfo.fps_n,
1378 GST_SECOND * enc->vinfo.fps_d);
1379 enc->timestamp_offset = running_time;
1383 ret = theora_enc_encode_and_push (enc, op, timestamp, running_time, duration,
1389 header_buffer_alloc:
1391 gst_buffer_unref (buffer);
1396 gst_buffer_unref (buffer);
1401 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1402 ("libtheora has been compiled with the encoder disabled"));
1403 gst_buffer_unref (buffer);
1404 return GST_FLOW_ERROR;
1408 static GstStateChangeReturn
1409 theora_enc_change_state (GstElement * element, GstStateChange transition)
1412 GstStateChangeReturn ret;
1415 enc = GST_THEORA_ENC (element);
1417 switch (transition) {
1418 case GST_STATE_CHANGE_NULL_TO_READY:
1419 th_ctx = dummy_encode_ctx ();
1421 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1422 ("libtheora has been compiled with the encoder disabled"));
1423 return GST_STATE_CHANGE_FAILURE;
1425 th_encode_free (th_ctx);
1427 case GST_STATE_CHANGE_READY_TO_PAUSED:
1428 GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state");
1429 th_info_init (&enc->info);
1430 th_comment_init (&enc->comment);
1432 enc->force_keyframe = FALSE;
1434 if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) {
1437 if (!enc->multipass_cache_file) {
1438 ret = GST_STATE_CHANGE_FAILURE;
1439 GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
1442 enc->multipass_cache_fd =
1443 g_io_channel_new_file (enc->multipass_cache_file,
1444 (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"),
1447 if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS)
1448 enc->multipass_cache_adapter = gst_adapter_new ();
1450 if (!enc->multipass_cache_fd) {
1451 ret = GST_STATE_CHANGE_FAILURE;
1452 GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL),
1453 ("Failed to open multipass cache file: %s", err->message));
1458 g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL);
1461 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1467 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1469 switch (transition) {
1470 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1472 case GST_STATE_CHANGE_PAUSED_TO_READY:
1473 GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state");
1475 th_encode_free (enc->encoder);
1476 enc->encoder = NULL;
1478 th_comment_clear (&enc->comment);
1479 th_info_clear (&enc->info);
1481 theora_enc_clear (enc);
1482 enc->initialised = FALSE;
1484 case GST_STATE_CHANGE_READY_TO_NULL:
1494 theora_enc_set_property (GObject * object, guint prop_id,
1495 const GValue * value, GParamSpec * pspec)
1497 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1503 case PROP_KEYFRAME_THRESHOLD:
1504 case PROP_KEYFRAME_MINDISTANCE:
1505 case PROP_NOISE_SENSITIVITY:
1506 case PROP_SHARPNESS:
1507 /* kept for API compat, but ignored */
1508 GST_WARNING_OBJECT (object, "Obsolete property '%s' ignored",
1512 GST_OBJECT_LOCK (enc);
1513 enc->video_bitrate = g_value_get_int (value) * 1000;
1514 enc->bitrate_changed = TRUE;
1515 GST_OBJECT_UNLOCK (enc);
1518 GST_OBJECT_LOCK (enc);
1519 if (GST_STATE (enc) >= GST_STATE_PAUSED && enc->video_bitrate > 0) {
1520 GST_WARNING_OBJECT (object, "Can't change from bitrate to quality mode"
1523 enc->video_quality = g_value_get_int (value);
1524 enc->video_bitrate = 0;
1525 enc->quality_changed = TRUE;
1527 GST_OBJECT_UNLOCK (enc);
1529 case PROP_KEYFRAME_AUTO:
1530 enc->keyframe_auto = g_value_get_boolean (value);
1532 case PROP_KEYFRAME_FREQ:
1533 enc->keyframe_freq = g_value_get_int (value);
1535 case PROP_KEYFRAME_FREQ_FORCE:
1536 enc->keyframe_force = g_value_get_int (value);
1538 case PROP_SPEEDLEVEL:
1539 enc->speed_level = g_value_get_int (value);
1541 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
1542 sizeof (enc->speed_level));
1545 case PROP_VP3_COMPATIBLE:
1546 enc->vp3_compatible = g_value_get_boolean (value);
1548 case PROP_DROP_FRAMES:
1549 enc->drop_frames = g_value_get_boolean (value);
1551 case PROP_CAP_OVERFLOW:
1552 enc->cap_overflow = g_value_get_boolean (value);
1554 case PROP_CAP_UNDERFLOW:
1555 enc->cap_underflow = g_value_get_boolean (value);
1557 case PROP_RATE_BUFFER:
1558 enc->rate_buffer = g_value_get_int (value);
1560 case PROP_MULTIPASS_CACHE_FILE:
1561 enc->multipass_cache_file = g_value_dup_string (value);
1563 case PROP_MULTIPASS_MODE:
1564 enc->multipass_mode = g_value_get_enum (value);
1567 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1573 theora_enc_get_property (GObject * object, guint prop_id,
1574 GValue * value, GParamSpec * pspec)
1576 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1580 g_value_set_boolean (value, TRUE);
1583 g_value_set_enum (value, BORDER_BLACK);
1586 GST_OBJECT_LOCK (enc);
1587 g_value_set_int (value, enc->video_bitrate / 1000);
1588 GST_OBJECT_UNLOCK (enc);
1591 GST_OBJECT_LOCK (enc);
1592 g_value_set_int (value, enc->video_quality);
1593 GST_OBJECT_UNLOCK (enc);
1596 g_value_set_boolean (value, TRUE);
1598 case PROP_KEYFRAME_AUTO:
1599 g_value_set_boolean (value, enc->keyframe_auto);
1601 case PROP_KEYFRAME_FREQ:
1602 g_value_set_int (value, enc->keyframe_freq);
1604 case PROP_KEYFRAME_FREQ_FORCE:
1605 g_value_set_int (value, enc->keyframe_force);
1607 case PROP_KEYFRAME_THRESHOLD:
1608 g_value_set_int (value, 80);
1610 case PROP_KEYFRAME_MINDISTANCE:
1611 g_value_set_int (value, 8);
1613 case PROP_NOISE_SENSITIVITY:
1614 g_value_set_int (value, 1);
1616 case PROP_SHARPNESS:
1617 g_value_set_int (value, 0);
1619 case PROP_SPEEDLEVEL:
1620 g_value_set_int (value, enc->speed_level);
1622 case PROP_VP3_COMPATIBLE:
1623 g_value_set_boolean (value, enc->vp3_compatible);
1625 case PROP_DROP_FRAMES:
1626 g_value_set_boolean (value, enc->drop_frames);
1628 case PROP_CAP_OVERFLOW:
1629 g_value_set_boolean (value, enc->cap_overflow);
1631 case PROP_CAP_UNDERFLOW:
1632 g_value_set_boolean (value, enc->cap_underflow);
1634 case PROP_RATE_BUFFER:
1635 g_value_set_int (value, enc->rate_buffer);
1637 case PROP_MULTIPASS_CACHE_FILE:
1638 g_value_set_string (value, enc->multipass_cache_file);
1640 case PROP_MULTIPASS_MODE:
1641 g_value_set_enum (value, enc->multipass_mode);
1644 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);