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, GstEvent * event);
252 static gboolean theora_enc_src_event (GstPad * pad, GstEvent * event);
253 static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
254 static GstStateChangeReturn theora_enc_change_state (GstElement * element,
255 GstStateChange transition);
256 static gboolean theora_enc_sink_query (GstPad * pad, GstQuery * query);
257 static gboolean theora_enc_sink_setcaps (GstTheoraEnc * enc, GstCaps * caps);
258 static void theora_enc_get_property (GObject * object, guint prop_id,
259 GValue * value, GParamSpec * pspec);
260 static void theora_enc_set_property (GObject * object, guint prop_id,
261 const GValue * value, GParamSpec * pspec);
262 static void theora_enc_finalize (GObject * object);
264 static gboolean theora_enc_write_multipass_cache (GstTheoraEnc * enc,
265 gboolean begin, gboolean eos);
267 static char *theora_enc_get_supported_formats (void);
270 gst_theora_enc_class_init (GstTheoraEncClass * klass)
272 GObjectClass *gobject_class = (GObjectClass *) klass;
273 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
276 /* query runtime encoder properties */
278 int default_speed_level = THEORA_DEF_SPEEDLEVEL;
279 int max_speed_level = default_speed_level;
281 GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
283 th_ctx = dummy_encode_ctx ();
285 if (check_speed_level (th_ctx, &default_speed_level, &max_speed_level))
287 ("Failed to determine settings for the speed-level property.");
288 th_encode_free (th_ctx);
291 gobject_class->set_property = theora_enc_set_property;
292 gobject_class->get_property = theora_enc_get_property;
293 gobject_class->finalize = theora_enc_finalize;
295 g_object_class_install_property (gobject_class, PROP_CENTER,
296 g_param_spec_boolean ("center", "Center",
297 "ignored and kept for API compat only", TRUE,
298 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
299 g_object_class_install_property (gobject_class, PROP_BORDER,
300 g_param_spec_enum ("border", "Border",
301 "ignored and kept for API compat only",
302 GST_TYPE_BORDER_MODE, BORDER_BLACK,
303 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
304 /* general encoding stream options */
305 g_object_class_install_property (gobject_class, PROP_BITRATE,
306 g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
307 0, (1 << 24) - 1, THEORA_DEF_BITRATE,
308 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
309 GST_PARAM_MUTABLE_PLAYING));
310 g_object_class_install_property (gobject_class, PROP_QUALITY,
311 g_param_spec_int ("quality", "Quality", "Video quality", 0, 63,
313 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
314 GST_PARAM_MUTABLE_PLAYING));
315 g_object_class_install_property (gobject_class, PROP_QUICK,
316 g_param_spec_boolean ("quick", "Quick",
317 "ignored and kept for API compat only", TRUE,
318 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
319 g_object_class_install_property (gobject_class, PROP_KEYFRAME_AUTO,
320 g_param_spec_boolean ("keyframe-auto", "Keyframe Auto",
321 "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO,
322 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
323 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ,
324 g_param_spec_int ("keyframe-freq", "Keyframe frequency",
325 "Keyframe frequency", 1, 32768, THEORA_DEF_KEYFRAME_FREQ,
326 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
327 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ_FORCE,
328 g_param_spec_int ("keyframe-force", "Keyframe force",
329 "Force keyframe every N frames", 1, 32768,
330 THEORA_DEF_KEYFRAME_FREQ_FORCE,
331 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
332 g_object_class_install_property (gobject_class, PROP_KEYFRAME_THRESHOLD,
333 g_param_spec_int ("keyframe-threshold", "Keyframe threshold",
334 "ignored and kept for API compat only", 0, 32768, 80,
335 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
336 g_object_class_install_property (gobject_class, PROP_KEYFRAME_MINDISTANCE,
337 g_param_spec_int ("keyframe-mindistance", "Keyframe mindistance",
338 "ignored and kept for API compat only", 1, 32768, 8,
339 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
340 g_object_class_install_property (gobject_class, PROP_NOISE_SENSITIVITY,
341 g_param_spec_int ("noise-sensitivity", "Noise sensitivity",
342 "ignored and kept for API compat only", 0, 32768, 1,
343 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
344 g_object_class_install_property (gobject_class, PROP_SHARPNESS,
345 g_param_spec_int ("sharpness", "Sharpness",
346 "ignored and kept for API compat only", 0, 2, 0,
347 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
348 g_object_class_install_property (gobject_class, PROP_SPEEDLEVEL,
349 g_param_spec_int ("speed-level", "Speed level",
350 "Controls the amount of analysis performed when encoding."
351 " Higher values trade compression quality for speed."
352 " This property requires libtheora version >= 1.0"
353 ", and the maximum value may vary based on encoder version.",
354 0, max_speed_level, default_speed_level,
355 (GParamFlags) G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
356 G_PARAM_STATIC_STRINGS));
357 g_object_class_install_property (gobject_class, PROP_VP3_COMPATIBLE,
358 g_param_spec_boolean ("vp3-compatible", "VP3 Compatible",
359 "Disables non-VP3 compatible features",
360 THEORA_DEF_VP3_COMPATIBLE,
361 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
362 g_object_class_install_property (gobject_class, PROP_DROP_FRAMES,
363 g_param_spec_boolean ("drop-frames", "Drop Frames",
364 "Allow or disallow frame dropping",
365 THEORA_DEF_DROP_FRAMES,
366 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
367 g_object_class_install_property (gobject_class, PROP_CAP_OVERFLOW,
368 g_param_spec_boolean ("cap-overflow", "Cap Overflow",
369 "Enable capping of bit reservoir overflows",
370 THEORA_DEF_CAP_OVERFLOW,
371 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
372 g_object_class_install_property (gobject_class, PROP_CAP_UNDERFLOW,
373 g_param_spec_boolean ("cap-underflow", "Cap Underflow",
374 "Enable capping of bit reservoir underflows",
375 THEORA_DEF_CAP_UNDERFLOW,
376 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
377 g_object_class_install_property (gobject_class, PROP_RATE_BUFFER,
378 g_param_spec_int ("rate-buffer", "Rate Control Buffer",
379 "Sets the size of the rate control buffer, in units of frames. "
380 "The default value of 0 instructs the encoder to automatically "
381 "select an appropriate value",
382 0, 1000, THEORA_DEF_RATE_BUFFER,
383 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
384 g_object_class_install_property (gobject_class, PROP_MULTIPASS_CACHE_FILE,
385 g_param_spec_string ("multipass-cache-file", "Multipass Cache File",
386 "Multipass cache file", THEORA_DEF_MULTIPASS_CACHE_FILE,
387 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
388 g_object_class_install_property (gobject_class, PROP_MULTIPASS_MODE,
389 g_param_spec_enum ("multipass-mode", "Multipass mode",
390 "Single pass or first/second pass", GST_TYPE_MULTIPASS_MODE,
391 THEORA_DEF_MULTIPASS_MODE,
392 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
394 gst_element_class_add_pad_template (gstelement_class,
395 gst_static_pad_template_get (&theora_enc_src_factory));
396 gst_element_class_add_pad_template (gstelement_class,
397 gst_static_pad_template_get (&theora_enc_sink_factory));
398 gst_element_class_set_details_simple (gstelement_class,
399 "Theora video encoder", "Codec/Encoder/Video",
400 "encode raw YUV video to a theora stream",
401 "Wim Taymans <wim@fluendo.com>");
403 caps_string = g_strdup_printf ("video/x-raw, "
404 "format = (string) { %s }, "
405 "framerate = (fraction) [1/MAX, MAX], "
406 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]",
407 theora_enc_get_supported_formats ());
408 theora_enc_src_caps = gst_caps_from_string (caps_string);
409 g_free (caps_string);
411 gstelement_class->change_state = theora_enc_change_state;
415 gst_theora_enc_init (GstTheoraEnc * enc)
418 gst_pad_new_from_static_template (&theora_enc_sink_factory, "sink");
419 gst_pad_set_chain_function (enc->sinkpad, theora_enc_chain);
420 gst_pad_set_event_function (enc->sinkpad, theora_enc_sink_event);
421 gst_pad_set_query_function (enc->sinkpad, theora_enc_sink_query);
422 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
425 gst_pad_new_from_static_template (&theora_enc_src_factory, "src");
426 gst_pad_set_event_function (enc->srcpad, theora_enc_src_event);
427 gst_pad_use_fixed_caps (enc->srcpad);
428 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
430 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
432 enc->video_bitrate = THEORA_DEF_BITRATE;
433 enc->video_quality = THEORA_DEF_QUALITY;
434 enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
435 enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ;
436 enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE;
438 enc->expected_ts = GST_CLOCK_TIME_NONE;
440 /* enc->speed_level is set to the libtheora default by the constructor */
441 enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE;
442 enc->drop_frames = THEORA_DEF_DROP_FRAMES;
443 enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW;
444 enc->cap_underflow = THEORA_DEF_CAP_UNDERFLOW;
445 enc->rate_buffer = THEORA_DEF_RATE_BUFFER;
447 enc->multipass_mode = THEORA_DEF_MULTIPASS_MODE;
448 enc->multipass_cache_file = THEORA_DEF_MULTIPASS_CACHE_FILE;
452 theora_enc_clear_multipass_cache (GstTheoraEnc * enc)
454 if (enc->multipass_cache_fd) {
455 g_io_channel_shutdown (enc->multipass_cache_fd, TRUE, NULL);
456 g_io_channel_unref (enc->multipass_cache_fd);
457 enc->multipass_cache_fd = NULL;
460 if (enc->multipass_cache_adapter) {
461 gst_object_unref (enc->multipass_cache_adapter);
462 enc->multipass_cache_adapter = NULL;
467 theora_enc_finalize (GObject * object)
469 GstTheoraEnc *enc = GST_THEORA_ENC (object);
471 GST_DEBUG_OBJECT (enc, "Finalizing");
473 th_encode_free (enc->encoder);
474 th_comment_clear (&enc->comment);
475 th_info_clear (&enc->info);
476 g_free (enc->multipass_cache_file);
478 theora_enc_clear_multipass_cache (enc);
480 G_OBJECT_CLASS (parent_class)->finalize (object);
484 theora_enc_reset (GstTheoraEnc * enc)
486 ogg_uint32_t keyframe_force;
489 GST_OBJECT_LOCK (enc);
490 enc->info.target_bitrate = enc->video_bitrate;
491 if (enc->quality_changed) {
492 enc->info.quality = enc->video_quality;
494 if (enc->video_bitrate == 0) {
495 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, GstCaps * filter)
601 GstTheoraEnc *encoder;
605 /* If we already have caps return them */
606 if ((caps = gst_pad_get_current_caps (pad)) != NULL)
609 encoder = GST_THEORA_ENC (gst_pad_get_parent (pad));
611 return gst_caps_new_empty ();
613 peer = gst_pad_get_peer (encoder->srcpad);
615 const GstCaps *templ_caps;
616 GstCaps *peer_caps, *tmp_caps;
620 peer_caps = gst_pad_query_caps (peer, NULL);
622 /* Translate peercaps to YUV */
623 peer_caps = gst_caps_make_writable (peer_caps);
624 n = gst_caps_get_size (peer_caps);
625 for (i = 0; i < n; i++) {
626 s = gst_caps_get_structure (peer_caps, i);
628 gst_structure_set_name (s, "video/x-raw");
629 gst_structure_remove_field (s, "streamheader");
632 templ_caps = gst_pad_get_pad_template_caps (pad);
634 tmp_caps = gst_caps_intersect (peer_caps, templ_caps);
635 caps = gst_caps_intersect (tmp_caps, theora_enc_src_caps);
636 gst_caps_unref (tmp_caps);
637 gst_caps_unref (peer_caps);
638 gst_object_unref (peer);
641 caps = gst_caps_ref (theora_enc_src_caps);
644 gst_object_unref (encoder);
647 GstCaps *intersection;
650 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
651 gst_caps_unref (caps);
659 theora_enc_sink_query (GstPad * pad, GstQuery * query)
661 gboolean res = FALSE;
663 switch (GST_QUERY_TYPE (query)) {
666 GstCaps *filter, *caps;
668 gst_query_parse_caps (query, &filter);
669 caps = theora_enc_sink_getcaps (pad, filter);
670 gst_query_set_caps_result (query, caps);
671 gst_caps_unref (caps);
676 res = gst_pad_query_default (pad, query);
684 theora_enc_sink_setcaps (GstTheoraEnc * enc, GstCaps * caps)
688 th_info_clear (&enc->info);
689 th_info_init (&enc->info);
691 if (!gst_video_info_from_caps (&info, caps))
696 /* Theora has a divisible-by-sixteen restriction for the encoded video size but
697 * we can define a picture area using pic_width/pic_height */
698 enc->info.frame_width = GST_ROUND_UP_16 (info.width);
699 enc->info.frame_height = GST_ROUND_UP_16 (info.height);
700 enc->info.pic_width = info.width;
701 enc->info.pic_height = info.height;
703 switch (GST_VIDEO_INFO_FORMAT (&info)) {
704 case GST_VIDEO_FORMAT_I420:
705 enc->info.pixel_fmt = TH_PF_420;
707 case GST_VIDEO_FORMAT_Y42B:
708 enc->info.pixel_fmt = TH_PF_422;
710 case GST_VIDEO_FORMAT_Y444:
711 enc->info.pixel_fmt = TH_PF_444;
714 g_assert_not_reached ();
717 enc->info.fps_numerator = info.fps_n;
718 enc->info.fps_denominator = info.fps_d;
720 enc->info.aspect_numerator = info.par_n;
721 enc->info.aspect_denominator = info.par_d;
723 /* setting them to 0 indicates that the decoder can chose a good aspect
724 * ratio, defaulting to 1/1 */
725 enc->info.aspect_numerator = 0;
727 enc->info.aspect_denominator = 0;
731 enc->info.colorspace = TH_CS_UNSPECIFIED;
733 /* as done in theora */
734 enc->info.keyframe_granule_shift = _ilog (enc->keyframe_force - 1);
735 GST_DEBUG_OBJECT (enc,
736 "keyframe_frequency_force is %d, granule shift is %d",
737 enc->keyframe_force, enc->info.keyframe_granule_shift);
739 theora_enc_reset (enc);
740 enc->initialised = TRUE;
747 GST_DEBUG_OBJECT (enc, "could not parse caps");
753 granulepos_add (guint64 granulepos, guint64 addend, gint shift)
755 guint64 iframe, pframe;
757 iframe = granulepos >> shift;
758 pframe = granulepos - (iframe << shift);
761 return (iframe << shift) + pframe;
764 /* prepare a buffer for transmission by passing data through libtheora */
766 theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
767 GstClockTime timestamp, GstClockTime running_time,
768 GstClockTime duration, GstBuffer ** buffer)
771 GstFlowReturn ret = GST_FLOW_OK;
773 buf = gst_buffer_new_and_alloc (packet->bytes);
775 GST_WARNING_OBJECT (enc, "Could not allocate buffer");
776 ret = GST_FLOW_ERROR;
780 gst_buffer_fill (buf, 0, packet->packet, packet->bytes);
781 /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
782 * time representation */
783 GST_BUFFER_OFFSET_END (buf) =
784 granulepos_add (packet->granulepos, enc->granulepos_offset,
785 enc->info.keyframe_granule_shift);
786 GST_BUFFER_OFFSET (buf) = granulepos_to_timestamp (enc,
787 GST_BUFFER_OFFSET_END (buf));
789 GST_BUFFER_TIMESTAMP (buf) = timestamp;
790 GST_BUFFER_DURATION (buf) = duration;
792 if (enc->next_discont) {
793 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
794 enc->next_discont = FALSE;
797 /* th_packet_iskeyframe returns positive for keyframes */
798 if (th_packet_iskeyframe (packet) > 0) {
799 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
801 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
810 /* push out the buffer and do internal bookkeeping */
812 theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
816 enc->bytes_out += gst_buffer_get_size (buffer);
818 ret = gst_pad_push (enc->srcpad, buffer);
824 theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet,
825 GstClockTime timestamp, GstClockTime running_time, GstClockTime duration)
831 theora_buffer_from_packet (enc, packet, timestamp, running_time, duration,
833 if (ret == GST_FLOW_OK)
834 ret = theora_push_buffer (enc, buf);
840 theora_set_header_on_caps (GstCaps * caps, GSList * buffers)
842 GstStructure *structure;
843 GValue array = { 0 };
844 GValue value = { 0 };
848 caps = gst_caps_make_writable (caps);
849 structure = gst_caps_get_structure (caps, 0);
851 /* put copies of the buffers in a fixed list */
852 g_value_init (&array, GST_TYPE_ARRAY);
854 for (walk = buffers; walk; walk = walk->next) {
858 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
860 /* Copy buffer, because we can't use the original -
861 * it creates a circular refcount with the caps<->buffers */
862 buffer = gst_buffer_copy (buffer);
864 g_value_init (&value, GST_TYPE_BUFFER);
865 gst_value_set_buffer (&value, buffer);
866 gst_value_array_append_value (&array, &value);
867 g_value_unset (&value);
870 gst_buffer_unref (buffer);
873 gst_structure_set_value (structure, "streamheader", &array);
874 g_value_unset (&array);
880 theora_enc_force_keyframe (GstTheoraEnc * enc)
882 GstClockTime next_ts;
884 /* make sure timestamps increment after resetting the decoder */
885 next_ts = enc->next_ts + enc->timestamp_offset;
887 theora_enc_reset (enc);
888 enc->granulepos_offset =
889 gst_util_uint64_scale (next_ts, enc->vinfo.fps_n,
890 GST_SECOND * enc->vinfo.fps_d);
891 enc->timestamp_offset = next_ts;
896 theora_enc_sink_event (GstPad * pad, GstEvent * event)
902 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
904 switch (GST_EVENT_TYPE (event)) {
909 gst_event_parse_caps (event, &caps);
910 res = theora_enc_sink_setcaps (enc, caps);
911 gst_event_unref (event);
914 case GST_EVENT_SEGMENT:
916 gst_event_copy_segment (event, &enc->segment);
918 res = gst_pad_push_event (enc->srcpad, event);
922 if (enc->initialised) {
923 /* push last packet with eos flag, should not be called */
924 while (th_encode_packetout (enc->encoder, 1, &op)) {
925 GstClockTime next_time =
926 th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
928 theora_push_packet (enc, &op, GST_CLOCK_TIME_NONE, enc->next_ts,
929 next_time - enc->next_ts);
930 enc->next_ts = next_time;
933 if (enc->initialised && enc->multipass_cache_fd
934 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
935 theora_enc_write_multipass_cache (enc, TRUE, TRUE);
937 theora_enc_clear_multipass_cache (enc);
939 res = gst_pad_push_event (enc->srcpad, event);
941 case GST_EVENT_FLUSH_STOP:
942 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
943 res = gst_pad_push_event (enc->srcpad, event);
945 case GST_EVENT_CUSTOM_DOWNSTREAM:
947 const GstStructure *s;
949 s = gst_event_get_structure (event);
951 if (gst_structure_has_name (s, "GstForceKeyUnit"))
952 theora_enc_force_keyframe (enc);
953 res = gst_pad_push_event (enc->srcpad, event);
957 res = gst_pad_push_event (enc->srcpad, event);
964 theora_enc_src_event (GstPad * pad, GstEvent * event)
969 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
971 switch (GST_EVENT_TYPE (event)) {
972 case GST_EVENT_CUSTOM_UPSTREAM:
974 const GstStructure *s;
976 s = gst_event_get_structure (event);
978 if (gst_structure_has_name (s, "GstForceKeyUnit")) {
979 GST_OBJECT_LOCK (enc);
980 enc->force_keyframe = TRUE;
981 GST_OBJECT_UNLOCK (enc);
982 /* consume the event */
984 gst_event_unref (event);
986 res = gst_pad_push_event (enc->sinkpad, event);
991 res = gst_pad_push_event (enc->sinkpad, event);
999 theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp,
1000 GstClockTime duration)
1002 GstClockTimeDiff max_diff;
1003 gboolean ret = FALSE;
1005 /* Allow 3/4 a frame off */
1006 max_diff = (enc->info.fps_denominator * GST_SECOND * 3) /
1007 (enc->info.fps_numerator * 4);
1009 if (timestamp != GST_CLOCK_TIME_NONE
1010 && enc->expected_ts != GST_CLOCK_TIME_NONE) {
1011 if ((GstClockTimeDiff) (timestamp - enc->expected_ts) > max_diff) {
1012 GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT
1013 " exceeds expected value %" GST_TIME_FORMAT
1014 " by too much, marking discontinuity",
1015 GST_TIME_ARGS (timestamp), GST_TIME_ARGS (enc->expected_ts));
1020 if (GST_CLOCK_TIME_IS_VALID (duration))
1021 enc->expected_ts = timestamp + duration;
1023 enc->expected_ts = GST_CLOCK_TIME_NONE;
1029 theora_enc_init_buffer (th_ycbcr_buffer buf, GstVideoFrame * frame)
1033 /* According to Theora developer Timothy Terriberry, the Theora
1034 * encoder will not use memory outside of pic_width/height, even when
1035 * the frame size is bigger. The values outside this region will be encoded
1036 * to default values.
1037 * Due to this, setting the frame's width/height as the buffer width/height
1038 * is perfectly ok, even though it does not strictly look ok.
1040 for (i = 0; i < 3; i++) {
1041 buf[i].width = GST_VIDEO_FRAME_COMP_WIDTH (frame, i);
1042 buf[i].height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, i);
1043 buf[i].data = GST_VIDEO_FRAME_COMP_DATA (frame, i);
1044 buf[i].stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
1049 theora_enc_read_multipass_cache (GstTheoraEnc * enc)
1051 GstBuffer *cache_buf;
1052 const guint8 *cache_data;
1053 gsize bytes_read = 0;
1054 gint bytes_consumed = 0;
1055 GIOStatus stat = G_IO_STATUS_NORMAL;
1056 gboolean done = FALSE;
1059 if (gst_adapter_available (enc->multipass_cache_adapter) == 0) {
1063 cache_buf = gst_buffer_new_and_alloc (512);
1065 data = gst_buffer_map (cache_buf, &size, NULL, GST_MAP_READ);
1066 stat = g_io_channel_read_chars (enc->multipass_cache_fd,
1067 (gchar *) data, size, &bytes_read, NULL);
1069 if (bytes_read <= 0) {
1070 gst_buffer_unmap (cache_buf, data, 0);
1071 gst_buffer_unref (cache_buf);
1074 gst_buffer_unmap (cache_buf, data, bytes_read);
1075 gst_adapter_push (enc->multipass_cache_adapter, cache_buf);
1078 if (gst_adapter_available (enc->multipass_cache_adapter) == 0)
1082 MIN (gst_adapter_available (enc->multipass_cache_adapter), 512);
1084 cache_data = gst_adapter_map (enc->multipass_cache_adapter, bytes_read);
1087 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data,
1089 gst_adapter_unmap (enc->multipass_cache_adapter);
1091 done = bytes_consumed <= 0;
1092 if (bytes_consumed > 0)
1093 gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed);
1096 if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_EOF && bytes_read == 0)
1097 || bytes_consumed < 0) {
1098 GST_ELEMENT_ERROR (enc, RESOURCE, READ, (NULL),
1099 ("Failed to read multipass cache file"));
1106 theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin,
1110 GIOStatus stat = G_IO_STATUS_NORMAL;
1111 gint bytes_read = 0;
1112 gsize bytes_written = 0;
1116 stat = g_io_channel_seek_position (enc->multipass_cache_fd, 0, G_SEEK_SET,
1118 if (stat != G_IO_STATUS_ERROR) {
1121 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_OUT, &buf, sizeof (buf));
1123 g_io_channel_write_chars (enc->multipass_cache_fd, buf, bytes_read,
1124 &bytes_written, NULL);
1125 } while (bytes_read > 0 && bytes_written > 0);
1129 if (stat == G_IO_STATUS_ERROR || bytes_read < 0) {
1132 GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL),
1133 ("Failed to seek to beginning of multipass cache file: %s",
1136 GST_ELEMENT_ERROR (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 write multipass cache file"));
1151 static GstFlowReturn
1152 theora_enc_encode_and_push (GstTheoraEnc * enc, ogg_packet op,
1153 GstClockTime timestamp, GstClockTime running_time,
1154 GstClockTime duration, GstBuffer * buffer)
1157 th_ycbcr_buffer ycbcr;
1159 GstVideoFrame frame;
1161 gst_video_frame_map (&frame, &enc->vinfo, buffer, GST_MAP_READ);
1162 theora_enc_init_buffer (ycbcr, &frame);
1164 if (theora_enc_is_discontinuous (enc, running_time, duration)) {
1165 theora_enc_reset (enc);
1166 enc->granulepos_offset =
1167 gst_util_uint64_scale (running_time, enc->vinfo.fps_n,
1168 GST_SECOND * enc->vinfo.fps_d);
1169 enc->timestamp_offset = running_time;
1171 enc->next_discont = TRUE;
1174 if (enc->multipass_cache_fd
1175 && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
1176 if (!theora_enc_read_multipass_cache (enc)) {
1177 ret = GST_FLOW_ERROR;
1178 goto multipass_read_failed;
1182 res = th_encode_ycbcr_in (enc->encoder, ycbcr);
1183 /* none of the failure cases can happen here */
1184 g_assert (res == 0);
1186 if (enc->multipass_cache_fd
1187 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
1188 if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
1189 ret = GST_FLOW_ERROR;
1190 goto multipass_write_failed;
1195 while (th_encode_packetout (enc->encoder, 0, &op)) {
1196 GstClockTime next_time;
1198 next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
1201 theora_push_packet (enc, &op, timestamp, enc->next_ts,
1202 next_time - enc->next_ts);
1204 enc->next_ts = next_time;
1205 if (ret != GST_FLOW_OK)
1210 gst_video_frame_unmap (&frame);
1211 gst_buffer_unref (buffer);
1216 multipass_read_failed:
1218 GST_DEBUG_OBJECT (enc, "multipass read failed");
1221 multipass_write_failed:
1223 GST_DEBUG_OBJECT (enc, "multipass write failed");
1228 GST_DEBUG_OBJECT (enc, "error pushing buffer: %s", gst_flow_get_name (ret));
1233 static GstFlowReturn
1234 theora_enc_chain (GstPad * pad, GstBuffer * buffer)
1238 GstClockTime timestamp, duration, running_time;
1240 gboolean force_keyframe;
1242 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
1244 /* we keep track of two timelines.
1245 * - The timestamps from the incoming buffers, which we copy to the outgoing
1246 * encoded buffers as-is. We need to do this as we simply forward the
1247 * newsegment events.
1248 * - The running_time of the buffers, which we use to construct the granulepos
1251 timestamp = GST_BUFFER_TIMESTAMP (buffer);
1252 duration = GST_BUFFER_DURATION (buffer);
1255 gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
1256 if ((gint64) running_time < 0) {
1257 GST_DEBUG_OBJECT (enc, "Dropping buffer, timestamp: %" GST_TIME_FORMAT,
1258 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
1259 gst_buffer_unref (buffer);
1263 GST_OBJECT_LOCK (enc);
1264 if (enc->bitrate_changed) {
1265 long int bitrate = enc->video_bitrate;
1267 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
1269 enc->bitrate_changed = FALSE;
1272 if (enc->quality_changed) {
1273 long int quality = enc->video_quality;
1275 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
1277 enc->quality_changed = FALSE;
1280 /* see if we need to schedule a keyframe */
1281 force_keyframe = enc->force_keyframe;
1282 enc->force_keyframe = FALSE;
1283 GST_OBJECT_UNLOCK (enc);
1285 if (force_keyframe) {
1286 GstClockTime stream_time;
1289 stream_time = gst_segment_to_stream_time (&enc->segment,
1290 GST_FORMAT_TIME, timestamp);
1292 s = gst_structure_new ("GstForceKeyUnit",
1293 "timestamp", G_TYPE_UINT64, timestamp,
1294 "stream-time", G_TYPE_UINT64, stream_time,
1295 "running-time", G_TYPE_UINT64, running_time, NULL);
1297 theora_enc_force_keyframe (enc);
1299 gst_pad_push_event (enc->srcpad,
1300 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
1303 /* make sure we copy the discont flag to the next outgoing buffer when it's
1304 * set on the incoming buffer */
1305 if (GST_BUFFER_IS_DISCONT (buffer)) {
1306 enc->next_discont = TRUE;
1309 if (enc->packetno == 0) {
1310 /* no packets written yet, setup headers */
1313 GSList *buffers = NULL;
1316 enc->granulepos_offset = 0;
1317 enc->timestamp_offset = 0;
1319 GST_DEBUG_OBJECT (enc, "output headers");
1320 /* Theora streams begin with three headers; the initial header (with
1321 most of the codec setup parameters) which is mandated by the Ogg
1322 bitstream spec. The second header holds any comment fields. The
1323 third header holds the bitstream codebook. We merely need to
1324 make the headers, then pass them to libtheora one at a time;
1325 libtheora handles the additional Ogg bitstream constraints */
1327 /* create the remaining theora headers */
1328 th_comment_clear (&enc->comment);
1329 th_comment_init (&enc->comment);
1332 th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
1334 theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
1335 GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf);
1336 if (ret != GST_FLOW_OK) {
1337 goto header_buffer_alloc;
1339 buffers = g_slist_prepend (buffers, buf);
1342 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1343 g_slist_free (buffers);
1344 goto encoder_disabled;
1347 buffers = g_slist_reverse (buffers);
1349 /* mark buffers and put on caps */
1350 caps = gst_caps_new_simple ("video/x-theora",
1351 "width", G_TYPE_INT, enc->vinfo.width,
1352 "height", G_TYPE_INT, enc->vinfo.height,
1353 "framerate", GST_TYPE_FRACTION, enc->vinfo.fps_n, enc->vinfo.fps_d,
1354 "pixel-aspect-ratio", GST_TYPE_FRACTION, enc->vinfo.par_n,
1355 enc->vinfo.par_d, NULL);
1356 caps = theora_set_header_on_caps (caps, buffers);
1357 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
1358 gst_pad_set_caps (enc->srcpad, caps);
1359 gst_caps_unref (caps);
1361 /* push out the header buffers */
1363 buf = buffers->data;
1364 buffers = g_slist_delete_link (buffers, buffers);
1365 if ((ret = theora_push_buffer (enc, buf)) != GST_FLOW_OK) {
1366 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1367 g_slist_free (buffers);
1372 enc->granulepos_offset =
1373 gst_util_uint64_scale (running_time, enc->vinfo.fps_n,
1374 GST_SECOND * enc->vinfo.fps_d);
1375 enc->timestamp_offset = running_time;
1379 ret = theora_enc_encode_and_push (enc, op, timestamp, running_time, duration,
1385 header_buffer_alloc:
1387 gst_buffer_unref (buffer);
1392 gst_buffer_unref (buffer);
1397 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1398 ("libtheora has been compiled with the encoder disabled"));
1399 gst_buffer_unref (buffer);
1400 return GST_FLOW_ERROR;
1404 static GstStateChangeReturn
1405 theora_enc_change_state (GstElement * element, GstStateChange transition)
1408 GstStateChangeReturn ret;
1411 enc = GST_THEORA_ENC (element);
1413 switch (transition) {
1414 case GST_STATE_CHANGE_NULL_TO_READY:
1415 th_ctx = dummy_encode_ctx ();
1417 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1418 ("libtheora has been compiled with the encoder disabled"));
1419 return GST_STATE_CHANGE_FAILURE;
1421 th_encode_free (th_ctx);
1423 case GST_STATE_CHANGE_READY_TO_PAUSED:
1424 GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state");
1425 th_info_init (&enc->info);
1426 th_comment_init (&enc->comment);
1428 enc->force_keyframe = FALSE;
1430 if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) {
1433 if (!enc->multipass_cache_file) {
1434 ret = GST_STATE_CHANGE_FAILURE;
1435 GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
1438 enc->multipass_cache_fd =
1439 g_io_channel_new_file (enc->multipass_cache_file,
1440 (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"),
1443 if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS)
1444 enc->multipass_cache_adapter = gst_adapter_new ();
1446 if (!enc->multipass_cache_fd) {
1447 ret = GST_STATE_CHANGE_FAILURE;
1448 GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL),
1449 ("Failed to open multipass cache file: %s", err->message));
1454 g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL);
1457 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1463 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1465 switch (transition) {
1466 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1468 case GST_STATE_CHANGE_PAUSED_TO_READY:
1469 GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state");
1471 th_encode_free (enc->encoder);
1472 enc->encoder = NULL;
1474 th_comment_clear (&enc->comment);
1475 th_info_clear (&enc->info);
1477 theora_enc_clear (enc);
1478 enc->initialised = FALSE;
1480 case GST_STATE_CHANGE_READY_TO_NULL:
1490 theora_enc_set_property (GObject * object, guint prop_id,
1491 const GValue * value, GParamSpec * pspec)
1493 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1499 case PROP_KEYFRAME_THRESHOLD:
1500 case PROP_KEYFRAME_MINDISTANCE:
1501 case PROP_NOISE_SENSITIVITY:
1502 case PROP_SHARPNESS:
1503 /* kept for API compat, but ignored */
1504 GST_WARNING_OBJECT (object, "Obsolete property '%s' ignored",
1508 GST_OBJECT_LOCK (enc);
1509 enc->video_bitrate = g_value_get_int (value) * 1000;
1510 enc->bitrate_changed = TRUE;
1511 GST_OBJECT_UNLOCK (enc);
1514 GST_OBJECT_LOCK (enc);
1515 if (GST_STATE (enc) >= GST_STATE_PAUSED && enc->video_bitrate > 0) {
1516 GST_WARNING_OBJECT (object, "Can't change from bitrate to quality mode"
1519 enc->video_quality = g_value_get_int (value);
1520 enc->video_bitrate = 0;
1521 enc->quality_changed = TRUE;
1523 GST_OBJECT_UNLOCK (enc);
1525 case PROP_KEYFRAME_AUTO:
1526 enc->keyframe_auto = g_value_get_boolean (value);
1528 case PROP_KEYFRAME_FREQ:
1529 enc->keyframe_freq = g_value_get_int (value);
1531 case PROP_KEYFRAME_FREQ_FORCE:
1532 enc->keyframe_force = g_value_get_int (value);
1534 case PROP_SPEEDLEVEL:
1535 enc->speed_level = g_value_get_int (value);
1537 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
1538 sizeof (enc->speed_level));
1541 case PROP_VP3_COMPATIBLE:
1542 enc->vp3_compatible = g_value_get_boolean (value);
1544 case PROP_DROP_FRAMES:
1545 enc->drop_frames = g_value_get_boolean (value);
1547 case PROP_CAP_OVERFLOW:
1548 enc->cap_overflow = g_value_get_boolean (value);
1550 case PROP_CAP_UNDERFLOW:
1551 enc->cap_underflow = g_value_get_boolean (value);
1553 case PROP_RATE_BUFFER:
1554 enc->rate_buffer = g_value_get_int (value);
1556 case PROP_MULTIPASS_CACHE_FILE:
1557 enc->multipass_cache_file = g_value_dup_string (value);
1559 case PROP_MULTIPASS_MODE:
1560 enc->multipass_mode = g_value_get_enum (value);
1563 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1569 theora_enc_get_property (GObject * object, guint prop_id,
1570 GValue * value, GParamSpec * pspec)
1572 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1576 g_value_set_boolean (value, TRUE);
1579 g_value_set_enum (value, BORDER_BLACK);
1582 GST_OBJECT_LOCK (enc);
1583 g_value_set_int (value, enc->video_bitrate / 1000);
1584 GST_OBJECT_UNLOCK (enc);
1587 GST_OBJECT_LOCK (enc);
1588 g_value_set_int (value, enc->video_quality);
1589 GST_OBJECT_UNLOCK (enc);
1592 g_value_set_boolean (value, TRUE);
1594 case PROP_KEYFRAME_AUTO:
1595 g_value_set_boolean (value, enc->keyframe_auto);
1597 case PROP_KEYFRAME_FREQ:
1598 g_value_set_int (value, enc->keyframe_freq);
1600 case PROP_KEYFRAME_FREQ_FORCE:
1601 g_value_set_int (value, enc->keyframe_force);
1603 case PROP_KEYFRAME_THRESHOLD:
1604 g_value_set_int (value, 80);
1606 case PROP_KEYFRAME_MINDISTANCE:
1607 g_value_set_int (value, 8);
1609 case PROP_NOISE_SENSITIVITY:
1610 g_value_set_int (value, 1);
1612 case PROP_SHARPNESS:
1613 g_value_set_int (value, 0);
1615 case PROP_SPEEDLEVEL:
1616 g_value_set_int (value, enc->speed_level);
1618 case PROP_VP3_COMPATIBLE:
1619 g_value_set_boolean (value, enc->vp3_compatible);
1621 case PROP_DROP_FRAMES:
1622 g_value_set_boolean (value, enc->drop_frames);
1624 case PROP_CAP_OVERFLOW:
1625 g_value_set_boolean (value, enc->cap_overflow);
1627 case PROP_CAP_UNDERFLOW:
1628 g_value_set_boolean (value, enc->cap_underflow);
1630 case PROP_RATE_BUFFER:
1631 g_value_set_int (value, enc->rate_buffer);
1633 case PROP_MULTIPASS_CACHE_FILE:
1634 g_value_set_string (value, enc->multipass_cache_file);
1636 case PROP_MULTIPASS_MODE:
1637 g_value_set_enum (value, enc->multipass_mode);
1640 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);