diff --git a/dvd_reader.h b/dvd_reader.h new file mode 100644 index 0000000..9a99ed9 --- /dev/null +++ b/dvd_reader.h @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2001, 2002 Billy Biggs , + * Håkan Hjort , + * Björn Englund + * + * 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 ); diff --git a/dvd_ripper.py b/dvd_ripper.py new file mode 100644 index 0000000..a2454ff --- /dev/null +++ b/dvd_ripper.py @@ -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) \ No newline at end of file diff --git a/dvd_types.h b/dvd_types.h new file mode 100644 index 0000000..d53ded9 --- /dev/null +++ b/dvd_types.h @@ -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 diff --git a/dvdcss.h b/dvdcss.h new file mode 100644 index 0000000..1bdfa5f --- /dev/null +++ b/dvdcss.h @@ -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); \ No newline at end of file diff --git a/dvdnav.h b/dvdnav.h new file mode 100644 index 0000000..15a5edd --- /dev/null +++ b/dvdnav.h @@ -0,0 +1,718 @@ +/* + * Copyright (C) 2001 Rich Wareham + * + * 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 +// #include +// #include +// #include /* For vm_cmd_t */ +// #include + +// #include + +/********************************************************************* + * 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); diff --git a/dvdnav.py b/dvdnav.py new file mode 100644 index 0000000..fe8102c --- /dev/null +++ b/dvdnav.py @@ -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 " {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)) \ No newline at end of file diff --git a/dvdnav_events.h b/dvdnav_events.h new file mode 100644 index 0000000..ebf07c2 --- /dev/null +++ b/dvdnav_events.h @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2001 Rich Wareham + * + * 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 diff --git a/dvdread.py b/dvdread.py new file mode 100644 index 0000000..a34e922 --- /dev/null +++ b/dvdread.py @@ -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) \ No newline at end of file diff --git a/ff_d2v.py b/ff_d2v.py new file mode 100644 index 0000000..2262fb3 --- /dev/null +++ b/ff_d2v.py @@ -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") diff --git a/ifo_print.h b/ifo_print.h new file mode 100644 index 0000000..69a28bf --- /dev/null +++ b/ifo_print.h @@ -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); diff --git a/ifo_read.h b/ifo_read.h new file mode 100644 index 0000000..27fb306 --- /dev/null +++ b/ifo_read.h @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2000, 2001, 2002 Björn Englund , + * Håkan Hjort + * + * 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 *); + diff --git a/ifo_types.h b/ifo_types.h new file mode 100644 index 0000000..9a5834f --- /dev/null +++ b/ifo_types.h @@ -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; diff --git a/nav_print.h b/nav_print.h new file mode 100644 index 0000000..445d454 --- /dev/null +++ b/nav_print.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2001, 2002 Billy Biggs , + * Håkan Hjort + * + * 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 *); diff --git a/nav_read.h b/nav_read.h new file mode 100644 index 0000000..6a21917 --- /dev/null +++ b/nav_read.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2000, 2001, 2002 Håkan Hjort . + * + * 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 *); + diff --git a/nav_types.h b/nav_types.h new file mode 100644 index 0000000..12ab073 --- /dev/null +++ b/nav_types.h @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2000, 2001, 2002 Håkan Hjort + * + * 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 + * + * 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; diff --git a/vob_demux.py b/vob_demux.py new file mode 100644 index 0000000..eec2025 --- /dev/null +++ b/vob_demux.py @@ -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) \ No newline at end of file