~ubuntu-branches/ubuntu/quantal/gst-plugins-bad0.10/quantal-proposed

« back to all changes in this revision

Viewing changes to ext/theora/theoradec.c

  • Committer: Bazaar Package Importer
  • Author(s): Ken VanDine
  • Date: 2011-07-19 14:32:43 UTC
  • mfrom: (18.4.21 sid)
  • Revision ID: james.westby@ubuntu.com-20110719143243-p7pnkh45akfp0ihk
Tags: 0.10.22-2ubuntu1
* Rebased on debian unstable, remaining changes:
  - debian/gstreamer-plugins-bad.install
    * don't include dtmf, liveadder, rtpmux, autoconvert and shm, we include 
      them in -good

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* GStreamer
2
 
 * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
3
 
 *               2006 Michael Smith <msmith@fluendo.com>
4
 
 *
5
 
 * This library is free software; you can redistribute it and/or
6
 
 * modify it under the terms of the GNU Library General Public
7
 
 * License as published by the Free Software Foundation; either
8
 
 * version 2 of the License, or (at your option) any later version.
9
 
 *
10
 
 * This library is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 
 * Library General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU Library General Public
16
 
 * License along with this library; if not, write to the
17
 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
 
 * Boston, MA 02111-1307, USA.
19
 
 */
20
 
 
21
 
/**
22
 
 * SECTION:element-theoradecexp
23
 
 * @see_also: theoradec, theoraenc, oggdemux
24
 
 *
25
 
 * This element decodes theora streams into raw video using the theora-exp
26
 
 * decoder
27
 
 * <ulink url="http://www.theora.org/">Theora</ulink> is a royalty-free
28
 
 * video codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
29
 
 * Foundation</ulink>, based on the VP3 codec.
30
 
 * 
31
 
 * <refsect2>
32
 
 * <title>Example pipeline</title>
33
 
 * |[
34
 
 * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoraexpdec ! xvimagesink
35
 
 * ]| This example pipeline will demux an ogg stream and decode the theora video,
36
 
 * displaying it on screen.
37
 
 * </refsect2>
38
 
 */
39
 
 
40
 
#ifdef HAVE_CONFIG_H
41
 
#  include "config.h"
42
 
#endif
43
 
 
44
 
#include "theoradec.h"
45
 
#include <gst/tag/tag.h>
46
 
 
47
 
GST_DEBUG_CATEGORY_STATIC (theoradecexp_debug);
48
 
#define GST_CAT_DEFAULT theoradecexp_debug
49
 
 
50
 
static GstStaticPadTemplate theora_dec_src_factory =
51
 
GST_STATIC_PAD_TEMPLATE ("src",
52
 
    GST_PAD_SRC,
53
 
    GST_PAD_ALWAYS,
54
 
    GST_STATIC_CAPS ("video/x-raw-yuv, "
55
 
        "format = (fourcc) { I420, YUY2, Y444 }, "
56
 
        "framerate = (fraction) [0/1, MAX], "
57
 
        "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
58
 
    );
59
 
 
60
 
static GstStaticPadTemplate theora_dec_sink_factory =
61
 
GST_STATIC_PAD_TEMPLATE ("sink",
62
 
    GST_PAD_SINK,
63
 
    GST_PAD_ALWAYS,
64
 
    GST_STATIC_CAPS ("video/x-theora")
65
 
    );
66
 
 
67
 
GST_BOILERPLATE (GstTheoraExpDec, gst_theoradec, GstElement, GST_TYPE_ELEMENT);
68
 
 
69
 
static gboolean theora_dec_sink_event (GstPad * pad, GstEvent * event);
70
 
static GstFlowReturn theora_dec_chain (GstPad * pad, GstBuffer * buffer);
71
 
static GstStateChangeReturn theora_dec_change_state (GstElement * element,
72
 
    GstStateChange transition);
73
 
static gboolean theora_dec_src_event (GstPad * pad, GstEvent * event);
74
 
static gboolean theora_dec_src_query (GstPad * pad, GstQuery * query);
75
 
static gboolean theora_dec_src_convert (GstPad * pad,
76
 
    GstFormat src_format, gint64 src_value,
77
 
    GstFormat * dest_format, gint64 * dest_value);
78
 
static gboolean theora_dec_sink_convert (GstPad * pad,
79
 
    GstFormat src_format, gint64 src_value,
80
 
    GstFormat * dest_format, gint64 * dest_value);
81
 
static gboolean theora_dec_sink_query (GstPad * pad, GstQuery * query);
82
 
 
83
 
static const GstQueryType *theora_get_query_types (GstPad * pad);
84
 
 
85
 
static void
86
 
gst_theoradec_base_init (gpointer g_class)
87
 
{
88
 
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
89
 
 
90
 
  gst_element_class_add_pad_template (element_class,
91
 
      gst_static_pad_template_get (&theora_dec_src_factory));
92
 
  gst_element_class_add_pad_template (element_class,
93
 
      gst_static_pad_template_get (&theora_dec_sink_factory));
94
 
  gst_element_class_set_details_simple (element_class, "Theora video decoder",
95
 
      "Codec/Decoder/Video",
96
 
      "decode raw theora streams to raw YUV video using libtheoradec",
97
 
      "Benjamin Otte <in7y118@public.uni-hamburg.de>, "
98
 
      "Wim Taymans <wim@fluendo.com>, " "Michael Smith <msmith@fluendo,com>");
99
 
}
100
 
 
101
 
static void
102
 
gst_theoradec_class_init (GstTheoraExpDecClass * klass)
103
 
{
104
 
  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
105
 
 
106
 
  gstelement_class->change_state = theora_dec_change_state;
107
 
 
108
 
  GST_DEBUG_CATEGORY_INIT (theoradecexp_debug, "theoradecexp", 0,
109
 
      "Theora decoder");
110
 
}
111
 
 
112
 
static void
113
 
gst_theoradec_init (GstTheoraExpDec * dec, GstTheoraExpDecClass * g_class)
114
 
{
115
 
  dec->sinkpad =
116
 
      gst_pad_new_from_static_template (&theora_dec_sink_factory, "sink");
117
 
  gst_pad_set_query_function (dec->sinkpad, theora_dec_sink_query);
118
 
  gst_pad_set_event_function (dec->sinkpad, theora_dec_sink_event);
119
 
  gst_pad_set_chain_function (dec->sinkpad, theora_dec_chain);
120
 
  gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
121
 
 
122
 
  dec->srcpad =
123
 
      gst_pad_new_from_static_template (&theora_dec_src_factory, "src");
124
 
  gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
125
 
  gst_pad_set_query_type_function (dec->srcpad, theora_get_query_types);
126
 
  gst_pad_set_query_function (dec->srcpad, theora_dec_src_query);
127
 
  gst_pad_use_fixed_caps (dec->srcpad);
128
 
 
129
 
  gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
130
 
 
131
 
  dec->queued = NULL;
132
 
}
133
 
 
134
 
static void
135
 
gst_theoradec_reset (GstTheoraExpDec * dec)
136
 
{
137
 
  GList *walk;
138
 
 
139
 
  dec->need_keyframe = TRUE;
140
 
  dec->last_timestamp = -1;
141
 
  dec->granulepos = -1;
142
 
  dec->discont = TRUE;
143
 
  dec->frame_nr = -1;
144
 
  gst_segment_init (&dec->segment, GST_FORMAT_TIME);
145
 
 
146
 
  GST_OBJECT_LOCK (dec);
147
 
  dec->proportion = 1.0;
148
 
  dec->earliest_time = -1;
149
 
  GST_OBJECT_UNLOCK (dec);
150
 
 
151
 
  for (walk = dec->queued; walk; walk = g_list_next (walk)) {
152
 
    gst_buffer_unref (GST_BUFFER_CAST (walk->data));
153
 
  }
154
 
  g_list_free (dec->queued);
155
 
  dec->queued = NULL;
156
 
}
157
 
 
158
 
static gint64
159
 
inc_granulepos (GstTheoraExpDec * dec, gint64 granulepos)
160
 
{
161
 
  gint framecount;
162
 
 
163
 
  if (granulepos == -1)
164
 
    return -1;
165
 
 
166
 
  framecount = th_granule_frame (dec->dec, granulepos);
167
 
 
168
 
  return (framecount + 1) << dec->info.keyframe_granule_shift;
169
 
}
170
 
 
171
 
static const GstQueryType *
172
 
theora_get_query_types (GstPad * pad)
173
 
{
174
 
  static const GstQueryType theora_src_query_types[] = {
175
 
    GST_QUERY_POSITION,
176
 
    GST_QUERY_DURATION,
177
 
    GST_QUERY_CONVERT,
178
 
    0
179
 
  };
180
 
 
181
 
  return theora_src_query_types;
182
 
}
183
 
 
184
 
static GstClockTime
185
 
gst_theoradec_granule_clocktime (GstTheoraExpDec * dec, ogg_int64_t granulepos)
186
 
{
187
 
  /* Avoid using theora_granule_time, which returns a double (in seconds); not
188
 
   * what we want
189
 
   */
190
 
  if (granulepos >= 0) {
191
 
    guint64 framecount = th_granule_frame (dec->dec, granulepos);
192
 
 
193
 
    return gst_util_uint64_scale_int (framecount * GST_SECOND,
194
 
        dec->info.fps_denominator, dec->info.fps_numerator);
195
 
  }
196
 
  return -1;
197
 
}
198
 
 
199
 
static gboolean
200
 
theora_dec_src_convert (GstPad * pad,
201
 
    GstFormat src_format, gint64 src_value,
202
 
    GstFormat * dest_format, gint64 * dest_value)
203
 
{
204
 
  gboolean res = TRUE;
205
 
  GstTheoraExpDec *dec;
206
 
  guint64 scale = 1;
207
 
 
208
 
  if (src_format == *dest_format) {
209
 
    *dest_value = src_value;
210
 
    return TRUE;
211
 
  }
212
 
 
213
 
  dec = GST_THEORA_DEC_EXP (gst_pad_get_parent (pad));
214
 
 
215
 
  /* we need the info part before we can done something */
216
 
  if (!dec->have_header)
217
 
    goto no_header;
218
 
 
219
 
  switch (src_format) {
220
 
    case GST_FORMAT_BYTES:
221
 
      switch (*dest_format) {
222
 
        case GST_FORMAT_DEFAULT:
223
 
          *dest_value = gst_util_uint64_scale_int (src_value, 8,
224
 
              dec->info.pic_height * dec->info.pic_width * dec->output_bpp);
225
 
          break;
226
 
        case GST_FORMAT_TIME:
227
 
          /* seems like a rather silly conversion, implement me if you like */
228
 
        default:
229
 
          res = FALSE;
230
 
      }
231
 
      break;
232
 
    case GST_FORMAT_TIME:
233
 
      switch (*dest_format) {
234
 
        case GST_FORMAT_BYTES:
235
 
          scale = dec->output_bpp *
236
 
              (dec->info.pic_width * dec->info.pic_height) / 8;
237
 
        case GST_FORMAT_DEFAULT:
238
 
          if (dec->info.fps_numerator && dec->info.fps_denominator)
239
 
            *dest_value = scale * gst_util_uint64_scale (src_value,
240
 
                dec->info.fps_numerator,
241
 
                dec->info.fps_denominator * GST_SECOND);
242
 
          else
243
 
            res = FALSE;
244
 
          break;
245
 
        default:
246
 
          res = FALSE;
247
 
      }
248
 
      break;
249
 
    case GST_FORMAT_DEFAULT:
250
 
      switch (*dest_format) {
251
 
        case GST_FORMAT_TIME:
252
 
          if (dec->info.fps_numerator && dec->info.fps_denominator)
253
 
            *dest_value = gst_util_uint64_scale (src_value,
254
 
                GST_SECOND * dec->info.fps_denominator,
255
 
                dec->info.fps_numerator);
256
 
          else
257
 
            res = FALSE;
258
 
          break;
259
 
        case GST_FORMAT_BYTES:
260
 
          *dest_value = gst_util_uint64_scale_int (src_value,
261
 
              dec->output_bpp * dec->info.pic_width * dec->info.pic_height, 8);
262
 
          break;
263
 
        default:
264
 
          res = FALSE;
265
 
      }
266
 
      break;
267
 
    default:
268
 
      res = FALSE;
269
 
  }
270
 
done:
271
 
  gst_object_unref (dec);
272
 
  return res;
273
 
 
274
 
  /* ERRORS */
275
 
no_header:
276
 
  {
277
 
    GST_DEBUG_OBJECT (dec, "no header yet, cannot convert");
278
 
    res = FALSE;
279
 
    goto done;
280
 
  }
281
 
}
282
 
 
283
 
static gboolean
284
 
theora_dec_sink_convert (GstPad * pad,
285
 
    GstFormat src_format, gint64 src_value,
286
 
    GstFormat * dest_format, gint64 * dest_value)
287
 
{
288
 
  gboolean res = TRUE;
289
 
  GstTheoraExpDec *dec;
290
 
 
291
 
  if (src_format == *dest_format) {
292
 
    *dest_value = src_value;
293
 
    return TRUE;
294
 
  }
295
 
 
296
 
  dec = GST_THEORA_DEC_EXP (gst_pad_get_parent (pad));
297
 
 
298
 
  /* we need the info part before we can done something */
299
 
  if (!dec->have_header)
300
 
    goto no_header;
301
 
 
302
 
  switch (src_format) {
303
 
    case GST_FORMAT_DEFAULT:
304
 
      switch (*dest_format) {
305
 
        case GST_FORMAT_TIME:
306
 
          *dest_value = gst_theoradec_granule_clocktime (dec, src_value);
307
 
          break;
308
 
        default:
309
 
          res = FALSE;
310
 
      }
311
 
      break;
312
 
    case GST_FORMAT_TIME:
313
 
      switch (*dest_format) {
314
 
        case GST_FORMAT_DEFAULT:
315
 
        {
316
 
          guint rest;
317
 
 
318
 
          if (!dec->info.fps_numerator || !dec->info.fps_denominator) {
319
 
            res = FALSE;
320
 
            break;
321
 
          }
322
 
 
323
 
          /* framecount */
324
 
          *dest_value = gst_util_uint64_scale (src_value,
325
 
              dec->info.fps_numerator, GST_SECOND * dec->info.fps_denominator);
326
 
 
327
 
          /* funny way of calculating granulepos in theora */
328
 
          rest = *dest_value / (1 << dec->info.keyframe_granule_shift);
329
 
          *dest_value -= rest;
330
 
          *dest_value <<= dec->info.keyframe_granule_shift;
331
 
          *dest_value += rest;
332
 
          break;
333
 
        }
334
 
        default:
335
 
          res = FALSE;
336
 
          break;
337
 
      }
338
 
      break;
339
 
    default:
340
 
      res = FALSE;
341
 
  }
342
 
done:
343
 
  gst_object_unref (dec);
344
 
  return res;
345
 
 
346
 
  /* ERRORS */
347
 
no_header:
348
 
  {
349
 
    GST_DEBUG_OBJECT (dec, "no header yet, cannot convert");
350
 
    res = FALSE;
351
 
    goto done;
352
 
  }
353
 
}
354
 
 
355
 
static gboolean
356
 
theora_dec_src_query (GstPad * pad, GstQuery * query)
357
 
{
358
 
  GstTheoraExpDec *dec;
359
 
 
360
 
  gboolean res = FALSE;
361
 
 
362
 
  dec = GST_THEORA_DEC_EXP (gst_pad_get_parent (pad));
363
 
 
364
 
  switch (GST_QUERY_TYPE (query)) {
365
 
    case GST_QUERY_POSITION:
366
 
    {
367
 
      gint64 granulepos, value;
368
 
      GstFormat my_format, format;
369
 
      gint64 time;
370
 
 
371
 
      /* we can convert a granule position to everything */
372
 
      granulepos = dec->granulepos;
373
 
 
374
 
      GST_LOG_OBJECT (dec,
375
 
          "query %p: we have current granule: %lld", query, granulepos);
376
 
 
377
 
      /* parse format */
378
 
      gst_query_parse_position (query, &format, NULL);
379
 
 
380
 
      /* and convert to the final format in two steps with time as the 
381
 
       * intermediate step */
382
 
      my_format = GST_FORMAT_TIME;
383
 
      if (!(res =
384
 
              theora_dec_sink_convert (dec->sinkpad, GST_FORMAT_DEFAULT,
385
 
                  granulepos, &my_format, &time)))
386
 
        goto error;
387
 
 
388
 
      time = gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, time);
389
 
 
390
 
      GST_LOG_OBJECT (dec,
391
 
          "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time));
392
 
 
393
 
      if (!(res =
394
 
              theora_dec_src_convert (pad, my_format, time, &format, &value)))
395
 
        goto error;
396
 
 
397
 
      gst_query_set_position (query, format, value);
398
 
 
399
 
      GST_LOG_OBJECT (dec,
400
 
          "query %p: we return %lld (format %u)", query, value, format);
401
 
 
402
 
      break;
403
 
    }
404
 
    case GST_QUERY_DURATION:
405
 
    {
406
 
      /* forward to peer for total */
407
 
      GstPad *peer;
408
 
 
409
 
      if (!(peer = gst_pad_get_peer (dec->sinkpad)))
410
 
        goto error;
411
 
 
412
 
      res = gst_pad_query (peer, query);
413
 
      gst_object_unref (peer);
414
 
      if (!res)
415
 
        goto error;
416
 
      break;
417
 
    }
418
 
    case GST_QUERY_CONVERT:
419
 
    {
420
 
      GstFormat src_fmt, dest_fmt;
421
 
      gint64 src_val, dest_val;
422
 
 
423
 
      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
424
 
      if (!(res =
425
 
              theora_dec_src_convert (pad, src_fmt, src_val, &dest_fmt,
426
 
                  &dest_val)))
427
 
        goto error;
428
 
 
429
 
      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
430
 
      break;
431
 
    }
432
 
    default:
433
 
      res = gst_pad_query_default (pad, query);
434
 
      break;
435
 
  }
436
 
done:
437
 
  gst_object_unref (dec);
438
 
 
439
 
  return res;
440
 
 
441
 
  /* ERRORS */
442
 
error:
443
 
  {
444
 
    GST_DEBUG_OBJECT (dec, "query failed");
445
 
    goto done;
446
 
  }
447
 
}
448
 
 
449
 
static gboolean
450
 
theora_dec_sink_query (GstPad * pad, GstQuery * query)
451
 
{
452
 
  gboolean res = FALSE;
453
 
 
454
 
  switch (GST_QUERY_TYPE (query)) {
455
 
    case GST_QUERY_CONVERT:
456
 
    {
457
 
      GstFormat src_fmt, dest_fmt;
458
 
      gint64 src_val, dest_val;
459
 
 
460
 
      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
461
 
      if (!(res =
462
 
              theora_dec_sink_convert (pad, src_fmt, src_val, &dest_fmt,
463
 
                  &dest_val)))
464
 
        goto error;
465
 
 
466
 
      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
467
 
      break;
468
 
    }
469
 
    default:
470
 
      res = gst_pad_query_default (pad, query);
471
 
      break;
472
 
  }
473
 
 
474
 
error:
475
 
  return res;
476
 
}
477
 
 
478
 
static gboolean
479
 
theora_dec_src_event (GstPad * pad, GstEvent * event)
480
 
{
481
 
  gboolean res = TRUE;
482
 
  GstTheoraExpDec *dec;
483
 
 
484
 
  dec = GST_THEORA_DEC_EXP (gst_pad_get_parent (pad));
485
 
 
486
 
  switch (GST_EVENT_TYPE (event)) {
487
 
    case GST_EVENT_SEEK:
488
 
    {
489
 
      GstFormat format, tformat;
490
 
      gdouble rate;
491
 
      GstEvent *real_seek;
492
 
      GstSeekFlags flags;
493
 
      GstSeekType cur_type, stop_type;
494
 
      gint64 cur, stop;
495
 
      gint64 tcur, tstop;
496
 
 
497
 
      gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
498
 
          &stop_type, &stop);
499
 
      gst_event_unref (event);
500
 
 
501
 
      /* we have to ask our peer to seek to time here as we know
502
 
       * nothing about how to generate a granulepos from the src
503
 
       * formats or anything.
504
 
       * 
505
 
       * First bring the requested format to time 
506
 
       */
507
 
      tformat = GST_FORMAT_TIME;
508
 
      if (!(res = theora_dec_src_convert (pad, format, cur, &tformat, &tcur)))
509
 
        goto convert_error;
510
 
      if (!(res = theora_dec_src_convert (pad, format, stop, &tformat, &tstop)))
511
 
        goto convert_error;
512
 
 
513
 
      /* then seek with time on the peer */
514
 
      real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
515
 
          flags, cur_type, tcur, stop_type, tstop);
516
 
 
517
 
      res = gst_pad_push_event (dec->sinkpad, real_seek);
518
 
 
519
 
      gst_event_unref (event);
520
 
      break;
521
 
    }
522
 
    case GST_EVENT_QOS:
523
 
    {
524
 
      gdouble proportion;
525
 
      GstClockTimeDiff diff;
526
 
      GstClockTime timestamp;
527
 
 
528
 
      gst_event_parse_qos (event, &proportion, &diff, &timestamp);
529
 
 
530
 
      /* we cannot randomly skip frame decoding since we don't have
531
 
       * B frames. we can however use the timestamp and diff to not
532
 
       * push late frames. This would let us save the time for copying and
533
 
       * cropping the frame. */
534
 
      GST_OBJECT_LOCK (dec);
535
 
      dec->proportion = proportion;
536
 
      dec->earliest_time = timestamp + diff;
537
 
      GST_OBJECT_UNLOCK (dec);
538
 
 
539
 
      res = gst_pad_event_default (pad, event);
540
 
      break;
541
 
    }
542
 
    default:
543
 
      res = gst_pad_event_default (pad, event);
544
 
      break;
545
 
  }
546
 
done:
547
 
  gst_object_unref (dec);
548
 
 
549
 
  return res;
550
 
 
551
 
  /* ERRORS */
552
 
convert_error:
553
 
  {
554
 
    GST_DEBUG_OBJECT (dec, "could not convert format");
555
 
    goto done;
556
 
  }
557
 
}
558
 
 
559
 
static gboolean
560
 
theora_dec_sink_event (GstPad * pad, GstEvent * event)
561
 
{
562
 
  gboolean ret = FALSE;
563
 
  GstTheoraExpDec *dec;
564
 
 
565
 
  dec = GST_THEORA_DEC_EXP (gst_pad_get_parent (pad));
566
 
 
567
 
  GST_LOG_OBJECT (dec, "handling event");
568
 
  switch (GST_EVENT_TYPE (event)) {
569
 
    case GST_EVENT_FLUSH_START:
570
 
      ret = gst_pad_push_event (dec->srcpad, event);
571
 
      break;
572
 
    case GST_EVENT_FLUSH_STOP:
573
 
      /* TODO: Call appropriate func with OC_DECCTL_SET_GRANPOS? */
574
 
      gst_theoradec_reset (dec);
575
 
      ret = gst_pad_push_event (dec->srcpad, event);
576
 
      break;
577
 
    case GST_EVENT_EOS:
578
 
      ret = gst_pad_push_event (dec->srcpad, event);
579
 
      break;
580
 
    case GST_EVENT_NEWSEGMENT:
581
 
    {
582
 
      gboolean update;
583
 
      GstFormat format;
584
 
      gdouble rate, arate;
585
 
      gint64 start, stop, time;
586
 
 
587
 
      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
588
 
          &start, &stop, &time);
589
 
 
590
 
      /* we need TIME and a positive rate */
591
 
      if (format != GST_FORMAT_TIME)
592
 
        goto newseg_wrong_format;
593
 
 
594
 
      if (rate <= 0.0)
595
 
        goto newseg_wrong_rate;
596
 
 
597
 
      /* now configure the values */
598
 
      gst_segment_set_newsegment_full (&dec->segment, update,
599
 
          rate, arate, format, start, stop, time);
600
 
 
601
 
      /* and forward */
602
 
      ret = gst_pad_push_event (dec->srcpad, event);
603
 
      break;
604
 
    }
605
 
    default:
606
 
      ret = gst_pad_push_event (dec->srcpad, event);
607
 
      break;
608
 
  }
609
 
done:
610
 
  gst_object_unref (dec);
611
 
 
612
 
  return ret;
613
 
 
614
 
  /* ERRORS */
615
 
newseg_wrong_format:
616
 
  {
617
 
    GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
618
 
    gst_event_unref (event);
619
 
    goto done;
620
 
  }
621
 
newseg_wrong_rate:
622
 
  {
623
 
    GST_DEBUG_OBJECT (dec, "negative rates not supported yet");
624
 
    gst_event_unref (event);
625
 
    goto done;
626
 
  }
627
 
}
628
 
 
629
 
static GstFlowReturn
630
 
theora_handle_comment_packet (GstTheoraExpDec * dec, ogg_packet * packet)
631
 
{
632
 
  gchar *encoder = NULL;
633
 
  GstBuffer *buf;
634
 
  GstTagList *list;
635
 
 
636
 
  GST_DEBUG_OBJECT (dec, "parsing comment packet");
637
 
 
638
 
  buf = gst_buffer_new_and_alloc (packet->bytes);
639
 
  memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
640
 
 
641
 
  list =
642
 
      gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\201theora", 7,
643
 
      &encoder);
644
 
 
645
 
  gst_buffer_unref (buf);
646
 
 
647
 
  if (!list) {
648
 
    GST_ERROR_OBJECT (dec, "couldn't decode comments");
649
 
    list = gst_tag_list_new ();
650
 
  }
651
 
  if (encoder) {
652
 
    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
653
 
        GST_TAG_ENCODER, encoder, NULL);
654
 
    g_free (encoder);
655
 
  }
656
 
  gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
657
 
      GST_TAG_ENCODER_VERSION, dec->info.version_major,
658
 
      GST_TAG_VIDEO_CODEC, "Theora", NULL);
659
 
 
660
 
  if (dec->info.target_bitrate > 0) {
661
 
    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
662
 
        GST_TAG_BITRATE, dec->info.target_bitrate,
663
 
        GST_TAG_NOMINAL_BITRATE, dec->info.target_bitrate, NULL);
664
 
  }
665
 
 
666
 
  gst_element_found_tags_for_pad (GST_ELEMENT_CAST (dec), dec->srcpad, list);
667
 
 
668
 
  return GST_FLOW_OK;
669
 
}
670
 
 
671
 
static GstFlowReturn
672
 
theora_handle_type_packet (GstTheoraExpDec * dec, ogg_packet * packet)
673
 
{
674
 
  GstCaps *caps;
675
 
  gint par_num, par_den;
676
 
  guint32 fourcc;
677
 
 
678
 
  GST_DEBUG_OBJECT (dec, "fps %d/%d, PAR %d/%d",
679
 
      dec->info.fps_numerator, dec->info.fps_denominator,
680
 
      dec->info.aspect_numerator, dec->info.aspect_denominator);
681
 
 
682
 
  /* calculate par
683
 
   * the info.aspect_* values reflect PAR;
684
 
   * 0 for either is undefined; we're told to assume 1:1 */
685
 
  par_num = dec->info.aspect_numerator;
686
 
  par_den = dec->info.aspect_denominator;
687
 
  if (par_num == 0 || par_den == 0) {
688
 
    par_num = par_den = 1;
689
 
  }
690
 
  /* theora has:
691
 
   *
692
 
   *  frame_width/frame_height : dimension of the encoded frame 
693
 
   *  pic_width/pic_height : dimension of the visible part
694
 
   *  pic_x/pic_y : offset in encoded frame where visible part starts
695
 
   */
696
 
  GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.frame_width,
697
 
      dec->info.frame_height, par_num, par_den);
698
 
  GST_DEBUG_OBJECT (dec, "pic dimension %dx%d, offset %d:%d",
699
 
      dec->info.pic_width, dec->info.pic_height,
700
 
      dec->info.pic_x, dec->info.pic_y);
701
 
 
702
 
  /* add black borders to make width/height/offsets even. we need this because
703
 
   * we cannot express an offset to the peer plugin. */
704
 
  dec->width = GST_ROUND_UP_2 (dec->info.pic_width + (dec->info.pic_x & 1));
705
 
  dec->height = GST_ROUND_UP_2 (dec->info.pic_height + (dec->info.pic_y & 1));
706
 
  dec->offset_x = dec->info.pic_x & ~1;
707
 
  dec->offset_y = dec->info.pic_y & ~1;
708
 
 
709
 
  GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d",
710
 
      dec->width, dec->height, dec->offset_x, dec->offset_y);
711
 
 
712
 
  if (dec->info.pixel_fmt == TH_PF_420) {
713
 
    dec->output_bpp = 12;       /* Average bits per pixel. */
714
 
 
715
 
    /* This is bad. I420 is very specific, and has implicit stride. This means
716
 
     * we can't use the native output of the decoder, we have to memcpy it to
717
 
     * an I420 buffer. For now, GStreamer gives us no better alternative.
718
 
     */
719
 
    fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
720
 
  } else if (dec->info.pixel_fmt == TH_PF_422) {
721
 
    dec->output_bpp = 16;
722
 
    /* Unfortunately, we don't have a planar 'fourcc' value, which means we
723
 
     * can't represent the output format of the decoder at all in gstreamer.
724
 
     * So, we convert to a widely-supported packed format.
725
 
     */
726
 
    fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
727
 
  } else if (dec->info.pixel_fmt == TH_PF_444) {
728
 
    dec->output_bpp = 24;
729
 
    /* As for I420, we can't define the stride for this, so we need to memcpy,
730
 
     * though at least this is a planar format...
731
 
     */
732
 
    fourcc = GST_MAKE_FOURCC ('Y', '4', '4', '4');
733
 
  } else {
734
 
    GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixel_fmt);
735
 
    return GST_FLOW_ERROR;
736
 
  }
737
 
 
738
 
  dec->dec = th_decode_alloc (&dec->info, dec->setup);
739
 
 
740
 
  th_setup_free (dec->setup);
741
 
  dec->setup = NULL;
742
 
 
743
 
  caps = gst_caps_new_simple ("video/x-raw-yuv",
744
 
      "format", GST_TYPE_FOURCC, fourcc,
745
 
      "framerate", GST_TYPE_FRACTION,
746
 
      dec->info.fps_numerator, dec->info.fps_denominator,
747
 
      "pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
748
 
      "width", G_TYPE_INT, dec->width, "height", G_TYPE_INT, dec->height, NULL);
749
 
  gst_pad_set_caps (dec->srcpad, caps);
750
 
  gst_caps_unref (caps);
751
 
 
752
 
  dec->have_header = TRUE;
753
 
 
754
 
  return GST_FLOW_OK;
755
 
}
756
 
 
757
 
static GstFlowReturn
758
 
theora_handle_header_packet (GstTheoraExpDec * dec, ogg_packet * packet)
759
 
{
760
 
  GstFlowReturn res;
761
 
  int ret;
762
 
 
763
 
  GST_DEBUG_OBJECT (dec, "parsing header packet");
764
 
 
765
 
  ret = th_decode_headerin (&dec->info, &dec->comment, &dec->setup, packet);
766
 
  if (ret < 0)
767
 
    goto header_read_error;
768
 
 
769
 
  /* We can never get here unless we have at least a one-byte packet */
770
 
  switch (packet->packet[0]) {
771
 
    case 0x81:
772
 
      res = theora_handle_comment_packet (dec, packet);
773
 
      break;
774
 
    case 0x82:
775
 
      res = theora_handle_type_packet (dec, packet);
776
 
      break;
777
 
    default:
778
 
      /* ignore */
779
 
      g_warning ("unknown theora header packet found");
780
 
    case 0x80:
781
 
      /* nothing special, this is the identification header */
782
 
      res = GST_FLOW_OK;
783
 
      break;
784
 
  }
785
 
  return res;
786
 
 
787
 
  /* ERRORS */
788
 
header_read_error:
789
 
  {
790
 
    GST_WARNING_OBJECT (dec, "Header parsing failed: %d", ret);
791
 
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
792
 
        (NULL), ("couldn't read header packet"));
793
 
    return GST_FLOW_ERROR;
794
 
  }
795
 
}
796
 
 
797
 
/* returns TRUE if buffer is within segment, else FALSE.
798
 
 * if buffer is on segment border, its timestamp and duration will be clipped */
799
 
static gboolean
800
 
clip_buffer (GstTheoraExpDec * dec, GstBuffer * buf)
801
 
{
802
 
  gboolean res = TRUE;
803
 
  GstClockTime in_ts, in_dur, stop;
804
 
  gint64 cstart, cstop;
805
 
 
806
 
  in_ts = GST_BUFFER_TIMESTAMP (buf);
807
 
  in_dur = GST_BUFFER_DURATION (buf);
808
 
 
809
 
  GST_LOG_OBJECT (dec,
810
 
      "timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT,
811
 
      GST_TIME_ARGS (in_ts), GST_TIME_ARGS (in_dur));
812
 
 
813
 
  /* can't clip without TIME segment */
814
 
  if (dec->segment.format != GST_FORMAT_TIME)
815
 
    goto beach;
816
 
 
817
 
  /* we need a start time */
818
 
  if (!GST_CLOCK_TIME_IS_VALID (in_ts))
819
 
    goto beach;
820
 
 
821
 
  /* generate valid stop, if duration unknown, we have unknown stop */
822
 
  stop =
823
 
      GST_CLOCK_TIME_IS_VALID (in_dur) ? (in_ts + in_dur) : GST_CLOCK_TIME_NONE;
824
 
 
825
 
  /* now clip */
826
 
  if (!(res = gst_segment_clip (&dec->segment, GST_FORMAT_TIME,
827
 
              in_ts, stop, &cstart, &cstop)))
828
 
    goto beach;
829
 
 
830
 
  /* update timestamp and possibly duration if the clipped stop time is valid */
831
 
  GST_BUFFER_TIMESTAMP (buf) = cstart;
832
 
  if (GST_CLOCK_TIME_IS_VALID (cstop))
833
 
    GST_BUFFER_DURATION (buf) = cstop - cstart;
834
 
 
835
 
beach:
836
 
  GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : ""));
837
 
  return res;
838
 
}
839
 
 
840
 
 
841
 
/* FIXME, this needs to be moved to the demuxer */
842
 
static GstFlowReturn
843
 
theora_dec_push (GstTheoraExpDec * dec, GstBuffer * buf)
844
 
{
845
 
  GstFlowReturn result = GST_FLOW_OK;
846
 
  GstClockTime outtime = GST_BUFFER_TIMESTAMP (buf);
847
 
 
848
 
  if (outtime == GST_CLOCK_TIME_NONE) {
849
 
    dec->queued = g_list_append (dec->queued, buf);
850
 
    GST_DEBUG_OBJECT (dec, "queued buffer");
851
 
    result = GST_FLOW_OK;
852
 
  } else {
853
 
    if (dec->queued) {
854
 
      gint64 size;
855
 
      GList *walk;
856
 
 
857
 
      GST_DEBUG_OBJECT (dec, "first buffer with time %" GST_TIME_FORMAT,
858
 
          GST_TIME_ARGS (outtime));
859
 
 
860
 
      size = g_list_length (dec->queued);
861
 
      for (walk = dec->queued; walk; walk = g_list_next (walk)) {
862
 
        GstBuffer *buffer = GST_BUFFER (walk->data);
863
 
        GstClockTime time;
864
 
 
865
 
        time = outtime - gst_util_uint64_scale_int (size * GST_SECOND,
866
 
            dec->info.fps_denominator, dec->info.fps_numerator);
867
 
 
868
 
        GST_DEBUG_OBJECT (dec, "patch buffer %lld %lld", size, time);
869
 
        GST_BUFFER_TIMESTAMP (buffer) = time;
870
 
 
871
 
        if (dec->discont) {
872
 
          GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
873
 
          dec->discont = FALSE;
874
 
        }
875
 
 
876
 
        /* ignore the result.. */
877
 
        if (clip_buffer (dec, buffer))
878
 
          gst_pad_push (dec->srcpad, buffer);
879
 
        else
880
 
          gst_buffer_unref (buffer);
881
 
        size--;
882
 
      }
883
 
      g_list_free (dec->queued);
884
 
      dec->queued = NULL;
885
 
    }
886
 
 
887
 
    if (dec->discont) {
888
 
      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
889
 
      dec->discont = FALSE;
890
 
    }
891
 
 
892
 
    if (clip_buffer (dec, buf))
893
 
      result = gst_pad_push (dec->srcpad, buf);
894
 
    else
895
 
      gst_buffer_unref (buf);
896
 
  }
897
 
 
898
 
  return result;
899
 
}
900
 
 
901
 
/* Create a packed 'YUY2' image, push it.
902
 
 */
903
 
static GstFlowReturn
904
 
theora_handle_422_image (GstTheoraExpDec * dec, th_ycbcr_buffer yuv,
905
 
    GstClockTime outtime)
906
 
{
907
 
  int i, j;
908
 
  gint width, height;
909
 
  gint out_size;
910
 
  gint stride;
911
 
  GstBuffer *out;
912
 
  GstFlowReturn result;
913
 
 
914
 
  width = dec->width;
915
 
  height = dec->height;
916
 
 
917
 
  stride = GST_ROUND_UP_2 (width) * 2;
918
 
 
919
 
  out_size = stride * height;
920
 
 
921
 
  /* now copy over the area contained in offset_x,offset_y,
922
 
   * frame_width, frame_height */
923
 
  result =
924
 
      gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
925
 
      out_size, GST_PAD_CAPS (dec->srcpad), &out);
926
 
  if (result != GST_FLOW_OK)
927
 
    goto no_buffer;
928
 
 
929
 
  /* The output pixels look like:
930
 
   *   YUYVYUYV....
931
 
   *
932
 
   * Do the interleaving... Note that this is kinda messed up if our width is
933
 
   * odd. In that case, we can't represent it properly in YUY2, so we just
934
 
   * pad out to even in that case (this is why we have GST_ROUND_UP_2() above).
935
 
   */
936
 
  {
937
 
    guchar *src_y;
938
 
    guchar *src_cb;
939
 
    guchar *src_cr;
940
 
    guchar *dest;
941
 
    guchar *curdest;
942
 
    guchar *src;
943
 
 
944
 
    dest = GST_BUFFER_DATA (out);
945
 
 
946
 
    src_y = yuv[0].data + dec->offset_x + dec->offset_y * yuv[0].ystride;
947
 
    src_cb = yuv[1].data + dec->offset_x / 2 + dec->offset_y * yuv[1].ystride;
948
 
    src_cr = yuv[2].data + dec->offset_x / 2 + dec->offset_y * yuv[2].ystride;
949
 
 
950
 
    for (i = 0; i < height; i++) {
951
 
      /* Y first */
952
 
      curdest = dest;
953
 
      src = src_y;
954
 
      for (j = 0; j < width; j++) {
955
 
        *curdest = *src++;
956
 
        curdest += 2;
957
 
      }
958
 
      src_y += yuv[0].ystride;
959
 
 
960
 
      curdest = dest + 1;
961
 
      src = src_cb;
962
 
      for (j = 0; j < width; j++) {
963
 
        *curdest = *src++;
964
 
        curdest += 4;
965
 
      }
966
 
      src_cb += yuv[1].ystride;
967
 
 
968
 
      curdest = dest + 3;
969
 
      src = src_cr;
970
 
      for (j = 0; j < width; j++) {
971
 
        *curdest = *src++;
972
 
        curdest += 4;
973
 
      }
974
 
      src_cr += yuv[2].ystride;
975
 
 
976
 
      dest += stride;
977
 
    }
978
 
  }
979
 
 
980
 
  GST_BUFFER_OFFSET (out) = dec->frame_nr;
981
 
  if (dec->frame_nr != -1)
982
 
    dec->frame_nr++;
983
 
  GST_BUFFER_OFFSET_END (out) = dec->frame_nr;
984
 
  GST_BUFFER_DURATION (out) =
985
 
      gst_util_uint64_scale_int (GST_SECOND, dec->info.fps_denominator,
986
 
      dec->info.fps_numerator);
987
 
  GST_BUFFER_TIMESTAMP (out) = outtime;
988
 
 
989
 
  return theora_dec_push (dec, out);
990
 
 
991
 
no_buffer:
992
 
  {
993
 
    GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
994
 
        gst_flow_get_name (result));
995
 
    return result;
996
 
  }
997
 
}
998
 
 
999
 
/* Get buffer, populate with original data (we must memcpy to get things to
1000
 
 * have the expected strides, etc...), and push.
1001
 
 */
1002
 
static GstFlowReturn
1003
 
theora_handle_444_image (GstTheoraExpDec * dec, th_ycbcr_buffer yuv,
1004
 
    GstClockTime outtime)
1005
 
{
1006
 
  int i, plane;
1007
 
  gint width, height;
1008
 
  gint out_size;
1009
 
  gint stride;
1010
 
  GstBuffer *out;
1011
 
  GstFlowReturn result;
1012
 
 
1013
 
  width = dec->width;
1014
 
  height = dec->height;
1015
 
 
1016
 
  /* TODO: Check if we have any special alignment requirements for the planes,
1017
 
   * or for each line within a plane. */
1018
 
  stride = width;
1019
 
  out_size = stride * height * 3;
1020
 
 
1021
 
  /* now copy over the area contained in offset_x,offset_y,
1022
 
   * frame_width, frame_height */
1023
 
  result =
1024
 
      gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
1025
 
      out_size, GST_PAD_CAPS (dec->srcpad), &out);
1026
 
  if (result != GST_FLOW_OK)
1027
 
    goto no_buffer;
1028
 
 
1029
 
  {
1030
 
    guchar *dest, *src;
1031
 
 
1032
 
    for (plane = 0; plane < 3; plane++) {
1033
 
      /* TODO: do we have to use something different here? */
1034
 
      dest = GST_BUFFER_DATA (out) + plane * stride * height;
1035
 
 
1036
 
      src = yuv[plane].data + dec->offset_x +
1037
 
          dec->offset_y * yuv[plane].ystride;
1038
 
 
1039
 
      for (i = 0; i < height; i++) {
1040
 
        memcpy (dest, src, width);
1041
 
 
1042
 
        dest += stride;
1043
 
        src += yuv[plane].ystride;
1044
 
      }
1045
 
 
1046
 
    }
1047
 
  }
1048
 
 
1049
 
  /* FIXME, frame_nr not correct */
1050
 
  GST_BUFFER_OFFSET (out) = dec->frame_nr;
1051
 
  dec->frame_nr++;
1052
 
  GST_BUFFER_OFFSET_END (out) = dec->frame_nr;
1053
 
  GST_BUFFER_DURATION (out) =
1054
 
      gst_util_uint64_scale_int (GST_SECOND, dec->info.fps_denominator,
1055
 
      dec->info.fps_numerator);
1056
 
  GST_BUFFER_TIMESTAMP (out) = outtime;
1057
 
 
1058
 
  return theora_dec_push (dec, out);
1059
 
 
1060
 
no_buffer:
1061
 
  {
1062
 
    GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
1063
 
        gst_flow_get_name (result));
1064
 
    return result;
1065
 
  }
1066
 
}
1067
 
 
1068
 
/* Create a (planar, but with special alignment and stride requirements) 'I420'
1069
 
 * buffer, populate, push.
1070
 
 */
1071
 
static GstFlowReturn
1072
 
theora_handle_420_image (GstTheoraExpDec * dec, th_ycbcr_buffer yuv,
1073
 
    GstClockTime outtime)
1074
 
{
1075
 
  int i;
1076
 
  gint width, height, cwidth, cheight;
1077
 
  gint out_size;
1078
 
  gint stride_y, stride_uv;
1079
 
  GstBuffer *out;
1080
 
  GstFlowReturn result;
1081
 
 
1082
 
  width = dec->width;
1083
 
  height = dec->height;
1084
 
  cwidth = width / 2;
1085
 
  cheight = height / 2;
1086
 
 
1087
 
  /* should get the stride from the caps, for now we round up to the nearest
1088
 
   * multiple of 4 because some element needs it. chroma needs special 
1089
 
   * treatment, see videotestsrc. */
1090
 
  stride_y = GST_ROUND_UP_4 (width);
1091
 
  stride_uv = GST_ROUND_UP_8 (width) / 2;
1092
 
 
1093
 
  out_size = stride_y * height + stride_uv * cheight * 2;
1094
 
 
1095
 
  /* now copy over the area contained in offset_x,offset_y,
1096
 
   * frame_width, frame_height */
1097
 
  result =
1098
 
      gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
1099
 
      out_size, GST_PAD_CAPS (dec->srcpad), &out);
1100
 
  if (result != GST_FLOW_OK)
1101
 
    goto no_buffer;
1102
 
 
1103
 
  /* copy the visible region to the destination. This is actually pretty
1104
 
   * complicated and gstreamer doesn't support all the needed caps to do this
1105
 
   * correctly. For example, when we have an odd offset, we should only combine
1106
 
   * 1 row/column of luma samples with one chroma sample in colorspace conversion. 
1107
 
   * We compensate for this by adding a black border around the image when the
1108
 
   * offset or size is odd (see above).
1109
 
   */
1110
 
  {
1111
 
    guchar *dest_y, *src_y;
1112
 
    guchar *dest_u, *src_u;
1113
 
    guchar *dest_v, *src_v;
1114
 
    gint offset_u, offset_v;
1115
 
 
1116
 
    dest_y = GST_BUFFER_DATA (out);
1117
 
    dest_u = dest_y + stride_y * height;
1118
 
    dest_v = dest_u + stride_uv * cheight;
1119
 
 
1120
 
    src_y = yuv[0].data + dec->offset_x + dec->offset_y * yuv[0].ystride;
1121
 
 
1122
 
    for (i = 0; i < height; i++) {
1123
 
      memcpy (dest_y, src_y, width);
1124
 
 
1125
 
      dest_y += stride_y;
1126
 
      src_y += yuv[0].ystride;
1127
 
    }
1128
 
 
1129
 
    offset_u = dec->offset_x / 2 + dec->offset_y / 2 * yuv[1].ystride;
1130
 
    offset_v = dec->offset_x / 2 + dec->offset_y / 2 * yuv[2].ystride;
1131
 
 
1132
 
    src_u = yuv[1].data + offset_u;
1133
 
    src_v = yuv[2].data + offset_v;
1134
 
 
1135
 
    for (i = 0; i < cheight; i++) {
1136
 
      memcpy (dest_u, src_u, cwidth);
1137
 
      memcpy (dest_v, src_v, cwidth);
1138
 
 
1139
 
      dest_u += stride_uv;
1140
 
      src_u += yuv[1].ystride;
1141
 
      dest_v += stride_uv;
1142
 
      src_v += yuv[2].ystride;
1143
 
    }
1144
 
  }
1145
 
 
1146
 
  /* FIXME, frame_nr not correct */
1147
 
  GST_BUFFER_OFFSET (out) = dec->frame_nr;
1148
 
  dec->frame_nr++;
1149
 
  GST_BUFFER_OFFSET_END (out) = dec->frame_nr;
1150
 
  GST_BUFFER_DURATION (out) =
1151
 
      gst_util_uint64_scale_int (GST_SECOND, dec->info.fps_denominator,
1152
 
      dec->info.fps_numerator);
1153
 
  GST_BUFFER_TIMESTAMP (out) = outtime;
1154
 
 
1155
 
  return theora_dec_push (dec, out);
1156
 
 
1157
 
no_buffer:
1158
 
  {
1159
 
    GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
1160
 
        gst_flow_get_name (result));
1161
 
    return result;
1162
 
  }
1163
 
}
1164
 
 
1165
 
static GstFlowReturn
1166
 
theora_handle_data_packet (GstTheoraExpDec * dec, ogg_packet * packet,
1167
 
    GstClockTime outtime)
1168
 
{
1169
 
  /* normal data packet */
1170
 
  th_ycbcr_buffer yuv;
1171
 
  GstFlowReturn result;
1172
 
  ogg_int64_t gp;
1173
 
 
1174
 
  if (G_UNLIKELY (!dec->have_header))
1175
 
    goto not_initialized;
1176
 
 
1177
 
  if (th_packet_iskeyframe (packet)) {
1178
 
    dec->need_keyframe = FALSE;
1179
 
  } else if (G_UNLIKELY (dec->need_keyframe)) {
1180
 
    goto dropping;
1181
 
  }
1182
 
 
1183
 
  /* this does the decoding */
1184
 
  if (G_UNLIKELY (th_decode_packetin (dec->dec, packet, &gp)))
1185
 
    goto decode_error;
1186
 
 
1187
 
  if (outtime != -1) {
1188
 
    gboolean need_skip;
1189
 
    GstClockTime qostime;
1190
 
 
1191
 
    /* QoS is done on running time */
1192
 
    qostime = gst_segment_to_running_time (&dec->segment, GST_FORMAT_TIME,
1193
 
        outtime);
1194
 
 
1195
 
    GST_OBJECT_LOCK (dec);
1196
 
    /* check for QoS, don't perform the last steps of getting and
1197
 
     * pushing the buffers that are known to be late. */
1198
 
    /* FIXME, we can also entirely skip decoding if the next valid buffer is 
1199
 
     * known to be after a keyframe (using the granule_shift) */
1200
 
    need_skip = dec->earliest_time != -1 && qostime <= dec->earliest_time;
1201
 
    GST_OBJECT_UNLOCK (dec);
1202
 
 
1203
 
    if (need_skip)
1204
 
      goto dropping_qos;
1205
 
  }
1206
 
 
1207
 
  /* this does postprocessing and set up the decoded frame
1208
 
   * pointers in our yuv variable */
1209
 
  if (G_UNLIKELY (th_decode_ycbcr_out (dec->dec, yuv) < 0))
1210
 
    goto no_yuv;
1211
 
 
1212
 
  if (G_UNLIKELY ((yuv[0].width != dec->info.frame_width) ||
1213
 
          (yuv[0].height != dec->info.frame_height)))
1214
 
    goto wrong_dimensions;
1215
 
 
1216
 
  if (dec->info.pixel_fmt == TH_PF_420) {
1217
 
    result = theora_handle_420_image (dec, yuv, outtime);
1218
 
  } else if (dec->info.pixel_fmt == TH_PF_422) {
1219
 
    result = theora_handle_422_image (dec, yuv, outtime);
1220
 
  } else if (dec->info.pixel_fmt == TH_PF_444) {
1221
 
    result = theora_handle_444_image (dec, yuv, outtime);
1222
 
  } else {
1223
 
    g_assert_not_reached ();
1224
 
  }
1225
 
 
1226
 
  return result;
1227
 
 
1228
 
  /* ERRORS */
1229
 
not_initialized:
1230
 
  {
1231
 
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
1232
 
        (NULL), ("no header sent yet"));
1233
 
    return GST_FLOW_ERROR;
1234
 
  }
1235
 
dropping:
1236
 
  {
1237
 
    GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe");
1238
 
    dec->discont = TRUE;
1239
 
    return GST_FLOW_OK;
1240
 
  }
1241
 
dropping_qos:
1242
 
  {
1243
 
    if (dec->frame_nr != -1)
1244
 
      dec->frame_nr++;
1245
 
    dec->discont = TRUE;
1246
 
    GST_WARNING_OBJECT (dec, "dropping frame because of QoS");
1247
 
    return GST_FLOW_OK;
1248
 
  }
1249
 
decode_error:
1250
 
  {
1251
 
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
1252
 
        (NULL), ("theora decoder did not decode data packet"));
1253
 
    return GST_FLOW_ERROR;
1254
 
  }
1255
 
no_yuv:
1256
 
  {
1257
 
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
1258
 
        (NULL), ("couldn't read out YUV image"));
1259
 
    return GST_FLOW_ERROR;
1260
 
  }
1261
 
wrong_dimensions:
1262
 
  {
1263
 
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, FORMAT,
1264
 
        (NULL), ("dimensions of image do not match header"));
1265
 
    return GST_FLOW_ERROR;
1266
 
  }
1267
 
}
1268
 
 
1269
 
static GstFlowReturn
1270
 
theora_dec_chain (GstPad * pad, GstBuffer * buf)
1271
 
{
1272
 
  GstTheoraExpDec *dec;
1273
 
  ogg_packet packet;
1274
 
  GstFlowReturn result = GST_FLOW_OK;
1275
 
  gboolean isheader;
1276
 
 
1277
 
  dec = GST_THEORA_DEC_EXP (gst_pad_get_parent (pad));
1278
 
 
1279
 
  /* resync on DISCONT */
1280
 
  if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))) {
1281
 
    GST_DEBUG_OBJECT (dec, "Received DISCONT buffer");
1282
 
    dec->need_keyframe = TRUE;
1283
 
    dec->last_timestamp = -1;
1284
 
    dec->granulepos = -1;
1285
 
    dec->discont = TRUE;
1286
 
  }
1287
 
 
1288
 
  GST_DEBUG ("Offset end is %d, k-g-s %d", (int) (GST_BUFFER_OFFSET_END (buf)),
1289
 
      dec->info.keyframe_granule_shift);
1290
 
  /* make ogg_packet out of the buffer */
1291
 
  packet.packet = GST_BUFFER_DATA (buf);
1292
 
  packet.bytes = GST_BUFFER_SIZE (buf);
1293
 
  packet.granulepos = GST_BUFFER_OFFSET_END (buf);
1294
 
  packet.packetno = 0;          /* we don't really care */
1295
 
  packet.b_o_s = dec->have_header ? 0 : 1;
1296
 
  /* EOS does not matter for the decoder */
1297
 
  packet.e_o_s = 0;
1298
 
 
1299
 
  if (dec->have_header) {
1300
 
    if (packet.granulepos != -1) {
1301
 
      GST_DEBUG_OBJECT (dec, "Granulepos from packet: %lld", packet.granulepos);
1302
 
      dec->granulepos = packet.granulepos;
1303
 
      dec->last_timestamp =
1304
 
          gst_theoradec_granule_clocktime (dec, packet.granulepos);
1305
 
    } else if (dec->last_timestamp != -1) {
1306
 
      GST_DEBUG_OBJECT (dec, "Granulepos inferred?: %lld", dec->granulepos);
1307
 
      dec->last_timestamp =
1308
 
          gst_theoradec_granule_clocktime (dec, dec->granulepos);
1309
 
    } else {
1310
 
      GST_DEBUG_OBJECT (dec, "Granulepos unknown");
1311
 
      dec->last_timestamp = GST_CLOCK_TIME_NONE;
1312
 
    }
1313
 
    if (dec->last_timestamp == GST_CLOCK_TIME_NONE &&
1314
 
        GST_BUFFER_TIMESTAMP_IS_VALID (buf))
1315
 
      dec->last_timestamp = GST_BUFFER_TIMESTAMP (buf);
1316
 
 
1317
 
  } else {
1318
 
    GST_DEBUG_OBJECT (dec, "Granulepos not usable: no headers seen");
1319
 
    dec->last_timestamp = -1;
1320
 
  }
1321
 
 
1322
 
  /* A zero-byte packet is a valid data packet, meaning 'duplicate frame' */
1323
 
  if (packet.bytes > 0 && packet.packet[0] & 0x80)
1324
 
    isheader = TRUE;
1325
 
  else
1326
 
    isheader = FALSE;
1327
 
 
1328
 
  GST_DEBUG_OBJECT (dec, "header=%d packetno=%lld, outtime=%" GST_TIME_FORMAT,
1329
 
      packet.bytes ? packet.packet[0] : -1, packet.packetno,
1330
 
      GST_TIME_ARGS (dec->last_timestamp));
1331
 
 
1332
 
  /* switch depending on packet type */
1333
 
  if (isheader) {
1334
 
    if (dec->have_header) {
1335
 
      GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
1336
 
      goto done;
1337
 
    }
1338
 
    result = theora_handle_header_packet (dec, &packet);
1339
 
  } else {
1340
 
    result = theora_handle_data_packet (dec, &packet, dec->last_timestamp);
1341
 
  }
1342
 
 
1343
 
done:
1344
 
  /* interpolate granule pos */
1345
 
  dec->granulepos = inc_granulepos (dec, dec->granulepos);
1346
 
 
1347
 
  gst_object_unref (dec);
1348
 
 
1349
 
  gst_buffer_unref (buf);
1350
 
 
1351
 
  return result;
1352
 
}
1353
 
 
1354
 
static GstStateChangeReturn
1355
 
theora_dec_change_state (GstElement * element, GstStateChange transition)
1356
 
{
1357
 
  GstTheoraExpDec *dec = GST_THEORA_DEC_EXP (element);
1358
 
  GstStateChangeReturn ret;
1359
 
 
1360
 
 
1361
 
  switch (transition) {
1362
 
    case GST_STATE_CHANGE_NULL_TO_READY:
1363
 
      break;
1364
 
    case GST_STATE_CHANGE_READY_TO_PAUSED:
1365
 
      th_info_init (&dec->info);
1366
 
      th_comment_init (&dec->comment);
1367
 
      dec->have_header = FALSE;
1368
 
      gst_theoradec_reset (dec);
1369
 
      break;
1370
 
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1371
 
      break;
1372
 
    default:
1373
 
      break;
1374
 
  }
1375
 
 
1376
 
  ret = parent_class->change_state (element, transition);
1377
 
 
1378
 
  switch (transition) {
1379
 
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1380
 
      break;
1381
 
    case GST_STATE_CHANGE_PAUSED_TO_READY:
1382
 
      th_decode_free (dec->dec);
1383
 
      dec->dec = NULL;
1384
 
 
1385
 
      th_comment_clear (&dec->comment);
1386
 
      th_info_clear (&dec->info);
1387
 
      gst_theoradec_reset (dec);
1388
 
      break;
1389
 
    case GST_STATE_CHANGE_READY_TO_NULL:
1390
 
      break;
1391
 
    default:
1392
 
      break;
1393
 
  }
1394
 
 
1395
 
  return ret;
1396
 
}
1397
 
 
1398
 
static gboolean
1399
 
plugin_init (GstPlugin * plugin)
1400
 
{
1401
 
  if (!gst_element_register (plugin, "theoradecexp", GST_RANK_PRIMARY,
1402
 
          gst_theoradec_get_type ()))
1403
 
    return FALSE;
1404
 
 
1405
 
  return TRUE;
1406
 
}
1407
 
 
1408
 
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1409
 
    GST_VERSION_MINOR,
1410
 
    "theoradec",
1411
 
    "Theora dec (exp) plugin library",
1412
 
    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)