2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
23 Some data gathered from the net, specificaly for DV in riff/AVI : http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/dvdataintheavifileformat.asp
25 The 'dvsd' stream handler FOURCC specifies that the DV data is as defined in Part 2 of the Specification of Consumer-use Digital VCRs. Video is in the format of 525 lines at 29.97 Hz (525-60) or 625 lines at 25.00 Hz (625-50).
26 The 'dvhd' stream handler FOURCC specifies that the DV data is as defined in Part 3 of the Specification of Consumer-use Digital VCRs. Video is in the format of 1125 lines at 30.00 Hz (1125-60) or 1250 lines at 25.00 Hz (1250-50).
27 The 'dvsl' stream handler FOURCC specifies that the DV data is as defined in Part 6 of Specification of Consumer-use Digital VCRs. Video is in the format of high-compression SD (SDL).
37 /* First, include the header file for the plugin, to bring in the
38 * object definition and other useful things.
42 #define NTSC_HEIGHT 480
43 #define NTSC_BUFFER 120000
44 #define NTSC_FRAMERATE 29.997
46 #define PAL_HEIGHT 576
47 #define PAL_BUFFER 144000
48 #define PAL_FRAMERATE 25.0
50 #define PAL_NORMAL_PAR_X 16
51 #define PAL_NORMAL_PAR_Y 15
52 #define PAL_WIDE_PAR_X 64
53 #define PAL_WIDE_PAR_Y 45
55 #define NTSC_NORMAL_PAR_X 80
56 #define NTSC_NORMAL_PAR_Y 89
57 #define NTSC_WIDE_PAR_X 320
58 #define NTSC_WIDE_PAR_Y 267
60 /* The ElementDetails structure gives a human-readable description
61 * of the plugin, as well as author and version data.
63 static GstElementDetails dvdec_details =
64 GST_ELEMENT_DETAILS ("DV (smpte314) decoder plugin",
65 "Codec/Decoder/Video",
66 "Uses libdv to decode DV video (libdv.sourceforge.net)",
67 "Erik Walthinsen <omega@cse.ogi.edu>\n" "Wim Taymans <wim.taymans@tvd.be>");
70 /* These are the signals that this element can fire. They are zero-
71 * based because the numbers themselves are private to the object.
72 * LAST_SIGNAL is used for initialization of the signal array.
80 #define DV_DEFAULT_QUALITY DV_QUALITY_BEST
81 #define DV_DEFAULT_DECODE_NTH 1
83 /* Arguments are identified the same way, but cannot be zero, so you
84 * must leave the ARG_0 entry in as a placeholder.
96 const gint qualities[] = {
100 DV_QUALITY_DC | DV_QUALITY_COLOR,
101 DV_QUALITY_AC_1 | DV_QUALITY_COLOR,
102 DV_QUALITY_AC_2 | DV_QUALITY_COLOR
105 /* The PadFactory structures describe what pads the element has or
106 * can have. They can be quite complex, but for this dvdec plugin
107 * they are rather simple.
109 static GstStaticPadTemplate sink_temp = GST_STATIC_PAD_TEMPLATE ("sink",
112 GST_STATIC_CAPS ("video/x-dv, systemstream = (boolean) true")
115 static GstStaticPadTemplate video_src_temp = GST_STATIC_PAD_TEMPLATE ("video",
118 GST_STATIC_CAPS ("video/x-raw-yuv, "
119 "format = (fourcc) YUY2, "
120 "width = (int) 720, "
122 G_STRINGIFY (NTSC_HEIGHT) ", " G_STRINGIFY (PAL_HEIGHT)
124 "pixel-aspect-ratio=(fraction) { "
125 G_STRINGIFY (PAL_NORMAL_PAR_X) "/" G_STRINGIFY (PAL_NORMAL_PAR_Y) ","
126 G_STRINGIFY (PAL_WIDE_PAR_X) "/" G_STRINGIFY (PAL_WIDE_PAR_Y) ","
127 G_STRINGIFY (NTSC_NORMAL_PAR_X) "/" G_STRINGIFY (NTSC_NORMAL_PAR_Y) ","
128 G_STRINGIFY (NTSC_WIDE_PAR_X) "/" G_STRINGIFY (NTSC_WIDE_PAR_Y) "},"
129 "framerate = (double) [ 1.0, 60.0 ];"
130 //"framerate = (double) { "
131 //G_STRINGIFY (PAL_FRAMERATE) ", " G_STRINGIFY (NTSC_FRAMERATE)
136 "endianness = (int) " G_STRINGIFY (G_BIG_ENDIAN) ", "
137 "red_mask = (int) 0x00ff0000, "
138 "green_mask = (int) 0x0000ff00, "
139 "blue_mask = (int) 0x000000ff, "
140 "width = (int) 720, "
142 G_STRINGIFY (NTSC_HEIGHT) ", " G_STRINGIFY (PAL_HEIGHT)
144 "pixel-aspect-ratio=(fraction) { "
145 G_STRINGIFY (PAL_NORMAL_PAR_X) "/" G_STRINGIFY (PAL_NORMAL_PAR_Y) ","
146 G_STRINGIFY (PAL_WIDE_PAR_X) "/" G_STRINGIFY (PAL_WIDE_PAR_Y) ","
147 G_STRINGIFY (NTSC_NORMAL_PAR_X) "/" G_STRINGIFY (NTSC_NORMAL_PAR_Y) ","
148 G_STRINGIFY (NTSC_WIDE_PAR_X) "/" G_STRINGIFY (NTSC_WIDE_PAR_Y) "},"
149 "framerate = (double) [ 1.0, 60.0 ];"
150 //"framerate = (double) { "
151 //G_STRINGIFY (PAL_FRAMERATE) ", " G_STRINGIFY (NTSC_FRAMERATE)
156 "endianness = (int) " G_STRINGIFY (G_BIG_ENDIAN) ", "
157 "red_mask = (int) 0x00ff0000, "
158 "green_mask = (int) 0x0000ff00, "
159 "blue_mask = (int) 0x000000ff, "
160 "width = (int) 720, "
162 G_STRINGIFY (NTSC_HEIGHT) ", " G_STRINGIFY (PAL_HEIGHT)
164 "pixel-aspect-ratio=(fraction) { "
165 G_STRINGIFY (PAL_NORMAL_PAR_X) "/" G_STRINGIFY (PAL_NORMAL_PAR_Y) ","
166 G_STRINGIFY (PAL_WIDE_PAR_X) "/" G_STRINGIFY (PAL_WIDE_PAR_Y) ","
167 G_STRINGIFY (NTSC_NORMAL_PAR_X) "/" G_STRINGIFY (NTSC_NORMAL_PAR_Y) ","
168 G_STRINGIFY (NTSC_WIDE_PAR_X) "/" G_STRINGIFY (NTSC_WIDE_PAR_Y) "},"
169 "framerate = (double) [ 1.0, 60.0 ]"
170 //"framerate = (double) { "
171 //G_STRINGIFY (PAL_FRAMERATE) ", " G_STRINGIFY (NTSC_FRAMERATE)
176 static GstStaticPadTemplate audio_src_temp = GST_STATIC_PAD_TEMPLATE ("audio",
179 GST_STATIC_CAPS ("audio/x-raw-int, "
182 "signed = (boolean) TRUE, "
183 "channels = (int) {2, 4}, "
184 "endianness = (int) " G_STRINGIFY (G_LITTLE_ENDIAN) ", "
185 "rate = (int) { 32000, 44100, 48000 }")
188 #define GST_TYPE_DVDEC_QUALITY (gst_dvdec_quality_get_type())
190 gst_dvdec_quality_get_type (void)
192 static GType qtype = 0;
195 static const GEnumValue values[] = {
196 {0, "DV_QUALITY_FASTEST", "Fastest decoding, low-quality mono"},
197 {1, "DV_QUALITY_AC_1", "Mono decoding using the first AC coefficient"},
198 {2, "DV_QUALITY_AC_2", "Highest quality mono decoding"},
199 {3, "DV_QUALITY_DC|DV_QUALITY_COLOUR", "Fastest colour decoding"},
200 {4, "DV_QUALITY_AC_1|DV_QUALITY_COLOUR",
201 "Colour, using only the first AC coefficient"},
202 {5, "DV_QUALITY_BEST", "Highest quality colour decoding"},
206 qtype = g_enum_register_static ("GstDVDecQualityEnum", values);
211 /* A number of functon prototypes are given so we can refer to them later. */
212 static void gst_dvdec_base_init (gpointer g_class);
213 static void gst_dvdec_class_init (GstDVDecClass * klass);
214 static void gst_dvdec_init (GstDVDec * dvdec);
216 static const GstQueryType *gst_dvdec_get_src_query_types (GstPad * pad);
217 static gboolean gst_dvdec_src_query (GstPad * pad, GstQueryType type,
218 GstFormat * format, gint64 * value);
219 static const GstFormat *gst_dvdec_get_formats (GstPad * pad);
220 static gboolean gst_dvdec_sink_convert (GstPad * pad, GstFormat src_format,
221 gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
222 static gboolean gst_dvdec_src_convert (GstPad * pad, GstFormat src_format,
223 gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
225 static GstPadLinkReturn gst_dvdec_video_link (GstPad * pad,
226 const GstCaps * caps);
227 static GstCaps *gst_dvdec_video_getcaps (GstPad * pad);
229 static const GstEventMask *gst_dvdec_get_event_masks (GstPad * pad);
230 static gboolean gst_dvdec_handle_src_event (GstPad * pad, GstEvent * event);
232 static void gst_dvdec_loop (GstElement * element);
234 static GstElementStateReturn gst_dvdec_change_state (GstElement * element);
236 static void gst_dvdec_set_property (GObject * object, guint prop_id,
237 const GValue * value, GParamSpec * pspec);
238 static void gst_dvdec_get_property (GObject * object, guint prop_id,
239 GValue * value, GParamSpec * pspec);
241 /* The parent class pointer needs to be kept around for some object
244 static GstElementClass *parent_class = NULL;
246 /* This array holds the ids of the signals registered for this object.
247 * The array indexes are based on the enum up above.
249 /*static guint gst_dvdec_signals[LAST_SIGNAL] = { 0 }; */
251 /* This function is used to register and subsequently return the type
252 * identifier for this object class. On first invocation, it will
253 * register the type, providing the name of the class, struct sizes,
254 * and pointers to the various functions that define the class.
257 gst_dvdec_get_type (void)
259 static GType dvdec_type = 0;
262 static const GTypeInfo dvdec_info = {
263 sizeof (GstDVDecClass),
266 (GClassInitFunc) gst_dvdec_class_init,
271 (GInstanceInitFunc) gst_dvdec_init,
275 g_type_register_static (GST_TYPE_ELEMENT, "GstDVDec", &dvdec_info, 0);
281 gst_dvdec_base_init (gpointer g_class)
283 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
285 /* The pad templates can be easily generated from the factories above,
286 * and then added to the list of padtemplates for the elementfactory.
287 * Note that the generated padtemplates are stored in static global
288 * variables, for the gst_dvdec_init function to use later on.
290 gst_element_class_add_pad_template (element_class,
291 gst_static_pad_template_get (&sink_temp));
292 gst_element_class_add_pad_template (element_class,
293 gst_static_pad_template_get (&video_src_temp));
294 gst_element_class_add_pad_template (element_class,
295 gst_static_pad_template_get (&audio_src_temp));
297 gst_element_class_set_details (element_class, &dvdec_details);
300 /* In order to create an instance of an object, the class must be
301 * initialized by this function. GObject will take care of running
302 * it, based on the pointer to the function provided above.
305 gst_dvdec_class_init (GstDVDecClass * klass)
307 /* Class pointers are needed to supply pointers to the private
308 * implementations of parent class methods.
310 GObjectClass *gobject_class;
311 GstElementClass *gstelement_class;
313 /* Since the dvdec class contains the parent classes, you can simply
314 * cast the pointer to get access to the parent classes.
316 gobject_class = (GObjectClass *) klass;
317 gstelement_class = (GstElementClass *) klass;
319 /* The parent class is needed for class method overrides. */
320 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
322 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CLAMP_LUMA,
323 g_param_spec_boolean ("clamp_luma", "Clamp luma", "Clamp luma",
324 FALSE, G_PARAM_READWRITE));
325 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CLAMP_CHROMA,
326 g_param_spec_boolean ("clamp_chroma", "Clamp chroma", "Clamp chroma",
327 FALSE, G_PARAM_READWRITE));
328 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
329 g_param_spec_enum ("quality", "Quality", "Decoding quality",
330 GST_TYPE_DVDEC_QUALITY, DV_DEFAULT_QUALITY, G_PARAM_READWRITE));
331 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DECODE_NTH,
332 g_param_spec_int ("drop-factor", "Drop Factor", "Only decode Nth frame",
333 1, G_MAXINT, DV_DEFAULT_DECODE_NTH, G_PARAM_READWRITE));
335 gobject_class->set_property = gst_dvdec_set_property;
336 gobject_class->get_property = gst_dvdec_get_property;
338 gstelement_class->change_state = gst_dvdec_change_state;
340 /* table initialization, only do once */
344 /* This function is responsible for initializing a specific instance of
348 gst_dvdec_init (GstDVDec * dvdec)
352 dvdec->found_header = FALSE;
355 gst_pad_new_from_template (gst_static_pad_template_get (&sink_temp),
357 gst_pad_set_query_function (dvdec->sinkpad, NULL);
358 gst_pad_set_convert_function (dvdec->sinkpad,
359 GST_DEBUG_FUNCPTR (gst_dvdec_sink_convert));
360 gst_pad_set_formats_function (dvdec->sinkpad,
361 GST_DEBUG_FUNCPTR (gst_dvdec_get_formats));
362 gst_element_add_pad (GST_ELEMENT (dvdec), dvdec->sinkpad);
365 gst_pad_new_from_template (gst_static_pad_template_get (&video_src_temp),
367 gst_pad_set_query_function (dvdec->videosrcpad,
368 GST_DEBUG_FUNCPTR (gst_dvdec_src_query));
369 gst_pad_set_query_type_function (dvdec->videosrcpad,
370 GST_DEBUG_FUNCPTR (gst_dvdec_get_src_query_types));
371 gst_pad_set_event_function (dvdec->videosrcpad,
372 GST_DEBUG_FUNCPTR (gst_dvdec_handle_src_event));
373 gst_pad_set_event_mask_function (dvdec->videosrcpad,
374 GST_DEBUG_FUNCPTR (gst_dvdec_get_event_masks));
375 gst_pad_set_convert_function (dvdec->videosrcpad,
376 GST_DEBUG_FUNCPTR (gst_dvdec_src_convert));
377 gst_pad_set_formats_function (dvdec->videosrcpad,
378 GST_DEBUG_FUNCPTR (gst_dvdec_get_formats));
379 gst_pad_set_getcaps_function (dvdec->videosrcpad,
380 GST_DEBUG_FUNCPTR (gst_dvdec_video_getcaps));
381 gst_pad_set_link_function (dvdec->videosrcpad,
382 GST_DEBUG_FUNCPTR (gst_dvdec_video_link));
383 gst_element_add_pad (GST_ELEMENT (dvdec), dvdec->videosrcpad);
386 gst_pad_new_from_template (gst_static_pad_template_get (&audio_src_temp),
388 gst_pad_set_query_function (dvdec->audiosrcpad,
389 GST_DEBUG_FUNCPTR (gst_dvdec_src_query));
390 gst_pad_set_query_type_function (dvdec->audiosrcpad,
391 GST_DEBUG_FUNCPTR (gst_dvdec_get_src_query_types));
392 gst_pad_set_event_function (dvdec->audiosrcpad,
393 GST_DEBUG_FUNCPTR (gst_dvdec_handle_src_event));
394 gst_pad_set_event_mask_function (dvdec->audiosrcpad,
395 GST_DEBUG_FUNCPTR (gst_dvdec_get_event_masks));
396 gst_pad_set_convert_function (dvdec->audiosrcpad,
397 GST_DEBUG_FUNCPTR (gst_dvdec_src_convert));
398 gst_pad_set_formats_function (dvdec->audiosrcpad,
399 GST_DEBUG_FUNCPTR (gst_dvdec_get_formats));
400 gst_pad_use_explicit_caps (dvdec->audiosrcpad);
401 gst_element_add_pad (GST_ELEMENT (dvdec), dvdec->audiosrcpad);
403 gst_element_set_loop_function (GST_ELEMENT (dvdec), gst_dvdec_loop);
407 dvdec->next_ts = 0LL;
408 dvdec->end_position = -1LL;
409 dvdec->need_discont = FALSE;
410 dvdec->new_media = FALSE;
411 dvdec->framerate = 0;
413 dvdec->frequency = 0;
416 dvdec->drop_factor = 1;
418 dvdec->clamp_luma = FALSE;
419 dvdec->clamp_chroma = FALSE;
420 dvdec->quality = DV_DEFAULT_QUALITY;
423 for (i = 0; i < 4; i++) {
424 dvdec->audio_buffers[i] =
425 (gint16 *) g_malloc (DV_AUDIO_MAX_SAMPLES * sizeof (gint16));
429 static const GstFormat *
430 gst_dvdec_get_formats (GstPad * pad)
432 static const GstFormat src_formats[] = {
438 static const GstFormat sink_formats[] = {
445 return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
449 gst_dvdec_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
450 GstFormat * dest_format, gint64 * dest_value)
455 dvdec = GST_DVDEC (gst_pad_get_parent (pad));
456 if (dvdec->length == 0)
459 if (dvdec->decoder == NULL)
462 switch (src_format) {
463 case GST_FORMAT_BYTES:
464 switch (*dest_format) {
465 case GST_FORMAT_BYTES:
466 *dest_value = src_value;
468 case GST_FORMAT_DEFAULT:
469 case GST_FORMAT_TIME:
470 *dest_format = GST_FORMAT_TIME;
471 if (pad == dvdec->videosrcpad)
472 *dest_value = src_value * GST_SECOND /
473 (720 * dvdec->height * dvdec->bpp * dvdec->framerate /
475 else if (pad == dvdec->audiosrcpad)
476 *dest_value = src_value * GST_SECOND /
477 (2 * dvdec->frequency * dvdec->channels);
483 case GST_FORMAT_TIME:
484 switch (*dest_format) {
485 case GST_FORMAT_BYTES:
486 if (pad == dvdec->videosrcpad)
487 *dest_value = src_value * 720 * dvdec->height * dvdec->bpp *
488 dvdec->framerate / GST_SECOND;
489 else if (pad == dvdec->audiosrcpad)
490 *dest_value = 2 * src_value * dvdec->frequency *
491 dvdec->channels / GST_SECOND;
493 case GST_FORMAT_TIME:
494 case GST_FORMAT_DEFAULT:
495 *dest_format = GST_FORMAT_TIME;
496 *dest_value = src_value;
509 gst_dvdec_sink_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
510 GstFormat * dest_format, gint64 * dest_value)
515 dvdec = GST_DVDEC (gst_pad_get_parent (pad));
517 if (dvdec->length == 0)
520 if (*dest_format == GST_FORMAT_DEFAULT)
521 *dest_format = GST_FORMAT_TIME;
523 switch (src_format) {
524 case GST_FORMAT_BYTES:
525 switch (*dest_format) {
526 case GST_FORMAT_TIME:
530 /* get frame number */
531 frame = src_value / dvdec->length;
533 *dest_value = (frame * GST_SECOND) / dvdec->framerate;
536 case GST_FORMAT_BYTES:
537 *dest_value = src_value;
543 case GST_FORMAT_TIME:
544 switch (*dest_format) {
545 case GST_FORMAT_BYTES:
549 /* calculate the frame */
550 frame = src_value * dvdec->framerate / GST_SECOND;
551 /* calculate the offset */
552 *dest_value = frame * dvdec->length;
555 case GST_FORMAT_TIME:
556 *dest_value = src_value;
568 static const GstQueryType *
569 gst_dvdec_get_src_query_types (GstPad * pad)
571 static const GstQueryType src_query_types[] = {
577 return src_query_types;
581 gst_dvdec_src_query (GstPad * pad, GstQueryType type,
582 GstFormat * format, gint64 * value)
587 dvdec = GST_DVDEC (gst_pad_get_parent (pad));
590 case GST_QUERY_TOTAL:
595 GstFormat tmp_format;
600 len = gst_bytestream_length (dvdec->bs);
601 tmp_format = GST_FORMAT_TIME;
602 if (len == -1 || !gst_pad_convert (dvdec->sinkpad,
603 GST_FORMAT_BYTES, len, &tmp_format, value)) {
606 if (!gst_pad_convert (pad, GST_FORMAT_TIME, *value, format, value)) {
613 case GST_QUERY_POSITION:
617 gst_pad_convert (pad, GST_FORMAT_TIME, dvdec->next_ts, format,
629 static const GstEventMask *
630 gst_dvdec_get_event_masks (GstPad * pad)
632 static const GstEventMask src_event_masks[] = {
633 {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH},
636 static const GstEventMask sink_event_masks[] = {
638 {GST_EVENT_DISCONTINUOUS, 0},
639 {GST_EVENT_FLUSH, 0},
643 return (GST_PAD_IS_SRC (pad) ? src_event_masks : sink_event_masks);
647 gst_dvdec_handle_sink_event (GstDVDec * dvdec)
653 gst_bytestream_get_status (dvdec->bs, &remaining, &event);
655 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
658 case GST_EVENT_FLUSH:
660 case GST_EVENT_FILLER:
662 /* Forward the event to output sinks */
663 if (GST_PAD_IS_LINKED (dvdec->videosrcpad)) {
664 gst_event_ref (event);
665 gst_pad_push (dvdec->videosrcpad, GST_DATA (event));
667 if (GST_PAD_IS_LINKED (dvdec->audiosrcpad)) {
668 gst_event_ref (event);
669 gst_pad_push (dvdec->audiosrcpad, GST_DATA (event));
671 if (type == GST_EVENT_EOS) {
672 gst_element_set_eos (GST_ELEMENT (dvdec));
676 case GST_EVENT_DISCONTINUOUS:
679 gboolean found = FALSE;
682 format = GST_FORMAT_TIME;
683 /* try to get a timestamp from the discont formats */
684 for (i = 0; i < GST_EVENT_DISCONT_OFFSET_LEN (event); i++) {
685 if (gst_pad_convert (dvdec->sinkpad,
686 GST_EVENT_DISCONT_OFFSET (event, i).format,
687 GST_EVENT_DISCONT_OFFSET (event, i).value,
688 &format, &dvdec->next_ts)) {
695 dvdec->next_ts = 0LL;
697 dvdec->need_discont = TRUE;
701 return gst_pad_event_default (dvdec->sinkpad, event);
704 gst_event_unref (event);
709 gst_dvdec_handle_src_event (GstPad * pad, GstEvent * event)
714 dvdec = GST_DVDEC (gst_pad_get_parent (pad));
716 switch (GST_EVENT_TYPE (event)) {
717 case GST_EVENT_SEEK_SEGMENT:
722 /* first bring the format to time */
723 format = GST_FORMAT_TIME;
724 if (!gst_pad_convert (pad,
725 GST_EVENT_SEEK_FORMAT (event),
726 GST_EVENT_SEEK_ENDOFFSET (event), &format, &position)) {
727 /* could not convert seek format to time offset */
732 dvdec->end_position = position;
733 dvdec->loop = GST_EVENT_SEEK_TYPE (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
740 /* first bring the format to time */
741 format = GST_FORMAT_TIME;
742 if (!gst_pad_convert (pad,
743 GST_EVENT_SEEK_FORMAT (event),
744 GST_EVENT_SEEK_OFFSET (event), &format, &position)) {
745 /* could not convert seek format to time offset */
749 dvdec->next_ts = position;
750 /* then try to figure out the byteoffset for this time */
751 format = GST_FORMAT_BYTES;
752 if (!gst_pad_convert (dvdec->sinkpad, GST_FORMAT_TIME, position,
753 &format, &position)) {
754 /* could not convert seek format to byte offset */
759 if (!gst_bytestream_seek (dvdec->bs, position, GST_SEEK_METHOD_SET)) {
762 if (GST_EVENT_TYPE (event) != GST_EVENT_SEEK_SEGMENT)
763 dvdec->end_position = -1;
770 gst_event_unref (event);
775 gst_dvdec_video_getcaps (GstPad * pad)
779 GstPadTemplate *src_pad_template;
781 dvdec = GST_DVDEC (gst_pad_get_parent (pad));
782 src_pad_template = gst_static_pad_template_get (&video_src_temp);
783 caps = gst_caps_copy (gst_pad_template_get_caps (src_pad_template));
785 if (dvdec->found_header) {
791 par_x = PAL_WIDE_PAR_X;
792 par_y = PAL_WIDE_PAR_Y;
794 par_x = PAL_NORMAL_PAR_X;
795 par_y = PAL_NORMAL_PAR_Y;
799 par_x = NTSC_WIDE_PAR_X;
800 par_y = NTSC_WIDE_PAR_Y;
802 par_x = NTSC_NORMAL_PAR_X;
803 par_y = NTSC_NORMAL_PAR_Y;
807 for (i = 0; i < gst_caps_get_size (caps); i++) {
808 GstStructure *structure = gst_caps_get_structure (caps, i);
810 gst_structure_set (structure,
811 "height", G_TYPE_INT, dvdec->height,
812 "framerate", G_TYPE_DOUBLE, dvdec->framerate / dvdec->drop_factor,
813 "pixel-aspect-ratio", GST_TYPE_FRACTION, par_x, par_y, NULL);
820 static GstPadLinkReturn
821 gst_dvdec_video_link (GstPad * pad, const GstCaps * caps)
824 GstStructure *structure;
829 dvdec = GST_DVDEC (gst_pad_get_parent (pad));
831 /* if we did not find a header yet, return delayed */
832 if (!dvdec->found_header) {
833 return GST_PAD_LINK_DELAYED;
836 structure = gst_caps_get_structure (caps, 0);
838 if (!gst_structure_get_int (structure, "height", &height) ||
839 !gst_structure_get_double (structure, "framerate", &framerate))
840 return GST_PAD_LINK_REFUSED;
842 /* allow a margin of error for the framerate caused by float rounding errors */
843 if ((height != dvdec->height) ||
844 (fabs (framerate - (dvdec->framerate / dvdec->drop_factor)) > 0.00000001))
845 return GST_PAD_LINK_REFUSED;
847 if (strcmp (gst_structure_get_name (structure), "video/x-raw-rgb") == 0) {
850 gst_structure_get_int (structure, "bpp", &bpp);
852 dvdec->space = e_dv_color_rgb;
855 dvdec->space = e_dv_color_bgr0;
859 if (!gst_structure_get_fourcc (structure, "format", &fourcc))
860 return GST_PAD_LINK_REFUSED;
862 dvdec->space = e_dv_color_yuv;
866 return GST_PAD_LINK_OK;
870 gst_dvdec_push (GstDVDec * dvdec, GstBuffer * outbuf, GstPad * pad,
873 if ((dvdec->need_discont) || (dvdec->new_media)) {
876 discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, ts, NULL);
877 GST_EVENT_DISCONT_NEW_MEDIA (discont) = dvdec->new_media;
879 gst_pad_push (pad, GST_DATA (discont));
882 gst_pad_push (pad, GST_DATA (outbuf));
884 if ((dvdec->end_position != -1) && (dvdec->next_ts >= dvdec->end_position)) {
886 gst_pad_push (pad, GST_DATA (gst_event_new (GST_EVENT_SEGMENT_DONE)));
888 gst_pad_push (pad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
893 gst_dvdec_loop (GstElement * element)
896 GstBuffer *buf, *outbuf;
899 guint32 length, got_bytes;
900 GstClockTime ts, duration;
904 dvdec = GST_DVDEC (element);
907 * Apparently dv_parse_header can read from the body of the frame
908 * too, so it needs more than header_size bytes. Wacky!
910 if (dvdec->found_header)
911 length = (dvdec->PAL ? PAL_BUFFER : NTSC_BUFFER);
913 length = NTSC_BUFFER;
915 /* first read enough bytes to parse the header */
916 got_bytes = gst_bytestream_peek_bytes (dvdec->bs, &inframe, length);
917 if (got_bytes < length) {
918 gst_dvdec_handle_sink_event (dvdec);
921 if (dv_parse_header (dvdec->decoder, inframe) < 0) {
922 GST_ELEMENT_ERROR (dvdec, STREAM, DECODE, (NULL), (NULL));
926 /* after parsing the header we know the length of the data */
927 dvdec->PAL = dv_system_50_fields (dvdec->decoder);
928 dvdec->found_header = TRUE;
930 fps = (dvdec->PAL ? PAL_FRAMERATE : NTSC_FRAMERATE);
931 height = (dvdec->PAL ? PAL_HEIGHT : NTSC_HEIGHT);
932 length = (dvdec->PAL ? PAL_BUFFER : NTSC_BUFFER);
933 wide = dv_format_wide (dvdec->decoder);
935 if (length != dvdec->length) {
936 dvdec->length = length;
937 gst_bytestream_size_hint (dvdec->bs, length);
940 /* then read the read data */
941 got_bytes = gst_bytestream_read (dvdec->bs, &buf, length);
942 if (got_bytes < length) {
943 gst_dvdec_handle_sink_event (dvdec);
948 dvdec->next_ts += GST_SECOND / fps;
949 duration = dvdec->next_ts - ts;
951 dv_parse_packs (dvdec->decoder, GST_BUFFER_DATA (buf));
952 if (dv_is_new_recording (dvdec->decoder, GST_BUFFER_DATA (buf)))
953 dvdec->new_media = TRUE;
954 if (GST_PAD_IS_LINKED (dvdec->audiosrcpad)) {
957 dv_decode_full_audio (dvdec->decoder, GST_BUFFER_DATA (buf),
958 dvdec->audio_buffers);
960 if ((dv_get_frequency (dvdec->decoder) != dvdec->frequency) ||
961 (dv_get_num_channels (dvdec->decoder) != dvdec->channels)) {
962 if (!gst_pad_set_explicit_caps (dvdec->audiosrcpad,
963 gst_caps_new_simple ("audio/x-raw-int",
964 "rate", G_TYPE_INT, dv_get_frequency (dvdec->decoder),
965 "depth", G_TYPE_INT, 16,
966 "width", G_TYPE_INT, 16,
967 "signed", G_TYPE_BOOLEAN, TRUE,
968 "channels", G_TYPE_INT, dv_get_num_channels (dvdec->decoder),
969 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL))) {
970 gst_buffer_unref (buf);
971 GST_ELEMENT_ERROR (dvdec, CORE, NEGOTIATION, (NULL),
972 ("Failed to negotiate audio parameters for the DV audio stream"));
976 dvdec->frequency = dv_get_frequency (dvdec->decoder);
977 dvdec->channels = dv_get_num_channels (dvdec->decoder);
980 num_samples = dv_get_num_samples (dvdec->decoder);
986 outbuf = gst_buffer_new ();
987 GST_BUFFER_SIZE (outbuf) = dv_get_num_samples (dvdec->decoder) *
988 sizeof (gint16) * dv_get_num_channels (dvdec->decoder);
989 GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf));
991 a_ptr = (gint16 *) GST_BUFFER_DATA (outbuf);
993 for (i = 0; i < num_samples; i++) {
994 for (j = 0; j < dv_get_num_channels (dvdec->decoder); j++) {
995 *(a_ptr++) = dvdec->audio_buffers[j][i];
999 GST_BUFFER_TIMESTAMP (outbuf) = ts;
1000 GST_BUFFER_DURATION (outbuf) = duration;
1001 GST_BUFFER_OFFSET (outbuf) = dvdec->audio_offset;
1002 dvdec->audio_offset += num_samples;
1003 GST_BUFFER_OFFSET_END (outbuf) = dvdec->audio_offset;
1005 gst_dvdec_push (dvdec, outbuf, dvdec->audiosrcpad, ts);
1008 dvdec->frequency = dv_get_frequency (dvdec->decoder);
1009 dvdec->channels = dv_get_num_channels (dvdec->decoder);
1012 if (GST_PAD_IS_LINKED (dvdec->videosrcpad)) {
1014 guint8 *outframe_ptrs[3];
1015 gint outframe_pitches[3];
1017 dvdec->framecount++;
1018 if (dvdec->framecount < dvdec->drop_factor) {
1022 dvdec->framecount = 0;
1024 if ((dvdec->framerate != fps) || (dvdec->height != height)
1025 || dvdec->wide != wide) {
1026 dvdec->height = height;
1027 dvdec->framerate = fps;
1030 if (GST_PAD_LINK_FAILED (gst_pad_renegotiate (dvdec->videosrcpad))) {
1031 GST_ELEMENT_ERROR (dvdec, CORE, NEGOTIATION, (NULL), (NULL));
1036 outbuf = gst_buffer_new_and_alloc ((720 * height) * dvdec->bpp);
1038 outframe = GST_BUFFER_DATA (outbuf);
1040 outframe_ptrs[0] = outframe;
1041 outframe_pitches[0] = 720 * dvdec->bpp;
1043 /* the rest only matters for YUY2 */
1044 if (dvdec->bpp < 3) {
1045 outframe_ptrs[1] = outframe_ptrs[0] + 720 * height;
1046 outframe_ptrs[2] = outframe_ptrs[1] + 360 * height;
1048 outframe_pitches[1] = height / 2;
1049 outframe_pitches[2] = outframe_pitches[1];
1052 dv_decode_full_frame (dvdec->decoder, GST_BUFFER_DATA (buf),
1053 dvdec->space, outframe_ptrs, outframe_pitches);
1055 GST_BUFFER_TIMESTAMP (outbuf) = ts;
1056 GST_BUFFER_DURATION (outbuf) = duration * dvdec->drop_factor;
1058 gst_dvdec_push (dvdec, outbuf, dvdec->videosrcpad, ts);
1060 dvdec->height = height;
1061 dvdec->framerate = fps;
1066 if ((dvdec->end_position != -1) &&
1067 (dvdec->next_ts >= dvdec->end_position) && !dvdec->loop) {
1068 gst_element_set_eos (GST_ELEMENT (dvdec));
1071 dvdec->need_discont = FALSE;
1072 dvdec->new_media = FALSE;
1074 gst_buffer_unref (buf);
1077 static GstElementStateReturn
1078 gst_dvdec_change_state (GstElement * element)
1080 GstDVDec *dvdec = GST_DVDEC (element);
1082 switch (GST_STATE_TRANSITION (element)) {
1083 case GST_STATE_NULL_TO_READY:
1085 case GST_STATE_READY_TO_PAUSED:
1086 dvdec->bs = gst_bytestream_new (dvdec->sinkpad);
1088 dv_decoder_new (0, dvdec->clamp_luma, dvdec->clamp_chroma);
1089 dvdec->decoder->quality = qualities[dvdec->quality];
1090 dvdec->audio_offset = 0;
1091 dvdec->framecount = 0;
1093 * Enable this function call when libdv2 0.100 or higher is more
1096 /* dv_set_quality (dvdec->decoder, qualities [dvdec->quality]); */
1098 case GST_STATE_PAUSED_TO_PLAYING:
1100 case GST_STATE_PLAYING_TO_PAUSED:
1102 case GST_STATE_PAUSED_TO_READY:
1103 dv_decoder_free (dvdec->decoder);
1104 dvdec->decoder = NULL;
1105 dvdec->found_header = FALSE;
1106 gst_bytestream_destroy (dvdec->bs);
1109 case GST_STATE_READY_TO_NULL:
1115 return parent_class->change_state (element);
1118 /* Arguments are part of the Gtk+ object system, and these functions
1119 * enable the element to respond to various arguments.
1122 gst_dvdec_set_property (GObject * object, guint prop_id, const GValue * value,
1127 /* It's not null if we got it, but it might not be ours */
1128 g_return_if_fail (GST_IS_DVDEC (object));
1130 /* Get a pointer of the right type. */
1131 dvdec = GST_DVDEC (object);
1133 /* Check the argument id to see which argument we're setting. */
1135 case ARG_CLAMP_LUMA:
1136 dvdec->clamp_luma = g_value_get_boolean (value);
1138 case ARG_CLAMP_CHROMA:
1139 dvdec->clamp_chroma = g_value_get_boolean (value);
1142 dvdec->quality = g_value_get_enum (value);
1143 if ((dvdec->quality < 0) || (dvdec->quality > 5))
1146 case ARG_DECODE_NTH:
1147 dvdec->drop_factor = g_value_get_int (value);
1150 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1155 /* The set function is simply the inverse of the get fuction. */
1157 gst_dvdec_get_property (GObject * object, guint prop_id, GValue * value,
1162 /* It's not null if we got it, but it might not be ours */
1163 g_return_if_fail (GST_IS_DVDEC (object));
1164 dvdec = GST_DVDEC (object);
1167 case ARG_CLAMP_LUMA:
1168 g_value_set_boolean (value, dvdec->clamp_luma);
1170 case ARG_CLAMP_CHROMA:
1171 g_value_set_boolean (value, dvdec->clamp_chroma);
1174 g_value_set_enum (value, dvdec->quality);
1176 case ARG_DECODE_NTH:
1177 g_value_set_int (value, dvdec->drop_factor);
1180 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1185 /* This is the entry into the plugin itself. When the plugin loads,
1186 * this function is called to register everything that the plugin provides.
1189 plugin_init (GstPlugin * plugin)
1191 if (!gst_library_load ("gstbytestream"))
1194 if (!gst_element_register (plugin, "dvdec", GST_RANK_PRIMARY,
1195 gst_dvdec_get_type ()))
1201 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1204 "Uses libdv to decode DV video (libdv.sourceforge.net)",
1205 plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN);