gsttheoradec.c 28.2 KB
Newer Older
Benjamin Otte's avatar
Benjamin Otte committed
1 2
/* GStreamer
 * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
3 4 5
 * Copyright (c) 2012 Collabora Ltd.
 *	Author : Edward Hervey <edward@collabora.com>
 *      Author : Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Benjamin Otte's avatar
Benjamin Otte committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

Wim Taymans's avatar
Wim Taymans committed
23 24 25 26 27 28 29 30
/**
 * SECTION:element-theoradec
 * @see_also: theoraenc, oggdemux
 *
 * This element decodes theora streams into raw video
 * <ulink url="http://www.theora.org/">Theora</ulink> is a royalty-free
 * video codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
 * Foundation</ulink>, based on the VP3 codec.
31 32
 *
 * <refsect2>
Wim Taymans's avatar
Wim Taymans committed
33
 * <title>Example pipeline</title>
34
 * |[
Wim Taymans's avatar
Wim Taymans committed
35
 * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! xvimagesink
36
 * ]| This example pipeline will decode an ogg stream and decodes the theora video. Refer to
Wim Taymans's avatar
Wim Taymans committed
37 38 39 40 41 42
 * the theoraenc example to create the ogg file.
 * </refsect2>
 *
 * Last reviewed on 2006-03-01 (0.10.4)
 */

Benjamin Otte's avatar
Benjamin Otte committed
43 44 45 46
#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

Wim Taymans's avatar
Wim Taymans committed
47
#include "gsttheoradec.h"
Benjamin Otte's avatar
Benjamin Otte committed
48
#include <gst/tag/tag.h>
49
#include <gst/video/video.h>
50 51
#include <gst/video/gstvideometa.h>
#include <gst/video/gstvideopool.h>
Benjamin Otte's avatar
Benjamin Otte committed
52

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
53
#define GST_CAT_DEFAULT theoradec_debug
54
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
55
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
Benjamin Otte's avatar
Benjamin Otte committed
56

57 58 59 60 61
#define THEORA_DEF_TELEMETRY_MV 0
#define THEORA_DEF_TELEMETRY_MBMODE 0
#define THEORA_DEF_TELEMETRY_QI 0
#define THEORA_DEF_TELEMETRY_BITS 0

62 63
enum
{
64
  PROP_0,
65 66 67 68
  PROP_TELEMETRY_MV,
  PROP_TELEMETRY_MBMODE,
  PROP_TELEMETRY_QI,
  PROP_TELEMETRY_BITS
69 70
};

Benjamin Otte's avatar
Benjamin Otte committed
71
static GstStaticPadTemplate theora_dec_src_factory =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
72 73 74
GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
75 76
    GST_STATIC_CAPS ("video/x-raw, "
        "format = (string) { I420, Y42B, Y444 }, "
77
        "framerate = (fraction) [0/1, MAX], "
78
        "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
79
    );
Benjamin Otte's avatar
Benjamin Otte committed
80 81

static GstStaticPadTemplate theora_dec_sink_factory =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
82 83 84 85 86
GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/x-theora")
    );
Benjamin Otte's avatar
Benjamin Otte committed
87

88 89
#define gst_theora_dec_parent_class parent_class
G_DEFINE_TYPE (GstTheoraDec, gst_theora_dec, GST_TYPE_VIDEO_DECODER);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
90

91 92 93 94 95
static void theora_dec_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);
static void theora_dec_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);

96 97 98 99 100 101 102 103 104
static gboolean theora_dec_start (GstVideoDecoder * decoder);
static gboolean theora_dec_stop (GstVideoDecoder * decoder);
static gboolean theora_dec_set_format (GstVideoDecoder * decoder,
    GstVideoCodecState * state);
static gboolean theora_dec_reset (GstVideoDecoder * decoder, gboolean hard);
static GstFlowReturn theora_dec_parse (GstVideoDecoder * decoder,
    GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos);
static GstFlowReturn theora_dec_handle_frame (GstVideoDecoder * decoder,
    GstVideoCodecFrame * frame);
105 106
static gboolean theora_dec_decide_allocation (GstVideoDecoder * decoder,
    GstQuery * query);
107 108 109

static GstFlowReturn theora_dec_decode_buffer (GstTheoraDec * dec,
    GstBuffer * buf, GstVideoCodecFrame * frame);
Benjamin Otte's avatar
Benjamin Otte committed
110

111 112 113 114 115 116 117
static gboolean
gst_theora_dec_ctl_is_supported (int req)
{
  /* should return TH_EFAULT or TH_EINVAL if supported, and TH_EIMPL if not */
  return (th_decode_ctl (NULL, req, NULL, 0) != TH_EIMPL);
}

Benjamin Otte's avatar
Benjamin Otte committed
118
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
119
gst_theora_dec_class_init (GstTheoraDecClass * klass)
Benjamin Otte's avatar
Benjamin Otte committed
120
{
121
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
122
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
123
  GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
Benjamin Otte's avatar
Benjamin Otte committed
124

125 126 127
  gobject_class->set_property = theora_dec_set_property;
  gobject_class->get_property = theora_dec_get_property;

128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
  if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_MV)) {
    g_object_class_install_property (gobject_class, PROP_TELEMETRY_MV,
        g_param_spec_int ("visualize-motion-vectors",
            "Visualize motion vectors",
            "Show motion vector selection overlaid on image. "
            "Value gives a mask for motion vector (MV) modes to show",
            0, 0xffff, THEORA_DEF_TELEMETRY_MV,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }

  if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_MBMODE)) {
    g_object_class_install_property (gobject_class, PROP_TELEMETRY_MBMODE,
        g_param_spec_int ("visualize-macroblock-modes",
            "Visualize macroblock modes",
            "Show macroblock mode selection overlaid on image. "
            "Value gives a mask for macroblock (MB) modes to show",
            0, 0xffff, THEORA_DEF_TELEMETRY_MBMODE,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }

  if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_QI)) {
    g_object_class_install_property (gobject_class, PROP_TELEMETRY_QI,
        g_param_spec_int ("visualize-quantization-modes",
            "Visualize adaptive quantization modes",
            "Show adaptive quantization mode selection overlaid on image. "
            "Value gives a mask for quantization (QI) modes to show",
            0, 0xffff, THEORA_DEF_TELEMETRY_QI,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }

  if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_BITS)) {
    /* FIXME: make this a boolean instead? The value scales the bars so
     * they're less wide. Default is to use full width, and anything else
     * doesn't seem particularly useful, since the smaller bars just disappear
     * then (they almost disappear for a value of 2 already). */
    g_object_class_install_property (gobject_class, PROP_TELEMETRY_BITS,
        g_param_spec_int ("visualize-bit-usage",
            "Visualize bitstream usage breakdown",
            "Sets the bitstream breakdown visualization mode. "
            "Values influence the width of the bit usage bars to show",
            0, 0xff, THEORA_DEF_TELEMETRY_BITS,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }
171

172 173 174 175 176 177 178 179 180
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&theora_dec_src_factory));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&theora_dec_sink_factory));
  gst_element_class_set_details_simple (element_class,
      "Theora video decoder", "Codec/Decoder/Video",
      "decode raw theora streams to raw YUV video",
      "Benjamin Otte <otte@gnome.org>, Wim Taymans <wim@fluendo.com>");

181 182 183 184 185 186 187
  video_decoder_class->start = GST_DEBUG_FUNCPTR (theora_dec_start);
  video_decoder_class->stop = GST_DEBUG_FUNCPTR (theora_dec_stop);
  video_decoder_class->reset = GST_DEBUG_FUNCPTR (theora_dec_reset);
  video_decoder_class->set_format = GST_DEBUG_FUNCPTR (theora_dec_set_format);
  video_decoder_class->parse = GST_DEBUG_FUNCPTR (theora_dec_parse);
  video_decoder_class->handle_frame =
      GST_DEBUG_FUNCPTR (theora_dec_handle_frame);
188 189
  video_decoder_class->decide_allocation =
      GST_DEBUG_FUNCPTR (theora_dec_decide_allocation);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
190 191

  GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
Benjamin Otte's avatar
Benjamin Otte committed
192 193 194
}

static void
195
gst_theora_dec_init (GstTheoraDec * dec)
Benjamin Otte's avatar
Benjamin Otte committed
196
{
197 198 199 200
  dec->telemetry_mv = THEORA_DEF_TELEMETRY_MV;
  dec->telemetry_mbmode = THEORA_DEF_TELEMETRY_MBMODE;
  dec->telemetry_qi = THEORA_DEF_TELEMETRY_QI;
  dec->telemetry_bits = THEORA_DEF_TELEMETRY_BITS;
201 202 203

  /* input is packetized,
   * but is not marked that way so data gets parsed and keyframes marked */
204
  gst_video_decoder_set_packetized (GST_VIDEO_DECODER(dec), FALSE);
Benjamin Otte's avatar
Benjamin Otte committed
205
}
206

207 208 209 210
static void
gst_theora_dec_reset (GstTheoraDec * dec)
{
  dec->need_keyframe = TRUE;
211
  dec->can_crop = FALSE;
212 213
}

214
static gboolean
215
theora_dec_start (GstVideoDecoder * decoder)
216
{
217
  GstTheoraDec *dec = GST_THEORA_DEC (decoder);
Wim Taymans's avatar
Wim Taymans committed
218

219 220 221 222 223 224
  GST_DEBUG_OBJECT (dec, "start");
  th_info_clear (&dec->info);
  th_comment_clear (&dec->comment);
  GST_DEBUG_OBJECT (dec, "Setting have_header to FALSE");
  dec->have_header = FALSE;
  gst_theora_dec_reset (dec);
225

226
  return TRUE;
227 228
}

Benjamin Otte's avatar
Benjamin Otte committed
229
static gboolean
230
theora_dec_stop (GstVideoDecoder * decoder)
Benjamin Otte's avatar
Benjamin Otte committed
231
{
232 233 234 235 236 237 238 239 240 241 242 243 244
  GstTheoraDec *dec = GST_THEORA_DEC (decoder);

  GST_DEBUG_OBJECT (dec, "stop");
  th_info_clear (&dec->info);
  th_comment_clear (&dec->comment);
  th_setup_free (dec->setup);
  dec->setup = NULL;
  th_decode_free (dec->decoder);
  dec->decoder = NULL;
  gst_theora_dec_reset (dec);
  if (dec->tags) {
    gst_tag_list_free (dec->tags);
    dec->tags = NULL;
Benjamin Otte's avatar
Benjamin Otte committed
245
  }
246

247
  return TRUE;
Benjamin Otte's avatar
Benjamin Otte committed
248
}
249

250
/* FIXME : Do we want to handle hard resets differently ? */
251
static gboolean
252
theora_dec_reset (GstVideoDecoder * bdec, gboolean hard)
253
{
254 255
  gst_theora_dec_reset (GST_THEORA_DEC (bdec));
  return TRUE;
Wim Taymans's avatar
Wim Taymans committed
256 257
}

258 259 260
static GstFlowReturn
theora_dec_parse (GstVideoDecoder * decoder,
    GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
Benjamin Otte's avatar
Benjamin Otte committed
261
{
262 263
  gint av;
  const guint8 *data;
Benjamin Otte's avatar
Benjamin Otte committed
264

265
  av = gst_adapter_available (adapter);
Benjamin Otte's avatar
Benjamin Otte committed
266

267
  data = gst_adapter_map (adapter, 1);
268 269 270
  /* check for keyframe; must not be header packet */
  if (!(data[0] & 0x80) && (data[0] & 0x40) == 0)
    GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
271
  gst_adapter_unmap (adapter);
272

273 274 275
  /* and pass along all */
  gst_video_decoder_add_to_frame (decoder, av);
  return gst_video_decoder_have_frame (decoder);
276 277
}

Benjamin Otte's avatar
Benjamin Otte committed
278

279
static gboolean
280
theora_dec_set_format (GstVideoDecoder * bdec, GstVideoCodecState * state)
281 282 283
{
  GstTheoraDec *dec;

284
  dec = GST_THEORA_DEC (bdec);
285

286 287 288 289
  /* Keep a copy of the input state */
  if (dec->input_state)
    gst_video_codec_state_unref (dec->input_state);
  dec->input_state = gst_video_codec_state_ref (state);
290

291 292 293
  /* FIXME : Interesting, we always accept any kind of caps ? */
  if (state->codec_data) {
    GstBuffer *buffer;
294
    GstMapInfo minfo;
295 296 297
    guint8 *data;
    guint size;
    guint offset;
298

299
    buffer = state->codec_data;
300
    gst_buffer_map (buffer, &minfo, GST_MAP_READ);
301

302
    offset = 0;
303 304
    size = minfo.size;
    data = (guint8 *) minfo.data;
305

306 307 308
    while (size > 2) {
      guint psize;
      GstBuffer *buf;
309

310 311 312 313 314
      psize = (data[0] << 8) | data[1];
      /* skip header */
      data += 2;
      size -= 2;
      offset += 2;
315

316 317
      /* make sure we don't read too much */
      psize = MIN (psize, size);
318

319
      buf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, psize);
320

321 322 323
      /* first buffer is a discont buffer */
      if (offset == 2)
        GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
324

325 326 327
      /* now feed it to the decoder we can ignore the error */
      theora_dec_decode_buffer (dec, buf, NULL);
      gst_buffer_unref (buf);
328

329 330 331 332
      /* skip the data */
      size -= psize;
      data += psize;
      offset += psize;
333
    }
334 335

    gst_buffer_unmap (buffer, &minfo);
336 337
  }

338
  GST_DEBUG_OBJECT (dec, "Done");
339 340 341 342

  return TRUE;
}

343
static GstFlowReturn
344
theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
Benjamin Otte's avatar
Benjamin Otte committed
345
{
346 347 348
  gchar *encoder = NULL;
  GstTagList *list;

349
  GST_DEBUG_OBJECT (dec, "parsing comment packet");
350

351
  list =
352 353
      gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
      (guint8 *) "\201theora", 7, &encoder);
354 355 356

  if (!list) {
    GST_ERROR_OBJECT (dec, "couldn't decode comments");
357
    list = gst_tag_list_new_empty ();
358 359 360 361 362 363 364 365 366 367
  }
  if (encoder) {
    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
        GST_TAG_ENCODER, encoder, NULL);
    g_free (encoder);
  }
  gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
      GST_TAG_ENCODER_VERSION, dec->info.version_major,
      GST_TAG_VIDEO_CODEC, "Theora", NULL);

368 369 370 371 372 373
  if (dec->info.target_bitrate > 0) {
    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
        GST_TAG_BITRATE, dec->info.target_bitrate,
        GST_TAG_NOMINAL_BITRATE, dec->info.target_bitrate, NULL);
  }

374 375
  if (dec->tags)
    gst_tag_list_free (dec->tags);
376
  dec->tags = list;
377 378 379 380 381

  return GST_FLOW_OK;
}

static GstFlowReturn
382
theora_handle_type_packet (GstTheoraDec * dec)
383 384
{
  gint par_num, par_den;
385
  GstFlowReturn ret = GST_FLOW_OK;
386 387 388
  GstVideoCodecState *state;
  GstVideoFormat fmt;
  GstVideoInfo *info = &dec->input_state->info;
389 390 391 392 393 394 395

  GST_DEBUG_OBJECT (dec, "fps %d/%d, PAR %d/%d",
      dec->info.fps_numerator, dec->info.fps_denominator,
      dec->info.aspect_numerator, dec->info.aspect_denominator);

  /* calculate par
   * the info.aspect_* values reflect PAR;
396
   * 0:x and x:0 are allowed and can be interpreted as 1:1.
397
   */
398 399 400 401 402 403
  par_num = GST_VIDEO_INFO_PAR_N (info);
  par_den = GST_VIDEO_INFO_PAR_D (info);

  /* If we have a default PAR, see if the decoder specified a different one */
  if (par_num == 1 && par_den == 1 &&
      (dec->info.aspect_numerator != 0 && dec->info.aspect_denominator != 0)) {
404 405 406
    par_num = dec->info.aspect_numerator;
    par_den = dec->info.aspect_denominator;
  }
407 408 409
  /* theora has:
   *
   *  width/height : dimension of the encoded frame 
410 411
   *  pic_width/pic_height : dimension of the visible part
   *  pic_x/pic_y : offset in encoded frame where visible part starts
412
   */
413 414
  GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.pic_width,
      dec->info.pic_height, par_num, par_den);
415
  GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d",
416 417
      dec->info.pic_width, dec->info.pic_height,
      dec->info.pic_x, dec->info.pic_y);
418

419 420 421 422 423 424 425 426 427 428 429 430
  switch (dec->info.pixel_fmt) {
    case TH_PF_420:
      fmt = GST_VIDEO_FORMAT_I420;
      break;
    case TH_PF_422:
      fmt = GST_VIDEO_FORMAT_Y42B;
      break;
    case TH_PF_444:
      fmt = GST_VIDEO_FORMAT_Y444;
      break;
    default:
      goto unsupported_format;
431
  }
432

433 434
  GST_VIDEO_INFO_WIDTH (info) = dec->info.pic_width;
  GST_VIDEO_INFO_HEIGHT (info) = dec->info.pic_height;
435

436 437 438 439 440 441 442 443 444
  /* Ensure correct offsets in chroma for formats that need it
   * by rounding the offset. libtheora will add proper pixels,
   * so no need to handle them ourselves. */
  if (dec->info.pic_x & 1 && dec->info.pixel_fmt != TH_PF_444) {
    GST_VIDEO_INFO_WIDTH (info)++;
  }
  if (dec->info.pic_y & 1 && dec->info.pixel_fmt == TH_PF_420) {
    GST_VIDEO_INFO_HEIGHT (info)++;
  }
445 446

  GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d",
447
      info->width, info->height, dec->info.pic_x, dec->info.pic_y);
448 449

  /* done */
450
  dec->decoder = th_decode_alloc (&dec->info, dec->setup);
451

452
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MV,
453
          &dec->telemetry_mv, sizeof (dec->telemetry_mv)) != TH_EIMPL) {
454
    GST_WARNING_OBJECT (dec, "Could not enable MV visualisation");
455
  }
456
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MBMODE,
457
          &dec->telemetry_mbmode, sizeof (dec->telemetry_mbmode)) != TH_EIMPL) {
458
    GST_WARNING_OBJECT (dec, "Could not enable MB mode visualisation");
459
  }
460
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_QI,
461
          &dec->telemetry_qi, sizeof (dec->telemetry_qi)) != TH_EIMPL) {
462
    GST_WARNING_OBJECT (dec, "Could not enable QI mode visualisation");
463
  }
464
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_BITS,
465
          &dec->telemetry_bits, sizeof (dec->telemetry_bits)) != TH_EIMPL) {
466
    GST_WARNING_OBJECT (dec, "Could not enable BITS mode visualisation");
467
  }
468

469 470 471 472
  /* Create the output state */
  dec->output_state = state =
      gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec), fmt,
      info->width, info->height, dec->input_state);
473

474 475 476 477 478
  /* FIXME : Do we still need to set fps/par now that we pass the reference input stream ? */
  state->info.fps_n = dec->info.fps_numerator;
  state->info.fps_d = dec->info.fps_denominator;
  state->info.par_n = par_num;
  state->info.par_d = par_den;
Wim Taymans's avatar
Wim Taymans committed
479

480 481
  /* these values are for all versions of the colorspace specified in the
   * theora info */
482
  state->info.chroma_site = GST_VIDEO_CHROMA_SITE_JPEG;
483 484 485 486 487 488 489 490 491 492 493 494 495 496
  state->info.colorimetry.range = GST_VIDEO_COLOR_RANGE_16_235;
  state->info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
  state->info.colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
  switch (dec->info.colorspace) {
    case TH_CS_ITU_REC_470M:
      state->info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M;
      break;
    case TH_CS_ITU_REC_470BG:
      state->info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
      break;
    default:
      state->info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
      break;
  }
497 498

  dec->have_header = TRUE;
499

500 501
  /* FIXME : Put this on the next outgoing frame */
  /* FIXME :  */
502
  if (dec->tags) {
503 504
    gst_pad_push_event (GST_VIDEO_DECODER (dec)->srcpad,
        gst_event_new_tag (dec->tags));
505 506 507 508
    dec->tags = NULL;
  }

  return ret;
509 510 511 512 513 514 515

  /* ERRORS */
unsupported_format:
  {
    GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixel_fmt);
    return GST_FLOW_ERROR;
  }
516 517 518 519 520 521
}

static GstFlowReturn
theora_handle_header_packet (GstTheoraDec * dec, ogg_packet * packet)
{
  GstFlowReturn res;
522
  int ret;
523

524
  GST_DEBUG_OBJECT (dec, "parsing header packet");
525

526 527
  ret = th_decode_headerin (&dec->info, &dec->comment, &dec->setup, packet);
  if (ret < 0)
528 529
    goto header_read_error;

Wim Taymans's avatar
Wim Taymans committed
530 531
  switch (packet->packet[0]) {
    case 0x81:
532 533
      res = theora_handle_comment_packet (dec, packet);
      break;
Wim Taymans's avatar
Wim Taymans committed
534
    case 0x82:
535
      res = theora_handle_type_packet (dec);
536 537 538
      break;
    default:
      /* ignore */
Wim Taymans's avatar
Wim Taymans committed
539 540 541
      g_warning ("unknown theora header packet found");
    case 0x80:
      /* nothing special, this is the identification header */
542 543 544 545 546 547 548 549 550 551 552 553 554 555
      res = GST_FLOW_OK;
      break;
  }
  return res;

  /* ERRORS */
header_read_error:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
        (NULL), ("couldn't read header packet"));
    return GST_FLOW_ERROR;
  }
}

Michael Smith's avatar
Michael Smith committed
556 557
/* Allocate buffer and copy image data into Y444 format */
static GstFlowReturn
558 559
theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf,
    GstVideoCodecFrame * frame)
Michael Smith's avatar
Michael Smith committed
560
{
561
  GstVideoDecoder *decoder = GST_VIDEO_DECODER (dec);
562
  gint width, height, stride;
Michael Smith's avatar
Michael Smith committed
563
  GstFlowReturn result;
564
  gint i, comp;
565
  guint8 *dest, *src;
566 567 568
  GstVideoFrame vframe;
  gint pic_width, pic_height;
  gint offset_x, offset_y;
Michael Smith's avatar
Michael Smith committed
569

570
  result = gst_video_decoder_alloc_output_frame (decoder, frame);
Michael Smith's avatar
Michael Smith committed
571

572
  if (G_UNLIKELY (result != GST_FLOW_OK)) {
573 574 575 576 577
    GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
        gst_flow_get_name (result));
    return result;
  }

578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
  if (!dec->can_crop) {
    /* we need to crop the hard way */
    offset_x = dec->info.pic_x;
    offset_y = dec->info.pic_y;
    pic_width = dec->info.pic_width;
    pic_height = dec->info.pic_height;
    /* Ensure correct offsets in chroma for formats that need it
     * by rounding the offset. libtheora will add proper pixels,
     * so no need to handle them ourselves. */
    if (offset_x & 1 && dec->info.pixel_fmt != TH_PF_444)
      offset_x--;
    if (offset_y & 1 && dec->info.pixel_fmt == TH_PF_420)
      offset_y--;
  } else {
    /* copy the whole frame */
    offset_x = 0;
    offset_y = 0;
    pic_width = dec->info.frame_width;
    pic_height = dec->info.frame_height;

    if (dec->info.pic_width != dec->info.frame_width ||
        dec->info.pic_height != dec->info.frame_height ||
        dec->info.pic_x != 0 || dec->info.pic_y != 0) {
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
      GstVideoMeta *vmeta;
      GstVideoCropMeta *cmeta;

      vmeta = gst_buffer_get_video_meta (frame->output_buffer);
      /* If the buffer pool didn't add the meta already
       * we add it ourselves here */
      if (!vmeta)
        vmeta = gst_buffer_add_video_meta (frame->output_buffer,
            GST_VIDEO_FRAME_FLAG_NONE,
            dec->output_state->info.finfo->format,
            dec->info.frame_width, dec->info.frame_height);

      /* Just to be sure that the buffer pool doesn't do something
       * completely weird and we would crash later
       */
      g_assert (vmeta->format == dec->output_state->info.finfo->format);
      g_assert (vmeta->width == dec->info.frame_width);
      g_assert (vmeta->height == dec->info.frame_height);

      cmeta = gst_buffer_add_video_crop_meta (frame->output_buffer);
621 622 623

      /* we can do things slightly more efficient when we know that
       * downstream understands clipping */
624 625 626 627
      cmeta->x = dec->info.pic_x;
      cmeta->y = dec->info.pic_y;
      cmeta->width = dec->info.pic_width;
      cmeta->height = dec->info.pic_height;
628 629 630 631 632 633
    }
  }

  /* if only libtheora would allow us to give it a destination frame */
  GST_CAT_TRACE_OBJECT (GST_CAT_PERFORMANCE, dec,
      "doing unavoidable video frame copy");
634

635 636 637
  if (G_UNLIKELY (!gst_video_frame_map (&vframe, &dec->output_state->info,
              frame->output_buffer, GST_MAP_WRITE)))
    goto invalid_frame;
638

639 640 641 642 643 644 645 646
  for (comp = 0; comp < 3; comp++) {
    width =
        GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (vframe.info.finfo, comp, pic_width);
    height =
        GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vframe.info.finfo, comp,
        pic_height);
    stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, comp);
    dest = GST_VIDEO_FRAME_COMP_DATA (&vframe, comp);
647

648 649 650 651
    src = buf[comp].data;
    src += ((height == pic_height) ? offset_y : offset_y / 2)
        * buf[comp].stride;
    src += (width == pic_width) ? offset_x : offset_x / 2;
652 653

    for (i = 0; i < height; i++) {
654
      memcpy (dest, src, width);
655

656
      dest += stride;
657
      src += buf[comp].stride;
658 659
    }
  }
660
  gst_video_frame_unmap (&vframe);
661

662
  return GST_FLOW_OK;
663 664 665 666 667
invalid_frame:
  {
    GST_DEBUG_OBJECT (dec, "could not map video frame");
    return GST_FLOW_ERROR;
  }
668 669 670 671
}

static GstFlowReturn
theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
672
    GstVideoCodecFrame * frame)
673 674
{
  /* normal data packet */
675
  th_ycbcr_buffer buf;
676 677
  gboolean keyframe;
  GstFlowReturn result;
678
  ogg_int64_t gp;
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695

  if (G_UNLIKELY (!dec->have_header))
    goto not_initialized;

  /* the second most significant bit of the first data byte is cleared 
   * for keyframes. We can only check it if it's not a zero-length packet. */
  keyframe = packet->bytes && ((packet->packet[0] & 0x40) == 0);
  if (G_UNLIKELY (keyframe)) {
    GST_DEBUG_OBJECT (dec, "we have a keyframe");
    dec->need_keyframe = FALSE;
  } else if (G_UNLIKELY (dec->need_keyframe)) {
    goto dropping;
  }

  GST_DEBUG_OBJECT (dec, "parsing data packet");

  /* this does the decoding */
696
  if (G_UNLIKELY (th_decode_packetin (dec->decoder, packet, &gp) < 0))
697 698
    goto decode_error;

699 700 701 702
  if (frame &&
      (gst_video_decoder_get_max_decode_time (GST_VIDEO_DECODER (dec),
              frame) < 0))
    goto dropping_qos;
703 704 705

  /* this does postprocessing and set up the decoded frame
   * pointers in our yuv variable */
706
  if (G_UNLIKELY (th_decode_ycbcr_out (dec->decoder, buf) < 0))
707 708
    goto no_yuv;

709 710
  if (G_UNLIKELY ((buf[0].width != dec->info.frame_width)
          || (buf[0].height != dec->info.frame_height)))
711 712
    goto wrong_dimensions;

713
  result = theora_handle_image (dec, buf, frame);
714 715 716 717 718 719 720

  return result;

  /* ERRORS */
not_initialized:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
Wim Taymans's avatar
Wim Taymans committed
721
        (NULL), ("no header sent yet"));
722 723 724 725 726
    return GST_FLOW_ERROR;
  }
dropping:
  {
    GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe");
727
    return GST_VIDEO_DECODER_FLOW_NEED_DATA;
728
  }
729 730 731
dropping_qos:
  {
    GST_WARNING_OBJECT (dec, "dropping frame because of QoS");
732
    return GST_VIDEO_DECODER_FLOW_NEED_DATA;
733 734
  }
decode_error:
735 736
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
737
        (NULL), ("theora decoder did not decode data packet"));
738 739
    return GST_FLOW_ERROR;
  }
740
no_yuv:
741 742 743 744 745 746 747
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
        (NULL), ("couldn't read out YUV image"));
    return GST_FLOW_ERROR;
  }
wrong_dimensions:
  {
748
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, FORMAT,
749 750 751 752 753 754
        (NULL), ("dimensions of image do not match header"));
    return GST_FLOW_ERROR;
  }
}

static GstFlowReturn
755 756
theora_dec_decode_buffer (GstTheoraDec * dec, GstBuffer * buf,
    GstVideoCodecFrame * frame)
757
{
Benjamin Otte's avatar
Benjamin Otte committed
758
  ogg_packet packet;
759
  GstFlowReturn result = GST_FLOW_OK;
760
  GstMapInfo minfo;
Benjamin Otte's avatar
Benjamin Otte committed
761 762

  /* make ogg_packet out of the buffer */
763 764 765
  gst_buffer_map (buf, &minfo, GST_MAP_READ);
  packet.packet = minfo.data;
  packet.bytes = minfo.size;
Wim Taymans's avatar
Wim Taymans committed
766
  packet.granulepos = -1;
Wim Taymans's avatar
Wim Taymans committed
767 768
  packet.packetno = 0;          /* we don't really care */
  packet.b_o_s = dec->have_header ? 0 : 1;
769
  /* EOS does not matter for the decoder */
770
  packet.e_o_s = 0;
771

772
  GST_LOG_OBJECT (dec, "decode buffer of size %ld", packet.bytes);
773

774
  GST_DEBUG_OBJECT (dec, "header=%02x", packet.bytes ? packet.packet[0] : -1);
775

776 777 778
  /* switch depending on packet type. A zero byte packet is always a data
   * packet; we don't dereference it in that case. */
  if (packet.bytes && packet.packet[0] & 0x80) {
Wim Taymans's avatar
Wim Taymans committed
779
    if (dec->have_header) {
780
      GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
781
      goto done;
782
    }
783
    result = theora_handle_header_packet (dec, &packet);
784 785 786 787 788
    /* header packets are not meant to be displayed */
    /* FIXME : This is a temporary hack. The proper fix would be to
     * not call _finish_frame() for these types of packets */
    GST_VIDEO_CODEC_FRAME_FLAG_SET (frame,
        GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
Benjamin Otte's avatar
Benjamin Otte committed
789
  } else {
790
    result = theora_handle_data_packet (dec, &packet, frame);
Benjamin Otte's avatar
Benjamin Otte committed
791
  }
792

793
done:
794 795
  gst_buffer_unmap (buf, &minfo);

796
  return result;
Benjamin Otte's avatar
Benjamin Otte committed
797 798
}

799
static GstFlowReturn
800
theora_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame)
801 802 803 804
{
  GstTheoraDec *dec;
  GstFlowReturn res;

805
  dec = GST_THEORA_DEC (bdec);
806

807 808 809
  res = theora_dec_decode_buffer (dec, frame->input_buffer, frame);
  if (res == GST_FLOW_OK)
    res = gst_video_decoder_finish_frame (bdec, frame);
810 811 812 813

  return res;
}

814
static gboolean
815
theora_dec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
816 817
{
  GstTheoraDec *dec = GST_THEORA_DEC (decoder);
818
  GstVideoCodecState *state;
819 820 821 822
  GstBufferPool *pool;
  guint size, min, max;
  GstStructure *config;

823 824 825
  if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder,
          query))
    return FALSE;
826

827
  state = gst_video_decoder_get_output_state (decoder);
828

829
  gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
830

831
  dec->can_crop = FALSE;
832 833 834 835
  config = gst_buffer_pool_get_config (pool);
  if (gst_query_has_allocation_meta (query, GST_VIDEO_META_API_TYPE)) {
    gst_buffer_pool_config_add_option (config,
        GST_BUFFER_POOL_OPTION_VIDEO_META);
836 837
    dec->can_crop =
        gst_query_has_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE);
838
  }
839

840 841
  if (dec->can_crop) {
    GstVideoInfo info = state->info;
842
    GstCaps *caps;
843 844 845 846 847

    /* Calculate uncropped size */
    gst_video_info_set_format (&info, info.finfo->format, dec->info.frame_width,
        dec->info.frame_height);
    size = MAX (size, info.size);
848 849 850
    caps = gst_video_info_to_caps (&info);
    gst_buffer_pool_config_set_params (config, caps, size, min, max);
    gst_caps_unref (caps);
851
  }
852

853
  gst_buffer_pool_set_config (pool, config);
854

855
  gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
856

857
  gst_object_unref (pool);
858 859
  gst_video_codec_state_unref (state);

860
  return TRUE;
861 862
}

863 864 865 866 867 868 869
static void
theora_dec_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstTheoraDec *dec = GST_THEORA_DEC (object);

  switch (prop_id) {
870 871 872 873 874 875 876 877 878 879 880 881
    case PROP_TELEMETRY_MV:
      dec->telemetry_mv = g_value_get_int (value);
      break;
    case PROP_TELEMETRY_MBMODE:
      dec->telemetry_mbmode = g_value_get_int (value);
      break;
    case PROP_TELEMETRY_QI:
      dec->telemetry_qi = g_value_get_int (value);
      break;
    case PROP_TELEMETRY_BITS:
      dec->telemetry_bits = g_value_get_int (value);
      break;
882 883 884 885 886 887 888 889 890 891 892 893 894
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
theora_dec_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstTheoraDec *dec = GST_THEORA_DEC (object);

  switch (prop_id) {
895 896 897 898 899 900 901 902 903 904 905 906
    case PROP_TELEMETRY_MV:
      g_value_set_int (value, dec->telemetry_mv);
      break;
    case PROP_TELEMETRY_MBMODE:
      g_value_set_int (value, dec->telemetry_mbmode);
      break;
    case PROP_TELEMETRY_QI:
      g_value_set_int (value, dec->telemetry_qi);
      break;
    case PROP_TELEMETRY_BITS:
      g_value_set_int (value, dec->telemetry_bits);
      break;
907 908 909 910 911
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
912 913 914 915 916 917 918

gboolean
gst_theora_dec_register (GstPlugin * plugin)
{
  return gst_element_register (plugin, "theoradec",
      GST_RANK_PRIMARY, GST_TYPE_THEORA_DEC);
}