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 typedef picture_t mpeg2_picture_t;
35 typedef gint mpeg2_state_t;
36 #define STATE_BUFFER 0
37 #endif
39 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_SEEK);
41 /* elementfactory information */
42 static GstElementDetails gst_mpeg2dec_details = {
43 "mpeg1 and mpeg2 video decoder",
44 "Codec/Video/Decoder",
45 "GPL",
46 "Uses libmpeg2 to decode MPEG video streams",
47 VERSION,
48 "Wim Taymans <wim.taymans@chello.be>",
49 "(C) 2002"
50 };
52 /* Mpeg2dec signals and args */
53 enum {
54 /* FILL ME */
55 LAST_SIGNAL
56 };
58 enum {
59 ARG_0,
60 ARG_STREAMINFO,
61 /* FILL ME */
62 };
64 GST_PAD_TEMPLATE_FACTORY (src_template_factory,
65 "src",
66 GST_PAD_SRC,
67 GST_PAD_ALWAYS,
68 GST_CAPS_NEW (
69 "mpeg2dec_src",
70 "video/x-raw-yuv",
71 "format", GST_PROPS_LIST (
72 GST_PROPS_FOURCC (GST_MAKE_FOURCC ('Y','V','1','2')),
73 GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0'))
74 ),
75 "width", GST_PROPS_INT_RANGE (16, 4096),
76 "height", GST_PROPS_INT_RANGE (16, 4096),
77 "pixel_width", GST_PROPS_INT_RANGE (1, 255),
78 "pixel_height", GST_PROPS_INT_RANGE (1, 255),
79 "framerate", GST_PROPS_LIST (
80 GST_PROPS_FLOAT (24/1.001),
81 GST_PROPS_FLOAT (24.),
82 GST_PROPS_FLOAT (25.),
83 GST_PROPS_FLOAT (30/1.001),
84 GST_PROPS_FLOAT (30.),
85 GST_PROPS_FLOAT (50.),
86 GST_PROPS_FLOAT (60/1.001),
87 GST_PROPS_FLOAT (60.)
88 )
89 )
90 );
92 GST_PAD_TEMPLATE_FACTORY (user_data_template_factory,
93 "user_data",
94 GST_PAD_SRC,
95 GST_PAD_ALWAYS,
96 GST_CAPS_NEW (
97 "mpeg2dec_user_data",
98 "application/octet-stream",
99 NULL
100 )
101 );
103 GST_PAD_TEMPLATE_FACTORY (sink_template_factory,
104 "sink",
105 GST_PAD_SINK,
106 GST_PAD_ALWAYS,
107 GST_CAPS_NEW (
108 "mpeg2dec_sink",
109 "video/mpeg",
110 /* width/height/framerate not needed */
111 "mpegversion", GST_PROPS_INT_RANGE (1, 2),
112 "systemstream", GST_PROPS_BOOLEAN (FALSE)
113 )
114 );
116 static void gst_mpeg2dec_class_init (GstMpeg2decClass *klass);
117 static void gst_mpeg2dec_init (GstMpeg2dec *mpeg2dec);
119 static void gst_mpeg2dec_dispose (GObject *object);
121 static void gst_mpeg2dec_set_property (GObject *object, guint prop_id,
122 const GValue *value, GParamSpec *pspec);
123 static void gst_mpeg2dec_get_property (GObject *object, guint prop_id,
124 GValue *value, GParamSpec *pspec);
125 static void gst_mpeg2dec_set_index (GstElement *element, GstIndex *index);
126 static GstIndex* gst_mpeg2dec_get_index (GstElement *element);
128 static const GstFormat*
129 gst_mpeg2dec_get_src_formats (GstPad *pad);
130 static const GstEventMask*
131 gst_mpeg2dec_get_src_event_masks (GstPad *pad);
132 static gboolean gst_mpeg2dec_src_event (GstPad *pad, GstEvent *event);
133 static const GstQueryType*
134 gst_mpeg2dec_get_src_query_types (GstPad *pad);
135 static gboolean gst_mpeg2dec_src_query (GstPad *pad, GstQueryType type,
136 GstFormat *format, gint64 *value);
138 static const GstFormat*
139 gst_mpeg2dec_get_sink_formats (GstPad *pad);
140 static gboolean gst_mpeg2dec_convert_sink (GstPad *pad, GstFormat src_format, gint64 src_value,
141 GstFormat *dest_format, gint64 *dest_value);
142 static gboolean gst_mpeg2dec_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value,
143 GstFormat *dest_format, gint64 *dest_value);
145 static GstElementStateReturn
146 gst_mpeg2dec_change_state (GstElement *element);
148 static void gst_mpeg2dec_chain (GstPad *pad, GstData *_data);
150 static GstElementClass *parent_class = NULL;
151 /*static guint gst_mpeg2dec_signals[LAST_SIGNAL] = { 0 };*/
153 GType
154 gst_mpeg2dec_get_type (void)
155 {
156 static GType mpeg2dec_type = 0;
158 if (!mpeg2dec_type) {
159 static const GTypeInfo mpeg2dec_info = {
160 sizeof(GstMpeg2decClass),
161 NULL,
162 NULL,
163 (GClassInitFunc)gst_mpeg2dec_class_init,
164 NULL,
165 NULL,
166 sizeof(GstMpeg2dec),
167 0,
168 (GInstanceInitFunc)gst_mpeg2dec_init,
169 };
170 mpeg2dec_type = g_type_register_static(GST_TYPE_ELEMENT, "GstMpeg2dec", &mpeg2dec_info, 0);
171 }
172 return mpeg2dec_type;
173 }
175 static void
176 gst_mpeg2dec_class_init(GstMpeg2decClass *klass)
177 {
178 GObjectClass *gobject_class;
179 GstElementClass *gstelement_class;
181 gobject_class = (GObjectClass*)klass;
182 gstelement_class = (GstElementClass*)klass;
184 parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
186 g_object_class_install_property (gobject_class, ARG_STREAMINFO,
187 g_param_spec_boxed ("streaminfo", "Streaminfo", "Streaminfo",
188 GST_TYPE_CAPS, G_PARAM_READABLE));
190 gobject_class->set_property = gst_mpeg2dec_set_property;
191 gobject_class->get_property = gst_mpeg2dec_get_property;
192 gobject_class->dispose = gst_mpeg2dec_dispose;
194 gstelement_class->change_state = gst_mpeg2dec_change_state;
195 gstelement_class->set_index = gst_mpeg2dec_set_index;
196 gstelement_class->get_index = gst_mpeg2dec_get_index;
197 }
199 static void
200 gst_mpeg2dec_init (GstMpeg2dec *mpeg2dec)
201 {
202 /* create the sink and src pads */
203 mpeg2dec->sinkpad = gst_pad_new_from_template (
204 GST_PAD_TEMPLATE_GET (sink_template_factory), "sink");
205 gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->sinkpad);
206 gst_pad_set_chain_function (mpeg2dec->sinkpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_chain));
207 gst_pad_set_formats_function (mpeg2dec->sinkpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_sink_formats));
208 gst_pad_set_convert_function (mpeg2dec->sinkpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_convert_sink));
210 mpeg2dec->srcpad = gst_pad_new_from_template (
211 GST_PAD_TEMPLATE_GET (src_template_factory), "src");
212 gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->srcpad);
213 gst_pad_set_formats_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_src_formats));
214 gst_pad_set_event_mask_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_src_event_masks));
215 gst_pad_set_event_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_event));
216 gst_pad_set_query_type_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_src_query_types));
217 gst_pad_set_query_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_query));
218 gst_pad_set_convert_function (mpeg2dec->srcpad, GST_DEBUG_FUNCPTR (gst_mpeg2dec_convert_src));
220 mpeg2dec->userdatapad = gst_pad_new_from_template (
221 GST_PAD_TEMPLATE_GET (user_data_template_factory), "user_data");
222 gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->userdatapad);
224 /* initialize the mpeg2dec acceleration */
225 mpeg2_accel (MPEG2_ACCEL_DETECT);
226 mpeg2dec->closed = TRUE;
227 mpeg2dec->have_fbuf = FALSE;
229 GST_FLAG_SET (GST_ELEMENT (mpeg2dec), GST_ELEMENT_EVENT_AWARE);
230 }
232 static void
233 gst_mpeg2dec_close_decoder (GstMpeg2dec *mpeg2dec)
234 {
235 if (!mpeg2dec->closed) {
236 mpeg2_close (mpeg2dec->decoder);
237 mpeg2dec->closed = TRUE;
238 mpeg2dec->decoder = NULL;
239 }
240 }
242 static void
243 gst_mpeg2dec_open_decoder (GstMpeg2dec *mpeg2dec)
244 {
245 gst_mpeg2dec_close_decoder (mpeg2dec);
246 mpeg2dec->decoder = mpeg2_init ();
247 mpeg2dec->closed = FALSE;
248 mpeg2dec->have_fbuf = FALSE;
249 }
251 static void
252 gst_mpeg2dec_dispose (GObject *object)
253 {
254 GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (object);
256 gst_mpeg2dec_close_decoder (mpeg2dec);
258 G_OBJECT_CLASS (parent_class)->dispose (object);
259 }
261 static void
262 gst_mpeg2dec_set_index (GstElement *element, GstIndex *index)
263 {
264 GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (element);
266 mpeg2dec->index = index;
268 gst_index_get_writer_id (index, GST_OBJECT (element), &mpeg2dec->index_id);
269 }
271 static GstIndex*
272 gst_mpeg2dec_get_index (GstElement *element)
273 {
274 GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (element);
276 return mpeg2dec->index;
277 }
279 static GstBuffer*
280 gst_mpeg2dec_alloc_buffer (GstMpeg2dec *mpeg2dec, const mpeg2_info_t *info, gint64 offset)
281 {
282 GstBuffer *outbuf = NULL;
283 gint size = mpeg2dec->width * mpeg2dec->height;
284 guint8 *buf[3], *out;
285 const mpeg2_picture_t *picture;
287 if (mpeg2dec->peerpool) {
288 outbuf = gst_buffer_new_from_pool (mpeg2dec->peerpool, 0, 0);
289 }
290 if (!outbuf) {
291 outbuf = gst_buffer_new_and_alloc ((size * 3) / 2);
292 }
294 out = GST_BUFFER_DATA (outbuf);
296 buf[0] = out;
297 if (mpeg2dec->format == MPEG2DEC_FORMAT_I420) {
298 buf[1] = buf[0] + size;
299 buf[2] = buf[1] + size/4;
300 }
301 else {
302 buf[2] = buf[0] + size;
303 buf[1] = buf[2] + size/4;
304 }
306 gst_buffer_ref (outbuf);
307 mpeg2_set_buf (mpeg2dec->decoder, buf, outbuf);
309 picture = info->current_picture;
311 if (picture && (picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I) {
312 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_KEY_UNIT);
313 }
314 else {
315 GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_KEY_UNIT);
316 }
317 /* we store the original byteoffset of this picture in the stream here
318 * because we need it for indexing */
319 GST_BUFFER_OFFSET (outbuf) = offset;
321 return outbuf;
322 }
324 static gboolean
325 gst_mpeg2dec_negotiate_format (GstMpeg2dec *mpeg2dec)
326 {
327 GstCaps *allowed;
328 GstCaps *intersect, *trylist, *head, *to_intersect;
330 if (!GST_PAD_IS_LINKED (mpeg2dec->srcpad)) {
331 mpeg2dec->format = MPEG2DEC_FORMAT_I420;
332 return TRUE;
333 }
335 /* we what we are allowed to do */
336 allowed = gst_pad_get_allowed_caps (mpeg2dec->srcpad);
337 /* we could not get allowed caps */
338 if (!allowed) {
339 allowed = GST_CAPS_NEW (
340 "mpeg2dec_negotiate",
341 "video/x-raw-yuv",
342 "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("I420"))
343 );
344 }
346 to_intersect = GST_CAPS_NEW (
347 "mpeg2dec_negotiate",
348 "video/x-raw-yuv",
349 "width", GST_PROPS_INT (mpeg2dec->width),
350 "height", GST_PROPS_INT (mpeg2dec->height),
351 "pixel_width", GST_PROPS_INT (mpeg2dec->pixel_width),
352 "pixel_height", GST_PROPS_INT (mpeg2dec->pixel_height),
353 "framerate", GST_PROPS_FLOAT (1. * GST_SECOND / mpeg2dec->frame_period)
354 );
356 /* try to fix our height */
357 intersect = gst_caps_intersect (allowed, to_intersect);
358 gst_caps_unref (allowed);
359 gst_caps_unref (to_intersect);
361 /* prepare for looping */
362 head = trylist = gst_caps_normalize (intersect);
363 gst_caps_unref (intersect);
365 while (trylist) {
366 GstCaps *to_try = gst_caps_copy_1 (trylist);
368 /* try each format */
369 if (gst_pad_try_set_caps (mpeg2dec->srcpad, to_try) > 0) {
370 guint32 fourcc;
372 /* it worked, try to find what it was again */
373 gst_caps_get_fourcc_int (to_try, "format", &fourcc);
375 if (fourcc == GST_STR_FOURCC ("I420")) {
376 mpeg2dec->format = MPEG2DEC_FORMAT_I420;
377 }
378 else {
379 mpeg2dec->format = MPEG2DEC_FORMAT_YV12;
380 }
381 break;
382 }
384 trylist = trylist->next;
385 }
386 gst_caps_unref (head);
388 /* oops list exhausted and nothing was found... */
389 if (!trylist) {
390 return FALSE;
391 }
392 return TRUE;
393 }
395 static void
396 update_streaminfo (GstMpeg2dec *mpeg2dec)
397 {
398 GstCaps *caps;
399 GstProps *props;
400 GstPropsEntry *entry;
401 const mpeg2_info_t *info;
403 info = mpeg2_info (mpeg2dec->decoder);
405 props = gst_props_empty_new ();
407 entry = gst_props_entry_new ("framerate", GST_PROPS_FLOAT (GST_SECOND/(float)mpeg2dec->frame_period));
408 gst_props_add_entry (props, entry);
409 entry = gst_props_entry_new ("bitrate", GST_PROPS_INT (info->sequence->byte_rate * 8));
410 gst_props_add_entry (props, entry);
412 caps = gst_caps_new ("mpeg2dec_streaminfo",
413 "application/x-gst-streaminfo",
414 props);
416 gst_caps_replace_sink (&mpeg2dec->streaminfo, caps);
417 g_object_notify (G_OBJECT (mpeg2dec), "streaminfo");
418 }
420 static void
421 gst_mpeg2dec_flush_decoder (GstMpeg2dec *mpeg2dec)
422 {
423 mpeg2_state_t state;
425 if (mpeg2dec->decoder) {
426 const mpeg2_info_t *info = mpeg2_info (mpeg2dec->decoder);
428 do {
429 state = mpeg2_parse (mpeg2dec->decoder);
430 if (state == STATE_END) {
431 if (info->discard_fbuf && info->discard_fbuf->id) {
432 gst_buffer_unref ((GstBuffer *)info->discard_fbuf->id);
433 }
434 }
435 }
436 while (state != STATE_BUFFER && state != -1);
437 }
438 }
440 static void
441 gst_mpeg2dec_chain (GstPad *pad, GstData *_data)
442 {
443 GstBuffer *buf = GST_BUFFER (_data);
444 GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
445 guint32 size;
446 guint8 *data, *end;
447 gint64 pts;
448 const mpeg2_info_t *info;
449 mpeg2_state_t state;
450 gboolean done = FALSE;
452 if (GST_IS_EVENT (buf)) {
453 GstEvent *event = GST_EVENT (buf);
455 switch (GST_EVENT_TYPE (event)) {
456 case GST_EVENT_DISCONTINUOUS:
457 {
458 GST_DEBUG ("discont");
459 mpeg2dec->next_time = 0;
460 mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
461 gst_mpeg2dec_flush_decoder (mpeg2dec);
462 gst_pad_event_default (pad, event);
463 return;
464 }
465 case GST_EVENT_EOS:
466 if (mpeg2dec->index && mpeg2dec->closed) {
467 gst_index_commit (mpeg2dec->index, mpeg2dec->index_id);
468 }
469 default:
470 gst_pad_event_default (pad, event);
471 return;
472 }
473 }
475 size = GST_BUFFER_SIZE (buf);
476 data = GST_BUFFER_DATA (buf);
477 pts = GST_BUFFER_TIMESTAMP (buf);
479 info = mpeg2_info (mpeg2dec->decoder);
480 end = data + size;
482 if (pts != -1) {
483 gint64 mpeg_pts = GSTTIME_TO_MPEGTIME (pts);
485 GST_DEBUG ("have pts: %" G_GINT64_FORMAT " (%" G_GINT64_FORMAT ")",
486 mpeg_pts, MPEGTIME_TO_GSTTIME (mpeg_pts));
488 mpeg2_pts (mpeg2dec->decoder, mpeg_pts);
489 }
490 else {
491 GST_DEBUG ("no pts");
492 }
494 GST_DEBUG ("calling _buffer");
495 mpeg2_buffer (mpeg2dec->decoder, data, end);
496 GST_DEBUG ("calling _buffer done");
498 while (!done) {
499 gboolean slice = FALSE;
501 GST_DEBUG ("calling parse");
502 state = mpeg2_parse (mpeg2dec->decoder);
503 GST_DEBUG ("parse state %d", state);
504 switch (state) {
505 case STATE_SEQUENCE:
506 {
507 mpeg2dec->width = info->sequence->width;
508 mpeg2dec->height = info->sequence->height;
509 mpeg2dec->pixel_width = info->sequence->pixel_width;
510 mpeg2dec->pixel_height = info->sequence->pixel_height;
511 mpeg2dec->total_frames = 0;
512 mpeg2dec->frame_period = info->sequence->frame_period * GST_USECOND / 27;
514 GST_DEBUG ("sequence flags: %d, frame period: %d",
515 info->sequence->flags, info->sequence->frame_period);
516 GST_DEBUG ("profile: %02x, colour_primaries: %d",
517 info->sequence->profile_level_id, info->sequence->colour_primaries);
518 GST_DEBUG ("transfer chars: %d, matrix coef: %d",
519 info->sequence->transfer_characteristics, info->sequence->matrix_coefficients);
521 if (!gst_mpeg2dec_negotiate_format (mpeg2dec)) {
522 gst_element_error (GST_ELEMENT (mpeg2dec), "could not negotiate format");
523 goto exit;
524 }
526 /* now that we've negotiated, try to get a bufferpool */
527 mpeg2dec->peerpool = gst_pad_get_bufferpool (mpeg2dec->srcpad);
528 if (mpeg2dec->peerpool)
529 GST_INFO ( "got pool %p", mpeg2dec->peerpool);
531 update_streaminfo (mpeg2dec);
533 if (!mpeg2dec->have_fbuf) {
534 /* alloc 3 buffers */
535 gst_mpeg2dec_alloc_buffer (mpeg2dec, info, GST_BUFFER_OFFSET (buf));
536 gst_mpeg2dec_alloc_buffer (mpeg2dec, info, GST_BUFFER_OFFSET (buf));
537 gst_mpeg2dec_alloc_buffer (mpeg2dec, info, GST_BUFFER_OFFSET (buf));
538 mpeg2dec->have_fbuf = TRUE;
539 }
541 mpeg2dec->need_sequence = FALSE;
542 if (mpeg2dec->pending_event) {
543 done = GST_EVENT_SEEK_FLAGS (mpeg2dec->pending_event) & GST_SEEK_FLAG_FLUSH;
545 gst_mpeg2dec_src_event (mpeg2dec->srcpad, mpeg2dec->pending_event);
546 mpeg2dec->pending_event = NULL;
547 }
548 break;
549 }
550 case STATE_SEQUENCE_REPEATED:
551 GST_DEBUG ("sequence repeated");
552 case STATE_GOP:
553 break;
554 case STATE_PICTURE:
555 {
556 gboolean key_frame = FALSE;
557 GstBuffer *outbuf;
559 if (info->current_picture) {
560 key_frame = (info->current_picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I;
561 }
562 outbuf = gst_mpeg2dec_alloc_buffer (mpeg2dec, info, GST_BUFFER_OFFSET (buf));
564 GST_DEBUG ("picture %d, %p, %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT,
565 key_frame, outbuf, GST_BUFFER_OFFSET (outbuf), pts);
567 if (mpeg2dec->discont_state == MPEG2DEC_DISC_NEW_PICTURE && key_frame)
568 mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_KEYFRAME;
570 if (!GST_PAD_IS_USABLE (mpeg2dec->srcpad))
571 mpeg2_skip (mpeg2dec->decoder, 1);
572 else
573 mpeg2_skip (mpeg2dec->decoder, 0);
575 break;
576 }
577 case STATE_SLICE_1ST:
578 GST_DEBUG ("slice 1st");
579 break;
580 case STATE_PICTURE_2ND:
581 GST_DEBUG ("picture second");
582 break;
583 case STATE_SLICE:
584 slice = TRUE;
585 case STATE_END:
586 {
587 GstBuffer *outbuf = NULL;
588 gboolean skip = FALSE;
590 if (!slice) {
591 mpeg2dec->need_sequence = TRUE;
592 }
593 GST_DEBUG ("picture end %p %p %p %p", info->display_fbuf, info->display_picture, info->current_picture,
594 (info->display_fbuf ? info->display_fbuf->id : NULL));
596 if (info->display_fbuf && info->display_fbuf->id) {
597 const mpeg2_picture_t *picture;
598 gboolean key_frame = FALSE;
600 outbuf = (GstBuffer *) info->display_fbuf->id;
601 picture = info->display_picture;
603 key_frame = (picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I;
604 GST_DEBUG ("picture keyfame %d", key_frame);
606 if (key_frame) {
607 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_KEY_UNIT);
608 }
609 if (mpeg2dec->discont_state == MPEG2DEC_DISC_NEW_KEYFRAME && key_frame)
610 mpeg2dec->discont_state = MPEG2DEC_DISC_NONE;
612 if (picture->flags & PIC_FLAG_PTS) {
613 GstClockTime time = MPEGTIME_TO_GSTTIME (picture->pts);
615 GST_DEBUG ("picture had pts %" G_GINT64_FORMAT, time);
616 GST_BUFFER_TIMESTAMP (outbuf) = time;
618 mpeg2dec->next_time = time;
619 }
620 else {
621 GST_DEBUG ("picture didn't have pts using %" G_GINT64_FORMAT, mpeg2dec->next_time);
622 GST_BUFFER_TIMESTAMP (outbuf) = mpeg2dec->next_time;
623 }
624 mpeg2dec->next_time += (mpeg2dec->frame_period * picture->nb_fields) >> 1;
627 GST_DEBUG ("picture: %s %s fields:%d off:%" G_GINT64_FORMAT " ts:%" G_GINT64_FORMAT,
628 (picture->flags & PIC_FLAG_TOP_FIELD_FIRST ? "tff " : " "),
629 (picture->flags & PIC_FLAG_PROGRESSIVE_FRAME ? "prog" : " "),
630 picture->nb_fields,
631 GST_BUFFER_OFFSET (outbuf),
632 GST_BUFFER_TIMESTAMP (outbuf));
634 if (mpeg2dec->index) {
635 gst_index_add_association (mpeg2dec->index, mpeg2dec->index_id,
636 (key_frame ? GST_ASSOCIATION_FLAG_KEY_UNIT : 0),
637 GST_FORMAT_BYTES, GST_BUFFER_OFFSET (outbuf),
638 GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (outbuf), 0);
639 }
642 if (picture->flags & PIC_FLAG_SKIP ||
643 !GST_PAD_IS_USABLE (mpeg2dec->srcpad) ||
644 mpeg2dec->discont_state != MPEG2DEC_DISC_NONE ||
645 mpeg2dec->next_time < mpeg2dec->segment_start ||
646 skip)
647 {
648 gst_buffer_unref (outbuf);
649 }
650 else {
651 /* TODO set correct offset here based on frame number */
652 GST_BUFFER_DURATION (outbuf) = mpeg2dec->frame_period;
653 gst_pad_push (mpeg2dec->srcpad, GST_DATA (outbuf));
654 }
655 }
656 if (info->discard_fbuf && info->discard_fbuf->id) {
657 gst_buffer_unref ((GstBuffer *)info->discard_fbuf->id);
658 }
659 break;
660 }
661 /* need more data */
662 case STATE_BUFFER:
663 case -1:
664 done = TRUE;
665 break;
666 /* error */
667 case STATE_INVALID:
668 g_warning ("mpeg2dec: decoding error");
669 /* it looks like setting a new frame in libmpeg2 avoids a crash */
670 /* FIXME figure out how this screws up sync and buffer leakage */
671 gst_mpeg2dec_alloc_buffer (mpeg2dec, info, GST_BUFFER_OFFSET (buf));
672 break;
673 default:
674 g_warning ("%s: unhandled state %d, FIXME",
675 gst_element_get_name (GST_ELEMENT (mpeg2dec)),
676 state);
677 break;
678 }
680 /*
681 * FIXME: should pass more information such as state the user data is from
682 */
683 if (info->user_data_len > 0) {
684 if (GST_PAD_IS_USABLE (mpeg2dec->userdatapad)) {
685 GstBuffer *udbuf = gst_buffer_new_and_alloc (info->user_data_len);
687 memcpy (GST_BUFFER_DATA (udbuf), info->user_data, info->user_data_len);
689 gst_pad_push (mpeg2dec->userdatapad, GST_DATA (udbuf));
690 }
691 }
692 }
693 exit:
694 gst_buffer_unref(buf);
695 }
697 static const GstFormat*
698 gst_mpeg2dec_get_sink_formats (GstPad *pad)
699 {
700 static const GstFormat formats[] = {
701 GST_FORMAT_BYTES,
702 GST_FORMAT_TIME,
703 0
704 };
705 return formats;
706 }
708 static gboolean
709 gst_mpeg2dec_convert_sink (GstPad *pad, GstFormat src_format, gint64 src_value,
710 GstFormat *dest_format, gint64 *dest_value)
711 {
712 gboolean res = TRUE;
713 GstMpeg2dec *mpeg2dec;
714 const mpeg2_info_t *info;
716 mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
718 if (mpeg2dec->decoder == NULL)
719 return FALSE;
721 info = mpeg2_info (mpeg2dec->decoder);
723 switch (src_format) {
724 case GST_FORMAT_BYTES:
725 switch (*dest_format) {
726 case GST_FORMAT_TIME:
727 if (info->sequence && info->sequence->byte_rate) {
728 *dest_value = GST_SECOND * src_value / info->sequence->byte_rate;
729 break;
730 }
731 default:
732 res = FALSE;
733 }
734 break;
735 case GST_FORMAT_TIME:
736 switch (*dest_format) {
737 case GST_FORMAT_BYTES:
738 if (info->sequence && info->sequence->byte_rate) {
739 *dest_value = src_value * info->sequence->byte_rate / GST_SECOND;
740 break;
741 }
742 default:
743 res = FALSE;
744 }
745 break;
746 default:
747 res = FALSE;
748 }
749 return res;
750 }
752 static const GstFormat*
753 gst_mpeg2dec_get_src_formats (GstPad *pad)
754 {
755 static const GstFormat formats[] = {
756 GST_FORMAT_BYTES,
757 GST_FORMAT_TIME,
758 GST_FORMAT_DEFAULT,
759 0
760 };
761 return formats;
762 }
764 static gboolean
765 gst_mpeg2dec_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value,
766 GstFormat *dest_format, gint64 *dest_value)
767 {
768 gboolean res = TRUE;
769 GstMpeg2dec *mpeg2dec;
770 const mpeg2_info_t *info;
771 guint64 scale = 1;
773 mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
775 if (mpeg2dec->decoder == NULL)
776 return FALSE;
778 info = mpeg2_info (mpeg2dec->decoder);
780 switch (src_format) {
781 case GST_FORMAT_BYTES:
782 switch (*dest_format) {
783 case GST_FORMAT_TIME:
784 default:
785 res = FALSE;
786 }
787 break;
788 case GST_FORMAT_TIME:
789 switch (*dest_format) {
790 case GST_FORMAT_BYTES:
791 scale = 6 * (mpeg2dec->width * mpeg2dec->height >> 2);
792 case GST_FORMAT_DEFAULT:
793 if (info->sequence && mpeg2dec->frame_period) {
794 *dest_value = src_value * scale / mpeg2dec->frame_period;
795 break;
796 }
797 default:
798 res = FALSE;
799 }
800 break;
801 case GST_FORMAT_DEFAULT:
802 switch (*dest_format) {
803 case GST_FORMAT_TIME:
804 *dest_value = src_value * mpeg2dec->frame_period;
805 break;
806 case GST_FORMAT_BYTES:
807 *dest_value = src_value * 6 * ((mpeg2dec->width * mpeg2dec->height) >> 2);
808 break;
809 default:
810 res = FALSE;
811 }
812 break;
813 default:
814 res = FALSE;
815 }
816 return res;
817 }
819 static const GstQueryType*
820 gst_mpeg2dec_get_src_query_types (GstPad *pad)
821 {
822 static const GstQueryType types[] = {
823 GST_QUERY_TOTAL,
824 GST_QUERY_POSITION,
825 0
826 };
827 return types;
828 }
830 static gboolean
831 gst_mpeg2dec_src_query (GstPad *pad, GstQueryType type,
832 GstFormat *format, gint64 *value)
833 {
834 gboolean res = TRUE;
835 GstMpeg2dec *mpeg2dec;
836 static const GstFormat *formats;
838 mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
840 switch (type) {
841 case GST_QUERY_TOTAL:
842 {
843 switch (*format) {
844 case GST_FORMAT_TIME:
845 case GST_FORMAT_BYTES:
846 case GST_FORMAT_DEFAULT:
847 {
848 res = FALSE;
850 /* get our peer formats */
851 formats = gst_pad_get_formats (GST_PAD_PEER (mpeg2dec->sinkpad));
853 /* while we did not exhaust our seek formats without result */
854 while (formats && *formats) {
855 GstFormat peer_format;
856 gint64 peer_value;
858 peer_format = *formats;
860 /* do the probe */
861 if (gst_pad_query (GST_PAD_PEER (mpeg2dec->sinkpad), GST_QUERY_TOTAL,
862 &peer_format, &peer_value))
863 {
864 GstFormat conv_format;
866 /* convert to TIME */
867 conv_format = GST_FORMAT_TIME;
868 res = gst_pad_convert (mpeg2dec->sinkpad,
869 peer_format, peer_value,
870 &conv_format, value);
871 /* and to final format */
872 res &= gst_pad_convert (pad,
873 GST_FORMAT_TIME, *value,
874 format, value);
875 }
876 formats++;
877 }
878 break;
879 }
880 default:
881 res = FALSE;
882 break;
883 }
884 break;
885 }
886 case GST_QUERY_POSITION:
887 {
888 switch (*format) {
889 default:
890 res = gst_pad_convert (pad,
891 GST_FORMAT_TIME, mpeg2dec->next_time,
892 format, value);
893 break;
894 }
895 break;
896 }
897 default:
898 res = FALSE;
899 break;
900 }
902 return res;
903 }
906 static const GstEventMask*
907 gst_mpeg2dec_get_src_event_masks (GstPad *pad)
908 {
909 static const GstEventMask masks[] = {
910 { GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH },
911 { 0, }
912 };
913 return masks;
914 }
916 static gboolean
917 index_seek (GstPad *pad, GstEvent *event)
918 {
919 GstIndexEntry *entry;
920 GstMpeg2dec *mpeg2dec;
922 mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
924 entry = gst_index_get_assoc_entry (mpeg2dec->index, mpeg2dec->index_id,
925 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
926 GST_EVENT_SEEK_FORMAT (event),
927 GST_EVENT_SEEK_OFFSET (event));
929 if (entry) {
930 const GstFormat *peer_formats, *try_formats;
931 /* since we know the exaxt byteoffset of the frame, make sure to seek on bytes first */
932 const GstFormat try_all_formats[] =
933 {
934 GST_FORMAT_BYTES,
935 GST_FORMAT_TIME,
936 0
937 };
939 try_formats = try_all_formats;
940 peer_formats = gst_pad_get_formats (GST_PAD_PEER (mpeg2dec->sinkpad));
942 while (gst_formats_contains (peer_formats, *try_formats)) {
943 gint64 value;
945 if (gst_index_entry_assoc_map (entry, *try_formats, &value)) {
946 GstEvent *seek_event;
948 GST_CAT_DEBUG (GST_CAT_SEEK, "index %s %" G_GINT64_FORMAT
949 " -> %s %" G_GINT64_FORMAT,
950 gst_format_get_details (GST_EVENT_SEEK_FORMAT (event))->nick,
951 GST_EVENT_SEEK_OFFSET (event),
952 gst_format_get_details (*try_formats)->nick,
953 value);
955 /* lookup succeeded, create the seek */
956 seek_event = gst_event_new_seek (*try_formats | GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH, value);
957 /* do the seekk */
958 if (gst_pad_send_event (GST_PAD_PEER (mpeg2dec->sinkpad), seek_event)) {
959 /* seek worked, we're done, loop will exit */
960 gst_mpeg2dec_flush_decoder (mpeg2dec);
961 mpeg2dec->segment_start = GST_EVENT_SEEK_OFFSET (event);
962 return TRUE;
963 }
964 }
965 try_formats++;
966 }
967 }
968 return FALSE;
969 }
972 static gboolean
973 normal_seek (GstPad *pad, GstEvent *event)
974 {
975 gint64 src_offset;
976 gboolean flush;
977 GstFormat format;
978 const GstFormat *peer_formats;
979 gboolean res = FALSE;
980 GstMpeg2dec *mpeg2dec;
982 mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
984 format = GST_FORMAT_TIME;
986 /* first bring the src_format to TIME */
987 if (!gst_pad_convert (pad,
988 GST_EVENT_SEEK_FORMAT (event), GST_EVENT_SEEK_OFFSET (event),
989 &format, &src_offset))
990 {
991 /* didn't work, probably unsupported seek format then */
992 return res;
993 }
995 /* shave off the flush flag, we'll need it later */
996 flush = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH;
998 /* get our peer formats */
999 peer_formats = gst_pad_get_formats (GST_PAD_PEER (mpeg2dec->sinkpad));
1001 /* while we did not exhaust our seek formats without result */
1002 while (peer_formats && *peer_formats) {
1003 gint64 desired_offset;
1005 format = *peer_formats;
1007 /* try to convert requested format to one we can seek with on the sinkpad */
1008 if (gst_pad_convert (mpeg2dec->sinkpad, GST_FORMAT_TIME, src_offset, &format, &desired_offset))
1009 {
1010 GstEvent *seek_event;
1012 /* conversion succeeded, create the seek */
1013 seek_event = gst_event_new_seek (format | GST_SEEK_METHOD_SET | flush, desired_offset);
1014 /* do the seekk */
1015 if (gst_pad_send_event (GST_PAD_PEER (mpeg2dec->sinkpad), seek_event)) {
1016 /* seek worked, we're done, loop will exit */
1017 mpeg2dec->segment_start = GST_EVENT_SEEK_OFFSET (event);
1018 res = TRUE;
1019 break;
1020 }
1021 }
1022 peer_formats++;
1023 }
1024 /* at this point, either the seek worked and res = TRUE or res == FALSE and the seek
1025 * failed */
1026 if (res && flush) {
1027 /* if we need to flush, iterate until the buffer is empty */
1028 gst_mpeg2dec_flush_decoder (mpeg2dec);
1029 }
1031 return res;
1032 }
1033 static gboolean
1034 gst_mpeg2dec_src_event (GstPad *pad, GstEvent *event)
1035 {
1036 gboolean res = TRUE;
1037 GstMpeg2dec *mpeg2dec;
1039 mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
1041 if (mpeg2dec->decoder == NULL)
1042 return FALSE;
1044 switch (GST_EVENT_TYPE (event)) {
1045 /* the all-formats seek logic */
1046 case GST_EVENT_SEEK:
1047 if (mpeg2dec->need_sequence) {
1048 mpeg2dec->pending_event = event;
1049 return TRUE;
1050 }
1051 else {
1052 if (mpeg2dec->index)
1053 res = index_seek (pad, event);
1054 else
1055 res = normal_seek (pad, event);
1057 if (res)
1058 mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
1059 }
1060 break;
1061 default:
1062 res = FALSE;
1063 break;
1064 }
1065 gst_event_unref (event);
1066 return res;
1067 }
1069 static GstElementStateReturn
1070 gst_mpeg2dec_change_state (GstElement *element)
1071 {
1072 GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (element);
1074 switch (GST_STATE_TRANSITION (element)) {
1075 case GST_STATE_NULL_TO_READY:
1076 break;
1077 case GST_STATE_READY_TO_PAUSED:
1078 {
1079 mpeg2dec->next_time = 0;
1080 mpeg2dec->peerpool = NULL;
1082 /* reset the initial video state */
1083 mpeg2dec->format = MPEG2DEC_FORMAT_NONE;
1084 mpeg2dec->width = -1;
1085 mpeg2dec->height = -1;
1086 mpeg2dec->segment_start = 0;
1087 mpeg2dec->segment_end = -1;
1088 mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
1089 mpeg2dec->frame_period = 0;
1090 mpeg2dec->streaminfo = NULL;
1091 gst_mpeg2dec_open_decoder (mpeg2dec);
1092 mpeg2dec->need_sequence = TRUE;
1093 break;
1094 }
1095 case GST_STATE_PAUSED_TO_PLAYING:
1096 /* if we've negotiated caps, try to get a bufferpool */
1097 if (mpeg2dec->peerpool == NULL && mpeg2dec->width > 0) {
1098 mpeg2dec->peerpool = gst_pad_get_bufferpool (mpeg2dec->srcpad);
1099 if (mpeg2dec->peerpool)
1100 GST_INFO ( "got pool %p", mpeg2dec->peerpool);
1101 }
1102 break;
1103 case GST_STATE_PLAYING_TO_PAUSED:
1104 /* need to clear things we get from other plugins, since we could be reconnected */
1105 if (mpeg2dec->peerpool) {
1106 gst_buffer_pool_unref (mpeg2dec->peerpool);
1107 mpeg2dec->peerpool = NULL;
1108 }
1109 break;
1110 case GST_STATE_PAUSED_TO_READY:
1111 gst_mpeg2dec_close_decoder (mpeg2dec);
1112 gst_caps_replace (&mpeg2dec->streaminfo, NULL);
1113 break;
1114 case GST_STATE_READY_TO_NULL:
1115 break;
1116 default:
1117 break;
1118 }
1120 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1121 }
1123 static void
1124 gst_mpeg2dec_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
1125 {
1126 GstMpeg2dec *src;
1128 /* it's not null if we got it, but it might not be ours */
1129 g_return_if_fail (GST_IS_MPEG2DEC (object));
1130 src = GST_MPEG2DEC (object);
1132 switch (prop_id) {
1133 default:
1134 break;
1135 }
1136 }
1138 static void
1139 gst_mpeg2dec_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
1140 {
1141 GstMpeg2dec *mpeg2dec;
1143 /* it's not null if we got it, but it might not be ours */
1144 g_return_if_fail (GST_IS_MPEG2DEC (object));
1145 mpeg2dec = GST_MPEG2DEC (object);
1147 switch (prop_id) {
1148 case ARG_STREAMINFO:
1149 g_value_set_boxed (value, mpeg2dec->streaminfo);
1150 break;
1151 default:
1152 break;
1153 }
1154 }
1156 static gboolean
1157 plugin_init (GModule *module, GstPlugin *plugin)
1158 {
1159 GstElementFactory *factory;
1161 /* create an elementfactory for the mpeg2dec element */
1162 factory = gst_element_factory_new("mpeg2dec",GST_TYPE_MPEG2DEC,
1163 &gst_mpeg2dec_details);
1164 g_return_val_if_fail(factory != NULL, FALSE);
1165 gst_element_factory_set_rank (factory, GST_ELEMENT_RANK_PRIMARY);
1167 gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (src_template_factory));
1168 gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (sink_template_factory));
1169 gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (user_data_template_factory));
1171 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
1173 return TRUE;
1174 }
1176 GstPluginDesc plugin_desc = {
1177 GST_VERSION_MAJOR,
1178 GST_VERSION_MINOR,
1179 "mpeg2dec",
1180 plugin_init
1181 };