2 * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
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-theoradec
22 * @see_also: theoraenc, oggdemux
24 * This element decodes theora streams into raw video
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.
30 * <title>Example pipeline</title>
32 * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! xvimagesink
33 * ]| This example pipeline will decode an ogg stream and decodes the theora video. Refer to
34 * the theoraenc example to create the ogg file.
37 * Last reviewed on 2006-03-01 (0.10.4)
44 #include "gsttheoradec.h"
45 #include <gst/tag/tag.h>
46 #include <gst/video/video.h>
47 #include <gst/video/gstvideometa.h>
48 #include <gst/video/gstvideopool.h>
50 #define GST_CAT_DEFAULT theoradec_debug
51 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
53 #define THEORA_DEF_TELEMETRY_MV 0
54 #define THEORA_DEF_TELEMETRY_MBMODE 0
55 #define THEORA_DEF_TELEMETRY_QI 0
56 #define THEORA_DEF_TELEMETRY_BITS 0
62 PROP_TELEMETRY_MBMODE,
67 static GstStaticPadTemplate theora_dec_src_factory =
68 GST_STATIC_PAD_TEMPLATE ("src",
71 GST_STATIC_CAPS ("video/x-raw, "
72 "format = (string) { I420, Y42B, Y444 }, "
73 "framerate = (fraction) [0/1, MAX], "
74 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
77 static GstStaticPadTemplate theora_dec_sink_factory =
78 GST_STATIC_PAD_TEMPLATE ("sink",
81 GST_STATIC_CAPS ("video/x-theora")
84 #define gst_theora_dec_parent_class parent_class
85 G_DEFINE_TYPE (GstTheoraDec, gst_theora_dec, GST_TYPE_ELEMENT);
87 static void theora_dec_get_property (GObject * object, guint prop_id,
88 GValue * value, GParamSpec * pspec);
89 static void theora_dec_set_property (GObject * object, guint prop_id,
90 const GValue * value, GParamSpec * pspec);
92 static gboolean theora_dec_setcaps (GstTheoraDec * dec, GstCaps * caps);
93 static gboolean theora_dec_sink_event (GstPad * pad, GstObject * parent,
95 static GstFlowReturn theora_dec_chain (GstPad * pad, GstObject * parent,
97 static GstStateChangeReturn theora_dec_change_state (GstElement * element,
98 GstStateChange transition);
99 static gboolean theora_dec_src_event (GstPad * pad, GstObject * parent,
101 static gboolean theora_dec_src_query (GstPad * pad, GstObject * parent,
103 static gboolean theora_dec_src_convert (GstPad * pad, GstFormat src_format,
104 gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
107 static const GstFormat *theora_get_formats (GstPad * pad);
110 static const GstEventMask *theora_get_event_masks (GstPad * pad);
114 gst_theora_dec_ctl_is_supported (int req)
116 /* should return TH_EFAULT or TH_EINVAL if supported, and TH_EIMPL if not */
117 return (th_decode_ctl (NULL, req, NULL, 0) != TH_EIMPL);
121 gst_theora_dec_class_init (GstTheoraDecClass * klass)
123 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
124 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
126 gobject_class->set_property = theora_dec_set_property;
127 gobject_class->get_property = theora_dec_get_property;
129 if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_MV)) {
130 g_object_class_install_property (gobject_class, PROP_TELEMETRY_MV,
131 g_param_spec_int ("visualize-motion-vectors",
132 "Visualize motion vectors",
133 "Show motion vector selection overlaid on image. "
134 "Value gives a mask for motion vector (MV) modes to show",
135 0, 0xffff, THEORA_DEF_TELEMETRY_MV,
136 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
139 if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_MBMODE)) {
140 g_object_class_install_property (gobject_class, PROP_TELEMETRY_MBMODE,
141 g_param_spec_int ("visualize-macroblock-modes",
142 "Visualize macroblock modes",
143 "Show macroblock mode selection overlaid on image. "
144 "Value gives a mask for macroblock (MB) modes to show",
145 0, 0xffff, THEORA_DEF_TELEMETRY_MBMODE,
146 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
149 if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_QI)) {
150 g_object_class_install_property (gobject_class, PROP_TELEMETRY_QI,
151 g_param_spec_int ("visualize-quantization-modes",
152 "Visualize adaptive quantization modes",
153 "Show adaptive quantization mode selection overlaid on image. "
154 "Value gives a mask for quantization (QI) modes to show",
155 0, 0xffff, THEORA_DEF_TELEMETRY_QI,
156 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
159 if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_BITS)) {
160 /* FIXME: make this a boolean instead? The value scales the bars so
161 * they're less wide. Default is to use full width, and anything else
162 * doesn't seem particularly useful, since the smaller bars just disappear
163 * then (they almost disappear for a value of 2 already). */
164 g_object_class_install_property (gobject_class, PROP_TELEMETRY_BITS,
165 g_param_spec_int ("visualize-bit-usage",
166 "Visualize bitstream usage breakdown",
167 "Sets the bitstream breakdown visualization mode. "
168 "Values influence the width of the bit usage bars to show",
169 0, 0xff, THEORA_DEF_TELEMETRY_BITS,
170 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
173 gst_element_class_add_pad_template (gstelement_class,
174 gst_static_pad_template_get (&theora_dec_src_factory));
175 gst_element_class_add_pad_template (gstelement_class,
176 gst_static_pad_template_get (&theora_dec_sink_factory));
177 gst_element_class_set_details_simple (gstelement_class,
178 "Theora video decoder", "Codec/Decoder/Video",
179 "decode raw theora streams to raw YUV video",
180 "Benjamin Otte <otte@gnome.org>, Wim Taymans <wim@fluendo.com>");
182 gstelement_class->change_state = theora_dec_change_state;
184 GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
188 gst_theora_dec_init (GstTheoraDec * dec)
191 gst_pad_new_from_static_template (&theora_dec_sink_factory, "sink");
192 gst_pad_set_event_function (dec->sinkpad, theora_dec_sink_event);
193 gst_pad_set_chain_function (dec->sinkpad, theora_dec_chain);
194 gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
197 gst_pad_new_from_static_template (&theora_dec_src_factory, "src");
198 gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
199 gst_pad_set_query_function (dec->srcpad, theora_dec_src_query);
200 gst_pad_use_fixed_caps (dec->srcpad);
202 gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
204 dec->telemetry_mv = THEORA_DEF_TELEMETRY_MV;
205 dec->telemetry_mbmode = THEORA_DEF_TELEMETRY_MBMODE;
206 dec->telemetry_qi = THEORA_DEF_TELEMETRY_QI;
207 dec->telemetry_bits = THEORA_DEF_TELEMETRY_BITS;
211 dec->pendingevents = NULL;
215 gst_theora_dec_reset (GstTheoraDec * dec)
217 dec->need_keyframe = TRUE;
218 dec->last_timestamp = -1;
221 dec->seqnum = gst_util_seqnum_next ();
224 gst_segment_init (&dec->segment, GST_FORMAT_TIME);
226 GST_OBJECT_LOCK (dec);
227 dec->proportion = 1.0;
228 dec->earliest_time = -1;
229 GST_OBJECT_UNLOCK (dec);
231 g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
232 g_list_free (dec->queued);
234 g_list_foreach (dec->gather, (GFunc) gst_mini_object_unref, NULL);
235 g_list_free (dec->gather);
237 g_list_foreach (dec->decode, (GFunc) gst_mini_object_unref, NULL);
238 g_list_free (dec->decode);
240 g_list_foreach (dec->pendingevents, (GFunc) gst_mini_object_unref, NULL);
241 g_list_free (dec->pendingevents);
242 dec->pendingevents = NULL;
245 gst_tag_list_free (dec->tags);
251 static const GstFormat *
252 theora_get_formats (GstPad * pad)
254 static GstFormat src_formats[] = {
255 GST_FORMAT_DEFAULT, /* frames in this case */
260 static GstFormat sink_formats[] = {
266 return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
271 static const GstEventMask *
272 theora_get_event_masks (GstPad * pad)
274 static const GstEventMask theora_src_event_masks[] = {
275 {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH},
279 return theora_src_event_masks;
284 theora_dec_src_convert (GstPad * pad,
285 GstFormat src_format, gint64 src_value,
286 GstFormat * dest_format, gint64 * dest_value)
292 if (src_format == *dest_format) {
293 *dest_value = src_value;
297 dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
299 /* we need the info part before we can done something */
300 if (!dec->have_header)
303 switch (src_format) {
304 case GST_FORMAT_BYTES:
305 switch (*dest_format) {
306 case GST_FORMAT_DEFAULT:
307 *dest_value = gst_util_uint64_scale_int (src_value, 8,
308 dec->info.pic_height * dec->info.pic_width * dec->output_bpp);
310 case GST_FORMAT_TIME:
311 /* seems like a rather silly conversion, implement me if you like */
316 case GST_FORMAT_TIME:
317 switch (*dest_format) {
318 case GST_FORMAT_BYTES:
320 dec->output_bpp * (dec->info.pic_width * dec->info.pic_height) /
322 case GST_FORMAT_DEFAULT:
323 *dest_value = scale * gst_util_uint64_scale (src_value,
324 dec->info.fps_numerator, dec->info.fps_denominator * GST_SECOND);
330 case GST_FORMAT_DEFAULT:
331 switch (*dest_format) {
332 case GST_FORMAT_TIME:
333 *dest_value = gst_util_uint64_scale (src_value,
334 GST_SECOND * dec->info.fps_denominator, dec->info.fps_numerator);
336 case GST_FORMAT_BYTES:
337 *dest_value = gst_util_uint64_scale_int (src_value,
338 dec->output_bpp * dec->info.pic_width * dec->info.pic_height, 8);
348 gst_object_unref (dec);
354 GST_DEBUG_OBJECT (dec, "no header yet, cannot convert");
362 theora_dec_sink_convert (GstPad * pad,
363 GstFormat src_format, gint64 src_value,
364 GstFormat * dest_format, gint64 * dest_value)
369 if (src_format == *dest_format) {
370 *dest_value = src_value;
374 dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
376 /* we need the info part before we can done something */
377 if (!dec->have_header)
380 switch (src_format) {
381 case GST_FORMAT_DEFAULT:
382 switch (*dest_format) {
383 case GST_FORMAT_TIME:
384 *dest_value = _theora_granule_start_time (dec, src_value);
390 case GST_FORMAT_TIME:
391 switch (*dest_format) {
392 case GST_FORMAT_DEFAULT:
397 *dest_value = gst_util_uint64_scale (src_value,
398 dec->info.fps_numerator, GST_SECOND * dec->info.fps_denominator);
400 /* funny way of calculating granulepos in theora */
401 rest = *dest_value / dec->info.keyframe_granule_shift;
403 *dest_value <<= dec->granule_shift;
416 gst_object_unref (dec);
422 GST_DEBUG_OBJECT (dec, "no header yet, cannot convert");
430 theora_dec_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
433 gboolean res = FALSE;
435 dec = GST_THEORA_DEC (parent);
437 switch (GST_QUERY_TYPE (query)) {
438 case GST_QUERY_POSITION:
445 gst_query_parse_position (query, &format, NULL);
447 time = dec->last_timestamp;
448 time = gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, time);
451 "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time));
454 theora_dec_src_convert (pad, GST_FORMAT_TIME, time, &format,
458 gst_query_set_position (query, format, value);
461 "query %p: we return %" G_GINT64_FORMAT " (format %u)", query, value,
465 case GST_QUERY_DURATION:
467 /* forward to peer for total */
468 res = gst_pad_peer_query (dec->sinkpad, query);
474 case GST_QUERY_CONVERT:
476 GstFormat src_fmt, dest_fmt;
477 gint64 src_val, dest_val;
479 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
481 theora_dec_src_convert (pad, src_fmt, src_val, &dest_fmt,
485 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
489 res = gst_pad_query_default (pad, parent, query);
499 GST_DEBUG_OBJECT (dec, "query failed");
505 theora_dec_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
510 dec = GST_THEORA_DEC (parent);
512 switch (GST_EVENT_TYPE (event)) {
515 GstFormat format, tformat;
519 GstSeekType cur_type, stop_type;
524 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
526 seqnum = gst_event_get_seqnum (event);
527 gst_event_unref (event);
529 /* we have to ask our peer to seek to time here as we know
530 * nothing about how to generate a granulepos from the src
531 * formats or anything.
533 * First bring the requested format to time
535 tformat = GST_FORMAT_TIME;
536 if (!(res = theora_dec_src_convert (pad, format, cur, &tformat, &tcur)))
538 if (!(res = theora_dec_src_convert (pad, format, stop, &tformat, &tstop)))
541 /* then seek with time on the peer */
542 real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
543 flags, cur_type, tcur, stop_type, tstop);
544 gst_event_set_seqnum (real_seek, seqnum);
546 res = gst_pad_push_event (dec->sinkpad, real_seek);
552 GstClockTimeDiff diff;
553 GstClockTime timestamp;
555 gst_event_parse_qos (event, NULL, &proportion, &diff, ×tamp);
557 /* we cannot randomly skip frame decoding since we don't have
558 * B frames. we can however use the timestamp and diff to not
559 * push late frames. This would at least save us the time to
560 * crop/memcpy the data. */
561 GST_OBJECT_LOCK (dec);
562 dec->proportion = proportion;
563 dec->earliest_time = timestamp + diff;
564 GST_OBJECT_UNLOCK (dec);
566 GST_DEBUG_OBJECT (dec, "got QoS %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
567 GST_TIME_ARGS (timestamp), diff);
569 res = gst_pad_push_event (dec->sinkpad, event);
573 res = gst_pad_push_event (dec->sinkpad, event);
583 GST_DEBUG_OBJECT (dec, "could not convert format");
589 theora_dec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
591 gboolean ret = FALSE;
594 dec = GST_THEORA_DEC (parent);
596 GST_LOG_OBJECT (dec, "handling event");
597 switch (GST_EVENT_TYPE (event)) {
598 case GST_EVENT_FLUSH_START:
599 ret = gst_pad_push_event (dec->srcpad, event);
601 case GST_EVENT_FLUSH_STOP:
602 gst_theora_dec_reset (dec);
603 ret = gst_pad_push_event (dec->srcpad, event);
606 ret = gst_pad_push_event (dec->srcpad, event);
608 case GST_EVENT_SEGMENT:
610 const GstSegment *segment;
612 gst_event_parse_segment (event, &segment);
614 /* we need TIME format */
615 if (segment->format != GST_FORMAT_TIME)
616 goto newseg_wrong_format;
618 GST_DEBUG_OBJECT (dec, "segment: %" GST_SEGMENT_FORMAT, segment);
620 /* now configure the values */
621 gst_segment_copy_into (segment, &dec->segment);
622 dec->seqnum = gst_event_get_seqnum (event);
624 /* We don't forward this unless/until the decoder is initialised */
625 if (dec->have_header) {
626 ret = gst_pad_push_event (dec->srcpad, event);
628 dec->pendingevents = g_list_append (dec->pendingevents, event);
637 gst_event_parse_caps (event, &caps);
638 ret = theora_dec_setcaps (dec, caps);
639 gst_event_unref (event);
644 if (dec->have_header)
646 ret = gst_pad_push_event (dec->srcpad, event);
648 /* store it to send once we're initialized */
649 dec->pendingevents = g_list_append (dec->pendingevents, event);
655 ret = gst_pad_event_default (pad, parent, event);
665 GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
666 gst_event_unref (event);
672 theora_dec_setcaps (GstTheoraDec * dec, GstCaps * caps)
675 const GValue *codec_data;
677 s = gst_caps_get_structure (caps, 0);
679 /* parse the par, this overrides the encoded par */
680 dec->have_par = gst_structure_get_fraction (s, "pixel-aspect-ratio",
681 &dec->par_num, &dec->par_den);
683 if ((codec_data = gst_structure_get_value (s, "codec_data"))) {
684 if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
691 buffer = gst_value_get_buffer (codec_data);
694 gst_buffer_map (buffer, &map, GST_MAP_READ);
703 psize = (ptr[0] << 8) | ptr[1];
709 /* make sure we don't read too much */
710 psize = MIN (psize, left);
713 gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, psize);
715 /* first buffer is a discont buffer */
717 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
719 /* now feed it to the decoder we can ignore the error */
720 theora_dec_chain (dec->sinkpad, GST_OBJECT_CAST (dec), buf);
727 gst_buffer_unmap (buffer, &map);
735 theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
737 gchar *encoder = NULL;
740 GST_DEBUG_OBJECT (dec, "parsing comment packet");
743 gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
744 (guint8 *) "\201theora", 7, &encoder);
747 GST_ERROR_OBJECT (dec, "couldn't decode comments");
748 list = gst_tag_list_new_empty ();
751 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
752 GST_TAG_ENCODER, encoder, NULL);
755 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
756 GST_TAG_ENCODER_VERSION, dec->info.version_major,
757 GST_TAG_VIDEO_CODEC, "Theora", NULL);
759 if (dec->info.target_bitrate > 0) {
760 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
761 GST_TAG_BITRATE, dec->info.target_bitrate,
762 GST_TAG_NOMINAL_BITRATE, dec->info.target_bitrate, NULL);
771 theora_negotiate (GstTheoraDec * dec)
773 GstVideoFormat format;
776 guint size, min, max;
777 GstStructure *config;
779 GstVideoInfo info, cinfo;
783 * frame_width/frame_height : dimension of the encoded frame
784 * pic_width/pic_height : dimension of the visible part
785 * pic_x/pic_y : offset in encoded frame where visible part starts
787 GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, PAR %d/%d, fps %d/%d",
788 dec->info.frame_width, dec->info.frame_height,
789 dec->info.aspect_numerator, dec->info.aspect_denominator,
790 dec->info.fps_numerator, dec->info.fps_denominator);
791 GST_DEBUG_OBJECT (dec, "picture dimension %dx%d, offset %d:%d",
792 dec->info.pic_width, dec->info.pic_height, dec->info.pic_x,
795 switch (dec->info.pixel_fmt) {
797 dec->output_bpp = 24;
798 format = GST_VIDEO_FORMAT_Y444;
801 dec->output_bpp = 12; /* Average bits per pixel. */
802 format = GST_VIDEO_FORMAT_I420;
805 dec->output_bpp = 16;
806 format = GST_VIDEO_FORMAT_Y42B;
812 if (dec->info.pic_width != dec->info.frame_width ||
813 dec->info.pic_height != dec->info.frame_height ||
814 dec->info.pic_x != 0 || dec->info.pic_y != 0) {
815 GST_DEBUG_OBJECT (dec, "we need to crop");
816 dec->need_cropping = TRUE;
818 GST_DEBUG_OBJECT (dec, "no cropping needed");
819 dec->need_cropping = FALSE;
822 /* info contains the dimensions for the coded picture before cropping */
823 gst_video_info_init (&info);
824 gst_video_info_set_format (&info, format, dec->info.frame_width,
825 dec->info.frame_height);
826 info.fps_n = dec->info.fps_numerator;
827 info.fps_d = dec->info.fps_denominator;
829 * the info.aspect_* values reflect PAR;
830 * 0:x and x:0 are allowed and can be interpreted as 1:1.
833 /* we had a par on the sink caps, override the encoded par */
834 GST_DEBUG_OBJECT (dec, "overriding with input PAR %dx%d", dec->par_num,
836 info.par_n = dec->par_num;
837 info.par_d = dec->par_den;
839 /* take encoded par */
840 info.par_n = dec->info.aspect_numerator;
841 info.par_d = dec->info.aspect_denominator;
843 if (info.par_n == 0 || info.par_d == 0) {
844 info.par_n = info.par_d = 1;
847 /* these values are for all versions of the colorspace specified in the
849 info.chroma_site = GST_VIDEO_CHROMA_SITE_JPEG;
850 info.colorimetry.range = GST_VIDEO_COLOR_RANGE_16_235;
851 info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
852 info.colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
853 switch (dec->info.colorspace) {
854 case TH_CS_ITU_REC_470M:
855 info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M;
857 case TH_CS_ITU_REC_470BG:
858 info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
861 info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
865 /* remove reconfigure flag now */
866 gst_pad_check_reconfigure (dec->srcpad);
868 /* for the output caps we always take the cropped dimensions */
870 gst_video_info_set_format (&cinfo, GST_VIDEO_INFO_FORMAT (&info),
871 dec->info.pic_width, dec->info.pic_height);
872 caps = gst_video_info_to_caps (&cinfo);
873 gst_pad_set_caps (dec->srcpad, caps);
875 /* find a pool for the negotiated caps now */
876 query = gst_query_new_allocation (caps, TRUE);
878 if (gst_pad_peer_query (dec->srcpad, query)) {
879 /* check if downstream supports cropping */
881 gst_query_has_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE);
883 /* not a problem, deal with defaults */
884 GST_DEBUG_OBJECT (dec, "didn't get downstream ALLOCATION hints");
885 dec->has_cropping = FALSE;
888 if (gst_query_get_n_allocation_pools (query) > 0) {
889 /* we got configuration from our peer, parse them */
890 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
896 GST_DEBUG_OBJECT (dec, "downstream cropping %d", dec->has_cropping);
899 /* we did not get a pool, make one ourselves then */
900 pool = gst_video_buffer_pool_new ();
904 gst_object_unref (dec->pool);
907 if (dec->has_cropping) {
909 /* we can crop, configure the pool with buffers of caps and size of the
910 * decoded picture size and then crop them with metadata */
911 gst_caps_unref (caps);
912 caps = gst_video_info_to_caps (&info);
914 /* no cropping, use cropped videoinfo */
917 size = MAX (size, GST_VIDEO_INFO_SIZE (&dec->vinfo));
919 config = gst_buffer_pool_get_config (pool);
920 gst_buffer_pool_config_set (config, caps, size, min, max, 0, 0, 0);
921 gst_caps_unref (caps);
923 if (gst_query_has_allocation_meta (query, GST_VIDEO_META_API_TYPE)) {
924 /* just set the option, if the pool can support it we will transparently use
925 * it through the video info API. We could also see if the pool support this
926 * option and only activate it then. */
927 gst_buffer_pool_config_add_option (config,
928 GST_BUFFER_POOL_OPTION_VIDEO_META);
931 gst_buffer_pool_set_config (pool, config);
933 gst_buffer_pool_set_active (pool, TRUE);
935 gst_query_unref (query);
942 GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixel_fmt);
943 return GST_FLOW_ERROR;
948 theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
950 GstFlowReturn ret = GST_FLOW_OK;
953 if ((ret = theora_negotiate (dec)) != GST_FLOW_OK)
954 goto negotiate_failed;
957 dec->decoder = th_decode_alloc (&dec->info, dec->setup);
959 if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MV,
960 &dec->telemetry_mv, sizeof (dec->telemetry_mv)) != TH_EIMPL) {
961 GST_WARNING_OBJECT (dec, "Could not enable MV visualisation");
963 if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MBMODE,
964 &dec->telemetry_mbmode, sizeof (dec->telemetry_mbmode)) != TH_EIMPL) {
965 GST_WARNING_OBJECT (dec, "Could not enable MB mode visualisation");
967 if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_QI,
968 &dec->telemetry_qi, sizeof (dec->telemetry_qi)) != TH_EIMPL) {
969 GST_WARNING_OBJECT (dec, "Could not enable QI mode visualisation");
971 if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_BITS,
972 &dec->telemetry_bits, sizeof (dec->telemetry_bits)) != TH_EIMPL) {
973 GST_WARNING_OBJECT (dec, "Could not enable BITS mode visualisation");
976 dec->have_header = TRUE;
978 if (dec->pendingevents) {
979 for (walk = dec->pendingevents; walk; walk = g_list_next (walk))
980 gst_pad_push_event (dec->srcpad, GST_EVENT_CAST (walk->data));
981 g_list_free (dec->pendingevents);
982 dec->pendingevents = NULL;
986 gst_pad_push_event (dec->srcpad, gst_event_new_tag (dec->tags));
995 GST_ERROR_OBJECT (dec, "failed to negotiate");
1000 static GstFlowReturn
1001 theora_handle_header_packet (GstTheoraDec * dec, ogg_packet * packet)
1006 GST_DEBUG_OBJECT (dec, "parsing header packet");
1008 ret = th_decode_headerin (&dec->info, &dec->comment, &dec->setup, packet);
1010 goto header_read_error;
1012 switch (packet->packet[0]) {
1014 res = theora_handle_comment_packet (dec, packet);
1017 res = theora_handle_type_packet (dec, packet);
1021 g_warning ("unknown theora header packet found");
1023 /* nothing special, this is the identification header */
1032 GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
1033 (NULL), ("couldn't read header packet"));
1034 return GST_FLOW_ERROR;
1038 /* returns TRUE if buffer is within segment, else FALSE.
1039 * if Buffer is on segment border, it's timestamp and duration will be clipped */
1041 clip_buffer (GstTheoraDec * dec, GstBuffer * buf)
1043 gboolean res = TRUE;
1044 GstClockTime in_ts, in_dur, stop;
1045 guint64 cstart, cstop;
1047 in_ts = GST_BUFFER_TIMESTAMP (buf);
1048 in_dur = GST_BUFFER_DURATION (buf);
1050 GST_LOG_OBJECT (dec,
1051 "timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT,
1052 GST_TIME_ARGS (in_ts), GST_TIME_ARGS (in_dur));
1054 /* can't clip without TIME segment */
1055 if (dec->segment.format != GST_FORMAT_TIME)
1058 /* we need a start time */
1059 if (!GST_CLOCK_TIME_IS_VALID (in_ts))
1062 /* generate valid stop, if duration unknown, we have unknown stop */
1064 GST_CLOCK_TIME_IS_VALID (in_dur) ? (in_ts + in_dur) : GST_CLOCK_TIME_NONE;
1067 if (!(res = gst_segment_clip (&dec->segment, GST_FORMAT_TIME,
1068 in_ts, stop, &cstart, &cstop)))
1071 /* update timestamp and possibly duration if the clipped stop time is
1073 GST_BUFFER_TIMESTAMP (buf) = cstart;
1074 if (GST_CLOCK_TIME_IS_VALID (cstop))
1075 GST_BUFFER_DURATION (buf) = cstop - cstart;
1078 GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : ""));
1082 static GstFlowReturn
1083 theora_dec_push_forward (GstTheoraDec * dec, GstBuffer * buf)
1085 GstFlowReturn result = GST_FLOW_OK;
1087 if (clip_buffer (dec, buf)) {
1089 GST_LOG_OBJECT (dec, "setting DISCONT");
1090 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
1091 dec->discont = FALSE;
1093 result = gst_pad_push (dec->srcpad, buf);
1095 gst_buffer_unref (buf);
1101 static GstFlowReturn
1102 theora_dec_push_reverse (GstTheoraDec * dec, GstBuffer * buf)
1104 GstFlowReturn result = GST_FLOW_OK;
1106 dec->queued = g_list_prepend (dec->queued, buf);
1111 /* Allocate buffer and copy image data into Y444 format */
1112 static GstFlowReturn
1113 theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf, GstBuffer ** out)
1115 gint width, height, stride;
1116 gint pic_width, pic_height;
1117 GstFlowReturn result;
1120 GstVideoFrame frame;
1121 GstVideoCropMeta *crop;
1122 gint offset_x, offset_y;
1125 (gst_pad_check_reconfigure (dec->srcpad))
1127 ((result = theora_negotiate (dec)) != GST_FLOW_OK)
1128 goto negotiate_failed;
1130 result = gst_buffer_pool_acquire_buffer (dec->pool, out, NULL);
1131 if (G_UNLIKELY (result != GST_FLOW_OK))
1135 (!gst_video_frame_map (&frame, &dec->vinfo, *out, GST_MAP_WRITE))
1138 if (!dec->has_cropping) {
1139 /* we need to crop the hard way */
1140 offset_x = dec->info.pic_x;
1141 offset_y = dec->info.pic_y;
1142 pic_width = dec->info.pic_width;
1143 pic_height = dec->info.pic_height;
1144 /* Ensure correct offsets in chroma for formats that need it
1145 * by rounding the offset. libtheora will add proper pixels,
1146 * so no need to handle them ourselves. */
1147 if (offset_x & 1 && dec->info.pixel_fmt != TH_PF_444)
1149 if (offset_y & 1 && dec->info.pixel_fmt == TH_PF_420)
1152 /* copy the whole frame */
1155 pic_width = dec->info.frame_width;
1156 pic_height = dec->info.frame_height;
1158 if (dec->has_cropping && dec->need_cropping) {
1159 crop = gst_buffer_add_video_crop_meta (*out);
1160 /* we can do things slightly more efficient when we know that
1161 * downstream understands clipping */
1162 crop->x = dec->info.pic_x;
1163 crop->y = dec->info.pic_y;
1164 crop->width = dec->info.pic_width;
1165 crop->height = dec->info.pic_height;
1169 for (comp = 0; comp < 3; comp++) {
1171 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (frame.info.finfo, comp, pic_width);
1173 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (frame.info.finfo, comp, pic_height);
1174 stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, comp);
1175 dest = GST_VIDEO_FRAME_COMP_DATA (&frame, comp);
1177 src = buf[comp].data;
1178 src += ((height == pic_height) ? offset_y : offset_y / 2)
1180 src += (width == pic_width) ? offset_x : offset_x / 2;
1182 for (i = 0; i < height; i++) {
1183 memcpy (dest, src, width);
1186 src += buf[comp].stride;
1189 gst_video_frame_unmap (&frame);
1196 GST_DEBUG_OBJECT (dec, "could not negotiate, reason: %s",
1197 gst_flow_get_name (result));
1202 GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
1203 gst_flow_get_name (result));
1208 GST_DEBUG_OBJECT (dec, "could not map video frame");
1209 return GST_FLOW_ERROR;
1213 static GstFlowReturn
1214 theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
1215 GstClockTime outtime, GstClockTime outdur)
1217 /* normal data packet */
1218 th_ycbcr_buffer buf;
1221 GstFlowReturn result;
1224 if (G_UNLIKELY (!dec->have_header))
1225 goto not_initialized;
1227 /* get timestamp and durations */
1229 outtime = dec->last_timestamp;
1231 outdur = gst_util_uint64_scale_int (GST_SECOND, dec->info.fps_denominator,
1232 dec->info.fps_numerator);
1234 /* calculate expected next timestamp */
1235 if (outtime != -1 && outdur != -1)
1236 dec->last_timestamp = outtime + outdur;
1238 /* the second most significant bit of the first data byte is cleared
1239 * for keyframes. We can only check it if it's not a zero-length packet. */
1240 keyframe = packet->bytes && ((packet->packet[0] & 0x40) == 0);
1241 if (G_UNLIKELY (keyframe)) {
1242 GST_DEBUG_OBJECT (dec, "we have a keyframe");
1243 dec->need_keyframe = FALSE;
1244 } else if (G_UNLIKELY (dec->need_keyframe)) {
1248 GST_DEBUG_OBJECT (dec, "parsing data packet");
1250 /* this does the decoding */
1251 if (G_UNLIKELY (th_decode_packetin (dec->decoder, packet, &gp) < 0))
1254 if (outtime != -1) {
1256 GstClockTime running_time;
1257 GstClockTime earliest_time;
1260 /* qos needs to be done on running time */
1261 running_time = gst_segment_to_running_time (&dec->segment, GST_FORMAT_TIME,
1264 GST_OBJECT_LOCK (dec);
1265 proportion = dec->proportion;
1266 earliest_time = dec->earliest_time;
1267 /* check for QoS, don't perform the last steps of getting and
1268 * pushing the buffers that are known to be late. */
1269 need_skip = earliest_time != -1 && running_time <= earliest_time;
1270 GST_OBJECT_UNLOCK (dec);
1273 GstMessage *qos_msg;
1274 guint64 stream_time;
1277 GST_DEBUG_OBJECT (dec, "skipping decoding: qostime %"
1278 GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
1279 GST_TIME_ARGS (running_time), GST_TIME_ARGS (earliest_time));
1284 gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, outtime);
1285 jitter = GST_CLOCK_DIFF (running_time, earliest_time);
1288 gst_message_new_qos (GST_OBJECT_CAST (dec), FALSE, running_time,
1289 stream_time, outtime, outdur);
1290 gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
1291 gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
1292 dec->processed, dec->dropped);
1293 gst_element_post_message (GST_ELEMENT_CAST (dec), qos_msg);
1299 /* this does postprocessing and set up the decoded frame
1300 * pointers in our yuv variable */
1301 if (G_UNLIKELY (th_decode_ycbcr_out (dec->decoder, buf) < 0))
1304 if (G_UNLIKELY ((buf[0].width != dec->info.frame_width)
1305 || (buf[0].height != dec->info.frame_height)))
1306 goto wrong_dimensions;
1308 result = theora_handle_image (dec, buf, &out);
1309 if (result != GST_FLOW_OK)
1312 GST_BUFFER_OFFSET (out) = dec->frame_nr;
1313 if (dec->frame_nr != -1)
1315 GST_BUFFER_OFFSET_END (out) = dec->frame_nr;
1317 GST_BUFFER_TIMESTAMP (out) = outtime;
1318 GST_BUFFER_DURATION (out) = outdur;
1322 if (dec->segment.rate >= 0.0)
1323 result = theora_dec_push_forward (dec, out);
1325 result = theora_dec_push_reverse (dec, out);
1332 GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
1333 (NULL), ("no header sent yet"));
1334 return GST_FLOW_ERROR;
1338 GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe");
1339 dec->discont = TRUE;
1344 if (dec->frame_nr != -1)
1346 dec->discont = TRUE;
1347 GST_WARNING_OBJECT (dec, "dropping frame because of QoS");
1352 GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
1353 (NULL), ("theora decoder did not decode data packet"));
1354 return GST_FLOW_ERROR;
1358 GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
1359 (NULL), ("couldn't read out YUV image"));
1360 return GST_FLOW_ERROR;
1364 GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, FORMAT,
1365 (NULL), ("dimensions of image do not match header"));
1366 return GST_FLOW_ERROR;
1370 static GstFlowReturn
1371 theora_dec_decode_buffer (GstTheoraDec * dec, GstBuffer * buf)
1374 GstFlowReturn result = GST_FLOW_OK;
1375 GstClockTime timestamp, duration;
1378 /* make ogg_packet out of the buffer */
1379 gst_buffer_map (buf, &map, GST_MAP_READ);
1380 packet.packet = map.data;
1381 packet.bytes = map.size;
1382 packet.granulepos = -1;
1383 packet.packetno = 0; /* we don't really care */
1384 packet.b_o_s = dec->have_header ? 0 : 1;
1385 /* EOS does not matter for the decoder */
1388 GST_LOG_OBJECT (dec, "decode buffer of size %ld", packet.bytes);
1390 /* save last seem timestamp for interpolating the next timestamps using the
1391 * framerate when we need to */
1392 timestamp = GST_BUFFER_TIMESTAMP (buf);
1393 duration = GST_BUFFER_DURATION (buf);
1395 GST_DEBUG_OBJECT (dec, "header=%02x, outtime=%" GST_TIME_FORMAT,
1396 packet.bytes ? packet.packet[0] : -1, GST_TIME_ARGS (timestamp));
1398 /* switch depending on packet type. A zero byte packet is always a data
1399 * packet; we don't dereference it in that case. */
1400 if (packet.bytes && packet.packet[0] & 0x80) {
1401 if (dec->have_header) {
1402 GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
1405 result = theora_handle_header_packet (dec, &packet);
1407 result = theora_handle_data_packet (dec, &packet, timestamp, duration);
1410 gst_buffer_unmap (buf, &map);
1415 /* For reverse playback we use a technique that can be used for
1416 * any keyframe based video codec.
1419 * Buffer decoding order: 7 8 9 4 5 6 1 2 3 EOS
1420 * Keyframe flag: K K
1421 * Discont flag: D D D
1423 * - Each Discont marks a discont in the decoding order.
1424 * - The keyframes mark where we can start decoding.
1426 * First we prepend incomming buffers to the gather queue, whenever we receive
1427 * a discont, we flush out the gather queue.
1429 * The above data will be accumulated in the gather queue like this:
1431 * gather queue: 9 8 7
1434 * Whe buffer 4 is received (with a DISCONT), we flush the gather queue like
1438 * take head of queue and prepend to decode queue.
1439 * if we copied a keyframe, decode the decode queue.
1441 * After we flushed the gather queue, we add 4 to the (now empty) gather queue.
1442 * We get the following situation:
1445 * decode queue: 7 8 9
1447 * After we received 5 (Keyframe) and 6:
1449 * gather queue: 6 5 4
1450 * decode queue: 7 8 9
1452 * When we receive 1 (DISCONT) which triggers a flush of the gather queue:
1454 * Copy head of the gather queue (6) to decode queue:
1457 * decode queue: 6 7 8 9
1459 * Copy head of the gather queue (5) to decode queue. This is a keyframe so we
1460 * can start decoding.
1463 * decode queue: 5 6 7 8 9
1465 * Decode frames in decode queue, store raw decoded data in output queue, we
1466 * can take the head of the decode queue and prepend the decoded result in the
1471 * output queue: 9 8 7 6 5
1473 * Now output all the frames in the output queue, picking a frame from the
1474 * head of the queue.
1476 * Copy head of the gather queue (4) to decode queue, we flushed the gather
1477 * queue and can now store input buffer in the gather queue:
1482 * When we receive EOS, the queue looks like:
1484 * gather queue: 3 2 1
1487 * Fill decode queue, first keyframe we copy is 2:
1490 * decode queue: 2 3 4
1496 * output queue: 4 3 2
1498 * Leftover buffer 1 cannot be decoded and must be discarded.
1500 static GstFlowReturn
1501 theora_dec_flush_decode (GstTheoraDec * dec)
1503 GstFlowReturn res = GST_FLOW_OK;
1505 while (dec->decode) {
1506 GstBuffer *buf = GST_BUFFER_CAST (dec->decode->data);
1508 GST_DEBUG_OBJECT (dec, "decoding buffer %p, ts %" GST_TIME_FORMAT,
1509 buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1511 /* decode buffer, prepend to output queue */
1512 res = theora_dec_decode_buffer (dec, buf);
1514 /* don't need it anymore now */
1515 gst_buffer_unref (buf);
1517 dec->decode = g_list_delete_link (dec->decode, dec->decode);
1519 while (dec->queued) {
1520 GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data);
1522 /* iterate output queue an push downstream */
1523 res = gst_pad_push (dec->srcpad, buf);
1525 dec->queued = g_list_delete_link (dec->queued, dec->queued);
1531 static GstFlowReturn
1532 theora_dec_chain_reverse (GstTheoraDec * dec, gboolean discont, GstBuffer * buf)
1534 GstFlowReturn res = GST_FLOW_OK;
1536 /* if we have a discont, move buffers to the decode list */
1537 if (G_UNLIKELY (discont)) {
1538 GST_DEBUG_OBJECT (dec, "received discont,gathering buffers");
1539 while (dec->gather) {
1543 gbuf = GST_BUFFER_CAST (dec->gather->data);
1544 /* remove from the gather list */
1545 dec->gather = g_list_delete_link (dec->gather, dec->gather);
1546 /* copy to decode queue */
1547 dec->decode = g_list_prepend (dec->decode, gbuf);
1549 /* if we copied a keyframe, flush and decode the decode queue */
1550 if (gst_buffer_extract (gbuf, 0, data, 1) == 1) {
1551 if ((data[0] & 0x40) == 0) {
1552 GST_DEBUG_OBJECT (dec, "copied keyframe");
1553 res = theora_dec_flush_decode (dec);
1559 /* add buffer to gather queue */
1560 GST_DEBUG_OBJECT (dec, "gathering buffer %p, size %" G_GSIZE_FORMAT, buf,
1561 gst_buffer_get_size (buf));
1562 dec->gather = g_list_prepend (dec->gather, buf);
1567 static GstFlowReturn
1568 theora_dec_chain_forward (GstTheoraDec * dec, gboolean discont,
1571 GstFlowReturn result;
1573 result = theora_dec_decode_buffer (dec, buffer);
1575 gst_buffer_unref (buffer);
1580 static GstFlowReturn
1581 theora_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1587 dec = GST_THEORA_DEC (parent);
1589 /* peel of DISCONT flag */
1590 discont = GST_BUFFER_IS_DISCONT (buf);
1592 /* resync on DISCONT */
1593 if (G_UNLIKELY (discont)) {
1594 GST_DEBUG_OBJECT (dec, "received DISCONT buffer");
1595 dec->need_keyframe = TRUE;
1596 dec->last_timestamp = -1;
1597 dec->discont = TRUE;
1600 if (dec->segment.rate > 0.0)
1601 res = theora_dec_chain_forward (dec, discont, buf);
1603 res = theora_dec_chain_reverse (dec, discont, buf);
1608 static GstStateChangeReturn
1609 theora_dec_change_state (GstElement * element, GstStateChange transition)
1611 GstTheoraDec *dec = GST_THEORA_DEC (element);
1612 GstStateChangeReturn ret;
1614 switch (transition) {
1615 case GST_STATE_CHANGE_NULL_TO_READY:
1617 case GST_STATE_CHANGE_READY_TO_PAUSED:
1618 th_info_clear (&dec->info);
1619 th_comment_clear (&dec->comment);
1620 GST_DEBUG_OBJECT (dec, "Setting have_header to FALSE in READY->PAUSED");
1621 dec->have_header = FALSE;
1622 dec->have_par = FALSE;
1623 gst_theora_dec_reset (dec);
1625 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1631 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1633 switch (transition) {
1634 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1636 case GST_STATE_CHANGE_PAUSED_TO_READY:
1637 th_info_clear (&dec->info);
1638 th_comment_clear (&dec->comment);
1639 th_setup_free (dec->setup);
1641 th_decode_free (dec->decoder);
1642 dec->decoder = NULL;
1643 gst_theora_dec_reset (dec);
1645 gst_buffer_pool_set_active (dec->pool, FALSE);
1646 gst_object_unref (dec->pool);
1650 case GST_STATE_CHANGE_READY_TO_NULL:
1660 theora_dec_set_property (GObject * object, guint prop_id,
1661 const GValue * value, GParamSpec * pspec)
1663 GstTheoraDec *dec = GST_THEORA_DEC (object);
1666 case PROP_TELEMETRY_MV:
1667 dec->telemetry_mv = g_value_get_int (value);
1669 case PROP_TELEMETRY_MBMODE:
1670 dec->telemetry_mbmode = g_value_get_int (value);
1672 case PROP_TELEMETRY_QI:
1673 dec->telemetry_qi = g_value_get_int (value);
1675 case PROP_TELEMETRY_BITS:
1676 dec->telemetry_bits = g_value_get_int (value);
1679 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1685 theora_dec_get_property (GObject * object, guint prop_id,
1686 GValue * value, GParamSpec * pspec)
1688 GstTheoraDec *dec = GST_THEORA_DEC (object);
1691 case PROP_TELEMETRY_MV:
1692 g_value_set_int (value, dec->telemetry_mv);
1694 case PROP_TELEMETRY_MBMODE:
1695 g_value_set_int (value, dec->telemetry_mbmode);
1697 case PROP_TELEMETRY_QI:
1698 g_value_set_int (value, dec->telemetry_qi);
1700 case PROP_TELEMETRY_BITS:
1701 g_value_set_int (value, dec->telemetry_bits);
1704 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);