mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
97148ae7cd
Original commit message from CVS: * ext/dvdread/dvdreadsrc.c: (dvdreadsrc_class_init), (dvdreadsrc_init), (dvdreadsrc_dispose), (dvdreadsrc_set_property), (dvdreadsrc_get_property), (_open), (_seek), (_read), (dvdreadsrc_get), (dvdreadsrc_open_file), (dvdreadsrc_change_state): Fix. Don't do one big huge loop around the whole DVD, that will cache all data and thus eat sizeof(dvd) (several GB) before we see something. * gst-libs/gst/riff/riff-read.c: (gst_riff_read_seek): Actually NULL'ify event after using it. * gst/matroska/ebml-read.c: (gst_ebml_read_use_event), (gst_ebml_read_handle_event), (gst_ebml_read_element_id), (gst_ebml_read_element_length), (gst_ebml_read_element_data), (gst_ebml_read_seek), (gst_ebml_read_skip): Handle events. * gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_base_init), (gst_dvd_demux_init), (gst_dvd_demux_get_audio_stream), (gst_dvd_demux_get_subpicture_stream), (gst_dvd_demux_plugin_init): Fix timing (this will probably break if I seek using menus, but I didn't get there yet). VOBs and normal DVDs should now work. Add a mpeg2-only pad with high rank so this get autoplugged for MPEG-2 movies. * gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_base_init), (gst_mpeg_demux_class_init), (gst_mpeg_demux_init), (gst_mpeg_demux_new_output_pad), (gst_mpeg_demux_get_video_stream), (gst_mpeg_demux_get_audio_stream), (gst_mpeg_demux_get_private_stream), (gst_mpeg_demux_parse_packet), (gst_mpeg_demux_parse_pes), (gst_mpeg_demux_plugin_init): Use this as second rank for MPEG-1 and MPEG-2. Still use this for MPEG-1 but use dvddemux for MPEG-2. * gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_class_init), (gst_mpeg_parse_init), (gst_mpeg_parse_new_pad), (gst_mpeg_parse_parse_packhead): Timing. Only add pad template if it exists. Add sink template from class and not from ourselves. This means we will always use the correct sink template even if it is not the one defined in this file.
706 lines
19 KiB
C
706 lines
19 KiB
C
/* GStreamer
|
|
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/**
|
|
* 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
|
|
|
|
#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 <errno.h>
|
|
//#include <linux/cdrom.h>
|
|
#include <assert.h>
|
|
|
|
#include <dvdreadsrc.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;
|
|
|
|
gboolean new_seek;
|
|
|
|
gboolean new_cell;
|
|
|
|
int title, chapter, angle;
|
|
int pgc_id, start_cell, cur_cell, cur_pack;
|
|
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;
|
|
};
|
|
|
|
GST_DEBUG_CATEGORY_STATIC (gstdvdreadsrc_debug);
|
|
#define GST_CAT_DEFAULT (gstdvdreadsrc_debug)
|
|
|
|
GstElementDetails dvdreadsrc_details = {
|
|
"DVD Source",
|
|
"Source/File/DVD",
|
|
"Access a DVD title/chapter/angle using libdvdread",
|
|
"Erik Walthinsen <omega@cse.ogi.edu>",
|
|
};
|
|
|
|
|
|
/* DVDReadSrc signals and args */
|
|
enum
|
|
{
|
|
/* FILL ME */
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
enum
|
|
{
|
|
ARG_0,
|
|
ARG_LOCATION,
|
|
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_dispose (GObject * object);
|
|
|
|
static void dvdreadsrc_set_property (GObject * object, guint prop_id,
|
|
const GValue * value, GParamSpec * pspec);
|
|
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 GstElementStateReturn dvdreadsrc_change_state (GstElement * element);
|
|
|
|
|
|
static GstElementClass *parent_class = NULL;
|
|
|
|
/*static guint dvdreadsrc_signals[LAST_SIGNAL] = { 0 }; */
|
|
|
|
GType
|
|
dvdreadsrc_get_type (void)
|
|
{
|
|
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,
|
|
};
|
|
|
|
dvdreadsrc_type =
|
|
g_type_register_static (GST_TYPE_ELEMENT, "DVDReadSrc",
|
|
&dvdreadsrc_info, 0);
|
|
}
|
|
return dvdreadsrc_type;
|
|
}
|
|
|
|
static void
|
|
dvdreadsrc_base_init (gpointer g_class)
|
|
{
|
|
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
|
|
|
gst_element_class_set_details (element_class, &dvdreadsrc_details);
|
|
}
|
|
|
|
static void
|
|
dvdreadsrc_class_init (DVDReadSrcClass * klass)
|
|
{
|
|
GObjectClass *gobject_class;
|
|
GstElementClass *gstelement_class;
|
|
|
|
gobject_class = (GObjectClass *) klass;
|
|
gstelement_class = (GstElementClass *) klass;
|
|
|
|
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
|
|
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION,
|
|
g_param_spec_string ("location", "location", "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));
|
|
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));
|
|
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->dispose = dvdreadsrc_dispose;
|
|
|
|
gstelement_class->change_state = dvdreadsrc_change_state;
|
|
|
|
GST_DEBUG_CATEGORY_INIT (gstdvdreadsrc_debug, "dvdreadsrc", 0,
|
|
"DVD reader element based on dvdreadsrc");
|
|
}
|
|
|
|
static void
|
|
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_element_add_pad (GST_ELEMENT (dvdreadsrc), dvdreadsrc->priv->srcpad);
|
|
|
|
dvdreadsrc->priv->location = g_strdup ("/dev/dvd");
|
|
dvdreadsrc->priv->new_seek = TRUE;
|
|
dvdreadsrc->priv->new_cell = TRUE;
|
|
dvdreadsrc->priv->title = 0;
|
|
dvdreadsrc->priv->chapter = 0;
|
|
dvdreadsrc->priv->angle = 0;
|
|
}
|
|
|
|
static void
|
|
dvdreadsrc_dispose (GObject * object)
|
|
{
|
|
DVDReadSrc *dvdreadsrc = DVDREADSRC (object);
|
|
|
|
if (dvdreadsrc->priv) {
|
|
g_free (dvdreadsrc->priv->location);
|
|
g_free (dvdreadsrc->priv);
|
|
dvdreadsrc->priv = NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
dvdreadsrc_set_property (GObject * object, guint prop_id, const GValue * value,
|
|
GParamSpec * pspec)
|
|
{
|
|
DVDReadSrc *src;
|
|
DVDReadSrcPrivate *priv;
|
|
|
|
/* it's not null if we got it, but it might not be ours */
|
|
g_return_if_fail (GST_IS_DVDREADSRC (object));
|
|
|
|
src = DVDREADSRC (object);
|
|
priv = src->priv;
|
|
|
|
switch (prop_id) {
|
|
case ARG_LOCATION:
|
|
/* the element must be stopped in order to do this */
|
|
/*g_return_if_fail(!GST_FLAG_IS_SET(src,GST_STATE_RUNNING)); */
|
|
|
|
if (priv->location)
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
static void
|
|
dvdreadsrc_get_property (GObject * object, guint prop_id, GValue * value,
|
|
GParamSpec * pspec)
|
|
{
|
|
DVDReadSrc *src;
|
|
DVDReadSrcPrivate *priv;
|
|
|
|
/* it's not null if we got it, but it might not be ours */
|
|
g_return_if_fail (GST_IS_DVDREADSRC (object));
|
|
|
|
src = DVDREADSRC (object);
|
|
priv = src->priv;
|
|
|
|
switch (prop_id) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/**
|
|
* 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");
|
|
DVDClose (priv->dvd);
|
|
return -1;
|
|
}
|
|
priv->tt_srpt = priv->vmg_file->tt_srpt;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_close (DVDReadSrcPrivate * priv)
|
|
{
|
|
ifoClose (priv->vts_file);
|
|
ifoClose (priv->vmg_file);
|
|
DVDCloseFile (priv->dvd_title);
|
|
DVDClose (priv->dvd);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_seek (DVDReadSrcPrivate * priv, int title, int chapter, int angle)
|
|
{
|
|
/**
|
|
* 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_ERROR ("Invalid title %d (only %d available)",
|
|
title, priv->tt_srpt->nr_of_srpts);
|
|
ifoClose (priv->vmg_file);
|
|
DVDClose (priv->dvd);
|
|
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);
|
|
ifoClose (priv->vmg_file);
|
|
DVDClose (priv->dvd);
|
|
return -1;
|
|
}
|
|
|
|
|
|
/**
|
|
* 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);
|
|
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;
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read function.
|
|
* -1: error, -2: eos, -3: try again, 0: ok.
|
|
*/
|
|
|
|
static int
|
|
_read (DVDReadSrcPrivate * priv, int angle, int new_seek, GstBuffer * buf)
|
|
{
|
|
unsigned char *data;
|
|
|
|
data = GST_BUFFER_DATA (buf);
|
|
|
|
/**
|
|
* Playback by cell in this pgc, starting at the cell for our chapter.
|
|
*/
|
|
if (new_seek) {
|
|
priv->next_cell = priv->start_cell;
|
|
priv->cur_cell = priv->start_cell;
|
|
}
|
|
|
|
if (priv->next_cell < priv->cur_pgc->nr_of_cells) {
|
|
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;
|
|
}
|
|
|
|
|
|
/**
|
|
* We loop until we're out of this cell.
|
|
*/
|
|
if (priv->new_cell) {
|
|
priv->cur_pack =
|
|
priv->cur_pgc->cell_playback[priv->cur_cell].first_sector;
|
|
priv->new_cell = 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.
|
|
*/
|
|
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;
|
|
}
|
|
assert (is_nav_pack (data));
|
|
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
assert (cur_output_size < 1024);
|
|
priv->cur_pack++;
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
GST_BUFFER_SIZE (buf) = cur_output_size * DVD_VIDEO_LB_LEN;
|
|
priv->cur_pack = next_vobu;
|
|
|
|
return 0;
|
|
} else {
|
|
priv->new_cell = TRUE;
|
|
}
|
|
} else {
|
|
return -2;
|
|
}
|
|
|
|
/* again */
|
|
return -3;
|
|
}
|
|
|
|
static GstData *
|
|
dvdreadsrc_get (GstPad * pad)
|
|
{
|
|
gint res;
|
|
DVDReadSrc *dvdreadsrc;
|
|
DVDReadSrcPrivate *priv;
|
|
GstBuffer *buf;
|
|
|
|
g_return_val_if_fail (pad != NULL, NULL);
|
|
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
|
|
|
dvdreadsrc = DVDREADSRC (gst_pad_get_parent (pad));
|
|
priv = dvdreadsrc->priv;
|
|
g_return_val_if_fail (GST_FLAG_IS_SET (dvdreadsrc, DVDREADSRC_OPEN), NULL);
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/* 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:
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
priv->new_seek = FALSE;
|
|
|
|
return GST_DATA (buf);
|
|
}
|
|
|
|
/* open the file, necessary to go to RUNNING state */
|
|
static gboolean
|
|
dvdreadsrc_open_file (DVDReadSrc * src)
|
|
{
|
|
g_return_val_if_fail (src != NULL, FALSE);
|
|
g_return_val_if_fail (GST_IS_DVDREADSRC (src), FALSE);
|
|
g_return_val_if_fail (!GST_FLAG_IS_SET (src, DVDREADSRC_OPEN), FALSE);
|
|
|
|
if (_open (src->priv, src->priv->location)) {
|
|
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;
|
|
}
|
|
|
|
GST_FLAG_SET (src, DVDREADSRC_OPEN);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* close the file */
|
|
static void
|
|
dvdreadsrc_close_file (DVDReadSrc * src)
|
|
{
|
|
g_return_if_fail (GST_FLAG_IS_SET (src, DVDREADSRC_OPEN));
|
|
|
|
_close (src->priv);
|
|
|
|
GST_FLAG_UNSET (src, DVDREADSRC_OPEN);
|
|
}
|
|
|
|
static GstElementStateReturn
|
|
dvdreadsrc_change_state (GstElement * element)
|
|
{
|
|
DVDReadSrc *dvdreadsrc = DVDREADSRC (element);
|
|
|
|
g_return_val_if_fail (GST_IS_DVDREADSRC (element), GST_STATE_FAILURE);
|
|
|
|
GST_DEBUG ("gstdvdreadsrc: state pending %d", GST_STATE_PENDING (element));
|
|
|
|
/* if going down into NULL state, close the file if it's open */
|
|
switch (GST_STATE_TRANSITION (element)) {
|
|
case GST_STATE_NULL_TO_READY:
|
|
if (!dvdreadsrc_open_file (DVDREADSRC (element)))
|
|
return GST_STATE_FAILURE;
|
|
break;
|
|
case GST_STATE_PAUSED_TO_READY:
|
|
dvdreadsrc->priv->new_cell = TRUE;
|
|
dvdreadsrc->priv->new_seek = TRUE;
|
|
dvdreadsrc->priv->chapter = 0;
|
|
dvdreadsrc->priv->title = 0;
|
|
break;
|
|
case GST_STATE_READY_TO_NULL:
|
|
dvdreadsrc_close_file (DVDREADSRC (element));
|
|
break;
|
|
default:
|
|
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);
|
|
|
|
return GST_STATE_SUCCESS;
|
|
}
|
|
|
|
static gboolean
|
|
plugin_init (GstPlugin * plugin)
|
|
{
|
|
if (!gst_element_register (plugin, "dvdreadsrc", GST_RANK_NONE,
|
|
GST_TYPE_DVDREADSRC))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
|
GST_VERSION_MINOR,
|
|
"dvdreadsrc",
|
|
"Access a DVD with dvdread",
|
|
plugin_init, VERSION, "GPL", GST_PACKAGE, GST_ORIGIN)
|