initial commit

This commit is contained in:
Daniel S. 2021-10-23 03:13:25 +02:00
parent 7c99758cad
commit be4930a8a3
16 changed files with 3329 additions and 0 deletions

344
dvd_reader.h Normal file
View File

@ -0,0 +1,344 @@
/*
* Copyright (C) 2001, 2002 Billy Biggs <vektor@dumbterm.net>,
* Håkan Hjort <d95hjort@dtek.chalmers.se>,
* Björn Englund <d4bjorn@dtek.chalmers.se>
*
* This file is part of libdvdread.
*
* libdvdread 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.
*
* libdvdread 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 libdvdread; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/**
* The DVD access interface.
*
* This file contains the functions that form the interface to to
* reading files located on a DVD.
*/
/**
* The current version.
*/
/**
* The length of one Logical Block of a DVD.
*/
#define DVD_VIDEO_LB_LEN 2048
/**
* Maximum length of filenames allowed in UDF.
*/
#define MAX_UDF_FILE_NAME_LEN 2048
typedef long int off_t;
/**
* Opaque type that is used as a handle for one instance of an opened DVD.
*/
typedef struct dvd_reader_s dvd_reader_t;
typedef struct dvd_reader_device_s dvd_reader_device_t;
/**
* Opaque type for a file read handle, much like a normal fd or FILE *.
*/
typedef struct dvd_file_s dvd_file_t;
struct dvd_reader_stream_cb
{
int ( *pf_seek ) ( void *p_stream, uint64_t i_pos);
int ( *pf_read ) ( void *p_stream, void* buffer, int i_read);
int ( *pf_readv ) ( void *p_stream, void *p_iovec, int i_blocks);
};
typedef struct dvd_reader_stream_cb dvd_reader_stream_cb;
/**
* Custom logger callback for DVDOpen[Stream]2
* @param private Handle as provided in Open functions
* @param level Log level
* @param fmt Format string
* @param args Arguments list
* pf_log(priv, level, fmt, args);
*/
typedef enum
{
DVD_LOGGER_LEVEL_INFO,
DVD_LOGGER_LEVEL_ERROR,
DVD_LOGGER_LEVEL_WARN,
DVD_LOGGER_LEVEL_DEBUG,
} dvd_logger_level_t;
typedef struct
{
// void ( *pf_log ) ( void *, dvd_logger_level_t, const char *, va_list );
void *pf_log;
} dvd_logger_cb;
/**
* Public type that is used to provide statistics on a handle.
*/
typedef struct {
off_t size; /**< Total size of file in bytes */
int nr_parts; /**< Number of file parts */
off_t parts_size[9]; /**< Size of each part in bytes */
} dvd_stat_t;
/**
* Opens a block device of a DVD-ROM file, or an image file, or a directory
* name for a mounted DVD or HD copy of a DVD.
* The second form of Open function (DVDOpenStream) can be used to
* provide custom stream_cb functions to access the DVD (see libdvdcss).
*
* If the given file is a block device, or is the mountpoint for a block
* device, then that device is used for CSS authentication using libdvdcss.
* If no device is available, then no CSS authentication is performed,
* and we hope that the image is decrypted.
*
* If the path given is a directory, then the files in that directory may be
* in any one of these formats:
*
* path/VIDEO_TS/VTS_01_1.VOB
* path/video_ts/vts_01_1.vob
* path/VTS_01_1.VOB
* path/vts_01_1.vob
*
* @param path Specifies the the device, file or directory to be used.
* @param stream is a private handle used by stream_cb
* @param stream_cb is a struct containing seek and read functions
* @return If successful a a read handle is returned. Otherwise 0 is returned.
*
* dvd = DVDOpen(path);
* dvd = DVDOpenStream(stream, &stream_cb);
*/
dvd_reader_t *DVDOpen( const char * );
dvd_reader_t *DVDOpenStream( void *, dvd_reader_stream_cb * );
/**
* Same as DVDOpen, but with private handle to be passed back on callbacks
*
* @param path Specifies the the device, file or directory to be used.
* @param priv is a private handle
* @param logcb is a custom logger callback struct, or NULL if none needed
* @param stream_cb is a struct containing seek and read functions
* @return If successful a a read handle is returned. Otherwise 0 is returned.
*
* dvd = DVDOpen2(priv, logcb, path);
* dvd = DVDOpenStream2(priv, logcb, &stream_cb);
*/
dvd_reader_t *DVDOpen2( void *, const dvd_logger_cb *, const char * );
dvd_reader_t *DVDOpenStream2( void *, const dvd_logger_cb *, dvd_reader_stream_cb * );
/**
* Closes and cleans up the DVD reader object.
*
* You must close all open files before calling this function.
*
* @param dvd A read handle that should be closed.
*
* DVDClose(dvd);
*/
void DVDClose( dvd_reader_t * );
/**
*
*/
typedef enum {
DVD_READ_INFO_FILE, /**< VIDEO_TS.IFO or VTS_XX_0.IFO (title) */
DVD_READ_INFO_BACKUP_FILE, /**< VIDEO_TS.BUP or VTS_XX_0.BUP (title) */
DVD_READ_MENU_VOBS, /**< VIDEO_TS.VOB or VTS_XX_0.VOB (title) */
DVD_READ_TITLE_VOBS /**< VTS_XX_[1-9].VOB (title). All files in
the title set are opened and read as a
single file. */
} dvd_read_domain_t;
/**
* Stats a file on the DVD given the title number and domain.
* The information about the file is stored in a dvd_stat_t
* which contains information about the size of the file and
* the number of parts in case of a multipart file and the respective
* sizes of the parts.
* A multipart file is for instance VTS_02_1.VOB, VTS_02_2.VOB, VTS_02_3.VOB
* The size of VTS_02_1.VOB will be stored in stat->parts_size[0],
* VTS_02_2.VOB in stat->parts_size[1], ...
* The total size (sum of all parts) is stored in stat->size and
* stat->nr_parts will hold the number of parts.
* Only DVD_READ_TITLE_VOBS (VTS_??_[1-9].VOB) can be multipart files.
*
* This function is only of use if you want to get the size of each file
* in the filesystem. These sizes are not needed to use any other
* functions in libdvdread.
*
* @param dvd A dvd read handle.
* @param titlenum Which Video Title Set should be used, VIDEO_TS is 0.
* @param domain Which domain.
* @param stat Pointer to where the result is stored.
* @return If successful 0, otherwise -1.
*
* int DVDFileStat(dvd, titlenum, domain, stat);
*/
int DVDFileStat(dvd_reader_t *, int, dvd_read_domain_t, dvd_stat_t *);
/**
* Opens a file on the DVD given the title number and domain.
*
* If the title number is 0, the video manager information is opened
* (VIDEO_TS.[IFO,BUP,VOB]). Returns a file structure which may be
* used for reads, or 0 if the file was not found.
*
* @param dvd A dvd read handle.
* @param titlenum Which Video Title Set should be used, VIDEO_TS is 0.
* @param domain Which domain.
* @return If successful a a file read handle is returned, otherwise 0.
*
* dvd_file = DVDOpenFile(dvd, titlenum, domain); */
dvd_file_t *DVDOpenFile( dvd_reader_t *, int, dvd_read_domain_t );
/**
* Closes a file and frees the associated structure.
*
* @param dvd_file The file read handle to be closed.
*
* DVDCloseFile(dvd_file);
*/
void DVDCloseFile( dvd_file_t * );
/**
* Reads block_count number of blocks from the file at the given block offset.
* Returns number of blocks read on success, -1 on error. This call is only
* for reading VOB data, and should not be used when reading the IFO files.
* When reading from an encrypted drive, blocks are decrypted using libdvdcss
* where required.
*
* @param dvd_file A file read handle.
* @param offset Block offset from the start of the file to start reading at.
* @param block_count Number of block to read.
* @param data Pointer to a buffer to write the data into.
* @return Returns number of blocks read on success, -1 on error.
*
* blocks_read = DVDReadBlocks(dvd_file, offset, block_count, data);
*/
ssize_t DVDReadBlocks( dvd_file_t *, int, size_t, unsigned char * );
/**
* Seek to the given position in the file. Returns the resulting position in
* bytes from the beginning of the file. The seek position is only used for
* byte reads from the file, the block read call always reads from the given
* offset.
*
* @param dvd_file A file read handle.
* @param seek_offset Byte offset from the start of the file to seek to.
* @return The resulting position in bytes from the beginning of the file.
*
* offset_set = DVDFileSeek(dvd_file, seek_offset);
*/
int32_t DVDFileSeek( dvd_file_t *, int32_t );
/**
* Reads the given number of bytes from the file. This call can only be used
* on the information files, and may not be used for reading from a VOB. This
* reads from and increments the currrent seek position for the file.
*
* @param dvd_file A file read handle.
* @param data Pointer to a buffer to write the data into.
* @param bytes Number of bytes to read.
* @return Returns number of bytes read on success, -1 on error.
*
* bytes_read = DVDReadBytes(dvd_file, data, bytes);
*/
ssize_t DVDReadBytes( dvd_file_t *, void *, size_t );
/**
* Returns the file size in blocks.
*
* @param dvd_file A file read handle.
* @return The size of the file in blocks, -1 on error.
*
* blocks = DVDFileSize(dvd_file);
*/
ssize_t DVDFileSize( dvd_file_t * );
/**
* Get a unique 128 bit disc ID.
* This is the MD5 sum of VIDEO_TS.IFO and the VTS_0?_0.IFO files
* in title order (those that exist).
* If you need a 'text' representation of the id, print it as a
* hexadecimal number, using lowercase letters, discid[0] first.
* I.e. the same format as the command-line 'md5sum' program uses.
*
* @param dvd A read handle to get the disc ID from
* @param discid The buffer to put the disc ID into. The buffer must
* have room for 128 bits (16 chars).
* @return 0 on success, -1 on error.
*/
int DVDDiscID( dvd_reader_t *, unsigned char * );
/**
* Get the UDF VolumeIdentifier and VolumeSetIdentifier
* from the PrimaryVolumeDescriptor.
*
* @param dvd A read handle to get the disc ID from
* @param volid The buffer to put the VolumeIdentifier into.
* The VolumeIdentifier is latin-1 encoded (8bit unicode)
* null terminated and max 32 bytes (including '\0')
* @param volid_size No more than volid_size bytes will be copied to volid.
* If the VolumeIdentifier is truncated because of this
* it will still be null terminated.
* @param volsetid The buffer to put the VolumeSetIdentifier into.
* The VolumeIdentifier is 128 bytes as
* stored in the UDF PrimaryVolumeDescriptor.
* Note that this is not a null terminated string.
* @param volsetid_size At most volsetid_size bytes will be copied to volsetid.
* @return 0 on success, -1 on error.
*/
int DVDUDFVolumeInfo( dvd_reader_t *, char *, unsigned int,
unsigned char *, unsigned int );
int DVDFileSeekForce( dvd_file_t *, int offset, int force_size);
/**
* Get the ISO9660 VolumeIdentifier and VolumeSetIdentifier
*
* * Only use this function as fallback if DVDUDFVolumeInfo returns 0 *
* * this will happen on a disc mastered only with a iso9660 filesystem *
* * All video DVD discs have UDF filesystem *
*
* @param dvd A read handle to get the disc ID from
* @param volid The buffer to put the VolumeIdentifier into.
* The VolumeIdentifier is coded with '0-9','A-Z','_'
* null terminated and max 33 bytes (including '\0')
* @param volid_size No more than volid_size bytes will be copied to volid.
* If the VolumeIdentifier is truncated because of this
* it will still be null terminated.
* @param volsetid The buffer to put the VolumeSetIdentifier into.
* The VolumeIdentifier is 128 bytes as
* stored in the ISO9660 PrimaryVolumeDescriptor.
* Note that this is not a null terminated string.
* @param volsetid_size At most volsetid_size bytes will be copied to volsetid.
* @return 0 on success, -1 on error.
*/
int DVDISOVolumeInfo( dvd_reader_t *, char *, unsigned int,
unsigned char *, unsigned int );
/**
* Sets the level of caching that is done when reading from a device
*
* @param dvd A read handle to get the disc ID from
* @param level The level of caching wanted.
* -1 - returns the current setting.
* 0 - UDF Cache turned off.
* 1 - (default level) Pointers to IFO files and some data from
* PrimaryVolumeDescriptor are cached.
*
* @return The level of caching.
*/
int DVDUDFCacheLevel( dvd_reader_t *, int );

38
dvd_ripper.py Normal file
View File

@ -0,0 +1,38 @@
import cffi
import os
import sys
import time
from dvdnav import DVDNav
from dvdread import DVDRead
import subprocess as SP
import json
from vob_demux import demux
from ff_d2v import make_d2v
def loadlib(dll_path,*includes,**kwargs):
ffi = cffi.FFI()
for include in includes:
ffi.cdef(open(include).read(),kwargs)
return ffi,ffi.dlopen(dll_path)
os.environ["DVDCSS_VERBOSE"]="2"
os.environ["DVDCSS_METHOD"]="disc"
r=DVDRead(sys.argv[1])
out_folder=os.path.join("out","_".join([r.disc_id,r.udf_disc_name or r.iso_disc_name]).replace(" ","_"))
del r
os.makedirs(out_folder,exist_ok=True)
d=DVDNav(sys.argv[1])
for k,v in d.titles.items():
v['duration']=v['duration'].total_seconds()
v['chapters']=[c.total_seconds() for c in v['chapters']]
d.titles[k]=v
with open(os.path.join(out_folder,f"{k}.json"),"w") as fh:
json.dump(v,fh)
for a in range(v['angles']):
a+=1
outfile=os.path.join(out_folder,f"{k}_{a}.vob")
with open(outfile,"wb") as fh:
for block in d.get_blocks(k,a):
fh.write(block)
demux(outfile)
os.unlink(outfile)

266
dvd_types.h Normal file
View File

@ -0,0 +1,266 @@
/*
* Copyright (C) 2000, 2001 Björn Englund, Håkan Hjort
*
* This file is part of libdvdnav, a DVD navigation library. It is a modified
* file originally part of the Ogle DVD player project.
*
* libdvdnav 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.
*
* libdvdnav 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 libdvdnav; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* Various useful structs and enums for DVDs.
*/
/*
* DVD Menu ID
* (see dvdnav_menu_call())
*/
typedef enum {
/* When used in VTS domain, DVD_MENU_Escape behaves like DVD_MENU_Root,
* but from within a menu domain, DVD_MENU_Escape resumes playback. */
DVD_MENU_Escape = 0,
DVD_MENU_Title = 2,
DVD_MENU_Root = 3,
DVD_MENU_Subpicture = 4,
DVD_MENU_Audio = 5,
DVD_MENU_Angle = 6,
DVD_MENU_Part = 7
} DVDMenuID_t;
/* Domain */
typedef enum {
DVD_DOMAIN_FirstPlay = 1, /* First Play Domain */
DVD_DOMAIN_VTSTitle = 2, /* Video Title Set Domain */
DVD_DOMAIN_VMGM = 4, /* Video Manager Domain */
DVD_DOMAIN_VTSMenu = 8 /* Video Title Set Menu Domain */
} DVDDomain_t;
/*
* Structure containing info on highlight areas
* (see dvdnav_get_highlight_area())
*/
typedef struct {
uint32_t palette; /* The CLUT entries for the highlight palette
(4-bits per entry -> 4 entries) */
uint16_t sx,sy,ex,ey; /* The start/end x,y positions */
uint32_t pts; /* Highlight PTS to match with SPU */
/* button number for the SPU decoder/overlaying engine */
uint32_t buttonN;
} dvdnav_highlight_area_t;
/* The audio format */
typedef enum {
DVD_AUDIO_FORMAT_AC3 = 0,
DVD_AUDIO_FORMAT_UNKNOWN_1 = 1,
DVD_AUDIO_FORMAT_MPEG = 2,
DVD_AUDIO_FORMAT_MPEG2_EXT = 3,
DVD_AUDIO_FORMAT_LPCM = 4,
DVD_AUDIO_FORMAT_UNKNOWN_5 = 5,
DVD_AUDIO_FORMAT_DTS = 6,
DVD_AUDIO_FORMAT_SDDS = 7
} DVDAudioFormat_t;
/* the following types are currently unused */
// #if 0
// /* User operation permissions */
// typedef enum {
// UOP_FLAG_TitleOrTimePlay = 0x00000001,
// UOP_FLAG_ChapterSearchOrPlay = 0x00000002,
// UOP_FLAG_TitlePlay = 0x00000004,
// UOP_FLAG_Stop = 0x00000008,
// UOP_FLAG_GoUp = 0x00000010,
// UOP_FLAG_TimeOrChapterSearch = 0x00000020,
// UOP_FLAG_PrevOrTopPGSearch = 0x00000040,
// UOP_FLAG_NextPGSearch = 0x00000080,
// UOP_FLAG_ForwardScan = 0x00000100,
// UOP_FLAG_BackwardScan = 0x00000200,
// UOP_FLAG_TitleMenuCall = 0x00000400,
// UOP_FLAG_RootMenuCall = 0x00000800,
// UOP_FLAG_SubPicMenuCall = 0x00001000,
// UOP_FLAG_AudioMenuCall = 0x00002000,
// UOP_FLAG_AngleMenuCall = 0x00004000,
// UOP_FLAG_ChapterMenuCall = 0x00008000,
// UOP_FLAG_Resume = 0x00010000,
// UOP_FLAG_ButtonSelectOrActivate = 0x00020000,
// UOP_FLAG_StillOff = 0x00040000,
// UOP_FLAG_PauseOn = 0x00080000,
// UOP_FLAG_AudioStreamChange = 0x00100000,
// UOP_FLAG_SubPicStreamChange = 0x00200000,
// UOP_FLAG_AngleChange = 0x00400000,
// UOP_FLAG_KaraokeAudioPresModeChange = 0x00800000,
// UOP_FLAG_VideoPresModeChange = 0x01000000
// } DVDUOP_t;
// /* Parental Level */
// typedef enum {
// DVD_PARENTAL_LEVEL_1 = 1,
// DVD_PARENTAL_LEVEL_2 = 2,
// DVD_PARENTAL_LEVEL_3 = 3,
// DVD_PARENTAL_LEVEL_4 = 4,
// DVD_PARENTAL_LEVEL_5 = 5,
// DVD_PARENTAL_LEVEL_6 = 6,
// DVD_PARENTAL_LEVEL_7 = 7,
// DVD_PARENTAL_LEVEL_8 = 8,
// DVD_PARENTAL_LEVEL_None = 15
// } DVDParentalLevel_t;
// /* Language ID (ISO-639 language code) */
// typedef uint16_t DVDLangID_t;
// /* Country ID (ISO-3166 country code) */
// typedef uint16_t DVDCountryID_t;
// /* Register */
// typedef uint16_t DVDRegister_t;
// typedef enum {
// DVDFalse = 0,
// DVDTrue = 1
// } DVDBool_t;
// typedef DVDRegister_t DVDGPRMArray_t[16];
// typedef DVDRegister_t DVDSPRMArray_t[24];
// /* Navigation */
// typedef int DVDStream_t;
// typedef int DVDPTT_t;
// typedef int DVDTitle_t;
// /* Angle number (1-9 or default?) */
// typedef int DVDAngle_t;
// /* Timecode */
// typedef struct {
// uint8_t Hours;
// uint8_t Minutes;
// uint8_t Seconds;
// uint8_t Frames;
// } DVDTimecode_t;
// /* Subpicture stream number (0-31,62,63) */
// typedef int DVDSubpictureStream_t;
// /* Audio stream number (0-7, 15(none)) */
// typedef int DVDAudioStream_t;
// /* The audio application mode */
// typedef enum {
// DVD_AUDIO_APP_MODE_None = 0,
// DVD_AUDIO_APP_MODE_Karaoke = 1,
// DVD_AUDIO_APP_MODE_Surround = 2,
// DVD_AUDIO_APP_MODE_Other = 3
// } DVDAudioAppMode_t;
// /* Audio language extension */
// typedef enum {
// DVD_AUDIO_LANG_EXT_NotSpecified = 0,
// DVD_AUDIO_LANG_EXT_NormalCaptions = 1,
// DVD_AUDIO_LANG_EXT_VisuallyImpaired = 2,
// DVD_AUDIO_LANG_EXT_DirectorsComments1 = 3,
// DVD_AUDIO_LANG_EXT_DirectorsComments2 = 4
// } DVDAudioLangExt_t;
// /* Subpicture language extension */
// typedef enum {
// DVD_SUBPICTURE_LANG_EXT_NotSpecified = 0,
// DVD_SUBPICTURE_LANG_EXT_NormalCaptions = 1,
// DVD_SUBPICTURE_LANG_EXT_BigCaptions = 2,
// DVD_SUBPICTURE_LANG_EXT_ChildrensCaptions = 3,
// DVD_SUBPICTURE_LANG_EXT_NormalCC = 5,
// DVD_SUBPICTURE_LANG_EXT_BigCC = 6,
// DVD_SUBPICTURE_LANG_EXT_ChildrensCC = 7,
// DVD_SUBPICTURE_LANG_EXT_Forced = 9,
// DVD_SUBPICTURE_LANG_EXT_NormalDirectorsComments = 13,
// DVD_SUBPICTURE_LANG_EXT_BigDirectorsComments = 14,
// DVD_SUBPICTURE_LANG_EXT_ChildrensDirectorsComments = 15,
// } DVDSubpictureLangExt_t;
// /* Karaoke Downmix mode */
// typedef enum {
// DVD_KARAOKE_DOWNMIX_0to0 = 0x0001,
// DVD_KARAOKE_DOWNMIX_1to0 = 0x0002,
// DVD_KARAOKE_DOWNMIX_2to0 = 0x0004,
// DVD_KARAOKE_DOWNMIX_3to0 = 0x0008,
// DVD_KARAOKE_DOWNMIX_4to0 = 0x0010,
// DVD_KARAOKE_DOWNMIX_Lto0 = 0x0020,
// DVD_KARAOKE_DOWNMIX_Rto0 = 0x0040,
// DVD_KARAOKE_DOWNMIX_0to1 = 0x0100,
// DVD_KARAOKE_DOWNMIX_1to1 = 0x0200,
// DVD_KARAOKE_DOWNMIX_2to1 = 0x0400,
// DVD_KARAOKE_DOWNMIX_3to1 = 0x0800,
// DVD_KARAOKE_DOWNMIX_4to1 = 0x1000,
// DVD_KARAOKE_DOWNMIX_Lto1 = 0x2000,
// DVD_KARAOKE_DOWNMIX_Rto1 = 0x4000
// } DVDKaraokeDownmix_t;
// typedef int DVDKaraokeDownmixMask_t;
// /* Display mode */
// typedef enum {
// DVD_DISPLAY_MODE_ContentDefault = 0,
// DVD_DISPLAY_MODE_16x9 = 1,
// DVD_DISPLAY_MODE_4x3PanScan = 2,
// DVD_DISPLAY_MODE_4x3Letterboxed = 3
// } DVDDisplayMode_t;
// /* Audio attributes */
// typedef struct {
// DVDAudioAppMode_t AppMode;
// DVDAudioFormat_t AudioFormat;
// DVDLangID_t Language;
// DVDAudioLangExt_t LanguageExtension;
// DVDBool_t HasMultichannelInfo;
// DVDAudioSampleFreq_t SampleFrequency;
// DVDAudioSampleQuant_t SampleQuantization;
// DVDChannelNumber_t NumberOfChannels;
// } DVDAudioAttributes_t;
// typedef int DVDAudioSampleFreq_t;
// typedef int DVDAudioSampleQuant_t;
// typedef int DVDChannelNumber_t;
// /* Subpicture attributes */
// typedef enum {
// DVD_SUBPICTURE_TYPE_NotSpecified = 0,
// DVD_SUBPICTURE_TYPE_Language = 1,
// DVD_SUBPICTURE_TYPE_Other = 2
// } DVDSubpictureType_t;
// typedef enum {
// DVD_SUBPICTURE_CODING_RunLength = 0,
// DVD_SUBPICTURE_CODING_Extended = 1,
// DVD_SUBPICTURE_CODING_Other = 2
// } DVDSubpictureCoding_t;
// typedef struct {
// DVDSubpictureType_t Type;
// DVDSubpictureCoding_t CodingMode;
// DVDLangID_t Language;
// DVDSubpictureLangExt_t LanguageExtension;
// } DVDSubpictureAttributes_t;
// /* Video attributes */
// typedef struct {
// DVDBool_t PanscanPermitted;
// DVDBool_t LetterboxPermitted;
// int AspectX;
// int AspectY;
// int FrameRate;
// int FrameHeight;
// DVDVideoCompression_t Compression;
// DVDBool_t Line21Field1InGop;
// DVDBool_t Line21Field2InGop;
// int more_to_come;
// } DVDVideoAttributes_t;
// typedef int DVDVideoCompression_t;
// #endif

10
dvdcss.h Normal file
View File

@ -0,0 +1,10 @@
typedef struct dvdcss_s * dvdcss_t;
typedef struct dvdcss_stream_cb dvdcss_stream_cb;
dvdcss_t dvdcss_open (const char *psz_target);
dvdcss_t dvdcss_open_stream (void *p_stream, dvdcss_stream_cb *p_stream_cb);
int dvdcss_close (dvdcss_t);
int dvdcss_seek (dvdcss_t, int i_blocks, int i_flags);
int dvdcss_read (dvdcss_t, void *p_buffer, int i_blocks, int i_flags);
int dvdcss_readv(dvdcss_t, void *p_iovec, int i_blocks, int i_flags);
const char* dvdcss_error (const dvdcss_t);
int dvdcss_is_scrambled (dvdcss_t);

718
dvdnav.h Normal file
View File

@ -0,0 +1,718 @@
/*
* Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net>
*
* This file is part of libdvdnav, a DVD navigation library.
*
* libdvdnav 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.
*
* libdvdnav 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 libdvdnav; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* This is the main header file applications should include if they want
* to access dvdnav functionality.
*/
// #include <dvdnav/dvd_types.h>
// #include <dvdread/dvd_reader.h>
// #include <dvdread/nav_types.h>
// #include <dvdread/ifo_types.h> /* For vm_cmd_t */
// #include <dvdnav/dvdnav_events.h>
// #include <stdarg.h>
/*********************************************************************
* dvdnav data types *
*********************************************************************/
/*
* Opaque data-type can be viewed as a 'DVD handle'. You should get
* a pointer to a dvdnav_t from the dvdnav_open() function.
* Never call free() on the pointer, you have to give it back with
* dvdnav_close().
*/
typedef struct dvdnav_s dvdnav_t;
/* Status as reported by most of libdvdnav's functions */
typedef int32_t dvdnav_status_t;
typedef dvd_reader_stream_cb dvdnav_stream_cb;
/*
* Unless otherwise stated, all functions return DVDNAV_STATUS_OK if
* they succeeded, otherwise DVDNAV_STATUS_ERR is returned and the error may
* be obtained by calling dvdnav_err_to_string().
*/
#define DVDNAV_STATUS_ERR 0
#define DVDNAV_STATUS_OK 1
/*********************************************************************
* initialisation & housekeeping functions *
*********************************************************************/
/*
* Logger callback definition
*/
typedef enum
{
DVDNAV_LOGGER_LEVEL_INFO,
DVDNAV_LOGGER_LEVEL_ERROR,
DVDNAV_LOGGER_LEVEL_WARN,
DVDNAV_LOGGER_LEVEL_DEBUG,
} dvdnav_logger_level_t;
typedef struct
{
void *pf_log;
} dvdnav_logger_cb;
/*
* These functions allow you to open a DVD device and associate it
* with a dvdnav_t.
*/
/*
* Attempts to open the DVD drive at the specified path or using external
* seek/read functions (dvdnav_open_stream) and pre-cache the CSS-keys.
* libdvdread is used to access the DVD, so any source supported by libdvdread
* can be given with "path" or "stream_cb". Currently, using dvdnav_open,
* libdvdread can access : DVD drives, DVD image files, DVD file-by-file
* copies. Using dvdnav_open_stream, libdvdread can access any kind of DVD
* storage via custom implementation of seek/read functions.
*
* The resulting dvdnav_t handle will be written to *dest.
*/
dvdnav_status_t dvdnav_open(dvdnav_t **dest, const char *path);
dvdnav_status_t
dvdnav_open_stream(dvdnav_t **dest, void *priv, dvdnav_stream_cb *stream_cb);
dvdnav_status_t dvdnav_open2(dvdnav_t **dest,
void *, const dvdnav_logger_cb *,
const char *path);
dvdnav_status_t dvdnav_open_stream2(dvdnav_t **dest,
void *priv, const dvdnav_logger_cb *,
dvdnav_stream_cb *stream_cb);
dvdnav_status_t dvdnav_dup(dvdnav_t **dest, dvdnav_t *src);
dvdnav_status_t dvdnav_free_dup(dvdnav_t * _this);
/*
* Closes a dvdnav_t previously opened with dvdnav_open(), freeing any
* memory associated with it.
*/
dvdnav_status_t dvdnav_close(dvdnav_t *self);
/*
* Resets the DVD virtual machine and cache buffers.
*/
dvdnav_status_t dvdnav_reset(dvdnav_t *self);
/*
* Fills a pointer with a value pointing to a string describing
* the path associated with an open dvdnav_t. It assigns *path to NULL
* on error.
*/
dvdnav_status_t dvdnav_path(dvdnav_t *self, const char **path);
/*
* Returns a human-readable string describing the last error.
*/
const char* dvdnav_err_to_string(dvdnav_t *self);
const char* dvdnav_version(void);
/*********************************************************************
* changing and reading DVD player characteristics *
*********************************************************************/
/*
* These functions allow you to manipulate the various global characteristics
* of the DVD playback engine.
*/
/*
* Sets the region mask (bit 0 set implies region 1, bit 1 set implies
* region 2, etc) of the virtual machine. Generally you will only need to set
* this if you are playing RCE discs which query the virtual machine as to its
* region setting.
*
* This has _nothing_ to do with the region setting of the DVD drive.
*/
dvdnav_status_t dvdnav_set_region_mask(dvdnav_t *self, int32_t region_mask);
/*
* Returns the region mask (bit 0 set implies region 1, bit 1 set implies
* region 2, etc) of the virtual machine.
*
* This has _nothing_ to do with the region setting of the DVD drive.
*/
dvdnav_status_t dvdnav_get_region_mask(dvdnav_t *self, int32_t *region_mask);
/*
* Specify whether read-ahead caching should be used. You may not want this if your
* decoding engine does its own buffering.
*
* The default read-ahead cache does not use an additional thread for the reading
* (see read_cache.c for a threaded cache, but note that this code is currently
* unmaintained). It prebuffers on VOBU level by reading ahead several buffers
* on every read request. The speed of this prebuffering has been optimized to
* also work on slow DVD drives.
*
* If in addition you want to prevent memcpy's to improve performance, have a look
* at dvdnav_get_next_cache_block().
*/
dvdnav_status_t dvdnav_set_readahead_flag(dvdnav_t *self, int32_t read_ahead_flag);
/*
* Query whether read-ahead caching/buffering will be used.
*/
dvdnav_status_t dvdnav_get_readahead_flag(dvdnav_t *self, int32_t *read_ahead_flag);
/*
* Specify whether the positioning works PGC or PG based.
* Programs (PGs) on DVDs are similar to Chapters and a program chain (PGC)
* usually covers a whole feature. This affects the behaviour of the
* functions dvdnav_get_position() and dvdnav_sector_search(). See there.
* Default is PG based positioning.
*/
dvdnav_status_t dvdnav_set_PGC_positioning_flag(dvdnav_t *self, int32_t pgc_based_flag);
/*
* Query whether positioning is PG or PGC based.
*/
dvdnav_status_t dvdnav_get_PGC_positioning_flag(dvdnav_t *self, int32_t *pgc_based_flag);
/*********************************************************************
* reading data *
*********************************************************************/
/*
* These functions are used to poll the playback engine and actually get data
* off the DVD.
*/
/*
* Attempts to get the next block off the DVD and copies it into the buffer 'buf'.
* If there is any special actions that may need to be performed, the value
* pointed to by 'event' gets set accordingly.
*
* If 'event' is DVDNAV_BLOCK_OK then 'buf' is filled with the next block
* (note that means it has to be at /least/ 2048 bytes big). 'len' is
* then set to 2048.
*
* Otherwise, buf is filled with an appropriate event structure and
* len is set to the length of that structure.
*
* See the dvdnav_events.h header for information on the various events.
*/
dvdnav_status_t dvdnav_get_next_block(dvdnav_t *self, uint8_t *buf,
int32_t *event, int32_t *len);
/*
* This basically does the same as dvdnav_get_next_block. The only difference is
* that it avoids a memcopy, when the requested block was found in the cache.
* In such a case (cache hit) this function will return a different pointer than
* the one handed in, pointing directly into the relevant block in the cache.
* Those pointers must _never_ be freed but instead returned to the library via
* dvdnav_free_cache_block().
*/
dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *self, uint8_t **buf,
int32_t *event, int32_t *len);
/*
* All buffers which came from the internal cache (when dvdnav_get_next_cache_block()
* returned a buffer different from the one handed in) have to be freed with this
* function. Although handing in other buffers not from the cache doesn't cause any harm.
*/
dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf);
/*
* If we are currently in a still-frame this function skips it.
*
* See also the DVDNAV_STILL_FRAME event.
*/
dvdnav_status_t dvdnav_still_skip(dvdnav_t *self);
/*
* If we are currently in WAIT state, that is: the application is required to
* wait for its fifos to become empty, calling this signals libdvdnav that this
* is achieved and that it can continue.
*
* See also the DVDNAV_WAIT event.
*/
dvdnav_status_t dvdnav_wait_skip(dvdnav_t *self);
/*
* Returns the still time from the currently playing cell.
* The still time is given in seconds with 0xff meaning an indefinite still.
*
* This function can be used to detect still frames before they are reached.
* Some players might need this to prepare for a frame to be shown for a
* longer time than usual.
*/
uint32_t dvdnav_get_next_still_flag(dvdnav_t *self);
/*
* Stops playback. The next event obtained with one of the get_next_block
* functions will be a DVDNAV_STOP event.
*
* It is not required to call this before dvdnav_close().
*/
dvdnav_status_t dvdnav_stop(dvdnav_t *self);
/*********************************************************************
* title/part navigation *
*********************************************************************/
/*
* Returns the number of titles on the disk.
*/
dvdnav_status_t dvdnav_get_number_of_titles(dvdnav_t *self, int32_t *titles);
/*
* Returns the number of parts within the given title.
*/
dvdnav_status_t dvdnav_get_number_of_parts(dvdnav_t *self, int32_t title, int32_t *parts);
/*
* Returns the number of angles for the given title.
*/
dvdnav_status_t dvdnav_get_number_of_angles(dvdnav_t *self, int32_t title, int32_t *angles);
/*
* Plays the specified title of the DVD from its beginning (that is: part 1).
*/
dvdnav_status_t dvdnav_title_play(dvdnav_t *self, int32_t title);
/*
* Plays the specified title, starting from the specified part.
*/
dvdnav_status_t dvdnav_part_play(dvdnav_t *self, int32_t title, int32_t part);
/*
* Plays the specified title, starting from the specified program
*/
dvdnav_status_t dvdnav_program_play(dvdnav_t *self, int32_t title, int32_t pgcn, int32_t pgn);
/*
* Stores in *times an array (that the application *must* free) of
* dvdtimes corresponding to the chapter times for the chosen title.
* *duration will have the duration of the title
* The number of entries in *times is the result of the function.
* On error *times is NULL and the output is 0
*/
uint32_t dvdnav_describe_title_chapters(dvdnav_t *self, int32_t title, uint64_t **times, uint64_t *duration);
/*
* Play the specified amount of parts of the specified title of
* the DVD then STOP.
*
* Currently unimplemented!
*/
dvdnav_status_t dvdnav_part_play_auto_stop(dvdnav_t *self, int32_t title,
int32_t part, int32_t parts_to_play);
/*
* Play the specified title starting from the specified time.
*
* Currently unimplemented!
*/
dvdnav_status_t dvdnav_time_play(dvdnav_t *self, int32_t title,
uint64_t time);
/*
* Stop playing the current position and jump to the specified menu.
*
* See also DVDMenuID_t from libdvdread
*/
dvdnav_status_t dvdnav_menu_call(dvdnav_t *self, DVDMenuID_t menu);
/*
* Return the title number and part currently being played.
* A title of 0 indicates we are in a menu. In this case, part
* is set to the current menu's ID.
*/
dvdnav_status_t dvdnav_current_title_info(dvdnav_t *self, int32_t *title,
int32_t *part);
/*
* Return the title number, pgcn and pgn currently being played.
* A title of 0 indicates, we are in a menu.
*/
dvdnav_status_t dvdnav_current_title_program(dvdnav_t *self, int32_t *title,
int32_t *pgcn, int32_t *pgn);
/*
* Return the current position (in blocks) within the current
* title and the length (in blocks) of said title.
*
* Current implementation is wrong and likely to behave unpredictably!
* Use is discouraged!
*/
dvdnav_status_t dvdnav_get_position_in_title(dvdnav_t *self,
uint32_t *pos,
uint32_t *len);
/*
* This function is only available for compatibility reasons.
*
* Stop playing the current position and start playback of the current title
* from the specified part.
*/
dvdnav_status_t dvdnav_part_search(dvdnav_t *self, int32_t part);
/*********************************************************************
* program chain/program navigation *
*********************************************************************/
/*
* Stop playing the current position and start playback from the last
* VOBU boundary before the given sector. The sector number is not
* meant to be an absolute physical DVD sector, but a relative sector
* in the current program. This function cannot leave the current
* program and will fail if asked to do so.
*
* If program chain based positioning is enabled
* (see dvdnav_set_PGC_positioning_flag()), this will seek to the relative
* sector inside the current program chain.
*
* 'origin' can be one of SEEK_SET, SEEK_CUR, SEEK_END as defined in
* fcntl.h.
*/
dvdnav_status_t dvdnav_sector_search(dvdnav_t *self,
int64_t offset, int32_t origin);
/*
returns the current stream time in PTS ticks as reported by the IFO structures
divide it by 90000 to get the current play time in seconds
*/
int64_t dvdnav_get_current_time(dvdnav_t *self);
/*
* Stop playing the current position and start playback of the title
* from the specified timecode.
*
* Currently implemented using interpolation. That interpolation is slightly
* inaccurate.
*/
dvdnav_status_t dvdnav_time_search(dvdnav_t *self,
uint64_t time);
/*
* Stop playing current position and play the "GoUp"-program chain.
* (which generally leads to the title menu or a higher-level menu).
*/
dvdnav_status_t dvdnav_go_up(dvdnav_t *self);
/*
* Stop playing the current position and start playback at the
* previous program (if it exists).
*/
dvdnav_status_t dvdnav_prev_pg_search(dvdnav_t *self);
/*
* Stop playing the current position and start playback at the
* first program.
*/
dvdnav_status_t dvdnav_top_pg_search(dvdnav_t *self);
/*
* Stop playing the current position and start playback at the
* next program (if it exists).
*/
dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *self);
/*
* Return the current position (in blocks) within the current
* program and the length (in blocks) of current program.
*
* If program chain based positioning is enabled
* (see dvdnav_set_PGC_positioning_flag()), this will return the
* relative position in and the length of the current program chain.
*/
dvdnav_status_t dvdnav_get_position(dvdnav_t *self, uint32_t *pos,
uint32_t *len);
/*********************************************************************
* menu highlights *
*********************************************************************/
/*
* Most functions related to highlights take a NAV PCI packet as a parameter.
* While you can get such a packet from libdvdnav, this will result in
* errors for players with internal FIFOs because due to the FIFO length,
* libdvdnav will be ahead in the stream compared to what the user is
* seeing on screen. Therefore, player applications who have a NAV
* packet available, which is better in sync with the actual playback,
* should always pass this one to these functions.
*/
/*
* Get the currently highlighted button
* number (1..36) or 0 if no button is highlighted.
*/
dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *self, int32_t *button);
/*
* Returns the Presentation Control Information (PCI) structure associated
* with the current position.
*
* Read the general notes above.
* See also libdvdreads nav_types.h for definition of pci_t.
*/
pci_t* dvdnav_get_current_nav_pci(dvdnav_t *self);
/*
* Returns the DSI (data search information) structure associated
* with the current position.
*
* Read the general notes above.
* See also libdvdreads nav_types.h for definition of dsi_t.
*/
dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *self);
/*
* Get the area associated with a certain button.
*/
dvdnav_status_t dvdnav_get_highlight_area(pci_t *nav_pci , int32_t button, int32_t mode,
dvdnav_highlight_area_t *highlight);
/*
* Move button highlight around as suggested by function name (e.g. with arrow keys).
*/
dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *self, pci_t *pci);
dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *self, pci_t *pci);
dvdnav_status_t dvdnav_right_button_select(dvdnav_t *self, pci_t *pci);
dvdnav_status_t dvdnav_left_button_select(dvdnav_t *self, pci_t *pci);
/*
* Activate ("press") the currently highlighted button.
*/
dvdnav_status_t dvdnav_button_activate(dvdnav_t *self, pci_t *pci);
/*
* Highlight a specific button.
*/
dvdnav_status_t dvdnav_button_select(dvdnav_t *self, pci_t *pci, int32_t button);
/*
* Activate ("press") specified button.
*/
dvdnav_status_t dvdnav_button_select_and_activate(dvdnav_t *self, pci_t *pci, int32_t button);
/*
* Activate ("press") a button and execute specified command.
*/
dvdnav_status_t dvdnav_button_activate_cmd(dvdnav_t *self, int32_t button, vm_cmd_t *cmd);
/*
* Select button at specified video frame coordinates.
*/
dvdnav_status_t dvdnav_mouse_select(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y);
/*
* Activate ("press") button at specified video frame coordinates.
*/
dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y);
/*********************************************************************
* languages *
*********************************************************************/
/*
* The language codes expected by these functions are two character
* codes as defined in ISO639.
*/
/*
* Set which menu language we should use per default.
*/
dvdnav_status_t dvdnav_menu_language_select(dvdnav_t *self,
char *code);
/*
* Set which audio language we should use per default.
*/
dvdnav_status_t dvdnav_audio_language_select(dvdnav_t *self,
char *code);
/*
* Set which spu language we should use per default.
*/
dvdnav_status_t dvdnav_spu_language_select(dvdnav_t *self,
char *code);
/*********************************************************************
* obtaining stream attributes *
*********************************************************************/
/*
* Return a string describing the title of the DVD.
* This is an ID string encoded on the disc by the author. In many cases
* this is a descriptive string such as `THE_MATRIX' but sometimes is singularly
* uninformative such as `PDVD-011421'. Some DVD authors even forget to set this,
* so you may also read the default of the authoring software they used, like
* `DVDVolume'.
*/
dvdnav_status_t dvdnav_get_title_string(dvdnav_t *self, const char **title_str);
/*
* Returns a string containing the serial number of the DVD.
* This has a max of 15 characters and should be more unique than the
* title string.
*/
dvdnav_status_t dvdnav_get_serial_string(dvdnav_t *self, const char **serial_str);
/*
* Get video aspect code.
* The aspect code does only change on VTS boundaries.
* See the DVDNAV_VTS_CHANGE event.
*
* 0 -- 4:3, 2 -- 16:9
*/
uint8_t dvdnav_get_video_aspect(dvdnav_t *self);
/*
* Get video resolution.
*/
dvdnav_status_t dvdnav_get_video_resolution(dvdnav_t *self, uint32_t *width, uint32_t *height);
/*
* Get video scaling permissions.
* The scaling permission does only change on VTS boundaries.
* See the DVDNAV_VTS_CHANGE event.
*
* bit0 set = deny letterboxing, bit1 set = deny pan&scan
*/
uint8_t dvdnav_get_video_scale_permission(dvdnav_t *self);
/*
* Converts a *logical* audio stream id into language code
* (returns 0xffff if no such stream).
*/
uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *self, uint8_t stream);
/*
* Returns the format of *logical* audio stream 'stream'
* (returns 0xffff if no such stream).
*/
uint16_t dvdnav_audio_stream_format(dvdnav_t *self, uint8_t stream);
/*
* Returns number of channels in *logical* audio stream 'stream'
* (returns 0xffff if no such stream).
*/
uint16_t dvdnav_audio_stream_channels(dvdnav_t *self, uint8_t stream);
/*
* Converts a *logical* subpicture stream id into country code
* (returns 0xffff if no such stream).
*/
uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *self, uint8_t stream);
/*
* Converts a *physical* (MPEG) audio stream id into a logical stream number.
*/
int8_t dvdnav_get_audio_logical_stream(dvdnav_t *self, uint8_t audio_num);
/*
* Get audio attr
*/
dvdnav_status_t dvdnav_get_audio_attr(dvdnav_t *self, uint8_t audio_mum, audio_attr_t *audio_attr);
/*
* Converts a *physical* (MPEG) subpicture stream id into a logical stream number.
*/
int8_t dvdnav_get_spu_logical_stream(dvdnav_t *self, uint8_t subp_num);
/*
* Get spu attr
*/
dvdnav_status_t dvdnav_get_spu_attr(dvdnav_t *self, uint8_t audio_mum, subp_attr_t *subp_attr);
/*
* Get active audio stream.
*/
int8_t dvdnav_get_active_audio_stream(dvdnav_t *self);
/*
* Get active spu stream.
*/
int8_t dvdnav_get_active_spu_stream(dvdnav_t *self);
/*
* Get the set of user operations that are currently prohibited.
* There are potentially new restrictions right after
* DVDNAV_CHANNEL_HOP and DVDNAV_NAV_PACKET.
*/
user_ops_t dvdnav_get_restrictions(dvdnav_t *self);
/*********************************************************************
* multiple angles *
*********************************************************************/
/*
* The libdvdnav library abstracts away the difference between seamless and
* non-seamless angles. From the point of view of the programmer you just set the
* angle number and all is well in the world. You will always see only the
* selected angle coming from the get_next_block functions.
*
* Note:
* It is quite possible that some tremendously strange DVD feature might change the
* angle number from under you. Generally you should always view the results from
* dvdnav_get_angle_info() as definitive only up to the next time you call
* dvdnav_get_next_block().
*/
/*
* Sets the current angle. If you try to follow a non existent angle
* the call fails.
*/
dvdnav_status_t dvdnav_angle_change(dvdnav_t *self, int32_t angle);
/*
* Returns the current angle and number of angles present.
*/
dvdnav_status_t dvdnav_get_angle_info(dvdnav_t *self, int32_t *current_angle,
int32_t *number_of_angles);
/*********************************************************************
* domain queries *
*********************************************************************/
/*
* Are we in the First Play domain?
*/
int8_t dvdnav_is_domain_fp(dvdnav_t *self);
/*
* Are we in the Video management Menu domain?
*/
int8_t dvdnav_is_domain_vmgm(dvdnav_t *self);
/*
* Are we in the Video Title Menu domain?
*/
int8_t dvdnav_is_domain_vtsm(dvdnav_t *self);
/*
* Are we in the Video Title Set domain?
*/
int8_t dvdnav_is_domain_vts(dvdnav_t *self);

212
dvdnav.py Normal file
View File

@ -0,0 +1,212 @@
import cffi
import os
import functools
from datetime import timedelta
from tqdm import tqdm
def loadlib(dll_path,*includes,**kwargs):
ffi = cffi.FFI()
for include in includes:
ffi.cdef(open(include).read(),kwargs)
return ffi,ffi.dlopen(dll_path)
class DVDError(Exception):
pass
class DVDNav(object):
def __init__(self,path,verbose=2,method="disc"):
os.environ["DVDCSS_VERBOSE"]=str(verbose)
os.environ["DVDCSS_METHOD"]=method
self.dvd=None
self.ffi,self.lib = loadlib("libdvdnav-4.dll",
"dvd_types.h",
"dvd_reader.h",
"ifo_types.h",
"nav_types.h",
"dvdnav_events.h",
"dvdnav.h")
self.path=path
self.titles={}
self.open(path)
def __del__(self):
self.__check_error(self.lib.dvdnav_close(self.dvd))
self.dvd=None
def __repr__(self):
return "<DVD Path={0.path} Title={0.title} Serial={0.serial}".format(self)
def get_blocks(self,title,angle=1,slang=None):
self.__check_error(self.lib.dvdnav_set_PGC_positioning_flag(self.dvd,1))
self.__check_error(self.lib.dvdnav_title_play(self.dvd,title))
self.__check_error(self.lib.dvdnav_angle_change(self.dvd,angle))
if slang is not None:
self.__check_error(self.lib.dvdnav_spu_language_select(self.dvd,slang))
event=self.lib.DVDNAV_NOP
buf=self.ffi.new("char[]",4096)
ev=self.ffi.new("int32_t*",self.lib.DVDNAV_NOP)
size=self.ffi.new("int32_t*",0)
pos=self.ffi.new("uint32_t*",0)
total_size=self.ffi.new("uint32_t*",0)
domains = {
1: "FirstPlay",
2: "VTSTitle",
4: "VMGM",
8: "VTSMenu"
}
events={
0: "DVDNAV_BLOCK_OK",
1: "DVDNAV_NOP",
2: "DVDNAV_STILL_FRAME",
3: "DVDNAV_SPU_STREAM_CHANGE",
4: "DVDNAV_AUDIO_STREAM_CHANGE",
5: "DVDNAV_VTS_CHANGE",
6: "DVDNAV_CELL_CHANGE",
7: "DVDNAV_NAV_PACKET",
8: "DVDNAV_STOP",
9: "DVDNAV_HIGHLIGHT",
10: "DVDNAV_SPU_CLUT_CHANGE",
12: "DVDNAV_HOP_CHANNEL",
13: "DVDNAV_WAIT"
}
progbar=tqdm(unit_divisor=1024,unit_scale=True,unit="iB",desc="Ripping DVD")
while True:
self.__check_error(self.lib.dvdnav_get_next_block(self.dvd,buf,ev,size))
if self.lib.dvdnav_get_position(self.dvd,pos,total_size)==self.lib.DVDNAV_STATUS_OK:
progbar.total=total_size[0]*2048
progbar.n=max(progbar.n,min(progbar.total,pos[0]*2048))
progbar.update(0)
# print("Got event:",events.get(ev[0],ev[0]),size[0])
if ev[0] in [self.lib.DVDNAV_SPU_CLUT_CHANGE,self.lib.DVDNAV_HOP_CHANNEL,self.lib.DVDNAV_NOP]:
continue
elif ev[0]==self.lib.DVDNAV_BLOCK_OK:
# print("Read",size[0])
yield self.ffi.buffer(buf,size[0])[:]
elif ev[0]==self.lib.DVDNAV_STOP:
break
elif ev[0]==self.lib.DVDNAV_NAV_PACKET:
nav=self.lib.dvdnav_get_current_nav_pci(self.dvd)
# print("PTS:",timedelta(seconds=nav.pci_gi.vobu_s_ptm/90000))
elif ev[0]==self.lib.DVDNAV_STILL_FRAME:
# print("Still")
self.__check_error(self.lib.dvdnav_still_skip(self.dvd))
elif ev[0]==self.lib.DVDNAV_WAIT:
# print("Wait",size[0])
self.__check_error(self.lib.dvdnav_wait_skip(self.dvd))
elif ev[0]==self.lib.DVDNAV_SPU_STREAM_CHANGE:
spu=self.ffi.cast("dvdnav_spu_stream_change_event_t*",buf)
progbar.write(f"[{title}|{angle}] SPU: Wide: {spu.physical_wide} Letterbox: {spu.physical_letterbox} Pan&Scan: {spu.physical_pan_scan} Logical: {spu.logical}")
elif ev[0]==self.lib.DVDNAV_AUDIO_STREAM_CHANGE:
audio=self.ffi.cast("dvdnav_audio_stream_change_event_t*",buf)
progbar.write(f"[{title}|{angle}] Audio: Physical: {audio.physical} Logical: {audio.logical}")
elif ev[0]==self.lib.DVDNAV_CELL_CHANGE:
cell=self.ffi.cast("dvdnav_cell_change_event_t*",buf)
progbar.write(f"[{title}|{angle}] Cell: {cell.cellN} ({cell.cell_start}-{cell.cell_start+cell.cell_length}), PG: {cell.pgN} ({cell.pg_start}-{cell.pg_start+cell.pg_length})")
elif ev[0]==self.lib.DVDNAV_VTS_CHANGE:
vts=self.ffi.cast("dvdnav_vts_change_event_t*",buf)
old_domain=sorted(domains[k] for k in domains if vts.old_domain&k)
new_domain=sorted(domains[k] for k in domains if vts.new_domain&k)
progbar.write(f"[{title}|{angle}] VTS: {vts.old_vtsN} ({vts.old_domain} {old_domain}) -> {vts.new_vtsN} ({vts.new_domain} {new_domain})")
if vts.new_domain==8: # back to menu
break
else:
progbar.write(f"[{title}|{angle}] Unhandled: {events.get(ev[0],ev[0])} {size[0]}")
def __check_error(self,ret):
if ret==self.lib.DVDNAV_STATUS_ERR:
if self.dvd:
err=self.ffi.string(self.lib.dvdnav_err_to_string(self.dvd))
raise DVDError(err)
raise DVDError("Unknown error")
def __get_titles(self):
titles=self.ffi.new("int32_t*",0)
p_times=self.ffi.new("uint64_t[]",512)
times=self.ffi.new("uint64_t**",p_times)
duration=self.ffi.new("uint64_t*",0)
titles=self.ffi.new("int32_t*",0)
self.lib.dvdnav_get_number_of_titles(self.dvd,titles)
num_titles=titles[0]
for title in range(0,num_titles+1):
if self.lib.dvdnav_get_number_of_parts(self.dvd,title,titles)==0:
continue
num_parts=titles[0]
self.lib.dvdnav_get_number_of_angles(self.dvd,title,titles)
num_angles=titles[0]
num_chapters=self.lib.dvdnav_describe_title_chapters(self.dvd,title,times,duration)
if duration[0]==0:
continue
chapters=[]
for t in range(num_chapters):
chapters.append(timedelta(seconds=times[0][t]/90000))
self.titles[title]={
'parts':num_parts,
'angles': num_angles,
'duration': timedelta(seconds=duration[0]/90000),
'chapters': chapters
}
def __get_info(self):
s=self.ffi.new("char**",self.ffi.NULL)
self.lib.dvdnav_get_title_string(self.dvd,s)
self.title=str(self.ffi.string(s[0]),"utf8").strip() or None
self.lib.dvdnav_get_serial_string(self.dvd,s)
self.serial=str(self.ffi.string(s[0]),"utf8").strip() or None
self.__get_titles()
def open(self,path):
audio_attrs=self.ffi.new("audio_attr_t*")
spu_attr=self.ffi.new("subp_attr_t*")
dvdnav=self.ffi.new("dvdnav_t**",self.ffi.cast("dvdnav_t*",0))
self.__check_error(self.lib.dvdnav_open(dvdnav,bytes(path,"utf8")))
self.dvd=dvdnav[0]
self.__check_error(self.lib.dvdnav_set_readahead_flag(self.dvd,1))
self.__get_info()
for title in self.titles:
self.__check_error(self.lib.dvdnav_title_play(self.dvd,title))
self.titles[title]['audio']={}
self.titles[title]['subtitles']={}
for n in range(255):
stream_id=self.lib.dvdnav_get_audio_logical_stream(self.dvd,n)
if stream_id==-1:
continue
self.__check_error(self.lib.dvdnav_get_audio_attr(self.dvd,stream_id,audio_attrs))
alang=None
if audio_attrs.lang_type:
alang = str(audio_attrs.lang_code.to_bytes(2,'big'),"utf8")
channels = audio_attrs.channels+1
codec = {
0: 'ac3',
2: 'mpeg1',
3: 'mpeg-2ext',
4: 'lpcm',
6: 'dts'
}[audio_attrs.audio_format]
audio_type={
0: None,
1: 'normal',
2: 'descriptive',
3: "director's commentary",
4: "alternate director's commentary"
}[audio_attrs.code_extension]
self.titles[title]['audio'][n]={
'stream_id': stream_id,
'lang':alang,
'channels': channels,
'codec': codec,
'type': audio_type
}
for n in range(255):
stream_id=self.lib.dvdnav_get_spu_logical_stream(self.dvd,n)
if stream_id==-1:
continue
self.__check_error(self.lib.dvdnav_get_spu_attr(self.dvd,stream_id,spu_attr))
slang = None
if spu_attr.type==1:
slang = str(spu_attr.lang_code.to_bytes(2,'big'),"utf8")
self.titles[title]['subtitles'][n]={
'stream_id': stream_id,
'lang':slang
}
self.__check_error(self.lib.dvdnav_stop(self.dvd))

230
dvdnav_events.h Normal file
View File

@ -0,0 +1,230 @@
/*
* Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net>
*
* This file is part of libdvdnav, a DVD navigation library.
*
* libdvdnav 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.
*
* libdvdnav 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 libdvdnav; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* This header defines events and event types
*/
/*
* DVDNAV_BLOCK_OK
*
* A regular data block from the DVD has been returned.
* This one should be demuxed and decoded for playback.
*/
#define DVDNAV_BLOCK_OK 0
/*
* DVDNAV_NOP
*
* Just ignore this.
*/
#define DVDNAV_NOP 1
/*
* DVDNAV_STILL_FRAME
*
* We have reached a still frame. The player application should wait
* the amount of time specified by the still's length while still handling
* user input to make menus and other interactive stills work.
* The last delivered frame should be kept showing.
* Once the still has timed out, call dvdnav_skip_still().
* A length of 0xff means an infinite still which has to be skipped
* indirectly by some user interaction.
*/
#define DVDNAV_STILL_FRAME 2
typedef struct {
/* The length (in seconds) the still frame should be displayed for,
* or 0xff if infinite. */
int length;
} dvdnav_still_event_t;
/*
* DVDNAV_SPU_STREAM_CHANGE
*
* Inform the SPU decoding/overlaying engine to switch SPU channels.
*/
#define DVDNAV_SPU_STREAM_CHANGE 3
typedef struct {
/* The physical (MPEG) stream number for widescreen SPU display.
* Use this, if you blend the SPU on an anamorphic image before
* unsqueezing it. */
int physical_wide;
/* The physical (MPEG) stream number for letterboxed display.
* Use this, if you blend the SPU on an anamorphic image after
* unsqueezing it. */
int physical_letterbox;
/* The physical (MPEG) stream number for pan&scan display.
* Use this, if you blend the SPU on an anamorphic image after
* unsqueezing it the pan&scan way. */
int physical_pan_scan;
/* The logical (DVD) stream number. */
int logical;
} dvdnav_spu_stream_change_event_t;
/*
* DVDNAV_AUDIO_STREAM_CHANGE
*
* Inform the audio decoder to switch channels.
*/
#define DVDNAV_AUDIO_STREAM_CHANGE 4
typedef struct {
/* The physical (MPEG) stream number. */
int physical;
/* The logical (DVD) stream number. */
int logical;
} dvdnav_audio_stream_change_event_t;
/*
* DVDNAV_VTS_CHANGE
*
* Some status information like video aspect and video scale permissions do
* not change inside a VTS. Therefore this event can be used to query such
* information only when necessary and update the decoding/displaying
* accordingly.
*/
#define DVDNAV_VTS_CHANGE 5
typedef struct {
int old_vtsN; /* the old VTS number */
DVDDomain_t old_domain; /* the old domain */
int new_vtsN; /* the new VTS number */
DVDDomain_t new_domain; /* the new domain */
} dvdnav_vts_change_event_t;
/*
* DVDNAV_CELL_CHANGE
*
* Some status information like the current Title and Part numbers do not
* change inside a cell. Therefore this event can be used to query such
* information only when necessary and update the decoding/displaying
* accordingly.
* Some useful information for accurate time display is also reported
* together with this event.
*/
#define DVDNAV_CELL_CHANGE 6
typedef struct {
int cellN; /* the new cell number */
int pgN; /* the current program number */
int64_t cell_length; /* the length of the current cell in sectors */
int64_t pg_length; /* the length of the current program in sectors */
int64_t pgc_length; /* the length of the current program chain in PTS ticks */
int64_t cell_start; /* the start offset of the current cell relatively to the PGC in sectors */
int64_t pg_start; /* the start offset of the current PG relatively to the PGC in sectors */
} dvdnav_cell_change_event_t;
/*
* DVDNAV_NAV_PACKET
*
* NAV packets are useful for various purposes. They define the button
* highlight areas and VM commands of DVD menus, so they should in any
* case be sent to the SPU decoder/overlaying engine for the menus to work.
* NAV packets also provide a way to detect PTS discontinuities, because
* they carry the start and end PTS values for the current VOBU.
* (pci.vobu_s_ptm and pci.vobu_e_ptm) Whenever the start PTS of the
* current NAV does not match the end PTS of the previous NAV, a PTS
* discontinuity has occured.
* NAV packets can also be used for time display, because they are
* timestamped relatively to the current Cell.
*/
#define DVDNAV_NAV_PACKET 7
/*
* DVDNAV_STOP
*
* Applications should end playback here. A subsequent dvdnav_get_next_block()
* call will restart the VM from the beginning of the DVD.
*/
#define DVDNAV_STOP 8
/*
* DVDNAV_HIGHLIGHT
*
* The current button highlight changed. Inform the overlaying engine to
* highlight a different button. Please note, that at the moment only mode 1
* highlights are reported this way. That means, when the button highlight
* has been moved around by some function call, you will receive an event
* telling you the new button. But when a button gets activated, you have
* to handle the mode 2 highlighting (that is some different colour the
* button turns to on activation) in your application.
*/
#define DVDNAV_HIGHLIGHT 9
typedef struct {
/* highlight mode: 0 - hide, 1 - show, 2 - activate, currently always 1 */
int display;
/* FIXME: these fields are currently not set */
uint32_t palette; /* The CLUT entries for the highlight palette
(4-bits per entry -> 4 entries) */
uint16_t sx,sy,ex,ey; /* The start/end x,y positions */
uint32_t pts; /* Highlight PTS to match with SPU */
/* button number for the SPU decoder/overlaying engine */
uint32_t buttonN;
} dvdnav_highlight_event_t;
/*
* DVDNAV_SPU_CLUT_CHANGE
*
* Inform the SPU decoder/overlaying engine to update its colour lookup table.
* The CLUT is given as 16 uint32_t's in the buffer.
*/
#define DVDNAV_SPU_CLUT_CHANGE 10
/*
* DVDNAV_HOP_CHANNEL
*
* A non-seamless operation has been performed. Applications can drop all
* their internal fifo's content, which will speed up the response.
*/
#define DVDNAV_HOP_CHANNEL 12
/*
* DVDNAV_WAIT
*
* We have reached a point in DVD playback, where timing is critical.
* Player application with internal fifos can introduce state
* inconsistencies, because libdvdnav is always the fifo's length
* ahead in the stream compared to what the application sees.
* Such applications should wait until their fifos are empty
* when they receive this type of event.
* Once this is achieved, call dvdnav_skip_wait().
*/
#define DVDNAV_WAIT 13

43
dvdread.py Normal file
View File

@ -0,0 +1,43 @@
import cffi
import os
import functools
import binascii
from datetime import timedelta
def loadlib(dll_path,*includes,**kwargs):
ffi = cffi.FFI()
for include in includes:
ffi.cdef(open(include).read(),**kwargs)
return ffi,ffi.dlopen(dll_path)
class DVDRead(object):
def __init__(self,path):
self.dvd=None
self.ffi,self.lib = loadlib("libdvdread-8.dll",
"dvd_types.h",
"dvd_reader.h",
"ifo_types.h",
"ifo_read.h",
"ifo_print.h",
"nav_types.h",
"nav_read.h",
"nav_print.h")
self.path=path
self.titles={}
self.open(path)
def __del__(self):
if self.dvd:
self.lib.DVDClose(self.dvd)
def open(self,path):
# self.dvd_css=self.css_lib.dvdcss_open()
self.dvd=self.lib.DVDOpen(bytes(path,"utf8"))
vol_id=self.ffi.new("unsigned char[]",32)
self.lib.DVDDiscID(self.dvd,vol_id)
self.disc_id=str(binascii.hexlify(self.ffi.buffer(vol_id,16)[:]),"utf8")
self.lib.DVDUDFVolumeInfo(self.dvd,vol_id,32,self.ffi.NULL,0)
self.udf_disc_name=str(self.ffi.string(vol_id),"utf8")
self.lib.DVDISOVolumeInfo(self.dvd,vol_id,32,self.ffi.NULL,0)
self.iso_disc_name=str(self.ffi.string(vol_id),"utf8")
self.ffi.release(vol_id)

173
ff_d2v.py Normal file
View File

@ -0,0 +1,173 @@
import sys
import json
import os
import subprocess as SP
import itertools as ITT
from tqdm import tqdm
colorspace={
"gbr": 0,
"bt709": 1,
"unknown": 2,
"fcc": 4,
"bt470bg": 5,
"smpte170m": 6,
"smpte240m": 7,
"ycgco": 8,
"bt2020nc": 9,
"bt2020c": 10,
"smpte2085": 11,
"chroma-derived-nc": 12,
"chroma-derived-c": 13,
"ictcp": 14,
}
pict_types={
'I':0b01,
'P':0b10,
'B':0b11
}
def make_info(frames):
has_interlaced = any(frame['interlaced_frame'] for frame in frames)
new_gop='timecode' in frames[0].get('tags',{})
info=0x000
info|=1<<11 # always 1
info|=0<<10 # 0=Closed GOP, 1=Open GOP
info|=(not has_interlaced)<<9 # Progressive
info|=new_gop<<8
return info
def make_flags(frames):
flags=[]
for frame in frames:
needs_prev=False
progressive=not int(frame['interlaced_frame'])
pt=pict_types[frame['pict_type']]
reserved=0b00
tff=int(frame['top_field_first'])
rff=int(frame['repeat_pict'])
flag=0b0
flag|=(not needs_prev)<<7
flag|=progressive<<6
flag|=pt<<4
flag|=reserved<<2
flag|=tff<<1
flag|=rff
flags.append(f"{flag:02x}")
return flags
def make_line(frames,stream):
info=f"{make_info(frames):03x}"
matrix=colorspace[stream['color_space']]
file=0
position=frames[0]['pkt_pos']
skip=0
vob=0
cell=0
flags=make_flags(frames)
return " ".join(map(str,[info,matrix,file,position,skip,vob,cell,*flags]))
def get_frames(path):
proc=SP.Popen([
"ffprobe",
"-probesize", str(0x7fffffff),
"-analyzeduration", str(0x7fffffff),
"-v","fatal",
"-i",path,
"-select_streams","v:0",
"-show_frames",
"-print_format","compact"
],stdout=SP.PIPE,stdin=SP.DEVNULL,bufsize=0)
data=None
for line in proc.stdout:
line=str(line,"utf8").strip().split("|")
line={line[0]: dict(v.split("=") for v in line[1:])}
yield line
ret=proc.wait()
if ret!=0:
exit(ret)
return data
def get_streams(path):
proc=SP.Popen([
"ffprobe",
"-probesize", str(0x7fffffff),
"-analyzeduration", str(0x7fffffff),
"-v","fatal",
"-i",path,
"-select_streams","v:0",
"-show_streams",
"-show_format",
"-print_format","json"
],stdout=SP.PIPE,stdin=SP.DEVNULL,bufsize=0)
data=json.load(proc.stdout)
ret=proc.wait()
if ret!=0:
exit(ret)
return data['streams'],data['format']
def make_header(file):
return ["DGIndexProjectFile16","1",os.path.abspath(file)]
def make_settings(stream):
pict_size="x".join(map(str,[stream["width"],stream["height"]]))
frame_rate = list(map(int,stream['r_frame_rate'].split("/")))
frame_rate=(frame_rate[0]*1000)//frame_rate[1]
frame_rate=f"{frame_rate} ({stream['r_frame_rate']})"
header=[
("Stream_Type",0), # Elementary Stream
("MPEG_Type",2), # MPEG-2
("iDCT_Algorithm",5), # 64-bit IEEE-1180 Reference
("YUVRGB_Scale",int(stream["color_range"]!="tv")),
("Luminance_Filter","0,0"),
("Clipping","0,0,0,0"),
("Aspect_Ratio",stream["display_aspect_ratio"]),
("Picture_Size",pict_size),
("Field_Operation",0), # Honor Pulldown Flags
("Frame_Rate", frame_rate),
("Location",f"0,0,0,0"),
]
for k,v in header:
yield f"{k}={v}"
def gen_d2v(path):
yield from make_header(path)
yield ""
streams,fmt=get_streams(path)
stream=[s for s in streams if s['codec_type']=='video'][0]
stream['index']=str(stream['index'])
yield from make_settings(stream)
yield ""
line_buffer=[]
frames=get_frames(path)
prog_bar=tqdm(frames,total=int(fmt['size']),unit_divisor=1024,unit_scale=True,unit="iB",dec="Writing d2v")
for line in prog_bar:
if 'frame' not in line:
continue
frame=line['frame']
prog_bar.n=min(max(prog_bar.n,int(frame['pkt_pos'])),int(fmt['size']))
prog_bar.update(0)
if frame['stream_index']!=stream['index']:
continue
if frame['pict_type']=="I" and line_buffer:
yield make_line(line_buffer,stream)
line_buffer.clear()
line_buffer.append(frame)
prog_bar.close()
yield None
def make_d2v(path):
outfile=os.path.splitext(os.path.basename(path))[0]
outfile=os.path.extsep.join([outfile,"d2v"])
a,b=ITT.tee(gen_d2v(path))
next(b)
with open(outfile,"w") as fh:
for line,next_line in zip(a,b):
fh.write(line)
if next_line is None: # last line, append end marker
fh.write(" ff")
fh.write("\n")

21
ifo_print.h Normal file
View File

@ -0,0 +1,21 @@
/*
* This file is part of libdvdread.
*
* libdvdread 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.
*
* libdvdread 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 libdvdread; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
void ifo_print(dvd_reader_t *dvd, int title);
void dvdread_print_time(dvd_time_t *dtime);

215
ifo_read.h Normal file
View File

@ -0,0 +1,215 @@
/*
* Copyright (C) 2000, 2001, 2002 Björn Englund <d4bjorn@dtek.chalmers.se>,
* Håkan Hjort <d95hjort@dtek.chalmers.se>
*
* This file is part of libdvdread.
*
* libdvdread 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.
*
* libdvdread 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 libdvdread; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/**
* handle = ifoOpen(dvd, title);
*
* Opens an IFO and reads in all the data for the IFO file corresponding to the
* given title. If title 0 is given, the video manager IFO file is read.
* Returns a handle to a completely parsed structure.
*/
ifo_handle_t *ifoOpen(dvd_reader_t *, int );
/**
* handle = ifoOpenVMGI(dvd);
*
* Opens an IFO and reads in _only_ the vmgi_mat data. This call can be used
* together with the calls below to read in each segment of the IFO file on
* demand.
*/
ifo_handle_t *ifoOpenVMGI(dvd_reader_t *);
/**
* handle = ifoOpenVTSI(dvd, title);
*
* Opens an IFO and reads in _only_ the vtsi_mat data. This call can be used
* together with the calls below to read in each segment of the IFO file on
* demand.
*/
ifo_handle_t *ifoOpenVTSI(dvd_reader_t *, int);
/**
* ifoClose(ifofile);
* Cleans up the IFO information. This will free all data allocated for the
* substructures.
*/
void ifoClose(ifo_handle_t *);
/**
* The following functions are for reading only part of the VMGI/VTSI files.
* Returns 1 if the data was successfully read and 0 on error.
*/
/**
* okay = ifoRead_PLT_MAIT(ifofile);
*
* Read in the Parental Management Information table, filling the
* ifofile->ptl_mait structure and its substructures. This data is only
* located in the video manager information file. This fills the
* ifofile->ptl_mait structure and all its substructures.
*/
int ifoRead_PTL_MAIT(ifo_handle_t *);
/**
* okay = ifoRead_VTS_ATRT(ifofile);
*
* Read in the attribute table for the main menu vob, filling the
* ifofile->vts_atrt structure and its substructures. Only located in the
* video manager information file. This fills in the ifofile->vts_atrt
* structure and all its substructures.
*/
int ifoRead_VTS_ATRT(ifo_handle_t *);
/**
* okay = ifoRead_TT_SRPT(ifofile);
*
* Reads the title info for the main menu, filling the ifofile->tt_srpt
* structure and its substructures. This data is only located in the video
* manager information file. This structure is mandatory in the IFO file.
*/
int ifoRead_TT_SRPT(ifo_handle_t *);
/**
* okay = ifoRead_VTS_PTT_SRPT(ifofile);
*
* Reads in the part of title search pointer table, filling the
* ifofile->vts_ptt_srpt structure and its substructures. This data is only
* located in the video title set information file. This structure is
* mandatory, and must be included in the VTSI file.
*/
int ifoRead_VTS_PTT_SRPT(ifo_handle_t *);
/**
* okay = ifoRead_FP_PGC(ifofile);
*
* Reads in the first play program chain data, filling the
* ifofile->first_play_pgc structure. This data is only located in the video
* manager information file (VMGI). This structure is optional.
*/
int ifoRead_FP_PGC(ifo_handle_t *);
/**
* okay = ifoRead_PGCIT(ifofile);
*
* Reads in the program chain information table for the video title set. Fills
* in the ifofile->vts_pgcit structure and its substructures, which includes
* the data for each program chain in the set. This data is only located in
* the video title set information file. This structure is mandatory, and must
* be included in the VTSI file.
*/
int ifoRead_PGCIT(ifo_handle_t *);
/**
* okay = ifoRead_PGCI_UT(ifofile);
*
* Reads in the menu PGCI unit table for the menu VOB. For the video manager,
* this corresponds to the VIDEO_TS.VOB file, and for each title set, this
* corresponds to the VTS_XX_0.VOB file. This data is located in both the
* video manager and video title set information files. For VMGI files, this
* fills the ifofile->vmgi_pgci_ut structure and all its substructures. For
* VTSI files, this fills the ifofile->vtsm_pgci_ut structure.
*/
int ifoRead_PGCI_UT(ifo_handle_t *);
/**
* okay = ifoRead_VTS_TMAPT(ifofile);
*
* Reads in the VTS Time Map Table, this data is only located in the video
* title set information file. This fills the ifofile->vts_tmapt structure
* and all its substructures. When pressent enables VOBU level time-based
* seeking for One_Sequential_PGC_Titles.
*/
int ifoRead_VTS_TMAPT(ifo_handle_t *);
/**
* okay = ifoRead_C_ADT(ifofile);
*
* Reads in the cell address table for the menu VOB. For the video manager,
* this corresponds to the VIDEO_TS.VOB file, and for each title set, this
* corresponds to the VTS_XX_0.VOB file. This data is located in both the
* video manager and video title set information files. For VMGI files, this
* fills the ifofile->vmgm_c_adt structure and all its substructures. For VTSI
* files, this fills the ifofile->vtsm_c_adt structure.
*/
int ifoRead_C_ADT(ifo_handle_t *);
/**
* okay = ifoRead_TITLE_C_ADT(ifofile);
*
* Reads in the cell address table for the video title set corresponding to
* this IFO file. This data is only located in the video title set information
* file. This structure is mandatory, and must be included in the VTSI file.
* This call fills the ifofile->vts_c_adt structure and its substructures.
*/
int ifoRead_TITLE_C_ADT(ifo_handle_t *);
/**
* okay = ifoRead_VOBU_ADMAP(ifofile);
*
* Reads in the VOBU address map for the menu VOB. For the video manager, this
* corresponds to the VIDEO_TS.VOB file, and for each title set, this
* corresponds to the VTS_XX_0.VOB file. This data is located in both the
* video manager and video title set information files. For VMGI files, this
* fills the ifofile->vmgm_vobu_admap structure and all its substructures. For
* VTSI files, this fills the ifofile->vtsm_vobu_admap structure.
*/
int ifoRead_VOBU_ADMAP(ifo_handle_t *);
/**
* okay = ifoRead_TITLE_VOBU_ADMAP(ifofile);
*
* Reads in the VOBU address map for the associated video title set. This data
* is only located in the video title set information file. This structure is
* mandatory, and must be included in the VTSI file. Fills the
* ifofile->vts_vobu_admap structure and its substructures.
*/
int ifoRead_TITLE_VOBU_ADMAP(ifo_handle_t *);
/**
* okay = ifoRead_TXTDT_MGI(ifofile);
*
* Reads in the text data strings for the DVD. Fills the ifofile->txtdt_mgi
* structure and all its substructures. This data is only located in the video
* manager information file. This structure is mandatory, and must be included
* in the VMGI file.
*/
int ifoRead_TXTDT_MGI(ifo_handle_t *);
/**
* The following functions are used for freeing parsed sections of the
* ifo_handle_t structure and the allocated substructures. The free calls
* below are safe: they will not mind if you attempt to free part of an IFO
* file which was not read in or which does not exist.
*/
void ifoFree_PTL_MAIT(ifo_handle_t *);
void ifoFree_VTS_ATRT(ifo_handle_t *);
void ifoFree_TT_SRPT(ifo_handle_t *);
void ifoFree_VTS_PTT_SRPT(ifo_handle_t *);
void ifoFree_FP_PGC(ifo_handle_t *);
void ifoFree_PGCIT(ifo_handle_t *);
void ifoFree_PGCI_UT(ifo_handle_t *);
void ifoFree_VTS_TMAPT(ifo_handle_t *);
void ifoFree_C_ADT(ifo_handle_t *);
void ifoFree_TITLE_C_ADT(ifo_handle_t *);
void ifoFree_VOBU_ADMAP(ifo_handle_t *);
void ifoFree_TITLE_VOBU_ADMAP(ifo_handle_t *);
void ifoFree_TXTDT_MGI(ifo_handle_t *);

683
ifo_types.h Normal file
View File

@ -0,0 +1,683 @@
/**
* Common
*
* The following structures are used in both the VMGI and VTSI.
*/
/**
* DVD Time Information.
*/
typedef struct {
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t frame_u; /* The two high bits are the frame rate. */
} dvd_time_t;
/**
* Type to store per-command data.
*/
typedef struct {
uint8_t bytes[8];
} vm_cmd_t;
#define COMMAND_DATA_SIZE 8U
/**
* Video Attributes.
*/
typedef struct {
unsigned char mpeg_version : 2;
unsigned char video_format : 2;
unsigned char display_aspect_ratio : 2;
unsigned char permitted_df : 2;
unsigned char line21_cc_1 : 1;
unsigned char line21_cc_2 : 1;
unsigned char unknown1 : 1;
unsigned char bit_rate : 1;
unsigned char picture_size : 2;
unsigned char letterboxed : 1;
unsigned char film_mode : 1;
} video_attr_t;
/**
* Audio Attributes.
*/
typedef struct {
unsigned char audio_format : 3;
unsigned char multichannel_extension : 1;
unsigned char lang_type : 2;
unsigned char application_mode : 2;
unsigned char quantization : 2;
unsigned char sample_frequency : 2;
unsigned char unknown1 : 1;
unsigned char channels : 3;
uint16_t lang_code;
uint8_t lang_extension;
uint8_t code_extension;
uint8_t unknown3;
union {
struct {
unsigned char unknown4 : 1;
unsigned char channel_assignment : 3;
unsigned char version : 2;
unsigned char mc_intro : 1; /* probably 0: true, 1:false */
unsigned char mode : 1; /* Karaoke mode 0: solo 1: duet */
} karaoke;
struct {
unsigned char unknown5 : 4;
unsigned char dolby_encoded : 1; /* suitable for surround decoding */
unsigned char unknown6 : 3;
} surround;
} app_info;
} audio_attr_t;
/**
* MultiChannel Extension
*/
typedef struct {
unsigned int zero1 : 7;
unsigned int ach0_gme : 1;
unsigned int zero2 : 7;
unsigned int ach1_gme : 1;
unsigned int zero3 : 4;
unsigned int ach2_gv1e : 1;
unsigned int ach2_gv2e : 1;
unsigned int ach2_gm1e : 1;
unsigned int ach2_gm2e : 1;
unsigned int zero4 : 4;
unsigned int ach3_gv1e : 1;
unsigned int ach3_gv2e : 1;
unsigned int ach3_gmAe : 1;
unsigned int ach3_se2e : 1;
unsigned int zero5 : 4;
unsigned int ach4_gv1e : 1;
unsigned int ach4_gv2e : 1;
unsigned int ach4_gmBe : 1;
unsigned int ach4_seBe : 1;
uint8_t zero6[19];
} multichannel_ext_t;
/**
* Subpicture Attributes.
*/
typedef struct {
/*
* type: 0 not specified
* 1 language
* 2 other
* coding mode: 0 run length
* 1 extended
* 2 other
* language: indicates language if type == 1
* lang extension: if type == 1 contains the lang extension
*/
unsigned char code_mode : 3;
unsigned char zero1 : 3;
unsigned char type : 2;
uint8_t zero2;
uint16_t lang_code;
uint8_t lang_extension;
uint8_t code_extension;
} subp_attr_t;
/**
* PGC Command Table.
*/
typedef struct {
uint16_t nr_of_pre;
uint16_t nr_of_post;
uint16_t nr_of_cell;
uint16_t zero_1;
vm_cmd_t *pre_cmds;
vm_cmd_t *post_cmds;
vm_cmd_t *cell_cmds;
} pgc_command_tbl_t;
#define PGC_COMMAND_TBL_SIZE 8U
/**
* PGC Program Map
*/
typedef uint8_t pgc_program_map_t;
/**
* Cell Playback Information.
*/
typedef struct {
unsigned int block_mode : 2;
unsigned int block_type : 2;
unsigned int seamless_play : 1;
unsigned int interleaved : 1;
unsigned int stc_discontinuity: 1;
unsigned int seamless_angle : 1;
unsigned int zero_1 : 1;
unsigned int playback_mode : 1; /**< When set, enter StillMode after each VOBU */
unsigned int restricted : 1; /**< ?? drop out of fastforward? */
unsigned int cell_type : 5; /** for karaoke, reserved otherwise */
uint8_t still_time;
uint8_t cell_cmd_nr;
dvd_time_t playback_time;
uint32_t first_sector;
uint32_t first_ilvu_end_sector;
uint32_t last_vobu_start_sector;
uint32_t last_sector;
} cell_playback_t;
#define BLOCK_TYPE_NONE 0x0
#define BLOCK_TYPE_ANGLE_BLOCK 0x1
#define BLOCK_MODE_NOT_IN_BLOCK 0x0
#define BLOCK_MODE_FIRST_CELL 0x1
#define BLOCK_MODE_IN_BLOCK 0x2
#define BLOCK_MODE_LAST_CELL 0x3
/**
* Cell Position Information.
*/
typedef struct {
uint16_t vob_id_nr;
uint8_t zero_1;
uint8_t cell_nr;
} cell_position_t;
/**
* User Operations.
*/
typedef struct {
unsigned int zero : 7; /* 25-31 */
unsigned int video_pres_mode_change : 1; /* 24 */
unsigned int karaoke_audio_pres_mode_change : 1; /* 23 */
unsigned int angle_change : 1;
unsigned int subpic_stream_change : 1;
unsigned int audio_stream_change : 1;
unsigned int pause_on : 1;
unsigned int still_off : 1;
unsigned int button_select_or_activate : 1;
unsigned int resume : 1; /* 16 */
unsigned int chapter_menu_call : 1; /* 15 */
unsigned int angle_menu_call : 1;
unsigned int audio_menu_call : 1;
unsigned int subpic_menu_call : 1;
unsigned int root_menu_call : 1;
unsigned int title_menu_call : 1;
unsigned int backward_scan : 1;
unsigned int forward_scan : 1; /* 8 */
unsigned int next_pg_search : 1; /* 7 */
unsigned int prev_or_top_pg_search : 1;
unsigned int time_or_chapter_search : 1;
unsigned int go_up : 1;
unsigned int stop : 1;
unsigned int title_play : 1;
unsigned int chapter_search_or_play : 1;
unsigned int title_or_time_play : 1; /* 0 */
} user_ops_t;
/**
* Program Chain Information.
*/
typedef struct {
uint16_t zero_1;
uint8_t nr_of_programs;
uint8_t nr_of_cells;
dvd_time_t playback_time;
user_ops_t prohibited_ops;
uint16_t audio_control[8]; /* New type? */
uint32_t subp_control[32]; /* New type? */
uint16_t next_pgc_nr;
uint16_t prev_pgc_nr;
uint16_t goup_pgc_nr;
uint8_t pg_playback_mode;
uint8_t still_time;
uint32_t palette[16]; /* New type struct {zero_1, Y, Cr, Cb} ? */
uint16_t command_tbl_offset;
uint16_t program_map_offset;
uint16_t cell_playback_offset;
uint16_t cell_position_offset;
pgc_command_tbl_t *command_tbl;
pgc_program_map_t *program_map;
cell_playback_t *cell_playback;
cell_position_t *cell_position;
int ref_count;
} pgc_t;
#define PGC_SIZE 236U
/**
* Program Chain Information Search Pointer.
*/
typedef struct {
uint8_t entry_id;
unsigned int block_mode : 2;
unsigned int block_type : 2;
unsigned int zero_1 : 4;
uint16_t ptl_id_mask;
uint32_t pgc_start_byte;
pgc_t *pgc;
} pgci_srp_t;
#define PGCI_SRP_SIZE 8U
/**
* Program Chain Information Table.
*/
typedef struct {
uint16_t nr_of_pgci_srp;
uint16_t zero_1;
uint32_t last_byte;
pgci_srp_t *pgci_srp;
int ref_count;
} pgcit_t;
#define PGCIT_SIZE 8U
/**
* Menu PGCI Language Unit.
*/
typedef struct {
uint16_t lang_code;
uint8_t lang_extension;
uint8_t exists;
uint32_t lang_start_byte;
pgcit_t *pgcit;
} pgci_lu_t;
#define PGCI_LU_SIZE 8U
/**
* Menu PGCI Unit Table.
*/
typedef struct {
uint16_t nr_of_lus;
uint16_t zero_1;
uint32_t last_byte;
pgci_lu_t *lu;
} pgci_ut_t;
#define PGCI_UT_SIZE 8U
/**
* Cell Address Information.
*/
typedef struct {
uint16_t vob_id;
uint8_t cell_id;
uint8_t zero_1;
uint32_t start_sector;
uint32_t last_sector;
} cell_adr_t;
/**
* Cell Address Table.
*/
typedef struct {
uint16_t nr_of_vobs; /* VOBs */
uint16_t zero_1;
uint32_t last_byte;
cell_adr_t *cell_adr_table; /* No explicit size given. */
} c_adt_t;
#define C_ADT_SIZE 8U
/**
* VOBU Address Map.
*/
typedef struct {
uint32_t last_byte;
uint32_t *vobu_start_sectors;
} vobu_admap_t;
#define VOBU_ADMAP_SIZE 4U
/**
* VMGI
*
* The following structures relate to the Video Manager.
*/
/**
* Video Manager Information Management Table.
*/
typedef struct {
char vmg_identifier[12];
uint32_t vmg_last_sector;
uint8_t zero_1[12];
uint32_t vmgi_last_sector;
uint8_t zero_2;
uint8_t specification_version;
uint32_t vmg_category;
uint16_t vmg_nr_of_volumes;
uint16_t vmg_this_volume_nr;
uint8_t disc_side;
uint8_t zero_3[19];
uint16_t vmg_nr_of_title_sets; /* Number of VTSs. */
char provider_identifier[32];
uint64_t vmg_pos_code;
uint8_t zero_4[24];
uint32_t vmgi_last_byte;
uint32_t first_play_pgc;
uint8_t zero_5[56];
uint32_t vmgm_vobs; /* sector */
uint32_t tt_srpt; /* sector */
uint32_t vmgm_pgci_ut; /* sector */
uint32_t ptl_mait; /* sector */
uint32_t vts_atrt; /* sector */
uint32_t txtdt_mgi; /* sector */
uint32_t vmgm_c_adt; /* sector */
uint32_t vmgm_vobu_admap; /* sector */
uint8_t zero_6[32];
video_attr_t vmgm_video_attr;
uint8_t zero_7;
uint8_t nr_of_vmgm_audio_streams; /* should be 0 or 1 */
audio_attr_t vmgm_audio_attr;
audio_attr_t zero_8[7];
uint8_t zero_9[17];
uint8_t nr_of_vmgm_subp_streams; /* should be 0 or 1 */
subp_attr_t vmgm_subp_attr;
subp_attr_t zero_10[27]; /* XXX: how much 'padding' here? */
} vmgi_mat_t;
typedef struct {
unsigned int zero_1 : 1;
unsigned int multi_or_random_pgc_title : 1; /* 0: one sequential pgc title */
unsigned int jlc_exists_in_cell_cmd : 1;
unsigned int jlc_exists_in_prepost_cmd : 1;
unsigned int jlc_exists_in_button_cmd : 1;
unsigned int jlc_exists_in_tt_dom : 1;
unsigned int chapter_search_or_play : 1; /* UOP 1 */
unsigned int title_or_time_play : 1; /* UOP 0 */
} playback_type_t;
/**
* Title Information.
*/
typedef struct {
playback_type_t pb_ty;
uint8_t nr_of_angles;
uint16_t nr_of_ptts;
uint16_t parental_id;
uint8_t title_set_nr;
uint8_t vts_ttn;
uint32_t title_set_sector;
} title_info_t;
/**
* PartOfTitle Search Pointer Table.
*/
typedef struct {
uint16_t nr_of_srpts;
uint16_t zero_1;
uint32_t last_byte;
title_info_t *title;
} tt_srpt_t;
#define TT_SRPT_SIZE 8U
/**
* Parental Management Information Unit Table.
* Level 1 (US: G), ..., 7 (US: NC-17), 8
*/
#define PTL_MAIT_NUM_LEVEL 8
typedef uint16_t pf_level_t[PTL_MAIT_NUM_LEVEL];
/**
* Parental Management Information Unit Table.
*/
typedef struct {
uint16_t country_code;
uint16_t zero_1;
uint16_t pf_ptl_mai_start_byte;
uint16_t zero_2;
pf_level_t *pf_ptl_mai; /* table of (nr_of_vtss + 1), video_ts is first */
} ptl_mait_country_t;
#define PTL_MAIT_COUNTRY_SIZE 8U
/**
* Parental Management Information Table.
*/
typedef struct {
uint16_t nr_of_countries;
uint16_t nr_of_vtss;
uint32_t last_byte;
ptl_mait_country_t *countries;
} ptl_mait_t;
#define PTL_MAIT_SIZE 8U
/**
* Video Title Set Attributes.
*/
typedef struct {
uint32_t last_byte;
uint32_t vts_cat;
video_attr_t vtsm_vobs_attr;
uint8_t zero_1;
uint8_t nr_of_vtsm_audio_streams; /* should be 0 or 1 */
audio_attr_t vtsm_audio_attr;
audio_attr_t zero_2[7];
uint8_t zero_3[16];
uint8_t zero_4;
uint8_t nr_of_vtsm_subp_streams; /* should be 0 or 1 */
subp_attr_t vtsm_subp_attr;
subp_attr_t zero_5[27];
uint8_t zero_6[2];
video_attr_t vtstt_vobs_video_attr;
uint8_t zero_7;
uint8_t nr_of_vtstt_audio_streams;
audio_attr_t vtstt_audio_attr[8];
uint8_t zero_8[16];
uint8_t zero_9;
uint8_t nr_of_vtstt_subp_streams;
subp_attr_t vtstt_subp_attr[32];
} vts_attributes_t;
#define VTS_ATTRIBUTES_SIZE 542U
#define VTS_ATTRIBUTES_MIN_SIZE 356U
/**
* Video Title Set Attribute Table.
*/
typedef struct {
uint16_t nr_of_vtss;
uint16_t zero_1;
uint32_t last_byte;
vts_attributes_t *vts;
uint32_t *vts_atrt_offsets; /* offsets table for each vts_attributes */
} vts_atrt_t;
#define VTS_ATRT_SIZE 8U
/**
* Text Data. (Incomplete)
*/
typedef struct {
uint32_t last_byte; /* offsets are relative here */
uint16_t offsets[100]; /* == nr_of_srpts + 1 (first is disc title) */
} txtdt_t;
/**
* Text Data Language Unit. (Incomplete)
*/
typedef struct {
uint16_t lang_code;
uint8_t zero_1;
uint8_t char_set; /* 0x00 reserved Unicode, 0x01 ISO 646, 0x10 JIS Roman & JIS Kanji, 0x11 ISO 8859-1, 0x12 Shift JIS Kanji */
uint32_t txtdt_start_byte; /* prt, rel start of vmg_txtdt_mgi */
txtdt_t *txtdt;
} txtdt_lu_t;
#define TXTDT_LU_SIZE 8U
/**
* Text Data Manager Information. (Incomplete)
*/
typedef struct {
char disc_name[12];
uint16_t zero_1;
uint16_t nr_of_language_units;
uint32_t last_byte;
txtdt_lu_t *lu;
} txtdt_mgi_t;
#define TXTDT_MGI_SIZE 20U
/**
* VTS
*
* Structures relating to the Video Title Set (VTS).
*/
/**
* Video Title Set Information Management Table.
*/
typedef struct {
char vts_identifier[12];
uint32_t vts_last_sector;
uint8_t zero_1[12];
uint32_t vtsi_last_sector;
uint8_t zero_2;
uint8_t specification_version;
uint32_t vts_category;
uint16_t zero_3;
uint16_t zero_4;
uint8_t zero_5;
uint8_t zero_6[19];
uint16_t zero_7;
uint8_t zero_8[32];
uint64_t zero_9;
uint8_t zero_10[24];
uint32_t vtsi_last_byte;
uint32_t zero_11;
uint8_t zero_12[56];
uint32_t vtsm_vobs; /* sector */
uint32_t vtstt_vobs; /* sector */
uint32_t vts_ptt_srpt; /* sector */
uint32_t vts_pgcit; /* sector */
uint32_t vtsm_pgci_ut; /* sector */
uint32_t vts_tmapt; /* sector */
uint32_t vtsm_c_adt; /* sector */
uint32_t vtsm_vobu_admap; /* sector */
uint32_t vts_c_adt; /* sector */
uint32_t vts_vobu_admap; /* sector */
uint8_t zero_13[24];
video_attr_t vtsm_video_attr;
uint8_t zero_14;
uint8_t nr_of_vtsm_audio_streams; /* should be 0 or 1 */
audio_attr_t vtsm_audio_attr;
audio_attr_t zero_15[7];
uint8_t zero_16[17];
uint8_t nr_of_vtsm_subp_streams; /* should be 0 or 1 */
subp_attr_t vtsm_subp_attr;
subp_attr_t zero_17[27];
uint8_t zero_18[2];
video_attr_t vts_video_attr;
uint8_t zero_19;
uint8_t nr_of_vts_audio_streams;
audio_attr_t vts_audio_attr[8];
uint8_t zero_20[17];
uint8_t nr_of_vts_subp_streams;
subp_attr_t vts_subp_attr[32];
uint16_t zero_21;
multichannel_ext_t vts_mu_audio_attr[8];
/* XXX: how much 'padding' here, if any? */
} vtsi_mat_t;
/**
* PartOfTitle Unit Information.
*/
typedef struct {
uint16_t pgcn;
uint16_t pgn;
} ptt_info_t;
/**
* PartOfTitle Information.
*/
typedef struct {
uint16_t nr_of_ptts;
ptt_info_t *ptt;
} ttu_t;
/**
* PartOfTitle Search Pointer Table.
*/
typedef struct {
uint16_t nr_of_srpts;
uint16_t zero_1;
uint32_t last_byte;
ttu_t *title;
uint32_t *ttu_offset; /* offset table for each ttu */
} vts_ptt_srpt_t;
#define VTS_PTT_SRPT_SIZE 8U
/**
* Time Map Entry.
*/
/* Should this be bit field at all or just the uint32_t? */
typedef uint32_t map_ent_t;
/**
* Time Map.
*/
typedef struct {
uint8_t tmu; /* Time unit, in seconds */
uint8_t zero_1;
uint16_t nr_of_entries;
map_ent_t *map_ent;
} vts_tmap_t;
#define VTS_TMAP_SIZE 4U
/**
* Time Map Table.
*/
typedef struct {
uint16_t nr_of_tmaps;
uint16_t zero_1;
uint32_t last_byte;
vts_tmap_t *tmap;
uint32_t *tmap_offset; /* offset table for each tmap */
} vts_tmapt_t;
#define VTS_TMAPT_SIZE 8U
/**
* The following structure defines an IFO file. The structure is divided into
* two parts, the VMGI, or Video Manager Information, which is read from the
* VIDEO_TS.[IFO,BUP] file, and the VTSI, or Video Title Set Information, which
* is read in from the VTS_XX_0.[IFO,BUP] files.
*/
typedef struct {
/* VMGI */
vmgi_mat_t *vmgi_mat;
tt_srpt_t *tt_srpt;
pgc_t *first_play_pgc;
ptl_mait_t *ptl_mait;
vts_atrt_t *vts_atrt;
txtdt_mgi_t *txtdt_mgi;
/* Common */
pgci_ut_t *pgci_ut;
c_adt_t *menu_c_adt;
vobu_admap_t *menu_vobu_admap;
/* VTSI */
vtsi_mat_t *vtsi_mat;
vts_ptt_srpt_t *vts_ptt_srpt;
pgcit_t *vts_pgcit;
vts_tmapt_t *vts_tmapt;
c_adt_t *vts_c_adt;
vobu_admap_t *vts_vobu_admap;
} ifo_handle_t;

38
nav_print.h Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2001, 2002 Billy Biggs <vektor@dumbterm.net>,
* Håkan Hjort <d95hjort@dtek.chalmers.se>
*
* This file is part of libdvdread.
*
* libdvdread 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.
*
* libdvdread 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 libdvdread; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/**
* Pretty printing of the NAV packets, PCI and DSI structs.
*/
/**
* Prints information contained in the PCI to stdout.
*
* @param pci Pointer to the PCI data structure to be printed.
*/
void navPrint_PCI(pci_t *);
/**
* Prints information contained in the DSI to stdout.
*
* @param dsi Pointer to the DSI data structure to be printed.
*/
void navPrint_DSI(dsi_t *);

40
nav_read.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2000, 2001, 2002 Håkan Hjort <d95hjort@dtek.chalmers.se>.
*
* This file is part of libdvdread.
*
* libdvdread 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.
*
* libdvdread 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 libdvdread; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/**
* Parsing of NAV data, PCI and DSI parts.
*/
/**
* Reads the PCI packet data pointed to into th pci struct.
*
* @param pci Pointer to the PCI data structure to be filled in.
* @param bufffer Pointer to the buffer of the on disc PCI data.
*/
void navRead_PCI(pci_t *, unsigned char *);
/**
* Reads the DSI packet data pointed to into dsi struct.
*
* @param dsi Pointer to the DSI data structure to be filled in.
* @param bufffer Pointer to the buffer of the on disc DSI data.
*/
void navRead_DSI(dsi_t *, unsigned char *);

235
nav_types.h Normal file
View File

@ -0,0 +1,235 @@
/*
* Copyright (C) 2000, 2001, 2002 Håkan Hjort <d95hjort@dtek.chalmers.se>
*
* The data structures in this file should represent the layout of the
* pci and dsi packets as they are stored in the stream. Information
* found by reading the source to VOBDUMP is the base for the structure
* and names of these data types.
*
* VOBDUMP: a program for examining DVD .VOB files.
* Copyright 1998, 1999 Eric Smith <eric@brouhaha.com>
*
* VOBDUMP is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. Note that I am not
* granting permission to redistribute or modify VOBDUMP under the terms
* of any later version of the General Public License.
*
* This program is distributed in the hope that it will be useful (or at
* least amusing), 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* The length including the substream id byte. */
#define PCI_BYTES 0x3d4
#define DSI_BYTES 0x3fa
#define PS2_PCI_SUBSTREAM_ID 0x00
#define PS2_DSI_SUBSTREAM_ID 0x01
/* Remove this */
#define DSI_START_BYTE 1031
/**
* PCI General Information
*/
typedef struct {
uint32_t nv_pck_lbn; /**< sector address of this nav pack */
uint16_t vobu_cat; /**< 'category' of vobu */
uint16_t zero1; /**< reserved */
user_ops_t vobu_uop_ctl; /**< UOP of vobu */
uint32_t vobu_s_ptm; /**< start presentation time of vobu */
uint32_t vobu_e_ptm; /**< end presentation time of vobu */
uint32_t vobu_se_e_ptm; /**< end ptm of sequence end in vobu */
dvd_time_t e_eltm; /**< Cell elapsed time */
char vobu_isrc[32];
} pci_gi_t;
/**
* Non Seamless Angle Information
*/
typedef struct {
uint32_t nsml_agl_dsta[9]; /**< address of destination vobu in AGL_C#n */
} nsml_agli_t;
/**
* Highlight General Information
*
* For btngrX_dsp_ty the bits have the following meaning:
* 000b: normal 4/3 only buttons
* XX1b: wide (16/9) buttons
* X1Xb: letterbox buttons
* 1XXb: pan&scan buttons
*/
typedef struct {
uint16_t hli_ss; /**< status, only low 2 bits 0: no buttons, 1: different 2: equal 3: eual except for button cmds */
uint32_t hli_s_ptm; /**< start ptm of hli */
uint32_t hli_e_ptm; /**< end ptm of hli */
uint32_t btn_se_e_ptm; /**< end ptm of button select */
unsigned int zero1 : 2; /**< reserved */
unsigned int btngr_ns : 2; /**< number of button groups 1, 2 or 3 with 36/18/12 buttons */
unsigned int zero2 : 1; /**< reserved */
unsigned int btngr1_dsp_ty : 3; /**< display type of subpic stream for button group 1 */
unsigned int zero3 : 1; /**< reserved */
unsigned int btngr2_dsp_ty : 3; /**< display type of subpic stream for button group 2 */
unsigned int zero4 : 1; /**< reserved */
unsigned int btngr3_dsp_ty : 3; /**< display type of subpic stream for button group 3 */
uint8_t btn_ofn; /**< button offset number range 0-255 */
uint8_t btn_ns; /**< number of valid buttons <= 36/18/12 (low 6 bits) */
uint8_t nsl_btn_ns; /**< number of buttons selectable by U_BTNNi (low 6 bits) nsl_btn_ns <= btn_ns */
uint8_t zero5; /**< reserved */
uint8_t fosl_btnn; /**< forcedly selected button (low 6 bits) */
uint8_t foac_btnn; /**< forcedly activated button (low 6 bits) */
} hl_gi_t;
/**
* Button Color Information Table
* Each entry beeing a 32bit word that contains the color indexs and alpha
* values to use. They are all represented by 4 bit number and stored
* like this [Ci3, Ci2, Ci1, Ci0, A3, A2, A1, A0]. The actual palette
* that the indexes reference is in the PGC.
* @TODO split the uint32_t into a struct
*/
typedef struct {
uint32_t btn_coli[3][2]; /**< [button color number-1][select:0/action:1] */
} btn_colit_t;
/**
* Button Information
*
* NOTE: I've had to change the structure from the disk layout to get
* the packing to work with Sun's Forte C compiler.
* The 4 and 7 bytes are 'rotated' was: ABC DEF GHIJ is: ABCG DEFH IJ
*/
typedef struct {
unsigned int btn_coln : 2; /**< button color number */
unsigned int x_start : 10; /**< x start offset within the overlay */
unsigned int zero1 : 2; /**< reserved */
unsigned int x_end : 10; /**< x end offset within the overlay */
unsigned int auto_action_mode : 2; /**< 0: no, 1: activated if selected */
unsigned int y_start : 10; /**< y start offset within the overlay */
unsigned int zero2 : 2; /**< reserved */
unsigned int y_end : 10; /**< y end offset within the overlay */
unsigned int zero3 : 2; /**< reserved */
unsigned int up : 6; /**< button index when pressing up */
unsigned int zero4 : 2; /**< reserved */
unsigned int down : 6; /**< button index when pressing down */
unsigned int zero5 : 2; /**< reserved */
unsigned int left : 6; /**< button index when pressing left */
unsigned int zero6 : 2; /**< reserved */
unsigned int right : 6; /**< button index when pressing right */
vm_cmd_t cmd;
} btni_t;
/**
* Highlight Information
*/
typedef struct {
hl_gi_t hl_gi;
btn_colit_t btn_colit;
btni_t btnit[36];
} hli_t;
/**
* PCI packet
*/
typedef struct {
pci_gi_t pci_gi;
nsml_agli_t nsml_agli;
hli_t hli;
uint8_t zero1[189];
} pci_t;
/**
* DSI General Information
*/
typedef struct {
uint32_t nv_pck_scr;
uint32_t nv_pck_lbn; /**< sector address of this nav pack */
uint32_t vobu_ea; /**< end address of this VOBU */
uint32_t vobu_1stref_ea; /**< end address of the 1st reference image */
uint32_t vobu_2ndref_ea; /**< end address of the 2nd reference image */
uint32_t vobu_3rdref_ea; /**< end address of the 3rd reference image */
uint16_t vobu_vob_idn; /**< VOB Id number that this VOBU is part of */
uint8_t zero1; /**< reserved */
uint8_t vobu_c_idn; /**< Cell Id number that this VOBU is part of */
dvd_time_t c_eltm; /**< Cell elapsed time */
} dsi_gi_t;
/**
* Seamless Playback Information
*/
typedef struct {
uint16_t category; /**< 'category' of seamless VOBU */
uint32_t ilvu_ea; /**< end address of interleaved Unit */
uint32_t ilvu_sa; /**< start address of next interleaved unit */
uint16_t size; /**< size of next interleaved unit */
uint32_t vob_v_s_s_ptm; /**< video start ptm in vob */
uint32_t vob_v_e_e_ptm; /**< video end ptm in vob */
struct {
uint32_t stp_ptm1;
uint32_t stp_ptm2;
uint32_t gap_len1;
uint32_t gap_len2;
} vob_a[8];
} sml_pbi_t;
/**
* Seamless Angle Information for one angle
*/
typedef struct {
uint32_t address; /**< offset to next ILVU, high bit is before/after */
uint16_t size; /**< byte size of the ILVU pointed to by address */
} sml_agl_data_t;
/**
* Seamless Angle Information
*/
typedef struct {
sml_agl_data_t data[9];
} sml_agli_t;
/**
* VOBU Search Information
*/
typedef struct {
uint32_t next_video; /**< Next vobu that contains video */
uint32_t fwda[19]; /**< Forwards, time */
uint32_t next_vobu;
uint32_t prev_vobu;
uint32_t bwda[19]; /**< Backwards, time */
uint32_t prev_video;
} vobu_sri_t;
#define SRI_END_OF_CELL 0x3fffffff
/**
* Synchronous Information
*/
typedef struct {
uint16_t a_synca[8]; /**< offset to first audio packet for this VOBU */
uint32_t sp_synca[32]; /**< offset to first subpicture packet */
} synci_t;
/**
* DSI packet
*/
typedef struct {
dsi_gi_t dsi_gi;
sml_pbi_t sml_pbi;
sml_agli_t sml_agli;
vobu_sri_t vobu_sri;
synci_t synci;
uint8_t zero1[471];
} dsi_t;

63
vob_demux.py Normal file
View File

@ -0,0 +1,63 @@
import sys
import os
import json
import subprocess as SP
def get_streams(path):
proc=SP.Popen([
"ffprobe",
"-probesize", str(0x7fffffff),
"-analyzeduration", str(0x7fffffff),
"-v","fatal",
"-i",path,
"-show_streams",
"-show_format",
"-print_format","json"
],stdout=SP.PIPE,stdin=SP.DEVNULL,bufsize=0)
data=json.load(proc.stdout)
ret=proc.wait()
if ret!=0:
return [],{}
return data['streams'],data['format']
types={
'mpeg2video': 'm2v',
'ac3': 'ac3',
'dvd_subtitle': 'sup',
}
def demux(path):
folder=os.path.dirname(path)
basename=os.path.splitext(os.path.basename(path))[0]
streams,fmt=get_streams(path)
cmd=[
"ffmpeg",
"-y",
"-strict","-2",
"-fflags","+genpts",
"-probesize", str(0x7fffffff),
"-analyzeduration", str(0x7fffffff),
"-i",path,
"-scodec","copy",
"-vcodec","copy",
"-acodec","copy",
]
need_ffmpeg=False
for stream in streams:
codec=stream['codec_name']
ext=types.get(codec,codec)
idx=stream['index']
hex_id=stream['id']
codec_name=stream['codec_long_name']
outfile=os.path.join(folder,f"{basename}_{idx}_{hex_id}")
if codec=="dvd_subtitle":
SP.check_call([
"mencoder",path,"-vobsuboutindex",str(idx),"-vobsubout", outfile,"-nosound","-ovc", "copy", "-o",os.devnull
])
continue
print(idx,hex_id,codec_name,codec)
cmd+=["-map",f"0:#{hex_id}",outfile+f".{ext}"]
need_ffmpeg=True
if need_ffmpeg:
SP.check_call(cmd)