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, "
234 "format = (string) { 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 (GstTheoraEnc * enc, 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, "
405 "format = (string) { %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_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
426 gst_pad_new_from_static_template (&theora_enc_src_factory, "src");
427 gst_pad_set_event_function (enc->srcpad, theora_enc_src_event);
428 gst_pad_use_fixed_caps (enc->srcpad);
429 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
431 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
433 enc->video_bitrate = THEORA_DEF_BITRATE;
434 enc->video_quality = THEORA_DEF_QUALITY;
435 enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
436 enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ;
437 enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE;
439 enc->expected_ts = GST_CLOCK_TIME_NONE;
441 /* enc->speed_level is set to the libtheora default by the constructor */
442 enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE;
443 enc->drop_frames = THEORA_DEF_DROP_FRAMES;
444 enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW;
445 enc->cap_underflow = THEORA_DEF_CAP_UNDERFLOW;
446 enc->rate_buffer = THEORA_DEF_RATE_BUFFER;
448 enc->multipass_mode = THEORA_DEF_MULTIPASS_MODE;
449 enc->multipass_cache_file = THEORA_DEF_MULTIPASS_CACHE_FILE;
453 theora_enc_clear_multipass_cache (GstTheoraEnc * enc)
455 if (enc->multipass_cache_fd) {
456 g_io_channel_shutdown (enc->multipass_cache_fd, TRUE, NULL);
457 g_io_channel_unref (enc->multipass_cache_fd);
458 enc->multipass_cache_fd = NULL;
461 if (enc->multipass_cache_adapter) {
462 gst_object_unref (enc->multipass_cache_adapter);
463 enc->multipass_cache_adapter = NULL;
468 theora_enc_finalize (GObject * object)
470 GstTheoraEnc *enc = GST_THEORA_ENC (object);
472 GST_DEBUG_OBJECT (enc, "Finalizing");
474 th_encode_free (enc->encoder);
475 th_comment_clear (&enc->comment);
476 th_info_clear (&enc->info);
477 g_free (enc->multipass_cache_file);
479 theora_enc_clear_multipass_cache (enc);
481 G_OBJECT_CLASS (parent_class)->finalize (object);
485 theora_enc_reset (GstTheoraEnc * enc)
487 ogg_uint32_t keyframe_force;
490 GST_OBJECT_LOCK (enc);
491 enc->info.target_bitrate = enc->video_bitrate;
492 enc->info.quality = enc->video_quality;
493 enc->bitrate_changed = FALSE;
494 enc->quality_changed = FALSE;
495 GST_OBJECT_UNLOCK (enc);
498 th_encode_free (enc->encoder);
499 enc->encoder = th_encode_alloc (&enc->info);
500 /* We ensure this function cannot fail. */
501 g_assert (enc->encoder != NULL);
502 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
503 sizeof (enc->speed_level));
504 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_VP3_COMPATIBLE,
505 &enc->vp3_compatible, sizeof (enc->vp3_compatible));
508 if (enc->drop_frames)
509 rate_flags |= TH_RATECTL_DROP_FRAMES;
510 if (enc->drop_frames)
511 rate_flags |= TH_RATECTL_CAP_OVERFLOW;
512 if (enc->drop_frames)
513 rate_flags |= TH_RATECTL_CAP_UNDERFLOW;
514 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_FLAGS,
515 &rate_flags, sizeof (rate_flags));
517 if (enc->rate_buffer) {
518 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_BUFFER,
519 &enc->rate_buffer, sizeof (enc->rate_buffer));
524 keyframe_force = enc->keyframe_auto ?
525 enc->keyframe_force : enc->keyframe_freq;
526 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
527 &keyframe_force, sizeof (keyframe_force));
529 /* Get placeholder data */
530 if (enc->multipass_cache_fd
531 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
532 theora_enc_write_multipass_cache (enc, TRUE, FALSE);
536 theora_enc_clear (GstTheoraEnc * enc)
540 enc->granulepos_offset = 0;
541 enc->timestamp_offset = 0;
543 enc->next_ts = GST_CLOCK_TIME_NONE;
544 enc->next_discont = FALSE;
545 enc->expected_ts = GST_CLOCK_TIME_NONE;
549 theora_enc_get_supported_formats (void)
555 th_pixel_fmt pixelformat;
559 TH_PF_420, "I420"}, {
560 TH_PF_422, "Y42B"}, {
563 GString *string = NULL;
566 th_info_init (&info);
567 info.frame_width = 16;
568 info.frame_height = 16;
569 info.fps_numerator = 25;
570 info.fps_denominator = 1;
571 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
572 info.pixel_fmt = formats[i].pixelformat;
574 encoder = th_encode_alloc (&info);
578 GST_LOG ("format %s is supported", formats[i].fourcc);
579 th_encode_free (encoder);
581 if (string == NULL) {
582 string = g_string_new (formats[i].fourcc);
584 g_string_append (string, ", ");
585 g_string_append (string, formats[i].fourcc);
588 th_info_clear (&info);
590 return string == NULL ? NULL : g_string_free (string, FALSE);
594 theora_enc_sink_getcaps (GstPad * pad, GstCaps * filter)
596 GstTheoraEnc *encoder;
600 /* If we already have caps return them */
601 if ((caps = gst_pad_get_current_caps (pad)) != NULL)
604 encoder = GST_THEORA_ENC (gst_pad_get_parent (pad));
606 return gst_caps_new_empty ();
608 peer = gst_pad_get_peer (encoder->srcpad);
610 const GstCaps *templ_caps;
615 peer_caps = gst_pad_get_caps (peer, NULL);
617 /* Translate peercaps to YUV */
618 peer_caps = gst_caps_make_writable (peer_caps);
619 n = gst_caps_get_size (peer_caps);
620 for (i = 0; i < n; i++) {
621 s = gst_caps_get_structure (peer_caps, i);
623 gst_structure_set_name (s, "video/x-raw");
624 gst_structure_remove_field (s, "streamheader");
627 templ_caps = gst_pad_get_pad_template_caps (pad);
629 caps = gst_caps_intersect (peer_caps, templ_caps);
630 caps = gst_caps_intersect (caps, theora_enc_src_caps);
631 gst_caps_unref (peer_caps);
632 gst_object_unref (peer);
635 caps = gst_caps_ref (theora_enc_src_caps);
638 gst_object_unref (encoder);
641 GstCaps *intersection;
644 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
645 gst_caps_unref (caps);
653 theora_enc_sink_setcaps (GstTheoraEnc * enc, GstCaps * caps)
655 GstStructure *structure = gst_caps_get_structure (caps, 0);
660 gst_structure_get_fourcc (structure, "format", &fourcc);
661 gst_structure_get_int (structure, "width", &enc->width);
662 gst_structure_get_int (structure, "height", &enc->height);
663 gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d);
664 par = gst_structure_get_value (structure, "pixel-aspect-ratio");
666 th_info_clear (&enc->info);
667 th_info_init (&enc->info);
668 /* Theora has a divisible-by-sixteen restriction for the encoded video size but
669 * we can define a picture area using pic_width/pic_height */
670 enc->info.frame_width = GST_ROUND_UP_16 (enc->width);
671 enc->info.frame_height = GST_ROUND_UP_16 (enc->height);
672 enc->info.pic_width = enc->width;
673 enc->info.pic_height = enc->height;
675 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
676 enc->info.pixel_fmt = TH_PF_420;
678 case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
679 enc->info.pixel_fmt = TH_PF_422;
681 case GST_MAKE_FOURCC ('Y', '4', '4', '4'):
682 enc->info.pixel_fmt = TH_PF_444;
685 g_assert_not_reached ();
688 enc->info.fps_numerator = enc->fps_n = fps_n;
689 enc->info.fps_denominator = enc->fps_d = fps_d;
691 enc->info.aspect_numerator = gst_value_get_fraction_numerator (par);
692 enc->par_n = gst_value_get_fraction_numerator (par);
693 enc->info.aspect_denominator = gst_value_get_fraction_denominator (par);
694 enc->par_d = gst_value_get_fraction_denominator (par);
696 /* setting them to 0 indicates that the decoder can chose a good aspect
697 * ratio, defaulting to 1/1 */
698 enc->info.aspect_numerator = 0;
700 enc->info.aspect_denominator = 0;
704 enc->info.colorspace = TH_CS_UNSPECIFIED;
706 /* as done in theora */
707 enc->info.keyframe_granule_shift = _ilog (enc->keyframe_force - 1);
708 GST_DEBUG_OBJECT (enc,
709 "keyframe_frequency_force is %d, granule shift is %d",
710 enc->keyframe_force, enc->info.keyframe_granule_shift);
712 theora_enc_reset (enc);
713 enc->initialised = TRUE;
719 granulepos_add (guint64 granulepos, guint64 addend, gint shift)
721 guint64 iframe, pframe;
723 iframe = granulepos >> shift;
724 pframe = granulepos - (iframe << shift);
727 return (iframe << shift) + pframe;
730 /* prepare a buffer for transmission by passing data through libtheora */
732 theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
733 GstClockTime timestamp, GstClockTime running_time,
734 GstClockTime duration, GstBuffer ** buffer)
737 GstFlowReturn ret = GST_FLOW_OK;
739 buf = gst_buffer_new_and_alloc (packet->bytes);
741 GST_WARNING_OBJECT (enc, "Could not allocate buffer");
742 ret = GST_FLOW_ERROR;
746 gst_buffer_fill (buf, 0, packet->packet, packet->bytes);
747 /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
748 * time representation */
749 GST_BUFFER_OFFSET_END (buf) =
750 granulepos_add (packet->granulepos, enc->granulepos_offset,
751 enc->info.keyframe_granule_shift);
752 GST_BUFFER_OFFSET (buf) = granulepos_to_timestamp (enc,
753 GST_BUFFER_OFFSET_END (buf));
755 GST_BUFFER_TIMESTAMP (buf) = timestamp;
756 GST_BUFFER_DURATION (buf) = duration;
758 if (enc->next_discont) {
759 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
760 enc->next_discont = FALSE;
763 /* the second most significant bit of the first data byte is cleared
765 if (packet->bytes > 0 && (packet->packet[0] & 0x40) == 0) {
766 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
768 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
777 /* push out the buffer and do internal bookkeeping */
779 theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
783 enc->bytes_out += gst_buffer_get_size (buffer);
785 ret = gst_pad_push (enc->srcpad, buffer);
791 theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet,
792 GstClockTime timestamp, GstClockTime running_time, GstClockTime duration)
798 theora_buffer_from_packet (enc, packet, timestamp, running_time, duration,
800 if (ret == GST_FLOW_OK)
801 ret = theora_push_buffer (enc, buf);
807 theora_set_header_on_caps (GstCaps * caps, GSList * buffers)
809 GstStructure *structure;
810 GValue array = { 0 };
811 GValue value = { 0 };
815 caps = gst_caps_make_writable (caps);
816 structure = gst_caps_get_structure (caps, 0);
818 /* put copies of the buffers in a fixed list */
819 g_value_init (&array, GST_TYPE_ARRAY);
821 for (walk = buffers; walk; walk = walk->next) {
825 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
827 /* Copy buffer, because we can't use the original -
828 * it creates a circular refcount with the caps<->buffers */
829 buffer = gst_buffer_copy (buffer);
831 g_value_init (&value, GST_TYPE_BUFFER);
832 gst_value_set_buffer (&value, buffer);
833 gst_value_array_append_value (&array, &value);
834 g_value_unset (&value);
837 gst_buffer_unref (buffer);
840 gst_structure_set_value (structure, "streamheader", &array);
841 g_value_unset (&array);
847 theora_enc_force_keyframe (GstTheoraEnc * enc)
849 GstClockTime next_ts;
851 /* make sure timestamps increment after resetting the decoder */
852 next_ts = enc->next_ts + enc->timestamp_offset;
854 theora_enc_reset (enc);
855 enc->granulepos_offset =
856 gst_util_uint64_scale (next_ts, enc->fps_n, GST_SECOND * enc->fps_d);
857 enc->timestamp_offset = next_ts;
862 theora_enc_sink_event (GstPad * pad, GstEvent * event)
868 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
870 switch (GST_EVENT_TYPE (event)) {
875 gst_event_parse_caps (event, &caps);
876 res = theora_enc_sink_setcaps (enc, caps);
877 gst_event_unref (event);
880 case GST_EVENT_SEGMENT:
882 gst_event_copy_segment (event, &enc->segment);
884 res = gst_pad_push_event (enc->srcpad, event);
888 if (enc->initialised) {
889 /* push last packet with eos flag, should not be called */
890 while (th_encode_packetout (enc->encoder, 1, &op)) {
891 GstClockTime next_time =
892 th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
894 theora_push_packet (enc, &op, GST_CLOCK_TIME_NONE, enc->next_ts,
895 next_time - enc->next_ts);
896 enc->next_ts = next_time;
899 if (enc->initialised && enc->multipass_cache_fd
900 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
901 theora_enc_write_multipass_cache (enc, TRUE, TRUE);
903 theora_enc_clear_multipass_cache (enc);
905 res = gst_pad_push_event (enc->srcpad, event);
907 case GST_EVENT_FLUSH_STOP:
908 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
909 res = gst_pad_push_event (enc->srcpad, event);
911 case GST_EVENT_CUSTOM_DOWNSTREAM:
913 const GstStructure *s;
915 s = gst_event_get_structure (event);
917 if (gst_structure_has_name (s, "GstForceKeyUnit"))
918 theora_enc_force_keyframe (enc);
919 res = gst_pad_push_event (enc->srcpad, event);
923 res = gst_pad_push_event (enc->srcpad, event);
930 theora_enc_src_event (GstPad * pad, GstEvent * event)
935 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
937 switch (GST_EVENT_TYPE (event)) {
938 case GST_EVENT_CUSTOM_UPSTREAM:
940 const GstStructure *s;
942 s = gst_event_get_structure (event);
944 if (gst_structure_has_name (s, "GstForceKeyUnit")) {
945 GST_OBJECT_LOCK (enc);
946 enc->force_keyframe = TRUE;
947 GST_OBJECT_UNLOCK (enc);
948 /* consume the event */
950 gst_event_unref (event);
952 res = gst_pad_push_event (enc->sinkpad, event);
957 res = gst_pad_push_event (enc->sinkpad, event);
965 theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp,
966 GstClockTime duration)
968 GstClockTimeDiff max_diff;
969 gboolean ret = FALSE;
971 /* Allow 3/4 a frame off */
972 max_diff = (enc->info.fps_denominator * GST_SECOND * 3) /
973 (enc->info.fps_numerator * 4);
975 if (timestamp != GST_CLOCK_TIME_NONE
976 && enc->expected_ts != GST_CLOCK_TIME_NONE) {
977 if ((GstClockTimeDiff) (timestamp - enc->expected_ts) > max_diff) {
978 GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT
979 " exceeds expected value %" GST_TIME_FORMAT
980 " by too much, marking discontinuity",
981 GST_TIME_ARGS (timestamp), GST_TIME_ARGS (enc->expected_ts));
986 if (GST_CLOCK_TIME_IS_VALID (duration))
987 enc->expected_ts = timestamp + duration;
989 enc->expected_ts = GST_CLOCK_TIME_NONE;
995 theora_enc_init_buffer (th_ycbcr_buffer buf, th_info * info, guint8 * data)
997 GstVideoFormat format;
1000 switch (info->pixel_fmt) {
1002 format = GST_VIDEO_FORMAT_Y444;
1005 format = GST_VIDEO_FORMAT_I420;
1008 format = GST_VIDEO_FORMAT_Y42B;
1011 g_assert_not_reached ();
1014 /* According to Theora developer Timothy Terriberry, the Theora
1015 * encoder will not use memory outside of pic_width/height, even when
1016 * the frame size is bigger. The values outside this region will be encoded
1017 * to default values.
1018 * Due to this, setting the frame's width/height as the buffer width/height
1019 * is perfectly ok, even though it does not strictly look ok.
1021 for (i = 0; i < 3; i++) {
1023 gst_video_format_get_component_width (format, i, info->frame_width);
1025 gst_video_format_get_component_height (format, i, info->frame_height);
1028 data + gst_video_format_get_component_offset (format, i,
1029 info->pic_width, info->pic_height);
1031 gst_video_format_get_row_stride (format, i, info->pic_width);
1036 theora_enc_read_multipass_cache (GstTheoraEnc * enc)
1038 GstBuffer *cache_buf;
1039 const guint8 *cache_data;
1040 gsize bytes_read = 0;
1041 gint bytes_consumed = 0;
1042 GIOStatus stat = G_IO_STATUS_NORMAL;
1043 gboolean done = FALSE;
1046 if (gst_adapter_available (enc->multipass_cache_adapter) == 0) {
1050 cache_buf = gst_buffer_new_and_alloc (512);
1052 data = gst_buffer_map (cache_buf, &size, NULL, GST_MAP_READ);
1053 stat = g_io_channel_read_chars (enc->multipass_cache_fd,
1054 (gchar *) data, size, &bytes_read, NULL);
1056 if (bytes_read <= 0) {
1057 gst_buffer_unmap (cache_buf, data, 0);
1058 gst_buffer_unref (cache_buf);
1061 gst_buffer_unmap (cache_buf, data, bytes_read);
1062 gst_adapter_push (enc->multipass_cache_adapter, cache_buf);
1065 if (gst_adapter_available (enc->multipass_cache_adapter) == 0)
1069 MIN (gst_adapter_available (enc->multipass_cache_adapter), 512);
1071 cache_data = gst_adapter_map (enc->multipass_cache_adapter, bytes_read);
1074 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data,
1076 gst_adapter_unmap (enc->multipass_cache_adapter, 0);
1078 done = bytes_consumed <= 0;
1079 if (bytes_consumed > 0)
1080 gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed);
1083 if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_EOF && bytes_read == 0)
1084 || bytes_consumed < 0) {
1085 GST_ELEMENT_ERROR (enc, RESOURCE, READ, (NULL),
1086 ("Failed to read multipass cache file"));
1093 theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin,
1097 GIOStatus stat = G_IO_STATUS_NORMAL;
1098 gint bytes_read = 0;
1099 gsize bytes_written = 0;
1103 stat = g_io_channel_seek_position (enc->multipass_cache_fd, 0, G_SEEK_SET,
1105 if (stat != G_IO_STATUS_ERROR) {
1108 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_OUT, &buf, sizeof (buf));
1110 g_io_channel_write_chars (enc->multipass_cache_fd, buf, bytes_read,
1111 &bytes_written, NULL);
1112 } while (bytes_read > 0 && bytes_written > 0);
1116 if (stat == G_IO_STATUS_ERROR || bytes_read < 0) {
1119 GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL),
1120 ("Failed to seek to beginning of multipass cache file: %s",
1123 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1124 ("Failed to seek to beginning of multipass cache file: %s",
1127 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1128 ("Failed to write multipass cache file"));
1138 static GstFlowReturn
1139 theora_enc_encode_and_push (GstTheoraEnc * enc, ogg_packet op,
1140 GstClockTime timestamp, GstClockTime running_time,
1141 GstClockTime duration, GstBuffer * buffer)
1144 th_ycbcr_buffer ycbcr;
1149 data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
1150 theora_enc_init_buffer (ycbcr, &enc->info, data);
1152 if (theora_enc_is_discontinuous (enc, running_time, duration)) {
1153 theora_enc_reset (enc);
1154 enc->granulepos_offset =
1155 gst_util_uint64_scale (running_time, enc->fps_n,
1156 GST_SECOND * enc->fps_d);
1157 enc->timestamp_offset = running_time;
1159 enc->next_discont = TRUE;
1162 if (enc->multipass_cache_fd
1163 && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
1164 if (!theora_enc_read_multipass_cache (enc)) {
1165 ret = GST_FLOW_ERROR;
1166 goto multipass_read_failed;
1170 res = th_encode_ycbcr_in (enc->encoder, ycbcr);
1171 /* none of the failure cases can happen here */
1172 g_assert (res == 0);
1174 if (enc->multipass_cache_fd
1175 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
1176 if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
1177 ret = GST_FLOW_ERROR;
1178 goto multipass_write_failed;
1183 while (th_encode_packetout (enc->encoder, 0, &op)) {
1184 GstClockTime next_time;
1186 next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
1189 theora_push_packet (enc, &op, timestamp, enc->next_ts,
1190 next_time - enc->next_ts);
1192 enc->next_ts = next_time;
1193 if (ret != GST_FLOW_OK)
1198 gst_buffer_unmap (buffer, data, size);
1199 gst_buffer_unref (buffer);
1204 multipass_read_failed:
1206 GST_DEBUG_OBJECT (enc, "multipass read failed");
1209 multipass_write_failed:
1211 GST_DEBUG_OBJECT (enc, "multipass write failed");
1216 GST_DEBUG_OBJECT (enc, "error pushing buffer: %s", gst_flow_get_name (ret));
1221 static GstFlowReturn
1222 theora_enc_chain (GstPad * pad, GstBuffer * buffer)
1226 GstClockTime timestamp, duration, running_time;
1228 gboolean force_keyframe;
1230 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
1232 /* we keep track of two timelines.
1233 * - The timestamps from the incomming buffers, which we copy to the outgoing
1234 * encoded buffers as-is. We need to do this as we simply forward the
1235 * newsegment events.
1236 * - The running_time of the buffers, which we use to construct the granulepos
1239 timestamp = GST_BUFFER_TIMESTAMP (buffer);
1240 duration = GST_BUFFER_DURATION (buffer);
1243 gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
1244 if ((gint64) running_time < 0) {
1245 GST_DEBUG_OBJECT (enc, "Dropping buffer, timestamp: %" GST_TIME_FORMAT,
1246 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
1247 gst_buffer_unref (buffer);
1251 GST_OBJECT_LOCK (enc);
1252 if (enc->bitrate_changed) {
1253 long int bitrate = enc->video_bitrate;
1255 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
1257 enc->bitrate_changed = FALSE;
1260 if (enc->quality_changed) {
1261 long int quality = enc->video_quality;
1263 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
1265 enc->quality_changed = FALSE;
1268 /* see if we need to schedule a keyframe */
1269 force_keyframe = enc->force_keyframe;
1270 enc->force_keyframe = FALSE;
1271 GST_OBJECT_UNLOCK (enc);
1273 if (force_keyframe) {
1274 GstClockTime stream_time;
1277 stream_time = gst_segment_to_stream_time (&enc->segment,
1278 GST_FORMAT_TIME, timestamp);
1280 s = gst_structure_new ("GstForceKeyUnit",
1281 "timestamp", G_TYPE_UINT64, timestamp,
1282 "stream-time", G_TYPE_UINT64, stream_time,
1283 "running-time", G_TYPE_UINT64, running_time, NULL);
1285 theora_enc_force_keyframe (enc);
1287 gst_pad_push_event (enc->srcpad,
1288 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
1291 /* make sure we copy the discont flag to the next outgoing buffer when it's
1292 * set on the incomming buffer */
1293 if (GST_BUFFER_IS_DISCONT (buffer)) {
1294 enc->next_discont = TRUE;
1297 if (enc->packetno == 0) {
1298 /* no packets written yet, setup headers */
1301 GSList *buffers = NULL;
1304 enc->granulepos_offset = 0;
1305 enc->timestamp_offset = 0;
1307 GST_DEBUG_OBJECT (enc, "output headers");
1308 /* Theora streams begin with three headers; the initial header (with
1309 most of the codec setup parameters) which is mandated by the Ogg
1310 bitstream spec. The second header holds any comment fields. The
1311 third header holds the bitstream codebook. We merely need to
1312 make the headers, then pass them to libtheora one at a time;
1313 libtheora handles the additional Ogg bitstream constraints */
1315 /* create the remaining theora headers */
1316 th_comment_clear (&enc->comment);
1317 th_comment_init (&enc->comment);
1320 th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
1322 theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
1323 GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf);
1324 if (ret != GST_FLOW_OK) {
1325 goto header_buffer_alloc;
1327 buffers = g_slist_prepend (buffers, buf);
1330 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1331 g_slist_free (buffers);
1332 goto encoder_disabled;
1335 buffers = g_slist_reverse (buffers);
1337 /* mark buffers and put on caps */
1338 caps = gst_caps_new_simple ("video/x-theora",
1339 "width", G_TYPE_INT, enc->width,
1340 "height", G_TYPE_INT, enc->height,
1341 "framerate", GST_TYPE_FRACTION, enc->fps_n, enc->fps_d,
1342 "pixel-aspect-ratio", GST_TYPE_FRACTION, enc->par_n, enc->par_d, NULL);
1343 caps = theora_set_header_on_caps (caps, buffers);
1344 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
1345 gst_pad_set_caps (enc->srcpad, caps);
1346 gst_caps_unref (caps);
1348 /* push out the header buffers */
1350 buf = buffers->data;
1351 buffers = g_slist_delete_link (buffers, buffers);
1352 if ((ret = theora_push_buffer (enc, buf)) != GST_FLOW_OK) {
1353 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1354 g_slist_free (buffers);
1359 enc->granulepos_offset =
1360 gst_util_uint64_scale (running_time, enc->fps_n,
1361 GST_SECOND * enc->fps_d);
1362 enc->timestamp_offset = running_time;
1366 ret = theora_enc_encode_and_push (enc, op, timestamp, running_time, duration,
1372 header_buffer_alloc:
1374 gst_buffer_unref (buffer);
1379 gst_buffer_unref (buffer);
1384 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1385 ("libtheora has been compiled with the encoder disabled"));
1386 gst_buffer_unref (buffer);
1387 return GST_FLOW_ERROR;
1391 static GstStateChangeReturn
1392 theora_enc_change_state (GstElement * element, GstStateChange transition)
1395 GstStateChangeReturn ret;
1397 enc = GST_THEORA_ENC (element);
1399 switch (transition) {
1400 case GST_STATE_CHANGE_NULL_TO_READY:
1402 case GST_STATE_CHANGE_READY_TO_PAUSED:
1403 GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state");
1404 th_info_init (&enc->info);
1405 th_comment_init (&enc->comment);
1407 enc->force_keyframe = FALSE;
1409 if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) {
1412 if (!enc->multipass_cache_file) {
1413 ret = GST_STATE_CHANGE_FAILURE;
1414 GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
1417 enc->multipass_cache_fd =
1418 g_io_channel_new_file (enc->multipass_cache_file,
1419 (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"),
1422 if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS)
1423 enc->multipass_cache_adapter = gst_adapter_new ();
1425 if (!enc->multipass_cache_fd) {
1426 ret = GST_STATE_CHANGE_FAILURE;
1427 GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL),
1428 ("Failed to open multipass cache file: %s", err->message));
1433 g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL);
1436 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1442 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1444 switch (transition) {
1445 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1447 case GST_STATE_CHANGE_PAUSED_TO_READY:
1448 GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state");
1450 th_encode_free (enc->encoder);
1451 enc->encoder = NULL;
1453 th_comment_clear (&enc->comment);
1454 th_info_clear (&enc->info);
1456 theora_enc_clear (enc);
1457 enc->initialised = FALSE;
1459 case GST_STATE_CHANGE_READY_TO_NULL:
1469 theora_enc_set_property (GObject * object, guint prop_id,
1470 const GValue * value, GParamSpec * pspec)
1472 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1478 case PROP_KEYFRAME_THRESHOLD:
1479 case PROP_KEYFRAME_MINDISTANCE:
1480 case PROP_NOISE_SENSITIVITY:
1481 case PROP_SHARPNESS:
1482 /* kept for API compat, but ignored */
1485 GST_OBJECT_LOCK (enc);
1486 enc->video_bitrate = g_value_get_int (value) * 1000;
1487 enc->bitrate_changed = TRUE;
1488 GST_OBJECT_UNLOCK (enc);
1491 GST_OBJECT_LOCK (enc);
1492 if (GST_STATE (enc) >= GST_STATE_PAUSED && enc->video_bitrate > 0) {
1493 GST_WARNING_OBJECT (object, "Can't change from bitrate to quality mode"
1496 enc->video_quality = g_value_get_int (value);
1497 enc->video_bitrate = 0;
1498 enc->quality_changed = TRUE;
1500 GST_OBJECT_UNLOCK (enc);
1502 case PROP_KEYFRAME_AUTO:
1503 enc->keyframe_auto = g_value_get_boolean (value);
1505 case PROP_KEYFRAME_FREQ:
1506 enc->keyframe_freq = g_value_get_int (value);
1508 case PROP_KEYFRAME_FREQ_FORCE:
1509 enc->keyframe_force = g_value_get_int (value);
1511 case PROP_SPEEDLEVEL:
1512 enc->speed_level = g_value_get_int (value);
1514 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
1515 sizeof (enc->speed_level));
1518 case PROP_VP3_COMPATIBLE:
1519 enc->vp3_compatible = g_value_get_boolean (value);
1521 case PROP_DROP_FRAMES:
1522 enc->drop_frames = g_value_get_boolean (value);
1524 case PROP_CAP_OVERFLOW:
1525 enc->cap_overflow = g_value_get_boolean (value);
1527 case PROP_CAP_UNDERFLOW:
1528 enc->cap_underflow = g_value_get_boolean (value);
1530 case PROP_RATE_BUFFER:
1531 enc->rate_buffer = g_value_get_int (value);
1533 case PROP_MULTIPASS_CACHE_FILE:
1534 enc->multipass_cache_file = g_value_dup_string (value);
1536 case PROP_MULTIPASS_MODE:
1537 enc->multipass_mode = g_value_get_enum (value);
1540 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1546 theora_enc_get_property (GObject * object, guint prop_id,
1547 GValue * value, GParamSpec * pspec)
1549 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1553 g_value_set_boolean (value, TRUE);
1556 g_value_set_enum (value, BORDER_BLACK);
1559 GST_OBJECT_LOCK (enc);
1560 g_value_set_int (value, enc->video_bitrate / 1000);
1561 GST_OBJECT_UNLOCK (enc);
1564 GST_OBJECT_LOCK (enc);
1565 g_value_set_int (value, enc->video_quality);
1566 GST_OBJECT_UNLOCK (enc);
1569 g_value_set_boolean (value, TRUE);
1571 case PROP_KEYFRAME_AUTO:
1572 g_value_set_boolean (value, enc->keyframe_auto);
1574 case PROP_KEYFRAME_FREQ:
1575 g_value_set_int (value, enc->keyframe_freq);
1577 case PROP_KEYFRAME_FREQ_FORCE:
1578 g_value_set_int (value, enc->keyframe_force);
1580 case PROP_KEYFRAME_THRESHOLD:
1581 g_value_set_int (value, 80);
1583 case PROP_KEYFRAME_MINDISTANCE:
1584 g_value_set_int (value, 8);
1586 case PROP_NOISE_SENSITIVITY:
1587 g_value_set_int (value, 1);
1589 case PROP_SHARPNESS:
1590 g_value_set_int (value, 0);
1592 case PROP_SPEEDLEVEL:
1593 g_value_set_int (value, enc->speed_level);
1595 case PROP_VP3_COMPATIBLE:
1596 g_value_set_boolean (value, enc->vp3_compatible);
1598 case PROP_DROP_FRAMES:
1599 g_value_set_boolean (value, enc->drop_frames);
1601 case PROP_CAP_OVERFLOW:
1602 g_value_set_boolean (value, enc->cap_overflow);
1604 case PROP_CAP_UNDERFLOW:
1605 g_value_set_boolean (value, enc->cap_underflow);
1607 case PROP_RATE_BUFFER:
1608 g_value_set_int (value, enc->rate_buffer);
1610 case PROP_MULTIPASS_CACHE_FILE:
1611 g_value_set_string (value, enc->multipass_cache_file);
1613 case PROP_MULTIPASS_MODE:
1614 g_value_set_enum (value, enc->multipass_mode);
1617 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);