/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * 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
#include "config.h"
#endif
+#include "_stdint.h"
+
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <time.h>
#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <dirent.h>
+#include <string.h>
#include <errno.h>
-//#include <linux/cdrom.h>
-#include <assert.h>
#include "dvdreadsrc.h"
-#include "stream_labels.h"
-
-#include <dvdread/dvd_reader.h>
-#include <dvdread/ifo_types.h>
-#include <dvdread/ifo_read.h>
-#include <dvdread/nav_read.h>
-#include <dvdread/nav_print.h>
-
-struct _DVDReadSrcPrivate
-{
- /* pads */
- GstPad *srcpad;
- /* location */
- gchar *location;
- gchar *last_uri;
-
- gboolean new_seek;
-
- gboolean new_cell;
-
- int title, chapter, angle;
- int pgc_id, start_cell, cur_cell, cur_pack;
- int last_cell;
- int ttn, pgn, next_cell;
- dvd_reader_t *dvd;
- dvd_file_t *dvd_title;
- ifo_handle_t *vmg_file;
- tt_srpt_t *tt_srpt;
- 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);
-#define GST_CAT_DEFAULT (gstdvdreadsrc_debug)
+/* #include <gst/gst-i18n-plugin.h> */
+/* FIXME: remove once GETTEXT_PACKAGE etc. is set */
+#define _(s) s
-GstElementDetails dvdreadsrc_details = {
- "DVD Source",
- "Source/File/DVD",
- "Access a DVD title/chapter/angle using libdvdread",
- "Erik Walthinsen <omega@cse.ogi.edu>",
-};
+GST_DEBUG_CATEGORY_STATIC (gstgst_dvd_read_src_debug);
+#define GST_CAT_DEFAULT (gstgst_dvd_read_src_debug)
-
-/* DVDReadSrc signals and args */
-enum
-{
- /* FILL ME */
- LAST_SIGNAL
-};
+static void gst_dvd_read_src_do_init (GType dvdreadsrc_type);
enum
{
ARG_0,
- ARG_LOCATION,
ARG_DEVICE,
ARG_TITLE,
ARG_CHAPTER,
ARG_ANGLE
};
-static void dvdreadsrc_base_init (gpointer g_class);
-static void dvdreadsrc_class_init (DVDReadSrcClass * klass);
-static void dvdreadsrc_init (DVDReadSrc * dvdreadsrc);
-static void dvdreadsrc_finalize (GObject * object);
+static GstElementDetails gst_dvd_read_src_details = {
+ "DVD Source",
+ "Source/File/DVD",
+ "Access a DVD title/chapter/angle using libdvdread",
+ "Erik Walthinsen <omega@cse.ogi.edu>",
+};
-static void dvdreadsrc_set_property (GObject * object, guint prop_id,
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/mpeg, mpegversion=2, systemstream=(boolean)true"));
+
+static GstFormat title_format;
+static GstFormat angle_format;
+static GstFormat sector_format;
+static GstFormat chapter_format;
+
+static gboolean gst_dvd_read_src_start (GstBaseSrc * basesrc);
+static gboolean gst_dvd_read_src_stop (GstBaseSrc * basesrc);
+static GstFlowReturn gst_dvd_read_src_create (GstPushSrc * pushsrc,
+ GstBuffer ** buf);
+static gboolean gst_dvd_read_src_src_query (GstBaseSrc * basesrc,
+ GstQuery * query);
+static gboolean gst_dvd_read_src_src_event (GstBaseSrc * basesrc,
+ GstEvent * event);
+static gboolean gst_dvd_read_src_goto_title (GstDvdReadSrc * src, gint title,
+ gint angle);
+static gboolean gst_dvd_read_src_goto_chapter (GstDvdReadSrc * src,
+ gint chapter);
+static gboolean gst_dvd_read_src_goto_sector (GstDvdReadSrc * src, gint angle);
+static void gst_dvd_read_src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
-static void dvdreadsrc_get_property (GObject * object, guint prop_id,
+static void gst_dvd_read_src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
+static GstEvent *gst_dvd_read_src_make_clut_change_event (GstDvdReadSrc * src,
+ const guint * clut);
-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 GstStateChangeReturn dvdreadsrc_change_state (GstElement * element,
- GstStateChange transition);
+GST_BOILERPLATE_FULL (GstDvdReadSrc, gst_dvd_read_src, GstPushSrc,
+ GST_TYPE_PUSH_SRC, gst_dvd_read_src_do_init)
-static void dvdreadsrc_uri_handler_init (gpointer g_iface, gpointer iface_data);
-
-
-static GstElementClass *parent_class = NULL;
+ static void gst_dvd_read_src_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-static GstFormat sector_format, angle_format, title_format, chapter_format;
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&srctemplate));
-/*static guint dvdreadsrc_signals[LAST_SIGNAL] = { 0 }; */
+ gst_element_class_set_details (element_class, &gst_dvd_read_src_details);
+}
-GType
-dvdreadsrc_get_type (void)
+static void
+gst_dvd_read_src_finalize (GObject * object)
{
- static GType dvdreadsrc_type = 0;
-
- if (!dvdreadsrc_type) {
- static const GTypeInfo dvdreadsrc_info = {
- sizeof (DVDReadSrcClass),
- dvdreadsrc_base_init,
- NULL,
- (GClassInitFunc) dvdreadsrc_class_init,
- NULL,
- NULL,
- sizeof (DVDReadSrc),
- 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);
- }
+ GstDvdReadSrc *src = GST_DVD_READ_SRC (object);
- return dvdreadsrc_type;
+ g_free (src->location);
+ g_free (src->last_uri);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
-dvdreadsrc_base_init (gpointer g_class)
+gst_dvd_read_src_init (GstDvdReadSrc * src, GstDvdReadSrcClass * klass)
{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details (element_class, &dvdreadsrc_details);
+ src->dvd = NULL;
+ src->vts_file = NULL;
+ src->vmg_file = NULL;
+ src->dvd_title = NULL;
+
+ src->location = g_strdup ("/dev/dvd");
+ src->last_uri = NULL;
+ src->new_seek = TRUE;
+ src->new_cell = TRUE;
+ src->change_cell = FALSE;
+ src->title = 0;
+ src->chapter = 0;
+ src->angle = 0;
+
+ src->seek_pend = FALSE;
+ src->flush_pend = FALSE;
+ src->seek_pend_fmt = GST_FORMAT_UNDEFINED;
+ src->title_lang_event_pending = NULL;
+ src->pending_clut_event = NULL;
}
static void
-dvdreadsrc_class_init (DVDReadSrcClass * klass)
+gst_dvd_read_src_class_init (GstDvdReadSrcClass * klass)
{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
+ GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
+ GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+ gobject_class->finalize = gst_dvd_read_src_finalize;
+ gobject_class->set_property = gst_dvd_read_src_set_property;
+ gobject_class->get_property = gst_dvd_read_src_get_property;
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION,
- g_param_spec_string ("location", "Location",
- "DVD device location (deprecated; use device)",
- NULL, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE,
g_param_spec_string ("device", "Device",
"DVD device location", NULL, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TITLE,
g_param_spec_int ("title", "title", "title",
- 0, G_MAXINT, 0, G_PARAM_READWRITE));
+ 0, 999, 0, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CHAPTER,
g_param_spec_int ("chapter", "chapter", "chapter",
- 0, G_MAXINT, 0, G_PARAM_READWRITE));
+ 0, 999, 0, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ANGLE,
g_param_spec_int ("angle", "angle", "angle",
- 0, G_MAXINT, 0, G_PARAM_READWRITE));
-
- gobject_class->set_property = GST_DEBUG_FUNCPTR (dvdreadsrc_set_property);
- gobject_class->get_property = GST_DEBUG_FUNCPTR (dvdreadsrc_get_property);
-
- gobject_class->finalize = dvdreadsrc_finalize;
+ 0, 999, 0, G_PARAM_READWRITE));
- gstelement_class->change_state = dvdreadsrc_change_state;
+ gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_dvd_read_src_start);
+ gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_dvd_read_src_stop);
+ gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_dvd_read_src_src_query);
+ gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_dvd_read_src_src_event);
- GST_DEBUG_CATEGORY_INIT (gstdvdreadsrc_debug, "dvdreadsrc", 0,
- "DVD reader element based on dvdreadsrc");
+ gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_dvd_read_src_create);
}
-static void
-dvdreadsrc_init (DVDReadSrc * dvdreadsrc)
+static gboolean
+gst_dvd_read_src_start (GstBaseSrc * basesrc)
{
- 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->dvd = NULL;
- dvdreadsrc->priv->vts_file = NULL;
- dvdreadsrc->priv->vmg_file = NULL;
- dvdreadsrc->priv->dvd_title = NULL;
-
- dvdreadsrc->priv->location = g_strdup ("/dev/dvd");
- dvdreadsrc->priv->last_uri = NULL;
- 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;
-}
+ GstDvdReadSrc *src = GST_DVD_READ_SRC (basesrc);
-static void
-dvdreadsrc_finalize (GObject * object)
-{
- DVDReadSrc *dvdreadsrc = DVDREADSRC (object);
+ g_return_val_if_fail (src->location != NULL, FALSE);
+
+ GST_DEBUG_OBJECT (src, "Opening DVD '%s'", src->location);
- if (dvdreadsrc->priv) {
- g_free (dvdreadsrc->priv->location);
- g_free (dvdreadsrc->priv->last_uri);
- g_free (dvdreadsrc->priv);
- dvdreadsrc->priv = NULL;
+ src->dvd = DVDOpen (src->location);
+ if (src->dvd == NULL) {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+ (_("Could not open DVD")),
+ ("DVDOpen(%s) failed: %s", src->location, g_strerror (errno)));
+ return FALSE;
}
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-static void
-dvdreadsrc_set_property (GObject * object, guint prop_id, const GValue * value,
- GParamSpec * pspec)
-{
- DVDReadSrc *src;
- DVDReadSrcPrivate *priv;
+ /* Load the video manager to find out the information about the titles */
+ GST_DEBUG_OBJECT (src, "Loading VMG info");
- g_return_if_fail (GST_IS_DVDREADSRC (object));
+ src->vmg_file = ifoOpen (src->dvd, 0);
+ if (!src->vmg_file) {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+ (_("Could not open DVD")),
+ ("ifoOpen() failed: %s", g_strerror (errno)));
+ return FALSE;
+ }
- src = DVDREADSRC (object);
- priv = src->priv;
+ src->tt_srpt = src->vmg_file->tt_srpt;
- switch (prop_id) {
- case ARG_LOCATION:
- case ARG_DEVICE:
- /* the element must be stopped in order to do this */
- /*g_return_if_fail(!GST_OBJECT_FLAG_IS_SET(src,GST_STATE_RUNNING)); */
+ src->seek_pend_fmt = title_format;
+ src->seek_pend = TRUE;
- g_free (priv->location);
- /* clear the filename if we get a NULL (is that possible?) */
- if (g_value_get_string (value) == NULL)
- priv->location = g_strdup ("/dev/dvd");
- /* otherwise set the new filename */
- else
- priv->location = g_strdup (g_value_get_string (value));
- break;
- case ARG_TITLE:
- priv->title = g_value_get_int (value);
- priv->new_seek = TRUE;
- break;
- case ARG_CHAPTER:
- priv->chapter = g_value_get_int (value);
- priv->new_seek = TRUE;
- break;
- case ARG_ANGLE:
- priv->angle = g_value_get_int (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
+ return TRUE;
+}
+
+static gboolean
+gst_dvd_read_src_stop (GstBaseSrc * basesrc)
+{
+ GstDvdReadSrc *src = GST_DVD_READ_SRC (basesrc);
+
+ if (src->vts_file) {
+ ifoClose (src->vts_file);
+ src->vts_file = NULL;
+ }
+ if (src->vmg_file) {
+ ifoClose (src->vmg_file);
+ src->vmg_file = NULL;
+ }
+ if (src->dvd_title) {
+ DVDCloseFile (src->dvd_title);
+ src->dvd_title = NULL;
+ }
+ if (src->dvd) {
+ DVDClose (src->dvd);
+ src->dvd = NULL;
+ }
+ src->new_cell = TRUE;
+ src->new_seek = TRUE;
+ src->change_cell = FALSE;
+ src->chapter = 0;
+ src->title = 0;
+ src->flush_pend = FALSE;
+ src->seek_pend = FALSE;
+ src->seek_pend_fmt = GST_FORMAT_UNDEFINED;
+ if (src->title_lang_event_pending) {
+ gst_event_unref (src->title_lang_event_pending);
+ src->title_lang_event_pending = NULL;
+ }
+ if (src->pending_clut_event) {
+ gst_event_unref (src->pending_clut_event);
+ src->pending_clut_event = NULL;
}
+ return TRUE;
}
static void
-dvdreadsrc_get_property (GObject * object, guint prop_id, GValue * value,
- GParamSpec * pspec)
+cur_title_get_chapter_pgc (GstDvdReadSrc * src, gint chapter, gint * p_pgn,
+ gint * p_pgc_id, pgc_t ** p_pgc)
{
- DVDReadSrc *src;
- DVDReadSrcPrivate *priv;
+ pgc_t *pgc;
+ gint pgn, pgc_id;
- g_return_if_fail (GST_IS_DVDREADSRC (object));
+ g_assert (chapter >= 0 && chapter < src->num_chapters);
- src = DVDREADSRC (object);
- priv = src->priv;
+ pgc_id = src->vts_ptt_srpt->title[src->ttn - 1].ptt[chapter].pgcn;
+ pgn = src->vts_ptt_srpt->title[src->ttn - 1].ptt[chapter].pgn;
+ pgc = src->vts_file->vts_pgcit->pgci_srp[pgc_id - 1].pgc;
- switch (prop_id) {
- case ARG_DEVICE:
- case ARG_LOCATION:
- g_value_set_string (value, priv->location);
- break;
- case ARG_TITLE:
- g_value_set_int (value, priv->title);
- break;
- case ARG_CHAPTER:
- g_value_set_int (value, priv->chapter);
- break;
- case ARG_ANGLE:
- g_value_set_int (value, priv->angle);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
+ *p_pgn = pgn;
+ *p_pgc_id = pgc_id;
+ *p_pgc = pgc;
}
-/*
- * Querying and seeking.
- */
-
-static const GstEventMask *
-dvdreadsrc_get_event_mask (GstPad * pad)
+static void
+cur_title_get_chapter_bounds (GstDvdReadSrc * src, gint chapter,
+ gint * p_first_cell, gint * p_last_cell)
{
- 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}
- };
+ pgc_t *pgc;
+ gint pgn, pgc_id, pgn_next_ch;
- return masks;
-}
+ g_assert (chapter >= 0 && chapter < src->num_chapters);
-static const GstQueryType *
-dvdreadsrc_get_query_types (GstPad * pad)
-{
- static const GstQueryType types[] = {
- GST_QUERY_TOTAL,
- GST_QUERY_POSITION,
- 0
- };
+ cur_title_get_chapter_pgc (src, chapter, &pgn, &pgc_id, &pgc);
- return types;
-}
+ *p_first_cell = pgc->program_map[pgn - 1] - 1;
-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;
+ if (chapter == (src->num_chapters - 1)) {
+ *p_last_cell = pgc->nr_of_cells;
+ } else {
+ pgn_next_ch = src->vts_ptt_srpt->title[src->ttn - 1].ptt[chapter + 1].pgn;
+ *p_last_cell = pgc->program_map[pgn_next_ch - 1] - 1;
}
-
- return formats;
}
static gboolean
-dvdreadsrc_srcpad_event (GstPad * pad, GstEvent * event)
+gst_dvd_read_src_goto_chapter (GstDvdReadSrc * src, gint chapter)
{
- DVDReadSrc *dvdreadsrc = DVDREADSRC (gst_pad_get_parent (pad));
- gboolean res = TRUE;
+ gint i;
- 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;
- }
+ /* make sure the chapter number is valid for this title */
+ if (chapter < 0 || chapter >= src->num_chapters) {
+ GST_WARNING_OBJECT (src, "invalid chapter %d (only %d available)",
+ chapter, src->num_chapters);
+ chapter = CLAMP (chapter, 0, src->num_chapters - 1);
+ }
- /* 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;
- }
+ /* determine which program chain we want to watch. This is
+ * based on the chapter number */
+ cur_title_get_chapter_pgc (src, chapter, &src->pgn, &src->pgc_id,
+ &src->cur_pgc);
+ cur_title_get_chapter_bounds (src, chapter, &src->start_cell,
+ &src->last_cell);
- /* 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_OBJECT (src, "Opened chapter %d - cell %d-%d", chapter,
+ src->start_cell, src->last_cell);
- 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;
- }
+ /* retrieve position */
+ src->cur_pack = 0;
+ for (i = 0; i < chapter; i++) {
+ gint c1, c2;
- /* 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;
- }
+ cur_title_get_chapter_bounds (src, i, &c1, &c2);
- break;
+ while (c1 < c2) {
+ src->cur_pack +=
+ src->cur_pgc->cell_playback[c1].last_sector -
+ src->cur_pgc->cell_playback[c1].first_sector;
+ ++c1;
}
- default:
- res = FALSE;
- break;
}
- gst_event_unref (event);
+ /* prepare reading for new cell */
+ src->new_cell = TRUE;
+ src->next_cell = src->start_cell;
- return res;
+ src->chapter = chapter;
+
+ if (src->pending_clut_event)
+ gst_event_unref (src->pending_clut_event);
+
+ src->pending_clut_event =
+ gst_dvd_read_src_make_clut_change_event (src, src->cur_pgc->palette);
+
+ return TRUE;
}
static gboolean
-dvdreadsrc_srcpad_query (GstPad * pad, GstQueryType type,
- GstFormat * format, gint64 * value)
+gst_dvd_read_src_goto_title (GstDvdReadSrc * src, gint title, gint angle)
{
- DVDReadSrc *dvdreadsrc = DVDREADSRC (gst_pad_get_parent (pad));
- DVDReadSrcPrivate *priv = dvdreadsrc->priv;
- gboolean res = TRUE;
+ GstStructure *s;
+ gchar lang_code[3] = { '\0', '\0', '\0' }, *t;
+ gint title_set_nr;
+ gint num_titles;
+ gint num_angles;
+ gint i;
+
+ /* make sure our title number is valid */
+ num_titles = src->tt_srpt->nr_of_srpts;
+ GST_INFO_OBJECT (src, "There are %d titles on this DVD", num_titles);
+ if (title < 0 || title >= num_titles) {
+ GST_WARNING_OBJECT (src, "Invalid title %d (only %d available)",
+ title, num_titles);
+ title = CLAMP (title, 0, num_titles - 1);
+ }
+
+ src->num_chapters = src->tt_srpt->title[title].nr_of_ptts;
+ GST_INFO_OBJECT (src, "Title %d has %d chapters", title, src->num_chapters);
+
+ /* make sure the angle number is valid for this title */
+ num_angles = src->tt_srpt->title[title].nr_of_angles;
+ GST_LOG_OBJECT (src, "Title %d has %d angles", title, num_angles);
+ if (angle < 0 || angle >= num_angles) {
+ GST_WARNING_OBJECT (src, "Invalid angle %d (only %d available)",
+ angle, num_angles);
+ angle = CLAMP (angle, 0, num_angles - 1);
+ }
- if (!GST_OBJECT_FLAG_IS_SET (dvdreadsrc, DVDREADSRC_OPEN))
+ /* load the VTS information for the title set our title is in */
+ title_set_nr = src->tt_srpt->title[title].title_set_nr;
+ src->vts_file = ifoOpen (src->dvd, title_set_nr);
+ if (src->vts_file == NULL) {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+ (_("Could not open DVD title %d"), title_set_nr),
+ ("ifoOpen(%d) failed: %s", title_set_nr, g_strerror (errno)));
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;
+ src->ttn = src->tt_srpt->title[title].vts_ttn;
+ src->vts_ptt_srpt = src->vts_file->vts_ptt_srpt;
+
+ /* we've got enough info, time to open the title set data */
+ src->dvd_title = DVDOpenFile (src->dvd, title_set_nr, DVD_READ_TITLE_VOBS);
+ if (src->dvd_title == NULL) {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+ (_("Could not open DVD title %d"), title_set_nr),
+ ("Can't open title VOBS (VTS_%02d_1.VOB)", title_set_nr));
+ return FALSE;
}
- return res;
-}
+ GST_INFO_OBJECT (src, "Opened title %d, angle %d", title, angle);
+ src->title = title;
+ src->angle = angle;
-/*
- * 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
- * need to make this stronger.
- */
-static int
-is_nav_pack (unsigned char *buffer)
-{
- return (buffer[41] == 0xbf && buffer[1027] == 0xbf);
-}
+ /* build event */
-static int
-_close (DVDReadSrcPrivate * priv)
-{
- ifoClose (priv->vts_file);
- priv->vts_file = NULL;
+ if (src->title_lang_event_pending) {
+ gst_event_unref (src->title_lang_event_pending);
+ src->title_lang_event_pending = NULL;
+ }
- ifoClose (priv->vmg_file);
- priv->vmg_file = NULL;
+ s = gst_structure_new ("application/x-gst-event",
+ "event", G_TYPE_STRING, "dvd-lang-codes", NULL);
- DVDCloseFile (priv->dvd_title);
- priv->dvd_title = NULL;
+ /* audio */
+ for (i = 0; i < src->vts_file->vtsi_mat->nr_of_vts_audio_streams; i++) {
+ const audio_attr_t *a = &src->vts_file->vtsi_mat->vts_audio_attr[i];
- DVDClose (priv->dvd);
- priv->dvd = NULL;
+ t = g_strdup_printf ("audio-%d-format", i);
+ gst_structure_set (s, t, G_TYPE_INT, (int) a->audio_format, NULL);
+ g_free (t);
- return 0;
-}
+ if (a->lang_type) {
+ t = g_strdup_printf ("audio-%d-language", i);
+ lang_code[0] = (a->lang_code >> 8) & 0xff;
+ lang_code[1] = a->lang_code & 0xff;
+ gst_structure_set (s, t, G_TYPE_STRING, lang_code, NULL);
+ g_free (t);
+ } else {
+ lang_code[0] = '\0';
+ }
-static int
-_open (DVDReadSrcPrivate * priv, const gchar * location)
-{
- g_return_val_if_fail (priv != NULL, -1);
- g_return_val_if_fail (location != NULL, -1);
-
- /*
- * Open the disc.
- */
- priv->dvd = DVDOpen (location);
- if (!priv->dvd) {
- GST_ERROR ("Couldn't open DVD: %s", location);
- return -1;
+ GST_INFO_OBJECT (src, "[%02d] Audio %02d: lang='%s', format=%d",
+ src->title, i, lang_code, (gint) a->audio_format);
}
+ /* subtitle */
+ for (i = 0; i < src->vts_file->vtsi_mat->nr_of_vts_subp_streams; i++) {
+ const subp_attr_t *u = &src->vts_file->vtsi_mat->vts_subp_attr[i];
- /*
- * Load the video manager to find out the information about the titles on
- * this disc.
- */
- priv->vmg_file = ifoOpen (priv->dvd, 0);
- if (!priv->vmg_file) {
- GST_ERROR ("Can't open VMG info");
- return -1;
+ if (u->type) {
+ t = g_strdup_printf ("subtitle-%d-language", i);
+ lang_code[0] = (u->lang_code >> 8) & 0xff;
+ lang_code[1] = u->lang_code & 0xff;
+ gst_structure_set (s, t, G_TYPE_STRING, lang_code, NULL);
+ g_free (t);
+ } else {
+ lang_code[0] = '\0';
+ }
+
+ GST_INFO_OBJECT (src, "[%02d] Subtitle %02d: lang='%s', format=%d",
+ src->title, i, lang_code);
}
- priv->tt_srpt = priv->vmg_file->tt_srpt;
+
+ src->title_lang_event_pending =
+ gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
return 0;
}
-static int
-_seek_title (DVDReadSrcPrivate * priv, int title, int angle)
+/* FIXME: double-check this function, compare against original */
+static gint
+gst_dvd_read_src_get_next_cell_for (GstDvdReadSrc * src, gint cell)
{
- GHashTable *languagelist = NULL;
-
- /*
- * Make sure our title number is valid.
- */
- GST_LOG ("There are %d titles on this DVD", priv->tt_srpt->nr_of_srpts);
- if (title < 0 || title >= priv->tt_srpt->nr_of_srpts) {
- GST_WARNING ("Invalid title %d (only %d available)",
- title, priv->tt_srpt->nr_of_srpts);
-
- if (title < 0)
- title = 0;
- else
- title = priv->tt_srpt->nr_of_srpts - 1;
- }
+ /* Check if we're entering an angle block. */
+ if (src->cur_pgc->cell_playback[cell].block_type != BLOCK_TYPE_ANGLE_BLOCK)
+ return (cell + 1);
- GST_LOG ("There are %d chapters in this title",
- priv->tt_srpt->title[title].nr_of_ptts);
-
- /*
- * 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_WARNING ("Invalid angle %d (only %d available)",
- angle, priv->tt_srpt->title[title].nr_of_angles);
- if (angle < 0)
- angle = 0;
- else
- angle = priv->tt_srpt->title[title].nr_of_angles - 1;
- }
+ while (src->cur_pgc->cell_playback[cell].block_mode == BLOCK_MODE_LAST_CELL)
+ ++cell;
- /*
- * Load the VTS information for the title set our title is in.
- */
- priv->vts_file =
- ifoOpen (priv->dvd, priv->tt_srpt->title[title].title_set_nr);
- if (!priv->vts_file) {
- GST_ERROR ("Can't open the info file of title %d",
- priv->tt_srpt->title[title].title_set_nr);
- _close (priv);
- return -1;
- }
+ return cell + 1; /* really +1? (tpm) */
+}
- 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);
- _close (priv);
- return -1;
- }
+/* 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
+ * need to make this stronger. */
+static gboolean
+gst_dvd_read_src_is_nav_pack (const guint8 * buffer)
+{
+ return (buffer[41] == 0xbf && buffer[1027] == 0xbf);
+}
- /* Get stream labels for all audio and subtitle streams */
- languagelist = dvdreadsrc_init_languagelist ();
+typedef enum
+{
+ GST_DVD_READ_OK = 0,
+ GST_DVD_READ_ERROR = -1,
+ GST_DVD_READ_EOS = -2,
+ GST_DVD_READ_AGAIN = -3
+} GstDvdReadReturn;
+
+static GstDvdReadReturn
+gst_dvd_read_src_read (GstDvdReadSrc * src, gint angle, gint new_seek,
+ GstBuffer * buf)
+{
+ guint8 *data;
+ dsi_t dsi_pack;
+ guint next_vobu, next_ilvu_start, cur_output_size;
+ gint len;
- dvdreadsrc_get_audio_stream_labels (priv->vts_file, languagelist);
- dvdreadsrc_get_subtitle_stream_labels (priv->vts_file, languagelist);
+ /* playback by cell in this pgc, starting at the cell for our chapter */
+ if (new_seek)
+ src->cur_cell = src->start_cell;
- g_hash_table_destroy (languagelist);
+again:
- GST_LOG ("Opened title %d, angle %d", title, angle);
- priv->title = title;
- priv->angle = angle;
+ if (src->cur_cell >= src->last_cell) {
+ /* advance to next chapter */
+ if (src->chapter == (src->num_chapters - 1)) {
+ GST_INFO_OBJECT (src, "last chapter done - EOS");
+ return GST_DVD_READ_EOS;
+ }
- return 0;
-}
+ GST_INFO_OBJECT (src, "end of chapter %d, switch to next", src->chapter);
-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_WARNING ("Invalid chapter %d (only %d available)",
- chapter, priv->tt_srpt->title[priv->title].nr_of_ptts);
- if (chapter < 0)
- chapter = 0;
- chapter = priv->tt_srpt->title[priv->title].nr_of_ptts - 1;
- }
+ ++src->chapter;
+ gst_dvd_read_src_goto_chapter (src, src->chapter);
- /*
- * Determine which program chain we want to watch. This is based on the
- * chapter number.
- */
- 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[priv->title].nr_of_ptts) {
- priv->last_cell = priv->cur_pgc->nr_of_cells;
- } else {
- priv->last_cell =
- priv->cur_pgc->program_map[(priv->vts_ptt_srpt->title[priv->ttn -
- 1].ptt[chapter + 1].pgn) - 1] - 1;
+ return GST_DVD_READ_AGAIN;
}
- GST_LOG ("Opened chapter %d - cell %d-%d",
- chapter, priv->start_cell, priv->last_cell);
+ if (src->new_cell || new_seek) {
+ if (!new_seek) {
+ src->cur_cell = src->next_cell;
+ if (src->cur_cell >= src->last_cell) {
+ GST_LOG_OBJECT (src, "last cell in chapter");
+ goto again;
+ }
+ }
- /* retrieve position */
- priv->cur_pack = 0;
- for (i = 0; i < chapter; i++) {
- gint c1, c2;
+ /* take angle into account */
+ if (src->cur_pgc->cell_playback[src->cur_cell].block_type
+ == BLOCK_TYPE_ANGLE_BLOCK)
+ src->cur_cell += angle;
- 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;
- }
+ /* calculate next cell */
+ src->next_cell = gst_dvd_read_src_get_next_cell_for (src, src->cur_cell);
- for (; c1 < c2; c1++) {
- priv->cur_pack +=
- priv->cur_pgc->cell_playback[c1].last_sector -
- priv->cur_pgc->cell_playback[c1].first_sector;
- }
+ /* we loop until we're out of this cell */
+ src->cur_pack = src->cur_pgc->cell_playback[src->cur_cell].first_sector;
+ src->new_cell = FALSE;
}
- /* prepare reading for new cell */
- priv->new_cell = TRUE;
- priv->next_cell = priv->start_cell;
-
- priv->chapter = chapter;
- return 0;
-}
+ if (src->cur_pack >= src->cur_pgc->cell_playback[src->cur_cell].last_sector) {
+ src->new_cell = TRUE;
+ GST_LOG_OBJECT (src, "Beyond last sector, go to next cell");
+ return GST_DVD_READ_AGAIN;
+ }
-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;
+ /* read NAV packet */
+ data = GST_BUFFER_DATA (buf);
- for (i = 0;; ++i) {
- if (priv->cur_pgc->cell_playback[cell + i].block_mode
- == BLOCK_MODE_LAST_CELL) {
- return cell + i + 1;
- }
- }
+nav_retry:
- /* not reached */
+ len = DVDReadBlocks (src->dvd_title, src->cur_pack, 1, data);
+ if (len == 0) {
+ GST_ERROR_OBJECT (src, "Read failed for block %d", src->cur_pack);
+ return GST_DVD_READ_ERROR;
}
- return cell + 1;
-}
+ if (!gst_dvd_read_src_is_nav_pack (data)) {
+ src->cur_pack++;
+ goto nav_retry;
+ }
-/*
- * Read function.
- * -1: error, -2: eos, -3: try again, 0: ok.
- */
+ /* parse the contained dsi packet */
+ navRead_DSI (&dsi_pack, &data[DSI_START_BYTE]);
+ g_assert (src->cur_pack == dsi_pack.dsi_gi.nv_pck_lbn);
+
+ /* determine where we go next. These values are the ones we
+ * mostly care about */
+ next_ilvu_start = src->cur_pack + dsi_pack.sml_agli.data[angle].address;
+ cur_output_size = dsi_pack.dsi_gi.vobu_ea;
+
+ /* If we're not at the end of this cell, we can determine the next
+ * VOBU to display using the VOBU_SRI information section of the
+ * DSI. Using this value correctly follows the current angle,
+ * avoiding the doubled scenes in The Matrix, and makes our life
+ * really happy.
+ *
+ * Otherwise, we set our next address past the end of this cell to
+ * force the code above to go to the next cell in the program. */
+ if (dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL) {
+ next_vobu = src->cur_pack + (dsi_pack.vobu_sri.next_vobu & 0x7fffffff);
+ } else {
+ next_vobu = src->cur_pack + cur_output_size + 1;
+ }
-static int
-_read (DVDReadSrcPrivate * priv, int angle, int new_seek, GstBuffer * buf)
-{
- unsigned char *data, static_data[DVD_VIDEO_LB_LEN];
+ g_assert (cur_output_size < 1024);
+ ++src->cur_pack;
- if (buf) {
- data = GST_BUFFER_DATA (buf);
- } else {
- data = static_data;
+ /* read in and output cursize packs */
+ len = DVDReadBlocks (src->dvd_title, src->cur_pack, cur_output_size, data);
+ if (len != cur_output_size) {
+ GST_ERROR_OBJECT (src, "Read failed for %d blocks at %d",
+ cur_output_size, src->cur_pack);
+ return GST_DVD_READ_ERROR;
}
- /*
- * Playback by cell in this pgc, starting at the cell for our chapter.
- */
- if (new_seek)
- priv->cur_cell = priv->start_cell;
+ GST_BUFFER_SIZE (buf) = cur_output_size * DVD_VIDEO_LB_LEN;
+ /* GST_BUFFER_OFFSET (buf) = priv->cur_pack * DVD_VIDEO_LB_LEN; */
-again:
+ src->cur_pack = next_vobu;
- if (priv->cur_cell < priv->last_cell) {
- if (priv->new_cell || new_seek) {
- if (!new_seek) {
- priv->cur_cell = priv->next_cell;
- if (priv->cur_cell >= priv->last_cell) {
- GST_LOG ("last cell in chapter");
- goto again;
- }
- }
+ GST_LOG_OBJECT (src, "Read %u sectors", cur_output_size);
+ return GST_DVD_READ_OK;
+}
+
+static GstFlowReturn
+gst_dvd_read_src_create (GstPushSrc * pushsrc, GstBuffer ** p_buf)
+{
+ GstDvdReadSrc *src = GST_DVD_READ_SRC (pushsrc);
+ GstBuffer *buf;
+ GstPad *srcpad;
+ gint res;
- /* take angle into account */
- if (priv->cur_pgc->cell_playback[priv->cur_cell].block_type
- == BLOCK_TYPE_ANGLE_BLOCK)
- priv->cur_cell += angle;
+ g_return_val_if_fail (src->dvd != NULL, GST_FLOW_ERROR);
- /* calculate next cell */
- priv->next_cell = get_next_cell_for (priv, priv->cur_cell);
+ srcpad = GST_BASE_SRC (src)->srcpad;
- /*
- * 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;
+ /* handle events, if any */
+ if (src->seek_pend) {
+ if (src->flush_pend) {
+ gst_pad_push_event (srcpad, gst_event_new_flush_start ());
+ gst_pad_push_event (srcpad, gst_event_new_flush_stop ());
+ src->flush_pend = FALSE;
}
- if (priv->cur_pack <
- priv->cur_pgc->cell_playback[priv->cur_cell].last_sector) {
- dsi_t dsi_pack;
- unsigned int next_vobu, next_ilvu_start, cur_output_size;
- int len;
-
- /*
- * Read NAV packet.
- */
- nav_retry:
-
- len = DVDReadBlocks (priv->dvd_title, priv->cur_pack, 1, data);
- if (len == 0) {
- GST_ERROR ("Read failed for block %d", priv->cur_pack);
- return -1;
+ if (src->seek_pend_fmt != GST_FORMAT_UNDEFINED) {
+ if (src->seek_pend_fmt == title_format) {
+ gst_dvd_read_src_goto_title (src, src->title, src->angle);
}
+ gst_dvd_read_src_goto_chapter (src, src->chapter);
- if (!is_nav_pack (data)) {
- priv->cur_pack++;
- goto nav_retry;
+ src->seek_pend_fmt = GST_FORMAT_UNDEFINED;
+ } else {
+ if (!gst_dvd_read_src_goto_sector (src, src->angle)) {
+ GST_DEBUG_OBJECT (src, "seek to sector failed, going EOS");
+ gst_pad_push_event (srcpad, gst_event_new_eos ());
+ return GST_FLOW_UNEXPECTED;
}
+ }
+ gst_pad_push_event (srcpad,
+ gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
+ src->cur_pack * DVD_VIDEO_LB_LEN, -1, 0));
- /*
- * Parse the contained dsi packet.
- */
- navRead_DSI (&dsi_pack, &(data[DSI_START_BYTE]));
- assert (priv->cur_pack == dsi_pack.dsi_gi.nv_pck_lbn);
-
-
- /*
- * Determine where we go next. These values are the ones we mostly
- * care about.
- */
- next_ilvu_start = priv->cur_pack + dsi_pack.sml_agli.data[angle].address;
- cur_output_size = dsi_pack.dsi_gi.vobu_ea;
-
-
- /*
- * If we're not at the end of this cell, we can determine the next
- * VOBU to display using the VOBU_SRI information section of the
- * DSI. Using this value correctly follows the current angle,
- * avoiding the doubled scenes in The Matrix, and makes our life
- * really happy.
- *
- * Otherwise, we set our next address past the end of this cell to
- * force the code above to go to the next cell in the program.
- */
- if (dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL) {
- next_vobu = priv->cur_pack + (dsi_pack.vobu_sri.next_vobu & 0x7fffffff);
- } else {
- next_vobu = priv->cur_pack + cur_output_size + 1;
- }
+ src->seek_pend = FALSE;
+ }
- 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;
- }
+ if (src->new_seek) {
+ gst_dvd_read_src_goto_title (src, src->title, src->angle);
+ gst_dvd_read_src_goto_chapter (src, src->chapter);
- GST_BUFFER_SIZE (buf) = cur_output_size * DVD_VIDEO_LB_LEN;
- //GST_BUFFER_OFFSET (buf) = priv->cur_pack * DVD_VIDEO_LB_LEN;
- }
+ src->new_seek = FALSE;
+ src->change_cell = TRUE;
+ }
- priv->cur_pack = next_vobu;
+ if (src->title_lang_event_pending) {
+ gst_pad_push_event (srcpad, src->title_lang_event_pending);
+ src->title_lang_event_pending = NULL;
+ }
- GST_LOG ("done reading data - %u sectors", cur_output_size);
+ if (src->pending_clut_event) {
+ gst_pad_push_event (srcpad, src->pending_clut_event);
+ src->pending_clut_event = NULL;
+ }
- return 0;
- } else {
- priv->new_cell = TRUE;
- }
- } else {
- /* 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;
- }
+ /* create the buffer (TODO: use buffer pool?) */
+ buf = gst_buffer_new_and_alloc (1024 * DVD_VIDEO_LB_LEN);
- GST_LOG ("end-of-chapter, switch to next");
+ /* read it in */
+ do {
+ res = gst_dvd_read_src_read (src, src->angle, src->change_cell, buf);
+ } while (res == GST_DVD_READ_AGAIN);
- priv->chapter++;
- _seek_chapter (priv, priv->chapter);
+ switch (res) {
+ case GST_DVD_READ_ERROR:{
+ GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), (NULL));
+ gst_buffer_unref (buf);
+ return GST_FLOW_ERROR;
+ }
+ case GST_DVD_READ_EOS:{
+ GST_INFO_OBJECT (src, "Reached EOS");
+ gst_pad_push_event (GST_BASE_SRC (src)->srcpad, gst_event_new_eos ());
+ gst_buffer_unref (buf);
+ return GST_FLOW_UNEXPECTED;
+ }
+ case GST_DVD_READ_OK:{
+ src->change_cell = FALSE;
+ *p_buf = buf;
+ return GST_FLOW_OK;
+ }
+ default:
+ break;
}
- /* again */
- GST_LOG ("Need another try");
-
- return -3;
+ g_return_val_if_reached (GST_FLOW_UNEXPECTED);
}
-static gboolean
-seek_sector (DVDReadSrcPrivate * priv, int angle)
+static void
+gst_dvd_read_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
{
- gint seek_to = priv->cur_pack;
- gint chapter, sectors, next, cur, i;
+ GstDvdReadSrc *src = GST_DVD_READ_SRC (object);
- /* retrieve position */
- priv->cur_pack = 0;
- for (i = 0; i < priv->tt_srpt->title[priv->title].nr_of_ptts; i++) {
- gint c1, c2;
+ GST_OBJECT_LOCK (src);
- 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;
- }
+ switch (prop_id) {
+ case ARG_DEVICE:{
+ if (!GST_OBJECT_FLAG_IS_SET (src, GST_BASE_SRC_STARTED)) {
+ g_warning ("%s: property '%s' needs to be set before the device is "
+ "opened", GST_ELEMENT_NAME (src), pspec->name);
+ break;;
+ }
- 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;
+ g_free (src->location);
+ /* clear the filename if we get a NULL (is that possible?) */
+ if (g_value_get_string (value) == NULL) {
+ src->location = g_strdup ("/dev/dvd");
+ } else {
+ src->location = g_strdup (g_value_get_string (value));
}
- cur = next;
- if (priv->cur_pgc->cell_playback[cur].block_type
- == BLOCK_TYPE_ANGLE_BLOCK)
- cur += angle;
- next = get_next_cell_for (priv, cur);
+ break;
}
+ case ARG_TITLE:
+ src->title = g_value_get_int (value);
+ src->new_seek = TRUE;
+ break;
+ case ARG_CHAPTER:
+ src->chapter = g_value_get_int (value);
+ src->new_seek = TRUE;
+ break;
+ case ARG_ANGLE:
+ src->angle = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
}
- GST_LOG ("Seek to sector %u failed", seek_to);
- return FALSE;
+ GST_OBJECT_UNLOCK (src);
+}
-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);
+static void
+gst_dvd_read_src_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstDvdReadSrc *src = GST_DVD_READ_SRC (object);
- _seek_chapter (priv, chapter);
- priv->cur_cell = cur;
- priv->next_cell = next;
- priv->new_cell = FALSE;
- priv->cur_pack = seek_to;
+ GST_OBJECT_LOCK (src);
- return TRUE;
+ switch (prop_id) {
+ case ARG_DEVICE:
+ g_value_set_string (value, src->location);
+ break;
+ case ARG_TITLE:
+ g_value_set_int (value, src->title);
+ break;
+ case ARG_CHAPTER:
+ g_value_set_int (value, src->chapter);
+ break;
+ case ARG_ANGLE:
+ g_value_set_int (value, src->angle);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ GST_OBJECT_UNLOCK (src);
}
-static GstData *
-dvdreadsrc_get (GstPad * pad)
+/*** Querying and seeking ***/
+
+static gboolean
+gst_dvd_read_src_do_seek (GstDvdReadSrc * src, GstEvent * event)
{
- gint res;
- DVDReadSrc *dvdreadsrc;
- DVDReadSrcPrivate *priv;
- GstBuffer *buf;
+ GstSeekFlags flags;
+ GstSeekType cur_type, end_type;
+ gint64 new_off, total, cur;
+ GstFormat format;
+ GstPad *srcpad;
+ gdouble rate;
- g_return_val_if_fail (pad != NULL, NULL);
- g_return_val_if_fail (GST_IS_PAD (pad), NULL);
+ srcpad = GST_BASE_SRC (src)->srcpad;
- dvdreadsrc = DVDREADSRC (gst_pad_get_parent (pad));
- priv = dvdreadsrc->priv;
- g_return_val_if_fail (GST_OBJECT_FLAG_IS_SET (dvdreadsrc, DVDREADSRC_OPEN),
- NULL);
+ gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &new_off,
+ &end_type, NULL);
- /* handle vents, if any */
- if (priv->seek_pend) {
- if (priv->flush_pend) {
- priv->flush_pend = FALSE;
+ if (end_type != GST_SEEK_TYPE_NONE) {
+ GST_WARNING_OBJECT (src, "End seek type not supported, will be ignored");
+ }
- return GST_DATA (gst_event_new (GST_EVENT_FLUSH));
+ switch (format) {
+ case GST_FORMAT_BYTES:{
+ new_off /= DVD_VIDEO_LB_LEN;
+ format = sector_format;
+ break;
}
-
- 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)) {
- gst_element_set_eos (GST_ELEMENT (dvdreadsrc));
- return GST_DATA (gst_event_new (GST_EVENT_EOS));
+ default:{
+ if (format != chapter_format &&
+ format != sector_format &&
+ format != angle_format && format != title_format) {
+ GST_DEBUG_OBJECT (src, "Unsupported seek format %d (%s)", format,
+ gst_format_get_name (format));
+ return FALSE;
}
+ break;
}
-
- return GST_DATA (gst_event_new_discontinuous (FALSE,
- GST_FORMAT_BYTES, (gint64) (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);
+ /* get current offset and length */
+ gst_pad_query_duration (srcpad, &format, &total);
+ gst_pad_query_position (srcpad, &format, &cur);
+
+ GST_DEBUG_OBJECT (src, "Current %s: %" G_GINT64_FORMAT,
+ gst_format_get_name (format), cur);
+ GST_DEBUG_OBJECT (src, "Total %s: %" G_GINT64_FORMAT,
+ gst_format_get_name (format), total);
- if (priv->new_seek) {
- _seek_title (priv, priv->title, priv->angle);
- _seek_chapter (priv, priv->chapter);
+ if (cur == new_off) {
+ GST_DEBUG_OBJECT (src, "We're already at that position!");
+ return TRUE;
}
- /* read it in from the file */
- while ((res = _read (priv, priv->angle, priv->new_seek, buf)) == -3);
- switch (res) {
- case -1:
- GST_ELEMENT_ERROR (dvdreadsrc, RESOURCE, READ, (NULL), (NULL));
- gst_buffer_unref (buf);
- return NULL;
- case -2:
- gst_element_set_eos (GST_ELEMENT (dvdreadsrc));
- gst_buffer_unref (buf);
- return GST_DATA (gst_event_new (GST_EVENT_EOS));
- case 0:
+ /* get absolute */
+ switch (cur_type) {
+ case GST_SEEK_TYPE_SET:
+ /* no-op */
+ break;
+ case GST_SEEK_TYPE_CUR:
+ new_off += cur;
+ break;
+ case GST_SEEK_TYPE_END:
+ new_off = total - new_off;
break;
default:
- g_assert_not_reached ();
+ GST_DEBUG_OBJECT (src, "Unsupported seek method");
+ return FALSE;
+ }
+
+ if (new_off < 0 || new_off >= total) {
+ GST_DEBUG_OBJECT (src, "Invalid seek position %" G_GINT64_FORMAT, new_off);
+ return FALSE;
+ }
+
+ GST_LOG_OBJECT (src, "Seeking to unit %" G_GINT64_FORMAT, new_off);
+
+ GST_OBJECT_LOCK (src);
+
+ if (format == angle_format) {
+ src->angle = new_off;
+ GST_OBJECT_UNLOCK (src);
+ return TRUE;
+ }
+
+ if (format == sector_format) {
+ src->cur_pack = new_off;
+ } else if (format == chapter_format) {
+ src->cur_pack = 0;
+ src->chapter = new_off;
+ src->seek_pend_fmt = format;
+ } else if (format == title_format) {
+ src->cur_pack = 0;
+ src->title = new_off;
+ src->chapter = 0;
+ src->seek_pend_fmt = format;
+ } else {
+ g_return_val_if_reached (FALSE);
}
- priv->new_seek = FALSE;
+ /* leave for events */
+ src->seek_pend = TRUE;
+ if ((flags & GST_SEEK_FLAG_FLUSH) != 0)
+ src->flush_pend = TRUE;
- return GST_DATA (buf);
+ GST_OBJECT_UNLOCK (src);
+
+ return TRUE;
}
-/* open the file, necessary to go to RUNNING state */
static gboolean
-dvdreadsrc_open_file (DVDReadSrc * src)
+gst_dvd_read_src_src_event (GstBaseSrc * basesrc, GstEvent * event)
{
- g_return_val_if_fail (src != NULL, FALSE);
- g_return_val_if_fail (GST_IS_DVDREADSRC (src), FALSE);
- g_return_val_if_fail (!GST_OBJECT_FLAG_IS_SET (src, DVDREADSRC_OPEN), FALSE);
+ GstDvdReadSrc *src = GST_DVD_READ_SRC (basesrc);
+ gboolean res;
- if (_open (src->priv, src->priv->location)) {
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), (NULL));
- return FALSE;
+ GST_DEBUG_OBJECT (src, "handling %s event", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ res = gst_dvd_read_src_do_seek (src, event);
+ break;
+ default:
+ res = GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
+ break;
}
- src->priv->seek_pend_fmt = title_format;
- src->priv->seek_pend = TRUE;
- GST_OBJECT_FLAG_SET (src, DVDREADSRC_OPEN);
+ return res;
+}
+
+static GstEvent *
+gst_dvd_read_src_make_clut_change_event (GstDvdReadSrc * src,
+ const guint * clut)
+{
+ GstStructure *structure;
+ gchar name[16];
+ gint i;
+
+ structure = gst_structure_new ("application/x-gst-dvd",
+ "event", G_TYPE_STRING, "dvd-spu-clut-change", NULL);
+
+ /* Create a separate field for each value in the table. */
+ for (i = 0; i < 16; i++) {
+ g_snprintf (name, sizeof (name), "clut%02d", i);
+ gst_structure_set (structure, name, G_TYPE_INT, (int) clut[i], NULL);
+ }
+
+ /* Create the DVD event and put the structure into it. */
+ return gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, structure);
+}
+
+static gint64
+gst_dvd_read_src_convert_timecode (dvd_time_t * time)
+{
+ gint64 ret_time;
+ const gint64 one_hour = 3600 * GST_SECOND;
+ const gint64 one_min = 60 * GST_SECOND;
+
+ g_return_val_if_fail ((time->hour >> 4) < 0xa
+ && (time->hour & 0xf) < 0xa, -1);
+ g_return_val_if_fail ((time->minute >> 4) < 0x7
+ && (time->minute & 0xf) < 0xa, -1);
+ g_return_val_if_fail ((time->second >> 4) < 0x7
+ && (time->second & 0xf) < 0xa, -1);
+
+ ret_time = ((time->hour >> 4) * 10 + (time->hour & 0xf)) * one_hour;
+ ret_time += ((time->minute >> 4) * 10 + (time->minute & 0xf)) * one_min;
+ ret_time += ((time->second >> 4) * 10 + (time->second & 0xf)) * GST_SECOND;
+
+ return ret_time;
+}
+static gboolean
+gst_dvd_read_src_do_duration_query (GstDvdReadSrc * src, GstQuery * query)
+{
+ GstFormat format;
+ gint64 val;
+
+ gst_query_parse_duration (query, &format, NULL);
+
+ switch (format) {
+ case GST_FORMAT_TIME:{
+ if (src->cur_pgc == NULL)
+ return FALSE;
+ val = gst_dvd_read_src_convert_timecode (&src->cur_pgc->playback_time);
+ if (val < 0)
+ return FALSE;
+ break;
+ }
+ case GST_FORMAT_BYTES:{
+ val = DVDFileSize (src->dvd_title) * DVD_VIDEO_LB_LEN;
+ break;
+ }
+ default:{
+ if (format == sector_format) {
+ val = DVDFileSize (src->dvd_title);
+ } else if (format == title_format) {
+ val = src->tt_srpt->nr_of_srpts;
+ } else if (format == chapter_format) {
+ val = src->num_chapters;
+ } else if (format == angle_format) {
+ val = src->tt_srpt->title[src->title].nr_of_angles;
+ } else {
+ GST_DEBUG_OBJECT (src, "Don't know how to handle format %d (%s)",
+ format, gst_format_get_name (format));
+ return FALSE;
+ }
+ break;
+ }
+ }
+
+ gst_query_set_duration (query, format, val);
return TRUE;
}
-/* close the file */
-static void
-dvdreadsrc_close_file (DVDReadSrc * src)
+static gboolean
+gst_dvd_read_src_do_position_query (GstDvdReadSrc * src, GstQuery * query)
{
- g_return_if_fail (GST_OBJECT_FLAG_IS_SET (src, DVDREADSRC_OPEN));
+ GstFormat format;
+ gint64 val;
- _close (src->priv);
+ gst_query_parse_position (query, &format, NULL);
- GST_OBJECT_FLAG_UNSET (src, DVDREADSRC_OPEN);
+ switch (format) {
+ case GST_FORMAT_BYTES:{
+ val = src->cur_pack * DVD_VIDEO_LB_LEN;
+ break;
+ }
+ default:{
+ if (format == sector_format) {
+ val = src->cur_pack;
+ } else if (format == title_format) {
+ val = src->title;
+ } else if (format == chapter_format) {
+ val = src->chapter;
+ } else if (format == angle_format) {
+ val = src->angle;
+ } else {
+ GST_DEBUG_OBJECT (src, "Don't know how to handle format %d (%s)",
+ format, gst_format_get_name (format));
+ return FALSE;
+ }
+ break;
+ }
+ }
+
+ gst_query_set_position (query, format, val);
+ return TRUE;
}
-static GstStateChangeReturn
-dvdreadsrc_change_state (GstElement * element, GstStateChange transition)
+static gboolean
+gst_dvd_read_src_src_query (GstBaseSrc * basesrc, GstQuery * query)
{
- DVDReadSrc *dvdreadsrc = DVDREADSRC (element);
+ GstDvdReadSrc *src = GST_DVD_READ_SRC (basesrc);
+ gboolean started;
+ gboolean res = TRUE;
- g_return_val_if_fail (GST_IS_DVDREADSRC (element), GST_STATE_CHANGE_FAILURE);
+ GST_LOG_OBJECT (src, "handling %s query",
+ gst_query_type_get_name (GST_QUERY_TYPE (query)));
- GST_DEBUG ("gstdvdreadsrc: state pending %d", GST_STATE_PENDING (element));
+ GST_OBJECT_LOCK (src);
+ started = (GST_OBJECT_FLAG_IS_SET (src, GST_BASE_SRC_STARTED));
+ GST_OBJECT_UNLOCK (src);
- /* if going down into NULL state, close the file if it's open */
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- if (!dvdreadsrc_open_file (DVDREADSRC (element)))
- return GST_STATE_CHANGE_FAILURE;
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- dvdreadsrc->priv->new_cell = TRUE;
- 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;
+ if (!started) {
+ GST_DEBUG_OBJECT (src, "query failed: not started");
+ return FALSE;
+ }
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_DURATION:
+ GST_OBJECT_LOCK (src);
+ res = gst_dvd_read_src_do_duration_query (src, query);
+ GST_OBJECT_UNLOCK (src);
break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- dvdreadsrc_close_file (DVDREADSRC (element));
+ case GST_QUERY_POSITION:
+ GST_OBJECT_LOCK (src);
+ res = gst_dvd_read_src_do_position_query (src, query);
+ GST_OBJECT_UNLOCK (src);
break;
default:
+ res = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
break;
}
- /* if we haven't failed already, give the parent class a chance to ;-) */
- if (GST_ELEMENT_CLASS (parent_class)->change_state)
- return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ return res;
+}
- return GST_STATE_CHANGE_SUCCESS;
+static gboolean
+gst_dvd_read_src_goto_sector (GstDvdReadSrc * src, int angle)
+{
+ gint seek_to = src->cur_pack;
+ gint chapter, sectors, next, cur, i;
+
+ /* retrieve position */
+ src->cur_pack = 0;
+ for (i = 0; i < src->num_chapters; i++) {
+ gint c1, c2;
+
+ cur_title_get_chapter_bounds (src, i, &c1, &c2);
+
+ for (next = cur = c1; cur < c2;) {
+ if (next != cur) {
+ sectors =
+ src->cur_pgc->cell_playback[cur].last_sector -
+ src->cur_pgc->cell_playback[cur].first_sector;
+ if (src->cur_pack + sectors > seek_to) {
+ chapter = i;
+ goto done;
+ }
+ src->cur_pack += sectors;
+ }
+ cur = next;
+ if (src->cur_pgc->cell_playback[cur].block_type == BLOCK_TYPE_ANGLE_BLOCK)
+ cur += angle;
+ next = gst_dvd_read_src_get_next_cell_for (src, cur);
+ }
+ }
+
+ GST_DEBUG_OBJECT (src, "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_INFO_OBJECT (src, "Seek succeeded, going to chapter %u, cell %u",
+ chapter, cur);
+
+ gst_dvd_read_src_goto_chapter (src, chapter);
+ src->cur_cell = cur;
+ src->next_cell = next;
+ src->new_cell = FALSE;
+ src->cur_pack = seek_to;
+
+ return TRUE;
}
-/*
- * URI interface.
- */
+
+/*** URI interface ***/
static GstURIType
-dvdreadsrc_uri_get_type (void)
+gst_dvd_read_src_uri_get_type (void)
{
return GST_URI_SRC;
}
static gchar **
-dvdreadsrc_uri_get_protocols (void)
+gst_dvd_read_src_uri_get_protocols (void)
{
static gchar *protocols[] = { "dvd", NULL };
}
static const gchar *
-dvdreadsrc_uri_get_uri (GstURIHandler * handler)
+gst_dvd_read_src_uri_get_uri (GstURIHandler * handler)
{
- DVDReadSrc *dvdreadsrc = DVDREADSRC (handler);
+ GstDvdReadSrc *src = GST_DVD_READ_SRC (handler);
- g_free (dvdreadsrc->priv->last_uri);
- dvdreadsrc->priv->last_uri =
- g_strdup_printf ("dvd://%d,%d,%d", dvdreadsrc->priv->title,
- dvdreadsrc->priv->chapter, dvdreadsrc->priv->angle);
+ g_free (src->last_uri);
+ src->last_uri =
+ g_strdup_printf ("dvd://%d,%d,%d", src->title, src->chapter, src->angle);
- return dvdreadsrc->priv->last_uri;
+ return src->last_uri;
}
static gboolean
-dvdreadsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+gst_dvd_read_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
{
- DVDReadSrc *dvdreadsrc = DVDREADSRC (handler);
+ GstDvdReadSrc *src = GST_DVD_READ_SRC (handler);
gboolean ret;
- gchar *protocol = gst_uri_get_protocol (uri);
+ gchar *protocol;
- ret = (protocol && !strcmp (protocol, "dvd")) ? TRUE : FALSE;
+ protocol = gst_uri_get_protocol (uri);
+ ret = (protocol != NULL && g_str_equal (protocol, "dvd"));
g_free (protocol);
protocol = NULL;
if (!ret)
return ret;
- /*
- * Parse out the new t/c/a and seek to them
- */
+ /* parse out the new t/c/a and seek to them */
{
gchar *location = NULL;
gchar **strs;
switch (pos) {
case 0:
- if (val != dvdreadsrc->priv->title) {
- dvdreadsrc->priv->title = val;
- dvdreadsrc->priv->new_seek = TRUE;
+ if (val != src->title) {
+ src->title = val;
+ src->new_seek = TRUE;
}
break;
case 1:
- if (val != dvdreadsrc->priv->chapter) {
- dvdreadsrc->priv->chapter = val;
- dvdreadsrc->priv->new_seek = TRUE;
+ if (val != src->chapter) {
+ src->chapter = val;
+ src->new_seek = TRUE;
}
break;
case 2:
- dvdreadsrc->priv->angle = val;
+ src->angle = val;
break;
}
}
static void
-dvdreadsrc_uri_handler_init (gpointer g_iface, gpointer iface_data)
+gst_dvd_read_src_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;
+ iface->get_type = gst_dvd_read_src_uri_get_type;
+ iface->get_protocols = gst_dvd_read_src_uri_get_protocols;
+ iface->get_uri = gst_dvd_read_src_uri_get_uri;
+ iface->set_uri = gst_dvd_read_src_uri_set_uri;
+}
+
+static void
+gst_dvd_read_src_do_init (GType dvdreadsrc_type)
+{
+ static const GInterfaceInfo urihandler_info = {
+ gst_dvd_read_src_uri_handler_init,
+ NULL,
+ NULL
+ };
+
+ g_type_add_interface_static (dvdreadsrc_type, GST_TYPE_URI_HANDLER,
+ &urihandler_info);
+
+ title_format = gst_format_register ("title", "DVD title");
+ angle_format = gst_format_register ("angle", "DVD angle");
+ sector_format = gst_format_register ("sector", "DVD sector");
+ chapter_format = gst_format_register ("chapter", "DVD chapter");
}
static gboolean
plugin_init (GstPlugin * plugin)
{
- if (!gst_element_register (plugin, "dvdreadsrc", GST_RANK_NONE,
- GST_TYPE_DVDREADSRC))
+ GST_DEBUG_CATEGORY_INIT (gstgst_dvd_read_src_debug, "dvdreadsrc", 0,
+ "DVD reader element based on dvdreadsrc");
+
+ if (!gst_element_register (plugin, "dvdreadsrc", GST_RANK_SECONDARY,
+ GST_TYPE_DVD_READ_SRC)) {
return FALSE;
+ }
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
- "dvdreadsrc",
+ "dvdread",
"Access a DVD with dvdread",
plugin_init, VERSION, "GPL", GST_PACKAGE, GST_ORIGIN)
+++ /dev/null
-/* GStreamer
- * Copyright (C) <2005> Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "dvdreadsrc.h"
-#include "stream_labels.h"
-#include <gst/gst-i18n-plugin.h>
-
-GHashTable *
-dvdreadsrc_init_languagelist (void)
-{
- GHashTable *languagelist = NULL;
-
- languagelist = g_hash_table_new (g_str_hash, g_str_equal);
-
- g_hash_table_insert (languagelist, "aa", _("Afar"));
- g_hash_table_insert (languagelist, "ab", _("Abkhazian"));
- g_hash_table_insert (languagelist, "af", _("Afrikaans"));
- g_hash_table_insert (languagelist, "am", _("Amharic"));
- g_hash_table_insert (languagelist, "ar", _("Arabic"));
- g_hash_table_insert (languagelist, "as", _("Assamese"));
- g_hash_table_insert (languagelist, "ax", _("Aymara"));
- g_hash_table_insert (languagelist, "az", _("Azerbaijani"));
- g_hash_table_insert (languagelist, "ba", _("Bashkir"));
- g_hash_table_insert (languagelist, "be", _("Byelorussian"));
- g_hash_table_insert (languagelist, "bg", _("Bulgarian"));
- g_hash_table_insert (languagelist, "bh", _("Bislama"));
- g_hash_table_insert (languagelist, "bn", _("Bengali"));
- g_hash_table_insert (languagelist, "bo", _("Tibetan"));
- g_hash_table_insert (languagelist, "br", _("Breton"));
- g_hash_table_insert (languagelist, "ca", _("Catalan"));
- g_hash_table_insert (languagelist, "co", _("Corsican"));
- g_hash_table_insert (languagelist, "cs", _("Czech"));
- g_hash_table_insert (languagelist, "cy", _("Welsh"));
- g_hash_table_insert (languagelist, "da", _("Danish"));
- g_hash_table_insert (languagelist, "de", _("German"));
- g_hash_table_insert (languagelist, "dz", _("Bhutani"));
- g_hash_table_insert (languagelist, "el", _("Greek"));
- g_hash_table_insert (languagelist, "en", _("English"));
- g_hash_table_insert (languagelist, "eo", _("Esperanto"));
- g_hash_table_insert (languagelist, "es", _("Spanish"));
- g_hash_table_insert (languagelist, "et", _("Estonian"));
- g_hash_table_insert (languagelist, "eu", _("Basque"));
- g_hash_table_insert (languagelist, "fa", _("Persian"));
- g_hash_table_insert (languagelist, "fi", _("Finnish"));
- g_hash_table_insert (languagelist, "fj", _("Fiji"));
- g_hash_table_insert (languagelist, "fo", _("Faeroese"));
- g_hash_table_insert (languagelist, "fr", _("French"));
- g_hash_table_insert (languagelist, "fy", _("Frisian"));
- g_hash_table_insert (languagelist, "ga", _("Irish"));
- g_hash_table_insert (languagelist, "gd", _("Scots/Gaelic"));
- g_hash_table_insert (languagelist, "gl", _("Galician"));
- g_hash_table_insert (languagelist, "gn", _("Guarani"));
- g_hash_table_insert (languagelist, "gu", _("Gujarati"));
- g_hash_table_insert (languagelist, "ha", _("Hausa"));
- g_hash_table_insert (languagelist, "hi", _("Hindi"));
- g_hash_table_insert (languagelist, "hr", _("Croatian"));
- g_hash_table_insert (languagelist, "hu", _("Hungarian"));
- g_hash_table_insert (languagelist, "hy", _("Armenian"));
- g_hash_table_insert (languagelist, "ia", _("Interlingua"));
- g_hash_table_insert (languagelist, "in", _("Indonesian"));
- g_hash_table_insert (languagelist, "is", _("Icelandic"));
- g_hash_table_insert (languagelist, "it", _("Italian"));
- g_hash_table_insert (languagelist, "iw", _("Hebrew"));
- g_hash_table_insert (languagelist, "ja", _("Japanese"));
- g_hash_table_insert (languagelist, "ji", _("Yiddish"));
- g_hash_table_insert (languagelist, "jw", _("Javanese"));
- g_hash_table_insert (languagelist, "ka", _("Georgian"));
- g_hash_table_insert (languagelist, "kk", _("Kazakh"));
- g_hash_table_insert (languagelist, "kl", _("Greenlandic"));
- g_hash_table_insert (languagelist, "km", _("Cambodian"));
- g_hash_table_insert (languagelist, "kn", _("Kannada"));
- g_hash_table_insert (languagelist, "ko", _("Korean"));
- g_hash_table_insert (languagelist, "ks", _("Kashmiri"));
- g_hash_table_insert (languagelist, "ku", _("Kurdish"));
- g_hash_table_insert (languagelist, "ky", _("Kirghiz"));
- g_hash_table_insert (languagelist, "la", _("Latin"));
- g_hash_table_insert (languagelist, "ln", _("Lingala"));
- g_hash_table_insert (languagelist, "lo", _("Laothian"));
- g_hash_table_insert (languagelist, "lt", _("Lithuanian"));
- g_hash_table_insert (languagelist, "lv", _("Latvian/Lettish"));
- g_hash_table_insert (languagelist, "mg", _("Malagasy"));
- g_hash_table_insert (languagelist, "mi", _("Maori"));
- g_hash_table_insert (languagelist, "mk", _("Macedonian"));
- g_hash_table_insert (languagelist, "ml", _("Malayalam"));
- g_hash_table_insert (languagelist, "mn", _("Mongolian"));
- g_hash_table_insert (languagelist, "mo", _("Moldavian"));
- g_hash_table_insert (languagelist, "mr", _("Marathi"));
- g_hash_table_insert (languagelist, "ms", _("Malay"));
- g_hash_table_insert (languagelist, "mt", _("Maltese"));
- g_hash_table_insert (languagelist, "my", _("Burmese"));
- g_hash_table_insert (languagelist, "na", _("Nauru"));
- g_hash_table_insert (languagelist, "ne", _("Nepali"));
- g_hash_table_insert (languagelist, "nl", _("Dutch"));
- g_hash_table_insert (languagelist, "no", _("Norwegian"));
- g_hash_table_insert (languagelist, "or", _("Oriya"));
- g_hash_table_insert (languagelist, "pa", _("Punjabi"));
- g_hash_table_insert (languagelist, "pl", _("Polish"));
- g_hash_table_insert (languagelist, "ps", _("Pashto/Pushto"));
- g_hash_table_insert (languagelist, "pt", _("Portuguese"));
- g_hash_table_insert (languagelist, "qu", _("Quechua"));
- g_hash_table_insert (languagelist, "rm", _("Rhaeto-Romance"));
- g_hash_table_insert (languagelist, "ro", _("Romanian"));
- g_hash_table_insert (languagelist, "ru", _("Russian"));
- g_hash_table_insert (languagelist, "sa", _("Kinyarwanda"));
- g_hash_table_insert (languagelist, "sd", _("Sanskrit"));
- g_hash_table_insert (languagelist, "sh", _("Serbo-Croatian"));
- g_hash_table_insert (languagelist, "si", _("Singhalese"));
- g_hash_table_insert (languagelist, "sk", _("Slovak"));
- g_hash_table_insert (languagelist, "sl", _("Slovenian"));
- g_hash_table_insert (languagelist, "sm", _("Samoan"));
- g_hash_table_insert (languagelist, "sn", _("Shona"));
- g_hash_table_insert (languagelist, "so", _("Somali"));
- g_hash_table_insert (languagelist, "sq", _("Albanian"));
- g_hash_table_insert (languagelist, "sr", _("Serbian"));
- g_hash_table_insert (languagelist, "su", _("Sundanese"));
- g_hash_table_insert (languagelist, "sv", _("Swedish"));
- g_hash_table_insert (languagelist, "sw", _("Swahili"));
- g_hash_table_insert (languagelist, "ta", _("Tamil"));
- g_hash_table_insert (languagelist, "te", _("Tegulu"));
- g_hash_table_insert (languagelist, "tg", _("Tajik"));
- g_hash_table_insert (languagelist, "th", _("Thai"));
- g_hash_table_insert (languagelist, "ti", _("Tigrinya"));
- g_hash_table_insert (languagelist, "tk", _("Turkmen"));
- g_hash_table_insert (languagelist, "tl", _("Tagalog"));
- g_hash_table_insert (languagelist, "to", _("Tonga"));
- g_hash_table_insert (languagelist, "tr", _("Turkish"));
- g_hash_table_insert (languagelist, "tt", _("Tatar"));
- g_hash_table_insert (languagelist, "tw", _("Twi"));
- g_hash_table_insert (languagelist, "uk", _("Ukrainian"));
- g_hash_table_insert (languagelist, "ur", _("Urdu"));
- g_hash_table_insert (languagelist, "uz", _("Uzbek"));
- g_hash_table_insert (languagelist, "vi", _("Vietnamese"));
- g_hash_table_insert (languagelist, "vo", _("Volapuk"));
- g_hash_table_insert (languagelist, "wo", _("Wolof"));
- g_hash_table_insert (languagelist, "xh", _("Xhosa"));
- g_hash_table_insert (languagelist, "yo", _("Yoruba"));
- g_hash_table_insert (languagelist, "zh", _("Chinese"));
- g_hash_table_insert (languagelist, "zu", _("Zulu"));
-
- return languagelist;
-}
-
-void
-dvdreadsrc_get_audio_stream_labels (ifo_handle_t * vts_file,
- GHashTable * languagelist)
-{
- GList *audio_stream_label = NULL;
-
- if (vts_file->vts_pgcit) {
- int i;
-
- /* 8 audio streams maximum */
- for (i = 0; i < 8; i++) {
- const gchar *format, *channel_nb, *language = NULL;
- guchar language_code[3] = "??";
- gchar *streamlabel;
-
- if (vts_file->vts_pgcit->pgci_srp[0].pgc->audio_control[i] & 0x8000) {
- audio_attr_t *audio = &vts_file->vtsi_mat->vts_audio_attr[i];
-
- if (audio->lang_type == 1) {
- language_code[0] = (audio->lang_code >> 8);
- language_code[1] = (audio->lang_code & 0xFF);
- language = g_hash_table_lookup (languagelist, language_code);
- }
-
- if (!language) {
- language = "?";
- }
-
- switch (audio->audio_format) {
- case 0:
- format = _("Dolby AC-3");
- break;
- case 2:
- case 3:
- format = _("MPEG layer I, II or III");
- break;
- case 4:
- format = _("LPCM");
- break;
- case 6:
- format = _("Digital Theatre System");
- break;
- default:
- format = "?";
- }
-
- switch (audio->channels) {
- case 1:
- channel_nb = _("Stereo");
- break;
- case 5:
- channel_nb = _("5.1");
- break;
- default:
- channel_nb = "?";
- }
-
- streamlabel = g_strdup_printf ("%u : %s, %s %s", i + 1, language,
- format, channel_nb);
- audio_stream_label = g_list_append (audio_stream_label, streamlabel); /* "French, Dolby AC-3 Stereo" */
-
- printf ("%u : %s, %s %s\n", i + 1, language, format, channel_nb);
- }
- }
- }
-
- g_list_foreach (audio_stream_label, (GFunc) g_free, NULL);
- g_list_free (audio_stream_label);
-}
-
-void
-dvdreadsrc_get_subtitle_stream_labels (ifo_handle_t * vts_file,
- GHashTable * languagelist)
-{
-
-}