2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2001 Billy Biggs <vektor@dumbterm.net>.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
31 #include <sys/ioctl.h>
32 #include <sys/types.h>
34 #include <sys/types.h>
37 //#include <linux/cdrom.h>
40 #include "dvdreadsrc.h"
41 #include "stream_labels.h"
43 #include <dvdread/dvd_reader.h>
44 #include <dvdread/ifo_types.h>
45 #include <dvdread/ifo_read.h>
46 #include <dvdread/nav_read.h>
47 #include <dvdread/nav_print.h>
49 struct _DVDReadSrcPrivate
62 int title, chapter, angle;
63 int pgc_id, start_cell, cur_cell, cur_pack;
65 int ttn, pgn, next_cell;
67 dvd_file_t *dvd_title;
68 ifo_handle_t *vmg_file;
70 ifo_handle_t *vts_file;
71 vts_ptt_srpt_t *vts_ptt_srpt;
75 gboolean seek_pend, flush_pend;
76 GstFormat seek_pend_fmt;
79 GST_DEBUG_CATEGORY_STATIC (gstdvdreadsrc_debug);
80 #define GST_CAT_DEFAULT (gstdvdreadsrc_debug)
82 GstElementDetails dvdreadsrc_details = {
85 "Access a DVD title/chapter/angle using libdvdread",
86 "Erik Walthinsen <omega@cse.ogi.edu>",
90 /* DVDReadSrc signals and args */
107 static void dvdreadsrc_base_init (gpointer g_class);
108 static void dvdreadsrc_class_init (DVDReadSrcClass * klass);
109 static void dvdreadsrc_init (DVDReadSrc * dvdreadsrc);
110 static void dvdreadsrc_finalize (GObject * object);
112 static void dvdreadsrc_set_property (GObject * object, guint prop_id,
113 const GValue * value, GParamSpec * pspec);
114 static void dvdreadsrc_get_property (GObject * object, guint prop_id,
115 GValue * value, GParamSpec * pspec);
117 static const GstEventMask *dvdreadsrc_get_event_mask (GstPad * pad);
118 static const GstQueryType *dvdreadsrc_get_query_types (GstPad * pad);
119 static const GstFormat *dvdreadsrc_get_formats (GstPad * pad);
120 static gboolean dvdreadsrc_srcpad_event (GstPad * pad, GstEvent * event);
121 static gboolean dvdreadsrc_srcpad_query (GstPad * pad, GstQueryType type,
122 GstFormat * format, gint64 * value);
124 static GstData *dvdreadsrc_get (GstPad * pad);
125 static GstStateChangeReturn dvdreadsrc_change_state (GstElement * element,
126 GstStateChange transition);
128 static void dvdreadsrc_uri_handler_init (gpointer g_iface, gpointer iface_data);
131 static GstElementClass *parent_class = NULL;
133 static GstFormat sector_format, angle_format, title_format, chapter_format;
135 /*static guint dvdreadsrc_signals[LAST_SIGNAL] = { 0 }; */
138 dvdreadsrc_get_type (void)
140 static GType dvdreadsrc_type = 0;
142 if (!dvdreadsrc_type) {
143 static const GTypeInfo dvdreadsrc_info = {
144 sizeof (DVDReadSrcClass),
145 dvdreadsrc_base_init,
147 (GClassInitFunc) dvdreadsrc_class_init,
152 (GInstanceInitFunc) dvdreadsrc_init,
154 static const GInterfaceInfo urihandler_info = {
155 dvdreadsrc_uri_handler_init,
160 sector_format = gst_format_register ("sector", "DVD sector");
161 title_format = gst_format_register ("title", "DVD title");
162 chapter_format = gst_format_register ("chapter", "DVD chapter");
163 angle_format = gst_format_register ("angle", "DVD angle");
166 g_type_register_static (GST_TYPE_ELEMENT, "DVDReadSrc",
167 &dvdreadsrc_info, 0);
168 g_type_add_interface_static (dvdreadsrc_type,
169 GST_TYPE_URI_HANDLER, &urihandler_info);
172 return dvdreadsrc_type;
176 dvdreadsrc_base_init (gpointer g_class)
178 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
180 gst_element_class_set_details (element_class, &dvdreadsrc_details);
184 dvdreadsrc_class_init (DVDReadSrcClass * klass)
186 GObjectClass *gobject_class;
187 GstElementClass *gstelement_class;
189 gobject_class = (GObjectClass *) klass;
190 gstelement_class = (GstElementClass *) klass;
192 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
194 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION,
195 g_param_spec_string ("location", "Location",
196 "DVD device location (deprecated; use device)",
197 NULL, G_PARAM_READWRITE));
198 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE,
199 g_param_spec_string ("device", "Device",
200 "DVD device location", NULL, G_PARAM_READWRITE));
201 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TITLE,
202 g_param_spec_int ("title", "title", "title",
203 0, G_MAXINT, 0, G_PARAM_READWRITE));
204 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CHAPTER,
205 g_param_spec_int ("chapter", "chapter", "chapter",
206 0, G_MAXINT, 0, G_PARAM_READWRITE));
207 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ANGLE,
208 g_param_spec_int ("angle", "angle", "angle",
209 0, G_MAXINT, 0, G_PARAM_READWRITE));
211 gobject_class->set_property = GST_DEBUG_FUNCPTR (dvdreadsrc_set_property);
212 gobject_class->get_property = GST_DEBUG_FUNCPTR (dvdreadsrc_get_property);
214 gobject_class->finalize = dvdreadsrc_finalize;
216 gstelement_class->change_state = dvdreadsrc_change_state;
218 GST_DEBUG_CATEGORY_INIT (gstdvdreadsrc_debug, "dvdreadsrc", 0,
219 "DVD reader element based on dvdreadsrc");
223 dvdreadsrc_init (DVDReadSrc * dvdreadsrc)
225 dvdreadsrc->priv = g_new (DVDReadSrcPrivate, 1);
226 dvdreadsrc->priv->srcpad = gst_pad_new ("src", GST_PAD_SRC);
227 gst_pad_set_get_function (dvdreadsrc->priv->srcpad, dvdreadsrc_get);
228 gst_pad_set_event_function (dvdreadsrc->priv->srcpad,
229 dvdreadsrc_srcpad_event);
230 gst_pad_set_event_mask_function (dvdreadsrc->priv->srcpad,
231 dvdreadsrc_get_event_mask);
232 gst_pad_set_query_function (dvdreadsrc->priv->srcpad,
233 dvdreadsrc_srcpad_query);
234 gst_pad_set_query_type_function (dvdreadsrc->priv->srcpad,
235 dvdreadsrc_get_query_types);
236 gst_pad_set_formats_function (dvdreadsrc->priv->srcpad,
237 dvdreadsrc_get_formats);
238 gst_element_add_pad (GST_ELEMENT (dvdreadsrc), dvdreadsrc->priv->srcpad);
240 dvdreadsrc->priv->dvd = NULL;
241 dvdreadsrc->priv->vts_file = NULL;
242 dvdreadsrc->priv->vmg_file = NULL;
243 dvdreadsrc->priv->dvd_title = NULL;
245 dvdreadsrc->priv->location = g_strdup ("/dev/dvd");
246 dvdreadsrc->priv->last_uri = NULL;
247 dvdreadsrc->priv->new_seek = TRUE;
248 dvdreadsrc->priv->new_cell = TRUE;
249 dvdreadsrc->priv->title = 0;
250 dvdreadsrc->priv->chapter = 0;
251 dvdreadsrc->priv->angle = 0;
253 dvdreadsrc->priv->seek_pend = FALSE;
254 dvdreadsrc->priv->flush_pend = FALSE;
255 dvdreadsrc->priv->seek_pend_fmt = GST_FORMAT_UNDEFINED;
259 dvdreadsrc_finalize (GObject * object)
261 DVDReadSrc *dvdreadsrc = DVDREADSRC (object);
263 if (dvdreadsrc->priv) {
264 g_free (dvdreadsrc->priv->location);
265 g_free (dvdreadsrc->priv->last_uri);
266 g_free (dvdreadsrc->priv);
267 dvdreadsrc->priv = NULL;
269 G_OBJECT_CLASS (parent_class)->finalize (object);
273 dvdreadsrc_set_property (GObject * object, guint prop_id, const GValue * value,
277 DVDReadSrcPrivate *priv;
279 g_return_if_fail (GST_IS_DVDREADSRC (object));
281 src = DVDREADSRC (object);
287 /* the element must be stopped in order to do this */
288 /*g_return_if_fail(!GST_FLAG_IS_SET(src,GST_STATE_RUNNING)); */
290 g_free (priv->location);
291 /* clear the filename if we get a NULL (is that possible?) */
292 if (g_value_get_string (value) == NULL)
293 priv->location = g_strdup ("/dev/dvd");
294 /* otherwise set the new filename */
296 priv->location = g_strdup (g_value_get_string (value));
299 priv->title = g_value_get_int (value);
300 priv->new_seek = TRUE;
303 priv->chapter = g_value_get_int (value);
304 priv->new_seek = TRUE;
307 priv->angle = g_value_get_int (value);
310 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
317 dvdreadsrc_get_property (GObject * object, guint prop_id, GValue * value,
321 DVDReadSrcPrivate *priv;
323 g_return_if_fail (GST_IS_DVDREADSRC (object));
325 src = DVDREADSRC (object);
331 g_value_set_string (value, priv->location);
334 g_value_set_int (value, priv->title);
337 g_value_set_int (value, priv->chapter);
340 g_value_set_int (value, priv->angle);
343 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
349 * Querying and seeking.
352 static const GstEventMask *
353 dvdreadsrc_get_event_mask (GstPad * pad)
355 static const GstEventMask masks[] = {
356 {GST_EVENT_SEEK, GST_SEEK_METHOD_CUR |
357 GST_SEEK_METHOD_SET | GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH},
364 static const GstQueryType *
365 dvdreadsrc_get_query_types (GstPad * pad)
367 static const GstQueryType types[] = {
376 static const GstFormat *
377 dvdreadsrc_get_formats (GstPad * pad)
379 static GstFormat formats[] = {
381 0, 0, 0, 0, /* init later */
384 if (formats[1] == 0) {
385 formats[1] = sector_format;
386 formats[2] = angle_format;
387 formats[3] = title_format;
388 formats[4] = chapter_format;
395 dvdreadsrc_srcpad_event (GstPad * pad, GstEvent * event)
397 DVDReadSrc *dvdreadsrc = DVDREADSRC (gst_pad_get_parent (pad));
400 switch (GST_EVENT_TYPE (event)) {
401 case GST_EVENT_SEEK:{
402 gint64 new_off, total, cur;
405 /* get requested offset */
406 new_off = GST_EVENT_SEEK_OFFSET (event);
407 switch (GST_EVENT_SEEK_FORMAT (event)) {
408 case GST_FORMAT_BYTES:
409 new_off /= DVD_VIDEO_LB_LEN;
413 fmt = GST_EVENT_SEEK_FORMAT (event);
414 if (fmt == sector_format ||
415 fmt == angle_format ||
416 fmt == title_format || fmt == chapter_format)
418 GST_LOG ("Unsupported seek format");
422 /* get current offset and length */
423 gst_pad_query (pad, GST_QUERY_TOTAL, &fmt, &total);
424 gst_pad_query (pad, GST_QUERY_POSITION, &fmt, &cur);
425 if (cur == new_off) {
426 GST_LOG ("We're already at that position!");
431 switch (GST_EVENT_SEEK_METHOD (event)) {
432 case GST_SEEK_METHOD_SET:
435 case GST_SEEK_METHOD_CUR:
438 case GST_SEEK_METHOD_END:
439 new_off = total - new_off;
442 GST_LOG ("Unsupported seek method");
445 if (new_off < 0 || new_off >= total) {
446 GST_LOG ("Invalid seek position");
450 GST_LOG ("Seeking to unit %d in format %d", new_off, fmt);
452 if (fmt == sector_format || fmt == chapter_format || fmt == title_format) {
453 if (fmt == sector_format) {
454 dvdreadsrc->priv->cur_pack = new_off;
455 } else if (fmt == chapter_format) {
456 dvdreadsrc->priv->cur_pack = 0;
457 dvdreadsrc->priv->chapter = new_off;
458 dvdreadsrc->priv->seek_pend_fmt = fmt;
459 } else if (fmt == title_format) {
460 dvdreadsrc->priv->cur_pack = 0;
461 dvdreadsrc->priv->title = new_off;
462 dvdreadsrc->priv->chapter = 0;
463 dvdreadsrc->priv->seek_pend_fmt = fmt;
466 /* leave for events */
467 dvdreadsrc->priv->seek_pend = TRUE;
468 if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH)
469 dvdreadsrc->priv->flush_pend = TRUE;
470 } else if (fmt == angle_format) {
471 dvdreadsrc->priv->angle = new_off;
481 gst_event_unref (event);
487 dvdreadsrc_srcpad_query (GstPad * pad, GstQueryType type,
488 GstFormat * format, gint64 * value)
490 DVDReadSrc *dvdreadsrc = DVDREADSRC (gst_pad_get_parent (pad));
491 DVDReadSrcPrivate *priv = dvdreadsrc->priv;
494 if (!GST_FLAG_IS_SET (dvdreadsrc, DVDREADSRC_OPEN))
498 case GST_QUERY_TOTAL:
500 case GST_FORMAT_BYTES:
501 *value = DVDFileSize (priv->dvd_title) * DVD_VIDEO_LB_LEN;
504 if (*format == sector_format) {
505 *value = DVDFileSize (priv->dvd_title);
506 } else if (*format == title_format) {
507 *value = priv->tt_srpt->nr_of_srpts;
508 } else if (*format == chapter_format) {
509 *value = priv->tt_srpt->title[priv->title].nr_of_ptts;
510 } else if (*format == angle_format) {
511 *value = priv->tt_srpt->title[priv->title].nr_of_angles;
513 GST_LOG ("Unknown format");
519 case GST_QUERY_POSITION:
521 case GST_FORMAT_BYTES:
522 *value = priv->cur_pack * DVD_VIDEO_LB_LEN;
525 if (*format == sector_format) {
526 *value = priv->cur_pack;
527 } else if (*format == title_format) {
528 *value = priv->title;
529 } else if (*format == chapter_format) {
530 *value = priv->chapter;
531 } else if (*format == angle_format) {
532 *value = priv->angle;
534 GST_LOG ("Unknown format");
549 * Returns true if the pack is a NAV pack. This check is clearly insufficient,
550 * and sometimes we incorrectly think that valid other packs are NAV packs. I
551 * need to make this stronger.
554 is_nav_pack (unsigned char *buffer)
556 return (buffer[41] == 0xbf && buffer[1027] == 0xbf);
560 _close (DVDReadSrcPrivate * priv)
562 ifoClose (priv->vts_file);
563 priv->vts_file = NULL;
565 ifoClose (priv->vmg_file);
566 priv->vmg_file = NULL;
568 DVDCloseFile (priv->dvd_title);
569 priv->dvd_title = NULL;
571 DVDClose (priv->dvd);
578 _open (DVDReadSrcPrivate * priv, const gchar * location)
580 g_return_val_if_fail (priv != NULL, -1);
581 g_return_val_if_fail (location != NULL, -1);
586 priv->dvd = DVDOpen (location);
588 GST_ERROR ("Couldn't open DVD: %s", location);
594 * Load the video manager to find out the information about the titles on
597 priv->vmg_file = ifoOpen (priv->dvd, 0);
598 if (!priv->vmg_file) {
599 GST_ERROR ("Can't open VMG info");
602 priv->tt_srpt = priv->vmg_file->tt_srpt;
608 _seek_title (DVDReadSrcPrivate * priv, int title, int angle)
610 GHashTable *languagelist = NULL;
613 * Make sure our title number is valid.
615 GST_LOG ("There are %d titles on this DVD", priv->tt_srpt->nr_of_srpts);
616 if (title < 0 || title >= priv->tt_srpt->nr_of_srpts) {
617 GST_WARNING ("Invalid title %d (only %d available)",
618 title, priv->tt_srpt->nr_of_srpts);
623 title = priv->tt_srpt->nr_of_srpts - 1;
626 GST_LOG ("There are %d chapters in this title",
627 priv->tt_srpt->title[title].nr_of_ptts);
630 * Make sure the angle number is valid for this title.
632 GST_LOG ("There are %d angles available in this title",
633 priv->tt_srpt->title[title].nr_of_angles);
635 if (angle < 0 || angle >= priv->tt_srpt->title[title].nr_of_angles) {
636 GST_WARNING ("Invalid angle %d (only %d available)",
637 angle, priv->tt_srpt->title[title].nr_of_angles);
641 angle = priv->tt_srpt->title[title].nr_of_angles - 1;
645 * Load the VTS information for the title set our title is in.
648 ifoOpen (priv->dvd, priv->tt_srpt->title[title].title_set_nr);
649 if (!priv->vts_file) {
650 GST_ERROR ("Can't open the info file of title %d",
651 priv->tt_srpt->title[title].title_set_nr);
656 priv->ttn = priv->tt_srpt->title[title].vts_ttn;
657 priv->vts_ptt_srpt = priv->vts_file->vts_ptt_srpt;
660 * We've got enough info, time to open the title set data.
663 DVDOpenFile (priv->dvd, priv->tt_srpt->title[title].title_set_nr,
664 DVD_READ_TITLE_VOBS);
665 if (!priv->dvd_title) {
666 GST_ERROR ("Can't open title VOBS (VTS_%02d_1.VOB)",
667 priv->tt_srpt->title[title].title_set_nr);
672 /* Get stream labels for all audio and subtitle streams */
673 languagelist = dvdreadsrc_init_languagelist ();
675 dvdreadsrc_get_audio_stream_labels (priv->vts_file, languagelist);
676 dvdreadsrc_get_subtitle_stream_labels (priv->vts_file, languagelist);
678 g_hash_table_destroy (languagelist);
680 GST_LOG ("Opened title %d, angle %d", title, angle);
688 _seek_chapter (DVDReadSrcPrivate * priv, int chapter)
693 * Make sure the chapter number is valid for this title.
695 if (chapter < 0 || chapter >= priv->tt_srpt->title[priv->title].nr_of_ptts) {
696 GST_WARNING ("Invalid chapter %d (only %d available)",
697 chapter, priv->tt_srpt->title[priv->title].nr_of_ptts);
700 chapter = priv->tt_srpt->title[priv->title].nr_of_ptts - 1;
704 * Determine which program chain we want to watch. This is based on the
707 priv->pgc_id = priv->vts_ptt_srpt->title[priv->ttn - 1].ptt[chapter].pgcn;
708 priv->pgn = priv->vts_ptt_srpt->title[priv->ttn - 1].ptt[chapter].pgn;
709 priv->cur_pgc = priv->vts_file->vts_pgcit->pgci_srp[priv->pgc_id - 1].pgc;
710 priv->start_cell = priv->cur_pgc->program_map[priv->pgn - 1] - 1;
712 if (chapter + 1 == priv->tt_srpt->title[priv->title].nr_of_ptts) {
713 priv->last_cell = priv->cur_pgc->nr_of_cells;
716 priv->cur_pgc->program_map[(priv->vts_ptt_srpt->title[priv->ttn -
717 1].ptt[chapter + 1].pgn) - 1] - 1;
720 GST_LOG ("Opened chapter %d - cell %d-%d",
721 chapter, priv->start_cell, priv->last_cell);
723 /* retrieve position */
725 for (i = 0; i < chapter; i++) {
728 c1 = priv->cur_pgc->program_map[(priv->vts_ptt_srpt->title[priv->ttn -
729 1].ptt[i].pgn) - 1] - 1;
730 if (i + 1 == priv->tt_srpt->title[priv->title].nr_of_ptts) {
731 c2 = priv->cur_pgc->nr_of_cells;
733 c2 = priv->cur_pgc->program_map[(priv->vts_ptt_srpt->title[priv->ttn -
734 1].ptt[i + 1].pgn) - 1] - 1;
737 for (; c1 < c2; c1++) {
739 priv->cur_pgc->cell_playback[c1].last_sector -
740 priv->cur_pgc->cell_playback[c1].first_sector;
744 /* prepare reading for new cell */
745 priv->new_cell = TRUE;
746 priv->next_cell = priv->start_cell;
748 priv->chapter = chapter;
753 get_next_cell_for (DVDReadSrcPrivate * priv, int cell)
755 /* Check if we're entering an angle block. */
756 if (priv->cur_pgc->cell_playback[cell].block_type == BLOCK_TYPE_ANGLE_BLOCK) {
760 if (priv->cur_pgc->cell_playback[cell + i].block_mode
761 == BLOCK_MODE_LAST_CELL) {
774 * -1: error, -2: eos, -3: try again, 0: ok.
778 _read (DVDReadSrcPrivate * priv, int angle, int new_seek, GstBuffer * buf)
780 unsigned char *data, static_data[DVD_VIDEO_LB_LEN];
783 data = GST_BUFFER_DATA (buf);
789 * Playback by cell in this pgc, starting at the cell for our chapter.
792 priv->cur_cell = priv->start_cell;
796 if (priv->cur_cell < priv->last_cell) {
797 if (priv->new_cell || new_seek) {
799 priv->cur_cell = priv->next_cell;
800 if (priv->cur_cell >= priv->last_cell) {
801 GST_LOG ("last cell in chapter");
806 /* take angle into account */
807 if (priv->cur_pgc->cell_playback[priv->cur_cell].block_type
808 == BLOCK_TYPE_ANGLE_BLOCK)
809 priv->cur_cell += angle;
811 /* calculate next cell */
812 priv->next_cell = get_next_cell_for (priv, priv->cur_cell);
815 * We loop until we're out of this cell.
818 priv->cur_pgc->cell_playback[priv->cur_cell].first_sector;
819 priv->new_cell = FALSE;
823 priv->cur_pgc->cell_playback[priv->cur_cell].last_sector) {
825 unsigned int next_vobu, next_ilvu_start, cur_output_size;
833 len = DVDReadBlocks (priv->dvd_title, priv->cur_pack, 1, data);
835 GST_ERROR ("Read failed for block %d", priv->cur_pack);
839 if (!is_nav_pack (data)) {
846 * Parse the contained dsi packet.
848 navRead_DSI (&dsi_pack, &(data[DSI_START_BYTE]));
849 assert (priv->cur_pack == dsi_pack.dsi_gi.nv_pck_lbn);
853 * Determine where we go next. These values are the ones we mostly
856 next_ilvu_start = priv->cur_pack + dsi_pack.sml_agli.data[angle].address;
857 cur_output_size = dsi_pack.dsi_gi.vobu_ea;
861 * If we're not at the end of this cell, we can determine the next
862 * VOBU to display using the VOBU_SRI information section of the
863 * DSI. Using this value correctly follows the current angle,
864 * avoiding the doubled scenes in The Matrix, and makes our life
867 * Otherwise, we set our next address past the end of this cell to
868 * force the code above to go to the next cell in the program.
870 if (dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL) {
871 next_vobu = priv->cur_pack + (dsi_pack.vobu_sri.next_vobu & 0x7fffffff);
873 next_vobu = priv->cur_pack + cur_output_size + 1;
876 assert (cur_output_size < 1024);
881 * Read in and output cursize packs.
884 DVDReadBlocks (priv->dvd_title, priv->cur_pack, cur_output_size,
886 if (len != cur_output_size) {
887 GST_ERROR ("Read failed for %d blocks at %d",
888 cur_output_size, priv->cur_pack);
892 GST_BUFFER_SIZE (buf) = cur_output_size * DVD_VIDEO_LB_LEN;
893 //GST_BUFFER_OFFSET (buf) = priv->cur_pack * DVD_VIDEO_LB_LEN;
896 priv->cur_pack = next_vobu;
898 GST_LOG ("done reading data - %u sectors", cur_output_size);
902 priv->new_cell = TRUE;
905 /* swap to next chapter */
906 if (priv->chapter + 1 == priv->tt_srpt->title[priv->title].nr_of_ptts) {
907 GST_LOG ("last chapter done - eos");
911 GST_LOG ("end-of-chapter, switch to next");
914 _seek_chapter (priv, priv->chapter);
918 GST_LOG ("Need another try");
924 seek_sector (DVDReadSrcPrivate * priv, int angle)
926 gint seek_to = priv->cur_pack;
927 gint chapter, sectors, next, cur, i;
929 /* retrieve position */
931 for (i = 0; i < priv->tt_srpt->title[priv->title].nr_of_ptts; i++) {
934 c1 = priv->cur_pgc->program_map[(priv->vts_ptt_srpt->title[priv->ttn -
935 1].ptt[i].pgn) - 1] - 1;
936 if (i + 1 == priv->tt_srpt->title[priv->title].nr_of_ptts) {
937 c2 = priv->cur_pgc->nr_of_cells;
939 c2 = priv->cur_pgc->program_map[(priv->vts_ptt_srpt->title[priv->ttn -
940 1].ptt[i + 1].pgn) - 1] - 1;
943 for (next = cur = c1; cur < c2;) {
946 priv->cur_pgc->cell_playback[cur].last_sector -
947 priv->cur_pgc->cell_playback[cur].first_sector;
948 if (priv->cur_pack + sectors > seek_to) {
952 priv->cur_pack += sectors;
955 if (priv->cur_pgc->cell_playback[cur].block_type
956 == BLOCK_TYPE_ANGLE_BLOCK)
958 next = get_next_cell_for (priv, cur);
962 GST_LOG ("Seek to sector %u failed", seek_to);
966 /* so chapter $chapter and cell $cur contain our sector
967 * of interest. Let's go there! */
968 GST_LOG ("Seek succeeded, going to chapter %u, cell %u", chapter, cur);
970 _seek_chapter (priv, chapter);
971 priv->cur_cell = cur;
972 priv->next_cell = next;
973 priv->new_cell = FALSE;
974 priv->cur_pack = seek_to;
980 dvdreadsrc_get (GstPad * pad)
983 DVDReadSrc *dvdreadsrc;
984 DVDReadSrcPrivate *priv;
987 g_return_val_if_fail (pad != NULL, NULL);
988 g_return_val_if_fail (GST_IS_PAD (pad), NULL);
990 dvdreadsrc = DVDREADSRC (gst_pad_get_parent (pad));
991 priv = dvdreadsrc->priv;
992 g_return_val_if_fail (GST_FLAG_IS_SET (dvdreadsrc, DVDREADSRC_OPEN), NULL);
994 /* handle vents, if any */
995 if (priv->seek_pend) {
996 if (priv->flush_pend) {
997 priv->flush_pend = FALSE;
999 return GST_DATA (gst_event_new (GST_EVENT_FLUSH));
1002 priv->seek_pend = FALSE;
1003 if (priv->seek_pend_fmt != GST_FORMAT_UNDEFINED) {
1004 if (priv->seek_pend_fmt == title_format) {
1005 _seek_title (priv, priv->title, priv->angle);
1007 _seek_chapter (priv, priv->chapter);
1009 priv->seek_pend_fmt = GST_FORMAT_UNDEFINED;
1011 if (!seek_sector (priv, priv->angle)) {
1012 gst_element_set_eos (GST_ELEMENT (dvdreadsrc));
1013 return GST_DATA (gst_event_new (GST_EVENT_EOS));
1017 return GST_DATA (gst_event_new_discontinuous (FALSE,
1018 GST_FORMAT_BYTES, (gint64) (priv->cur_pack * DVD_VIDEO_LB_LEN),
1019 GST_FORMAT_UNDEFINED));
1022 /* create the buffer */
1023 /* FIXME: should eventually use a bufferpool for this */
1024 buf = gst_buffer_new_and_alloc (1024 * DVD_VIDEO_LB_LEN);
1026 if (priv->new_seek) {
1027 _seek_title (priv, priv->title, priv->angle);
1028 _seek_chapter (priv, priv->chapter);
1031 /* read it in from the file */
1032 while ((res = _read (priv, priv->angle, priv->new_seek, buf)) == -3);
1035 GST_ELEMENT_ERROR (dvdreadsrc, RESOURCE, READ, (NULL), (NULL));
1036 gst_buffer_unref (buf);
1039 gst_element_set_eos (GST_ELEMENT (dvdreadsrc));
1040 gst_buffer_unref (buf);
1041 return GST_DATA (gst_event_new (GST_EVENT_EOS));
1045 g_assert_not_reached ();
1048 priv->new_seek = FALSE;
1050 return GST_DATA (buf);
1053 /* open the file, necessary to go to RUNNING state */
1055 dvdreadsrc_open_file (DVDReadSrc * src)
1057 g_return_val_if_fail (src != NULL, FALSE);
1058 g_return_val_if_fail (GST_IS_DVDREADSRC (src), FALSE);
1059 g_return_val_if_fail (!GST_FLAG_IS_SET (src, DVDREADSRC_OPEN), FALSE);
1061 if (_open (src->priv, src->priv->location)) {
1062 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), (NULL));
1065 src->priv->seek_pend_fmt = title_format;
1066 src->priv->seek_pend = TRUE;
1068 GST_FLAG_SET (src, DVDREADSRC_OPEN);
1073 /* close the file */
1075 dvdreadsrc_close_file (DVDReadSrc * src)
1077 g_return_if_fail (GST_FLAG_IS_SET (src, DVDREADSRC_OPEN));
1081 GST_FLAG_UNSET (src, DVDREADSRC_OPEN);
1084 static GstStateChangeReturn
1085 dvdreadsrc_change_state (GstElement * element, GstStateChange transition)
1087 DVDReadSrc *dvdreadsrc = DVDREADSRC (element);
1089 g_return_val_if_fail (GST_IS_DVDREADSRC (element), GST_STATE_CHANGE_FAILURE);
1091 GST_DEBUG ("gstdvdreadsrc: state pending %d", GST_STATE_PENDING (element));
1093 /* if going down into NULL state, close the file if it's open */
1094 switch (transition) {
1095 case GST_STATE_CHANGE_NULL_TO_READY:
1096 if (!dvdreadsrc_open_file (DVDREADSRC (element)))
1097 return GST_STATE_CHANGE_FAILURE;
1099 case GST_STATE_CHANGE_PAUSED_TO_READY:
1100 dvdreadsrc->priv->new_cell = TRUE;
1101 dvdreadsrc->priv->new_seek = TRUE;
1102 dvdreadsrc->priv->chapter = 0;
1103 dvdreadsrc->priv->title = 0;
1104 dvdreadsrc->priv->flush_pend = FALSE;
1105 dvdreadsrc->priv->seek_pend = FALSE;
1106 dvdreadsrc->priv->seek_pend_fmt = GST_FORMAT_UNDEFINED;
1108 case GST_STATE_CHANGE_READY_TO_NULL:
1109 dvdreadsrc_close_file (DVDREADSRC (element));
1115 /* if we haven't failed already, give the parent class a chance to ;-) */
1116 if (GST_ELEMENT_CLASS (parent_class)->change_state)
1117 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1119 return GST_STATE_CHANGE_SUCCESS;
1127 dvdreadsrc_uri_get_type (void)
1133 dvdreadsrc_uri_get_protocols (void)
1135 static gchar *protocols[] = { "dvd", NULL };
1140 static const gchar *
1141 dvdreadsrc_uri_get_uri (GstURIHandler * handler)
1143 DVDReadSrc *dvdreadsrc = DVDREADSRC (handler);
1145 g_free (dvdreadsrc->priv->last_uri);
1146 dvdreadsrc->priv->last_uri =
1147 g_strdup_printf ("dvd://%d,%d,%d", dvdreadsrc->priv->title,
1148 dvdreadsrc->priv->chapter, dvdreadsrc->priv->angle);
1150 return dvdreadsrc->priv->last_uri;
1154 dvdreadsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri)
1156 DVDReadSrc *dvdreadsrc = DVDREADSRC (handler);
1158 gchar *protocol = gst_uri_get_protocol (uri);
1160 ret = (protocol && !strcmp (protocol, "dvd")) ? TRUE : FALSE;
1168 * Parse out the new t/c/a and seek to them
1171 gchar *location = NULL;
1176 location = gst_uri_get_location (uri);
1181 strcur = strs = g_strsplit (location, ",", 0);
1182 while (strcur && *strcur) {
1185 if (!sscanf (*strcur, "%d", &val))
1190 if (val != dvdreadsrc->priv->title) {
1191 dvdreadsrc->priv->title = val;
1192 dvdreadsrc->priv->new_seek = TRUE;
1196 if (val != dvdreadsrc->priv->chapter) {
1197 dvdreadsrc->priv->chapter = val;
1198 dvdreadsrc->priv->new_seek = TRUE;
1202 dvdreadsrc->priv->angle = val;
1218 dvdreadsrc_uri_handler_init (gpointer g_iface, gpointer iface_data)
1220 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
1222 iface->get_type = dvdreadsrc_uri_get_type;
1223 iface->get_protocols = dvdreadsrc_uri_get_protocols;
1224 iface->get_uri = dvdreadsrc_uri_get_uri;
1225 iface->set_uri = dvdreadsrc_uri_set_uri;
1229 plugin_init (GstPlugin * plugin)
1231 if (!gst_element_register (plugin, "dvdreadsrc", GST_RANK_NONE,
1232 GST_TYPE_DVDREADSRC))
1238 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1241 "Access a DVD with dvdread",
1242 plugin_init, VERSION, "GPL", GST_PACKAGE, GST_ORIGIN)