ext/a52dec/gsta52dec.c: Add buffer-frames=0.
authorRonald S. Bultje <rbultje@ronald.bitfreak.net>
Sat, 27 Nov 2004 17:20:26 +0000 (17:20 +0000)
committerRonald S. Bultje <rbultje@ronald.bitfreak.net>
Sat, 27 Nov 2004 17:20:26 +0000 (17:20 +0000)
Original commit message from CVS:
* ext/a52dec/gsta52dec.c: (gst_a52dec_reneg):
Add buffer-frames=0.
* ext/dvdread/dvdreadsrc.c: (dvdreadsrc_get_type),
(dvdreadsrc_init), (dvdreadsrc_get_event_mask),
(dvdreadsrc_get_query_types), (dvdreadsrc_get_formats),
(dvdreadsrc_srcpad_event), (dvdreadsrc_srcpad_query),
(_seek_title), (_seek_chapter), (get_next_cell_for), (_read),
(seek_sector), (dvdreadsrc_get), (dvdreadsrc_open_file),
(dvdreadsrc_change_state), (dvdreadsrc_uri_get_type),
(dvdreadsrc_uri_get_protocols), (dvdreadsrc_uri_get_uri),
(dvdreadsrc_uri_set_uri), (dvdreadsrc_uri_handler_init):
* ext/dvdread/dvdreadsrc.h:
Add seeking, querying for bytes, sectors, title, angle and
chapter. Handle multiple chapters. Relicense to LGPL because
Billy agreed on that (thanks Billy!).

ChangeLog
ext/a52dec/gsta52dec.c
ext/dvdread/dvdreadsrc.c
ext/dvdread/dvdreadsrc.h

index 65b59c2..61ddf5a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2004-11-27  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+       * ext/a52dec/gsta52dec.c: (gst_a52dec_reneg):
+         Add buffer-frames=0.
+       * ext/dvdread/dvdreadsrc.c: (dvdreadsrc_get_type),
+       (dvdreadsrc_init), (dvdreadsrc_get_event_mask),
+       (dvdreadsrc_get_query_types), (dvdreadsrc_get_formats),
+       (dvdreadsrc_srcpad_event), (dvdreadsrc_srcpad_query),
+       (_seek_title), (_seek_chapter), (get_next_cell_for), (_read),
+       (seek_sector), (dvdreadsrc_get), (dvdreadsrc_open_file),
+       (dvdreadsrc_change_state), (dvdreadsrc_uri_get_type),
+       (dvdreadsrc_uri_get_protocols), (dvdreadsrc_uri_get_uri),
+       (dvdreadsrc_uri_set_uri), (dvdreadsrc_uri_handler_init):
+       * ext/dvdread/dvdreadsrc.h:
+         Add seeking, querying for bytes, sectors, title, angle and
+         chapter. Handle multiple chapters. Relicense to LGPL because
+         Billy agreed on that (thanks Billy!).
+
 2004-11-27  Christophe Fergeau  <teuf@gnome.org>
 
        * gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_dispose):
index 9c7f639..92fdc12 100644 (file)
@@ -79,7 +79,8 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
     GST_STATIC_CAPS ("audio/x-raw-float, "
         "endianness = (int) BYTE_ORDER, "
         "width = (int) " G_STRINGIFY (SAMPLE_WIDTH) ", "
-        "rate = (int) [ 4000, 96000 ], " "channels = (int) [ 1, 6 ]")
+        "rate = (int) [ 4000, 96000 ], "
+        "channels = (int) [ 1, 6 ], " "buffer-frames = (int) 0")
     );
 
 static void gst_a52dec_base_init (gpointer g_class);
@@ -304,7 +305,8 @@ gst_a52dec_reneg (GstPad * pad)
       "endianness", G_TYPE_INT, G_BYTE_ORDER,
       "width", G_TYPE_INT, SAMPLE_WIDTH,
       "channels", G_TYPE_INT, channels,
-      "rate", G_TYPE_INT, a52dec->sample_rate, NULL);
+      "rate", G_TYPE_INT, a52dec->sample_rate,
+      "buffer-frames", G_TYPE_INT, 0, NULL);
   gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos);
   g_free (pos);
 
index 53c3fd0..ba1d96b 100644 (file)
@@ -1,5 +1,6 @@
 /* GStreamer
  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2001 Billy Biggs <vektor@dumbterm.net>.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * Boston, MA 02111-1307, USA.
  */
 
-/**
- * Copyright (C) 2001 Billy Biggs <vektor@dumbterm.net>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -85,6 +68,10 @@ struct _DVDReadSrcPrivate
   ifo_handle_t *vts_file;
   vts_ptt_srpt_t *vts_ptt_srpt;
   pgc_t *cur_pgc;
+
+  /* where we are */
+  gboolean seek_pend, flush_pend;
+  GstFormat seek_pend_fmt;
 };
 
 GST_DEBUG_CATEGORY_STATIC (gstdvdreadsrc_debug);
@@ -124,15 +111,23 @@ static void dvdreadsrc_set_property (GObject * object, guint prop_id,
 static void dvdreadsrc_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
-static GstData *dvdreadsrc_get (GstPad * pad);
-
-/*static GstBuffer *   dvdreadsrc_get_region   (GstPad *pad,gulong offset,gulong size); */
+static const GstEventMask *dvdreadsrc_get_event_mask (GstPad * pad);
+static const GstQueryType *dvdreadsrc_get_query_types (GstPad * pad);
+static const GstFormat *dvdreadsrc_get_formats (GstPad * pad);
+static gboolean dvdreadsrc_srcpad_event (GstPad * pad, GstEvent * event);
+static gboolean dvdreadsrc_srcpad_query (GstPad * pad, GstQueryType type,
+    GstFormat * format, gint64 * value);
 
+static GstData *dvdreadsrc_get (GstPad * pad);
 static GstElementStateReturn dvdreadsrc_change_state (GstElement * element);
 
+static void dvdreadsrc_uri_handler_init (gpointer g_iface, gpointer iface_data);
+
 
 static GstElementClass *parent_class = NULL;
 
+static GstFormat sector_format, angle_format, title_format, chapter_format;
+
 /*static guint dvdreadsrc_signals[LAST_SIGNAL] = { 0 }; */
 
 GType
@@ -152,11 +147,24 @@ dvdreadsrc_get_type (void)
       0,
       (GInstanceInitFunc) dvdreadsrc_init,
     };
+    static const GInterfaceInfo urihandler_info = {
+      dvdreadsrc_uri_handler_init,
+      NULL,
+      NULL
+    };
+
+    sector_format = gst_format_register ("sector", "DVD sector");
+    title_format = gst_format_register ("title", "DVD title");
+    chapter_format = gst_format_register ("chapter", "DVD chapter");
+    angle_format = gst_format_register ("angle", "DVD angle");
 
     dvdreadsrc_type =
         g_type_register_static (GST_TYPE_ELEMENT, "DVDReadSrc",
         &dvdreadsrc_info, 0);
+    g_type_add_interface_static (dvdreadsrc_type,
+        GST_TYPE_URI_HANDLER, &urihandler_info);
   }
+
   return dvdreadsrc_type;
 }
 
@@ -209,14 +217,28 @@ dvdreadsrc_init (DVDReadSrc * dvdreadsrc)
   dvdreadsrc->priv = g_new (DVDReadSrcPrivate, 1);
   dvdreadsrc->priv->srcpad = gst_pad_new ("src", GST_PAD_SRC);
   gst_pad_set_get_function (dvdreadsrc->priv->srcpad, dvdreadsrc_get);
+  gst_pad_set_event_function (dvdreadsrc->priv->srcpad,
+      dvdreadsrc_srcpad_event);
+  gst_pad_set_event_mask_function (dvdreadsrc->priv->srcpad,
+      dvdreadsrc_get_event_mask);
+  gst_pad_set_query_function (dvdreadsrc->priv->srcpad,
+      dvdreadsrc_srcpad_query);
+  gst_pad_set_query_type_function (dvdreadsrc->priv->srcpad,
+      dvdreadsrc_get_query_types);
+  gst_pad_set_formats_function (dvdreadsrc->priv->srcpad,
+      dvdreadsrc_get_formats);
   gst_element_add_pad (GST_ELEMENT (dvdreadsrc), dvdreadsrc->priv->srcpad);
 
-  dvdreadsrc->priv->location = g_strdup ("/dev/dvd");
+  dvdreadsrc->priv->location = g_strdup ("/dev/cdrom");
   dvdreadsrc->priv->new_seek = TRUE;
   dvdreadsrc->priv->new_cell = TRUE;
   dvdreadsrc->priv->title = 0;
   dvdreadsrc->priv->chapter = 0;
   dvdreadsrc->priv->angle = 0;
+
+  dvdreadsrc->priv->seek_pend = FALSE;
+  dvdreadsrc->priv->flush_pend = FALSE;
+  dvdreadsrc->priv->seek_pend_fmt = GST_FORMAT_UNDEFINED;
 }
 
 static void
@@ -309,6 +331,206 @@ dvdreadsrc_get_property (GObject * object, guint prop_id, GValue * value,
   }
 }
 
+/*
+ * Querying and seeking.
+ */
+
+static const GstEventMask *
+dvdreadsrc_get_event_mask (GstPad * pad)
+{
+  static const GstEventMask masks[] = {
+    {GST_EVENT_SEEK, GST_SEEK_METHOD_CUR |
+          GST_SEEK_METHOD_SET | GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH},
+    {0, 0}
+  };
+
+  return masks;
+}
+
+static const GstQueryType *
+dvdreadsrc_get_query_types (GstPad * pad)
+{
+  static const GstQueryType types[] = {
+    GST_QUERY_TOTAL,
+    GST_QUERY_POSITION,
+    0
+  };
+
+  return types;
+}
+
+static const GstFormat *
+dvdreadsrc_get_formats (GstPad * pad)
+{
+  static GstFormat formats[] = {
+    GST_FORMAT_BYTES,
+    0, 0, 0, 0,                 /* init later */
+    0,
+  };
+  if (formats[1] == 0) {
+    formats[1] = sector_format;
+    formats[2] = angle_format;
+    formats[3] = title_format;
+    formats[4] = chapter_format;
+  }
+
+  return formats;
+}
+
+static gboolean
+dvdreadsrc_srcpad_event (GstPad * pad, GstEvent * event)
+{
+  DVDReadSrc *dvdreadsrc = DVDREADSRC (gst_pad_get_parent (pad));
+  gboolean res = TRUE;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:{
+      gint64 new_off, total, cur;
+      GstFormat fmt;
+
+      /* get requested offset */
+      new_off = GST_EVENT_SEEK_OFFSET (event);
+      switch (GST_EVENT_SEEK_FORMAT (event)) {
+        case GST_FORMAT_BYTES:
+          new_off /= DVD_VIDEO_LB_LEN;
+          fmt = sector_format;
+          break;
+        default:
+          fmt = GST_EVENT_SEEK_FORMAT (event);
+          if (fmt == sector_format ||
+              fmt == angle_format ||
+              fmt == title_format || fmt == chapter_format)
+            break;
+          GST_LOG ("Unsupported seek format");
+          return FALSE;
+      }
+
+      /* get current offset and length */
+      gst_pad_query (pad, GST_QUERY_TOTAL, &fmt, &total);
+      gst_pad_query (pad, GST_QUERY_POSITION, &fmt, &cur);
+      if (cur == new_off) {
+        GST_LOG ("We're already at that position!");
+        return TRUE;
+      }
+
+      /* get absolute */
+      switch (GST_EVENT_SEEK_METHOD (event)) {
+        case GST_SEEK_METHOD_SET:
+          /* no-op */
+          break;
+        case GST_SEEK_METHOD_CUR:
+          new_off += cur;
+          break;
+        case GST_SEEK_METHOD_END:
+          new_off = total - new_off;
+          break;
+        default:
+          GST_LOG ("Unsupported seek method");
+          return FALSE;
+      }
+      if (new_off < 0 || new_off >= total) {
+        GST_LOG ("Invalid seek position");
+        return FALSE;
+      }
+
+      GST_LOG ("Seeking to unit %d in format %d", new_off, fmt);
+
+      if (fmt == sector_format || fmt == chapter_format || fmt == title_format) {
+        if (fmt == sector_format) {
+          dvdreadsrc->priv->cur_pack = new_off;
+        } else if (fmt == chapter_format) {
+          dvdreadsrc->priv->cur_pack = 0;
+          dvdreadsrc->priv->chapter = new_off;
+          dvdreadsrc->priv->seek_pend_fmt = fmt;
+        } else if (fmt == title_format) {
+          dvdreadsrc->priv->cur_pack = 0;
+          dvdreadsrc->priv->title = new_off;
+          dvdreadsrc->priv->chapter = 0;
+          dvdreadsrc->priv->seek_pend_fmt = fmt;
+        }
+
+        /* leave for events */
+        dvdreadsrc->priv->seek_pend = TRUE;
+        if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH)
+          dvdreadsrc->priv->flush_pend = TRUE;
+      } else if (fmt == angle_format) {
+        dvdreadsrc->priv->angle = new_off;
+      }
+
+      break;
+    }
+    default:
+      res = FALSE;
+      break;
+  }
+
+  gst_event_unref (event);
+
+  return res;
+}
+
+static gboolean
+dvdreadsrc_srcpad_query (GstPad * pad, GstQueryType type,
+    GstFormat * format, gint64 * value)
+{
+  DVDReadSrc *dvdreadsrc = DVDREADSRC (gst_pad_get_parent (pad));
+  DVDReadSrcPrivate *priv = dvdreadsrc->priv;
+  gboolean res = TRUE;
+
+  if (!GST_FLAG_IS_SET (dvdreadsrc, DVDREADSRC_OPEN))
+    return FALSE;
+
+  switch (type) {
+    case GST_QUERY_TOTAL:
+      switch (*format) {
+        case GST_FORMAT_BYTES:
+          *value = DVDFileSize (priv->dvd_title) * DVD_VIDEO_LB_LEN;
+          break;
+        default:
+          if (*format == sector_format) {
+            *value = DVDFileSize (priv->dvd_title);
+          } else if (*format == title_format) {
+            *value = priv->tt_srpt->nr_of_srpts;
+          } else if (*format == chapter_format) {
+            *value = priv->tt_srpt->title[priv->title].nr_of_ptts;
+          } else if (*format == angle_format) {
+            *value = priv->tt_srpt->title[priv->title].nr_of_angles;
+          } else {
+            GST_LOG ("Unknown format");
+            res = FALSE;
+          }
+          break;
+      }
+      break;
+    case GST_QUERY_POSITION:
+      switch (*format) {
+        case GST_FORMAT_BYTES:
+          *value = priv->cur_pack * DVD_VIDEO_LB_LEN;
+          break;
+        default:
+          if (*format == sector_format) {
+            *value = priv->cur_pack;
+          } else if (*format == title_format) {
+            *value = priv->title;
+          } else if (*format == chapter_format) {
+            *value = priv->chapter;
+          } else if (*format == angle_format) {
+            *value = priv->angle;
+          } else {
+            GST_LOG ("Unknown format");
+            res = FALSE;
+          }
+          break;
+      }
+      break;
+    default:
+      res = FALSE;
+      break;
+  }
+
+  return res;
+}
+
 /**
  * Returns true if the pack is a NAV pack.  This check is clearly insufficient,
  * and sometimes we incorrectly think that valid other packs are NAV packs.  I
@@ -362,7 +584,7 @@ _close (DVDReadSrcPrivate * priv)
 }
 
 static int
-_seek (DVDReadSrcPrivate * priv, int title, int chapter, int angle)
+_seek_title (DVDReadSrcPrivate * priv, int title, int angle)
 {
     /**
      * Make sure our title number is valid.
@@ -376,27 +598,15 @@ _seek (DVDReadSrcPrivate * priv, int title, int chapter, int angle)
     return -1;
   }
 
-
-    /**
-     * Make sure the chapter number is valid for this title.
-     */
   GST_LOG ("There are %d chapters in this title",
       priv->tt_srpt->title[title].nr_of_ptts);
 
-  if (chapter < 0 || chapter >= priv->tt_srpt->title[title].nr_of_ptts) {
-    GST_ERROR ("Invalid chapter %d (only %d available)",
-        chapter, priv->tt_srpt->title[title].nr_of_ptts);
-    ifoClose (priv->vmg_file);
-    DVDClose (priv->dvd);
-    return -1;
-  }
-
-
     /**
      * Make sure the angle number is valid for this title.
      */
   GST_LOG ("There are %d angles available in this title",
       priv->tt_srpt->title[title].nr_of_angles);
+
   if (angle < 0 || angle >= priv->tt_srpt->title[title].nr_of_angles) {
     GST_ERROR ("Invalid angle %d (only %d available)",
         angle, priv->tt_srpt->title[title].nr_of_angles);
@@ -419,19 +629,55 @@ _seek (DVDReadSrcPrivate * priv, int title, int chapter, int angle)
     return -1;
   }
 
+  priv->ttn = priv->tt_srpt->title[title].vts_ttn;
+  priv->vts_ptt_srpt = priv->vts_file->vts_ptt_srpt;
+
+    /**
+     * We've got enough info, time to open the title set data.
+     */
+  priv->dvd_title =
+      DVDOpenFile (priv->dvd, priv->tt_srpt->title[title].title_set_nr,
+      DVD_READ_TITLE_VOBS);
+  if (!priv->dvd_title) {
+    GST_ERROR ("Can't open title VOBS (VTS_%02d_1.VOB)",
+        priv->tt_srpt->title[title].title_set_nr);
+    ifoClose (priv->vts_file);
+    ifoClose (priv->vmg_file);
+    DVDClose (priv->dvd);
+    return -1;
+  }
+
+  GST_LOG ("Opened title %d, angle %d", title, angle);
+
+  return 0;
+}
+
+static int
+_seek_chapter (DVDReadSrcPrivate * priv, int chapter)
+{
+  int i;
+
+    /**
+     * Make sure the chapter number is valid for this title.
+     */
+  if (chapter < 0 || chapter >= priv->tt_srpt->title[priv->title].nr_of_ptts) {
+    GST_ERROR ("Invalid chapter %d (only %d available)",
+        chapter, priv->tt_srpt->title[priv->title].nr_of_ptts);
+    ifoClose (priv->vmg_file);
+    DVDClose (priv->dvd);
+    return -1;
+  }
 
     /**
      * Determine which program chain we want to watch.  This is based on the
      * chapter number.
      */
-  priv->ttn = priv->tt_srpt->title[title].vts_ttn;
-  priv->vts_ptt_srpt = priv->vts_file->vts_ptt_srpt;
   priv->pgc_id = priv->vts_ptt_srpt->title[priv->ttn - 1].ptt[chapter].pgcn;
   priv->pgn = priv->vts_ptt_srpt->title[priv->ttn - 1].ptt[chapter].pgn;
   priv->cur_pgc = priv->vts_file->vts_pgcit->pgci_srp[priv->pgc_id - 1].pgc;
   priv->start_cell = priv->cur_pgc->program_map[priv->pgn - 1] - 1;
 
-  if (chapter + 1 == priv->tt_srpt->title[title].nr_of_ptts) {
+  if (chapter + 1 == priv->tt_srpt->title[priv->title].nr_of_ptts) {
     priv->last_cell = priv->cur_pgc->nr_of_cells;
   } else {
     priv->last_cell =
@@ -439,24 +685,59 @@ _seek (DVDReadSrcPrivate * priv, int title, int chapter, int angle)
                 1].ptt[chapter + 1].pgn) - 1] - 1;
   }
 
-    /**
-     * We've got enough info, time to open the title set data.
-     */
-  priv->dvd_title =
-      DVDOpenFile (priv->dvd, priv->tt_srpt->title[title].title_set_nr,
-      DVD_READ_TITLE_VOBS);
-  if (!priv->dvd_title) {
-    GST_ERROR ("Can't open title VOBS (VTS_%02d_1.VOB)",
-        priv->tt_srpt->title[title].title_set_nr);
-    ifoClose (priv->vts_file);
-    ifoClose (priv->vmg_file);
-    DVDClose (priv->dvd);
-    return -1;
+  GST_LOG ("Opened chapter %d - cell %d-%d",
+      chapter, priv->start_cell, priv->last_cell);
+
+  /* retrieve position */
+  priv->cur_pack = 0;
+  for (i = 0; i < chapter; i++) {
+    gint c1, c2;
+
+    c1 = priv->cur_pgc->program_map[(priv->vts_ptt_srpt->title[priv->ttn -
+                1].ptt[i].pgn) - 1] - 1;
+    if (i + 1 == priv->tt_srpt->title[priv->title].nr_of_ptts) {
+      c2 = priv->cur_pgc->nr_of_cells;
+    } else {
+      c2 = priv->cur_pgc->program_map[(priv->vts_ptt_srpt->title[priv->ttn -
+                  1].ptt[i + 1].pgn) - 1] - 1;
+    }
+
+    for (; c1 < c2; c1++) {
+      priv->cur_pack +=
+          priv->cur_pgc->cell_playback[c1].last_sector -
+          priv->cur_pgc->cell_playback[c1].first_sector;
+    }
   }
 
+  /* prepare reading for new cell */
+  priv->new_cell = TRUE;
+  priv->next_cell = priv->start_cell;
+
   return 0;
 }
 
+static int
+get_next_cell_for (DVDReadSrcPrivate * priv, int cell)
+{
+  /* Check if we're entering an angle block. */
+  if (priv->cur_pgc->cell_playback[cell].block_type == BLOCK_TYPE_ANGLE_BLOCK) {
+    int i;
+
+    for (i = 0;; ++i) {
+      if (priv->cur_pgc->cell_playback[cell + i].block_mode
+          == BLOCK_MODE_LAST_CELL) {
+        return cell + i + 1;
+      }
+    }
+  } else {
+    return cell + 1;
+  }
+
+  /* shut up compiler */
+  g_assert_not_reached ();
+  return -1;
+}
+
 /*
  * Read function.
  * -1: error, -2: eos, -3: try again, 0: ok.
@@ -465,44 +746,36 @@ _seek (DVDReadSrcPrivate * priv, int title, int chapter, int angle)
 static int
 _read (DVDReadSrcPrivate * priv, int angle, int new_seek, GstBuffer * buf)
 {
-  unsigned char *data;
+  unsigned char *data, static_data[DVD_VIDEO_LB_LEN];
 
-  data = GST_BUFFER_DATA (buf);
+  if (buf) {
+    data = GST_BUFFER_DATA (buf);
+  } else {
+    data = static_data;
+  }
 
     /**
      * Playback by cell in this pgc, starting at the cell for our chapter.
      */
-  if (new_seek) {
-    priv->next_cell = priv->start_cell;
+  if (new_seek)
     priv->cur_cell = priv->start_cell;
-  }
 
   if (priv->cur_cell < priv->last_cell) {
-    if (priv->new_cell)
-      priv->cur_cell = priv->next_cell;
-
-    /* Check if we're entering an angle block. */
-    if (priv->cur_pgc->cell_playback[priv->cur_cell].block_type
-        == BLOCK_TYPE_ANGLE_BLOCK) {
-      int i;
-
-      priv->cur_cell += angle;
-      for (i = 0;; ++i) {
-        if (priv->cur_pgc->cell_playback[priv->cur_cell + i].block_mode
-            == BLOCK_MODE_LAST_CELL) {
-          priv->next_cell = priv->cur_cell + i + 1;
-          break;
-        }
-      }
-    } else {
-      priv->next_cell = priv->cur_cell + 1;
-    }
+    if (priv->new_cell || new_seek) {
+      if (!new_seek)
+        priv->cur_cell = priv->next_cell;
 
+      /* take angle into account */
+      if (priv->cur_pgc->cell_playback[priv->cur_cell].block_type
+          == BLOCK_TYPE_ANGLE_BLOCK)
+        priv->cur_cell += angle;
 
-        /**
-         * We loop until we're out of this cell.
-         */
-    if (priv->new_cell) {
+      /* calculate next cell */
+      priv->next_cell = get_next_cell_for (priv, priv->cur_cell);
+
+      /**
+       * We loop until we're out of this cell.
+       */
       priv->cur_pack =
           priv->cur_pgc->cell_playback[priv->cur_cell].first_sector;
       priv->new_cell = FALSE;
@@ -565,33 +838,105 @@ _read (DVDReadSrcPrivate * priv, int angle, int new_seek, GstBuffer * buf)
       assert (cur_output_size < 1024);
       priv->cur_pack++;
 
+      if (buf) {
             /**
              * Read in and output cursize packs.
              */
-      len =
-          DVDReadBlocks (priv->dvd_title, priv->cur_pack, cur_output_size,
-          data);
-      if (len != cur_output_size) {
-        GST_ERROR ("Read failed for %d blocks at %d",
-            cur_output_size, priv->cur_pack);
-        return -1;
+        len =
+            DVDReadBlocks (priv->dvd_title, priv->cur_pack, cur_output_size,
+            data);
+        if (len != cur_output_size) {
+          GST_ERROR ("Read failed for %d blocks at %d",
+              cur_output_size, priv->cur_pack);
+          return -1;
+        }
+
+        GST_BUFFER_SIZE (buf) = cur_output_size * DVD_VIDEO_LB_LEN;
+        //GST_BUFFER_OFFSET (buf) = priv->cur_pack * DVD_VIDEO_LB_LEN;
       }
 
-      GST_BUFFER_SIZE (buf) = cur_output_size * DVD_VIDEO_LB_LEN;
       priv->cur_pack = next_vobu;
 
+      GST_LOG ("done reading data - %u sectors", cur_output_size);
+
       return 0;
     } else {
       priv->new_cell = TRUE;
     }
   } else {
-    return -2;
+    /* swap to next chapter */
+    if (priv->chapter + 1 == priv->tt_srpt->title[priv->title].nr_of_ptts) {
+      GST_LOG ("last chapter done - eos");
+      return -2;
+    }
+
+    GST_LOG ("end-of-chapter, switch to next");
+
+    priv->chapter++;
+    _seek_chapter (priv, priv->chapter);
   }
 
   /* again */
+  GST_LOG ("Need another try");
+
   return -3;
 }
 
+static gboolean
+seek_sector (DVDReadSrcPrivate * priv, int angle)
+{
+  gint seek_to = priv->cur_pack, chapter, sectors, next, cur, i;
+
+  /* retrieve position */
+  priv->cur_pack = 0;
+  for (i = 0; i < priv->tt_srpt->title[priv->title].nr_of_ptts; i++) {
+    gint c1, c2;
+
+    c1 = priv->cur_pgc->program_map[(priv->vts_ptt_srpt->title[priv->ttn -
+                1].ptt[i].pgn) - 1] - 1;
+    if (i + 1 == priv->tt_srpt->title[priv->title].nr_of_ptts) {
+      c2 = priv->cur_pgc->nr_of_cells;
+    } else {
+      c2 = priv->cur_pgc->program_map[(priv->vts_ptt_srpt->title[priv->ttn -
+                  1].ptt[i + 1].pgn) - 1] - 1;
+    }
+
+    for (next = cur = c1; cur < c2;) {
+      if (next != cur) {
+        sectors =
+            priv->cur_pgc->cell_playback[cur].last_sector -
+            priv->cur_pgc->cell_playback[cur].first_sector;
+        if (priv->cur_pack + sectors > seek_to) {
+          chapter = i;
+          goto done;
+        }
+        priv->cur_pack += sectors;
+      }
+      cur = next;
+      if (priv->cur_pgc->cell_playback[cur].block_type
+          == BLOCK_TYPE_ANGLE_BLOCK)
+        cur += angle;
+      next = get_next_cell_for (priv, cur);
+    }
+  }
+
+  GST_LOG ("Seek to sector %u failed", seek_to);
+  return FALSE;
+
+done:
+  /* so chapter $chapter and cell $cur contain our sector
+   * of interest. Let's go there! */
+  GST_LOG ("Seek succeeded, going to chapter %u, cell %u", chapter, cur);
+
+  _seek_chapter (priv, chapter);
+  priv->cur_cell = cur;
+  priv->next_cell = next;
+  priv->new_cell = FALSE;
+  priv->cur_pack = seek_to;
+
+  return TRUE;
+}
+
 static GstData *
 dvdreadsrc_get (GstPad * pad)
 {
@@ -607,12 +952,40 @@ dvdreadsrc_get (GstPad * pad)
   priv = dvdreadsrc->priv;
   g_return_val_if_fail (GST_FLAG_IS_SET (dvdreadsrc, DVDREADSRC_OPEN), NULL);
 
+  /* handle vents, if any */
+  if (priv->seek_pend) {
+    if (priv->flush_pend) {
+      priv->flush_pend = FALSE;
+
+      return GST_DATA (gst_event_new (GST_EVENT_FLUSH));
+    }
+
+    priv->seek_pend = FALSE;
+    if (priv->seek_pend_fmt != GST_FORMAT_UNDEFINED) {
+      if (priv->seek_pend_fmt == title_format) {
+        _seek_title (priv, priv->title, priv->angle);
+      }
+      _seek_chapter (priv, priv->chapter);
+
+      priv->seek_pend_fmt = GST_FORMAT_UNDEFINED;
+    } else {
+      if (!seek_sector (priv, priv->angle)) {
+        return GST_DATA (gst_event_new (GST_EVENT_EOS));
+      }
+    }
+
+    return GST_DATA (gst_event_new_discontinuous (FALSE,
+            GST_FORMAT_BYTES, priv->cur_pack * DVD_VIDEO_LB_LEN,
+            GST_FORMAT_UNDEFINED));
+  }
+
   /* create the buffer */
   /* FIXME: should eventually use a bufferpool for this */
   buf = gst_buffer_new_and_alloc (1024 * DVD_VIDEO_LB_LEN);
 
   if (priv->new_seek) {
-    _seek (priv, priv->title, priv->chapter, priv->angle);
+    _seek_title (priv, priv->title, priv->angle);
+    _seek_chapter (priv, priv->chapter);
   }
 
   /* read it in from the file */
@@ -649,10 +1022,8 @@ dvdreadsrc_open_file (DVDReadSrc * src)
     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), (NULL));
     return FALSE;
   }
-  if (_seek (src->priv, src->priv->title, src->priv->chapter, src->priv->angle)) {
-    GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL), (NULL));
-    return FALSE;
-  }
+  src->priv->seek_pend_fmt = title_format;
+  src->priv->seek_pend = TRUE;
 
   GST_FLAG_SET (src, DVDREADSRC_OPEN);
 
@@ -690,6 +1061,9 @@ dvdreadsrc_change_state (GstElement * element)
       dvdreadsrc->priv->new_seek = TRUE;
       dvdreadsrc->priv->chapter = 0;
       dvdreadsrc->priv->title = 0;
+      dvdreadsrc->priv->flush_pend = FALSE;
+      dvdreadsrc->priv->seek_pend = FALSE;
+      dvdreadsrc->priv->seek_pend_fmt = GST_FORMAT_UNDEFINED;
       break;
     case GST_STATE_READY_TO_NULL:
       dvdreadsrc_close_file (DVDREADSRC (element));
@@ -705,6 +1079,53 @@ dvdreadsrc_change_state (GstElement * element)
   return GST_STATE_SUCCESS;
 }
 
+/*
+ * URI interface.
+ */
+
+static guint
+dvdreadsrc_uri_get_type (void)
+{
+  return GST_URI_SRC;
+}
+
+static gchar **
+dvdreadsrc_uri_get_protocols (void)
+{
+  static gchar *protocols[] = { "dvd", NULL };
+
+  return protocols;
+}
+
+static const gchar *
+dvdreadsrc_uri_get_uri (GstURIHandler * handler)
+{
+  return "dvd://";
+}
+
+static gboolean
+dvdreadsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+{
+  gboolean ret;
+  gchar *protocol = gst_uri_get_protocol (uri);
+
+  ret = (protocol && !strcmp (protocol, "dvd")) ? TRUE : FALSE;
+  g_free (protocol);
+
+  return ret;
+}
+
+static void
+dvdreadsrc_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = dvdreadsrc_uri_get_type;
+  iface->get_protocols = dvdreadsrc_uri_get_protocols;
+  iface->get_uri = dvdreadsrc_uri_get_uri;
+  iface->set_uri = dvdreadsrc_uri_set_uri;
+}
+
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
index c896f01..f1e1366 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
-
 #ifndef __DVDREADSRC_H__
 #define __DVDREADSRC_H__
 
-
 #include <gst/gst.h>
 
-
 G_BEGIN_DECLS
 
 GstElementDetails dvdreadsrc_details;
 
-
 #define GST_TYPE_DVDREADSRC \
   (dvdreadsrc_get_type())
 #define DVDREADSRC(obj) \
@@ -61,7 +57,7 @@ struct _DVDReadSrcClass {
   GstElementClass parent_class;
 };
 
-GType dvdreadsrc_get_type(void);
+GType dvdreadsrc_get_type (void);
 
 G_END_DECLS