1 /* GStreamer
2 * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
3 * Copyright (c) 2012 Collabora Ltd.
4 * Author : Edward Hervey <edward@collabora.com>
5 * Author : Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 /**
24 * SECTION:element-theoraenc
25 * @title: theoraenc
26 * @see_also: theoradec, oggmux
27 *
28 * This element encodes raw video into a Theora stream.
29 * <ulink url="http://www.theora.org/">Theora</ulink> is a royalty-free
30 * video codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
31 * Foundation</ulink>, based on the VP3 codec.
32 *
33 * The theora codec internally only supports encoding of images that are a
34 * multiple of 16 pixels in both X and Y direction. It is however perfectly
35 * possible to encode images with other dimensions because an arbitrary
36 * rectangular cropping region can be set up. This element will automatically
37 * set up a correct cropping region if the dimensions are not multiples of 16
38 * pixels.
39 *
40 * To control the quality of the encoding, the #GstTheoraEnc::bitrate and
41 * #GstTheoraEnc::quality properties can be used. These two properties are
42 * mutualy exclusive. Setting the bitrate property will produce a constant
43 * bitrate (CBR) stream while setting the quality property will produce a
44 * variable bitrate (VBR) stream.
45 *
46 * A videorate element is often required in front of theoraenc, especially
47 * when transcoding and when putting Theora into the Ogg container.
48 *
49 * ## Example pipeline
50 * |[
51 * gst-launch-1.0 -v videotestsrc num-buffers=500 ! video/x-raw,width=1280,height=720 ! queue ! progressreport ! theoraenc ! oggmux ! filesink location=videotestsrc.ogg
52 * ]|
53 * This example pipeline will encode a test video source to theora muxed in an
54 * ogg container. Refer to the theoradec documentation to decode the create
55 * stream.
56 *
57 */
58
59 #ifdef HAVE_CONFIG_H
60 #include "config.h"
61 #endif
62
63 #include <string.h>
64 #include <stdlib.h> /* free */
65
66 #include <gst/tag/tag.h>
67 #include <gst/video/video.h>
68 #include <gst/video/gstvideometa.h>
69
70 #include "gsttheoraenc.h"
71
72 #define GST_CAT_DEFAULT theoraenc_debug
73 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
74
75 #define GST_TYPE_MULTIPASS_MODE (gst_multipass_mode_get_type())
76 static GType
gst_multipass_mode_get_type(void)77 gst_multipass_mode_get_type (void)
78 {
79 static GType multipass_mode_type = 0;
80 static const GEnumValue multipass_mode[] = {
81 {MULTIPASS_MODE_SINGLE_PASS, "Single pass", "single-pass"},
82 {MULTIPASS_MODE_FIRST_PASS, "First pass", "first-pass"},
83 {MULTIPASS_MODE_SECOND_PASS, "Second pass", "second-pass"},
84 {0, NULL, NULL},
85 };
86
87 if (!multipass_mode_type) {
88 multipass_mode_type =
89 g_enum_register_static ("GstTheoraEncMultipassMode", multipass_mode);
90 }
91 return multipass_mode_type;
92 }
93
94 /* taken from theora/lib/toplevel.c */
95 static int
_ilog(unsigned int v)96 _ilog (unsigned int v)
97 {
98 int ret = 0;
99
100 while (v) {
101 ret++;
102 v >>= 1;
103 }
104 return (ret);
105 }
106
107 #define THEORA_DEF_BITRATE 0
108 #define THEORA_DEF_QUALITY 48
109 #define THEORA_DEF_KEYFRAME_AUTO TRUE
110 #define THEORA_DEF_KEYFRAME_FREQ 64
111 #define THEORA_DEF_KEYFRAME_FREQ_FORCE 64
112 #define THEORA_DEF_SPEEDLEVEL 1
113 #define THEORA_DEF_VP3_COMPATIBLE FALSE
114 #define THEORA_DEF_DROP_FRAMES TRUE
115 #define THEORA_DEF_CAP_OVERFLOW TRUE
116 #define THEORA_DEF_CAP_UNDERFLOW FALSE
117 #define THEORA_DEF_RATE_BUFFER 0
118 #define THEORA_DEF_MULTIPASS_CACHE_FILE NULL
119 #define THEORA_DEF_MULTIPASS_MODE MULTIPASS_MODE_SINGLE_PASS
120 enum
121 {
122 PROP_0,
123 PROP_BITRATE,
124 PROP_QUALITY,
125 PROP_KEYFRAME_AUTO,
126 PROP_KEYFRAME_FREQ,
127 PROP_KEYFRAME_FREQ_FORCE,
128 PROP_SPEEDLEVEL,
129 PROP_VP3_COMPATIBLE,
130 PROP_DROP_FRAMES,
131 PROP_CAP_OVERFLOW,
132 PROP_CAP_UNDERFLOW,
133 PROP_RATE_BUFFER,
134 PROP_MULTIPASS_CACHE_FILE,
135 PROP_MULTIPASS_MODE
136 /* FILL ME */
137 };
138
139 /* this function does a straight granulepos -> timestamp conversion */
140 static GstClockTime
granulepos_to_timestamp(GstTheoraEnc * theoraenc,ogg_int64_t granulepos)141 granulepos_to_timestamp (GstTheoraEnc * theoraenc, ogg_int64_t granulepos)
142 {
143 guint64 iframe, pframe;
144 int shift = theoraenc->info.keyframe_granule_shift;
145
146 if (granulepos < 0)
147 return GST_CLOCK_TIME_NONE;
148
149 iframe = granulepos >> shift;
150 pframe = granulepos - (iframe << shift);
151
152 /* num and den are 32 bit, so we can safely multiply with GST_SECOND */
153 return gst_util_uint64_scale ((guint64) (iframe + pframe),
154 GST_SECOND * theoraenc->info.fps_denominator,
155 theoraenc->info.fps_numerator);
156 }
157
158 static GstStaticPadTemplate theora_enc_sink_factory =
159 GST_STATIC_PAD_TEMPLATE ("sink",
160 GST_PAD_SINK,
161 GST_PAD_ALWAYS,
162 GST_STATIC_CAPS ("video/x-raw, "
163 "format = (string) { I420, Y42B, Y444 }, "
164 "framerate = (fraction) [1/MAX, MAX], "
165 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
166 );
167
168 static GstStaticPadTemplate theora_enc_src_factory =
169 GST_STATIC_PAD_TEMPLATE ("src",
170 GST_PAD_SRC,
171 GST_PAD_ALWAYS,
172 GST_STATIC_CAPS ("video/x-theora, "
173 "framerate = (fraction) [1/MAX, MAX], "
174 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
175 );
176
177 #define gst_theora_enc_parent_class parent_class
178 G_DEFINE_TYPE (GstTheoraEnc, gst_theora_enc, GST_TYPE_VIDEO_ENCODER);
179
180 static gboolean theora_enc_start (GstVideoEncoder * enc);
181 static gboolean theora_enc_stop (GstVideoEncoder * enc);
182 static gboolean theora_enc_flush (GstVideoEncoder * enc);
183 static gboolean theora_enc_set_format (GstVideoEncoder * enc,
184 GstVideoCodecState * state);
185 static GstFlowReturn theora_enc_handle_frame (GstVideoEncoder * enc,
186 GstVideoCodecFrame * frame);
187 static GstFlowReturn theora_enc_pre_push (GstVideoEncoder * benc,
188 GstVideoCodecFrame * frame);
189 static GstFlowReturn theora_enc_finish (GstVideoEncoder * enc);
190 static gboolean theora_enc_propose_allocation (GstVideoEncoder * encoder,
191 GstQuery * query);
192
193 static GstCaps *theora_enc_getcaps (GstVideoEncoder * encoder,
194 GstCaps * filter);
195 static void theora_enc_get_property (GObject * object, guint prop_id,
196 GValue * value, GParamSpec * pspec);
197 static void theora_enc_set_property (GObject * object, guint prop_id,
198 const GValue * value, GParamSpec * pspec);
199 static void theora_enc_finalize (GObject * object);
200
201 static gboolean theora_enc_write_multipass_cache (GstTheoraEnc * enc,
202 gboolean begin, gboolean eos);
203
204 static void
gst_theora_enc_class_init(GstTheoraEncClass * klass)205 gst_theora_enc_class_init (GstTheoraEncClass * klass)
206 {
207 GObjectClass *gobject_class = (GObjectClass *) klass;
208 GstElementClass *element_class = (GstElementClass *) klass;
209 GstVideoEncoderClass *gstvideo_encoder_class =
210 GST_VIDEO_ENCODER_CLASS (klass);
211
212 gobject_class->set_property = theora_enc_set_property;
213 gobject_class->get_property = theora_enc_get_property;
214 gobject_class->finalize = theora_enc_finalize;
215
216 gst_element_class_add_static_pad_template (element_class,
217 &theora_enc_src_factory);
218 gst_element_class_add_static_pad_template (element_class,
219 &theora_enc_sink_factory);
220 gst_element_class_set_static_metadata (element_class, "Theora video encoder",
221 "Codec/Encoder/Video", "encode raw YUV video to a theora stream",
222 "Wim Taymans <wim@fluendo.com>");
223
224 gstvideo_encoder_class->start = GST_DEBUG_FUNCPTR (theora_enc_start);
225 gstvideo_encoder_class->stop = GST_DEBUG_FUNCPTR (theora_enc_stop);
226 gstvideo_encoder_class->flush = GST_DEBUG_FUNCPTR (theora_enc_flush);
227 gstvideo_encoder_class->set_format =
228 GST_DEBUG_FUNCPTR (theora_enc_set_format);
229 gstvideo_encoder_class->handle_frame =
230 GST_DEBUG_FUNCPTR (theora_enc_handle_frame);
231 gstvideo_encoder_class->pre_push = GST_DEBUG_FUNCPTR (theora_enc_pre_push);
232 gstvideo_encoder_class->finish = GST_DEBUG_FUNCPTR (theora_enc_finish);
233 gstvideo_encoder_class->getcaps = GST_DEBUG_FUNCPTR (theora_enc_getcaps);
234 gstvideo_encoder_class->propose_allocation =
235 GST_DEBUG_FUNCPTR (theora_enc_propose_allocation);
236
237 /* general encoding stream options */
238 g_object_class_install_property (gobject_class, PROP_BITRATE,
239 g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
240 0, (1 << 24) - 1, THEORA_DEF_BITRATE,
241 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
242 GST_PARAM_MUTABLE_PLAYING));
243 g_object_class_install_property (gobject_class, PROP_QUALITY,
244 g_param_spec_int ("quality", "Quality", "Video quality", 0, 63,
245 THEORA_DEF_QUALITY,
246 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
247 GST_PARAM_MUTABLE_PLAYING));
248 g_object_class_install_property (gobject_class, PROP_KEYFRAME_AUTO,
249 g_param_spec_boolean ("keyframe-auto", "Keyframe Auto",
250 "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO,
251 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
252 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ,
253 g_param_spec_int ("keyframe-freq", "Keyframe frequency",
254 "Keyframe frequency", 1, 32768, THEORA_DEF_KEYFRAME_FREQ,
255 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
256 g_object_class_install_property (gobject_class, PROP_KEYFRAME_FREQ_FORCE,
257 g_param_spec_int ("keyframe-force", "Keyframe force",
258 "Force keyframe every N frames", 1, 32768,
259 THEORA_DEF_KEYFRAME_FREQ_FORCE,
260 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
261 g_object_class_install_property (gobject_class, PROP_SPEEDLEVEL,
262 g_param_spec_int ("speed-level", "Speed level",
263 "Controls the amount of motion vector searching done while encoding",
264 0, 3, THEORA_DEF_SPEEDLEVEL,
265 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
266 g_object_class_install_property (gobject_class, PROP_VP3_COMPATIBLE,
267 g_param_spec_boolean ("vp3-compatible", "VP3 compatible",
268 "Disables non-VP3 compatible features",
269 THEORA_DEF_VP3_COMPATIBLE,
270 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
271 g_object_class_install_property (gobject_class, PROP_DROP_FRAMES,
272 g_param_spec_boolean ("drop-frames", "Drop frames",
273 "Allow or disallow frame dropping",
274 THEORA_DEF_DROP_FRAMES,
275 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
276 g_object_class_install_property (gobject_class, PROP_CAP_OVERFLOW,
277 g_param_spec_boolean ("cap-overflow", "Cap overflow",
278 "Enable capping of bit reservoir overflows",
279 THEORA_DEF_CAP_OVERFLOW,
280 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
281 g_object_class_install_property (gobject_class, PROP_CAP_UNDERFLOW,
282 g_param_spec_boolean ("cap-underflow", "Cap underflow",
283 "Enable capping of bit reservoir underflows",
284 THEORA_DEF_CAP_UNDERFLOW,
285 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
286 g_object_class_install_property (gobject_class, PROP_RATE_BUFFER,
287 g_param_spec_int ("rate-buffer", "Rate Control Buffer",
288 "Sets the size of the rate control buffer, in units of frames. "
289 "The default value of 0 instructs the encoder to automatically "
290 "select an appropriate value",
291 0, 1000, THEORA_DEF_RATE_BUFFER,
292 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
293 g_object_class_install_property (gobject_class, PROP_MULTIPASS_CACHE_FILE,
294 g_param_spec_string ("multipass-cache-file", "Multipass Cache File",
295 "Multipass cache file", THEORA_DEF_MULTIPASS_CACHE_FILE,
296 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
297 g_object_class_install_property (gobject_class, PROP_MULTIPASS_MODE,
298 g_param_spec_enum ("multipass-mode", "Multipass mode",
299 "Single pass or first/second pass", GST_TYPE_MULTIPASS_MODE,
300 THEORA_DEF_MULTIPASS_MODE,
301 (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
302
303 GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
304 }
305
306 static void
gst_theora_enc_init(GstTheoraEnc * enc)307 gst_theora_enc_init (GstTheoraEnc * enc)
308 {
309 GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (enc));
310
311 enc->video_bitrate = THEORA_DEF_BITRATE;
312 enc->video_quality = THEORA_DEF_QUALITY;
313 enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
314 enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ;
315 enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE;
316
317 enc->speed_level = THEORA_DEF_SPEEDLEVEL;
318 enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE;
319 enc->drop_frames = THEORA_DEF_DROP_FRAMES;
320 enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW;
321 enc->cap_underflow = THEORA_DEF_CAP_UNDERFLOW;
322 enc->rate_buffer = THEORA_DEF_RATE_BUFFER;
323
324 enc->multipass_mode = THEORA_DEF_MULTIPASS_MODE;
325 enc->multipass_cache_file = THEORA_DEF_MULTIPASS_CACHE_FILE;
326 }
327
328 static void
theora_enc_clear_multipass_cache(GstTheoraEnc * enc)329 theora_enc_clear_multipass_cache (GstTheoraEnc * enc)
330 {
331 if (enc->multipass_cache_fd) {
332 g_io_channel_shutdown (enc->multipass_cache_fd, TRUE, NULL);
333 g_io_channel_unref (enc->multipass_cache_fd);
334 enc->multipass_cache_fd = NULL;
335 }
336
337 if (enc->multipass_cache_adapter) {
338 gst_object_unref (enc->multipass_cache_adapter);
339 enc->multipass_cache_adapter = NULL;
340 }
341 }
342
343 static void
theora_enc_finalize(GObject * object)344 theora_enc_finalize (GObject * object)
345 {
346 GstTheoraEnc *enc = GST_THEORA_ENC (object);
347
348 GST_DEBUG_OBJECT (enc, "Finalizing");
349 if (enc->encoder)
350 th_encode_free (enc->encoder);
351 th_comment_clear (&enc->comment);
352 th_info_clear (&enc->info);
353 g_free (enc->multipass_cache_file);
354
355 theora_enc_clear_multipass_cache (enc);
356
357 if (enc->input_state)
358 gst_video_codec_state_unref (enc->input_state);
359
360 G_OBJECT_CLASS (parent_class)->finalize (object);
361 }
362
363 static gboolean
theora_enc_flush(GstVideoEncoder * encoder)364 theora_enc_flush (GstVideoEncoder * encoder)
365 {
366 GstTheoraEnc *enc = GST_THEORA_ENC (encoder);
367 ogg_uint32_t keyframe_force;
368 int rate_flags;
369
370
371 if (enc->input_state == NULL) {
372 GST_INFO_OBJECT (enc, "Not configured yet, returning FALSE");
373
374 return FALSE;
375 }
376
377 GST_OBJECT_LOCK (enc);
378 enc->info.target_bitrate = enc->video_bitrate;
379 enc->info.quality = enc->video_quality;
380 enc->bitrate_changed = FALSE;
381 enc->quality_changed = FALSE;
382 GST_OBJECT_UNLOCK (enc);
383
384 if (enc->encoder)
385 th_encode_free (enc->encoder);
386
387 enc->encoder = th_encode_alloc (&enc->info);
388 /* We ensure this function cannot fail. */
389 g_assert (enc->encoder != NULL);
390 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
391 sizeof (enc->speed_level));
392 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_VP3_COMPATIBLE,
393 &enc->vp3_compatible, sizeof (enc->vp3_compatible));
394
395 rate_flags = 0;
396 if (enc->drop_frames)
397 rate_flags |= TH_RATECTL_DROP_FRAMES;
398 if (enc->drop_frames)
399 rate_flags |= TH_RATECTL_CAP_OVERFLOW;
400 if (enc->drop_frames)
401 rate_flags |= TH_RATECTL_CAP_UNDERFLOW;
402 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_FLAGS,
403 &rate_flags, sizeof (rate_flags));
404
405 if (enc->rate_buffer) {
406 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_BUFFER,
407 &enc->rate_buffer, sizeof (enc->rate_buffer));
408 } else {
409 /* FIXME */
410 }
411
412 keyframe_force = enc->keyframe_auto ?
413 enc->keyframe_force : enc->keyframe_freq;
414 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
415 &keyframe_force, sizeof (keyframe_force));
416
417 /* Get placeholder data */
418 if (enc->multipass_cache_fd
419 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
420 theora_enc_write_multipass_cache (enc, TRUE, FALSE);
421
422 return TRUE;
423 }
424
425 static gboolean
theora_enc_start(GstVideoEncoder * benc)426 theora_enc_start (GstVideoEncoder * benc)
427 {
428 GstTheoraEnc *enc;
429
430 GST_DEBUG_OBJECT (benc, "start: init theora");
431 enc = GST_THEORA_ENC (benc);
432
433 if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) {
434 GError *err = NULL;
435
436 if (!enc->multipass_cache_file) {
437 GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
438 return FALSE;
439 }
440 enc->multipass_cache_fd =
441 g_io_channel_new_file (enc->multipass_cache_file,
442 (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"), &err);
443
444 if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS)
445 enc->multipass_cache_adapter = gst_adapter_new ();
446
447 if (!enc->multipass_cache_fd) {
448 GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL),
449 ("Failed to open multipass cache file: %s", err->message));
450 g_error_free (err);
451 return FALSE;
452 }
453
454 g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL);
455 }
456
457 enc->packetno = 0;
458 enc->initialised = FALSE;
459
460 return TRUE;
461 }
462
463 static gboolean
theora_enc_stop(GstVideoEncoder * benc)464 theora_enc_stop (GstVideoEncoder * benc)
465 {
466 GstTheoraEnc *enc;
467
468 GST_DEBUG_OBJECT (benc, "stop: clearing theora state");
469 enc = GST_THEORA_ENC (benc);
470
471 if (enc->encoder)
472 th_encode_free (enc->encoder);
473 enc->encoder = NULL;
474 th_comment_clear (&enc->comment);
475 th_info_clear (&enc->info);
476
477 if (enc->input_state)
478 gst_video_codec_state_unref (enc->input_state);
479 enc->input_state = NULL;
480
481 /* Everything else is handled in reset() */
482 theora_enc_clear_multipass_cache (enc);
483
484 return TRUE;
485 }
486
487 static char *
theora_enc_get_supported_formats(void)488 theora_enc_get_supported_formats (void)
489 {
490 th_enc_ctx *encoder;
491 th_info info;
492 struct
493 {
494 th_pixel_fmt pixelformat;
495 const char *fourcc;
496 } formats[] = {
497 {
498 TH_PF_420, "I420"}, {
499 TH_PF_422, "Y42B"}, {
500 TH_PF_444, "Y444"}
501 };
502 GString *string = NULL;
503 guint i;
504
505 th_info_init (&info);
506 info.frame_width = 16;
507 info.frame_height = 16;
508 info.fps_numerator = 25;
509 info.fps_denominator = 1;
510 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
511 info.pixel_fmt = formats[i].pixelformat;
512
513 encoder = th_encode_alloc (&info);
514 if (encoder == NULL)
515 continue;
516
517 GST_LOG ("format %s is supported", formats[i].fourcc);
518 th_encode_free (encoder);
519
520 if (string == NULL) {
521 string = g_string_new (formats[i].fourcc);
522 } else {
523 g_string_append (string, ", ");
524 g_string_append (string, formats[i].fourcc);
525 }
526 }
527 th_info_clear (&info);
528
529 return string == NULL ? NULL : g_string_free (string, FALSE);
530 }
531
532 static GstCaps *
theora_enc_getcaps(GstVideoEncoder * encoder,GstCaps * filter)533 theora_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
534 {
535 GstCaps *caps, *ret;
536 char *supported_formats, *caps_string;
537
538 supported_formats = theora_enc_get_supported_formats ();
539 if (!supported_formats) {
540 GST_WARNING ("no supported formats found. Encoder disabled?");
541 return gst_caps_new_empty ();
542 }
543
544 caps_string = g_strdup_printf ("video/x-raw, "
545 "format = (string) { %s }, "
546 "framerate = (fraction) [1/MAX, MAX], "
547 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]",
548 supported_formats);
549 caps = gst_caps_from_string (caps_string);
550 g_free (caps_string);
551 g_free (supported_formats);
552 GST_DEBUG ("Supported caps: %" GST_PTR_FORMAT, caps);
553
554 ret = gst_video_encoder_proxy_getcaps (encoder, caps, filter);
555 gst_caps_unref (caps);
556
557 return ret;
558 }
559
560 static gboolean
theora_enc_set_format(GstVideoEncoder * benc,GstVideoCodecState * state)561 theora_enc_set_format (GstVideoEncoder * benc, GstVideoCodecState * state)
562 {
563 GstTheoraEnc *enc = GST_THEORA_ENC (benc);
564 GstVideoInfo *info = &state->info;
565
566 enc->width = GST_VIDEO_INFO_WIDTH (info);
567 enc->height = GST_VIDEO_INFO_HEIGHT (info);
568
569 th_info_clear (&enc->info);
570 th_info_init (&enc->info);
571 /* Theora has a divisible-by-sixteen restriction for the encoded video size but
572 * we can define a picture area using pic_width/pic_height */
573 enc->info.frame_width = GST_ROUND_UP_16 (enc->width);
574 enc->info.frame_height = GST_ROUND_UP_16 (enc->height);
575 enc->info.pic_width = enc->width;
576 enc->info.pic_height = enc->height;
577 switch (GST_VIDEO_INFO_FORMAT (info)) {
578 case GST_VIDEO_FORMAT_I420:
579 enc->info.pixel_fmt = TH_PF_420;
580 break;
581 case GST_VIDEO_FORMAT_Y42B:
582 enc->info.pixel_fmt = TH_PF_422;
583 break;
584 case GST_VIDEO_FORMAT_Y444:
585 enc->info.pixel_fmt = TH_PF_444;
586 break;
587 default:
588 g_assert_not_reached ();
589 }
590
591 enc->info.fps_numerator = enc->fps_n = GST_VIDEO_INFO_FPS_N (info);
592 enc->info.fps_denominator = enc->fps_d = GST_VIDEO_INFO_FPS_D (info);
593 enc->info.aspect_numerator = GST_VIDEO_INFO_PAR_N (info);
594 enc->info.aspect_denominator = GST_VIDEO_INFO_PAR_D (info);
595
596 enc->info.colorspace = TH_CS_UNSPECIFIED;
597
598 /* Save input state */
599 if (enc->input_state)
600 gst_video_codec_state_unref (enc->input_state);
601 enc->input_state = gst_video_codec_state_ref (state);
602
603 /* as done in theora */
604 enc->info.keyframe_granule_shift = _ilog (enc->keyframe_force - 1);
605 GST_DEBUG_OBJECT (enc,
606 "keyframe_frequency_force is %d, granule shift is %d",
607 enc->keyframe_force, enc->info.keyframe_granule_shift);
608
609 theora_enc_flush (benc);
610 enc->initialised = TRUE;
611
612 return TRUE;
613 }
614
615 static GstFlowReturn
theora_enc_pre_push(GstVideoEncoder * benc,GstVideoCodecFrame * frame)616 theora_enc_pre_push (GstVideoEncoder * benc, GstVideoCodecFrame * frame)
617 {
618 GstTheoraEnc *enc = GST_THEORA_ENC (benc);
619 guint64 pfn;
620
621 /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
622 * time representation */
623 /* granulepos from sync frame */
624 pfn = frame->presentation_frame_number - frame->distance_from_sync;
625 /* correct to correspond to linear running time */
626 pfn -= enc->pfn_offset;
627 pfn += enc->granulepos_offset + 1;
628 /* granulepos */
629 GST_BUFFER_OFFSET_END (frame->output_buffer) =
630 (pfn << enc->info.keyframe_granule_shift) + frame->distance_from_sync;
631 GST_BUFFER_OFFSET (frame->output_buffer) = granulepos_to_timestamp (enc,
632 GST_BUFFER_OFFSET_END (frame->output_buffer));
633
634 return GST_FLOW_OK;
635 }
636
637 static GstFlowReturn
theora_push_packet(GstTheoraEnc * enc,ogg_packet * packet)638 theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet)
639 {
640 GstVideoEncoder *benc;
641 GstFlowReturn ret;
642 GstVideoCodecFrame *frame;
643
644 benc = GST_VIDEO_ENCODER (enc);
645
646 frame = gst_video_encoder_get_oldest_frame (benc);
647 if (gst_video_encoder_allocate_output_frame (benc, frame,
648 packet->bytes) != GST_FLOW_OK) {
649 GST_WARNING_OBJECT (enc, "Could not allocate buffer");
650 gst_video_codec_frame_unref (frame);
651 ret = GST_FLOW_ERROR;
652 goto done;
653 }
654
655 if (packet->bytes > 0)
656 gst_buffer_fill (frame->output_buffer, 0, packet->packet, packet->bytes);
657
658 /* the second most significant bit of the first data byte is cleared
659 * for keyframes */
660 if (packet->bytes > 0 && (packet->packet[0] & 0x40) == 0) {
661 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
662 } else {
663 GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
664 }
665 enc->packetno++;
666
667 ret = gst_video_encoder_finish_frame (benc, frame);
668
669 done:
670 return ret;
671 }
672
673 static GstCaps *
theora_set_header_on_caps(GstCaps * caps,GList * buffers)674 theora_set_header_on_caps (GstCaps * caps, GList * buffers)
675 {
676 GstStructure *structure;
677 GValue array = { 0 };
678 GValue value = { 0 };
679 GstBuffer *buffer;
680 GList *walk;
681
682 caps = gst_caps_make_writable (caps);
683 structure = gst_caps_get_structure (caps, 0);
684
685 /* put copies of the buffers in a fixed list */
686 g_value_init (&array, GST_TYPE_ARRAY);
687
688 for (walk = buffers; walk; walk = walk->next) {
689 buffer = walk->data;
690 g_value_init (&value, GST_TYPE_BUFFER);
691 gst_value_set_buffer (&value, buffer);
692 gst_value_array_append_value (&array, &value);
693 g_value_unset (&value);
694 }
695
696 gst_structure_take_value (structure, "streamheader", &array);
697
698 return caps;
699 }
700
701 static void
theora_enc_init_buffer(th_ycbcr_buffer buf,GstVideoFrame * frame)702 theora_enc_init_buffer (th_ycbcr_buffer buf, GstVideoFrame * frame)
703 {
704 GstVideoInfo vinfo;
705 guint i;
706
707 /* According to Theora developer Timothy Terriberry, the Theora
708 * encoder will not use memory outside of pic_width/height, even when
709 * the frame size is bigger. The values outside this region will be encoded
710 * to default values.
711 * Due to this, setting the frame's width/height as the buffer width/height
712 * is perfectly ok, even though it does not strictly look ok.
713 */
714
715 gst_video_info_init (&vinfo);
716 gst_video_info_set_format (&vinfo, GST_VIDEO_FRAME_FORMAT (frame),
717 GST_ROUND_UP_16 (GST_VIDEO_FRAME_WIDTH (frame)),
718 GST_ROUND_UP_16 (GST_VIDEO_FRAME_HEIGHT (frame)));
719
720 for (i = 0; i < 3; i++) {
721 buf[i].width = GST_VIDEO_INFO_COMP_WIDTH (&vinfo, i);
722 buf[i].height = GST_VIDEO_INFO_COMP_HEIGHT (&vinfo, i);
723 buf[i].data = GST_VIDEO_FRAME_COMP_DATA (frame, i);
724 buf[i].stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
725 }
726 }
727
728 static gboolean
theora_enc_read_multipass_cache(GstTheoraEnc * enc)729 theora_enc_read_multipass_cache (GstTheoraEnc * enc)
730 {
731 GstBuffer *cache_buf;
732 const guint8 *cache_data;
733 gsize bytes_read = 0;
734 gssize bytes_consumed = 0;
735 GIOStatus stat = G_IO_STATUS_NORMAL;
736 gboolean done = FALSE;
737
738 while (!done) {
739 if (gst_adapter_available (enc->multipass_cache_adapter) == 0) {
740 GstMapInfo minfo;
741
742 cache_buf = gst_buffer_new_allocate (NULL, 512, NULL);
743
744 gst_buffer_map (cache_buf, &minfo, GST_MAP_WRITE);
745
746 stat = g_io_channel_read_chars (enc->multipass_cache_fd,
747 (gchar *) minfo.data, minfo.size, &bytes_read, NULL);
748
749 if (bytes_read <= 0) {
750 gst_buffer_unmap (cache_buf, &minfo);
751 gst_buffer_unref (cache_buf);
752 break;
753 } else {
754 gst_buffer_unmap (cache_buf, &minfo);
755 gst_buffer_resize (cache_buf, 0, bytes_read);
756
757 gst_adapter_push (enc->multipass_cache_adapter, cache_buf);
758 }
759 }
760 if (gst_adapter_available (enc->multipass_cache_adapter) == 0)
761 break;
762
763 bytes_read =
764 MIN (gst_adapter_available (enc->multipass_cache_adapter), 512);
765
766 cache_data = gst_adapter_map (enc->multipass_cache_adapter, bytes_read);
767
768 bytes_consumed =
769 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data,
770 bytes_read);
771 gst_adapter_unmap (enc->multipass_cache_adapter);
772
773 done = bytes_consumed <= 0;
774 if (bytes_consumed > 0)
775 gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed);
776 }
777
778 if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_EOF && bytes_read == 0)
779 || bytes_consumed < 0) {
780 GST_ELEMENT_ERROR (enc, RESOURCE, READ, (NULL),
781 ("Failed to read multipass cache file"));
782 return FALSE;
783 }
784 return TRUE;
785 }
786
787 static gboolean
theora_enc_write_multipass_cache(GstTheoraEnc * enc,gboolean begin,gboolean eos)788 theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin,
789 gboolean eos)
790 {
791 GError *err = NULL;
792 GIOStatus stat = G_IO_STATUS_NORMAL;
793 gint bytes_read = 0;
794 gsize bytes_written = 0;
795 gchar *buf;
796
797 if (begin) {
798 stat = g_io_channel_seek_position (enc->multipass_cache_fd, 0, G_SEEK_SET,
799 &err);
800
801 if (stat == G_IO_STATUS_ERROR) {
802 if (eos)
803 GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL),
804 ("Failed to seek to beginning of multipass cache file: %s",
805 err->message));
806 else
807 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
808 ("Failed to seek to beginning of multipass cache file: %s",
809 err->message));
810 g_error_free (err);
811 return FALSE;
812 }
813 }
814
815
816 do {
817 bytes_read =
818 th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_OUT, &buf, sizeof (buf));
819 if (bytes_read > 0)
820 g_io_channel_write_chars (enc->multipass_cache_fd, buf, bytes_read,
821 &bytes_written, &err);
822 } while (bytes_read > 0 && bytes_written > 0 && !err);
823
824 if (bytes_read < 0 || err) {
825 if (bytes_read < 0) {
826 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
827 ("Failed to read multipass cache data: %d", bytes_read));
828 } else {
829 GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL),
830 ("Failed to write multipass cache file: %s", err->message));
831 }
832 if (err)
833 g_error_free (err);
834
835 return FALSE;
836 }
837
838 return TRUE;
839 }
840
841 static void
theora_enc_reset_ts(GstTheoraEnc * enc,GstClockTime running_time,gint pfn)842 theora_enc_reset_ts (GstTheoraEnc * enc, GstClockTime running_time, gint pfn)
843 {
844 enc->granulepos_offset =
845 gst_util_uint64_scale (running_time, enc->fps_n, GST_SECOND * enc->fps_d);
846 enc->timestamp_offset = running_time;
847 enc->pfn_offset = pfn;
848 }
849
850 static GstBuffer *
theora_enc_buffer_from_header_packet(GstTheoraEnc * enc,ogg_packet * packet)851 theora_enc_buffer_from_header_packet (GstTheoraEnc * enc, ogg_packet * packet)
852 {
853 GstBuffer *outbuf;
854
855 outbuf =
856 gst_video_encoder_allocate_output_buffer (GST_VIDEO_ENCODER (enc),
857 packet->bytes);
858 gst_buffer_fill (outbuf, 0, packet->packet, packet->bytes);
859 GST_BUFFER_OFFSET (outbuf) = 0;
860 GST_BUFFER_OFFSET_END (outbuf) = 0;
861 GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
862 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
863 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_HEADER);
864
865 GST_DEBUG ("created header packet buffer, %u bytes",
866 (guint) gst_buffer_get_size (outbuf));
867 return outbuf;
868 }
869
870 static GstFlowReturn
theora_enc_handle_frame(GstVideoEncoder * benc,GstVideoCodecFrame * frame)871 theora_enc_handle_frame (GstVideoEncoder * benc, GstVideoCodecFrame * frame)
872 {
873 GstTheoraEnc *enc;
874 ogg_packet op;
875 GstClockTime timestamp, running_time;
876 GstFlowReturn ret;
877 gboolean force_keyframe;
878
879 enc = GST_THEORA_ENC (benc);
880
881 /* we keep track of two timelines.
882 * - The timestamps from the incomming buffers, which we copy to the outgoing
883 * encoded buffers as-is. We need to do this as we simply forward the
884 * newsegment events.
885 * - The running_time of the buffers, which we use to construct the granulepos
886 * in the packets.
887 */
888 timestamp = frame->pts;
889
890 /* incoming buffers are clipped, so this should be positive */
891 running_time =
892 gst_segment_to_running_time (&GST_VIDEO_ENCODER_INPUT_SEGMENT (enc),
893 GST_FORMAT_TIME, timestamp);
894
895 GST_OBJECT_LOCK (enc);
896 if (enc->bitrate_changed) {
897 long int bitrate = enc->video_bitrate;
898
899 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
900 sizeof (long int));
901 enc->bitrate_changed = FALSE;
902 }
903
904 if (enc->quality_changed) {
905 long int quality = enc->video_quality;
906
907 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
908 sizeof (long int));
909 enc->quality_changed = FALSE;
910 }
911
912 /* see if we need to schedule a keyframe */
913 force_keyframe = GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame);
914 GST_OBJECT_UNLOCK (enc);
915
916 if (enc->packetno == 0) {
917 /* no packets written yet, setup headers */
918 GstCaps *caps;
919 GstBuffer *buf;
920 GList *buffers = NULL;
921 int result;
922 GstVideoCodecState *state;
923
924 enc->granulepos_offset = 0;
925 enc->timestamp_offset = 0;
926
927 GST_DEBUG_OBJECT (enc, "output headers");
928 /* Theora streams begin with three headers; the initial header (with
929 most of the codec setup parameters) which is mandated by the Ogg
930 bitstream spec. The second header holds any comment fields. The
931 third header holds the bitstream codebook. We merely need to
932 make the headers, then pass them to libtheora one at a time;
933 libtheora handles the additional Ogg bitstream constraints */
934
935 /* create the remaining theora headers */
936 th_comment_clear (&enc->comment);
937 th_comment_init (&enc->comment);
938
939 while ((result =
940 th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
941 buf = theora_enc_buffer_from_header_packet (enc, &op);
942 buffers = g_list_prepend (buffers, buf);
943 }
944 if (result < 0) {
945 g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
946 g_list_free (buffers);
947 goto encoder_disabled;
948 }
949
950 buffers = g_list_reverse (buffers);
951
952 /* mark buffers and put on caps */
953 caps = gst_caps_new_empty_simple ("video/x-theora");
954 caps = theora_set_header_on_caps (caps, buffers);
955 state = gst_video_encoder_set_output_state (benc, caps, enc->input_state);
956
957 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, state->caps);
958
959 gst_video_codec_state_unref (state);
960
961 gst_video_encoder_negotiate (GST_VIDEO_ENCODER (enc));
962
963 gst_video_encoder_set_headers (benc, buffers);
964
965 theora_enc_reset_ts (enc, running_time, frame->presentation_frame_number);
966 }
967
968 {
969 th_ycbcr_buffer ycbcr;
970 gint res, keyframe_interval;
971 GstVideoFrame vframe;
972
973 if (force_keyframe) {
974 /* if we want a keyframe, temporarily reset the max keyframe interval
975 * to 1, which will cause libtheora to emit one. There is no API to
976 * request a keyframe at the moment. */
977 keyframe_interval = 1;
978 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
979 &keyframe_interval, sizeof (keyframe_interval));
980 }
981
982 if (enc->multipass_cache_fd
983 && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
984 if (!theora_enc_read_multipass_cache (enc)) {
985 ret = GST_FLOW_ERROR;
986 goto multipass_read_failed;
987 }
988 }
989
990 gst_video_frame_map (&vframe, &enc->input_state->info, frame->input_buffer,
991 GST_MAP_READ);
992 theora_enc_init_buffer (ycbcr, &vframe);
993
994 res = th_encode_ycbcr_in (enc->encoder, ycbcr);
995 gst_video_frame_unmap (&vframe);
996
997 /* none of the failure cases can happen here */
998 g_assert (res == 0);
999
1000 if (enc->multipass_cache_fd
1001 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
1002 if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
1003 ret = GST_FLOW_ERROR;
1004 goto multipass_write_failed;
1005 }
1006 }
1007
1008 ret = GST_FLOW_OK;
1009 while (th_encode_packetout (enc->encoder, 0, &op)) {
1010 /* Reset the max keyframe interval to its original state, and reset
1011 * the flag so we don't create more keyframes if we loop */
1012 if (force_keyframe) {
1013 keyframe_interval =
1014 enc->keyframe_auto ? enc->keyframe_force : enc->keyframe_freq;
1015 th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
1016 &keyframe_interval, sizeof (keyframe_interval));
1017 force_keyframe = FALSE;
1018 }
1019
1020 ret = theora_push_packet (enc, &op);
1021 if (ret != GST_FLOW_OK)
1022 goto beach;
1023 }
1024 }
1025
1026 beach:
1027 gst_video_codec_frame_unref (frame);
1028 return ret;
1029
1030 /* ERRORS */
1031 multipass_read_failed:
1032 {
1033 gst_video_codec_frame_unref (frame);
1034 return ret;
1035 }
1036 multipass_write_failed:
1037 {
1038 gst_video_codec_frame_unref (frame);
1039 return ret;
1040 }
1041 encoder_disabled:
1042 {
1043 gst_video_codec_frame_unref (frame);
1044 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1045 ("libtheora has been compiled with the encoder disabled"));
1046 return GST_FLOW_ERROR;
1047 }
1048 }
1049
1050 static gboolean
theora_enc_finish(GstVideoEncoder * benc)1051 theora_enc_finish (GstVideoEncoder * benc)
1052 {
1053 GstTheoraEnc *enc;
1054 ogg_packet op;
1055
1056 enc = GST_THEORA_ENC (benc);
1057
1058 if (enc->initialised) {
1059 /* push last packet with eos flag, should not be called */
1060 while (th_encode_packetout (enc->encoder, 1, &op)) {
1061 theora_push_packet (enc, &op);
1062 }
1063 }
1064 if (enc->initialised && enc->multipass_cache_fd
1065 && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
1066 theora_enc_write_multipass_cache (enc, TRUE, TRUE);
1067
1068 theora_enc_clear_multipass_cache (enc);
1069
1070 return TRUE;
1071 }
1072
1073 static gboolean
theora_enc_propose_allocation(GstVideoEncoder * encoder,GstQuery * query)1074 theora_enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
1075 {
1076 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
1077
1078 return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
1079 query);
1080 }
1081
1082 static void
theora_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1083 theora_enc_set_property (GObject * object, guint prop_id,
1084 const GValue * value, GParamSpec * pspec)
1085 {
1086 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1087
1088 switch (prop_id) {
1089 case PROP_BITRATE:
1090 GST_OBJECT_LOCK (enc);
1091 enc->video_bitrate = g_value_get_int (value) * 1000;
1092 enc->video_quality = 0;
1093 enc->bitrate_changed = TRUE;
1094 GST_OBJECT_UNLOCK (enc);
1095 break;
1096 case PROP_QUALITY:
1097 GST_OBJECT_LOCK (enc);
1098 if (GST_STATE (enc) >= GST_STATE_PAUSED && enc->video_quality == 0) {
1099 GST_WARNING_OBJECT (object, "Can't change from bitrate to quality mode"
1100 " while playing");
1101 } else {
1102 enc->video_quality = g_value_get_int (value);
1103 enc->video_bitrate = 0;
1104 enc->quality_changed = TRUE;
1105 }
1106 GST_OBJECT_UNLOCK (enc);
1107 break;
1108 case PROP_KEYFRAME_AUTO:
1109 enc->keyframe_auto = g_value_get_boolean (value);
1110 break;
1111 case PROP_KEYFRAME_FREQ:
1112 enc->keyframe_freq = g_value_get_int (value);
1113 break;
1114 case PROP_KEYFRAME_FREQ_FORCE:
1115 enc->keyframe_force = g_value_get_int (value);
1116 break;
1117 case PROP_SPEEDLEVEL:
1118 enc->speed_level = g_value_get_int (value);
1119 break;
1120 case PROP_VP3_COMPATIBLE:
1121 enc->vp3_compatible = g_value_get_boolean (value);
1122 break;
1123 case PROP_DROP_FRAMES:
1124 enc->drop_frames = g_value_get_boolean (value);
1125 break;
1126 case PROP_CAP_OVERFLOW:
1127 enc->cap_overflow = g_value_get_boolean (value);
1128 break;
1129 case PROP_CAP_UNDERFLOW:
1130 enc->cap_underflow = g_value_get_boolean (value);
1131 break;
1132 case PROP_RATE_BUFFER:
1133 enc->rate_buffer = g_value_get_int (value);
1134 break;
1135 case PROP_MULTIPASS_CACHE_FILE:
1136 enc->multipass_cache_file = g_value_dup_string (value);
1137 break;
1138 case PROP_MULTIPASS_MODE:
1139 enc->multipass_mode = g_value_get_enum (value);
1140 break;
1141 default:
1142 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1143 break;
1144 }
1145 }
1146
1147 static void
theora_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1148 theora_enc_get_property (GObject * object, guint prop_id,
1149 GValue * value, GParamSpec * pspec)
1150 {
1151 GstTheoraEnc *enc = GST_THEORA_ENC (object);
1152
1153 switch (prop_id) {
1154 case PROP_BITRATE:
1155 GST_OBJECT_LOCK (enc);
1156 g_value_set_int (value, enc->video_bitrate / 1000);
1157 GST_OBJECT_UNLOCK (enc);
1158 break;
1159 case PROP_QUALITY:
1160 GST_OBJECT_LOCK (enc);
1161 g_value_set_int (value, enc->video_quality);
1162 GST_OBJECT_UNLOCK (enc);
1163 break;
1164 case PROP_KEYFRAME_AUTO:
1165 g_value_set_boolean (value, enc->keyframe_auto);
1166 break;
1167 case PROP_KEYFRAME_FREQ:
1168 g_value_set_int (value, enc->keyframe_freq);
1169 break;
1170 case PROP_KEYFRAME_FREQ_FORCE:
1171 g_value_set_int (value, enc->keyframe_force);
1172 break;
1173 case PROP_SPEEDLEVEL:
1174 g_value_set_int (value, enc->speed_level);
1175 break;
1176 case PROP_VP3_COMPATIBLE:
1177 g_value_set_boolean (value, enc->vp3_compatible);
1178 break;
1179 case PROP_DROP_FRAMES:
1180 g_value_set_boolean (value, enc->drop_frames);
1181 break;
1182 case PROP_CAP_OVERFLOW:
1183 g_value_set_boolean (value, enc->cap_overflow);
1184 break;
1185 case PROP_CAP_UNDERFLOW:
1186 g_value_set_boolean (value, enc->cap_underflow);
1187 break;
1188 case PROP_RATE_BUFFER:
1189 g_value_set_int (value, enc->rate_buffer);
1190 break;
1191 case PROP_MULTIPASS_CACHE_FILE:
1192 g_value_set_string (value, enc->multipass_cache_file);
1193 break;
1194 case PROP_MULTIPASS_MODE:
1195 g_value_set_enum (value, enc->multipass_mode);
1196 break;
1197 default:
1198 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1199 break;
1200 }
1201 }
1202