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")
246 #define gst_theora_enc_parent_class parent_class
247 G_DEFINE_TYPE_WITH_CODE (GstTheoraEnc, gst_theora_enc,
248 GST_TYPE_ELEMENT, G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
250 static GstCaps *theora_enc_src_caps;
252 static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event);
253 static gboolean theora_enc_src_event (GstPad * pad, GstEvent * event);
254 static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
255 static GstStateChangeReturn theora_enc_change_state (GstElement * element,
256 GstStateChange transition);
257 static GstCaps *theora_enc_sink_getcaps (GstPad * pad, GstCaps * filter);
258 static gboolean theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
259 static void theora_enc_get_property (GObject * object, guint prop_id,
260 GValue * value, GParamSpec * pspec);
261 static void theora_enc_set_property (GObject * object, guint prop_id,
262 const GValue * value, GParamSpec * pspec);
263 static void theora_enc_finalize (GObject * object);
265 static gboolean theora_enc_write_multipass_cache (GstTheoraEnc * enc,
266 gboolean begin, gboolean eos);
268 static char *theora_enc_get_supported_formats (void);
271 gst_theora_enc_class_init (GstTheoraEncClass * klass)
273 GObjectClass *gobject_class = (GObjectClass *) klass;
274 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
277 /* query runtime encoder properties */
279 int default_speed_level = THEORA_DEF_SPEEDLEVEL;
280 int max_speed_level = default_speed_level;
282 GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
284 th_ctx = dummy_encode_ctx ();
286 if (!check_speed_level (th_ctx, &default_speed_level, &max_speed_level))
288 ("Failed to determine settings for the speed-level property.");
289 th_encode_free (th_ctx);
292 gobject_class->set_property = theora_enc_set_property;
293 gobject_class->get_property = theora_enc_get_property;
294 gobject_class->finalize = theora_enc_finalize;
296 g_object_class_install_property (gobject_class, PROP_CENTER,
297 g_param_spec_boolean ("center", "Center",
298 "ignored and kept for API compat only", TRUE,
299 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
300 g_object_class_install_property (gobject_class, PROP_BORDER,
301 g_param_spec_enum ("border", "Border",
302 "ignored and kept for API compat only",
303 GST_TYPE_BORDER_MODE, BORDER_BLACK,
304 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
305 /* general encoding stream options */
306 g_object_class_install_property (gobject_class, PROP_BITRATE,
307 g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
308 0, (1 << 24) - 1, THEORA_DEF_BITRATE,
309 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
310 GST_PARAM_MUTABLE_PLAYING));
311 g_object_class_install_property (gobject_class, PROP_QUALITY,
312 g_param_spec_int ("quality", "Quality", "Video quality", 0, 63,
314 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
315 GST_PARAM_MUTABLE_PLAYING));
316 g_object_class_install_property (gobject_class, PROP_QUICK,
317 g_param_spec_boolean ("quick", "Quick",
318 "ignored and kept for API compat only", TRUE,
319 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
320 g_object_class_install_property (gobject_class, PROP_KEYFRAME_AUTO,
321 g_param_spec_boolean ("keyframe-auto", "Keyframe Auto",
322 "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO,
323 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
324 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ,
325 g_param_spec_int ("keyframe-freq", "Keyframe frequency",
326 "Keyframe frequency", 1, 32768, THEORA_DEF_KEYFRAME_FREQ,
327 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
328 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ_FORCE,
329 g_param_spec_int ("keyframe-force", "Keyframe force",
330 "Force keyframe every N frames", 1, 32768,
331 THEORA_DEF_KEYFRAME_FREQ_FORCE,
332 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
333 g_object_class_install_property (gobject_class, PROP_KEYFRAME_THRESHOLD,
334 g_param_spec_int ("keyframe-threshold", "Keyframe threshold",
335 "ignored and kept for API compat only", 0, 32768, 80,
336 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
337 g_object_class_install_property (gobject_class, PROP_KEYFRAME_MINDISTANCE,
338 g_param_spec_int ("keyframe-mindistance", "Keyframe mindistance",
339 "ignored and kept for API compat only", 1, 32768, 8,
340 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
341 g_object_class_install_property (gobject_class, PROP_NOISE_SENSITIVITY,
342 g_param_spec_int ("noise-sensitivity", "Noise sensitivity",
343 "ignored and kept for API compat only", 0, 32768, 1,
344 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
345 g_object_class_install_property (gobject_class, PROP_SHARPNESS,
346 g_param_spec_int ("sharpness", "Sharpness",
347 "ignored and kept for API compat only", 0, 2, 0,
348 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
349 g_object_class_install_property (gobject_class, PROP_SPEEDLEVEL,
350 g_param_spec_int ("speed-level", "Speed level",
351 "Controls the amount of analysis performed when encoding."
352 " Higher values trade compression quality for speed."
353 " This property requires libtheora version >= 1.0"
354 ", and the maximum value may vary based on encoder version.",
355 0, max_speed_level, default_speed_level,
356 (GParamFlags) G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
357 G_PARAM_STATIC_STRINGS));
358 g_object_class_install_property (gobject_class, PROP_VP3_COMPATIBLE,
359 g_param_spec_boolean ("vp3-compatible", "VP3 Compatible",
360 "Disables non-VP3 compatible features",
361 THEORA_DEF_VP3_COMPATIBLE,
362 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
363 g_object_class_install_property (gobject_class, PROP_DROP_FRAMES,
364 g_param_spec_boolean ("drop-frames", "VP3 Compatible",
365 "Allow or disallow frame dropping",
366 THEORA_DEF_DROP_FRAMES,
367 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
368 g_object_class_install_property (gobject_class, PROP_CAP_OVERFLOW,
369 g_param_spec_boolean ("cap-overflow", "VP3 Compatible",
370 "Enable capping of bit reservoir overflows",
371 THEORA_DEF_CAP_OVERFLOW,
372 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
373 g_object_class_install_property (gobject_class, PROP_CAP_UNDERFLOW,
374 g_param_spec_boolean ("cap-underflow", "VP3 Compatible",
375 "Enable capping of bit reservoir underflows",
376 THEORA_DEF_CAP_UNDERFLOW,
377 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
378 g_object_class_install_property (gobject_class, PROP_RATE_BUFFER,
379 g_param_spec_int ("rate-buffer", "Rate Control Buffer",
380 "Sets the size of the rate control buffer, in units of frames. "
381 "The default value of 0 instructs the encoder to automatically "
382 "select an appropriate value",
383 0, 1000, THEORA_DEF_RATE_BUFFER,
384 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
385 g_object_class_install_property (gobject_class, PROP_MULTIPASS_CACHE_FILE,
386 g_param_spec_string ("multipass-cache-file", "Multipass Cache File",
387 "Multipass cache file", THEORA_DEF_MULTIPASS_CACHE_FILE,
388 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
389 g_object_class_install_property (gobject_class, PROP_MULTIPASS_MODE,
390 g_param_spec_enum ("multipass-mode", "Multipass mode",
391 "Single pass or first/second pass", GST_TYPE_MULTIPASS_MODE,
392 THEORA_DEF_MULTIPASS_MODE,
393 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
395 gst_element_class_add_pad_template (gstelement_class,
396 gst_static_pad_template_get (&theora_enc_src_factory));
397 gst_element_class_add_pad_template (gstelement_class,
398 gst_static_pad_template_get (&theora_enc_sink_factory));
399 gst_element_class_set_details_simple (gstelement_class,
400 "Theora video encoder", "Codec/Encoder/Video",
401 "encode raw YUV video to a theora stream",
402 "Wim Taymans <wim@fluendo.com>");
404 caps_string = g_strdup_printf ("video/x-raw-yuv, "
405 "format = (fourcc) { %s }, "
406 "framerate = (fraction) [1/MAX, MAX], "
407 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]",
408 theora_enc_get_supported_formats ());
409 theora_enc_src_caps = gst_caps_from_string (caps_string);
410 g_free (caps_string);
412 gstelement_class->change_state = theora_enc_change_state;
416 gst_theora_enc_init (GstTheoraEnc * enc)
419 gst_pad_new_from_static_template (&theora_enc_sink_factory, "sink");
420 gst_pad_set_chain_function (enc->sinkpad, theora_enc_chain);
421 gst_pad_set_event_function (enc->sinkpad, theora_enc_sink_event);
422 gst_pad_set_getcaps_function (enc->sinkpad, theora_enc_sink_getcaps);
423 gst_pad_set_setcaps_function (enc->sinkpad, theora_enc_sink_setcaps);
424 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
427 gst_pad_new_from_static_template (&theora_enc_src_factory, "src");
428 gst_pad_set_event_function (enc->srcpad, theora_enc_src_event);
429 gst_pad_use_fixed_caps (enc->srcpad);
430 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
432 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
434 enc->video_bitrate = THEORA_DEF_BITRATE;
435 enc->video_quality = THEORA_DEF_QUALITY;
436 enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
437 enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ;
438 enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE;
440 enc->expected_ts = GST_CLOCK_TIME_NONE;
442 /* enc->speed_level is set to the libtheora default by the constructor */
443 enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE;
444 enc->drop_frames = THEORA_DEF_DROP_FRAMES;
445 enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW;
446 enc->cap_underflow = THEORA_DEF_CAP_UNDERFLOW;
447 enc->rate_buffer = THEORA_DEF_RATE_BUFFER;
449 enc->multipass_mode = THEORA_DEF_MULTIPASS_MODE;
450 enc->multipass_cache_file = THEORA_DEF_MULTIPASS_CACHE_FILE;
454 theora_enc_clear_multipass_cache (GstTheoraEnc * enc)
456 if (enc->multipass_cache_fd) {
457 g_io_channel_shutdown (enc->multipass_cache_fd, TRUE, NULL);
458 g_io_channel_unref (enc->multipass_cache_fd);
459 enc->multipass_cache_fd = NULL;
462 if (enc->multipass_cache_adapter) {
463 gst_object_unref (enc->multipass_cache_adapter);
464 enc->multipass_cache_adapter = NULL;
469 theora_enc_finalize (GObject * object)
471 GstTheoraEnc *enc = GST_THEORA_ENC (object);
473 GST_DEBUG_OBJECT (enc, "Finalizing");
475 th_encode_free (enc->encoder);
476 th_comment_clear (&enc->comment);
477 th_info_clear (&enc->info);
478 g_free (enc->multipass_cache_file);
480 theora_enc_clear_multipass_cache (enc);
482 G_OBJECT_CLASS (parent_class)->finalize (object);
486 theora_enc_reset (GstTheoraEnc * enc)
488 ogg_uint32_t keyframe_force;
491 GST_OBJECT_LOCK (enc);
492 enc->info.target_bitrate = enc->video_bitrate;
493 enc->info.quality = enc->video_quality;
494 enc->bitrate_changed = FALSE;
495 enc->quality_changed = FALSE;
496 GST_OBJECT_UNLOCK (enc);
499 th_encode_free (enc->encoder);
500 enc->encoder = th_encode_alloc (&enc->info);
501 /* We ensure this function cannot fail. */
502 g_assert (enc->encoder != NULL);
503 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
504 sizeof (enc->speed_level));
505 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_VP3_COMPATIBLE,
506 &enc->vp3_compatible, sizeof (enc->vp3_compatible));
509 if (enc->drop_frames)
510 rate_flags |= TH_RATECTL_DROP_FRAMES;
511 if (enc->drop_frames)
512 rate_flags |= TH_RATECTL_CAP_OVERFLOW;
513 if (enc->drop_frames)
514 rate_flags |= TH_RATECTL_CAP_UNDERFLOW;
515 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_FLAGS,
516 &rate_flags, sizeof (rate_flags));
518 if (enc->rate_buffer) {
519 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_BUFFER,
520 &enc->rate_buffer, sizeof (enc->rate_buffer));
525 keyframe_force = enc->keyframe_auto ?
526 enc->keyframe_force : enc->keyframe_freq;
527 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
528 &keyframe_force, sizeof (keyframe_force));
530 /* Get placeholder data */
531 if (enc->multipass_cache_fd
532 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
533 theora_enc_write_multipass_cache (enc, TRUE, FALSE);
537 theora_enc_clear (GstTheoraEnc * enc)
541 enc->granulepos_offset = 0;
542 enc->timestamp_offset = 0;
544 enc->next_ts = GST_CLOCK_TIME_NONE;
545 enc->next_discont = FALSE;
546 enc->expected_ts = GST_CLOCK_TIME_NONE;
550 theora_enc_get_supported_formats (void)
556 th_pixel_fmt pixelformat;
560 TH_PF_420, "I420"}, {
561 TH_PF_422, "Y42B"}, {
564 GString *string = NULL;
567 th_info_init (&info);
568 info.frame_width = 16;
569 info.frame_height = 16;
570 info.fps_numerator = 25;
571 info.fps_denominator = 1;
572 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
573 info.pixel_fmt = formats[i].pixelformat;
575 encoder = th_encode_alloc (&info);
579 GST_LOG ("format %s is supported", formats[i].fourcc);
580 th_encode_free (encoder);
582 if (string == NULL) {
583 string = g_string_new (formats[i].fourcc);
585 g_string_append (string, ", ");
586 g_string_append (string, formats[i].fourcc);
589 th_info_clear (&info);
591 return string == NULL ? NULL : g_string_free (string, FALSE);
595 theora_enc_sink_getcaps (GstPad * pad, GstCaps * filter)
597 GstTheoraEnc *encoder;
601 /* If we already have caps return them */
602 if ((caps = gst_pad_get_current_caps (pad)) != NULL)
605 encoder = GST_THEORA_ENC (gst_pad_get_parent (pad));
607 return gst_caps_new_empty ();
609 peer = gst_pad_get_peer (encoder->srcpad);
611 const GstCaps *templ_caps;
616 peer_caps = gst_pad_get_caps (peer, NULL);
618 /* Translate peercaps to YUV */
619 peer_caps = gst_caps_make_writable (peer_caps);
620 n = gst_caps_get_size (peer_caps);
621 for (i = 0; i < n; i++) {
622 s = gst_caps_get_structure (peer_caps, i);
624 gst_structure_set_name (s, "video/x-raw-yuv");
625 gst_structure_remove_field (s, "streamheader");
628 templ_caps = gst_pad_get_pad_template_caps (pad);
630 caps = gst_caps_intersect (peer_caps, templ_caps);
631 caps = gst_caps_intersect (caps, theora_enc_src_caps);
632 gst_caps_unref (peer_caps);
633 gst_object_unref (peer);
636 caps = gst_caps_ref (theora_enc_src_caps);
639 gst_object_unref (encoder);
642 GstCaps *intersection;
645 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
646 gst_caps_unref (caps);
654 theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
656 GstStructure *structure = gst_caps_get_structure (caps, 0);
657 GstTheoraEnc *enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
662 gst_structure_get_fourcc (structure, "format", &fourcc);
663 gst_structure_get_int (structure, "width", &enc->width);
664 gst_structure_get_int (structure, "height", &enc->height);
665 gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d);
666 par = gst_structure_get_value (structure, "pixel-aspect-ratio");
668 th_info_clear (&enc->info);
669 th_info_init (&enc->info);
670 /* Theora has a divisible-by-sixteen restriction for the encoded video size but
671 * we can define a picture area using pic_width/pic_height */
672 enc->info.frame_width = GST_ROUND_UP_16 (enc->width);
673 enc->info.frame_height = GST_ROUND_UP_16 (enc->height);
674 enc->info.pic_width = enc->width;
675 enc->info.pic_height = enc->height;
677 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
678 enc->info.pixel_fmt = TH_PF_420;
680 case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
681 enc->info.pixel_fmt = TH_PF_422;
683 case GST_MAKE_FOURCC ('Y', '4', '4', '4'):
684 enc->info.pixel_fmt = TH_PF_444;
687 g_assert_not_reached ();
690 enc->info.fps_numerator = enc->fps_n = fps_n;
691 enc->info.fps_denominator = enc->fps_d = fps_d;
693 enc->info.aspect_numerator = gst_value_get_fraction_numerator (par);
694 enc->par_n = gst_value_get_fraction_numerator (par);
695 enc->info.aspect_denominator = gst_value_get_fraction_denominator (par);
696 enc->par_d = gst_value_get_fraction_denominator (par);
698 /* setting them to 0 indicates that the decoder can chose a good aspect
699 * ratio, defaulting to 1/1 */
700 enc->info.aspect_numerator = 0;
702 enc->info.aspect_denominator = 0;
706 enc->info.colorspace = TH_CS_UNSPECIFIED;
708 /* as done in theora */
709 enc->info.keyframe_granule_shift = _ilog (enc->keyframe_force - 1);
710 GST_DEBUG_OBJECT (enc,
711 "keyframe_frequency_force is %d, granule shift is %d",
712 enc->keyframe_force, enc->info.keyframe_granule_shift);
714 theora_enc_reset (enc);
715 enc->initialised = TRUE;
717 gst_object_unref (enc);
723 granulepos_add (guint64 granulepos, guint64 addend, gint shift)
725 guint64 iframe, pframe;
727 iframe = granulepos >> shift;
728 pframe = granulepos - (iframe << shift);
731 return (iframe << shift) + pframe;
734 /* prepare a buffer for transmission by passing data through libtheora */
736 theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
737 GstClockTime timestamp, GstClockTime running_time,
738 GstClockTime duration, GstBuffer ** buffer)
741 GstFlowReturn ret = GST_FLOW_OK;
743 buf = gst_buffer_new_and_alloc (packet->bytes);
745 GST_WARNING_OBJECT (enc, "Could not allocate buffer");
746 ret = GST_FLOW_ERROR;
750 gst_buffer_fill (buf, 0, packet->packet, packet->bytes);
751 /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
752 * time representation */
753 GST_BUFFER_OFFSET_END (buf) =
754 granulepos_add (packet->granulepos, enc->granulepos_offset,
755 enc->info.keyframe_granule_shift);
756 GST_BUFFER_OFFSET (buf) = granulepos_to_timestamp (enc,
757 GST_BUFFER_OFFSET_END (buf));
759 GST_BUFFER_TIMESTAMP (buf) = timestamp;
760 GST_BUFFER_DURATION (buf) = duration;
762 if (enc->next_discont) {
763 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
764 enc->next_discont = FALSE;
767 /* the second most significant bit of the first data byte is cleared
769 if (packet->bytes > 0 && (packet->packet[0] & 0x40) == 0) {
770 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
772 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
781 /* push out the buffer and do internal bookkeeping */
783 theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
787 enc->bytes_out += gst_buffer_get_size (buffer);
789 ret = gst_pad_push (enc->srcpad, buffer);
795 theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet,
796 GstClockTime timestamp, GstClockTime running_time, GstClockTime duration)
802 theora_buffer_from_packet (enc, packet, timestamp, running_time, duration,
804 if (ret == GST_FLOW_OK)
805 ret = theora_push_buffer (enc, buf);
811 theora_set_header_on_caps (GstCaps * caps, GSList * buffers)
813 GstStructure *structure;
814 GValue array = { 0 };
815 GValue value = { 0 };
819 caps = gst_caps_make_writable (caps);
820 structure = gst_caps_get_structure (caps, 0);
822 /* put copies of the buffers in a fixed list */
823 g_value_init (&array, GST_TYPE_ARRAY);
825 for (walk = buffers; walk; walk = walk->next) {
829 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
831 /* Copy buffer, because we can't use the original -
832 * it creates a circular refcount with the caps<->buffers */
833 buffer = gst_buffer_copy (buffer);
835 g_value_init (&value, GST_TYPE_BUFFER);
836 gst_value_set_buffer (&value, buffer);
837 gst_value_array_append_value (&array, &value);
838 g_value_unset (&value);
841 gst_buffer_unref (buffer);
844 gst_structure_set_value (structure, "streamheader", &array);
845 g_value_unset (&array);
851 theora_enc_force_keyframe (GstTheoraEnc * enc)
853 GstClockTime next_ts;
855 /* make sure timestamps increment after resetting the decoder */
856 next_ts = enc->next_ts + enc->timestamp_offset;
858 theora_enc_reset (enc);
859 enc->granulepos_offset =
860 gst_util_uint64_scale (next_ts, enc->fps_n, GST_SECOND * enc->fps_d);
861 enc->timestamp_offset = next_ts;
866 theora_enc_sink_event (GstPad * pad, GstEvent * event)
872 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
874 switch (GST_EVENT_TYPE (event)) {
875 case GST_EVENT_SEGMENT:
877 gst_event_copy_segment (event, &enc->segment);
879 res = gst_pad_push_event (enc->srcpad, event);
883 if (enc->initialised) {
884 /* push last packet with eos flag, should not be called */
885 while (th_encode_packetout (enc->encoder, 1, &op)) {
886 GstClockTime next_time =
887 th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
889 theora_push_packet (enc, &op, GST_CLOCK_TIME_NONE, enc->next_ts,
890 next_time - enc->next_ts);
891 enc->next_ts = next_time;
894 if (enc->initialised && enc->multipass_cache_fd
895 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
896 theora_enc_write_multipass_cache (enc, TRUE, TRUE);
898 theora_enc_clear_multipass_cache (enc);
900 res = gst_pad_push_event (enc->srcpad, event);
902 case GST_EVENT_FLUSH_STOP:
903 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
904 res = gst_pad_push_event (enc->srcpad, event);
906 case GST_EVENT_CUSTOM_DOWNSTREAM:
908 const GstStructure *s;
910 s = gst_event_get_structure (event);
912 if (gst_structure_has_name (s, "GstForceKeyUnit"))
913 theora_enc_force_keyframe (enc);
914 res = gst_pad_push_event (enc->srcpad, event);
918 res = gst_pad_push_event (enc->srcpad, event);
925 theora_enc_src_event (GstPad * pad, GstEvent * event)
930 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
932 switch (GST_EVENT_TYPE (event)) {
933 case GST_EVENT_CUSTOM_UPSTREAM:
935 const GstStructure *s;
937 s = gst_event_get_structure (event);
939 if (gst_structure_has_name (s, "GstForceKeyUnit")) {
940 GST_OBJECT_LOCK (enc);
941 enc->force_keyframe = TRUE;
942 GST_OBJECT_UNLOCK (enc);
943 /* consume the event */
945 gst_event_unref (event);
947 res = gst_pad_push_event (enc->sinkpad, event);
952 res = gst_pad_push_event (enc->sinkpad, event);
960 theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp,
961 GstClockTime duration)
963 GstClockTimeDiff max_diff;
964 gboolean ret = FALSE;
966 /* Allow 3/4 a frame off */
967 max_diff = (enc->info.fps_denominator * GST_SECOND * 3) /
968 (enc->info.fps_numerator * 4);
970 if (timestamp != GST_CLOCK_TIME_NONE
971 && enc->expected_ts != GST_CLOCK_TIME_NONE) {
972 if ((GstClockTimeDiff) (timestamp - enc->expected_ts) > max_diff) {
973 GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT
974 " exceeds expected value %" GST_TIME_FORMAT
975 " by too much, marking discontinuity",
976 GST_TIME_ARGS (timestamp), GST_TIME_ARGS (enc->expected_ts));
981 if (GST_CLOCK_TIME_IS_VALID (duration))
982 enc->expected_ts = timestamp + duration;
984 enc->expected_ts = GST_CLOCK_TIME_NONE;
990 theora_enc_init_buffer (th_ycbcr_buffer buf, th_info * info, guint8 * data)
992 GstVideoFormat format;
995 switch (info->pixel_fmt) {
997 format = GST_VIDEO_FORMAT_Y444;
1000 format = GST_VIDEO_FORMAT_I420;
1003 format = GST_VIDEO_FORMAT_Y42B;
1006 g_assert_not_reached ();
1009 /* According to Theora developer Timothy Terriberry, the Theora
1010 * encoder will not use memory outside of pic_width/height, even when
1011 * the frame size is bigger. The values outside this region will be encoded
1012 * to default values.
1013 * Due to this, setting the frame's width/height as the buffer width/height
1014 * is perfectly ok, even though it does not strictly look ok.
1016 for (i = 0; i < 3; i++) {
1018 gst_video_format_get_component_width (format, i, info->frame_width);
1020 gst_video_format_get_component_height (format, i, info->frame_height);
1023 data + gst_video_format_get_component_offset (format, i,
1024 info->pic_width, info->pic_height);
1026 gst_video_format_get_row_stride (format, i, info->pic_width);
1031 theora_enc_read_multipass_cache (GstTheoraEnc * enc)
1033 GstBuffer *cache_buf;
1034 const guint8 *cache_data;
1035 gsize bytes_read = 0;
1036 gint bytes_consumed = 0;
1037 GIOStatus stat = G_IO_STATUS_NORMAL;
1038 gboolean done = FALSE;
1041 if (gst_adapter_available (enc->multipass_cache_adapter) == 0) {
1045 cache_buf = gst_buffer_new_and_alloc (512);
1047 data = gst_buffer_map (cache_buf, &size, NULL, GST_MAP_READ);
1048 stat = g_io_channel_read_chars (enc->multipass_cache_fd,
1049 (gchar *) data, size, &bytes_read, NULL);
1051 if (bytes_read <= 0) {
1052 gst_buffer_unmap (cache_buf, data, 0);
1053 gst_buffer_unref (cache_buf);
1056 gst_buffer_unmap (cache_buf, data, bytes_read);
1057 gst_adapter_push (enc->multipass_cache_adapter, cache_buf);
1060 if (gst_adapter_available (enc->multipass_cache_adapter) == 0)
1064 MIN (gst_adapter_available (enc->multipass_cache_adapter), 512);
1066 cache_data = gst_adapter_map (enc->multipass_cache_adapter, bytes_read);
1069 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data,
1071 gst_adapter_unmap (enc->multipass_cache_adapter, 0);
1073 done = bytes_consumed <= 0;
1074 if (bytes_consumed > 0)
1075 gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed);
1078 if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_EOF && bytes_read == 0)
1079 || bytes_consumed < 0) {
1080 GST_ELEMENT_ERROR (enc, RESOURCE, READ, (NULL),
1081 ("Failed to read multipass cache file"));
1088 theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin,
1092 GIOStatus stat = G_IO_STATUS_NORMAL;
1093 gint bytes_read = 0;
1094 gsize bytes_written = 0;
1098 stat = g_io_channel_seek_position (enc->multipass_cache_fd, 0, G_SEEK_SET,
1100 if (stat != G_IO_STATUS_ERROR) {
1103 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_OUT, &buf, sizeof (buf));
1105 g_io_channel_write_chars (enc->multipass_cache_fd, buf, bytes_read,
1106 &bytes_written, NULL);
1107 } while (bytes_read > 0 && bytes_written > 0);
1111 if (stat == G_IO_STATUS_ERROR || bytes_read < 0) {
1114 GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL),
1115 ("Failed to seek to beginning of multipass cache file: %s",
1118 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1119 ("Failed to seek to beginning of multipass cache file: %s",
1122 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1123 ("Failed to write multipass cache file"));
1133 static GstFlowReturn
1134 theora_enc_encode_and_push (GstTheoraEnc * enc, ogg_packet op,
1135 GstClockTime timestamp, GstClockTime running_time,
1136 GstClockTime duration, GstBuffer * buffer)
1139 th_ycbcr_buffer ycbcr;
1144 data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
1145 theora_enc_init_buffer (ycbcr, &enc->info, data);
1147 if (theora_enc_is_discontinuous (enc, running_time, duration)) {
1148 theora_enc_reset (enc);
1149 enc->granulepos_offset =
1150 gst_util_uint64_scale (running_time, enc->fps_n,
1151 GST_SECOND * enc->fps_d);
1152 enc->timestamp_offset = running_time;
1154 enc->next_discont = TRUE;
1157 if (enc->multipass_cache_fd
1158 && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
1159 if (!theora_enc_read_multipass_cache (enc)) {
1160 ret = GST_FLOW_ERROR;
1161 goto multipass_read_failed;
1165 res = th_encode_ycbcr_in (enc->encoder, ycbcr);
1166 /* none of the failure cases can happen here */
1167 g_assert (res == 0);
1169 if (enc->multipass_cache_fd
1170 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
1171 if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
1172 ret = GST_FLOW_ERROR;
1173 goto multipass_write_failed;
1178 while (th_encode_packetout (enc->encoder, 0, &op)) {
1179 GstClockTime next_time;
1181 next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
1184 theora_push_packet (enc, &op, timestamp, enc->next_ts,
1185 next_time - enc->next_ts);
1187 enc->next_ts = next_time;
1188 if (ret != GST_FLOW_OK)
1193 gst_buffer_unmap (buffer, data, size);
1194 gst_buffer_unref (buffer);
1199 multipass_read_failed:
1201 GST_DEBUG_OBJECT (enc, "multipass read failed");
1204 multipass_write_failed:
1206 GST_DEBUG_OBJECT (enc, "multipass write failed");
1211 GST_DEBUG_OBJECT (enc, "error pushing buffer: %s", gst_flow_get_name (ret));
1216 static GstFlowReturn
1217 theora_enc_chain (GstPad * pad, GstBuffer * buffer)
1221 GstClockTime timestamp, duration, running_time;
1223 gboolean force_keyframe;
1225 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
1227 /* we keep track of two timelines.
1228 * - The timestamps from the incomming buffers, which we copy to the outgoing
1229 * encoded buffers as-is. We need to do this as we simply forward the
1230 * newsegment events.
1231 * - The running_time of the buffers, which we use to construct the granulepos
1234 timestamp = GST_BUFFER_TIMESTAMP (buffer);
1235 duration = GST_BUFFER_DURATION (buffer);
1238 gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
1239 if ((gint64) running_time < 0) {
1240 GST_DEBUG_OBJECT (enc, "Dropping buffer, timestamp: %" GST_TIME_FORMAT,
1241 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
1242 gst_buffer_unref (buffer);
1246 GST_OBJECT_LOCK (enc);
1247 if (enc->bitrate_changed) {
1248 long int bitrate = enc->video_bitrate;
1250 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
1252 enc->bitrate_changed = FALSE;
1255 if (enc->quality_changed) {
1256 long int quality = enc->video_quality;
1258 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
1260 enc->quality_changed = FALSE;
1263 /* see if we need to schedule a keyframe */
1264 force_keyframe = enc->force_keyframe;
1265 enc->force_keyframe = FALSE;
1266 GST_OBJECT_UNLOCK (enc);
1268 if (force_keyframe) {
1269 GstClockTime stream_time;
1272 stream_time = gst_segment_to_stream_time (&enc->segment,
1273 GST_FORMAT_TIME, timestamp);
1275 s = gst_structure_new ("GstForceKeyUnit",
1276 "timestamp", G_TYPE_UINT64, timestamp,
1277 "stream-time", G_TYPE_UINT64, stream_time,
1278 "running-time", G_TYPE_UINT64, running_time, NULL);
1280 theora_enc_force_keyframe (enc);
1282 gst_pad_push_event (enc->srcpad,
1283 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
1286 /* make sure we copy the discont flag to the next outgoing buffer when it's
1287 * set on the incomming buffer */
1288 if (GST_BUFFER_IS_DISCONT (buffer)) {
1289 enc->next_discont = TRUE;
1292 if (enc->packetno == 0) {
1293 /* no packets written yet, setup headers */
1296 GSList *buffers = NULL;
1299 enc->granulepos_offset = 0;
1300 enc->timestamp_offset = 0;
1302 GST_DEBUG_OBJECT (enc, "output headers");
1303 /* Theora streams begin with three headers; the initial header (with
1304 most of the codec setup parameters) which is mandated by the Ogg
1305 bitstream spec. The second header holds any comment fields. The
1306 third header holds the bitstream codebook. We merely need to
1307 make the headers, then pass them to libtheora one at a time;
1308 libtheora handles the additional Ogg bitstream constraints */
1310 /* create the remaining theora headers */
1311 th_comment_clear (&enc->comment);
1312 th_comment_init (&enc->comment);
1315 th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
1317 theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
1318 GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf);
1319 if (ret != GST_FLOW_OK) {
1320 goto header_buffer_alloc;
1322 buffers = g_slist_prepend (buffers, buf);
1325 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1326 g_slist_free (buffers);
1327 goto encoder_disabled;
1330 buffers = g_slist_reverse (buffers);
1332 /* mark buffers and put on caps */
1333 caps = gst_caps_new_simple ("video/x-theora",
1334 "width", G_TYPE_INT, enc->width,
1335 "height", G_TYPE_INT, enc->height,
1336 "framerate", GST_TYPE_FRACTION, enc->fps_n, enc->fps_d,
1337 "pixel-aspect-ratio", GST_TYPE_FRACTION, enc->par_n, enc->par_d, NULL);
1338 caps = theora_set_header_on_caps (caps, buffers);
1339 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
1340 gst_pad_set_caps (enc->srcpad, caps);
1341 gst_caps_unref (caps);
1343 /* push out the header buffers */
1345 buf = buffers->data;
1346 buffers = g_slist_delete_link (buffers, buffers);
1347 if ((ret = theora_push_buffer (enc, buf)) != GST_FLOW_OK) {
1348 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1349 g_slist_free (buffers);
1354 enc->granulepos_offset =
1355 gst_util_uint64_scale (running_time, enc->fps_n,
1356 GST_SECOND * enc->fps_d);
1357 enc->timestamp_offset = running_time;
1361 ret = theora_enc_encode_and_push (enc, op, timestamp, running_time, duration,
1367 header_buffer_alloc:
1369 gst_buffer_unref (buffer);
1374 gst_buffer_unref (buffer);
1379 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1380 ("libtheora has been compiled with the encoder disabled"));
1381 gst_buffer_unref (buffer);
1382 return GST_FLOW_ERROR;
1386 static GstStateChangeReturn
1387 theora_enc_change_state (GstElement * element, GstStateChange transition)
1390 GstStateChangeReturn ret;
1392 enc = GST_THEORA_ENC (element);
1394 switch (transition) {
1395 case GST_STATE_CHANGE_NULL_TO_READY:
1397 case GST_STATE_CHANGE_READY_TO_PAUSED:
1398 GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state");
1399 th_info_init (&enc->info);
1400 th_comment_init (&enc->comment);
1402 enc->force_keyframe = FALSE;
1404 if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) {
1407 if (!enc->multipass_cache_file) {
1408 ret = GST_STATE_CHANGE_FAILURE;
1409 GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
1412 enc->multipass_cache_fd =
1413 g_io_channel_new_file (enc->multipass_cache_file,
1414 (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"),
1417 if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS)
1418 enc->multipass_cache_adapter = gst_adapter_new ();
1420 if (!enc->multipass_cache_fd) {
1421 ret = GST_STATE_CHANGE_FAILURE;
1422 GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL),
1423 ("Failed to open multipass cache file: %s", err->message));
1428 g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL);
1431 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1437 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1439 switch (transition) {
1440 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1442 case GST_STATE_CHANGE_PAUSED_TO_READY:
1443 GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state");
1445 th_encode_free (enc->encoder);
1446 enc->encoder = NULL;
1448 th_comment_clear (&enc->comment);
1449 th_info_clear (&enc->info);
1451 theora_enc_clear (enc);
1452 enc->initialised = FALSE;
1454 case GST_STATE_CHANGE_READY_TO_NULL:
1464 theora_enc_set_property (GObject * object, guint prop_id,
1465 const GValue * value, GParamSpec * pspec)
1467 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1473 case PROP_KEYFRAME_THRESHOLD:
1474 case PROP_KEYFRAME_MINDISTANCE:
1475 case PROP_NOISE_SENSITIVITY:
1476 case PROP_SHARPNESS:
1477 /* kept for API compat, but ignored */
1480 GST_OBJECT_LOCK (enc);
1481 enc->video_bitrate = g_value_get_int (value) * 1000;
1482 enc->bitrate_changed = TRUE;
1483 GST_OBJECT_UNLOCK (enc);
1486 GST_OBJECT_LOCK (enc);
1487 if (GST_STATE (enc) >= GST_STATE_PAUSED && enc->video_bitrate > 0) {
1488 GST_WARNING_OBJECT (object, "Can't change from bitrate to quality mode"
1491 enc->video_quality = g_value_get_int (value);
1492 enc->video_bitrate = 0;
1493 enc->quality_changed = TRUE;
1495 GST_OBJECT_UNLOCK (enc);
1497 case PROP_KEYFRAME_AUTO:
1498 enc->keyframe_auto = g_value_get_boolean (value);
1500 case PROP_KEYFRAME_FREQ:
1501 enc->keyframe_freq = g_value_get_int (value);
1503 case PROP_KEYFRAME_FREQ_FORCE:
1504 enc->keyframe_force = g_value_get_int (value);
1506 case PROP_SPEEDLEVEL:
1507 enc->speed_level = g_value_get_int (value);
1509 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
1510 sizeof (enc->speed_level));
1513 case PROP_VP3_COMPATIBLE:
1514 enc->vp3_compatible = g_value_get_boolean (value);
1516 case PROP_DROP_FRAMES:
1517 enc->drop_frames = g_value_get_boolean (value);
1519 case PROP_CAP_OVERFLOW:
1520 enc->cap_overflow = g_value_get_boolean (value);
1522 case PROP_CAP_UNDERFLOW:
1523 enc->cap_underflow = g_value_get_boolean (value);
1525 case PROP_RATE_BUFFER:
1526 enc->rate_buffer = g_value_get_int (value);
1528 case PROP_MULTIPASS_CACHE_FILE:
1529 enc->multipass_cache_file = g_value_dup_string (value);
1531 case PROP_MULTIPASS_MODE:
1532 enc->multipass_mode = g_value_get_enum (value);
1535 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1541 theora_enc_get_property (GObject * object, guint prop_id,
1542 GValue * value, GParamSpec * pspec)
1544 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1548 g_value_set_boolean (value, TRUE);
1551 g_value_set_enum (value, BORDER_BLACK);
1554 GST_OBJECT_LOCK (enc);
1555 g_value_set_int (value, enc->video_bitrate / 1000);
1556 GST_OBJECT_UNLOCK (enc);
1559 GST_OBJECT_LOCK (enc);
1560 g_value_set_int (value, enc->video_quality);
1561 GST_OBJECT_UNLOCK (enc);
1564 g_value_set_boolean (value, TRUE);
1566 case PROP_KEYFRAME_AUTO:
1567 g_value_set_boolean (value, enc->keyframe_auto);
1569 case PROP_KEYFRAME_FREQ:
1570 g_value_set_int (value, enc->keyframe_freq);
1572 case PROP_KEYFRAME_FREQ_FORCE:
1573 g_value_set_int (value, enc->keyframe_force);
1575 case PROP_KEYFRAME_THRESHOLD:
1576 g_value_set_int (value, 80);
1578 case PROP_KEYFRAME_MINDISTANCE:
1579 g_value_set_int (value, 8);
1581 case PROP_NOISE_SENSITIVITY:
1582 g_value_set_int (value, 1);
1584 case PROP_SHARPNESS:
1585 g_value_set_int (value, 0);
1587 case PROP_SPEEDLEVEL:
1588 g_value_set_int (value, enc->speed_level);
1590 case PROP_VP3_COMPATIBLE:
1591 g_value_set_boolean (value, enc->vp3_compatible);
1593 case PROP_DROP_FRAMES:
1594 g_value_set_boolean (value, enc->drop_frames);
1596 case PROP_CAP_OVERFLOW:
1597 g_value_set_boolean (value, enc->cap_overflow);
1599 case PROP_CAP_UNDERFLOW:
1600 g_value_set_boolean (value, enc->cap_underflow);
1602 case PROP_RATE_BUFFER:
1603 g_value_set_int (value, enc->rate_buffer);
1605 case PROP_MULTIPASS_CACHE_FILE:
1606 g_value_set_string (value, enc->multipass_cache_file);
1608 case PROP_MULTIPASS_MODE:
1609 g_value_set_enum (value, enc->multipass_mode);
1612 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);