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 static GstCaps *theora_enc_src_caps;
249 _do_init (GType object_type)
251 const GInterfaceInfo preset_interface_info = {
252 NULL, /* interface_init */
253 NULL, /* interface_finalize */
254 NULL /* interface_data */
257 g_type_add_interface_static (object_type, GST_TYPE_PRESET,
258 &preset_interface_info);
261 GST_BOILERPLATE_FULL (GstTheoraEnc, gst_theora_enc, GstElement,
262 GST_TYPE_ELEMENT, _do_init);
264 static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event);
265 static gboolean theora_enc_src_event (GstPad * pad, GstEvent * event);
266 static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
267 static GstStateChangeReturn theora_enc_change_state (GstElement * element,
268 GstStateChange transition);
269 static GstCaps *theora_enc_sink_getcaps (GstPad * pad);
270 static gboolean theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
271 static void theora_enc_get_property (GObject * object, guint prop_id,
272 GValue * value, GParamSpec * pspec);
273 static void theora_enc_set_property (GObject * object, guint prop_id,
274 const GValue * value, GParamSpec * pspec);
275 static void theora_enc_finalize (GObject * object);
277 static gboolean theora_enc_write_multipass_cache (GstTheoraEnc * enc,
278 gboolean begin, gboolean eos);
280 static char *theora_enc_get_supported_formats (void);
283 gst_theora_enc_base_init (gpointer g_class)
285 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
287 gst_element_class_add_static_pad_template (element_class,
288 &theora_enc_src_factory);
289 gst_element_class_add_static_pad_template (element_class,
290 &theora_enc_sink_factory);
291 gst_element_class_set_details_simple (element_class,
292 "Theora video encoder", "Codec/Encoder/Video",
293 "encode raw YUV video to a theora stream",
294 "Wim Taymans <wim@fluendo.com>");
298 gst_theora_enc_class_init (GstTheoraEncClass * klass)
300 GObjectClass *gobject_class = (GObjectClass *) klass;
301 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
304 /* query runtime encoder properties */
306 int default_speed_level = THEORA_DEF_SPEEDLEVEL;
307 int max_speed_level = default_speed_level;
309 GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
311 th_ctx = dummy_encode_ctx ();
313 if (check_speed_level (th_ctx, &default_speed_level, &max_speed_level))
315 ("Failed to determine settings for the speed-level property.");
316 th_encode_free (th_ctx);
319 gobject_class->set_property = theora_enc_set_property;
320 gobject_class->get_property = theora_enc_get_property;
321 gobject_class->finalize = theora_enc_finalize;
323 g_object_class_install_property (gobject_class, PROP_CENTER,
324 g_param_spec_boolean ("center", "Center",
325 "ignored and kept for API compat only", TRUE,
326 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
327 g_object_class_install_property (gobject_class, PROP_BORDER,
328 g_param_spec_enum ("border", "Border",
329 "ignored and kept for API compat only",
330 GST_TYPE_BORDER_MODE, BORDER_BLACK,
331 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
332 /* general encoding stream options */
333 g_object_class_install_property (gobject_class, PROP_BITRATE,
334 g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
335 0, (1 << 24) - 1, THEORA_DEF_BITRATE,
336 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
337 GST_PARAM_MUTABLE_PLAYING));
338 g_object_class_install_property (gobject_class, PROP_QUALITY,
339 g_param_spec_int ("quality", "Quality", "Video quality", 0, 63,
341 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
342 GST_PARAM_MUTABLE_PLAYING));
343 g_object_class_install_property (gobject_class, PROP_QUICK,
344 g_param_spec_boolean ("quick", "Quick",
345 "ignored and kept for API compat only", TRUE,
346 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
347 g_object_class_install_property (gobject_class, PROP_KEYFRAME_AUTO,
348 g_param_spec_boolean ("keyframe-auto", "Keyframe Auto",
349 "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO,
350 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
351 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ,
352 g_param_spec_int ("keyframe-freq", "Keyframe frequency",
353 "Keyframe frequency", 1, 32768, THEORA_DEF_KEYFRAME_FREQ,
354 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
355 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ_FORCE,
356 g_param_spec_int ("keyframe-force", "Keyframe force",
357 "Force keyframe every N frames", 1, 32768,
358 THEORA_DEF_KEYFRAME_FREQ_FORCE,
359 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
360 g_object_class_install_property (gobject_class, PROP_KEYFRAME_THRESHOLD,
361 g_param_spec_int ("keyframe-threshold", "Keyframe threshold",
362 "ignored and kept for API compat only", 0, 32768, 80,
363 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
364 g_object_class_install_property (gobject_class, PROP_KEYFRAME_MINDISTANCE,
365 g_param_spec_int ("keyframe-mindistance", "Keyframe mindistance",
366 "ignored and kept for API compat only", 1, 32768, 8,
367 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
368 g_object_class_install_property (gobject_class, PROP_NOISE_SENSITIVITY,
369 g_param_spec_int ("noise-sensitivity", "Noise sensitivity",
370 "ignored and kept for API compat only", 0, 32768, 1,
371 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
372 g_object_class_install_property (gobject_class, PROP_SHARPNESS,
373 g_param_spec_int ("sharpness", "Sharpness",
374 "ignored and kept for API compat only", 0, 2, 0,
375 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
376 g_object_class_install_property (gobject_class, PROP_SPEEDLEVEL,
377 g_param_spec_int ("speed-level", "Speed level",
378 "Controls the amount of analysis performed when encoding."
379 " Higher values trade compression quality for speed."
380 " This property requires libtheora version >= 1.0"
381 ", and the maximum value may vary based on encoder version.",
382 0, max_speed_level, default_speed_level,
383 (GParamFlags) G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
384 G_PARAM_STATIC_STRINGS));
385 g_object_class_install_property (gobject_class, PROP_VP3_COMPATIBLE,
386 g_param_spec_boolean ("vp3-compatible", "VP3 Compatible",
387 "Disables non-VP3 compatible features",
388 THEORA_DEF_VP3_COMPATIBLE,
389 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
390 g_object_class_install_property (gobject_class, PROP_DROP_FRAMES,
391 g_param_spec_boolean ("drop-frames", "Drop Frames",
392 "Allow or disallow frame dropping",
393 THEORA_DEF_DROP_FRAMES,
394 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
395 g_object_class_install_property (gobject_class, PROP_CAP_OVERFLOW,
396 g_param_spec_boolean ("cap-overflow", "Cap Overflow",
397 "Enable capping of bit reservoir overflows",
398 THEORA_DEF_CAP_OVERFLOW,
399 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
400 g_object_class_install_property (gobject_class, PROP_CAP_UNDERFLOW,
401 g_param_spec_boolean ("cap-underflow", "Cap Underflow",
402 "Enable capping of bit reservoir underflows",
403 THEORA_DEF_CAP_UNDERFLOW,
404 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
405 g_object_class_install_property (gobject_class, PROP_RATE_BUFFER,
406 g_param_spec_int ("rate-buffer", "Rate Control Buffer",
407 "Sets the size of the rate control buffer, in units of frames. "
408 "The default value of 0 instructs the encoder to automatically "
409 "select an appropriate value",
410 0, 1000, THEORA_DEF_RATE_BUFFER,
411 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
412 g_object_class_install_property (gobject_class, PROP_MULTIPASS_CACHE_FILE,
413 g_param_spec_string ("multipass-cache-file", "Multipass Cache File",
414 "Multipass cache file", THEORA_DEF_MULTIPASS_CACHE_FILE,
415 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
416 g_object_class_install_property (gobject_class, PROP_MULTIPASS_MODE,
417 g_param_spec_enum ("multipass-mode", "Multipass mode",
418 "Single pass or first/second pass", GST_TYPE_MULTIPASS_MODE,
419 THEORA_DEF_MULTIPASS_MODE,
420 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
422 caps_string = g_strdup_printf ("video/x-raw-yuv, "
423 "format = (fourcc) { %s }, "
424 "framerate = (fraction) [1/MAX, MAX], "
425 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]",
426 theora_enc_get_supported_formats ());
427 theora_enc_src_caps = gst_caps_from_string (caps_string);
428 g_free (caps_string);
430 gstelement_class->change_state = theora_enc_change_state;
434 gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class)
437 gst_pad_new_from_static_template (&theora_enc_sink_factory, "sink");
438 gst_pad_set_chain_function (enc->sinkpad, theora_enc_chain);
439 gst_pad_set_event_function (enc->sinkpad, theora_enc_sink_event);
440 gst_pad_set_getcaps_function (enc->sinkpad, theora_enc_sink_getcaps);
441 gst_pad_set_setcaps_function (enc->sinkpad, theora_enc_sink_setcaps);
442 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
445 gst_pad_new_from_static_template (&theora_enc_src_factory, "src");
446 gst_pad_set_event_function (enc->srcpad, theora_enc_src_event);
447 gst_pad_use_fixed_caps (enc->srcpad);
448 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
450 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
452 enc->video_bitrate = THEORA_DEF_BITRATE;
453 enc->video_quality = THEORA_DEF_QUALITY;
454 enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
455 enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ;
456 enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE;
458 enc->expected_ts = GST_CLOCK_TIME_NONE;
460 /* enc->speed_level is set to the libtheora default by the constructor */
461 enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE;
462 enc->drop_frames = THEORA_DEF_DROP_FRAMES;
463 enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW;
464 enc->cap_underflow = THEORA_DEF_CAP_UNDERFLOW;
465 enc->rate_buffer = THEORA_DEF_RATE_BUFFER;
467 enc->multipass_mode = THEORA_DEF_MULTIPASS_MODE;
468 enc->multipass_cache_file = THEORA_DEF_MULTIPASS_CACHE_FILE;
472 theora_enc_clear_multipass_cache (GstTheoraEnc * enc)
474 if (enc->multipass_cache_fd) {
475 g_io_channel_shutdown (enc->multipass_cache_fd, TRUE, NULL);
476 g_io_channel_unref (enc->multipass_cache_fd);
477 enc->multipass_cache_fd = NULL;
480 if (enc->multipass_cache_adapter) {
481 gst_object_unref (enc->multipass_cache_adapter);
482 enc->multipass_cache_adapter = NULL;
487 theora_enc_finalize (GObject * object)
489 GstTheoraEnc *enc = GST_THEORA_ENC (object);
491 GST_DEBUG_OBJECT (enc, "Finalizing");
493 th_encode_free (enc->encoder);
494 th_comment_clear (&enc->comment);
495 th_info_clear (&enc->info);
496 g_free (enc->multipass_cache_file);
498 theora_enc_clear_multipass_cache (enc);
500 G_OBJECT_CLASS (parent_class)->finalize (object);
504 theora_enc_reset (GstTheoraEnc * enc)
506 ogg_uint32_t keyframe_force;
509 GST_OBJECT_LOCK (enc);
510 enc->info.target_bitrate = enc->video_bitrate;
511 if (enc->quality_changed) {
512 enc->info.quality = enc->video_quality;
514 if (enc->video_bitrate == 0) {
515 enc->info.quality = enc->video_quality;
518 enc->bitrate_changed = FALSE;
519 enc->quality_changed = FALSE;
520 GST_OBJECT_UNLOCK (enc);
523 th_encode_free (enc->encoder);
524 enc->encoder = th_encode_alloc (&enc->info);
525 /* We ensure this function cannot fail. */
526 g_assert (enc->encoder != NULL);
527 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
528 sizeof (enc->speed_level));
529 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_VP3_COMPATIBLE,
530 &enc->vp3_compatible, sizeof (enc->vp3_compatible));
533 if (enc->drop_frames)
534 rate_flags |= TH_RATECTL_DROP_FRAMES;
535 if (enc->drop_frames)
536 rate_flags |= TH_RATECTL_CAP_OVERFLOW;
537 if (enc->drop_frames)
538 rate_flags |= TH_RATECTL_CAP_UNDERFLOW;
539 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_FLAGS,
540 &rate_flags, sizeof (rate_flags));
542 if (enc->rate_buffer) {
543 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_BUFFER,
544 &enc->rate_buffer, sizeof (enc->rate_buffer));
549 keyframe_force = enc->keyframe_auto ?
550 enc->keyframe_force : enc->keyframe_freq;
551 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
552 &keyframe_force, sizeof (keyframe_force));
554 /* Get placeholder data */
555 if (enc->multipass_cache_fd
556 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
557 theora_enc_write_multipass_cache (enc, TRUE, FALSE);
561 theora_enc_clear (GstTheoraEnc * enc)
565 enc->granulepos_offset = 0;
566 enc->timestamp_offset = 0;
568 enc->next_ts = GST_CLOCK_TIME_NONE;
569 enc->next_discont = FALSE;
570 enc->expected_ts = GST_CLOCK_TIME_NONE;
574 theora_enc_get_supported_formats (void)
580 th_pixel_fmt pixelformat;
581 const char fourcc[5];
584 TH_PF_420, "I420"}, {
585 TH_PF_422, "Y42B"}, {
588 GString *string = NULL;
591 th_info_init (&info);
592 info.frame_width = 16;
593 info.frame_height = 16;
594 info.fps_numerator = 25;
595 info.fps_denominator = 1;
596 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
597 info.pixel_fmt = formats[i].pixelformat;
599 encoder = th_encode_alloc (&info);
603 GST_LOG ("format %s is supported", formats[i].fourcc);
604 th_encode_free (encoder);
606 if (string == NULL) {
607 string = g_string_new (formats[i].fourcc);
609 g_string_append (string, ", ");
610 g_string_append (string, formats[i].fourcc);
613 th_info_clear (&info);
615 return string == NULL ? NULL : g_string_free (string, FALSE);
619 theora_enc_sink_getcaps (GstPad * pad)
621 GstTheoraEnc *encoder;
625 /* If we already have caps return them */
626 if (GST_PAD_CAPS (pad))
627 return gst_caps_ref (GST_PAD_CAPS (pad));
629 encoder = GST_THEORA_ENC (gst_pad_get_parent (pad));
631 return gst_caps_new_empty ();
633 peer = gst_pad_get_peer (encoder->srcpad);
635 const GstCaps *templ_caps;
636 GstCaps *peer_caps, *tmp_caps;
640 peer_caps = gst_pad_get_caps (peer);
642 /* Translate peercaps to YUV */
643 peer_caps = gst_caps_make_writable (peer_caps);
644 n = gst_caps_get_size (peer_caps);
645 for (i = 0; i < n; i++) {
646 s = gst_caps_get_structure (peer_caps, i);
648 gst_structure_set_name (s, "video/x-raw-yuv");
649 gst_structure_remove_field (s, "streamheader");
652 templ_caps = gst_pad_get_pad_template_caps (pad);
654 tmp_caps = gst_caps_intersect (peer_caps, templ_caps);
655 caps = gst_caps_intersect (tmp_caps, theora_enc_src_caps);
656 gst_caps_unref (tmp_caps);
657 gst_caps_unref (peer_caps);
658 gst_object_unref (peer);
661 caps = gst_caps_ref (theora_enc_src_caps);
664 gst_object_unref (encoder);
670 theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
672 GstStructure *structure = gst_caps_get_structure (caps, 0);
673 GstTheoraEnc *enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
678 gst_structure_get_fourcc (structure, "format", &fourcc);
679 gst_structure_get_int (structure, "width", &enc->width);
680 gst_structure_get_int (structure, "height", &enc->height);
681 gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d);
682 par = gst_structure_get_value (structure, "pixel-aspect-ratio");
684 th_info_clear (&enc->info);
685 th_info_init (&enc->info);
686 /* Theora has a divisible-by-sixteen restriction for the encoded video size but
687 * we can define a picture area using pic_width/pic_height */
688 enc->info.frame_width = GST_ROUND_UP_16 (enc->width);
689 enc->info.frame_height = GST_ROUND_UP_16 (enc->height);
690 enc->info.pic_width = enc->width;
691 enc->info.pic_height = enc->height;
693 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
694 enc->info.pixel_fmt = TH_PF_420;
696 case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
697 enc->info.pixel_fmt = TH_PF_422;
699 case GST_MAKE_FOURCC ('Y', '4', '4', '4'):
700 enc->info.pixel_fmt = TH_PF_444;
703 g_assert_not_reached ();
706 enc->info.fps_numerator = enc->fps_n = fps_n;
707 enc->info.fps_denominator = enc->fps_d = fps_d;
709 enc->info.aspect_numerator = gst_value_get_fraction_numerator (par);
710 enc->par_n = gst_value_get_fraction_numerator (par);
711 enc->info.aspect_denominator = gst_value_get_fraction_denominator (par);
712 enc->par_d = gst_value_get_fraction_denominator (par);
714 /* setting them to 0 indicates that the decoder can chose a good aspect
715 * ratio, defaulting to 1/1 */
716 enc->info.aspect_numerator = 0;
718 enc->info.aspect_denominator = 0;
722 enc->info.colorspace = TH_CS_UNSPECIFIED;
724 /* as done in theora */
725 enc->info.keyframe_granule_shift = _ilog (enc->keyframe_force - 1);
726 GST_DEBUG_OBJECT (enc,
727 "keyframe_frequency_force is %d, granule shift is %d",
728 enc->keyframe_force, enc->info.keyframe_granule_shift);
730 theora_enc_reset (enc);
731 enc->initialised = TRUE;
733 gst_object_unref (enc);
739 granulepos_add (guint64 granulepos, guint64 addend, gint shift)
741 guint64 iframe, pframe;
743 iframe = granulepos >> shift;
744 pframe = granulepos - (iframe << shift);
747 return (iframe << shift) + pframe;
750 /* prepare a buffer for transmission by passing data through libtheora */
752 theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
753 GstClockTime timestamp, GstClockTime running_time,
754 GstClockTime duration, GstBuffer ** buffer)
757 GstFlowReturn ret = GST_FLOW_OK;
759 buf = gst_buffer_new_and_alloc (packet->bytes);
761 GST_WARNING_OBJECT (enc, "Could not allocate buffer");
762 ret = GST_FLOW_ERROR;
766 memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
767 gst_buffer_set_caps (buf, GST_PAD_CAPS (enc->srcpad));
768 /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
769 * time representation */
770 GST_BUFFER_OFFSET_END (buf) =
771 granulepos_add (packet->granulepos, enc->granulepos_offset,
772 enc->info.keyframe_granule_shift);
773 GST_BUFFER_OFFSET (buf) = granulepos_to_timestamp (enc,
774 GST_BUFFER_OFFSET_END (buf));
776 GST_BUFFER_TIMESTAMP (buf) = timestamp;
777 GST_BUFFER_DURATION (buf) = duration;
779 if (enc->next_discont) {
780 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
781 enc->next_discont = FALSE;
784 /* th_packet_iskeyframe returns positive for keyframes */
785 if (th_packet_iskeyframe (packet) > 0) {
786 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
788 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
797 /* push out the buffer and do internal bookkeeping */
799 theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
803 enc->bytes_out += GST_BUFFER_SIZE (buffer);
805 ret = gst_pad_push (enc->srcpad, buffer);
811 theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet,
812 GstClockTime timestamp, GstClockTime running_time, GstClockTime duration)
818 theora_buffer_from_packet (enc, packet, timestamp, running_time, duration,
820 if (ret == GST_FLOW_OK)
821 ret = theora_push_buffer (enc, buf);
827 theora_set_header_on_caps (GstCaps * caps, GSList * buffers)
829 GstStructure *structure;
830 GValue array = { 0 };
831 GValue value = { 0 };
835 caps = gst_caps_make_writable (caps);
836 structure = gst_caps_get_structure (caps, 0);
838 /* put copies of the buffers in a fixed list */
839 g_value_init (&array, GST_TYPE_ARRAY);
841 for (walk = buffers; walk; walk = walk->next) {
845 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
847 /* Copy buffer, because we can't use the original -
848 * it creates a circular refcount with the caps<->buffers */
849 buffer = gst_buffer_copy (buffer);
851 g_value_init (&value, GST_TYPE_BUFFER);
852 gst_value_set_buffer (&value, buffer);
853 gst_value_array_append_value (&array, &value);
854 g_value_unset (&value);
857 gst_buffer_unref (buffer);
860 gst_structure_set_value (structure, "streamheader", &array);
861 g_value_unset (&array);
867 theora_enc_force_keyframe (GstTheoraEnc * enc)
869 GstClockTime next_ts;
871 /* make sure timestamps increment after resetting the decoder */
872 next_ts = enc->next_ts + enc->timestamp_offset;
874 theora_enc_reset (enc);
875 enc->granulepos_offset =
876 gst_util_uint64_scale (next_ts, enc->fps_n, GST_SECOND * enc->fps_d);
877 enc->timestamp_offset = next_ts;
882 theora_enc_sink_event (GstPad * pad, GstEvent * event)
888 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
890 switch (GST_EVENT_TYPE (event)) {
891 case GST_EVENT_NEWSEGMENT:
894 gdouble rate, applied_rate;
896 gint64 start, stop, time;
898 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
899 &format, &start, &stop, &time);
901 gst_segment_set_newsegment_full (&enc->segment, update, rate,
902 applied_rate, format, start, stop, time);
904 res = gst_pad_push_event (enc->srcpad, event);
908 if (enc->initialised) {
909 /* push last packet with eos flag, should not be called */
910 while (th_encode_packetout (enc->encoder, 1, &op)) {
911 GstClockTime next_time =
912 th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
914 theora_push_packet (enc, &op, GST_CLOCK_TIME_NONE, enc->next_ts,
915 next_time - enc->next_ts);
916 enc->next_ts = next_time;
919 if (enc->initialised && enc->multipass_cache_fd
920 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
921 theora_enc_write_multipass_cache (enc, TRUE, TRUE);
923 theora_enc_clear_multipass_cache (enc);
925 res = gst_pad_push_event (enc->srcpad, event);
927 case GST_EVENT_FLUSH_STOP:
928 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
929 res = gst_pad_push_event (enc->srcpad, event);
931 case GST_EVENT_CUSTOM_DOWNSTREAM:
933 const GstStructure *s;
935 s = gst_event_get_structure (event);
937 if (gst_structure_has_name (s, "GstForceKeyUnit"))
938 theora_enc_force_keyframe (enc);
939 res = gst_pad_push_event (enc->srcpad, event);
943 res = gst_pad_push_event (enc->srcpad, event);
950 theora_enc_src_event (GstPad * pad, GstEvent * event)
955 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
957 switch (GST_EVENT_TYPE (event)) {
958 case GST_EVENT_CUSTOM_UPSTREAM:
960 const GstStructure *s;
962 s = gst_event_get_structure (event);
964 if (gst_structure_has_name (s, "GstForceKeyUnit")) {
965 GST_OBJECT_LOCK (enc);
966 enc->force_keyframe = TRUE;
967 GST_OBJECT_UNLOCK (enc);
968 /* consume the event */
970 gst_event_unref (event);
972 res = gst_pad_push_event (enc->sinkpad, event);
977 res = gst_pad_push_event (enc->sinkpad, event);
985 theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp,
986 GstClockTime duration)
988 GstClockTimeDiff max_diff;
989 gboolean ret = FALSE;
991 /* Allow 3/4 a frame off */
992 max_diff = (enc->info.fps_denominator * GST_SECOND * 3) /
993 (enc->info.fps_numerator * 4);
995 if (timestamp != GST_CLOCK_TIME_NONE
996 && enc->expected_ts != GST_CLOCK_TIME_NONE) {
997 if ((GstClockTimeDiff) (timestamp - enc->expected_ts) > max_diff) {
998 GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT
999 " exceeds expected value %" GST_TIME_FORMAT
1000 " by too much, marking discontinuity",
1001 GST_TIME_ARGS (timestamp), GST_TIME_ARGS (enc->expected_ts));
1006 if (GST_CLOCK_TIME_IS_VALID (duration))
1007 enc->expected_ts = timestamp + duration;
1009 enc->expected_ts = GST_CLOCK_TIME_NONE;
1015 theora_enc_init_buffer (th_ycbcr_buffer buf, th_info * info, guint8 * data)
1017 GstVideoFormat format;
1020 switch (info->pixel_fmt) {
1022 format = GST_VIDEO_FORMAT_Y444;
1025 format = GST_VIDEO_FORMAT_I420;
1028 format = GST_VIDEO_FORMAT_Y42B;
1031 g_assert_not_reached ();
1034 /* According to Theora developer Timothy Terriberry, the Theora
1035 * encoder will not use memory outside of pic_width/height, even when
1036 * the frame size is bigger. The values outside this region will be encoded
1037 * to default values.
1038 * Due to this, setting the frame's width/height as the buffer width/height
1039 * is perfectly ok, even though it does not strictly look ok.
1041 for (i = 0; i < 3; i++) {
1043 gst_video_format_get_component_width (format, i, info->frame_width);
1045 gst_video_format_get_component_height (format, i, info->frame_height);
1048 data + gst_video_format_get_component_offset (format, i,
1049 info->pic_width, info->pic_height);
1051 gst_video_format_get_row_stride (format, i, info->pic_width);
1056 theora_enc_read_multipass_cache (GstTheoraEnc * enc)
1058 GstBuffer *cache_buf;
1059 const guint8 *cache_data;
1060 gsize bytes_read = 0;
1061 gint bytes_consumed = 0;
1062 GIOStatus stat = G_IO_STATUS_NORMAL;
1063 gboolean done = FALSE;
1066 if (gst_adapter_available (enc->multipass_cache_adapter) == 0) {
1067 cache_buf = gst_buffer_new_and_alloc (512);
1068 stat = g_io_channel_read_chars (enc->multipass_cache_fd,
1069 (gchar *) GST_BUFFER_DATA (cache_buf), GST_BUFFER_SIZE (cache_buf),
1072 if (bytes_read <= 0) {
1073 gst_buffer_unref (cache_buf);
1076 GST_BUFFER_SIZE (cache_buf) = bytes_read;
1078 gst_adapter_push (enc->multipass_cache_adapter, cache_buf);
1081 if (gst_adapter_available (enc->multipass_cache_adapter) == 0)
1085 MIN (gst_adapter_available (enc->multipass_cache_adapter), 512);
1087 cache_data = gst_adapter_peek (enc->multipass_cache_adapter, bytes_read);
1090 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data,
1092 done = bytes_consumed <= 0;
1093 if (bytes_consumed > 0)
1094 gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed);
1097 if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_EOF && bytes_read == 0)
1098 || bytes_consumed < 0) {
1099 GST_ELEMENT_ERROR (enc, RESOURCE, READ, (NULL),
1100 ("Failed to read multipass cache file"));
1107 theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin,
1111 GIOStatus stat = G_IO_STATUS_NORMAL;
1112 gint bytes_read = 0;
1113 gsize bytes_written = 0;
1117 stat = g_io_channel_seek_position (enc->multipass_cache_fd, 0, G_SEEK_SET,
1119 if (stat != G_IO_STATUS_ERROR) {
1122 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_OUT, &buf, sizeof (buf));
1124 g_io_channel_write_chars (enc->multipass_cache_fd, buf, bytes_read,
1125 &bytes_written, NULL);
1126 } while (bytes_read > 0 && bytes_written > 0);
1130 if (stat == G_IO_STATUS_ERROR || bytes_read < 0) {
1133 GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL),
1134 ("Failed to seek to beginning of multipass cache file: %s",
1137 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1138 ("Failed to seek to beginning of multipass cache file: %s",
1141 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1142 ("Failed to write multipass cache file"));
1152 static GstFlowReturn
1153 theora_enc_encode_and_push (GstTheoraEnc * enc, ogg_packet op,
1154 GstClockTime timestamp, GstClockTime running_time,
1155 GstClockTime duration, GstBuffer * buffer)
1158 th_ycbcr_buffer ycbcr;
1161 theora_enc_init_buffer (ycbcr, &enc->info, GST_BUFFER_DATA (buffer));
1163 if (theora_enc_is_discontinuous (enc, running_time, duration)) {
1164 theora_enc_reset (enc);
1165 enc->granulepos_offset =
1166 gst_util_uint64_scale (running_time, enc->fps_n,
1167 GST_SECOND * enc->fps_d);
1168 enc->timestamp_offset = running_time;
1170 enc->next_discont = TRUE;
1173 if (enc->multipass_cache_fd
1174 && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
1175 if (!theora_enc_read_multipass_cache (enc)) {
1176 ret = GST_FLOW_ERROR;
1177 goto multipass_read_failed;
1181 res = th_encode_ycbcr_in (enc->encoder, ycbcr);
1182 /* none of the failure cases can happen here */
1183 g_assert (res == 0);
1185 if (enc->multipass_cache_fd
1186 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
1187 if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
1188 ret = GST_FLOW_ERROR;
1189 goto multipass_write_failed;
1194 while (th_encode_packetout (enc->encoder, 0, &op)) {
1195 GstClockTime next_time;
1197 next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
1200 theora_push_packet (enc, &op, timestamp, enc->next_ts,
1201 next_time - enc->next_ts);
1203 enc->next_ts = next_time;
1204 if (ret != GST_FLOW_OK)
1207 gst_buffer_unref (buffer);
1212 multipass_read_failed:
1214 gst_buffer_unref (buffer);
1217 multipass_write_failed:
1219 gst_buffer_unref (buffer);
1224 gst_buffer_unref (buffer);
1229 static GstFlowReturn
1230 theora_enc_chain (GstPad * pad, GstBuffer * buffer)
1234 GstClockTime timestamp, duration, running_time;
1236 gboolean force_keyframe;
1238 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
1240 /* we keep track of two timelines.
1241 * - The timestamps from the incoming buffers, which we copy to the outgoing
1242 * encoded buffers as-is. We need to do this as we simply forward the
1243 * newsegment events.
1244 * - The running_time of the buffers, which we use to construct the granulepos
1247 timestamp = GST_BUFFER_TIMESTAMP (buffer);
1248 duration = GST_BUFFER_DURATION (buffer);
1251 gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
1252 if ((gint64) running_time < 0) {
1253 GST_DEBUG_OBJECT (enc, "Dropping buffer, timestamp: %" GST_TIME_FORMAT,
1254 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
1255 gst_buffer_unref (buffer);
1259 GST_OBJECT_LOCK (enc);
1260 if (enc->bitrate_changed) {
1261 long int bitrate = enc->video_bitrate;
1263 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
1265 enc->bitrate_changed = FALSE;
1268 if (enc->quality_changed) {
1269 long int quality = enc->video_quality;
1271 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
1273 enc->quality_changed = FALSE;
1276 /* see if we need to schedule a keyframe */
1277 force_keyframe = enc->force_keyframe;
1278 enc->force_keyframe = FALSE;
1279 GST_OBJECT_UNLOCK (enc);
1281 if (force_keyframe) {
1282 GstClockTime stream_time;
1285 stream_time = gst_segment_to_stream_time (&enc->segment,
1286 GST_FORMAT_TIME, timestamp);
1288 s = gst_structure_new ("GstForceKeyUnit",
1289 "timestamp", G_TYPE_UINT64, timestamp,
1290 "stream-time", G_TYPE_UINT64, stream_time,
1291 "running-time", G_TYPE_UINT64, running_time, NULL);
1293 theora_enc_force_keyframe (enc);
1295 gst_pad_push_event (enc->srcpad,
1296 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
1299 /* make sure we copy the discont flag to the next outgoing buffer when it's
1300 * set on the incoming buffer */
1301 if (GST_BUFFER_IS_DISCONT (buffer)) {
1302 enc->next_discont = TRUE;
1305 if (enc->packetno == 0) {
1306 /* no packets written yet, setup headers */
1309 GSList *buffers = NULL;
1312 enc->granulepos_offset = 0;
1313 enc->timestamp_offset = 0;
1315 GST_DEBUG_OBJECT (enc, "output headers");
1316 /* Theora streams begin with three headers; the initial header (with
1317 most of the codec setup parameters) which is mandated by the Ogg
1318 bitstream spec. The second header holds any comment fields. The
1319 third header holds the bitstream codebook. We merely need to
1320 make the headers, then pass them to libtheora one at a time;
1321 libtheora handles the additional Ogg bitstream constraints */
1323 /* create the remaining theora headers */
1324 th_comment_clear (&enc->comment);
1325 th_comment_init (&enc->comment);
1328 th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
1330 theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
1331 GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf);
1332 if (ret != GST_FLOW_OK) {
1333 goto header_buffer_alloc;
1335 buffers = g_slist_prepend (buffers, buf);
1338 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1339 g_slist_free (buffers);
1340 goto encoder_disabled;
1343 buffers = g_slist_reverse (buffers);
1345 /* mark buffers and put on caps */
1346 caps = gst_caps_new_simple ("video/x-theora",
1347 "width", G_TYPE_INT, enc->width,
1348 "height", G_TYPE_INT, enc->height,
1349 "framerate", GST_TYPE_FRACTION, enc->fps_n, enc->fps_d,
1350 "pixel-aspect-ratio", GST_TYPE_FRACTION, enc->par_n, enc->par_d, NULL);
1351 caps = theora_set_header_on_caps (caps, buffers);
1352 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
1353 gst_pad_set_caps (enc->srcpad, caps);
1355 g_slist_foreach (buffers, (GFunc) gst_buffer_set_caps, caps);
1357 gst_caps_unref (caps);
1359 /* push out the header buffers */
1361 buf = buffers->data;
1362 buffers = g_slist_delete_link (buffers, buffers);
1363 if ((ret = theora_push_buffer (enc, buf)) != GST_FLOW_OK) {
1364 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1365 g_slist_free (buffers);
1370 enc->granulepos_offset =
1371 gst_util_uint64_scale (running_time, enc->fps_n,
1372 GST_SECOND * enc->fps_d);
1373 enc->timestamp_offset = running_time;
1377 ret = theora_enc_encode_and_push (enc, op, timestamp, running_time, duration,
1383 header_buffer_alloc:
1385 gst_buffer_unref (buffer);
1390 gst_buffer_unref (buffer);
1395 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1396 ("libtheora has been compiled with the encoder disabled"));
1397 gst_buffer_unref (buffer);
1398 return GST_FLOW_ERROR;
1402 static GstStateChangeReturn
1403 theora_enc_change_state (GstElement * element, GstStateChange transition)
1406 GstStateChangeReturn ret;
1409 enc = GST_THEORA_ENC (element);
1411 switch (transition) {
1412 case GST_STATE_CHANGE_NULL_TO_READY:
1413 th_ctx = dummy_encode_ctx ();
1415 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1416 ("libtheora has been compiled with the encoder disabled"));
1417 return GST_STATE_CHANGE_FAILURE;
1419 th_encode_free (th_ctx);
1421 case GST_STATE_CHANGE_READY_TO_PAUSED:
1422 GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state");
1423 th_info_init (&enc->info);
1424 th_comment_init (&enc->comment);
1426 enc->force_keyframe = FALSE;
1428 if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) {
1431 if (!enc->multipass_cache_file) {
1432 ret = GST_STATE_CHANGE_FAILURE;
1433 GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
1436 enc->multipass_cache_fd =
1437 g_io_channel_new_file (enc->multipass_cache_file,
1438 (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"),
1441 if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS)
1442 enc->multipass_cache_adapter = gst_adapter_new ();
1444 if (!enc->multipass_cache_fd) {
1445 ret = GST_STATE_CHANGE_FAILURE;
1446 GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL),
1447 ("Failed to open multipass cache file: %s", err->message));
1452 g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL);
1455 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1461 ret = parent_class->change_state (element, transition);
1463 switch (transition) {
1464 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1466 case GST_STATE_CHANGE_PAUSED_TO_READY:
1467 GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state");
1469 th_encode_free (enc->encoder);
1470 enc->encoder = NULL;
1472 th_comment_clear (&enc->comment);
1473 th_info_clear (&enc->info);
1475 theora_enc_clear (enc);
1476 enc->initialised = FALSE;
1478 case GST_STATE_CHANGE_READY_TO_NULL:
1488 theora_enc_set_property (GObject * object, guint prop_id,
1489 const GValue * value, GParamSpec * pspec)
1491 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1497 case PROP_KEYFRAME_THRESHOLD:
1498 case PROP_KEYFRAME_MINDISTANCE:
1499 case PROP_NOISE_SENSITIVITY:
1500 case PROP_SHARPNESS:
1501 /* kept for API compat, but ignored */
1502 GST_WARNING_OBJECT (object, "Obsolete property '%s' ignored",
1506 GST_OBJECT_LOCK (enc);
1507 enc->video_bitrate = g_value_get_int (value) * 1000;
1508 enc->bitrate_changed = TRUE;
1509 GST_OBJECT_UNLOCK (enc);
1512 GST_OBJECT_LOCK (enc);
1513 if (GST_STATE (enc) >= GST_STATE_PAUSED && enc->video_bitrate > 0) {
1514 GST_WARNING_OBJECT (object, "Can't change from bitrate to quality mode"
1517 enc->video_quality = g_value_get_int (value);
1518 enc->video_bitrate = 0;
1519 enc->quality_changed = TRUE;
1521 GST_OBJECT_UNLOCK (enc);
1523 case PROP_KEYFRAME_AUTO:
1524 enc->keyframe_auto = g_value_get_boolean (value);
1526 case PROP_KEYFRAME_FREQ:
1527 enc->keyframe_freq = g_value_get_int (value);
1529 case PROP_KEYFRAME_FREQ_FORCE:
1530 enc->keyframe_force = g_value_get_int (value);
1532 case PROP_SPEEDLEVEL:
1533 enc->speed_level = g_value_get_int (value);
1535 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
1536 sizeof (enc->speed_level));
1539 case PROP_VP3_COMPATIBLE:
1540 enc->vp3_compatible = g_value_get_boolean (value);
1542 case PROP_DROP_FRAMES:
1543 enc->drop_frames = g_value_get_boolean (value);
1545 case PROP_CAP_OVERFLOW:
1546 enc->cap_overflow = g_value_get_boolean (value);
1548 case PROP_CAP_UNDERFLOW:
1549 enc->cap_underflow = g_value_get_boolean (value);
1551 case PROP_RATE_BUFFER:
1552 enc->rate_buffer = g_value_get_int (value);
1554 case PROP_MULTIPASS_CACHE_FILE:
1555 enc->multipass_cache_file = g_value_dup_string (value);
1557 case PROP_MULTIPASS_MODE:
1558 enc->multipass_mode = g_value_get_enum (value);
1561 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1567 theora_enc_get_property (GObject * object, guint prop_id,
1568 GValue * value, GParamSpec * pspec)
1570 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1574 g_value_set_boolean (value, TRUE);
1577 g_value_set_enum (value, BORDER_BLACK);
1580 GST_OBJECT_LOCK (enc);
1581 g_value_set_int (value, enc->video_bitrate / 1000);
1582 GST_OBJECT_UNLOCK (enc);
1585 GST_OBJECT_LOCK (enc);
1586 g_value_set_int (value, enc->video_quality);
1587 GST_OBJECT_UNLOCK (enc);
1590 g_value_set_boolean (value, TRUE);
1592 case PROP_KEYFRAME_AUTO:
1593 g_value_set_boolean (value, enc->keyframe_auto);
1595 case PROP_KEYFRAME_FREQ:
1596 g_value_set_int (value, enc->keyframe_freq);
1598 case PROP_KEYFRAME_FREQ_FORCE:
1599 g_value_set_int (value, enc->keyframe_force);
1601 case PROP_KEYFRAME_THRESHOLD:
1602 g_value_set_int (value, 80);
1604 case PROP_KEYFRAME_MINDISTANCE:
1605 g_value_set_int (value, 8);
1607 case PROP_NOISE_SENSITIVITY:
1608 g_value_set_int (value, 1);
1610 case PROP_SHARPNESS:
1611 g_value_set_int (value, 0);
1613 case PROP_SPEEDLEVEL:
1614 g_value_set_int (value, enc->speed_level);
1616 case PROP_VP3_COMPATIBLE:
1617 g_value_set_boolean (value, enc->vp3_compatible);
1619 case PROP_DROP_FRAMES:
1620 g_value_set_boolean (value, enc->drop_frames);
1622 case PROP_CAP_OVERFLOW:
1623 g_value_set_boolean (value, enc->cap_overflow);
1625 case PROP_CAP_UNDERFLOW:
1626 g_value_set_boolean (value, enc->cap_underflow);
1628 case PROP_RATE_BUFFER:
1629 g_value_set_int (value, enc->rate_buffer);
1631 case PROP_MULTIPASS_CACHE_FILE:
1632 g_value_set_string (value, enc->multipass_cache_file);
1634 case PROP_MULTIPASS_MODE:
1635 g_value_set_enum (value, enc->multipass_mode);
1638 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);