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_pad_template (element_class,
288 gst_static_pad_template_get (&theora_enc_src_factory));
289 gst_element_class_add_pad_template (element_class,
290 gst_static_pad_template_get (&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;
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 /* the second most significant bit of the first data byte is cleared
786 if (packet->bytes > 0 && (packet->packet[0] & 0x40) == 0) {
787 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
789 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
798 /* push out the buffer and do internal bookkeeping */
800 theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
804 enc->bytes_out += GST_BUFFER_SIZE (buffer);
806 ret = gst_pad_push (enc->srcpad, buffer);
812 theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet,
813 GstClockTime timestamp, GstClockTime running_time, GstClockTime duration)
819 theora_buffer_from_packet (enc, packet, timestamp, running_time, duration,
821 if (ret == GST_FLOW_OK)
822 ret = theora_push_buffer (enc, buf);
828 theora_set_header_on_caps (GstCaps * caps, GSList * buffers)
830 GstStructure *structure;
831 GValue array = { 0 };
832 GValue value = { 0 };
836 caps = gst_caps_make_writable (caps);
837 structure = gst_caps_get_structure (caps, 0);
839 /* put copies of the buffers in a fixed list */
840 g_value_init (&array, GST_TYPE_ARRAY);
842 for (walk = buffers; walk; walk = walk->next) {
846 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
848 /* Copy buffer, because we can't use the original -
849 * it creates a circular refcount with the caps<->buffers */
850 buffer = gst_buffer_copy (buffer);
852 g_value_init (&value, GST_TYPE_BUFFER);
853 gst_value_set_buffer (&value, buffer);
854 gst_value_array_append_value (&array, &value);
855 g_value_unset (&value);
858 gst_buffer_unref (buffer);
861 gst_structure_set_value (structure, "streamheader", &array);
862 g_value_unset (&array);
868 theora_enc_force_keyframe (GstTheoraEnc * enc)
870 GstClockTime next_ts;
872 /* make sure timestamps increment after resetting the decoder */
873 next_ts = enc->next_ts + enc->timestamp_offset;
875 theora_enc_reset (enc);
876 enc->granulepos_offset =
877 gst_util_uint64_scale (next_ts, enc->fps_n, GST_SECOND * enc->fps_d);
878 enc->timestamp_offset = next_ts;
883 theora_enc_sink_event (GstPad * pad, GstEvent * event)
889 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
891 switch (GST_EVENT_TYPE (event)) {
892 case GST_EVENT_NEWSEGMENT:
895 gdouble rate, applied_rate;
897 gint64 start, stop, time;
899 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
900 &format, &start, &stop, &time);
902 gst_segment_set_newsegment_full (&enc->segment, update, rate,
903 applied_rate, format, start, stop, time);
905 res = gst_pad_push_event (enc->srcpad, event);
909 if (enc->initialised) {
910 /* push last packet with eos flag, should not be called */
911 while (th_encode_packetout (enc->encoder, 1, &op)) {
912 GstClockTime next_time =
913 th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
915 theora_push_packet (enc, &op, GST_CLOCK_TIME_NONE, enc->next_ts,
916 next_time - enc->next_ts);
917 enc->next_ts = next_time;
920 if (enc->initialised && enc->multipass_cache_fd
921 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
922 theora_enc_write_multipass_cache (enc, TRUE, TRUE);
924 theora_enc_clear_multipass_cache (enc);
926 res = gst_pad_push_event (enc->srcpad, event);
928 case GST_EVENT_FLUSH_STOP:
929 gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
930 res = gst_pad_push_event (enc->srcpad, event);
932 case GST_EVENT_CUSTOM_DOWNSTREAM:
934 const GstStructure *s;
936 s = gst_event_get_structure (event);
938 if (gst_structure_has_name (s, "GstForceKeyUnit"))
939 theora_enc_force_keyframe (enc);
940 res = gst_pad_push_event (enc->srcpad, event);
944 res = gst_pad_push_event (enc->srcpad, event);
951 theora_enc_src_event (GstPad * pad, GstEvent * event)
956 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
958 switch (GST_EVENT_TYPE (event)) {
959 case GST_EVENT_CUSTOM_UPSTREAM:
961 const GstStructure *s;
963 s = gst_event_get_structure (event);
965 if (gst_structure_has_name (s, "GstForceKeyUnit")) {
966 GST_OBJECT_LOCK (enc);
967 enc->force_keyframe = TRUE;
968 GST_OBJECT_UNLOCK (enc);
969 /* consume the event */
971 gst_event_unref (event);
973 res = gst_pad_push_event (enc->sinkpad, event);
978 res = gst_pad_push_event (enc->sinkpad, event);
986 theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp,
987 GstClockTime duration)
989 GstClockTimeDiff max_diff;
990 gboolean ret = FALSE;
992 /* Allow 3/4 a frame off */
993 max_diff = (enc->info.fps_denominator * GST_SECOND * 3) /
994 (enc->info.fps_numerator * 4);
996 if (timestamp != GST_CLOCK_TIME_NONE
997 && enc->expected_ts != GST_CLOCK_TIME_NONE) {
998 if ((GstClockTimeDiff) (timestamp - enc->expected_ts) > max_diff) {
999 GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT
1000 " exceeds expected value %" GST_TIME_FORMAT
1001 " by too much, marking discontinuity",
1002 GST_TIME_ARGS (timestamp), GST_TIME_ARGS (enc->expected_ts));
1007 if (GST_CLOCK_TIME_IS_VALID (duration))
1008 enc->expected_ts = timestamp + duration;
1010 enc->expected_ts = GST_CLOCK_TIME_NONE;
1016 theora_enc_init_buffer (th_ycbcr_buffer buf, th_info * info, guint8 * data)
1018 GstVideoFormat format;
1021 switch (info->pixel_fmt) {
1023 format = GST_VIDEO_FORMAT_Y444;
1026 format = GST_VIDEO_FORMAT_I420;
1029 format = GST_VIDEO_FORMAT_Y42B;
1032 g_assert_not_reached ();
1035 /* According to Theora developer Timothy Terriberry, the Theora
1036 * encoder will not use memory outside of pic_width/height, even when
1037 * the frame size is bigger. The values outside this region will be encoded
1038 * to default values.
1039 * Due to this, setting the frame's width/height as the buffer width/height
1040 * is perfectly ok, even though it does not strictly look ok.
1042 for (i = 0; i < 3; i++) {
1044 gst_video_format_get_component_width (format, i, info->frame_width);
1046 gst_video_format_get_component_height (format, i, info->frame_height);
1049 data + gst_video_format_get_component_offset (format, i,
1050 info->pic_width, info->pic_height);
1052 gst_video_format_get_row_stride (format, i, info->pic_width);
1057 theora_enc_read_multipass_cache (GstTheoraEnc * enc)
1059 GstBuffer *cache_buf;
1060 const guint8 *cache_data;
1061 gsize bytes_read = 0;
1062 gint bytes_consumed = 0;
1063 GIOStatus stat = G_IO_STATUS_NORMAL;
1064 gboolean done = FALSE;
1067 if (gst_adapter_available (enc->multipass_cache_adapter) == 0) {
1068 cache_buf = gst_buffer_new_and_alloc (512);
1069 stat = g_io_channel_read_chars (enc->multipass_cache_fd,
1070 (gchar *) GST_BUFFER_DATA (cache_buf), GST_BUFFER_SIZE (cache_buf),
1073 if (bytes_read <= 0) {
1074 gst_buffer_unref (cache_buf);
1077 GST_BUFFER_SIZE (cache_buf) = bytes_read;
1079 gst_adapter_push (enc->multipass_cache_adapter, cache_buf);
1082 if (gst_adapter_available (enc->multipass_cache_adapter) == 0)
1086 MIN (gst_adapter_available (enc->multipass_cache_adapter), 512);
1088 cache_data = gst_adapter_peek (enc->multipass_cache_adapter, bytes_read);
1091 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data,
1093 done = bytes_consumed <= 0;
1094 if (bytes_consumed > 0)
1095 gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed);
1098 if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_EOF && bytes_read == 0)
1099 || bytes_consumed < 0) {
1100 GST_ELEMENT_ERROR (enc, RESOURCE, READ, (NULL),
1101 ("Failed to read multipass cache file"));
1108 theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin,
1112 GIOStatus stat = G_IO_STATUS_NORMAL;
1113 gint bytes_read = 0;
1114 gsize bytes_written = 0;
1118 stat = g_io_channel_seek_position (enc->multipass_cache_fd, 0, G_SEEK_SET,
1120 if (stat != G_IO_STATUS_ERROR) {
1123 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_OUT, &buf, sizeof (buf));
1125 g_io_channel_write_chars (enc->multipass_cache_fd, buf, bytes_read,
1126 &bytes_written, NULL);
1127 } while (bytes_read > 0 && bytes_written > 0);
1131 if (stat == G_IO_STATUS_ERROR || bytes_read < 0) {
1134 GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL),
1135 ("Failed to seek to beginning of multipass cache file: %s",
1138 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1139 ("Failed to seek to beginning of multipass cache file: %s",
1142 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
1143 ("Failed to write multipass cache file"));
1153 static GstFlowReturn
1154 theora_enc_encode_and_push (GstTheoraEnc * enc, ogg_packet op,
1155 GstClockTime timestamp, GstClockTime running_time,
1156 GstClockTime duration, GstBuffer * buffer)
1159 th_ycbcr_buffer ycbcr;
1162 theora_enc_init_buffer (ycbcr, &enc->info, GST_BUFFER_DATA (buffer));
1164 if (theora_enc_is_discontinuous (enc, running_time, duration)) {
1165 theora_enc_reset (enc);
1166 enc->granulepos_offset =
1167 gst_util_uint64_scale (running_time, enc->fps_n,
1168 GST_SECOND * enc->fps_d);
1169 enc->timestamp_offset = running_time;
1171 enc->next_discont = TRUE;
1174 if (enc->multipass_cache_fd
1175 && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
1176 if (!theora_enc_read_multipass_cache (enc)) {
1177 ret = GST_FLOW_ERROR;
1178 goto multipass_read_failed;
1182 res = th_encode_ycbcr_in (enc->encoder, ycbcr);
1183 /* none of the failure cases can happen here */
1184 g_assert (res == 0);
1186 if (enc->multipass_cache_fd
1187 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
1188 if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
1189 ret = GST_FLOW_ERROR;
1190 goto multipass_write_failed;
1195 while (th_encode_packetout (enc->encoder, 0, &op)) {
1196 GstClockTime next_time;
1198 next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
1201 theora_push_packet (enc, &op, timestamp, enc->next_ts,
1202 next_time - enc->next_ts);
1204 enc->next_ts = next_time;
1205 if (ret != GST_FLOW_OK)
1208 gst_buffer_unref (buffer);
1213 multipass_read_failed:
1215 gst_buffer_unref (buffer);
1218 multipass_write_failed:
1220 gst_buffer_unref (buffer);
1225 gst_buffer_unref (buffer);
1230 static GstFlowReturn
1231 theora_enc_chain (GstPad * pad, GstBuffer * buffer)
1235 GstClockTime timestamp, duration, running_time;
1237 gboolean force_keyframe;
1239 enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
1241 /* we keep track of two timelines.
1242 * - The timestamps from the incomming buffers, which we copy to the outgoing
1243 * encoded buffers as-is. We need to do this as we simply forward the
1244 * newsegment events.
1245 * - The running_time of the buffers, which we use to construct the granulepos
1248 timestamp = GST_BUFFER_TIMESTAMP (buffer);
1249 duration = GST_BUFFER_DURATION (buffer);
1252 gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
1253 if ((gint64) running_time < 0) {
1254 GST_DEBUG_OBJECT (enc, "Dropping buffer, timestamp: %" GST_TIME_FORMAT,
1255 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
1256 gst_buffer_unref (buffer);
1260 GST_OBJECT_LOCK (enc);
1261 if (enc->bitrate_changed) {
1262 long int bitrate = enc->video_bitrate;
1264 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
1266 enc->bitrate_changed = FALSE;
1269 if (enc->quality_changed) {
1270 long int quality = enc->video_quality;
1272 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
1274 enc->quality_changed = FALSE;
1277 /* see if we need to schedule a keyframe */
1278 force_keyframe = enc->force_keyframe;
1279 enc->force_keyframe = FALSE;
1280 GST_OBJECT_UNLOCK (enc);
1282 if (force_keyframe) {
1283 GstClockTime stream_time;
1286 stream_time = gst_segment_to_stream_time (&enc->segment,
1287 GST_FORMAT_TIME, timestamp);
1289 s = gst_structure_new ("GstForceKeyUnit",
1290 "timestamp", G_TYPE_UINT64, timestamp,
1291 "stream-time", G_TYPE_UINT64, stream_time,
1292 "running-time", G_TYPE_UINT64, running_time, NULL);
1294 theora_enc_force_keyframe (enc);
1296 gst_pad_push_event (enc->srcpad,
1297 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
1300 /* make sure we copy the discont flag to the next outgoing buffer when it's
1301 * set on the incomming buffer */
1302 if (GST_BUFFER_IS_DISCONT (buffer)) {
1303 enc->next_discont = TRUE;
1306 if (enc->packetno == 0) {
1307 /* no packets written yet, setup headers */
1310 GSList *buffers = NULL;
1313 enc->granulepos_offset = 0;
1314 enc->timestamp_offset = 0;
1316 GST_DEBUG_OBJECT (enc, "output headers");
1317 /* Theora streams begin with three headers; the initial header (with
1318 most of the codec setup parameters) which is mandated by the Ogg
1319 bitstream spec. The second header holds any comment fields. The
1320 third header holds the bitstream codebook. We merely need to
1321 make the headers, then pass them to libtheora one at a time;
1322 libtheora handles the additional Ogg bitstream constraints */
1324 /* create the remaining theora headers */
1325 th_comment_clear (&enc->comment);
1326 th_comment_init (&enc->comment);
1329 th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
1331 theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
1332 GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf);
1333 if (ret != GST_FLOW_OK) {
1334 goto header_buffer_alloc;
1336 buffers = g_slist_prepend (buffers, buf);
1339 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1340 g_slist_free (buffers);
1341 goto encoder_disabled;
1344 buffers = g_slist_reverse (buffers);
1346 /* mark buffers and put on caps */
1347 caps = gst_caps_new_simple ("video/x-theora",
1348 "width", G_TYPE_INT, enc->width,
1349 "height", G_TYPE_INT, enc->height,
1350 "framerate", GST_TYPE_FRACTION, enc->fps_n, enc->fps_d,
1351 "pixel-aspect-ratio", GST_TYPE_FRACTION, enc->par_n, enc->par_d, NULL);
1352 caps = theora_set_header_on_caps (caps, buffers);
1353 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
1354 gst_pad_set_caps (enc->srcpad, caps);
1356 g_slist_foreach (buffers, (GFunc) gst_buffer_set_caps, caps);
1358 gst_caps_unref (caps);
1360 /* push out the header buffers */
1362 buf = buffers->data;
1363 buffers = g_slist_delete_link (buffers, buffers);
1364 if ((ret = theora_push_buffer (enc, buf)) != GST_FLOW_OK) {
1365 g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
1366 g_slist_free (buffers);
1371 enc->granulepos_offset =
1372 gst_util_uint64_scale (running_time, enc->fps_n,
1373 GST_SECOND * enc->fps_d);
1374 enc->timestamp_offset = running_time;
1378 ret = theora_enc_encode_and_push (enc, op, timestamp, running_time, duration,
1384 header_buffer_alloc:
1386 gst_buffer_unref (buffer);
1391 gst_buffer_unref (buffer);
1396 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1397 ("libtheora has been compiled with the encoder disabled"));
1398 gst_buffer_unref (buffer);
1399 return GST_FLOW_ERROR;
1403 static GstStateChangeReturn
1404 theora_enc_change_state (GstElement * element, GstStateChange transition)
1407 GstStateChangeReturn ret;
1409 enc = GST_THEORA_ENC (element);
1411 switch (transition) {
1412 case GST_STATE_CHANGE_NULL_TO_READY:
1414 case GST_STATE_CHANGE_READY_TO_PAUSED:
1415 GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state");
1416 th_info_init (&enc->info);
1417 th_comment_init (&enc->comment);
1419 enc->force_keyframe = FALSE;
1421 if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) {
1424 if (!enc->multipass_cache_file) {
1425 ret = GST_STATE_CHANGE_FAILURE;
1426 GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
1429 enc->multipass_cache_fd =
1430 g_io_channel_new_file (enc->multipass_cache_file,
1431 (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"),
1434 if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS)
1435 enc->multipass_cache_adapter = gst_adapter_new ();
1437 if (!enc->multipass_cache_fd) {
1438 ret = GST_STATE_CHANGE_FAILURE;
1439 GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL),
1440 ("Failed to open multipass cache file: %s", err->message));
1445 g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL);
1448 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1454 ret = parent_class->change_state (element, transition);
1456 switch (transition) {
1457 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1459 case GST_STATE_CHANGE_PAUSED_TO_READY:
1460 GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state");
1462 th_encode_free (enc->encoder);
1463 enc->encoder = NULL;
1465 th_comment_clear (&enc->comment);
1466 th_info_clear (&enc->info);
1468 theora_enc_clear (enc);
1469 enc->initialised = FALSE;
1471 case GST_STATE_CHANGE_READY_TO_NULL:
1481 theora_enc_set_property (GObject * object, guint prop_id,
1482 const GValue * value, GParamSpec * pspec)
1484 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1490 case PROP_KEYFRAME_THRESHOLD:
1491 case PROP_KEYFRAME_MINDISTANCE:
1492 case PROP_NOISE_SENSITIVITY:
1493 case PROP_SHARPNESS:
1494 /* kept for API compat, but ignored */
1497 GST_OBJECT_LOCK (enc);
1498 enc->video_bitrate = g_value_get_int (value) * 1000;
1499 enc->bitrate_changed = TRUE;
1500 GST_OBJECT_UNLOCK (enc);
1503 GST_OBJECT_LOCK (enc);
1504 if (GST_STATE (enc) >= GST_STATE_PAUSED && enc->video_bitrate > 0) {
1505 GST_WARNING_OBJECT (object, "Can't change from bitrate to quality mode"
1508 enc->video_quality = g_value_get_int (value);
1509 enc->video_bitrate = 0;
1510 enc->quality_changed = TRUE;
1512 GST_OBJECT_UNLOCK (enc);
1514 case PROP_KEYFRAME_AUTO:
1515 enc->keyframe_auto = g_value_get_boolean (value);
1517 case PROP_KEYFRAME_FREQ:
1518 enc->keyframe_freq = g_value_get_int (value);
1520 case PROP_KEYFRAME_FREQ_FORCE:
1521 enc->keyframe_force = g_value_get_int (value);
1523 case PROP_SPEEDLEVEL:
1524 enc->speed_level = g_value_get_int (value);
1526 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
1527 sizeof (enc->speed_level));
1530 case PROP_VP3_COMPATIBLE:
1531 enc->vp3_compatible = g_value_get_boolean (value);
1533 case PROP_DROP_FRAMES:
1534 enc->drop_frames = g_value_get_boolean (value);
1536 case PROP_CAP_OVERFLOW:
1537 enc->cap_overflow = g_value_get_boolean (value);
1539 case PROP_CAP_UNDERFLOW:
1540 enc->cap_underflow = g_value_get_boolean (value);
1542 case PROP_RATE_BUFFER:
1543 enc->rate_buffer = g_value_get_int (value);
1545 case PROP_MULTIPASS_CACHE_FILE:
1546 enc->multipass_cache_file = g_value_dup_string (value);
1548 case PROP_MULTIPASS_MODE:
1549 enc->multipass_mode = g_value_get_enum (value);
1552 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1558 theora_enc_get_property (GObject * object, guint prop_id,
1559 GValue * value, GParamSpec * pspec)
1561 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1565 g_value_set_boolean (value, TRUE);
1568 g_value_set_enum (value, BORDER_BLACK);
1571 GST_OBJECT_LOCK (enc);
1572 g_value_set_int (value, enc->video_bitrate / 1000);
1573 GST_OBJECT_UNLOCK (enc);
1576 GST_OBJECT_LOCK (enc);
1577 g_value_set_int (value, enc->video_quality);
1578 GST_OBJECT_UNLOCK (enc);
1581 g_value_set_boolean (value, TRUE);
1583 case PROP_KEYFRAME_AUTO:
1584 g_value_set_boolean (value, enc->keyframe_auto);
1586 case PROP_KEYFRAME_FREQ:
1587 g_value_set_int (value, enc->keyframe_freq);
1589 case PROP_KEYFRAME_FREQ_FORCE:
1590 g_value_set_int (value, enc->keyframe_force);
1592 case PROP_KEYFRAME_THRESHOLD:
1593 g_value_set_int (value, 80);
1595 case PROP_KEYFRAME_MINDISTANCE:
1596 g_value_set_int (value, 8);
1598 case PROP_NOISE_SENSITIVITY:
1599 g_value_set_int (value, 1);
1601 case PROP_SHARPNESS:
1602 g_value_set_int (value, 0);
1604 case PROP_SPEEDLEVEL:
1605 g_value_set_int (value, enc->speed_level);
1607 case PROP_VP3_COMPATIBLE:
1608 g_value_set_boolean (value, enc->vp3_compatible);
1610 case PROP_DROP_FRAMES:
1611 g_value_set_boolean (value, enc->drop_frames);
1613 case PROP_CAP_OVERFLOW:
1614 g_value_set_boolean (value, enc->cap_overflow);
1616 case PROP_CAP_UNDERFLOW:
1617 g_value_set_boolean (value, enc->cap_underflow);
1619 case PROP_RATE_BUFFER:
1620 g_value_set_int (value, enc->rate_buffer);
1622 case PROP_MULTIPASS_CACHE_FILE:
1623 g_value_set_string (value, enc->multipass_cache_file);
1625 case PROP_MULTIPASS_MODE:
1626 g_value_set_enum (value, enc->multipass_mode);
1629 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);