Logo Search packages:      
Sourcecode: vamps version File versions  Download package

play_cell.c

/*
 * play_cell: Read cell from a DVDs VTS program chain and write it to STDOUT.
 *
 *            Should be used in connection with a (currently non-existing) tool
 *            which computes the appropriate numbers. Using play_cell instead
 *            of vamps-play_title avoids this anoying "SCR moves backward"
 *            issue with dvdauthor when authoring streams created by vamps.
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
 *
 *
 * Revision history (latest first):
 *
 * 2004/10/03: Initial.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <dvdread/ifo_read.h>
#include <dvdread/nav_read.h>

#define BUF_SECS  1024


/* shortcuts for some frequently used types */
typedef unsigned char      UInt8;
typedef unsigned long      UInt32;


/* globals */
UInt8       buf [BUF_SECS * DVD_VIDEO_LB_LEN];
const char  progname [] = "play_cell";


/* prototypes */
void play_cell (const char *, int, int, int);
void fatal (char *, ...);


int
main (int argc, char *const argv [])
{
  int vts, pgc, cell;

  if (argc != 5)
  {
    fputs ("Usage: play_cell dvd-dev vts pgc cell\n", stderr);
    exit (1);
  }

  vts  = strtol (argv [2], NULL, 10);
  pgc  = strtol (argv [3], NULL, 10);
  cell = strtol (argv [4], NULL, 10);

  play_cell (argv [1], vts, pgc, cell);

  return 0;
}


static inline int
is_nav_pack (UInt8 *ptr)
{
  UInt32 start_code;

  start_code  = (UInt32) (ptr [0]) << 24;
  start_code |= (UInt32) (ptr [1]) << 16;
  start_code |= (UInt32) (ptr [2]) <<  8;
  start_code |= (UInt32) (ptr [3]);

  if (start_code != 0x000001ba)
    return 0;

  if ((ptr [4] & 0xc0) != 0x40)
    return 0;

  ptr += 14;

  start_code  = (UInt32) (ptr [0]) << 24;
  start_code |= (UInt32) (ptr [1]) << 16;
  start_code |= (UInt32) (ptr [2]) <<  8;
  start_code |= (UInt32) (ptr [3]);

  if (start_code != 0x000001bb)
    return 0;

  ptr += 24;

  start_code  = (UInt32) (ptr [0]) << 24;
  start_code |= (UInt32) (ptr [1]) << 16;
  start_code |= (UInt32) (ptr [2]) <<  8;
  start_code |= (UInt32) (ptr [3]);

  if (start_code != 0x000001bf)
    return 0;

  ptr += 986;

  start_code  = (UInt32) (ptr [0]) << 24;
  start_code |= (UInt32) (ptr [1]) << 16;
  start_code |= (UInt32) (ptr [2]) <<  8;
  start_code |= (UInt32) (ptr [3]);

  if (start_code != 0x000001bf)
    return 0;

  return 1;
}


void
play_cell (const char *dev, int vts_num, int pgc_num, int cell)
{
  pgc_t *   pgc;
  dvd_reader_t *dvd_handle;
  ifo_handle_t *vts_handle;
  dvd_file_t *    file_handle;
  UInt32    sector, dsi_next_vobu = 0;

  /* open disc */
  dvd_handle = DVDOpen (dev);

  if (!dvd_handle)
    fatal ("can't open DVD: %s", dev);

  /* load information for the given VTS */
  vts_handle = ifoOpen (dvd_handle, vts_num);

  if (!vts_handle)
    fatal ("can't open info file for VTS %d", vts_num);

  /* open VTS data */
  file_handle = DVDOpenFile (dvd_handle, vts_num, DVD_READ_TITLE_VOBS);

  if (!file_handle)
    fatal ("can't open VOB for VTS %d", vts_num);

  /* check program chain number */
  if (pgc_num < 1 || pgc_num > vts_handle -> vts_pgcit -> nr_of_pgci_srp)
    fatal ("bad program chain: %d, VTS only has %d chains",
         pgc_num, vts_handle -> vts_pgcit -> nr_of_pgci_srp);

  pgc = vts_handle -> vts_pgcit -> pgci_srp [pgc_num - 1].pgc;

  /* check cell number */
  if (cell < 1 || cell > pgc -> nr_of_cells)
    fatal ("bad cell: %d, PGC only has %d cells", cell, pgc -> nr_of_cells);

  /* loop until out of the cell */
  for (sector = pgc -> cell_playback [cell - 1].first_sector;
       dsi_next_vobu != SRI_END_OF_CELL; sector += dsi_next_vobu & 0x7fffffff)
  {
    dsi_t   dsi_pack;
    UInt32  nsectors, len;

    /* read nav pack */
    len = DVDReadBlocks (file_handle, (int) sector, 1, buf);

    if (len != 1)
      fatal ("read failed for sector %u", sector);

    if (!is_nav_pack (buf))
      fatal ("not a navigation pack");

    /* generate an MPEG2 program stream (including nav packs) */
    if (fwrite (buf, DVD_VIDEO_LB_LEN, 1, stdout) != 1)
      fatal ("write failed: %s", strerror (errno));

    /* parse contained DSI pack */
    navRead_DSI (&dsi_pack, buf + DSI_START_BYTE);

    if (sector != dsi_pack.dsi_gi.nv_pck_lbn)
      fatal ("bad DSI pack");

    nsectors      = dsi_pack.dsi_gi.vobu_ea;
    dsi_next_vobu = dsi_pack.vobu_sri.next_vobu;

    if (nsectors >= BUF_SECS)
      fatal ("VOBU too big");

    /* read VOBU */
    len = DVDReadBlocks (file_handle, (int) (sector + 1), nsectors, buf);

    if (len != nsectors)
      fatal ("read failed for %u sectors at %u", nsectors, sector + 1);

    /* write VOBU */
    if (fwrite (buf, DVD_VIDEO_LB_LEN, nsectors, stdout) != nsectors)
      fatal ("write failed: %s", strerror (errno));
  }
}


/* this is a *very* sophisticated kind of error handling :-) */
void
fatal (char *fmt, ...)
{
  va_list ap;

  fprintf (stderr, "%s: Fatal: ", progname);
  va_start (ap, fmt);
  vfprintf (stderr, fmt, ap);
  va_end (ap);
  putc ('\n', stderr);
  exit (1);
}

Generated by  Doxygen 1.6.0   Back to index