1 /* GStreamer
2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 *
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.
8 *
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.
13 *
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.
18 */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include <string.h>
25 #include <inttypes.h>
27 #include "gstmpeg2dec.h"
29 /* mpeg2dec changed a struct name after 0.3.1, here's a workaround */
30 /* mpeg2dec also only defined MPEG2_RELEASE after 0.3.1
31 #if MPEG2_RELEASE < MPEG2_VERSION(0,3,2)
32 */
33 #ifndef MPEG2_RELEASE
34 #define MPEG2_VERSION(a,b,c) ((((a)&0xff)<<16)|(((b)&0xff)<<8)|((c)&0xff))
35 #define MPEG2_RELEASE MPEG2_VERSION(0,3,1)
36 typedef picture_t mpeg2_picture_t;
37 typedef gint mpeg2_state_t;
39 #define STATE_BUFFER 0
40 #endif
42 GST_DEBUG_CATEGORY_STATIC (mpeg2dec_debug);
43 #define GST_CAT_DEFAULT (mpeg2dec_debug)
45 /* table with framerates expressed as fractions */
46 static gdouble fpss[] = { 24.0 / 1.001, 24.0, 25.0,
47 30.0 / 1.001, 30.0, 50.0,
48 60.0 / 1.001, 60.0, 0
49 };
51 /* frame periods */
52 static guint frame_periods[] = {
53 1126125, 1125000, 1080000, 900900, 900000, 540000, 450450, 450000, 0
54 };
56 /* elementfactory information */
57 static GstElementDetails gst_mpeg2dec_details = {
58 "mpeg1 and mpeg2 video decoder",
59 "Codec/Decoder/Video",
60 "Uses libmpeg2 to decode MPEG video streams",
61 "Wim Taymans <wim.taymans@chello.be>",
62 };
64 /* Mpeg2dec signals and args */
65 enum
66 {
67 /* FILL ME */
68 LAST_SIGNAL
69 };
71 enum
72 {
73 ARG_0
74 /* FILL ME */
75 };
77 /*
78 * We can't use fractions in static pad templates, so
79 * we do something manual...
80 */
81 static GstPadTemplate *
82 src_templ (void)
83 {
84 static GstPadTemplate *templ = NULL;
86 if (!templ) {
87 GstCaps *caps;
88 GstStructure *structure;
89 GValue list = { 0 }
90 , fps = {
91 0}
92 , fmt = {
93 0};
94 char *fmts[] = { "YV12", "I420", "Y42B", NULL };
95 guint n;
97 caps = gst_caps_new_simple ("video/x-raw-yuv",
98 "format", GST_TYPE_FOURCC,
99 GST_MAKE_FOURCC ('I', '4', '2', '0'),
100 "width", GST_TYPE_INT_RANGE, 16, 4096,
101 "height", GST_TYPE_INT_RANGE, 16, 4096, NULL);
103 structure = gst_caps_get_structure (caps, 0);
105 g_value_init (&list, GST_TYPE_LIST);
106 g_value_init (&fps, G_TYPE_DOUBLE);
107 for (n = 0; fpss[n] != 0; n++) {
108 g_value_set_double (&fps, fpss[n]);
109 gst_value_list_append_value (&list, &fps);
110 }
111 gst_structure_set_value (structure, "framerate", &list);
112 g_value_unset (&list);
113 g_value_unset (&fps);
115 g_value_init (&list, GST_TYPE_LIST);
116 g_value_init (&fmt, GST_TYPE_FOURCC);
117 for (n = 0; fmts[n] != NULL; n++) {
118 gst_value_set_fourcc (&fmt, GST_STR_FOURCC (fmts[n]));
119 gst_value_list_append_value (&list, &fmt);
120 }
121 gst_structure_set_value (structure, "format", &list);
122 g_value_unset (&list);
123 g_value_unset (&fmt);
125 templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
126 }
127 return templ;
128 }
130 #ifdef enable_user_data
131 static GstStaticPadTemplate user_data_template_factory =
132 GST_STATIC_PAD_TEMPLATE ("user_data",
133 GST_PAD_SRC,
134 GST_PAD_ALWAYS,
135 GST_STATIC_CAPS_ANY);
136 #endif
138 static GstStaticPadTemplate sink_template_factory =
139 GST_STATIC_PAD_TEMPLATE ("sink",
140 GST_PAD_SINK,
141 GST_PAD_ALWAYS,
142 GST_STATIC_CAPS ("video/mpeg, "
143 "mpegversion = (int) [ 1, 2 ], " "systemstream = (boolean) false")
144 );
146 static void gst_mpeg2dec_base_init (gpointer g_class);
147 static void gst_mpeg2dec_class_init (GstMpeg2decClass * klass);
148 static void gst_mpeg2dec_init (GstMpeg2dec * mpeg2dec);
150 static void gst_mpeg2dec_dispose (GObject * object);
151 static void gst_mpeg2dec_reset (GstMpeg2dec * mpeg2dec);
153 static void gst_mpeg2dec_set_property (GObject * object, guint prop_id,
154 const GValue * value, GParamSpec * pspec);
155 static void gst_mpeg2dec_get_property (GObject * object, guint prop_id,
156 GValue * value, GParamSpec * pspec);
157 static void gst_mpeg2dec_set_index (GstElement * element, GstIndex * index);
158 static GstIndex *gst_mpeg2dec_get_index (GstElement * element);
160 static gboolean gst_mpeg2dec_src_event (GstPad * pad, GstEvent * event);
161 static const GstQueryType *gst_mpeg2dec_get_src_query_types (GstPad * pad);
163 static gboolean gst_mpeg2dec_src_query (GstPad * pad, GstQuery * query);
165 static gboolean gst_mpeg2dec_sink_convert (GstPad * pad, GstFormat src_format,
166 gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
167 static gboolean gst_mpeg2dec_src_convert (GstPad * pad, GstFormat src_format,
168 gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
170 static GstStateChangeReturn gst_mpeg2dec_change_state (GstElement * element,
171 GstStateChange transition);
173 static gboolean gst_mpeg2dec_sink_event (GstPad * pad, GstEvent * event);
174 static GstFlowReturn gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf);
176 //static gboolean gst_mpeg2dec_sink_query (GstPad * pad, GstQuery * query);
177 static GstCaps *gst_mpeg2dec_src_getcaps (GstPad * pad);
179 #if 0
180 static const GstFormat *gst_mpeg2dec_get_formats (GstPad * pad);
181 #endif
183 #if 0
184 static const GstEventMask *gst_mpeg2dec_get_event_masks (GstPad * pad);
185 #endif
187 static GstElementClass *parent_class = NULL;
189 static GstBuffer *crop_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * input);
191 /*static guint gst_mpeg2dec_signals[LAST_SIGNAL] = { 0 };*/
193 GType
194 gst_mpeg2dec_get_type (void)
195 {
196 static GType mpeg2dec_type = 0;
198 if (!mpeg2dec_type) {
199 static const GTypeInfo mpeg2dec_info = {
200 sizeof (GstMpeg2decClass),
201 gst_mpeg2dec_base_init,
202 NULL,
203 (GClassInitFunc) gst_mpeg2dec_class_init,
204 NULL,
205 NULL,
206 sizeof (GstMpeg2dec),
207 0,
208 (GInstanceInitFunc) gst_mpeg2dec_init,
209 };
211 mpeg2dec_type =
212 g_type_register_static (GST_TYPE_ELEMENT, "GstMpeg2dec", &mpeg2dec_info,
213 0);
214 }
216 GST_DEBUG_CATEGORY_INIT (mpeg2dec_debug, "mpeg2dec", 0,
217 "MPEG2 decoder element");
219 return mpeg2dec_type;
220 }
222 static void
223 gst_mpeg2dec_base_init (gpointer g_class)
224 {
225 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
227 gst_element_class_add_pad_template (element_class, src_templ ());
228 gst_element_class_add_pad_template (element_class,
229 gst_static_pad_template_get (&sink_template_factory));
230 #ifdef enable_user_data
231 gst_element_class_add_pad_template (element_class,
232 gst_static_pad_template_get (&user_data_template_factory));
233 #endif
234 gst_element_class_set_details (element_class, &gst_mpeg2dec_details);
235 }
237 static void
238 gst_mpeg2dec_class_init (GstMpeg2decClass * klass)
239 {
240 GObjectClass *gobject_class;
241 GstElementClass *gstelement_class;
243 gobject_class = (GObjectClass *) klass;
244 gstelement_class = (GstElementClass *) klass;
246 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
248 gobject_class->set_property = gst_mpeg2dec_set_property;
249 gobject_class->get_property = gst_mpeg2dec_get_property;
250 gobject_class->dispose = gst_mpeg2dec_dispose;
252 gstelement_class->change_state = gst_mpeg2dec_change_state;
253 gstelement_class->set_index = gst_mpeg2dec_set_index;
254 gstelement_class->get_index = gst_mpeg2dec_get_index;
255 }
257 static void
258 gst_mpeg2dec_init (GstMpeg2dec * mpeg2dec)
259 {
260 /* create the sink and src pads */
261 mpeg2dec->sinkpad =
262 gst_pad_new_from_template (gst_static_pad_template_get
263 (&sink_template_factory), "sink");
264 gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->sinkpad);
265 gst_pad_set_chain_function (mpeg2dec->sinkpad,
266 GST_DEBUG_FUNCPTR (gst_mpeg2dec_chain));
267 //gst_pad_set_query_function (mpeg2dec->sinkpad,
268 // GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_sink_query));
269 gst_pad_set_event_function (mpeg2dec->sinkpad,
270 GST_DEBUG_FUNCPTR (gst_mpeg2dec_sink_event));
272 mpeg2dec->srcpad = gst_pad_new_from_template (src_templ (), "src");
273 gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->srcpad);
274 gst_pad_set_getcaps_function (mpeg2dec->srcpad,
275 GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_getcaps));
276 gst_pad_set_event_function (mpeg2dec->srcpad,
277 GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_event));
278 gst_pad_set_query_type_function (mpeg2dec->srcpad,
279 GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_src_query_types));
280 gst_pad_set_query_function (mpeg2dec->srcpad,
281 GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_query));
283 #ifdef enable_user_data
284 mpeg2dec->userdatapad =
285 gst_pad_new_from_template (gst_static_pad_template_get
286 (&user_data_template_factory), "user_data");
287 gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->userdatapad);
288 #endif
290 /* initialize the mpeg2dec acceleration */
291 }
293 static void
294 gst_mpeg2dec_dispose (GObject * object)
295 {
296 GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (object);
298 if (mpeg2dec->decoder) {
299 GST_DEBUG_OBJECT (mpeg2dec, "closing decoder");
300 mpeg2_close (mpeg2dec->decoder);
301 mpeg2dec->decoder = NULL;
302 }
304 G_OBJECT_CLASS (parent_class)->dispose (object);
305 }
307 static void
308 gst_mpeg2dec_reset (GstMpeg2dec * mpeg2dec)
309 {
310 /* reset the initial video state */
311 mpeg2dec->format = MPEG2DEC_FORMAT_NONE;
312 mpeg2dec->width = -1;
313 mpeg2dec->height = -1;
314 mpeg2dec->segment_start = 0;
315 mpeg2dec->segment_end = -1;
316 mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
317 mpeg2dec->frame_period = 0;
318 mpeg2dec->need_sequence = TRUE;
319 mpeg2dec->next_time = 0;
320 mpeg2dec->offset = 0;
321 mpeg2_reset (mpeg2dec->decoder, 1);
322 }
324 static void
325 gst_mpeg2dec_set_index (GstElement * element, GstIndex * index)
326 {
327 GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (element);
329 mpeg2dec->index = index;
331 gst_index_get_writer_id (index, GST_OBJECT (element), &mpeg2dec->index_id);
332 }
334 static GstIndex *
335 gst_mpeg2dec_get_index (GstElement * element)
336 {
337 GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (element);
339 return mpeg2dec->index;
340 }
342 static GstBuffer *
343 crop_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * input)
344 {
345 unsigned char *in_data;
346 unsigned char *out_data;
347 unsigned int h_subsample;
348 unsigned int v_subsample;
349 unsigned int line;
350 GstBuffer *outbuf = input;
352 /*We crop only if the target region is smaller than the input one */
353 if ((mpeg2dec->decoded_width > mpeg2dec->width) ||
354 (mpeg2dec->decoded_height > mpeg2dec->height)) {
355 /* If we don't know about the format, we just return the original
356 * buffer.
357 */
358 if (mpeg2dec->format == MPEG2DEC_FORMAT_I422 ||
359 mpeg2dec->format == MPEG2DEC_FORMAT_I420 ||
360 mpeg2dec->format == MPEG2DEC_FORMAT_YV12) {
361 /*FIXME: I have tried to use gst_buffer_copy_on_write, but it
362 * still have some artifact, so I'me allocating new buffer
363 * for each frame decoded...
364 */
365 if (mpeg2dec->format == MPEG2DEC_FORMAT_I422) {
366 outbuf =
367 gst_buffer_new_and_alloc (mpeg2dec->width * mpeg2dec->height * 2);
368 h_subsample = 2;
369 v_subsample = 1;
370 } else {
371 outbuf =
372 gst_buffer_new_and_alloc (mpeg2dec->width * mpeg2dec->height * 1.5);
373 h_subsample = 2;
374 v_subsample = 2;
375 }
377 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (input);
378 GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (input);
379 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (input);
381 /* Copy Y first */
382 in_data = GST_BUFFER_DATA (input);
383 out_data = GST_BUFFER_DATA (outbuf);
384 for (line = 0; line < mpeg2dec->height; line++) {
385 memcpy (out_data, in_data, mpeg2dec->width);
386 out_data += mpeg2dec->width;
387 in_data += mpeg2dec->decoded_width;
388 }
390 /* Now copy U & V */
391 in_data =
392 GST_BUFFER_DATA (input) +
393 mpeg2dec->decoded_width * mpeg2dec->decoded_height;
394 for (line = 0; line < mpeg2dec->height / v_subsample; line++) {
395 memcpy (out_data, in_data, mpeg2dec->width / h_subsample);
396 memcpy (out_data +
397 mpeg2dec->width * mpeg2dec->height / (v_subsample * h_subsample),
398 in_data +
399 mpeg2dec->decoded_width * mpeg2dec->decoded_height / (v_subsample *
400 h_subsample), mpeg2dec->width / h_subsample);
401 out_data += mpeg2dec->width / h_subsample;
402 in_data += mpeg2dec->decoded_width / h_subsample;
403 }
405 gst_buffer_unref (input);
406 }
407 }
409 return outbuf;
410 }
412 static GstFlowReturn
413 gst_mpeg2dec_alloc_buffer (GstMpeg2dec * mpeg2dec, gint64 offset,
414 GstBuffer ** obuf)
415 {
416 GstBuffer *outbuf = NULL;
417 gint size = mpeg2dec->decoded_width * mpeg2dec->decoded_height;
418 guint8 *buf[3], *out = NULL;
419 GstFlowReturn ret = GST_FLOW_OK;
421 if (mpeg2dec->format == MPEG2DEC_FORMAT_I422) {
422 ret =
423 gst_pad_alloc_buffer (mpeg2dec->srcpad, GST_BUFFER_OFFSET_NONE,
424 size * 2, GST_PAD_CAPS (mpeg2dec->srcpad), &outbuf);
425 if (ret != GST_FLOW_OK)
426 goto no_buffer;
428 out = GST_BUFFER_DATA (outbuf);
430 buf[0] = out;
431 buf[1] = buf[0] + size;
432 buf[2] = buf[1] + size / 2;
434 } else {
435 ret =
436 gst_pad_alloc_buffer (mpeg2dec->srcpad, GST_BUFFER_OFFSET_NONE,
437 (size * 3) / 2, GST_PAD_CAPS (mpeg2dec->srcpad), &outbuf);
438 if (ret != GST_FLOW_OK)
439 goto no_buffer;
441 out = GST_BUFFER_DATA (outbuf);
443 buf[0] = out;
444 if (mpeg2dec->format == MPEG2DEC_FORMAT_I420) {
445 buf[0] = out;
446 buf[1] = buf[0] + size;
447 buf[2] = buf[1] + size / 4;
448 } else {
449 buf[0] = out;
450 buf[2] = buf[0] + size;
451 buf[1] = buf[2] + size / 4;
452 }
453 }
455 mpeg2_set_buf (mpeg2dec->decoder, buf, outbuf);
457 /* we store the original byteoffset of this picture in the stream here
458 * because we need it for indexing */
459 GST_BUFFER_OFFSET (outbuf) = offset;
461 done:
462 if (ret != GST_FLOW_OK) {
463 outbuf = NULL; /* just to asure NULL return, looking the path
464 above it happens only when gst_pad_alloc_buffer
465 fails to alloc outbf */
466 }
467 *obuf = outbuf;
469 return ret;
471 /* ERRORS */
472 no_buffer:
473 {
474 if (GST_FLOW_IS_FATAL (ret)) {
475 GST_ELEMENT_ERROR (mpeg2dec, RESOURCE, FAILED, (NULL),
476 ("Failed to allocate memory for buffer, reason %s",
477 gst_flow_get_name (ret)));
478 }
479 goto done;
480 }
481 }
483 static gboolean
484 gst_mpeg2dec_negotiate_format (GstMpeg2dec * mpeg2dec)
485 {
486 GstCaps *caps;
487 guint32 fourcc;
488 const mpeg2_info_t *info;
489 const mpeg2_sequence_t *sequence;
491 info = mpeg2_info (mpeg2dec->decoder);
492 sequence = info->sequence;
494 if (sequence->width != sequence->chroma_width &&
495 sequence->height != sequence->chroma_height) {
496 fourcc = GST_STR_FOURCC ("I420");
497 mpeg2dec->format = MPEG2DEC_FORMAT_I420;
498 } else if (sequence->width == sequence->chroma_width ||
499 sequence->height == sequence->chroma_height) {
500 fourcc = GST_STR_FOURCC ("Y42B");
501 mpeg2dec->format = MPEG2DEC_FORMAT_I422;
502 } else {
503 g_warning ("mpeg2dec: 4:4:4 format not yet supported");
504 return (FALSE);
505 }
507 caps = gst_caps_new_simple ("video/x-raw-yuv",
508 "format", GST_TYPE_FOURCC, fourcc,
509 "width", G_TYPE_INT, mpeg2dec->width,
510 "height", G_TYPE_INT, mpeg2dec->height,
511 "pixel-aspect-ratio", GST_TYPE_FRACTION, mpeg2dec->pixel_width,
512 mpeg2dec->pixel_height,
513 "framerate", G_TYPE_DOUBLE, mpeg2dec->frame_rate, NULL);
515 gst_pad_set_caps (mpeg2dec->srcpad, caps);
516 gst_caps_unref (caps);
518 return TRUE;
519 }
521 static GstFlowReturn
522 handle_sequence (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
523 {
524 gint i;
525 GstBuffer *buf;
526 GstFlowReturn ret;
528 mpeg2dec->width = info->sequence->picture_width;
529 mpeg2dec->height = info->sequence->picture_height;
530 mpeg2dec->pixel_width = info->sequence->pixel_width;
531 mpeg2dec->pixel_height = info->sequence->pixel_height;
532 mpeg2dec->decoded_width = info->sequence->width;
533 mpeg2dec->decoded_height = info->sequence->height;
534 mpeg2dec->total_frames = 0;
536 /* find framerate */
537 for (i = 0; i < 9; i++) {
538 if (info->sequence->frame_period == frame_periods[i]) {
539 mpeg2dec->frame_rate = fpss[i];
540 }
541 }
542 mpeg2dec->frame_period = info->sequence->frame_period * GST_USECOND / 27;
544 GST_DEBUG_OBJECT (mpeg2dec,
545 "sequence flags: %d, frame period: %d (%g), frame rate: %g",
546 info->sequence->flags, info->sequence->frame_period,
547 (double) (mpeg2dec->frame_period) / GST_SECOND, mpeg2dec->frame_rate);
548 GST_DEBUG_OBJECT (mpeg2dec, "profile: %02x, colour_primaries: %d",
549 info->sequence->profile_level_id, info->sequence->colour_primaries);
550 GST_DEBUG_OBJECT (mpeg2dec, "transfer chars: %d, matrix coef: %d",
551 info->sequence->transfer_characteristics,
552 info->sequence->matrix_coefficients);
554 if (!gst_mpeg2dec_negotiate_format (mpeg2dec))
555 goto negotiate_failed;
557 mpeg2_custom_fbuf (mpeg2dec->decoder, 1);
559 ret = gst_mpeg2dec_alloc_buffer (mpeg2dec, mpeg2dec->offset, &buf);
560 if (ret != GST_FLOW_OK)
561 goto done;
563 /* libmpeg2 discards first buffer twice for some reason. */
564 gst_buffer_ref (buf);
566 mpeg2dec->need_sequence = FALSE;
568 done:
569 return ret;
571 negotiate_failed:
572 {
573 GST_ELEMENT_ERROR (mpeg2dec, CORE, NEGOTIATION, (NULL), (NULL));
574 ret = GST_FLOW_NOT_NEGOTIATED;
575 goto done;
576 }
577 }
579 static GstFlowReturn
580 handle_picture (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
581 {
582 gboolean key_frame = FALSE;
583 GstBuffer *outbuf;
584 GstFlowReturn ret;
586 GST_DEBUG_OBJECT (mpeg2dec, "handle picture");
588 if (info->current_picture) {
589 key_frame =
590 (info->current_picture->flags & PIC_MASK_CODING_TYPE) ==
591 PIC_FLAG_CODING_TYPE_I;
592 }
593 ret = gst_mpeg2dec_alloc_buffer (mpeg2dec, mpeg2dec->offset, &outbuf);
594 if (ret != GST_FLOW_OK)
595 goto done;
597 GST_DEBUG_OBJECT (mpeg2dec, "picture %s, outbuf %p, offset %"
598 G_GINT64_FORMAT,
599 key_frame ? ", kf," : " ", outbuf, GST_BUFFER_OFFSET (outbuf)
600 );
602 if (mpeg2dec->discont_state == MPEG2DEC_DISC_NEW_PICTURE && key_frame)
603 mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_KEYFRAME;
605 mpeg2_skip (mpeg2dec->decoder, 0);
607 done:
608 return ret;
609 }
611 static GstFlowReturn
612 handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
613 {
614 GstBuffer *outbuf = NULL;
615 GstFlowReturn ret = GST_FLOW_OK;
617 GST_DEBUG_OBJECT (mpeg2dec, "picture slice/end %p %p %p %p",
618 info->display_fbuf,
619 info->display_picture, info->current_picture,
620 (info->display_fbuf ? info->display_fbuf->id : NULL));
622 if (info->display_fbuf && info->display_fbuf->id) {
623 const mpeg2_picture_t *picture;
624 gboolean key_frame = FALSE;
625 GstClockTime time;
627 outbuf = GST_BUFFER (info->display_fbuf->id);
629 picture = info->display_picture;
631 key_frame =
632 (picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I;
634 GST_DEBUG_OBJECT (mpeg2dec, "picture keyframe %d", key_frame);
636 if (!key_frame)
637 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
638 else
639 GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
641 if (mpeg2dec->discont_state == MPEG2DEC_DISC_NEW_KEYFRAME && key_frame)
642 mpeg2dec->discont_state = MPEG2DEC_DISC_NONE;
644 time = GST_CLOCK_TIME_NONE;
646 #if MPEG2_RELEASE < MPEG2_VERSION(0,4,0)
647 if (picture->flags & PIC_FLAG_PTS)
648 time = MPEG_TIME_TO_GST_TIME (picture->pts);
649 #else
650 if (picture->flags & PIC_FLAG_TAGS)
651 time = MPEG_TIME_TO_GST_TIME ((GstClockTime) (picture->
652 tag2) << 32 | picture->tag);
653 #endif
655 if (time == GST_CLOCK_TIME_NONE) {
656 time = mpeg2dec->next_time;
657 GST_DEBUG_OBJECT (mpeg2dec, "picture didn't have pts");
658 } else {
659 GST_DEBUG_OBJECT (mpeg2dec,
660 "picture had pts %" GST_TIME_FORMAT ", we had %"
661 GST_TIME_FORMAT, GST_TIME_ARGS (time),
662 GST_TIME_ARGS (mpeg2dec->next_time));
663 mpeg2dec->next_time = time;
664 }
665 GST_BUFFER_TIMESTAMP (outbuf) = time;
667 /* TODO set correct offset here based on frame number */
668 if (info->display_picture_2nd) {
669 GST_BUFFER_DURATION (outbuf) = (picture->nb_fields +
670 info->display_picture_2nd->nb_fields) * mpeg2dec->frame_period / 2;
671 } else {
672 GST_BUFFER_DURATION (outbuf) =
673 picture->nb_fields * mpeg2dec->frame_period / 2;
674 }
675 mpeg2dec->next_time += GST_BUFFER_DURATION (outbuf);
677 GST_DEBUG_OBJECT (mpeg2dec,
678 "picture: %s %s fields:%d off:%" G_GINT64_FORMAT " ts:%"
679 GST_TIME_FORMAT,
680 (picture->flags & PIC_FLAG_TOP_FIELD_FIRST ? "tff " : " "),
681 (picture->flags & PIC_FLAG_PROGRESSIVE_FRAME ? "prog" : " "),
682 picture->nb_fields, GST_BUFFER_OFFSET (outbuf),
683 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
685 if (mpeg2dec->index) {
686 gst_index_add_association (mpeg2dec->index, mpeg2dec->index_id,
687 (key_frame ? GST_ASSOCIATION_FLAG_KEY_UNIT : 0),
688 GST_FORMAT_BYTES, GST_BUFFER_OFFSET (outbuf),
689 GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (outbuf), 0);
690 }
692 if (picture->flags & PIC_FLAG_SKIP) {
693 GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer because of skip flag");
694 } else if (mpeg2dec->discont_state != MPEG2DEC_DISC_NONE) {
695 GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer, discont state %d",
696 mpeg2dec->discont_state);
697 } else if (mpeg2dec->next_time < mpeg2dec->segment_start) {
698 GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer, next_time %"
699 GST_TIME_FORMAT " < segment_start %" GST_TIME_FORMAT,
700 GST_TIME_ARGS (mpeg2dec->next_time),
701 GST_TIME_ARGS (mpeg2dec->segment_start));
702 } else {
703 GST_LOG_OBJECT (mpeg2dec, "pushing buffer, timestamp %"
704 GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
705 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
706 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
708 if ((mpeg2dec->decoded_height > mpeg2dec->height) ||
709 (mpeg2dec->decoded_width > mpeg2dec->width)) {
710 /* CHECKME: this might unref outbuf and return a new buffer.
711 * Does this affect the info->discard_fbuf stuff below? */
712 outbuf = crop_buffer (mpeg2dec, outbuf);
713 }
715 gst_buffer_ref (outbuf);
716 ret = gst_pad_push (mpeg2dec->srcpad, outbuf);
717 }
718 }
720 if (info->discard_fbuf && info->discard_fbuf->id) {
721 GstBuffer *discard = GST_BUFFER (info->discard_fbuf->id);
723 gst_buffer_unref (discard);
724 GST_DEBUG_OBJECT (mpeg2dec, "Discarded buffer %p", discard);
725 }
726 return ret;
727 }
729 #if 0
730 static void
731 update_streaminfo (GstMpeg2dec * mpeg2dec)
732 {
733 GstCaps *caps;
734 GstProps *props;
735 GstPropsEntry *entry;
736 const mpeg2_info_t *info;
738 info = mpeg2_info (mpeg2dec->decoder);
740 props = gst_props_empty_new ();
742 entry =
743 gst_props_entry_new ("framerate",
744 G_TYPE_DOUBLE (GST_SECOND / (float) mpeg2dec->frame_period));
745 gst_props_add_entry (props, entry);
746 entry =
747 gst_props_entry_new ("bitrate",
748 G_TYPE_INT (info->sequence->byte_rate * 8));
749 gst_props_add_entry (props, entry);
751 caps = gst_caps_new ("mpeg2dec_streaminfo",
752 "application/x-gst-streaminfo", props);
754 gst_caps_replace_sink (&mpeg2dec->streaminfo, caps);
755 g_object_notify (G_OBJECT (mpeg2dec), "streaminfo");
756 }
757 #endif
759 static GstFlowReturn
760 gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf)
761 {
762 GstMpeg2dec *mpeg2dec;
763 guint32 size;
764 guint8 *data, *end;
765 GstClockTime pts;
766 const mpeg2_info_t *info;
767 mpeg2_state_t state;
768 gboolean done = FALSE;
769 GstFlowReturn ret = GST_FLOW_OK;
771 mpeg2dec = GST_MPEG2DEC (GST_PAD_PARENT (pad));
773 size = GST_BUFFER_SIZE (buf);
774 data = GST_BUFFER_DATA (buf);
775 pts = GST_BUFFER_TIMESTAMP (buf);
777 GST_LOG_OBJECT (mpeg2dec, "received buffer, timestamp %"
778 GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
779 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
780 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
782 info = mpeg2dec->info;
783 end = data + size;
785 mpeg2dec->offset = GST_BUFFER_OFFSET (buf);
787 while (!done) {
788 GST_LOG_OBJECT (mpeg2dec, "calling parse");
789 state = mpeg2_parse (mpeg2dec->decoder);
790 GST_DEBUG_OBJECT (mpeg2dec, "parse state %d", state);
792 switch (state) {
793 case STATE_SEQUENCE:
794 ret = handle_sequence (mpeg2dec, info);
795 break;
796 case STATE_SEQUENCE_REPEATED:
797 GST_DEBUG_OBJECT (mpeg2dec, "sequence repeated");
798 break;
799 case STATE_GOP:
800 break;
801 case STATE_PICTURE:
802 ret = handle_picture (mpeg2dec, info);
803 break;
804 case STATE_SLICE_1ST:
805 GST_LOG_OBJECT (mpeg2dec, "1st slice of frame encountered");
806 break;
807 case STATE_PICTURE_2ND:
808 GST_LOG_OBJECT (mpeg2dec,
809 "Second picture header encountered. Decoding 2nd field");
810 break;
811 #if MPEG2_RELEASE >= MPEG2_VERSION (0, 4, 0)
812 case STATE_INVALID_END:
813 #endif
814 case STATE_END:
815 mpeg2dec->need_sequence = TRUE;
816 case STATE_SLICE:
817 ret = handle_slice (mpeg2dec, info);
818 break;
819 case STATE_BUFFER:
820 if (data == NULL) {
821 done = TRUE;
822 } else {
823 if (pts != GST_CLOCK_TIME_NONE) {
824 gint64 mpeg_pts = GST_TIME_TO_MPEG_TIME (pts);
826 GST_DEBUG_OBJECT (mpeg2dec,
827 "have pts: %" G_GINT64_FORMAT " (%" GST_TIME_FORMAT ")",
828 mpeg_pts, GST_TIME_ARGS (MPEG_TIME_TO_GST_TIME (mpeg_pts)));
830 #if MPEG2_RELEASE >= MPEG2_VERSION(0,4,0)
831 mpeg2_tag_picture (mpeg2dec->decoder, mpeg_pts & 0xffffffff,
832 mpeg_pts >> 32);
833 #else
834 mpeg2_pts (mpeg2dec->decoder, mpeg_pts);
835 #endif
836 } else {
837 GST_LOG ("no pts");
838 }
840 GST_LOG_OBJECT (mpeg2dec, "calling mpeg2_buffer");
841 mpeg2_buffer (mpeg2dec->decoder, data, end);
842 GST_LOG_OBJECT (mpeg2dec, "calling mpeg2_buffer done");
844 data = NULL;
845 }
846 break;
847 /* error */
848 case STATE_INVALID:
849 GST_WARNING_OBJECT (mpeg2dec, "Decoding error");
850 goto exit;
851 default:
852 GST_ERROR_OBJECT (mpeg2dec, "Unknown libmpeg2 state %d, FIXME", state);
853 break;
854 }
856 /*
857 * FIXME: should pass more information such as state the user data is from
858 */
859 #ifdef enable_user_data
860 if (info->user_data_len > 0) {
861 GstBuffer *udbuf = gst_buffer_new_and_alloc (info->user_data_len);
863 memcpy (GST_BUFFER_DATA (udbuf), info->user_data, info->user_data_len);
865 gst_pad_push (mpeg2dec->userdatapad, udbuf);
866 }
867 #endif
869 if (ret != GST_FLOW_OK) {
870 mpeg2_reset (mpeg2dec->decoder, 0);
871 break;
872 }
873 }
874 gst_buffer_unref (buf);
875 return ret;
877 exit:
878 gst_buffer_unref (buf);
879 return GST_FLOW_ERROR;
880 }
882 static gboolean
883 gst_mpeg2dec_sink_event (GstPad * pad, GstEvent * event)
884 {
886 GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (GST_PAD_PARENT (pad));
887 gboolean ret = TRUE;
889 GST_DEBUG_OBJECT (mpeg2dec, "Got %s event on sink pad",
890 GST_EVENT_TYPE_NAME (event));
892 switch (GST_EVENT_TYPE (event)) {
893 case GST_EVENT_NEWSEGMENT:
894 {
895 GST_STREAM_LOCK (pad);
896 mpeg2dec->next_time = -1;;
897 ret = gst_pad_event_default (pad, event);
898 GST_STREAM_UNLOCK (pad);
899 break;
900 }
901 case GST_EVENT_FLUSH_START:
902 ret = gst_pad_event_default (pad, event);
903 break;
904 case GST_EVENT_FLUSH_STOP:
905 GST_STREAM_LOCK (pad);
906 mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
907 mpeg2dec->next_time = -1;;
908 mpeg2_reset (mpeg2dec->decoder, 0);
909 ret = gst_pad_event_default (pad, event);
910 GST_STREAM_UNLOCK (pad);
911 break;
912 case GST_EVENT_EOS:
913 GST_STREAM_LOCK (pad);
914 if (mpeg2dec->index && mpeg2dec->closed) {
915 gst_index_commit (mpeg2dec->index, mpeg2dec->index_id);
916 }
917 ret = gst_pad_event_default (pad, event);
918 GST_STREAM_UNLOCK (pad);
919 break;
921 default:
922 ret = gst_pad_event_default (pad, event);
923 break;
924 }
926 return ret;
928 }
930 static GstCaps *
931 gst_mpeg2dec_src_getcaps (GstPad * pad)
932 {
933 GstCaps *caps;
935 GST_OBJECT_LOCK (pad);
936 if (!(caps = GST_PAD_CAPS (pad)))
937 caps = (GstCaps *) gst_pad_get_pad_template_caps (pad);
938 caps = gst_caps_ref (caps);
939 GST_OBJECT_UNLOCK (pad);
941 return caps;
942 }
944 static gboolean
945 gst_mpeg2dec_sink_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
946 GstFormat * dest_format, gint64 * dest_value)
947 {
948 gboolean res = TRUE;
949 GstMpeg2dec *mpeg2dec;
950 const mpeg2_info_t *info;
952 mpeg2dec = GST_MPEG2DEC (GST_PAD_PARENT (pad));
954 if (mpeg2dec->decoder == NULL)
955 return FALSE;
957 if (src_format == *dest_format) {
958 *dest_value = src_value;
959 return TRUE;
960 }
962 info = mpeg2_info (mpeg2dec->decoder);
964 switch (src_format) {
965 case GST_FORMAT_BYTES:
966 switch (*dest_format) {
967 case GST_FORMAT_TIME:
968 if (info->sequence && info->sequence->byte_rate) {
969 *dest_value = GST_SECOND * src_value / info->sequence->byte_rate;
970 break;
971 }
972 default:
973 res = FALSE;
974 }
975 break;
976 case GST_FORMAT_TIME:
977 switch (*dest_format) {
978 case GST_FORMAT_BYTES:
979 if (info->sequence && info->sequence->byte_rate) {
980 *dest_value = src_value * info->sequence->byte_rate / GST_SECOND;
981 break;
982 }
983 default:
984 res = FALSE;
985 }
986 break;
987 default:
988 res = FALSE;
989 }
990 return res;
991 }
994 static gboolean
995 gst_mpeg2dec_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
996 GstFormat * dest_format, gint64 * dest_value)
997 {
998 gboolean res = TRUE;
999 GstMpeg2dec *mpeg2dec;
1000 const mpeg2_info_t *info;
1001 guint64 scale = 1;
1003 mpeg2dec = GST_MPEG2DEC (GST_PAD_PARENT (pad));
1005 if (mpeg2dec->decoder == NULL)
1006 return FALSE;
1008 if (src_format == *dest_format) {
1009 *dest_value = src_value;
1010 return TRUE;
1011 }
1013 info = mpeg2_info (mpeg2dec->decoder);
1015 switch (src_format) {
1016 case GST_FORMAT_BYTES:
1017 switch (*dest_format) {
1018 case GST_FORMAT_TIME:
1019 default:
1020 res = FALSE;
1021 }
1022 break;
1023 case GST_FORMAT_TIME:
1024 switch (*dest_format) {
1025 case GST_FORMAT_BYTES:
1026 scale = 6 * (mpeg2dec->width * mpeg2dec->height >> 2);
1027 case GST_FORMAT_DEFAULT:
1028 if (info->sequence && mpeg2dec->frame_period) {
1029 *dest_value = src_value * scale / mpeg2dec->frame_period;
1030 break;
1031 }
1032 default:
1033 res = FALSE;
1034 }
1035 break;
1036 case GST_FORMAT_DEFAULT:
1037 switch (*dest_format) {
1038 case GST_FORMAT_TIME:
1039 *dest_value = src_value * mpeg2dec->frame_period;
1040 break;
1041 case GST_FORMAT_BYTES:
1042 *dest_value =
1043 src_value * 6 * ((mpeg2dec->width * mpeg2dec->height) >> 2);
1044 break;
1045 default:
1046 res = FALSE;
1047 }
1048 break;
1049 default:
1050 res = FALSE;
1051 }
1052 return res;
1053 }
1055 static const GstQueryType *
1056 gst_mpeg2dec_get_src_query_types (GstPad * pad)
1057 {
1058 static const GstQueryType types[] = {
1059 GST_QUERY_POSITION,
1060 GST_QUERY_DURATION,
1061 0
1062 };
1064 return types;
1065 }
1067 static gboolean
1068 gst_mpeg2dec_src_query (GstPad * pad, GstQuery * query)
1069 {
1070 gboolean res = TRUE;
1071 GstMpeg2dec *mpeg2dec;
1073 mpeg2dec = GST_MPEG2DEC (GST_PAD_PARENT (pad));
1075 switch (GST_QUERY_TYPE (query)) {
1076 case GST_QUERY_POSITION:
1077 {
1078 GstFormat format;
1079 gint64 cur;
1081 /* save requested format */
1082 gst_query_parse_position (query, &format, NULL);
1084 /* and convert to the requested format */
1085 if (!gst_mpeg2dec_src_convert (pad, GST_FORMAT_TIME,
1086 mpeg2dec->next_time, &format, &cur))
1087 goto error;
1089 gst_query_set_position (query, format, cur);
1091 GST_LOG_OBJECT (mpeg2dec,
1092 "position query: we return %llu (format %u)", cur, format);
1093 break;
1094 }
1095 case GST_QUERY_DURATION:
1096 {
1097 GstFormat format;
1098 GstFormat rformat;
1099 gint64 total, total_bytes;
1100 GstPad *peer;
1102 if ((peer = gst_pad_get_peer (mpeg2dec->sinkpad)) == NULL)
1103 goto error;
1105 /* send to peer */
1106 if ((res = gst_pad_query (peer, query))) {
1107 gst_object_unref (peer);
1108 goto done;
1109 } else {
1110 GST_LOG_OBJECT (mpeg2dec, "query on peer pad failed, trying bytes");
1111 }
1113 /* save requested format */
1114 gst_query_parse_duration (query, &format, NULL);
1116 /* query peer for total length in bytes */
1117 gst_query_set_duration (query, GST_FORMAT_BYTES, -1);
1119 if (!(res = gst_pad_query (peer, query))) {
1120 GST_LOG_OBJECT (mpeg2dec, "query on peer pad failed");
1121 gst_object_unref (peer);
1122 goto error;
1123 }
1124 gst_object_unref (peer);
1126 /* get the returned format */
1127 gst_query_parse_duration (query, &rformat, &total_bytes);
1128 GST_LOG_OBJECT (mpeg2dec, "peer pad returned total=%lld bytes",
1129 total_bytes);
1131 if (total_bytes != -1) {
1132 if (!gst_mpeg2dec_sink_convert (pad, GST_FORMAT_BYTES, total_bytes,
1133 &format, &total))
1134 goto error;
1135 } else {
1136 total = -1;
1137 }
1139 gst_query_set_duration (query, format, total);
1141 GST_LOG_OBJECT (mpeg2dec,
1142 "position query: we return %llu (format %u)", total, format);
1143 break;
1144 }
1145 default:
1146 res = FALSE;
1147 break;
1148 }
1149 done:
1150 return res;
1152 error:
1154 GST_DEBUG ("error handling query");
1155 return FALSE;
1156 }
1159 #if 0
1160 static const GstEventMask *
1161 gst_mpeg2dec_get_event_masks (GstPad * pad)
1162 {
1163 static const GstEventMask masks[] = {
1164 {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH},
1165 {GST_EVENT_NAVIGATION, GST_EVENT_FLAG_NONE},
1166 {0,}
1167 };
1169 return masks;
1170 }
1171 #endif
1173 static gboolean
1174 index_seek (GstPad * pad, GstEvent * event)
1175 {
1176 GstIndexEntry *entry;
1177 GstMpeg2dec *mpeg2dec;
1178 gdouble rate;
1179 GstFormat format;
1180 GstSeekFlags flags;
1181 GstSeekType cur_type, stop_type;
1182 gint64 cur, stop;
1184 mpeg2dec = GST_MPEG2DEC (GST_PAD_PARENT (pad));
1186 gst_event_parse_seek (event, &rate, &format, &flags,
1187 &cur_type, &cur, &stop_type, &stop);
1189 entry = gst_index_get_assoc_entry (mpeg2dec->index, mpeg2dec->index_id,
1190 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT, format, cur);
1192 if ((entry) && gst_pad_is_linked (mpeg2dec->sinkpad)) {
1193 const GstFormat *peer_formats, *try_formats;
1195 /* since we know the exact byteoffset of the frame, make sure to seek on bytes first */
1196 const GstFormat try_all_formats[] = {
1197 GST_FORMAT_BYTES,
1198 GST_FORMAT_TIME,
1199 0
1200 };
1202 try_formats = try_all_formats;
1204 #if 0
1205 peer_formats = gst_pad_get_formats (GST_PAD_PEER (mpeg2dec->sinkpad));
1206 #else
1207 peer_formats = try_all_formats; /* FIXE ME */
1208 #endif
1210 while (gst_formats_contains (peer_formats, *try_formats)) {
1211 gint64 value;
1213 if (gst_index_entry_assoc_map (entry, *try_formats, &value)) {
1214 GstEvent *seek_event;
1216 GST_DEBUG_OBJECT (mpeg2dec, "index %s %" G_GINT64_FORMAT
1217 " -> %s %" G_GINT64_FORMAT,
1218 gst_format_get_details (format)->nick,
1219 cur, gst_format_get_details (*try_formats)->nick, value);
1221 /* lookup succeeded, create the seek */
1222 seek_event =
1223 gst_event_new_seek (rate, *try_formats, flags, cur_type, value,
1224 stop_type, stop);
1225 /* do the seek */
1226 if (gst_pad_push_event (mpeg2dec->sinkpad, seek_event)) {
1227 /* seek worked, we're done, loop will exit */
1228 #if 0
1229 mpeg2dec->segment_start = GST_EVENT_SEEK_OFFSET (event);
1230 #endif
1231 return TRUE;
1232 }
1233 }
1234 try_formats++;
1235 }
1236 }
1237 return FALSE;
1238 }
1241 static gboolean
1242 normal_seek (GstPad * pad, GstEvent * event)
1243 {
1244 gdouble rate;
1245 GstFormat format, conv;
1246 GstSeekFlags flags;
1247 GstSeekType cur_type, stop_type;
1248 gint64 cur, stop;
1249 gint64 time_cur, bytes_cur;
1250 gint64 time_stop, bytes_stop;
1251 gboolean res;
1252 GstMpeg2dec *mpeg2dec;
1253 GstEvent *peer_event;
1255 mpeg2dec = GST_MPEG2DEC (GST_PAD_PARENT (pad));
1257 GST_DEBUG ("normal seek");
1259 gst_event_parse_seek (event, &rate, &format, &flags,
1260 &cur_type, &cur, &stop_type, &stop);
1262 conv = GST_FORMAT_TIME;
1263 if (!gst_mpeg2dec_src_convert (pad, format, cur, &conv, &time_cur))
1264 goto convert_failed;
1265 if (!gst_mpeg2dec_src_convert (pad, format, stop, &conv, &time_stop))
1266 goto convert_failed;
1268 GST_DEBUG ("seek to time %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1269 GST_TIME_ARGS (time_cur), GST_TIME_ARGS (time_stop));
1271 peer_event = gst_event_new_seek (rate, GST_FORMAT_TIME, flags,
1272 cur_type, time_cur, stop_type, time_stop);
1274 /* try seek on time then */
1275 if ((res = gst_pad_push_event (mpeg2dec->sinkpad, peer_event)))
1276 goto done;
1278 /* else we try to seek on bytes */
1279 conv = GST_FORMAT_BYTES;
1280 if (!gst_mpeg2dec_sink_convert (pad, GST_FORMAT_TIME, time_cur,
1281 &format, &bytes_cur))
1282 goto convert_failed;
1283 if (!gst_mpeg2dec_sink_convert (pad, GST_FORMAT_TIME, time_stop,
1284 &format, &bytes_stop))
1285 goto convert_failed;
1287 /* conversion succeeded, create the seek */
1288 peer_event =
1289 gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
1290 cur_type, bytes_cur, stop_type, bytes_stop);
1292 /* do the seek */
1293 res = gst_pad_push_event (mpeg2dec->sinkpad, peer_event);
1295 done:
1296 return res;
1298 /* ERRORS */
1299 convert_failed:
1300 {
1301 /* probably unsupported seek format */
1302 GST_DEBUG_OBJECT (mpeg2dec,
1303 "failed to convert format %u into GST_FORMAT_TIME", format);
1304 return FALSE;
1305 }
1306 }
1309 static gboolean
1310 gst_mpeg2dec_src_event (GstPad * pad, GstEvent * event)
1311 {
1312 gboolean res;
1313 GstMpeg2dec *mpeg2dec;
1315 mpeg2dec = GST_MPEG2DEC (GST_PAD_PARENT (pad));
1317 if (mpeg2dec->decoder == NULL)
1318 goto no_decoder;
1320 switch (GST_EVENT_TYPE (event)) {
1321 /* the all-formats seek logic */
1322 case GST_EVENT_SEEK:
1323 if (mpeg2dec->index)
1324 res = index_seek (pad, event);
1325 else
1326 res = normal_seek (pad, event);
1328 gst_event_unref (event);
1329 break;
1330 case GST_EVENT_NAVIGATION:
1331 /* Forward a navigation event unchanged */
1332 default:
1333 res = gst_pad_push_event (mpeg2dec->sinkpad, event);
1334 break;
1335 }
1336 return res;
1338 no_decoder:
1339 {
1340 GST_DEBUG_OBJECT (mpeg2dec, "no decoder, cannot handle event");
1341 gst_event_unref (event);
1342 return FALSE;
1343 }
1344 }
1346 static GstStateChangeReturn
1347 gst_mpeg2dec_change_state (GstElement * element, GstStateChange transition)
1348 {
1349 GstStateChangeReturn ret;
1350 GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (element);
1352 switch (transition) {
1353 case GST_STATE_CHANGE_NULL_TO_READY:
1354 mpeg2_accel (MPEG2_ACCEL_DETECT);
1355 if ((mpeg2dec->decoder = mpeg2_init ()) == NULL)
1356 goto init_failed;
1357 mpeg2dec->info = mpeg2_info (mpeg2dec->decoder);
1358 break;
1359 case GST_STATE_CHANGE_READY_TO_PAUSED:
1360 gst_mpeg2dec_reset (mpeg2dec);
1361 break;
1362 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1363 default:
1364 break;
1365 }
1367 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1369 switch (transition) {
1370 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1371 break;
1372 case GST_STATE_CHANGE_PAUSED_TO_READY:
1373 break;
1374 case GST_STATE_CHANGE_READY_TO_NULL:
1375 if (mpeg2dec->decoder) {
1376 mpeg2_close (mpeg2dec->decoder);
1377 mpeg2dec->decoder = NULL;
1378 mpeg2dec->info = NULL;
1379 }
1380 break;
1381 default:
1382 break;
1383 }
1384 return ret;
1386 /* ERRORS */
1387 init_failed:
1388 {
1389 GST_ELEMENT_ERROR (mpeg2dec, LIBRARY, INIT,
1390 (NULL), ("Failed to initialize libmpeg2 library"));
1391 return GST_STATE_CHANGE_FAILURE;
1392 }
1393 }
1395 static void
1396 gst_mpeg2dec_set_property (GObject * object, guint prop_id,
1397 const GValue * value, GParamSpec * pspec)
1398 {
1399 GstMpeg2dec *src;
1401 g_return_if_fail (GST_IS_MPEG2DEC (object));
1402 src = GST_MPEG2DEC (object);
1404 switch (prop_id) {
1405 default:
1406 break;
1407 }
1408 }
1410 static void
1411 gst_mpeg2dec_get_property (GObject * object, guint prop_id, GValue * value,
1412 GParamSpec * pspec)
1413 {
1414 GstMpeg2dec *mpeg2dec;
1416 g_return_if_fail (GST_IS_MPEG2DEC (object));
1417 mpeg2dec = GST_MPEG2DEC (object);
1419 switch (prop_id) {
1420 default:
1421 break;
1422 }
1423 }
1425 static gboolean
1426 plugin_init (GstPlugin * plugin)
1427 {
1428 if (!gst_element_register (plugin, "mpeg2dec", GST_RANK_SECONDARY,
1429 GST_TYPE_MPEG2DEC))
1430 return FALSE;
1432 return TRUE;
1433 }
1435 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1436 GST_VERSION_MINOR,
1437 "mpeg2dec",
1438 "LibMpeg2 decoder", plugin_init, VERSION, "GPL", GST_PACKAGE, GST_ORIGIN);