# HG changeset patch # User nicodvb # Date 1212331885 0 # Node ID 1c897db44135f0ebfff0780407ff24d09a68484c # Parent 427b7da5cbdb2ad9f0b564d3ace01154e8722938 first removal of dvdnav-specific code diff -r 427b7da5cbdb -r 1c897db44135 FELLOWSHIP.map --- a/FELLOWSHIP.map Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -# The Lord of the Rings: Fellowship of the Ring (Widescreen Theatrical Release) -domain 8, title 1, program 1, start 0x0000, end 0x1f0a # Introduction - -# history of middle earth -#domain 2, title 1, program 1, start 0x9cba, end 0xcea4 # violence/war -#domain 2, title 1, program 1, start 0xf018, end 0x1272c # violence/war -domain 2, title 1, program 1, start 0x11ff3, end 0x1272c # gore -#domain 2, title 1, program 1, start 0x173f1, end 0x185d6 # violence/death - -# hobbiton -domain 2, title 1, program 2, start 0x30373, end 0x31946 # vices/smoking -domain 2, title 1, program 2, start 0x32942, end 0x34426 # vices/smoking -domain 2, title 1, program 2, start 0x34895, end 0x34ad1 # vices/smoking -domain 2, title 1, program 2, start 0x3965c, end 0x39d7c # vices/smoking - -# bag end -domain 2, title 1, program 3, start 0x40288, end 0x412de # vices/drinking/talk -domain 2, title 1, program 3, start 0x4cfbe, end 0x4f955 # vices/smoking - -# party -domain 2, title 1, program 4, start 0x53ee0, end 0x54396 # vices/drinking -domain 2, title 1, program 4, start 0x58851, end 0x5ae3d # imitative/theft -domain 2, title 1, program 4, start 0x5cd0a, end 0x5e216 # jump - -# gandalf departs -domain 2, title 1, program 6, start 0x7f05d, end 0x7f1b3 # jump -domain 2, title 1, program 6, start 0x7f51a, end 0x834a7 # vices/smoking - -# research -domain 2, title 1, program 7, start 0x8e6e8, end 0x8e9d7 # vices/smoking - -# hobbiton -domain 2, title 1, program 8, start 0x98f49, end 0x990ba # jump -domain 2, title 1, program 8, start 0xa0ad1, end 0xa17ac # jump -domain 2, title 1, program 8, start 0xa9e32, end 0xaaa70 # violence/torture -domain 2, title 1, program 8, start 0xabc6c, end 0xabd92 # violence - -# orthanc -domain 2, title 1, program 9, start 0xd50b7, end 0xd87f9 # violence -domain 2, title 1, program 9, start 0xd8e49, end 0xda611 # violence - -# farmer maggot -domain 2, title 1, program 10, start 0xde856, end 0xdeb07 # jump -domain 2, title 1, program 10, start 0xe4cfe, end 0xe50b3 # gore/excrement -domain 2, title 1, program 10, start 0xebba3, end 0xebf93 # gore/blood -domain 2, title 1, program 10, start 0xed222, end 0xeda7e # gore/insects - -# buckleberry ferry -domain 2, title 1, program 11, start 0xf6d77, end 0xf83f8 # jump - -# prancing pony in bree -domain 2, title 1, program 12, start 0x10945e, end 0x10a2f2 # vices/drinking/rolemodel -domain 2, title 1, program 12, start 0x10c103, end 0x10c417 # vices/smoking -domain 2, title 1, program 12, start 0x10c934, end 0x10cb44 # vices/smoking -# 10c934 -# 10c9b4 -# 10ca3c -# 10cad6 -# 10cb44 -# 10cbb4 -domain 2, title 1, program 12, start 0x10ddab, end 0x10e0f2 # vices/smoking -domain 2, title 1, program 12, start 0x10e1df, end 0x10e411 # vices/drinking - -# ring wraiths in bree -domain 2, title 1, program 13, start 0x117853, end 0x117f6e # violence -domain 2, title 1, program 13, start 0x117853, end 0x117f6e # gore/crushing -domain 2, title 1, program 13, start 0x11b2b3, end 0x11bffc # violence - -# weathertop -#domain 2, title 1, program 15, start 0x13b85b, end 0x141b38 # violence -domain 2, title 1, program 15, start 0x14093a, end 0x141063 # gore/stabbing -domain 2, title 1, program 15, start 0x142555, end 0x1466e9 # violence - -# isengard -domain 2, title 1, program 16, start 0x152a28, end 0x1549fb # violence -domain 2, title 1, program 16, start 0x152a28, end 0x1549fb # gore - -# the ford -domain 2, title 1, program 17, start 0x173dbe, end 0x1748a6 # violence - -# rivendell -domain 2, title 1, program 18, start 0x179793, end 0x17a667 # vices/smoking -domain 2, title 1, program 18, start 0x17c452, end 0x17eab6 # violence - -# rivendell -domain 2, title 1, program 20, start 0x19caaf, end 0x19db12 # violence - -# tomb of isildur -domain 2, title 1, program 21, start 0x1a69ae, end 0x1a6a3d # gore/blood - -# rivendell -domain 2, title 1, program 22, start 0x1b298b, end 0x1b2bae # kiss - -# rivendell -domain 2, title 1, program 24, start 0x1d8253, end 0x1d8f5d # horror/posession - -# on the road south -domain 2, title 1, program 25, start 0x1e2fc2, end 0x1e31b8 # vices/smoking - -# at the entrance to moria -domain 2, title 1, program 27, start 0x214bdd, end 0x214fcc # gore/skeletons -domain 2, title 1, program 27, start 0x2157d9, end 0x216731 # gore/skeletons -domain 2, title 1, program 27, start 0x217ba6, end 0x21cdb4 # violence - -# moria -#domain 2, title 1, program 28, start 0x22173d, end 0x221e58 # gore/skeletons -#domain 2, title 1, program 28, start 0x222e0b, end 0x223345 # gore/skeletons -domain 2, title 1, program 28, start 0x22173d, end 0x223345 # gore/skeletons -domain 2, title 1, program 28, start 0x2239e2, end 0x223e8c # gore/skeletons -domain 2, title 1, program 28, start 0x22589f, end 0x2259bf # vices/smoking - -# balin's tomb -domain 2, title 1, program 29, start 0x234abb, end 0x234dd0 # gore/skeletons -domain 2, title 1, program 29, start 0x2352ed, end 0x2361d7 # gore/skeletons -domain 2, title 1, program 29, start 0x23898b, end 0x23955c # gore/skeletons -domain 2, title 1, program 29, start 0x23b467, end 0x23db2b # gore/skeletons -#domain 2, title 1, program 29, start 0x247360, end 0x25e24b # violence -domain 2, title 1, program 29, start 0x2483b6, end 0x248b62 # gore/impalement -domain 2, title 1, program 29, start 0x24a606, end 0x24a9f3 # gore/headshot -domain 2, title 1, program 29, start 0x24acd8, end 0x24ae7e # gore/decapitation -domain 2, title 1, program 29, start 0x24d708, end 0x24d88f # gore/bashing -domain 2, title 1, program 29, start 0x25013a, end 0x250501 # gore/impalement -domain 2, title 1, program 29, start 0x2540a0, end 0x254507 # jump -domain 2, title 1, program 29, start 0x2560b3, end 0x256423 # gore/impalement -domain 2, title 1, program 29, start 0x258152, end 0x258459 # gore/impalement -domain 2, title 1, program 29, start 0x258152, end 0x258459 # gore/impalement - -# the bridge -#domain 2, title 1, program 30, start 0x274235, end 0x275e59 # violence -domain 2, title 1, program 30, start 0x2744c6, end 0x274a5e # gore/headshot -domain 2, title 1, program 30, start 0x275661, end 0x275e59 # violence/death -domain 2, title 1, program 30, start 0x289d2a, end 0x28a066 # gore/falling - -# lothlorien -domain 2, title 1, program 32, start 0x2be304, end 0x2beb1d # violence -domain 2, title 1, program 32, start 0x2c5d59, end 0x2c9a40 # horror/posession -#domain 2, title 1, program 32, start 0x2c5d59, end 0x2c9e41 # horror/posession - -# parth galen -domain 2, title 1, program 36, start 0x2fa317, end 0x2fb0b0 # violence - -# parth galen w/ orcs -domain 2, title 1, program 37, start 0x30c8cb, end 0x313054 # violence -domain 2, title 1, program 37, start 0x310428, end 0x313054 # gore/impalement -#domain 2, title 1, program 37, start 0x317f45, end 0x332a52 # violence -domain 2, title 1, program 37, start 0x322d8b, end 0x328f4d # gore/impalement -domain 2, title 1, program 37, start 0x32f2a4, end 0x330731 # gore/impalement -domain 2, title 1, program 37, start 0x330b3b, end 0x330c4d # gore/blood -domain 2, title 1, program 37, start 0x331c4e, end 0x332a52 # gore/dismemberment -domain 2, title 1, program 37, start 0x331c4e, end 0x332a52 # gore/decapitation - -# death of boromir -domain 2, title 1, program 38, start 0x33322f, end 0x33c10c # gore/bodies -domain 2, title 1, program 38, start 0x33b558, end 0x33c10c # horror/death - -# to the eastern shore -domain 2, title 1, program 39, start 0x34a25b, end 0x34c1e3 # horror/drowning - - - - - - diff -r 427b7da5cbdb -r 1c897db44135 README.MAP --- a/README.MAP Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -Contents - -WHAT ARE MAP FILES -HOWTO -FINDING MAP FILES -WHOM TO BLAME - -WHAT ARE MAP FILES -================== - -Map files are an experimental feature that lets you customize the way -you watch DVDs. If you are opposed to violence, are sickened by gore, -or would rather your two year old didn't ask you just yet why that -woman in the movie was naked, you might want to create a map file. - -Map files identify sections of the movie that will be skipped during -playback. You can skip any section you like with the only restriction -(right now) that the movie player must play at least the last VOBU -(about a fifth of a second) of each chapter in the movie in order -to detect chapter changes correctly. - -Included with this patch is an example map file that describes most -of the potentially objectionable content in the new "The Lord of the -Rings" DVD. I've added a comment after each block that identifies -what content it contains so that you can customize the file to your -preferences. The map file looks something like this: - - # The Lord of the Rings: Fellowship of the Ring - # (Widescreen Theatrical Release) - debug - domain 8, title 1, program 1, start 0x0000, end 0x1f0a # Introduction - - # history of middle earth - #domain 2, title 1, program 1, start 0x9cba, end 0xcea4 # violence/war - #domain 2, title 1, program 1, start 0xf018, end 0x1272c # violence/war - domain 2, title 1, program 1, start 0x11ff3, end 0x1272c # gore - #domain 2, title 1, program 1, start 0x173f1, end 0x185d6 # violence/death - -Place the map file in your .xine directory to enable the selected -cuts as follows: - - cp FELLOWSHIP.map ~/.xine - -The debug command tells the map code that you would like to see the -VOBU numbers as the movie is playing. Comment out this line to hide -this output. The remaining lines are all either comments or blocks. -Each block has a start and an end, and whenever Xine tries to load -a VOBU between the start and end, it will be redirected to the end -block instead. - - -HOWTO -===== - -To create your own map files you would create a new map file using the -title of the disk as the filename, and add the debug line to it. The -map file should be placed in your '.xine' directory and have a '.map' -extension added. For example "The Lord Of The Rings" map must be stored -in the file ~/.xine/FELLOWSHIP.map - -After you create the file with the DEBUG line you will see output that -looks like this in window where you started Xine: - - FELLOWSHIP: domain 8, title 1, program 1, start 2205, next 22a8 - FELLOWSHIP: domain 8, title 1, program 1, start 22a8, next 234b - FELLOWSHIP: domain 8, title 1, program 1, start 234b, next 23eb - FELLOWSHIP: domain 8, title 1, program 1, start 23eb, next 248a - -Each line represents one VOBU, and the start and end addresses match -the start and end addresses that you should place in the map file -if you want to skip that block. If you want to skip multiple blocks -you would just add one line with the start address of the first block -to skip, and the end address of the last block to skip. For example -to skip these four blocks you would add the following line to your -map file: - - domain 8, title 1, program 1, start 0x2205, end 0x248a # 4 blocks - -Xine uses a buffered input chain so that if you pause the viewer you -won't find the same VOBU being displayed on the terminal as is -currently on the screen. In my testing the correct VOBU to use if -you pause exactly on the section you want to cut will be about five -or six lines above the last one printed to the screen. Replay the -scene with the deletion to see if you caught the correct blocks. - - -WHERE TO FIND MAP FILES -======================= - -If you create a map file for a new movie, please send it to me. If -there is widespread interest I'll put up a site where map files can -be located and downloaded. - - -WHOM TO BLAME -============= - -If the patch doesn't work for you (and you want it to) you can contact -me at 'kevin_smathers@hp.com'. - -If the patch works for you and you don't want it to, remember that -not everyone in the world has the same needs. The freedom to censor -movies in our own homes is quite different from the government -interfering into libraries and other public forums to censor movies -for us. diff -r 427b7da5cbdb -r 1c897db44135 dvd_types.h --- a/dvd_types.h Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,278 +0,0 @@ -/* - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -/* - * Various useful structs and enums for DVDs. - */ - -#ifndef DVD_H_INCLUDED -#define DVD_H_INCLUDED - -/* - * 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; - - -/* - * 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 following types are currently unused */ - -#if 0 - -/* Domain */ -typedef enum { - DVD_DOMAIN_FirstPlay, /* First Play Domain */ - DVD_DOMAIN_VMG, /* Video Manager Domain */ - DVD_DOMAIN_VTSMenu, /* Video Title Set Menu Domain */ - DVD_DOMAIN_VTSTitle, /* Video Title Set Domain */ - DVD_DOMAIN_Stop /* Stop Domain */ -} DVDDomain_t; - -/* 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; - -/* The audio format */ -typedef enum { - DVD_AUDIO_FORMAT_AC3 = 0, - DVD_AUDIO_FORMAT_MPEG1 = 1, - DVD_AUDIO_FORMAT_MPEG1_DRC = 2, - DVD_AUDIO_FORMAT_MPEG2 = 3, - DVD_AUDIO_FORMAT_MPEG2_DRC = 4, - DVD_AUDIO_FORMAT_LPCM = 5, - DVD_AUDIO_FORMAT_DTS = 6, - DVD_AUDIO_FORMAT_SDDS = 7, - DVD_AUDIO_FORMAT_Other = 8 -} DVDAudioFormat_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 - -#endif /* DVD_H_INCLUDED */ diff -r 427b7da5cbdb -r 1c897db44135 dvdnav.c --- a/dvdnav.c Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1165 +0,0 @@ -/* - * Copyright (C) 2000 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* -#define LOG_DEBUG -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "dvd_types.h" -#include "dvd_reader.h" -#include "nav_types.h" -#include "ifo_types.h" /* For vm_cmd_t */ -#include "remap.h" -#include "vm/decoder.h" -#include "vm/vm.h" -#include "dvdnav.h" -#include "dvdnav_events.h" -#include "dvdnav_internal.h" -#include "read_cache.h" -#include "nav_read.h" -#include "remap.h" - -static dvdnav_status_t dvdnav_clear(dvdnav_t * this) { - /* clear everything except file, vm, mutex, readahead */ - - pthread_mutex_lock(&this->vm_lock); - if (this->file) DVDCloseFile(this->file); - this->file = NULL; - - memset(&this->pci,0,sizeof(this->pci)); - memset(&this->dsi,0,sizeof(this->dsi)); - this->last_cmd_nav_lbn = SRI_END_OF_CELL; - - /* Set initial values of flags */ - this->position_current.still = 0; - this->skip_still = 0; - this->sync_wait = 0; - this->sync_wait_skip = 0; - this->spu_clut_changed = 0; - this->started = 0; - this->cur_cell_time = 0; - - dvdnav_read_cache_clear(this->cache); - pthread_mutex_unlock(&this->vm_lock); - - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_open(dvdnav_t** dest, const char *path) { - dvdnav_t *this; - struct timeval time; - - /* Create a new structure */ - fprintf(MSG_OUT, "libdvdnav: Using dvdnav version %s from http://dvd.sf.net\n", VERSION); - - (*dest) = NULL; - this = (dvdnav_t*)malloc(sizeof(dvdnav_t)); - if(!this) - return DVDNAV_STATUS_ERR; - memset(this, 0, (sizeof(dvdnav_t) ) ); /* Make sure this structure is clean */ - - pthread_mutex_init(&this->vm_lock, NULL); - /* Initialise the error string */ - printerr(""); - - /* Initialise the VM */ - this->vm = vm_new_vm(); - if(!this->vm) { - printerr("Error initialising the DVD VM."); - pthread_mutex_destroy(&this->vm_lock); - free(this); - return DVDNAV_STATUS_ERR; - } - if(!vm_reset(this->vm, path)) { - printerr("Error starting the VM / opening the DVD device."); - pthread_mutex_destroy(&this->vm_lock); - vm_free_vm(this->vm); - free(this); - return DVDNAV_STATUS_ERR; - } - - /* Set the path. FIXME: Is a deep copy 'right' */ - strncpy(this->path, path, MAX_PATH_LEN - 1); - this->path[MAX_PATH_LEN - 1] = '\0'; - - /* Pre-open and close a file so that the CSS-keys are cached. */ - this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), 0, DVD_READ_MENU_VOBS); - - /* Start the read-ahead cache. */ - this->cache = dvdnav_read_cache_new(this); - - /* Seed the random numbers. So that the DVD VM Command rand() - * gives a different start value each time a DVD is played. */ - gettimeofday(&time, NULL); - srand(time.tv_usec); - - dvdnav_clear(this); - - (*dest) = this; - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_close(dvdnav_t *this) { - -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: close:called\n"); -#endif - - if (this->file) { - pthread_mutex_lock(&this->vm_lock); - DVDCloseFile(this->file); -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: close:file closing\n"); -#endif - this->file = NULL; - pthread_mutex_unlock(&this->vm_lock); - } - - /* Free the VM */ - if(this->vm) - vm_free_vm(this->vm); - - pthread_mutex_destroy(&this->vm_lock); - - /* We leave the final freeing of the entire structure to the cache, - * because we don't know, if there are still buffers out in the wild, - * that must return first. */ - if(this->cache) - dvdnav_read_cache_free(this->cache); - else - free(this); - - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_reset(dvdnav_t *this) { - dvdnav_status_t result; - -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: reset:called\n"); -#endif - - pthread_mutex_lock(&this->vm_lock); - -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: reseting vm\n"); -#endif - if(!vm_reset(this->vm, NULL)) { - printerr("Error restarting the VM."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: clearing dvdnav\n"); -#endif - result = dvdnav_clear(this); - - pthread_mutex_unlock(&this->vm_lock); - return result; -} - -dvdnav_status_t dvdnav_path(dvdnav_t *this, const char** path) { - (*path) = this->path; - - return DVDNAV_STATUS_OK; -} - -const char* dvdnav_err_to_string(dvdnav_t *this) { - - if(!this) - return "Hey! You gave me a NULL pointer you naughty person!"; - - return this->err_str; -} - -/* converts a dvd_time_t to PTS ticks */ -int64_t dvdnav_convert_time(dvd_time_t *time) { - int64_t result; - int64_t frames; - - result = (time->hour >> 4 ) * 10 * 60 * 60 * 90000; - result += (time->hour & 0x0f) * 60 * 60 * 90000; - result += (time->minute >> 4 ) * 10 * 60 * 90000; - result += (time->minute & 0x0f) * 60 * 90000; - result += (time->second >> 4 ) * 10 * 90000; - result += (time->second & 0x0f) * 90000; - - frames = ((time->frame_u & 0x30) >> 4) * 10; - frames += ((time->frame_u & 0x0f) ) ; - - if (time->frame_u & 0x80) - result += frames * 3000; - else - result += frames * 3600; - - return result; -} - -/* - * Returns 1 if block contains NAV packet, 0 otherwise. - * Processes said NAV packet if present. - * - * Most of the code in here is copied from xine's MPEG demuxer - * so any bugs which are found in that should be corrected here also. - */ -static int32_t dvdnav_decode_packet(dvdnav_t *this, uint8_t *p, dsi_t *nav_dsi, pci_t *nav_pci) { - int32_t bMpeg1 = 0; - uint32_t nHeaderLen; - uint32_t nPacketLen; - uint32_t nStreamID; - - if (p[3] == 0xBA) { /* program stream pack header */ - int32_t nStuffingBytes; - - bMpeg1 = (p[4] & 0x40) == 0; - - if (bMpeg1) { - p += 12; - } else { /* mpeg2 */ - nStuffingBytes = p[0xD] & 0x07; - p += 14 + nStuffingBytes; - } - } - - if (p[3] == 0xbb) { /* program stream system header */ - nHeaderLen = (p[4] << 8) | p[5]; - p += 6 + nHeaderLen; - } - - /* we should now have a PES packet here */ - if (p[0] || p[1] || (p[2] != 1)) { - fprintf(MSG_OUT, "libdvdnav: demux error! %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]); - return 0; - } - - nPacketLen = p[4] << 8 | p[5]; - nStreamID = p[3]; - - nHeaderLen = 6; - p += nHeaderLen; - - if (nStreamID == 0xbf) { /* Private stream 2 */ -#if 0 - int32_t i; - fprintf(MSG_OUT, "libdvdnav: nav packet=%u\n",p-p_start-6); - for(i=0;i<80;i++) - fprintf(MSG_OUT, "%02x ",p[i-6]); - fprintf(MSG_OUT, "\n"); -#endif - - if(p[0] == 0x00) { - navRead_PCI(nav_pci, p+1); - } - - p += nPacketLen; - - /* We should now have a DSI packet. */ - if(p[6] == 0x01) { - nPacketLen = p[4] << 8 | p[5]; - p += 6; - navRead_DSI(nav_dsi, p+1); - } - return 1; - } - return 0; -} - -/* DSI is used for most angle stuff. - * PCI is used for only non-seemless angle stuff - */ -static int32_t dvdnav_get_vobu(dvdnav_t *this, dsi_t *nav_dsi, pci_t *nav_pci, dvdnav_vobu_t *vobu) { - uint32_t next; - int32_t angle, num_angle; - - vobu->vobu_start = nav_dsi->dsi_gi.nv_pck_lbn; /* Absolute offset from start of disk */ - vobu->vobu_length = nav_dsi->dsi_gi.vobu_ea; /* Relative offset from vobu_start */ - - /* - * If we're not at the end of this cell, we can determine the next - * VOBU to display using the VOBU_SRI information section of the - * DSI. Using this value correctly follows the current angle, - * avoiding the doubled scenes in The Matrix, and makes our life - * really happy. - * - * vobu_next is an offset value, 0x3fffffff = SRI_END_OF_CELL - * DVDs are about 6 Gigs, which is only up to 0x300000 blocks - * Should really assert if bit 31 != 1 - */ - -#if 0 - /* Old code -- may still be useful one day */ - if(nav_dsi->vobu_sri.next_vobu != SRI_END_OF_CELL ) { - vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff ); - } else { - vobu->vobu_next = vobu->vobu_length; - } -#else - /* Relative offset from vobu_start */ - vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff ); -#endif - - vm_get_angle_info(this->vm, &angle, &num_angle); - - /* FIMXE: The angle reset doesn't work for some reason for the moment */ -#if 0 - if((num_angle < angle) && (angle != 1)) { - fprintf(MSG_OUT, "libdvdnav: angle ends!\n"); - - /* This is to switch back to angle one when we - * finish with angles. */ - dvdnav_angle_change(this, 1); - } -#endif - - if(num_angle != 0) { - - if((next = nav_pci->nsml_agli.nsml_agl_dsta[angle-1]) != 0) { - if((next & 0x3fffffff) != 0) { - if(next & 0x80000000) - vobu->vobu_next = - (int32_t)(next & 0x3fffffff); - else - vobu->vobu_next = + (int32_t)(next & 0x3fffffff); - } - } else if((next = nav_dsi->sml_agli.data[angle-1].address) != 0) { - vobu->vobu_length = nav_dsi->sml_pbi.ilvu_ea; - - if((next & 0x80000000) && (next != 0x7fffffff)) - vobu->vobu_next = - (int32_t)(next & 0x3fffffff); - else - vobu->vobu_next = + (int32_t)(next & 0x3fffffff); - } - } - - return 1; -} - -/* - * These are the main get_next_block function which actually get the media stream video and audio etc. - * - * There are two versions: The second one is using the zero-copy read ahead cache and therefore - * hands out pointers targetting directly into the cache. - * The first one uses a memcopy to fill this cache block into the application provided memory. - * The benefit of this first one is that no special memory management is needed. The application is - * the only one responsible of allocating and freeing the memory associated with the pointer. - * The drawback is the additional memcopy. - */ - -dvdnav_status_t dvdnav_get_next_block(dvdnav_t *this, uint8_t *buf, - int32_t *event, int32_t *len) { - unsigned char *block; - dvdnav_status_t status; - - block = buf; - status = dvdnav_get_next_cache_block(this, &block, event, len); - if (status == DVDNAV_STATUS_OK && block != buf) { - /* we received a block from the cache, copy it, so we can give it back */ - memcpy(buf, block, DVD_VIDEO_LB_LEN); - dvdnav_free_cache_block(this, block); - } - return status; -} - -int64_t dvdnav_get_current_time(dvdnav_t *this) { - int i; - int64_t tm=0; - dvd_state_t *state = &this->vm->state; - - for(i=0; icellN-1; i++) { - if(! - (state->pgc->cell_playback[i].block_type == BLOCK_TYPE_ANGLE_BLOCK && - state->pgc->cell_playback[i].block_mode != BLOCK_MODE_FIRST_CELL) - ) - tm += dvdnav_convert_time(&state->pgc->cell_playback[i].playback_time); - } - tm += this->cur_cell_time; - - return tm; -} - -dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *this, uint8_t **buf, - int32_t *event, int32_t *len) { - dvd_state_t *state; - int32_t result; - - pthread_mutex_lock(&this->vm_lock); - - if(!this->started) { - /* Start the VM */ - if (!vm_start(this->vm)) { - printerr("Encrypted or faulty DVD"); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - this->started = 1; - } - - state = &(this->vm->state); - (*event) = DVDNAV_NOP; - (*len) = 0; - - /* Check the STOP flag */ - if(this->vm->stopped) { - vm_stop(this->vm); - (*event) = DVDNAV_STOP; - this->started = 0; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - - vm_position_get(this->vm, &this->position_next); - -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: POS-NEXT "); - vm_position_print(this->vm, &this->position_next); - fprintf(MSG_OUT, "libdvdnav: POS-CUR "); - vm_position_print(this->vm, &this->position_current); -#endif - - /* did we hop? */ - if(this->position_current.hop_channel != this->position_next.hop_channel) { - (*event) = DVDNAV_HOP_CHANNEL; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: HOP_CHANNEL\n"); -#endif - if (this->position_next.hop_channel - this->position_current.hop_channel >= HOP_SEEK) { - int32_t num_angles = 0, current; - - /* we seeked -> check for multiple angles */ - vm_get_angle_info(this->vm, ¤t, &num_angles); - if (num_angles > 1) { - int32_t result, block; - /* we have to skip the first VOBU when seeking in a multiangle feature, - * because it might belong to the wrong angle */ - block = this->position_next.cell_start + this->position_next.block; - result = dvdnav_read_cache_block(this->cache, block, 1, buf); - if(result <= 0) { - printerr("Error reading NAV packet."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - /* Decode nav into pci and dsi. Then get next VOBU info. */ - if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) { - printerr("Expected NAV packet but none found."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - dvdnav_get_vobu(this, &this->dsi, &this->pci, &this->vobu); - /* skip to next, if there is a next */ - if (this->vobu.vobu_next != SRI_END_OF_CELL) { - this->vobu.vobu_start += this->vobu.vobu_next; - this->vobu.vobu_next = 0; - } - /* update VM state */ - this->vm->state.blockN = this->vobu.vobu_start - this->position_next.cell_start; - } - } - this->position_current.hop_channel = this->position_next.hop_channel; - /* update VOBU info */ - this->vobu.vobu_start = this->position_next.cell_start + this->position_next.block; - this->vobu.vobu_next = 0; - /* Make blockN == vobu_length to do expected_nav */ - this->vobu.vobu_length = 0; - this->vobu.blockN = 0; - this->sync_wait = 0; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - - /* Check the HIGHLIGHT flag */ - if(this->position_current.button != this->position_next.button) { - dvdnav_highlight_event_t *hevent = (dvdnav_highlight_event_t *)*buf; - - (*event) = DVDNAV_HIGHLIGHT; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: HIGHLIGHT\n"); -#endif - (*len) = sizeof(dvdnav_highlight_event_t); - hevent->display = 1; - hevent->buttonN = this->position_next.button; - this->position_current.button = this->position_next.button; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - - /* Check the WAIT flag */ - if(this->sync_wait) { - (*event) = DVDNAV_WAIT; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: WAIT\n"); -#endif - (*len) = 0; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - - /* Check to see if we need to change the currently opened VOB */ - if((this->position_current.vts != this->position_next.vts) || - (this->position_current.domain != this->position_next.domain)) { - dvd_read_domain_t domain; - int32_t vtsN; - dvdnav_vts_change_event_t *vts_event = (dvdnav_vts_change_event_t *)*buf; - - if(this->file) { - DVDCloseFile(this->file); - this->file = NULL; - } - - vts_event->old_vtsN = this->position_current.vts; - vts_event->old_domain = this->position_current.domain; - - /* Use the DOMAIN to find whether to open menu or title VOBs */ - switch(this->position_next.domain) { - case FP_DOMAIN: - case VMGM_DOMAIN: - domain = DVD_READ_MENU_VOBS; - vtsN = 0; - break; - case VTSM_DOMAIN: - domain = DVD_READ_MENU_VOBS; - vtsN = this->position_next.vts; - break; - case VTS_DOMAIN: - domain = DVD_READ_TITLE_VOBS; - vtsN = this->position_next.vts; - break; - default: - printerr("Unknown domain when changing VTS."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - - this->position_current.vts = this->position_next.vts; - this->position_current.domain = this->position_next.domain; - dvdnav_read_cache_clear(this->cache); - this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), vtsN, domain); - vts_event->new_vtsN = this->position_next.vts; - vts_event->new_domain = this->position_next.domain; - - /* If couldn't open the file for some reason, moan */ - if(this->file == NULL) { - printerrf("Error opening vtsN=%i, domain=%i.", vtsN, domain); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - - /* File opened successfully so return a VTS change event */ - (*event) = DVDNAV_VTS_CHANGE; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: VTS_CHANGE\n"); -#endif - (*len) = sizeof(dvdnav_vts_change_event_t); - - this->spu_clut_changed = 1; - this->position_current.cell = -1; /* Force an update */ - this->position_current.spu_channel = -1; /* Force an update */ - this->position_current.audio_channel = -1; /* Force an update */; - - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - - /* Check if the cell changed */ - if( (this->position_current.cell != this->position_next.cell) || - (this->position_current.cell_restart != this->position_next.cell_restart) || - (this->position_current.cell_start != this->position_next.cell_start) ) { - dvdnav_cell_change_event_t *cell_event = (dvdnav_cell_change_event_t *)*buf; - int32_t first_cell_nr, last_cell_nr, i; - dvd_state_t *state = &this->vm->state; - - this->cur_cell_time = 0; - (*event) = DVDNAV_CELL_CHANGE; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: CELL_CHANGE\n"); -#endif - (*len) = sizeof(dvdnav_cell_change_event_t); - - cell_event->cellN = state->cellN; - cell_event->pgN = state->pgN; - cell_event->cell_length = - dvdnav_convert_time(&state->pgc->cell_playback[state->cellN-1].playback_time); - - cell_event->pg_length = 0; - /* Find start cell of program. */ - first_cell_nr = state->pgc->program_map[state->pgN-1]; - /* Find end cell of program */ - if(state->pgN < state->pgc->nr_of_programs) - last_cell_nr = state->pgc->program_map[state->pgN] - 1; - else - last_cell_nr = state->pgc->nr_of_cells; - for (i = first_cell_nr; i <= last_cell_nr; i++) - cell_event->pg_length += - dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time); - cell_event->pgc_length = dvdnav_convert_time(&state->pgc->playback_time); - - cell_event->cell_start = 0; - for (i = 1; i < state->cellN; i++) - cell_event->cell_start += - dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time); - - cell_event->pg_start = 0; - for (i = 1; i < state->pgc->program_map[state->pgN-1]; i++) - cell_event->pg_start += - dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time); - - this->position_current.cell = this->position_next.cell; - this->position_current.cell_restart = this->position_next.cell_restart; - this->position_current.cell_start = this->position_next.cell_start; - this->position_current.block = this->position_next.block; - - /* vobu info is used for mid cell resumes */ - this->vobu.vobu_start = this->position_next.cell_start + this->position_next.block; - this->vobu.vobu_next = 0; - /* Make blockN == vobu_length to do expected_nav */ - this->vobu.vobu_length = 0; - this->vobu.blockN = 0; - - /* update the spu palette at least on PGC changes */ - this->spu_clut_changed = 1; - this->position_current.spu_channel = -1; /* Force an update */ - this->position_current.audio_channel = -1; /* Force an update */ - - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - - /* has the CLUT changed? */ - if(this->spu_clut_changed) { - (*event) = DVDNAV_SPU_CLUT_CHANGE; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: SPU_CLUT_CHANGE\n"); -#endif - (*len) = 16 * sizeof(uint32_t); - memcpy(*buf, &(state->pgc->palette), 16 * sizeof(uint32_t)); - this->spu_clut_changed = 0; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - - /* has the SPU channel changed? */ - if(this->position_current.spu_channel != this->position_next.spu_channel) { - dvdnav_spu_stream_change_event_t *stream_change = (dvdnav_spu_stream_change_event_t *)*buf; - - (*event) = DVDNAV_SPU_STREAM_CHANGE; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE\n"); -#endif - (*len) = sizeof(dvdnav_spu_stream_change_event_t); - stream_change->physical_wide = vm_get_subp_active_stream(this->vm, 0); - stream_change->physical_letterbox = vm_get_subp_active_stream(this->vm, 1); - stream_change->physical_pan_scan = vm_get_subp_active_stream(this->vm, 2); - this->position_current.spu_channel = this->position_next.spu_channel; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_wide=%d\n",stream_change->physical_wide); - fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_letterbox=%d\n",stream_change->physical_letterbox); - fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_pan_scan=%d\n",stream_change->physical_pan_scan); - fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE returning DVDNAV_STATUS_OK\n"); -#endif - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - - /* has the audio channel changed? */ - if(this->position_current.audio_channel != this->position_next.audio_channel) { - dvdnav_audio_stream_change_event_t *stream_change = (dvdnav_audio_stream_change_event_t *)*buf; - - (*event) = DVDNAV_AUDIO_STREAM_CHANGE; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE\n"); -#endif - (*len) = sizeof(dvdnav_audio_stream_change_event_t); - stream_change->physical = vm_get_audio_active_stream( this->vm ); - this->position_current.audio_channel = this->position_next.audio_channel; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE stream_id=%d returning DVDNAV_STATUS_OK\n",stream_change->physical); -#endif - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - - /* Check the STILLFRAME flag */ - if(this->position_current.still != 0) { - dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)*buf; - - (*event) = DVDNAV_STILL_FRAME; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: STILL_FRAME\n"); -#endif - (*len) = sizeof(dvdnav_still_event_t); - still_event->length = this->position_current.still; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - - /* Have we reached the end of a VOBU? */ - if (this->vobu.blockN >= this->vobu.vobu_length) { - - /* Have we reached the end of a cell? */ - if(this->vobu.vobu_next == SRI_END_OF_CELL) { - /* End of Cell from NAV DSI info */ -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: Still set to %x\n", this->position_next.still); -#endif - this->position_current.still = this->position_next.still; - - /* we are about to leave a cell, so a lot of state changes could occur; - * under certain conditions, the application should get in sync with us before this, - * otherwise it might show stills or menus too shortly */ - if ((this->position_current.still || this->pci.hli.hl_gi.hli_ss) && !this->sync_wait_skip) { - this->sync_wait = 1; - } else { - if( this->position_current.still == 0 || this->skip_still ) { - /* no active cell still -> get us to the next cell */ - vm_get_next_cell(this->vm); - this->position_current.still = 0; /* still gets activated at end of cell */ - this->skip_still = 0; - this->sync_wait_skip = 0; - } - } - /* handle related state changes in next iteration */ - (*event) = DVDNAV_NOP; - (*len) = 0; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - - /* Perform remapping jump if necessary (this is always a - * VOBU boundary). */ - if (this->vm->map) { - this->vobu.vobu_next = remap_block( this->vm->map, - this->vm->state.domain, this->vm->state.TTN_REG, - this->vm->state.pgN, - this->vobu.vobu_start, this->vobu.vobu_next); - } - - /* at the start of the next VOBU -> expecting NAV packet */ - result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.vobu_next, 1, buf); - - if(result <= 0) { - printerr("Error reading NAV packet."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - /* Decode nav into pci and dsi. Then get next VOBU info. */ - if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) { - printerr("Expected NAV packet but none found."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - /* We need to update the vm state->blockN with which VOBU we are in. - * This is so RSM resumes to the VOBU level and not just the CELL level. - */ - this->vm->state.blockN = this->vobu.vobu_start - this->position_current.cell_start; - - dvdnav_get_vobu(this, &this->dsi, &this->pci, &this->vobu); - this->vobu.blockN = 0; - /* Give the cache a hint about the size of next VOBU. - * This improves pre-caching, because the VOBU will almost certainly be read entirely. - */ - dvdnav_pre_cache_blocks(this->cache, this->vobu.vobu_start+1, this->vobu.vobu_length+1); - - /* release NAV menu filter, when we reach the same NAV packet again */ - if (this->last_cmd_nav_lbn == this->pci.pci_gi.nv_pck_lbn) - this->last_cmd_nav_lbn = SRI_END_OF_CELL; - - /* Successfully got a NAV packet */ - (*event) = DVDNAV_NAV_PACKET; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: NAV_PACKET\n"); -#endif - (*len) = 2048; - this->cur_cell_time = dvdnav_convert_time(&this->dsi.dsi_gi.c_eltm); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - - /* If we've got here, it must just be a normal block. */ - if(!this->file) { - printerr("Attempting to read without opening file."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - - this->vobu.blockN++; - result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.blockN, 1, buf); - if(result <= 0) { - printerr("Error reading from DVD."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - (*event) = DVDNAV_BLOCK_OK; - (*len) = 2048; - - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_get_title_string(dvdnav_t *this, const char **title_str) { - (*title_str) = this->vm->dvd_name; - return DVDNAV_STATUS_OK; -} - -uint8_t dvdnav_get_video_aspect(dvdnav_t *this) { - uint8_t retval; - - if(!this->started) { - printerr("Virtual DVD machine not started."); - return -1; - } - - pthread_mutex_lock(&this->vm_lock); - retval = (uint8_t)vm_get_video_aspect(this->vm); - pthread_mutex_unlock(&this->vm_lock); - - return retval; -} - -uint8_t dvdnav_get_video_scale_permission(dvdnav_t *this) { - uint8_t retval; - - if(!this->started) { - printerr("Virtual DVD machine not started."); - return -1; - } - - pthread_mutex_lock(&this->vm_lock); - retval = (uint8_t)vm_get_video_scale_permission(this->vm); - pthread_mutex_unlock(&this->vm_lock); - - return retval; -} - -uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *this, uint8_t stream) { - audio_attr_t attr; - - if(!this->started) { - printerr("Virtual DVD machine not started."); - return -1; - } - - pthread_mutex_lock(&this->vm_lock); - attr = vm_get_audio_attr(this->vm, stream); - pthread_mutex_unlock(&this->vm_lock); - - if(attr.lang_type != 1) - return 0xffff; - - return attr.lang_code; -} - -uint16_t dvdnav_audio_stream_format(dvdnav_t *this, uint8_t stream) { - audio_attr_t attr; - uint16_t format; - - if(!this->started) { - printerr("Virtual DVD machine not started."); - return -1; /* 0xffff */ - } - - pthread_mutex_lock(&this->vm_lock); - attr = vm_get_audio_attr(this->vm, stream); - pthread_mutex_unlock(&this->vm_lock); - - switch(attr.audio_format) { - case 0: - format = DVDNAV_FORMAT_AC3; - break; - case 2: /* MPEG-1 or MPEG-2 without extension bitstream. */ - case 3: /* MPEG-2 with extension bitstream. */ - format = DVDNAV_FORMAT_MPEGAUDIO; - break; - case 4: - format = DVDNAV_FORMAT_LPCM; - break; - case 6: - format = DVDNAV_FORMAT_DTS; - break; - case 7: - format = DVDNAV_FORMAT_SDDS; - break; - default: - format = 0xffff; - break; - } - - return format; -} - -uint16_t dvdnav_audio_stream_channels(dvdnav_t *this, uint8_t stream) { - audio_attr_t attr; - - if(!this->started) { - printerr("Virtual DVD machine not started."); - return -1; /* 0xffff */ - } - - pthread_mutex_lock(&this->vm_lock); - attr = vm_get_audio_attr(this->vm, stream); - pthread_mutex_unlock(&this->vm_lock); - - return attr.channels + 1; -} - -uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *this, uint8_t stream) { - subp_attr_t attr; - - if(!this->started) { - printerr("Virtual DVD machine not started."); - return -1; - } - - pthread_mutex_lock(&this->vm_lock); - attr = vm_get_subp_attr(this->vm, stream); - pthread_mutex_unlock(&this->vm_lock); - - if(attr.type != 1) - return 0xffff; - - return attr.lang_code; -} - -int8_t dvdnav_get_audio_logical_stream(dvdnav_t *this, uint8_t audio_num) { - int8_t retval; - - if(!this->started) { - printerr("Virtual DVD machine not started."); - return -1; - } - - pthread_mutex_lock(&this->vm_lock); - if (!this->vm->state.pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return -1; - } - retval = vm_get_audio_stream(this->vm, audio_num); - pthread_mutex_unlock(&this->vm_lock); - - return retval; -} - -dvdnav_status_t dvdnav_get_audio_attr(dvdnav_t *this, uint8_t audio_num, audio_attr_t *audio_attr) { - if(!this->started) { - printerr("Virtual DVD machine not started."); - return -1; - } - pthread_mutex_lock(&this->vm_lock); - if (!this->vm->state.pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return -1; - } - *audio_attr=vm_get_audio_attr(this->vm, audio_num); - pthread_mutex_unlock(&this->vm_lock); - - return DVDNAV_STATUS_OK; -} - -int8_t dvdnav_get_spu_logical_stream(dvdnav_t *this, uint8_t subp_num) { - int8_t retval; - - if(!this->started) { - printerr("Virtual DVD machine not started."); - return -1; - } - - pthread_mutex_lock(&this->vm_lock); - if (!this->vm->state.pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return -1; - } - retval = vm_get_subp_stream(this->vm, subp_num, 0); - pthread_mutex_unlock(&this->vm_lock); - - return retval; -} - -dvdnav_status_t dvdnav_get_spu_attr(dvdnav_t *this, uint8_t audio_num, subp_attr_t *subp_attr) { - if(!this->started) { - printerr("Virtual DVD machine not started."); - return -1; - } - pthread_mutex_lock(&this->vm_lock); - if (!this->vm->state.pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return -1; - } - *subp_attr=vm_get_subp_attr(this->vm, audio_num); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; -} - -int8_t dvdnav_get_active_audio_stream(dvdnav_t *this) { - int8_t retval; - - if(!this->started) { - printerr("Virtual DVD machine not started."); - return -1; - } - - pthread_mutex_lock(&this->vm_lock); - if (!this->vm->state.pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return -1; - } - retval = vm_get_audio_active_stream(this->vm); - pthread_mutex_unlock(&this->vm_lock); - - return retval; -} - -int8_t dvdnav_get_active_spu_stream(dvdnav_t *this) { - int8_t retval; - - if(!this->started) { - printerr("Virtual DVD machine not started."); - return -1; - } - - pthread_mutex_lock(&this->vm_lock); - if (!this->vm->state.pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return -1; - } - retval = vm_get_subp_active_stream(this->vm, 0); - pthread_mutex_unlock(&this->vm_lock); - - return retval; -} - -static int8_t dvdnav_is_domain(dvdnav_t *this, domain_t domain) { - int8_t retval; - - if(!this->started) { - printerr("Virtual DVD machine not started."); - return -1; - } - - pthread_mutex_lock(&this->vm_lock); - retval = (this->vm->state.domain == domain); - pthread_mutex_unlock(&this->vm_lock); - - return retval; -} - -/* First Play domain. (Menu) */ -int8_t dvdnav_is_domain_fp(dvdnav_t *this) { - return dvdnav_is_domain(this, FP_DOMAIN); -} -/* Video management Menu domain. (Menu) */ -int8_t dvdnav_is_domain_vmgm(dvdnav_t *this) { - return dvdnav_is_domain(this, VMGM_DOMAIN); -} -/* Video Title Menu domain (Menu) */ -int8_t dvdnav_is_domain_vtsm(dvdnav_t *this) { - return dvdnav_is_domain(this, VTSM_DOMAIN); -} -/* Video Title domain (playing movie). */ -int8_t dvdnav_is_domain_vts(dvdnav_t *this) { - return dvdnav_is_domain(this, VTS_DOMAIN); -} - -/* Generally delegate angle information handling to VM */ -dvdnav_status_t dvdnav_angle_change(dvdnav_t *this, int32_t angle) { - int32_t num, current; - - pthread_mutex_lock(&this->vm_lock); - vm_get_angle_info(this->vm, ¤t, &num); - /* Set angle SPRM if valid */ - if((angle > 0) && (angle <= num)) { - this->vm->state.AGL_REG = angle; - } else { - printerr("Passed an invalid angle number."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - pthread_mutex_unlock(&this->vm_lock); - - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_get_angle_info(dvdnav_t *this, int32_t *current_angle, - int32_t *number_of_angles) { - pthread_mutex_lock(&this->vm_lock); - vm_get_angle_info(this->vm, current_angle, number_of_angles); - pthread_mutex_unlock(&this->vm_lock); - - return DVDNAV_STATUS_OK; -} - -pci_t* dvdnav_get_current_nav_pci(dvdnav_t *this) { - if(!this) return 0; - return &this->pci; -} - -dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *this) { - if(!this) return 0; - return &this->dsi; -} - -uint32_t dvdnav_get_next_still_flag(dvdnav_t *this) { - if(!this) return -1; - return this->position_next.still; -} - -user_ops_t dvdnav_get_restrictions(dvdnav_t* this) { - /* - * user_ops_t is a structure of 32 bits. We want to compute - * the union of two of those bitfields so to make this quicker - * than performing 32 ORs, we will access them as 32bits words. - */ - union { - user_ops_t ops_struct; - uint32_t ops_int; - } ops; - - ops.ops_int = 0; - - if(!this->started) { - printerr("Virtual DVD machine not started."); - return ops.ops_struct; - } - - pthread_mutex_lock(&this->vm_lock); - ops.ops_int |= *(uint32_t*)&this->pci.pci_gi.vobu_uop_ctl; - - if(this->vm && this->vm->state.pgc) - ops.ops_int |= *(uint32_t*)&this->vm->state.pgc->prohibited_ops; - pthread_mutex_unlock(&this->vm_lock); - - return ops.ops_struct; -} diff -r 427b7da5cbdb -r 1c897db44135 dvdnav.h --- a/dvdnav.h Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,684 +0,0 @@ -/* - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -/* - * This is the main header file applications should include if they want - * to access dvdnav functionality. - */ - -#ifndef DVDNAV_H_INCLUDED -#define DVDNAV_H_INCLUDED - -#define MP_DVDNAV 1 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef DVDNAV_COMPILE -# include -# include -# include -# include /* For vm_cmd_t */ -# include -#endif - - - -/********************************************************************* - * 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; - -/* - * 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 - -#define DVDNAV_FORMAT_AC3 0 -#define DVDNAV_FORMAT_MPEGAUDIO 3 -#define DVDNAV_FORMAT_LPCM 4 -#define DVDNAV_FORMAT_DTS 5 -#define DVDNAV_FORMAT_SDDS 6 - -/********************************************************************* - * initialisation & housekeeping functions * - *********************************************************************/ - -/* - * 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 and pre-cache - * the CSS-keys. libdvdread is used to access the DVD, so any source - * supported by libdvdread can be given with "path". Currently, - * libdvdread can access: DVD drives, DVD image files, DVD file-by-file - * copies. - * - * The resulting dvdnav_t handle will be written to *dest. - */ -dvdnav_status_t dvdnav_open(dvdnav_t **dest, const char *path); - -/* - * 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); - - -/********************************************************************* - * 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 enginge 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. - * I 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); - -/* - * 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); - -/* - * 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 *this, 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 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, - uint64_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 unimplemented! - */ -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 higer-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 the such a packet from libdvdnav, for players with internal - * FIFOs, this will result in errors, 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 sigularly - * 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); - -/* - * 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 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 channelsn 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); - -#define HAVE_GET_AUDIO_ATTR -/* - * 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); - -#define HAVE_GET_SPU_ATTR -/* - * 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 existant 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); - - -#ifdef __cplusplus -} -#endif - -#endif /* DVDNAV_H_INCLUDED */ diff -r 427b7da5cbdb -r 1c897db44135 dvdnav_events.h --- a/dvdnav_events.h Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,239 +0,0 @@ -/* - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -/* - * This header defines events and event types - */ - -#ifndef DVDNAV_EVENTS_H_INCLUDED -#define DVDNAV_EVENTS_H_INCLUDED - -/* - * 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 */ - dvd_read_domain_t old_domain; /* the old domain */ - int new_vtsN; /* the new VTS number */ - dvd_read_domain_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 PTS ticks */ - int64_t pg_length; /* the length of the current program in PTS ticks */ - int64_t pgc_length; /* the length of the current program chain in PTS ticks */ - int64_t cell_start; /* the start time of the current cell relatively to the PGC in PTS ticks */ - int64_t pg_start; /* the start time of the current PG relatively to the PGC in PTS ticks */ -} 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 - - -#endif /* DVDNAV_EVENTS_H_INCLUDED */ diff -r 427b7da5cbdb -r 1c897db44135 dvdnav_internal.h --- a/dvdnav_internal.h Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2001-2004 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -#ifndef DVDNAV_INTERNAL_H_INCLUDED -#define DVDNAV_INTERNAL_H_INCLUDED - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef WIN32 - -/* pthread_mutex_* wrapper for win32 */ -#include -#include -typedef CRITICAL_SECTION pthread_mutex_t; -#define pthread_mutex_init(a, b) InitializeCriticalSection(a) -#define pthread_mutex_lock(a) EnterCriticalSection(a) -#define pthread_mutex_unlock(a) LeaveCriticalSection(a) -#define pthread_mutex_destroy(a) - -/* replacement gettimeofday implementation */ -#include -static inline int _private_gettimeofday( struct timeval *tv, void *tz ) -{ - struct timeb t; - ftime( &t ); - tv->tv_sec = t.time; - tv->tv_usec = t.millitm * 1000; - return 0; -} -#define gettimeofday(TV, TZ) _private_gettimeofday((TV), (TZ)) -#include /* read() */ -#define lseek64 _lseeki64 - -#else - -#include - -#endif /* WIN32 */ - -/* where should libdvdnav write its messages (stdout/stderr) */ -#define MSG_OUT stdout - -/* Maximum length of an error string */ -#define MAX_ERR_LEN 255 - -/* Use the POSIX PATH_MAX if available */ -#ifdef PATH_MAX -#define MAX_PATH_LEN PATH_MAX -#else -#define MAX_PATH_LEN 255 /* Arbitrary */ -#endif - -#ifndef DVD_VIDEO_LB_LEN -#define DVD_VIDEO_LB_LEN 2048 -#endif - -typedef struct read_cache_s read_cache_t; - -/* - * These are defined here because they are - * not in ifo_types.h, they maybe one day - */ - -#ifndef audio_status_t -typedef struct { -#ifdef WORDS_BIGENDIAN - unsigned int available : 1; - unsigned int zero1 : 4; - unsigned int stream_number : 3; - uint8_t zero2; -#else - uint8_t zero2; - unsigned int stream_number : 3; - unsigned int zero1 : 4; - unsigned int available : 1; -#endif -} ATTRIBUTE_PACKED audio_status_t; -#endif - -#ifndef spu_status_t -typedef struct { -#ifdef WORDS_BIGENDIAN - unsigned int available : 1; - unsigned int zero1 : 2; - unsigned int stream_number_4_3 : 5; - unsigned int zero2 : 3; - unsigned int stream_number_wide : 5; - unsigned int zero3 : 3; - unsigned int stream_number_letterbox : 5; - unsigned int zero4 : 3; - unsigned int stream_number_pan_scan : 5; -#else - unsigned int stream_number_pan_scan : 5; - unsigned int zero4 : 3; - unsigned int stream_number_letterbox : 5; - unsigned int zero3 : 3; - unsigned int stream_number_wide : 5; - unsigned int zero2 : 3; - unsigned int stream_number_4_3 : 5; - unsigned int zero1 : 2; - unsigned int available : 1; -#endif -} ATTRIBUTE_PACKED spu_status_t; -#endif - -typedef struct dvdnav_vobu_s { - int32_t vobu_start; /* Logical Absolute. MAX needed is 0x300000 */ - int32_t vobu_length; - int32_t blockN; /* Relative offset */ - int32_t vobu_next; /* Relative offset */ -} dvdnav_vobu_t; - -/** The main DVDNAV type **/ - -struct dvdnav_s { - /* General data */ - char path[MAX_PATH_LEN]; /* Path to DVD device/dir */ - dvd_file_t *file; /* Currently opened file */ - - /* Position data */ - vm_position_t position_next; - vm_position_t position_current; - dvdnav_vobu_t vobu; - - /* NAV data */ - pci_t pci; - dsi_t dsi; - uint32_t last_cmd_nav_lbn; /* detects when a command is issued on an already left NAV */ - - /* Flags */ - int skip_still; /* Set when skipping a still */ - int sync_wait; /* applications should wait till they are in sync with us */ - int sync_wait_skip; /* Set when skipping wait state */ - int spu_clut_changed; /* The SPU CLUT changed */ - int started; /* vm_start has been called? */ - int use_read_ahead; /* 1 - use read-ahead cache, 0 - don't */ - int pgc_based; /* positioning works PGC based instead of PG based */ - int cur_cell_time; /* time expired since the beginning of the current cell, read from the dsi */ - - /* VM */ - vm_t *vm; - pthread_mutex_t vm_lock; - - /* Read-ahead cache */ - read_cache_t *cache; - - /* Errors */ - char err_str[MAX_ERR_LEN]; -}; - -/** HELPER FUNCTIONS **/ - -/* converts a dvd_time_t to PTS ticks */ -int64_t dvdnav_convert_time(dvd_time_t *time); - -/** USEFUL MACROS **/ - -#ifdef __GNUC__ -#define printerrf(format, args...) \ - do { if (this) snprintf(this->err_str, MAX_ERR_LEN, format, ## args); } while (0) -#else -#ifdef _MSC_VER -#define printerrf(str) \ - do { if (this) snprintf(this->err_str, MAX_ERR_LEN, str); } while (0) -#else -#define printerrf(...) \ - do { if (this) snprintf(this->err_str, MAX_ERR_LEN, __VA_ARGS__); } while (0) -#endif /* WIN32 */ -#endif -#define printerr(str) \ - do { if (this) strncpy(this->err_str, str, MAX_ERR_LEN - 1); } while (0) - -#endif /* DVDNAV_INTERNAL_H_INCLUDED */ diff -r 427b7da5cbdb -r 1c897db44135 highlight.c --- a/highlight.c Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,497 +0,0 @@ -/* - * Copyright (C) 2000 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include "nav_types.h" -#include "dvd_types.h" -#include "remap.h" -#include "vm/decoder.h" -#include "vm/vm.h" -#include "vm/vmcmd.h" -#include "dvdnav_internal.h" -#include "dvdnav.h" - -/* -#define BUTTON_TESTING -*/ - -#ifdef BUTTON_TESTING - -#include "nav_print.h" - -static void print_time(dvd_time_t *dtime) { - const char *rate; - - assert((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa); - assert((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa); - assert((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa); - assert((dtime->frame_u&0xf) < 0xa); - - fprintf(MSG_OUT,"%02x:%02x:%02x.%02x", - dtime->hour, - dtime->minute, - dtime->second, - dtime->frame_u & 0x3f); - switch((dtime->frame_u & 0xc0) >> 6) { - case 1: - rate = "25.00"; - break; - case 3: - rate = "29.97"; - break; - default: - rate = "(please send a bug report)"; - break; - } - fprintf(MSG_OUT," @ %s fps", rate); -} - -static void nav_print_PCI_GI(pci_gi_t *pci_gi) { - int32_t i; - - fprintf(MSG_OUT,"libdvdnav: pci_gi:\n"); - fprintf(MSG_OUT,"libdvdnav: nv_pck_lbn 0x%08x\n", pci_gi->nv_pck_lbn); - fprintf(MSG_OUT,"libdvdnav: vobu_cat 0x%04x\n", pci_gi->vobu_cat); - fprintf(MSG_OUT,"libdvdnav: vobu_uop_ctl 0x%08x\n", *(uint32_t*)&pci_gi->vobu_uop_ctl); - fprintf(MSG_OUT,"libdvdnav: vobu_s_ptm 0x%08x\n", pci_gi->vobu_s_ptm); - fprintf(MSG_OUT,"libdvdnav: vobu_e_ptm 0x%08x\n", pci_gi->vobu_e_ptm); - fprintf(MSG_OUT,"libdvdnav: vobu_se_e_ptm 0x%08x\n", pci_gi->vobu_se_e_ptm); - fprintf(MSG_OUT,"libdvdnav: e_eltm "); - print_time(&pci_gi->e_eltm); - fprintf(MSG_OUT,"\n"); - - fprintf(MSG_OUT,"libdvdnav: vobu_isrc \""); - for(i = 0; i < 32; i++) { - char c = pci_gi->vobu_isrc[i]; - if((c >= ' ') && (c <= '~')) - fprintf(MSG_OUT,"%c", c); - else - fprintf(MSG_OUT,"."); - } - fprintf(MSG_OUT,"\"\n"); -} - -static void nav_print_NSML_AGLI(nsml_agli_t *nsml_agli) { - int32_t i, j = 0; - - for(i = 0; i < 9; i++) - j |= nsml_agli->nsml_agl_dsta[i]; - if(j == 0) - return; - - fprintf(MSG_OUT,"libdvdnav: nsml_agli:\n"); - for(i = 0; i < 9; i++) - if(nsml_agli->nsml_agl_dsta[i]) - fprintf(MSG_OUT,"libdvdnav: nsml_agl_c%d_dsta 0x%08x\n", i + 1, - nsml_agli->nsml_agl_dsta[i]); -} - -static void nav_print_HL_GI(hl_gi_t *hl_gi, int32_t *btngr_ns, int32_t *btn_ns) { - - if((hl_gi->hli_ss & 0x03) == 0) - return; - - fprintf(MSG_OUT,"libdvdnav: hl_gi:\n"); - fprintf(MSG_OUT,"libdvdnav: hli_ss 0x%01x\n", hl_gi->hli_ss & 0x03); - fprintf(MSG_OUT,"libdvdnav: hli_s_ptm 0x%08x\n", hl_gi->hli_s_ptm); - fprintf(MSG_OUT,"libdvdnav: hli_e_ptm 0x%08x\n", hl_gi->hli_e_ptm); - fprintf(MSG_OUT,"libdvdnav: btn_se_e_ptm 0x%08x\n", hl_gi->btn_se_e_ptm); - - *btngr_ns = hl_gi->btngr_ns; - fprintf(MSG_OUT,"libdvdnav: btngr_ns %d\n", hl_gi->btngr_ns); - fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 1, hl_gi->btngr1_dsp_ty); - fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 2, hl_gi->btngr2_dsp_ty); - fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 3, hl_gi->btngr3_dsp_ty); - - fprintf(MSG_OUT,"libdvdnav: btn_ofn %d\n", hl_gi->btn_ofn); - *btn_ns = hl_gi->btn_ns; - fprintf(MSG_OUT,"libdvdnav: btn_ns %d\n", hl_gi->btn_ns); - fprintf(MSG_OUT,"libdvdnav: nsl_btn_ns %d\n", hl_gi->nsl_btn_ns); - fprintf(MSG_OUT,"libdvdnav: fosl_btnn %d\n", hl_gi->fosl_btnn); - fprintf(MSG_OUT,"libdvdnav: foac_btnn %d\n", hl_gi->foac_btnn); -} - -static void nav_print_BTN_COLIT(btn_colit_t *btn_colit) { - int32_t i, j; - - j = 0; - for(i = 0; i < 6; i++) - j |= btn_colit->btn_coli[i/2][i&1]; - if(j == 0) - return; - - fprintf(MSG_OUT,"libdvdnav: btn_colit:\n"); - for(i = 0; i < 3; i++) - for(j = 0; j < 2; j++) - fprintf(MSG_OUT,"libdvdnav: btn_cqoli %d %s_coli: %08x\n", - i, (j == 0) ? "sl" : "ac", - btn_colit->btn_coli[i][j]); -} - -static void nav_print_BTNIT(btni_t *btni_table, int32_t btngr_ns, int32_t btn_ns) { - int32_t i, j, k; - - fprintf(MSG_OUT,"libdvdnav: btnit:\n"); - fprintf(MSG_OUT,"libdvdnav: btngr_ns: %i\n", btngr_ns); - fprintf(MSG_OUT,"libdvdnav: btn_ns: %i\n", btn_ns); - - if(btngr_ns == 0) - return; - - for(i = 0; i < btngr_ns; i++) { - for(j = 0; j < (36 / btngr_ns); j++) { - if(j < btn_ns) { - btni_t *btni = &btni_table[(36 / btngr_ns) * i + j]; - - fprintf(MSG_OUT,"libdvdnav: group %d btni %d: ", i+1, j+1); - fprintf(MSG_OUT,"btn_coln %d, auto_action_mode %d\n", - btni->btn_coln, btni->auto_action_mode); - fprintf(MSG_OUT,"libdvdnav: coords (%d, %d) .. (%d, %d)\n", - btni->x_start, btni->y_start, btni->x_end, btni->y_end); - - fprintf(MSG_OUT,"libdvdnav: up %d, ", btni->up); - fprintf(MSG_OUT,"down %d, ", btni->down); - fprintf(MSG_OUT,"left %d, ", btni->left); - fprintf(MSG_OUT,"right %d\n", btni->right); - for(k = 0; k < 8; k++) { - fprintf(MSG_OUT, "libdvdnav: %02x ", btni->cmd.bytes[k]); - } - fprintf(MSG_OUT, "| "); -#ifdef TRACE - vm_print_mnemonic(&btni->cmd); -#endif - fprintf(MSG_OUT, "\n"); - } - } - } -} - -static void nav_print_HLI(hli_t *hli) { - int32_t btngr_ns = 0, btn_ns = 0; - - fprintf(MSG_OUT,"libdvdnav: hli:\n"); - nav_print_HL_GI(&hli->hl_gi, & btngr_ns, & btn_ns); - nav_print_BTN_COLIT(&hli->btn_colit); - nav_print_BTNIT(hli->btnit, btngr_ns, btn_ns); -} - -void nav_print_PCI(pci_t *pci) { - fprintf(MSG_OUT,"libdvdnav: pci packet:\n"); - nav_print_PCI_GI(&pci->pci_gi); - nav_print_NSML_AGLI(&pci->nsml_agli); - nav_print_HLI(&pci->hli); -} - -#endif - - -/* Highlighting API calls */ - -dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *this, int32_t *button) { - /* Simply return the appropriate value based on the SPRM */ - if(((*button) = this->position_current.button) == -1) - (*button) = this->vm->state.HL_BTNN_REG >> 10; - - return DVDNAV_STATUS_OK; -} - -static btni_t *get_current_button(dvdnav_t *this, pci_t *pci) { - int32_t button = 0; - - if(!pci->hli.hl_gi.hli_ss) { - printerr("Not in a menu."); - return NULL; - } - if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) { - printerr("This NAV has already been left."); - return NULL; - } - - button = this->vm->state.HL_BTNN_REG >> 10; -#ifdef BUTTON_TESTING - nav_print_PCI(pci); -#endif - - return &(pci->hli.btnit[button-1]); -} - -static dvdnav_status_t button_auto_action(dvdnav_t *this, pci_t *pci) { - if (get_current_button(this, pci)->auto_action_mode) - return dvdnav_button_activate(this, pci); - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *this, pci_t *pci) { - btni_t *button_ptr; - - if(!(button_ptr = get_current_button(this, pci))) - return DVDNAV_STATUS_ERR; - - dvdnav_button_select(this, pci, button_ptr->up); - return button_auto_action(this, pci); -} - -dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *this, pci_t *pci) { - btni_t *button_ptr; - - if(!(button_ptr = get_current_button(this, pci))) - return DVDNAV_STATUS_ERR; - - dvdnav_button_select(this, pci, button_ptr->down); - return button_auto_action(this, pci); -} - -dvdnav_status_t dvdnav_right_button_select(dvdnav_t *this, pci_t *pci) { - btni_t *button_ptr; - - if(!(button_ptr = get_current_button(this, pci))) - return DVDNAV_STATUS_ERR; - - dvdnav_button_select(this, pci, button_ptr->right); - return button_auto_action(this, pci); -} - -dvdnav_status_t dvdnav_left_button_select(dvdnav_t *this, pci_t *pci) { - btni_t *button_ptr; - - if(!(button_ptr = get_current_button(this, pci))) - return DVDNAV_STATUS_ERR; - - dvdnav_button_select(this, pci, button_ptr->left); - return button_auto_action(this, pci); -} - -dvdnav_status_t dvdnav_get_highlight_area(pci_t *nav_pci , int32_t button, int32_t mode, - dvdnav_highlight_area_t *highlight) { - btni_t *button_ptr; - -#ifdef BUTTON_TESTING - fprintf(MSG_OUT, "libdvdnav: Button get_highlight_area %i\n", button); -#endif - - if(!nav_pci->hli.hl_gi.hli_ss) - return DVDNAV_STATUS_ERR; - if((button <= 0) || (button > nav_pci->hli.hl_gi.btn_ns)) - return DVDNAV_STATUS_ERR; - - - button_ptr = &nav_pci->hli.btnit[button-1]; - - highlight->sx = button_ptr->x_start; - highlight->sy = button_ptr->y_start; - highlight->ex = button_ptr->x_end; - highlight->ey = button_ptr->y_end; - if(button_ptr->btn_coln != 0) { - highlight->palette = nav_pci->hli.btn_colit.btn_coli[button_ptr->btn_coln-1][mode]; - } else { - highlight->palette = 0; - } - highlight->pts = nav_pci->hli.hl_gi.hli_s_ptm; - highlight->buttonN = button; -#ifdef BUTTON_TESTING - fprintf(MSG_OUT, "libdvdnav: highlight: Highlight area is (%u,%u)-(%u,%u), display = %i, button = %u\n", - button_ptr->x_start, button_ptr->y_start, - button_ptr->x_end, button_ptr->y_end, - 1, - button); -#endif - - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_button_activate(dvdnav_t *this, pci_t *pci) { - int32_t button; - btni_t *button_ptr = NULL; - - if(!pci->hli.hl_gi.hli_ss) { - printerr("Not in a menu."); - return DVDNAV_STATUS_ERR; - } - if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) { - printerr("This NAV has already been left."); - return DVDNAV_STATUS_ERR; - } - pthread_mutex_lock(&this->vm_lock); - - button = this->vm->state.HL_BTNN_REG >> 10; - - if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) { - /* Special code to handle still menus with no buttons. - * The navigation is expected to report to the application that a STILL is - * underway. In turn, the application is supposed to report to the user - * that the playback is paused. The user is then expected to undo the pause, - * ie: hit play. At that point, the navigation should release the still and - * go to the next Cell. - * Explanation by Mathieu Lacage - * Code added by jcdutton. - */ - if (this->position_current.still != 0) { - /* In still, but no buttons. */ - vm_get_next_cell(this->vm); - this->position_current.still = 0; - this->sync_wait = 0; - this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn; - pthread_mutex_unlock(&this->vm_lock); - /* clear error message */ - printerr(""); - return DVDNAV_STATUS_OK; - } - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - - button_ptr = get_current_button(this, pci); - /* Finally, make the VM execute the appropriate code and probably - * scedule a jump */ -#ifdef BUTTON_TESTING - fprintf(MSG_OUT, "libdvdnav: Evaluating Button Activation commands.\n"); -#endif - if(vm_exec_cmd(this->vm, &(button_ptr->cmd)) == 1) { - /* Command caused a jump */ - this->vm->hop_channel++; - this->position_current.still = 0; - this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn; - } - - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_button_activate_cmd(dvdnav_t *this, int32_t button, vm_cmd_t *cmd) -{ - pthread_mutex_lock(&this->vm_lock); - /* make the VM execute the appropriate code and probably - * schedule a jump */ -#ifdef BUTTON_TESTING - fprintf(MSG_OUT, "libdvdnav: dvdnav_button_activate_cmd: Evaluating Button Activation commands.\n"); -#endif - if(button > 0) { - this->vm->state.HL_BTNN_REG = (button << 10); - if(vm_exec_cmd(this->vm, cmd) == 1) { - /* Command caused a jump */ - this->vm->hop_channel++; - } - } - /* Always remove still, because some still menus have no buttons. */ - this->position_current.still = 0; - this->sync_wait = 0; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_button_select(dvdnav_t *this, pci_t *pci, int32_t button) { - if(!pci->hli.hl_gi.hli_ss) { - printerr("Not in a menu."); - return DVDNAV_STATUS_ERR; - } - if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) { - printerr("This NAV has already been left."); - return DVDNAV_STATUS_ERR; - } - -#ifdef BUTTON_TESTING - fprintf(MSG_OUT, "libdvdnav: Button select %i\n", button); -#endif - - if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) { - printerr("Button does not exist."); - return DVDNAV_STATUS_ERR; - } - - this->vm->state.HL_BTNN_REG = (button << 10); - this->position_current.button = -1; /* Force Highligh change */ - - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_button_select_and_activate(dvdnav_t *this, pci_t *pci, - int32_t button) { - /* A trivial function */ - if(dvdnav_button_select(this, pci, button) != DVDNAV_STATUS_ERR) - return dvdnav_button_activate(this, pci); - return DVDNAV_STATUS_ERR; -} - -dvdnav_status_t dvdnav_mouse_select(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) { - int32_t button, cur_button; - int32_t best,dist,d; - int32_t mx,my,dx,dy; - - if(!pci->hli.hl_gi.hli_ss) { - printerr("Not in a menu."); - return DVDNAV_STATUS_ERR; - } - if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) { - printerr("This NAV has already been left."); - return DVDNAV_STATUS_ERR; - } - - cur_button = this->vm->state.HL_BTNN_REG >> 10; - - best = 0; - dist = 0x08000000; /* >> than (720*720)+(567*567); */ - - /* Loop through all buttons */ - for(button = 1; button <= pci->hli.hl_gi.btn_ns; button++) { - btni_t *button_ptr = &(pci->hli.btnit[button-1]); - - if((x >= button_ptr->x_start) && (x <= button_ptr->x_end) && - (y >= button_ptr->y_start) && (y <= button_ptr->y_end)) { - mx = (button_ptr->x_start + button_ptr->x_end)/2; - my = (button_ptr->y_start + button_ptr->y_end)/2; - dx = mx - x; - dy = my - y; - d = (dx*dx) + (dy*dy); - /* If the mouse is within the button and the mouse is closer - * to the center of this button then it is the best choice. */ - if(d < dist) { - dist = d; - best = button; - } - } - } - /* As an efficiency measure, only re-select the button - * if it is different to the previously selected one. */ - if (best != 0 && best != cur_button) - dvdnav_button_select(this, pci, best); - - /* return DVDNAV_STATUS_OK only if we actually found a matching button */ - return best ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR; -} - -dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) { - /* A trivial function */ - if(dvdnav_mouse_select(this, pci, x,y) != DVDNAV_STATUS_ERR) - return dvdnav_button_activate(this, pci); - return DVDNAV_STATUS_ERR; -} diff -r 427b7da5cbdb -r 1c897db44135 navigation.c --- a/navigation.c Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2000 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include "dvd_types.h" -#include "nav_types.h" -#include "ifo_types.h" -#include "remap.h" -#include "vm/decoder.h" -#include "vm/vm.h" -#include "dvdnav.h" -#include "dvdnav_internal.h" - -/* Navigation API calls */ - -dvdnav_status_t dvdnav_still_skip(dvdnav_t *this) { - this->position_current.still = 0; - this->skip_still = 1; - this->sync_wait = 0; - this->sync_wait_skip = 1; - - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_wait_skip(dvdnav_t *this) { - this->sync_wait = 0; - this->sync_wait_skip = 1; - - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_get_number_of_titles(dvdnav_t *this, int32_t *titles) { - if (!this->vm->vmgi) { - printerr("Bad VM state."); - return DVDNAV_STATUS_ERR; - } - - (*titles) = vm_get_vmgi(this->vm)->tt_srpt->nr_of_srpts; - - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_get_number_of_parts(dvdnav_t *this, int32_t title, int32_t *parts) { - if (!this->vm->vmgi) { - printerr("Bad VM state."); - return DVDNAV_STATUS_ERR; - } - if ((title < 1) || (title > vm_get_vmgi(this->vm)->tt_srpt->nr_of_srpts) ) { - printerr("Passed a title number out of range."); - return DVDNAV_STATUS_ERR; - } - - (*parts) = vm_get_vmgi(this->vm)->tt_srpt->title[title-1].nr_of_ptts; - - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_current_title_info(dvdnav_t *this, int32_t *title, int32_t *part) { - int32_t retval; - - pthread_mutex_lock(&this->vm_lock); - if (!this->vm->vtsi || !this->vm->vmgi) { - printerr("Bad VM state."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - if (!this->started) { - printerr("Virtual DVD machine not started."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - if (!this->vm->state.pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - if ( (this->vm->state.domain == VTSM_DOMAIN) - || (this->vm->state.domain == VMGM_DOMAIN) ) { - /* Get current Menu ID: into *part. */ - if(! vm_get_current_menu(this->vm, part)) { - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - if (*part > -1) { - *title = 0; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - } - if (this->vm->state.domain == VTS_DOMAIN) { - retval = vm_get_current_title_part(this->vm, title, part); - pthread_mutex_unlock(&this->vm_lock); - return retval ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR; - } - printerr("Not in a title or menu."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; -} - -dvdnav_status_t dvdnav_title_play(dvdnav_t *this, int32_t title) { - return dvdnav_part_play(this, title, 1); -} - -dvdnav_status_t dvdnav_part_play(dvdnav_t *this, int32_t title, int32_t part) { - int32_t retval; - - pthread_mutex_lock(&this->vm_lock); - if (!this->vm->vmgi) { - printerr("Bad VM state."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - if (!this->started) { - /* don't report an error but be nice */ - vm_start(this->vm); - this->started = 1; - } - if (!this->vm->state.pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - if((title < 1) || (title > this->vm->vmgi->tt_srpt->nr_of_srpts)) { - printerr("Title out of range."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - if((part < 1) || (part > this->vm->vmgi->tt_srpt->title[title-1].nr_of_ptts)) { - printerr("Part out of range."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - - retval = vm_jump_title_part(this->vm, title, part); - if (retval) - this->vm->hop_channel++; - pthread_mutex_unlock(&this->vm_lock); - - return retval ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR; -} - -dvdnav_status_t dvdnav_part_play_auto_stop(dvdnav_t *this, int32_t title, - int32_t part, int32_t parts_to_play) { - /* FIXME: Implement auto-stop */ - if (dvdnav_part_play(this, title, part) == DVDNAV_STATUS_OK) - printerr("Not implemented yet."); - return DVDNAV_STATUS_ERR; -} - -dvdnav_status_t dvdnav_time_play(dvdnav_t *this, int32_t title, - uint64_t time) { - /* FIXME: Implement */ - printerr("Not implemented yet."); - return DVDNAV_STATUS_ERR; -} - -dvdnav_status_t dvdnav_stop(dvdnav_t *this) { - pthread_mutex_lock(&this->vm_lock); - this->vm->stopped = 1; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_go_up(dvdnav_t *this) { - /* A nice easy function... delegate to the VM */ - pthread_mutex_lock(&this->vm_lock); - vm_jump_up(this->vm); - pthread_mutex_unlock(&this->vm_lock); - - return DVDNAV_STATUS_OK; -} diff -r 427b7da5cbdb -r 1c897db44135 read_cache.c --- a/read_cache.c Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,356 +0,0 @@ -/* - * Copyright (C) 2000 Rich Wareham - * 2001-2004 the dvdnav project - * - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ -/* - * There was a multithreaded read ahead cache in here for some time, but - * it had only been used for a short time. If you want to have a look at it, - * search the CVS attic. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include "dvd_types.h" -#include "nav_types.h" -#include "ifo_types.h" -#include "remap.h" -#include "vm/decoder.h" -#include "vm/vm.h" -#include "dvdnav.h" -#include "dvdnav_internal.h" -#include "read_cache.h" - -#define READ_CACHE_CHUNKS 10 - -/* all cache chunks must be memory aligned to allow use of raw devices */ -#define ALIGNMENT 2048 - -#define READ_AHEAD_SIZE_MIN 4 -#define READ_AHEAD_SIZE_MAX 512 - -typedef struct read_cache_chunk_s { - uint8_t *cache_buffer; - uint8_t *cache_buffer_base; /* used in malloc and free for alignment */ - int32_t cache_start_sector; /* -1 means cache invalid */ - int32_t cache_read_count; /* this many sectors are already read */ - size_t cache_block_count; /* this many sectors will go in this chunk */ - size_t cache_malloc_size; - int cache_valid; - int usage_count; /* counts how many buffers where issued from this chunk */ -} read_cache_chunk_t; - -struct read_cache_s { - read_cache_chunk_t chunk[READ_CACHE_CHUNKS]; - int current; - int freeing; /* is set to one when we are about to dispose the cache */ - uint32_t read_ahead_size; - int read_ahead_incr; - int last_sector; - pthread_mutex_t lock; - - /* Bit of strange cross-linking going on here :) -- Gotta love C :) */ - dvdnav_t *dvd_self; -}; - -/* -#define READ_CACHE_TRACE 0 -*/ - -#ifdef __GNUC__ -# if READ_CACHE_TRACE -# define dprintf(fmt, args...) fprintf(MSG_OUT, "libdvdnav: %s: "fmt, __func__ , ## args) -# else -# define dprintf(fmt, args...) /* Nowt */ -# endif -#else -# if READ_CACHE_TRACE -# define dprintf(fmt, ...) fprintf(MSG_OUT, "libdvdnav: %s: "fmt, __func__ , __VA_ARGS__) -# else -#ifdef _MSC_VER -# define dprintf(fmt, str) /* Nowt */ -#else -# define dprintf(fmt, ...) /* Nowt */ -#endif /* _MSC_VER */ -# endif -#endif - - -read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self) { - read_cache_t *self; - int i; - - self = (read_cache_t *)malloc(sizeof(read_cache_t)); - - if(self) { - self->current = 0; - self->freeing = 0; - self->dvd_self = dvd_self; - self->last_sector = 0; - self->read_ahead_size = READ_AHEAD_SIZE_MIN; - self->read_ahead_incr = 0; - pthread_mutex_init(&self->lock, NULL); - dvdnav_read_cache_clear(self); - for (i = 0; i < READ_CACHE_CHUNKS; i++) { - self->chunk[i].cache_buffer = NULL; - self->chunk[i].usage_count = 0; - } - } - - return self; -} - -void dvdnav_read_cache_free(read_cache_t* self) { - dvdnav_t *tmp; - int i; - - pthread_mutex_lock(&self->lock); - self->freeing = 1; - for (i = 0; i < READ_CACHE_CHUNKS; i++) - if (self->chunk[i].cache_buffer && self->chunk[i].usage_count == 0) { - free(self->chunk[i].cache_buffer_base); - self->chunk[i].cache_buffer = NULL; - } - pthread_mutex_unlock(&self->lock); - - for (i = 0; i < READ_CACHE_CHUNKS; i++) - if (self->chunk[i].cache_buffer) return; - - /* all buffers returned, free everything */ - tmp = self->dvd_self; - pthread_mutex_destroy(&self->lock); - free(self); - free(tmp); -} - -/* This function MUST be called whenever self->file changes. */ -void dvdnav_read_cache_clear(read_cache_t *self) { - int i; - - if(!self) - return; - - pthread_mutex_lock(&self->lock); - for (i = 0; i < READ_CACHE_CHUNKS; i++) - self->chunk[i].cache_valid = 0; - pthread_mutex_unlock(&self->lock); -} - -/* This function is called just after reading the NAV packet. */ -void dvdnav_pre_cache_blocks(read_cache_t *self, int sector, size_t block_count) { - int i, use; - - if(!self) - return; - - if(!self->dvd_self->use_read_ahead) - return; - - pthread_mutex_lock(&self->lock); - - /* find a free cache chunk that best fits the required size */ - use = -1; - for (i = 0; i < READ_CACHE_CHUNKS; i++) - if (self->chunk[i].usage_count == 0 && self->chunk[i].cache_buffer && - self->chunk[i].cache_malloc_size >= block_count && - (use == -1 || self->chunk[use].cache_malloc_size > self->chunk[i].cache_malloc_size)) - use = i; - - if (use == -1) { - /* we haven't found a cache chunk, so we try to reallocate an existing one */ - for (i = 0; i < READ_CACHE_CHUNKS; i++) - if (self->chunk[i].usage_count == 0 && self->chunk[i].cache_buffer && - (use == -1 || self->chunk[use].cache_malloc_size < self->chunk[i].cache_malloc_size)) - use = i; - if (use >= 0) { - self->chunk[use].cache_buffer_base = realloc(self->chunk[use].cache_buffer_base, - block_count * DVD_VIDEO_LB_LEN + ALIGNMENT); - self->chunk[use].cache_buffer = - (uint8_t *)(((uintptr_t)self->chunk[use].cache_buffer_base & ~((uintptr_t)(ALIGNMENT - 1))) + ALIGNMENT); - dprintf("pre_cache DVD read realloc happened\n"); - self->chunk[use].cache_malloc_size = block_count; - } else { - /* we still haven't found a cache chunk, let's allocate a new one */ - for (i = 0; i < READ_CACHE_CHUNKS; i++) - if (!self->chunk[i].cache_buffer) { - use = i; - break; - } - if (use >= 0) { - /* We start with a sensible figure for the first malloc of 500 blocks. - * Some DVDs I have seen venture to 450 blocks. - * This is so that fewer realloc's happen if at all. - */ - self->chunk[i].cache_buffer_base = - malloc((block_count > 500 ? block_count : 500) * DVD_VIDEO_LB_LEN + ALIGNMENT); - self->chunk[i].cache_buffer = - (uint8_t *)(((uintptr_t)self->chunk[i].cache_buffer_base & ~((uintptr_t)(ALIGNMENT - 1))) + ALIGNMENT); - self->chunk[i].cache_malloc_size = block_count > 500 ? block_count : 500; - dprintf("pre_cache DVD read malloc %d blocks\n", - (block_count > 500 ? block_count : 500 )); - } - } - } - - if (use >= 0) { - self->chunk[use].cache_start_sector = sector; - self->chunk[use].cache_block_count = block_count; - self->chunk[use].cache_read_count = 0; - self->chunk[use].cache_valid = 1; - self->current = use; - } else { - dprintf("pre_caching was impossible, no cache chunk available\n"); - } - pthread_mutex_unlock(&self->lock); -} - -int dvdnav_read_cache_block(read_cache_t *self, int sector, size_t block_count, uint8_t **buf) { - int i, use; - int start; - int size; - int incr; - uint8_t *read_ahead_buf; - int32_t res; - - if(!self) - return 0; - - use = -1; - - if(self->dvd_self->use_read_ahead) { - /* first check, if sector is in current chunk */ - read_cache_chunk_t cur = self->chunk[self->current]; - if (cur.cache_valid && sector >= cur.cache_start_sector && - sector <= (cur.cache_start_sector + cur.cache_read_count) && - sector + block_count <= cur.cache_start_sector + cur.cache_block_count) - use = self->current; - else - for (i = 0; i < READ_CACHE_CHUNKS; i++) - if (self->chunk[i].cache_valid && - sector >= self->chunk[i].cache_start_sector && - sector <= (self->chunk[i].cache_start_sector + self->chunk[i].cache_read_count) && - sector + block_count <= self->chunk[i].cache_start_sector + self->chunk[i].cache_block_count) - use = i; - } - - if (use >= 0) { - read_cache_chunk_t *chunk; - - /* Increment read-ahead size if sector follows the last sector */ - if (sector == (self->last_sector + 1)) { - if (self->read_ahead_incr < READ_AHEAD_SIZE_MAX) - self->read_ahead_incr++; - } else { - self->read_ahead_size = READ_AHEAD_SIZE_MIN; - self->read_ahead_incr = 0; - } - self->last_sector = sector; - - /* The following resources need to be protected by a mutex : - * self->chunk[*].cache_buffer - * self->chunk[*].cache_malloc_size - * self->chunk[*].usage_count - */ - pthread_mutex_lock(&self->lock); - chunk = &self->chunk[use]; - read_ahead_buf = chunk->cache_buffer + chunk->cache_read_count * DVD_VIDEO_LB_LEN; - *buf = chunk->cache_buffer + (sector - chunk->cache_start_sector) * DVD_VIDEO_LB_LEN; - chunk->usage_count++; - pthread_mutex_unlock(&self->lock); - - dprintf("libdvdnav: sector=%d, start_sector=%d, last_sector=%d\n", sector, chunk->cache_start_sector, chunk->cache_start_sector + chunk->cache_block_count); - - /* read_ahead_size */ - incr = self->read_ahead_incr >> 1; - if ((self->read_ahead_size + incr) > READ_AHEAD_SIZE_MAX) { - self->read_ahead_size = READ_AHEAD_SIZE_MAX; - } else { - self->read_ahead_size += incr; - } - - /* real read size */ - start = chunk->cache_start_sector + chunk->cache_read_count; - if (chunk->cache_read_count + self->read_ahead_size > chunk->cache_block_count) { - size = chunk->cache_block_count - chunk->cache_read_count; - } else { - size = self->read_ahead_size; - /* ensure that the sector we want will be read */ - if (sector >= chunk->cache_start_sector + chunk->cache_read_count + size) - size = sector - chunk->cache_start_sector - chunk->cache_read_count; - } - dprintf("libdvdnav: read_ahead_size=%d, size=%d\n", self->read_ahead_size, size); - - if (size) - chunk->cache_read_count += DVDReadBlocks(self->dvd_self->file, - start, - size, - read_ahead_buf); - - res = DVD_VIDEO_LB_LEN * block_count; - - } else { - - if (self->dvd_self->use_read_ahead) - dprintf("cache miss on sector %d\n", sector); - - res = DVDReadBlocks(self->dvd_self->file, - sector, - block_count, - *buf) * DVD_VIDEO_LB_LEN; - } - - return res; - -} - -dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf) { - read_cache_t *cache; - int i; - - if (!self) - return DVDNAV_STATUS_ERR; - - cache = self->cache; - if (!cache) - return DVDNAV_STATUS_ERR; - - pthread_mutex_lock(&cache->lock); - for (i = 0; i < READ_CACHE_CHUNKS; i++) { - if (cache->chunk[i].cache_buffer && buf >= cache->chunk[i].cache_buffer && - buf < cache->chunk[i].cache_buffer + cache->chunk[i].cache_malloc_size * DVD_VIDEO_LB_LEN) { - cache->chunk[i].usage_count--; - } - } - pthread_mutex_unlock(&cache->lock); - - if (cache->freeing) - /* when we want to dispose the cache, try freeing it now */ - dvdnav_read_cache_free(cache); - - return DVDNAV_STATUS_OK; -} diff -r 427b7da5cbdb -r 1c897db44135 read_cache.h --- a/read_cache.h Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2000 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -#ifndef __DVDNAV_READ_CACHE_H -#define __DVDNAV_READ_CACHE_H - -/* Opaque cache type -- defined in dvdnav_internal.h */ -/* typedef struct read_cache_s read_cache_t; */ - -/* EXPERIMENTAL: Setting the following to 1 will use an experimental multi-threaded - * read-ahead cache. - */ -#define _MULTITHREAD_ 0 - -/* Constructor/destructors */ -read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self); -void dvdnav_read_cache_free(read_cache_t* self); - -/* This function MUST be called whenever self->file changes. */ -void dvdnav_read_cache_clear(read_cache_t *self); -/* This function is called just after reading the NAV packet. */ -void dvdnav_pre_cache_blocks(read_cache_t *self, int sector, size_t block_count); -/* This function will do the cache read. - * The buffer handed in must be malloced to take one dvd block. - * On a cache hit, a different buffer will be returned though. - * Those buffers must _never_ be freed. */ -int dvdnav_read_cache_block(read_cache_t *self, int sector, size_t block_count, uint8_t **buf); - -#endif /* __DVDNAV_READ_CACHE_H */ diff -r 427b7da5cbdb -r 1c897db44135 remap.c --- a/remap.c Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,265 +0,0 @@ -/* - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#ifndef _MSC_VER -#include -#include -#else -#ifndef MAXPATHLEN -#define MAXPATHLEN 255 -#endif -#endif /* _MSC_VER */ - -#include -#include -#include -#include -#include "dvd_types.h" -#include "nav_types.h" -#include "ifo_types.h" -#include "remap.h" -#include "vm/decoder.h" -#include "vm/vm.h" -#include "dvdnav.h" -#include "dvdnav_internal.h" - -struct block_s { - int domain; - int title; - int program; - unsigned long start_block; - unsigned long end_block; -}; - -struct remap_s { - char *title; - int maxblocks; - int nblocks; - int debug; - struct block_s *blocks; -}; - -static remap_t* remap_new( char *title) { - remap_t *map = malloc( sizeof(remap_t)); - map->title = strdup(title); - map->maxblocks = 0; - map->nblocks = 0; - map->blocks = NULL; - map->debug = 0; - return map; -} - -static int compare_block( block_t *a, block_t *b) { - /* returns -1 if a precedes b, 1 if a follows b, and 0 if a and b overlap */ - if (a->domain < b->domain) { - return -1; - } else if (a->domain > b->domain) { - return 1; - } - - if (a->title < b->title) { - return -1; - } else if (a->title > b->title) { - return 1; - } - - if (a->program < b->program) { - return -1; - } else if (a->program > b->program) { - return 1; - } - - if (a->end_block < b->start_block) { - return -1; - } else if (a->start_block > b->end_block) { - /* - * if a->start_block == b->end_block then the two regions - * aren't strictly overlapping, but they should be merged - * anyway since there are zero blocks between them - */ - return 1; - } - - return 0; -} - -static block_t *findblock( remap_t *map, block_t *key) { - int lb = 0; - int ub = map->nblocks - 1; - int mid; - int res; - - while (lb <= ub) { - mid = lb + (ub - lb)/2; - res = compare_block( key, &map->blocks[mid]); - if (res < 0) { - ub = mid-1; - } else if (res > 0) { - lb = mid+1; - } else { - return &map->blocks[mid]; - } - } - return NULL; -} - -static void mergeblock( block_t *b, block_t tmp) { - if (tmp.start_block < b->start_block) b->start_block = tmp.start_block; - if (tmp.end_block > b->end_block) b->end_block = tmp.end_block; -} - -static void remap_add_node( remap_t *map, block_t block) { - block_t *b; - int n; - b = findblock( map, &block); - if (b) { - /* overlaps an existing block */ - mergeblock( b, block); - } else { - /* new block */ - if (map->nblocks >= map->maxblocks) { - map->maxblocks += 20; - map->blocks = realloc( map->blocks, sizeof( block_t)*map->maxblocks); - } - n = map->nblocks++; - while (n > 0 && compare_block( &block, &map->blocks[ n-1]) < 0) { - map->blocks[ n] = map->blocks[ n-1]; - n--; - } - map->blocks[ n] = block; - } -} - -static int parseblock(char *buf, int *dom, int *tt, int *pg, - unsigned long *start, unsigned long *end) { - long tmp; - char *tok; - char *epos; - char *marker[]={"domain", "title", "program", "start", "end"}; - int st = 0; - tok = strtok( buf, " "); - while (st < 5) { - if (strcmp(tok, marker[st])) return -st-1000; - tok = strtok( NULL, " "); - if (!tok) return -st-2000; - tmp = strtol( tok, &epos, 0); - if (*epos != 0 && *epos != ',') return -st-3000; - switch (st) { - case 0: - *dom = (int)tmp; - break; - case 1: - *tt = (int)tmp; - break; - case 2: - *pg = (int)tmp; - break; - case 3: - *start = tmp; - break; - case 4: - *end = tmp; - break; - } - st++; - tok = strtok( NULL, " "); - } - return st; -} - -remap_t* remap_loadmap( char *title) { - char buf[160]; - char fname[MAXPATHLEN]; - char *home; - int res; - FILE *fp; - block_t tmp; - remap_t *map; - - /* Build the map filename */ - home = getenv("HOME"); assert(home); - snprintf(fname, sizeof(fname), "%s/.dvdnav/%s.map", home, title); - - /* Open the map file */ - fp = fopen( fname, "r"); - if (!fp) { - fprintf(MSG_OUT, "libdvdnav: Unable to find map file '%s'\n", fname); - return NULL; - } - - /* Load the map file */ - map = remap_new( title); - while (fgets( buf, sizeof(buf), fp) != NULL) { - if (buf[0] == '\n' || buf[0] == '#' || buf[0] == 0) continue; - if (strncasecmp( buf, "debug", 5) == 0) { - map->debug = 1; - } else { - res = parseblock( buf, - &tmp.domain, &tmp.title, &tmp.program, &tmp.start_block, &tmp.end_block); - if (res != 5) { - fprintf(MSG_OUT, "libdvdnav: Ignoring map line (%d): %s\n", res, buf); - continue; - } - remap_add_node( map, tmp); - } - } - fclose(fp); - - if (map->nblocks == 0 && map->debug == 0) { - free(map); - return NULL; - } - return map; -} - -unsigned long remap_block( - remap_t *map, int domain, int title, int program, - unsigned long cblock, unsigned long offset) -{ - block_t key; - block_t *b; - - if (map->debug) { - fprintf(MSG_OUT, "libdvdnav: %s: domain %d, title %d, program %d, start %lx, next %lx\n", - map->title, domain, title, program, cblock, cblock+offset); - } - - key.domain = domain; - key.title = title; - key.program = program; - key.start_block = key.end_block = cblock + offset; - b = findblock( map, &key); - - if (b) { - if (map->debug) { - fprintf(MSG_OUT, "libdvdnav: Redirected to %lx\n", b->end_block); - } - return b->end_block - cblock; - } - return offset; -} diff -r 427b7da5cbdb -r 1c897db44135 remap.h --- a/remap.h Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - */ - -#ifndef __REMAP__H -#define __REMAP__H -typedef struct block_s block_t; - -typedef struct remap_s remap_t; - -remap_t* remap_loadmap( char *title); - -unsigned long remap_block( - remap_t *map, int domain, int title, int program, - unsigned long cblock, unsigned long offset); - -#endif diff -r 427b7da5cbdb -r 1c897db44135 searching.c --- a/searching.c Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,626 +0,0 @@ -/* - * Copyright (C) 2000 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include "dvd_types.h" -#include "nav_types.h" -#include "ifo_types.h" -#include "remap.h" -#include "vm/decoder.h" -#include "vm/vm.h" -#include "dvdnav.h" -#include "dvdnav_internal.h" - -/* -#define LOG_DEBUG -*/ - -/* Searching API calls */ - -/* Scan the ADMAP for a particular block number. */ -/* Return placed in vobu. */ -/* Returns error status */ -/* FIXME: Maybe need to handle seeking outside current cell. */ -static dvdnav_status_t dvdnav_scan_admap(dvdnav_t *this, int32_t domain, uint32_t seekto_block, uint32_t *vobu) { - vobu_admap_t *admap = NULL; - -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: Seeking to target %u ...\n", seekto_block); -#endif - *vobu = -1; - - /* Search through the VOBU_ADMAP for the nearest VOBU - * to the target block */ - switch(domain) { - case FP_DOMAIN: - case VMGM_DOMAIN: - admap = this->vm->vmgi->menu_vobu_admap; - break; - case VTSM_DOMAIN: - admap = this->vm->vtsi->menu_vobu_admap; - break; - case VTS_DOMAIN: - admap = this->vm->vtsi->vts_vobu_admap; - break; - default: - fprintf(MSG_OUT, "libdvdnav: Error: Unknown domain for seeking.\n"); - } - if(admap) { - uint32_t address = 0; - uint32_t vobu_start, next_vobu; - int admap_entries = (admap->last_byte + 1 - VOBU_ADMAP_SIZE)/VOBU_ADMAP_SIZE; - - /* Search through ADMAP for best sector */ - vobu_start = SRI_END_OF_CELL; - /* FIXME: Implement a faster search algorithm */ - while(address < admap_entries) { - next_vobu = admap->vobu_start_sectors[address]; - - /* fprintf(MSG_OUT, "libdvdnav: Found block %u\n", next_vobu); */ - - if(vobu_start <= seekto_block && next_vobu > seekto_block) - break; - vobu_start = next_vobu; - address++; - } - *vobu = vobu_start; - return DVDNAV_STATUS_OK; - } - fprintf(MSG_OUT, "libdvdnav: admap not located\n"); - return DVDNAV_STATUS_ERR; -} - -/* FIXME: right now, this function does not use the time tables but interpolates - only the cell times */ -dvdnav_status_t dvdnav_time_search(dvdnav_t *this, - uint64_t time) { - - uint64_t target = time; - uint64_t length = 0; - uint32_t first_cell_nr, last_cell_nr, cell_nr; - int32_t found; - cell_playback_t *cell; - dvd_state_t *state; - - if(this->position_current.still != 0) { - printerr("Cannot seek in a still frame."); - return DVDNAV_STATUS_ERR; - } - - pthread_mutex_lock(&this->vm_lock); - state = &(this->vm->state); - if(!state->pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - - - this->cur_cell_time = 0; - if (this->pgc_based) { - first_cell_nr = 1; - last_cell_nr = state->pgc->nr_of_cells; - } else { - /* Find start cell of program. */ - first_cell_nr = state->pgc->program_map[state->pgN-1]; - /* Find end cell of program */ - if(state->pgN < state->pgc->nr_of_programs) - last_cell_nr = state->pgc->program_map[state->pgN] - 1; - else - last_cell_nr = state->pgc->nr_of_cells; - } - - found = 0; - for(cell_nr = first_cell_nr; (cell_nr <= last_cell_nr) && !found; cell_nr ++) { - cell = &(state->pgc->cell_playback[cell_nr-1]); - if(cell->block_type == BLOCK_TYPE_ANGLE_BLOCK && cell->block_mode != BLOCK_MODE_FIRST_CELL) - continue; - length = dvdnav_convert_time(&cell->playback_time); - if (target >= length) { - target -= length; - } else { - /* FIXME: there must be a better way than interpolation */ - target = target * (cell->last_sector - cell->first_sector + 1) / length; - target += cell->first_sector; - - found = 1; - break; - } - } - - if(found) { - uint32_t vobu; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: Seeking to cell %i from choice of %i to %i\n", - cell_nr, first_cell_nr, last_cell_nr); -#endif - if (dvdnav_scan_admap(this, state->domain, target, &vobu) == DVDNAV_STATUS_OK) { - uint32_t start = state->pgc->cell_playback[cell_nr-1].first_sector; - - if (vm_jump_cell_block(this->vm, cell_nr, vobu - start)) { -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u target=%x vobu=%x start=%x\n" , - state->cellN, state->blockN, target, vobu, start); -#endif - this->vm->hop_channel += HOP_SEEK; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - } - } - - fprintf(MSG_OUT, "libdvdnav: Error when seeking\n"); - printerr("Error when seeking."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; -} - -dvdnav_status_t dvdnav_sector_search(dvdnav_t *this, - uint64_t offset, int32_t origin) { - uint32_t target = 0; - uint32_t length = 0; - uint32_t first_cell_nr, last_cell_nr, cell_nr; - int32_t found; - cell_playback_t *cell; - dvd_state_t *state; - dvdnav_status_t result; - - if(this->position_current.still != 0) { - printerr("Cannot seek in a still frame."); - return DVDNAV_STATUS_ERR; - } - - result = dvdnav_get_position(this, &target, &length); - if(!result) { - return DVDNAV_STATUS_ERR; - } - - pthread_mutex_lock(&this->vm_lock); - state = &(this->vm->state); - if(!state->pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: seeking to offset=%lu pos=%u length=%u\n", offset, target, length); - fprintf(MSG_OUT, "libdvdnav: Before cellN=%u blockN=%u\n", state->cellN, state->blockN); -#endif - - switch(origin) { - case SEEK_SET: - if(offset >= length) { - printerr("Request to seek behind end."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - target = offset; - break; - case SEEK_CUR: - if(target + offset >= length) { - printerr("Request to seek behind end."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - target += offset; - break; - case SEEK_END: - if(length < offset) { - printerr("Request to seek before start."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - target = length - offset; - break; - default: - /* Error occured */ - printerr("Illegal seek mode."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - - this->cur_cell_time = 0; - if (this->pgc_based) { - first_cell_nr = 1; - last_cell_nr = state->pgc->nr_of_cells; - } else { - /* Find start cell of program. */ - first_cell_nr = state->pgc->program_map[state->pgN-1]; - /* Find end cell of program */ - if(state->pgN < state->pgc->nr_of_programs) - last_cell_nr = state->pgc->program_map[state->pgN] - 1; - else - last_cell_nr = state->pgc->nr_of_cells; - } - - found = 0; - for(cell_nr = first_cell_nr; (cell_nr <= last_cell_nr) && !found; cell_nr ++) { - cell = &(state->pgc->cell_playback[cell_nr-1]); - if(cell->block_type == BLOCK_TYPE_ANGLE_BLOCK && cell->block_mode != BLOCK_MODE_FIRST_CELL) - continue; - length = cell->last_sector - cell->first_sector + 1; - if (target >= length) { - target -= length; - } else { - /* convert the target sector from Cell-relative to absolute physical sector */ - target += cell->first_sector; - found = 1; - break; - } - } - - if(found) { - int32_t vobu; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: Seeking to cell %i from choice of %i to %i\n", - cell_nr, first_cell_nr, last_cell_nr); -#endif - if (dvdnav_scan_admap(this, state->domain, target, &vobu) == DVDNAV_STATUS_OK) { - int32_t start = state->pgc->cell_playback[cell_nr-1].first_sector; - - if (vm_jump_cell_block(this->vm, cell_nr, vobu - start)) { -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u target=%x vobu=%x start=%x\n" , - state->cellN, state->blockN, target, vobu, start); -#endif - this->vm->hop_channel += HOP_SEEK; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - } - } - - fprintf(MSG_OUT, "libdvdnav: Error when seeking\n"); - fprintf(MSG_OUT, "libdvdnav: FIXME: Implement seeking to location %u\n", target); - printerr("Error when seeking."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; -} - -dvdnav_status_t dvdnav_part_search(dvdnav_t *this, int32_t part) { - int32_t title, old_part; - - if (dvdnav_current_title_info(this, &title, &old_part) == DVDNAV_STATUS_OK) - return dvdnav_part_play(this, title, part); - return DVDNAV_STATUS_ERR; -} - -dvdnav_status_t dvdnav_prev_pg_search(dvdnav_t *this) { - pthread_mutex_lock(&this->vm_lock); - if(!this->vm->state.pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: previous chapter\n"); -#endif - if (!vm_jump_prev_pg(this->vm)) { - fprintf(MSG_OUT, "libdvdnav: previous chapter failed.\n"); - printerr("Skip to previous chapter failed."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - this->cur_cell_time = 0; - this->position_current.still = 0; - this->vm->hop_channel++; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: previous chapter done\n"); -#endif - pthread_mutex_unlock(&this->vm_lock); - - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_top_pg_search(dvdnav_t *this) { - pthread_mutex_lock(&this->vm_lock); - if(!this->vm->state.pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: top chapter\n"); -#endif - if (!vm_jump_top_pg(this->vm)) { - fprintf(MSG_OUT, "libdvdnav: top chapter failed.\n"); - printerr("Skip to top chapter failed."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - this->cur_cell_time = 0; - this->position_current.still = 0; - this->vm->hop_channel++; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: top chapter done\n"); -#endif - pthread_mutex_unlock(&this->vm_lock); - - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *this) { - vm_t *try_vm; - - pthread_mutex_lock(&this->vm_lock); - if(!this->vm->state.pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: next chapter\n"); -#endif - /* make a copy of current VM and try to navigate the copy to the next PG */ - try_vm = vm_new_copy(this->vm); - if (!vm_jump_next_pg(try_vm) || try_vm->stopped) { - vm_free_copy(try_vm); - /* next_pg failed, try to jump at least to the next cell */ - try_vm = vm_new_copy(this->vm); - vm_get_next_cell(try_vm); - if (try_vm->stopped) { - vm_free_copy(try_vm); - fprintf(MSG_OUT, "libdvdnav: next chapter failed.\n"); - printerr("Skip to next chapter failed."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - } - this->cur_cell_time = 0; - /* merge changes on success */ - vm_merge(this->vm, try_vm); - vm_free_copy(try_vm); - this->position_current.still = 0; - this->vm->hop_channel++; -#ifdef LOG_DEBUG - fprintf(MSG_OUT, "libdvdnav: next chapter done\n"); -#endif - pthread_mutex_unlock(&this->vm_lock); - - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_menu_call(dvdnav_t *this, DVDMenuID_t menu) { - vm_t *try_vm; - - pthread_mutex_lock(&this->vm_lock); - if(!this->vm->state.pgc) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - - this->cur_cell_time = 0; - /* make a copy of current VM and try to navigate the copy to the menu */ - try_vm = vm_new_copy(this->vm); - if ( (menu == DVD_MENU_Escape) && (this->vm->state.domain != VTS_DOMAIN)) { - /* Try resume */ - if (vm_jump_resume(try_vm) && !try_vm->stopped) { - /* merge changes on success */ - vm_merge(this->vm, try_vm); - vm_free_copy(try_vm); - this->position_current.still = 0; - this->vm->hop_channel++; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } - } - if (menu == DVD_MENU_Escape) menu = DVD_MENU_Root; - - if (vm_jump_menu(try_vm, menu) && !try_vm->stopped) { - /* merge changes on success */ - vm_merge(this->vm, try_vm); - vm_free_copy(try_vm); - this->position_current.still = 0; - this->vm->hop_channel++; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; - } else { - vm_free_copy(try_vm); - printerr("No such menu or menu not reachable."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } -} - -dvdnav_status_t dvdnav_get_position(dvdnav_t *this, uint32_t *pos, - uint32_t *len) { - uint32_t cur_sector; - int32_t cell_nr, first_cell_nr, last_cell_nr; - cell_playback_t *cell; - dvd_state_t *state; - - if(!this->started) { - printerr("Virtual DVD machine not started."); - return DVDNAV_STATUS_ERR; - } - - pthread_mutex_lock(&this->vm_lock); - state = &(this->vm->state); - if(!state->pgc || this->vm->stopped) { - printerr("No current PGC."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - if (this->position_current.hop_channel != this->vm->hop_channel || - this->position_current.domain != state->domain || - this->position_current.vts != state->vtsN || - this->position_current.cell_restart != state->cell_restart) { - printerr("New position not yet determined."); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_ERR; - } - - /* Get current sector */ - cur_sector = this->vobu.vobu_start + this->vobu.blockN; - - if (this->pgc_based) { - first_cell_nr = 1; - last_cell_nr = state->pgc->nr_of_cells; - } else { - /* Find start cell of program. */ - first_cell_nr = state->pgc->program_map[state->pgN-1]; - /* Find end cell of program */ - if(state->pgN < state->pgc->nr_of_programs) - last_cell_nr = state->pgc->program_map[state->pgN] - 1; - else - last_cell_nr = state->pgc->nr_of_cells; - } - - *pos = -1; - *len = 0; - for (cell_nr = first_cell_nr; cell_nr <= last_cell_nr; cell_nr++) { - cell = &(state->pgc->cell_playback[cell_nr-1]); - if (cell_nr == state->cellN) { - /* the current sector is in this cell, - * pos is length of PG up to here + sector's offset in this cell */ - *pos = *len + cur_sector - cell->first_sector; - } - *len += cell->last_sector - cell->first_sector + 1; - } - - assert((signed)*pos != -1); - - pthread_mutex_unlock(&this->vm_lock); - - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_get_position_in_title(dvdnav_t *this, - uint32_t *pos, - uint32_t *len) { - uint32_t cur_sector; - uint32_t first_cell_nr; - uint32_t last_cell_nr; - cell_playback_t *first_cell; - cell_playback_t *last_cell; - dvd_state_t *state; - - state = &(this->vm->state); - if(!state->pgc) { - printerr("No current PGC."); - return DVDNAV_STATUS_ERR; - } - - /* Get current sector */ - cur_sector = this->vobu.vobu_start + this->vobu.blockN; - - /* Now find first and last cells in title. */ - first_cell_nr = state->pgc->program_map[0]; - first_cell = &(state->pgc->cell_playback[first_cell_nr-1]); - last_cell_nr = state->pgc->nr_of_cells; - last_cell = &(state->pgc->cell_playback[last_cell_nr-1]); - - *pos = cur_sector - first_cell->first_sector; - *len = last_cell->last_sector - first_cell->first_sector; - - return DVDNAV_STATUS_OK; -} - -uint32_t dvdnav_describe_title_chapters(dvdnav_t *this, int32_t title, uint64_t **times, uint64_t *duration) { - int32_t retval=0; - uint16_t parts, i; - title_info_t *ptitle = NULL; - ptt_info_t *ptt = NULL; - ifo_handle_t *ifo; - pgc_t *pgc; - cell_playback_t *cell; - uint64_t length, *tmp=NULL; - - *times = NULL; - *duration = 0; - pthread_mutex_lock(&this->vm_lock); - if(!this->vm->vmgi) { - printerr("Bad VM state or missing VTSI."); - goto fail; - } - if(!this->started) { - /* don't report an error but be nice */ - vm_start(this->vm); - this->started = 1; - } - ifo = vm_get_title_ifo(this->vm, title); - if(!ifo || !ifo->vts_pgcit) { - printerr("Couldn't open IFO for chosen title, exit."); - goto fail; - } - - ptitle = &this->vm->vmgi->tt_srpt->title[title-1]; - parts = ptitle->nr_of_ptts; - ptt = ifo->vts_ptt_srpt->title[ptitle->vts_ttn-1].ptt; - - tmp = calloc(1, sizeof(uint64_t)*parts); - if(!tmp) - goto fail; - - length = 0; - for(i=0; ivts_pgcit->pgci_srp[ptt[i].pgcn-1].pgc; - if(ptt[i].pgn > pgc->nr_of_programs) { - printerr("WRONG part number."); - goto fail; - } - - cellnr = pgc->program_map[ptt[i].pgn-1]; - if(ptt[i].pgn < pgc->nr_of_programs) - endcellnr = pgc->program_map[ptt[i].pgn]; - else - endcellnr = 0; - - do { - cell = &pgc->cell_playback[cellnr-1]; - if(!(cell->block_type == BLOCK_TYPE_ANGLE_BLOCK && - cell->block_mode != BLOCK_MODE_FIRST_CELL - )) - { - tmp[i] = length + dvdnav_convert_time(&cell->playback_time); - length = tmp[i]; - } - cellnr++; - } while(cellnr < endcellnr); - } - *duration = length; - vm_ifo_close(ifo); - retval = parts; - *times = tmp; - -fail: - pthread_mutex_unlock(&this->vm_lock); - if(!retval && tmp) - free(tmp); - return retval; -} diff -r 427b7da5cbdb -r 1c897db44135 settings.c --- a/settings.c Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2000 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include "dvd_types.h" -#include "nav_types.h" -#include "ifo_types.h" -#include "remap.h" -#include "vm/decoder.h" -#include "vm/vm.h" -#include "dvdnav.h" -#include "dvdnav_internal.h" - -/* Characteristics/setting API calls */ - -dvdnav_status_t dvdnav_get_region_mask(dvdnav_t *this, int32_t *region) { - (*region) = this->vm->state.registers.SPRM[20]; - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_set_region_mask(dvdnav_t *this, int32_t mask) { - pthread_mutex_lock(&this->vm_lock); - this->vm->state.registers.SPRM[20] = (mask & 0xff); - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_set_readahead_flag(dvdnav_t *this, int32_t use_readahead) { - this->use_read_ahead = use_readahead; - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_get_readahead_flag(dvdnav_t *this, int32_t *flag) { - (*flag) = this->use_read_ahead; - return DVDNAV_STATUS_OK; -} - -static dvdnav_status_t set_language_register(dvdnav_t *this, char *code, int reg) { - if(!code[0] || !code[1]) { - printerr("Passed illegal language code."); - return DVDNAV_STATUS_ERR; - } - - pthread_mutex_lock(&this->vm_lock); - this->vm->state.registers.SPRM[reg] = (code[0] << 8) | code[1]; - pthread_mutex_unlock(&this->vm_lock); - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_menu_language_select(dvdnav_t *this, char *code) { - return set_language_register(this, code, 0); -} - -dvdnav_status_t dvdnav_audio_language_select(dvdnav_t *this, char *code) { - return set_language_register(this, code, 16); -} - -dvdnav_status_t dvdnav_spu_language_select(dvdnav_t *this, char *code) { - return set_language_register(this, code, 18); -} - -dvdnav_status_t dvdnav_set_PGC_positioning_flag(dvdnav_t *this, int32_t pgc) { - this->pgc_based = pgc; - return DVDNAV_STATUS_OK; -} - -dvdnav_status_t dvdnav_get_PGC_positioning_flag(dvdnav_t *this, int32_t *flag) { - (*flag) = this->pgc_based; - return DVDNAV_STATUS_OK; -} diff -r 427b7da5cbdb -r 1c897db44135 vm/Makefile.am --- a/vm/Makefile.am Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -include $(top_srcdir)/misc/Makefile.common - -includedir = ${prefix}/include/dvdnav - -AM_CPPFLAGS = -DDVDNAV_COMPILE $(THREAD_CFLAGS) \ - -I$(top_srcdir)/src -I$(top_srcdir)/src/libdvdread - -noinst_LTLIBRARIES = libdvdvm.la - -libdvdvm_la_SOURCES = decoder.c vm.c vmcmd.c - -libdvdvm_la_LDFLAGS = $(THREAD_LIBS) - -include_HEADERS = - -noinst_HEADERS = decoder.h vm.h vmcmd.h diff -r 427b7da5cbdb -r 1c897db44135 vm/decoder.c --- a/vm/decoder.c Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,788 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Martin Norbäck, Håkan Hjort - * 2002-2004 the dvdnav project - * - * This file is part of libdvdnav, a DVD navigation library. It is modified - * from a file originally part of the Ogle DVD player. - * - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include /* For memset */ -#include -#include "nav_types.h" -#include "ifo_types.h" /* vm_cmd_t */ - -#include "dvd_types.h" -#include "remap.h" -#include "decoder.h" -#include "vm.h" -#include "vmcmd.h" -#include "dvdnav.h" -#include "dvdnav_internal.h" - -uint32_t vm_getbits(command_t *command, int32_t start, int32_t count) { - uint64_t result = 0; - uint64_t bit_mask = 0; - uint64_t examining = 0; - int32_t bits; - - if (count == 0) return 0; - - if ( ((start - count) < -1) || - (count > 32) || - (start > 63) || - (count < 0) || - (start < 0) ) { - fprintf(MSG_OUT, "libdvdnav: Bad call to vm_getbits. Parameter out of range\n"); - abort(); - } - /* all ones, please */ - bit_mask = ~bit_mask; - bit_mask >>= 63 - start; - bits = start + 1 - count; - examining = ((bit_mask >> bits) << bits ); - command->examined |= examining; - result = (command->instruction & bit_mask) >> bits; - return (uint32_t) result; -} - -static uint16_t get_GPRM(registers_t* registers, uint8_t reg) { - if (registers->GPRM_mode[reg] & 0x01) { - struct timeval current_time, time_offset; - uint16_t result; - /* Counter mode */ - /* fprintf(MSG_OUT, "libdvdnav: Getting counter %d\n",reg);*/ - gettimeofday(¤t_time, NULL); - time_offset.tv_sec = current_time.tv_sec - registers->GPRM_time[reg].tv_sec; - time_offset.tv_usec = current_time.tv_usec - registers->GPRM_time[reg].tv_usec; - if (time_offset.tv_usec < 0) { - time_offset.tv_sec--; - time_offset.tv_usec += 1000000; - } - result = (uint16_t) (time_offset.tv_sec & 0xffff); - registers->GPRM[reg]=result; - return result; - - } else { - /* Register mode */ - return registers->GPRM[reg]; - } - -} - -static void set_GPRM(registers_t* registers, uint8_t reg, uint16_t value) { - if (registers->GPRM_mode[reg] & 0x01) { - struct timeval current_time; - /* Counter mode */ - /* fprintf(MSG_OUT, "libdvdnav: Setting counter %d\n",reg); */ - gettimeofday(¤t_time, NULL); - registers->GPRM_time[reg] = current_time; - registers->GPRM_time[reg].tv_sec -= value; - } - registers->GPRM[reg] = value; -} - -/* Eval register code, can either be system or general register. - SXXX_XXXX, where S is 1 if it is system register. */ -static uint16_t eval_reg(command_t* command, uint8_t reg) { - if(reg & 0x80) { - if ((reg & 0x1f) == 20) { - fprintf(MSG_OUT, "libdvdnav: Suspected RCE Region Protection!!!\n"); - } - return command->registers->SPRM[reg & 0x1f]; /* FIXME max 24 not 32 */ - } else { - return get_GPRM(command->registers, reg & 0x0f) ; - } -} - -/* Eval register or immediate data. - AAAA_AAAA BBBB_BBBB, if immediate use all 16 bits for data else use - lower eight bits for the system or general purpose register. */ -static uint16_t eval_reg_or_data(command_t* command, int32_t imm, int32_t start) { - if(imm) { /* immediate */ - return vm_getbits(command, start, 16); - } else { - return eval_reg(command, vm_getbits(command, (start - 8), 8)); - } -} - -/* Eval register or immediate data. - xBBB_BBBB, if immediate use all 7 bits for data else use - lower four bits for the general purpose register number. */ -/* Evaluates gprm or data depending on bit, data is in byte n */ -static uint16_t eval_reg_or_data_2(command_t* command, - int32_t imm, int32_t start) { - if(imm) /* immediate */ - return vm_getbits(command, (start - 1), 7); - else - return get_GPRM(command->registers, (vm_getbits(command, (start - 4), 4)) ); -} - - -/* Compare data using operation, return result from comparison. - Helper function for the different if functions. */ -static int32_t eval_compare(uint8_t operation, uint16_t data1, uint16_t data2) { - switch(operation) { - case 1: - return data1 & data2; - case 2: - return data1 == data2; - case 3: - return data1 != data2; - case 4: - return data1 >= data2; - case 5: - return data1 > data2; - case 6: - return data1 <= data2; - case 7: - return data1 < data2; - } - fprintf(MSG_OUT, "libdvdnav: eval_compare: Invalid comparison code\n"); - return 0; -} - - -/* Evaluate if version 1. - Has comparison data in byte 3 and 4-5 (immediate or register) */ -static int32_t eval_if_version_1(command_t* command) { - uint8_t op = vm_getbits(command, 54, 3); - if(op) { - return eval_compare(op, eval_reg(command, vm_getbits(command, 39, 8)), - eval_reg_or_data(command, vm_getbits(command, 55, 1), 31)); - } - return 1; -} - -/* Evaluate if version 2. - This version only compares register which are in byte 6 and 7 */ -static int32_t eval_if_version_2(command_t* command) { - uint8_t op = vm_getbits(command, 54, 3); - if(op) { - return eval_compare(op, eval_reg(command, vm_getbits(command, 15, 8)), - eval_reg(command, vm_getbits(command, 7, 8))); - } - return 1; -} - -/* Evaluate if version 3. - Has comparison data in byte 2 and 6-7 (immediate or register) */ -static int32_t eval_if_version_3(command_t* command) { - uint8_t op = vm_getbits(command, 54, 3); - if(op) { - return eval_compare(op, eval_reg(command, vm_getbits(command, 47, 8)), - eval_reg_or_data(command, vm_getbits(command, 55, 1), 15)); - } - return 1; -} - -/* Evaluate if version 4. - Has comparison data in byte 1 and 4-5 (immediate or register) - The register in byte 1 is only the lowe nibble (4 bits) */ -static int32_t eval_if_version_4(command_t* command) { - uint8_t op = vm_getbits(command, 54, 3); - if(op) { - return eval_compare(op, eval_reg(command, vm_getbits(command, 51, 4)), - eval_reg_or_data(command, vm_getbits(command, 55, 1), 31)); - } - return 1; -} - -/* Evaluate special instruction.... returns the new row/line number, - 0 if no new row and 256 if Break. */ -static int32_t eval_special_instruction(command_t* command, int32_t cond) { - int32_t line, level; - - switch(vm_getbits(command, 51, 4)) { - case 0: /* NOP */ - line = 0; - return cond ? line : 0; - case 1: /* Goto line */ - line = vm_getbits(command, 7, 8); - return cond ? line : 0; - case 2: /* Break */ - /* max number of rows < 256, so we will end this set */ - line = 256; - return cond ? 256 : 0; - case 3: /* Set temporary parental level and goto */ - line = vm_getbits(command, 7, 8); - level = vm_getbits(command, 11, 4); - if(cond) { - /* This always succeeds now, if we want real parental protection */ - /* we need to ask the user and have passwords and stuff. */ - command->registers->SPRM[13] = level; - } - return cond ? line : 0; - } - return 0; -} - -/* Evaluate link by subinstruction. - Return 1 if link, or 0 if no link - Actual link instruction is in return_values parameter */ -static int32_t eval_link_subins(command_t* command, int32_t cond, link_t *return_values) { - uint16_t button = vm_getbits(command, 15, 6); - uint8_t linkop = vm_getbits(command, 4, 5); - - if(linkop > 0x10) - return 0; /* Unknown Link by Sub-Instruction command */ - - /* Assumes that the link_cmd_t enum has the same values as the LinkSIns codes */ - return_values->command = linkop; - return_values->data1 = button; - return cond; -} - - -/* Evaluate link instruction. - Return 1 if link, or 0 if no link - Actual link instruction is in return_values parameter */ -static int32_t eval_link_instruction(command_t* command, int32_t cond, link_t *return_values) { - uint8_t op = vm_getbits(command, 51, 4); - - switch(op) { - case 1: - return eval_link_subins(command, cond, return_values); - case 4: - return_values->command = LinkPGCN; - return_values->data1 = vm_getbits(command, 14, 15); - return cond; - case 5: - return_values->command = LinkPTTN; - return_values->data1 = vm_getbits(command, 9, 10); - return_values->data2 = vm_getbits(command, 15, 6); - return cond; - case 6: - return_values->command = LinkPGN; - return_values->data1 = vm_getbits(command, 6, 7); - return_values->data2 = vm_getbits(command, 15, 6); - return cond; - case 7: - return_values->command = LinkCN; - return_values->data1 = vm_getbits(command, 7, 8); - return_values->data2 = vm_getbits(command, 15, 6); - return cond; - } - return 0; -} - - -/* Evaluate a jump instruction. - returns 1 if jump or 0 if no jump - actual jump instruction is in return_values parameter */ -static int32_t eval_jump_instruction(command_t* command, int32_t cond, link_t *return_values) { - - switch(vm_getbits(command, 51, 4)) { - case 1: - return_values->command = Exit; - return cond; - case 2: - return_values->command = JumpTT; - return_values->data1 = vm_getbits(command, 22, 7); - return cond; - case 3: - return_values->command = JumpVTS_TT; - return_values->data1 = vm_getbits(command, 22, 7); - return cond; - case 5: - return_values->command = JumpVTS_PTT; - return_values->data1 = vm_getbits(command, 22, 7); - return_values->data2 = vm_getbits(command, 41, 10); - return cond; - case 6: - switch(vm_getbits(command, 23, 2)) { - case 0: - return_values->command = JumpSS_FP; - return cond; - case 1: - return_values->command = JumpSS_VMGM_MENU; - return_values->data1 = vm_getbits(command, 19, 4); - return cond; - case 2: - return_values->command = JumpSS_VTSM; - return_values->data1 = vm_getbits(command, 31, 8); - return_values->data2 = vm_getbits(command, 39, 8); - return_values->data3 = vm_getbits(command, 19, 4); - return cond; - case 3: - return_values->command = JumpSS_VMGM_PGC; - return_values->data1 = vm_getbits(command, 46, 15); - return cond; - } - break; - case 8: - switch(vm_getbits(command, 23, 2)) { - case 0: - return_values->command = CallSS_FP; - return_values->data1 = vm_getbits(command, 31, 8); - return cond; - case 1: - return_values->command = CallSS_VMGM_MENU; - return_values->data1 = vm_getbits(command, 19, 4); - return_values->data2 = vm_getbits(command, 31, 8); - return cond; - case 2: - return_values->command = CallSS_VTSM; - return_values->data1 = vm_getbits(command, 19, 4); - return_values->data2 = vm_getbits(command, 31, 8); - return cond; - case 3: - return_values->command = CallSS_VMGM_PGC; - return_values->data1 = vm_getbits(command, 46, 15); - return_values->data2 = vm_getbits(command, 31, 8); - return cond; - } - break; - } - return 0; -} - -/* Evaluate a set sytem register instruction - May contain a link so return the same as eval_link */ -static int32_t eval_system_set(command_t* command, int32_t cond, link_t *return_values) { - int32_t i; - uint16_t data, data2; - - switch(vm_getbits(command, 59, 4)) { - case 1: /* Set system reg 1 &| 2 &| 3 (Audio, Subp. Angle) */ - for(i = 1; i <= 3; i++) { - if(vm_getbits(command, 63 - ((2 + i)*8), 1)) { - data = eval_reg_or_data_2(command, vm_getbits(command, 60, 1), (47 - (i*8))); - if(cond) { - command->registers->SPRM[i] = data; - } - } - } - break; - case 2: /* Set system reg 9 & 10 (Navigation timer, Title PGC number) */ - data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 47); - data2 = vm_getbits(command, 23, 8); /* ?? size */ - if(cond) { - command->registers->SPRM[9] = data; /* time */ - command->registers->SPRM[10] = data2; /* pgcN */ - } - break; - case 3: /* Mode: Counter / Register + Set */ - data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 47); - data2 = vm_getbits(command, 19, 4); - if(vm_getbits(command, 23, 1)) { - command->registers->GPRM_mode[data2] |= 1; /* Set bit 0 */ - } else { - command->registers->GPRM_mode[data2] &= ~ 0x01; /* Reset bit 0 */ - } - if(cond) { - set_GPRM(command->registers, data2, data); - } - break; - case 6: /* Set system reg 8 (Highlighted button) */ - data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 31); /* Not system reg!! */ - if(cond) { - command->registers->SPRM[8] = data; - } - break; - } - if(vm_getbits(command, 51, 4)) { - return eval_link_instruction(command, cond, return_values); - } - return 0; -} - - -/* Evaluate set operation - Sets the register given to the value indicated by op and data. - For the swap case the contents of reg is stored in reg2. -*/ -static void eval_set_op(command_t* command, int32_t op, int32_t reg, int32_t reg2, int32_t data) { - static const int32_t shortmax = 0xffff; - int32_t tmp; - switch(op) { - case 1: - set_GPRM(command->registers, reg, data); - break; - case 2: /* SPECIAL CASE - SWAP! */ - set_GPRM(command->registers, reg2, get_GPRM(command->registers, reg)); - set_GPRM(command->registers, reg, data); - break; - case 3: - tmp = get_GPRM(command->registers, reg) + data; - if(tmp > shortmax) tmp = shortmax; - set_GPRM(command->registers, reg, (uint16_t)tmp); - break; - case 4: - tmp = get_GPRM(command->registers, reg) - data; - if(tmp < 0) tmp = 0; - set_GPRM(command->registers, reg, (uint16_t)tmp); - break; - case 5: - tmp = get_GPRM(command->registers, reg) * data; - if(tmp > shortmax) tmp = shortmax; - set_GPRM(command->registers, reg, (uint16_t)tmp); - break; - case 6: - if (data != 0) { - set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) / data) ); - } else { - set_GPRM(command->registers, reg, 0xffff); /* Avoid that divide by zero! */ - } - break; - case 7: - if (data != 0) { - set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) % data) ); - } else { - set_GPRM(command->registers, reg, 0xffff); /* Avoid that divide by zero! */ - } - break; - case 8: /* SPECIAL CASE - RND! Return numbers between 1 and data. */ - set_GPRM(command->registers, reg, 1 + ((uint16_t) ((float) data * rand()/(RAND_MAX+1.0))) ); - break; - case 9: - set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) & data) ); - break; - case 10: - set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) | data) ); - break; - case 11: - set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) ^ data) ); - break; - } -} - -/* Evaluate set instruction, combined with either Link or Compare. */ -static void eval_set_version_1(command_t* command, int32_t cond) { - uint8_t op = vm_getbits(command, 59, 4); - uint8_t reg = vm_getbits(command, 35, 4); /* FIXME: This is different from vmcmd.c!!! */ - uint8_t reg2 = vm_getbits(command, 19, 4); - uint16_t data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 31); - - if(cond) { - eval_set_op(command, op, reg, reg2, data); - } -} - - -/* Evaluate set instruction, combined with both Link and Compare. */ -static void eval_set_version_2(command_t* command, int32_t cond) { - uint8_t op = vm_getbits(command, 59, 4); - uint8_t reg = vm_getbits(command, 51, 4); - uint8_t reg2 = vm_getbits(command, 35, 4); /* FIXME: This is different from vmcmd.c!!! */ - uint16_t data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 47); - - if(cond) { - eval_set_op(command, op, reg, reg2, data); - } -} - - -/* Evaluate a command - returns row number of goto, 0 if no goto, -1 if link. - Link command in return_values */ -static int32_t eval_command(uint8_t *bytes, registers_t* registers, link_t *return_values) { - int32_t cond, res = 0; - command_t command; - command.instruction =( (uint64_t) bytes[0] << 56 ) | - ( (uint64_t) bytes[1] << 48 ) | - ( (uint64_t) bytes[2] << 40 ) | - ( (uint64_t) bytes[3] << 32 ) | - ( (uint64_t) bytes[4] << 24 ) | - ( (uint64_t) bytes[5] << 16 ) | - ( (uint64_t) bytes[6] << 8 ) | - (uint64_t) bytes[7] ; - command.examined = 0; - command.registers = registers; - memset(return_values, 0, sizeof(link_t)); - - switch(vm_getbits(&command, 63, 3)) { /* three first old_bits */ - case 0: /* Special instructions */ - cond = eval_if_version_1(&command); - res = eval_special_instruction(&command, cond); - if(res == -1) { - fprintf(MSG_OUT, "libdvdnav: Unknown Instruction!\n"); - abort(); - } - break; - case 1: /* Link/jump instructions */ - if(vm_getbits(&command, 60, 1)) { - cond = eval_if_version_2(&command); - res = eval_jump_instruction(&command, cond, return_values); - } else { - cond = eval_if_version_1(&command); - res = eval_link_instruction(&command, cond, return_values); - } - if(res) - res = -1; - break; - case 2: /* System set instructions */ - cond = eval_if_version_2(&command); - res = eval_system_set(&command, cond, return_values); - if(res) - res = -1; - break; - case 3: /* Set instructions, either Compare or Link may be used */ - cond = eval_if_version_3(&command); - eval_set_version_1(&command, cond); - if(vm_getbits(&command, 51, 4)) { - res = eval_link_instruction(&command, cond, return_values); - } - if(res) - res = -1; - break; - case 4: /* Set, Compare -> Link Sub-Instruction */ - eval_set_version_2(&command, /*True*/ 1); - cond = eval_if_version_4(&command); - res = eval_link_subins(&command, cond, return_values); - if(res) - res = -1; - break; - case 5: /* Compare -> (Set and Link Sub-Instruction) */ - /* FIXME: These are wrong. Need to be updated from vmcmd.c */ - cond = eval_if_version_4(&command); - eval_set_version_2(&command, cond); - res = eval_link_subins(&command, cond, return_values); - if(res) - res = -1; - break; - case 6: /* Compare -> Set, allways Link Sub-Instruction */ - /* FIXME: These are wrong. Need to be updated from vmcmd.c */ - cond = eval_if_version_4(&command); - eval_set_version_2(&command, cond); - res = eval_link_subins(&command, /*True*/ 1, return_values); - if(res) - res = -1; - break; - default: /* Unknown command */ - fprintf(MSG_OUT, "libdvdnav: WARNING: Unknown Command=%x\n", vm_getbits(&command, 63, 3)); - abort(); - } - /* Check if there are bits not yet examined */ - - if(command.instruction & ~ command.examined) { - fprintf(MSG_OUT, "libdvdnav: decoder.c: [WARNING, unknown bits:"); - fprintf(MSG_OUT, " %08"PRIx64, (command.instruction & ~ command.examined) ); - fprintf(MSG_OUT, "]\n"); - } - - return res; -} - -/* Evaluate a set of commands in the given register set (which is modified) */ -int32_t vmEval_CMD(vm_cmd_t commands[], int32_t num_commands, - registers_t *registers, link_t *return_values) { - int32_t i = 0; - int32_t total = 0; - -#ifdef TRACE - /* DEBUG */ - fprintf(MSG_OUT, "libdvdnav: Registers before transaction\n"); - vm_print_registers( registers ); - fprintf(MSG_OUT, "libdvdnav: Full list of commands to execute\n"); - for(i = 0; i < num_commands; i++) - vm_print_cmd(i, &commands[i]); - fprintf(MSG_OUT, "libdvdnav: --------------------------------------------\n"); - fprintf(MSG_OUT, "libdvdnav: Single stepping commands\n"); -#endif - - i = 0; - while(i < num_commands && total < 100000) { - int32_t line; - -#ifdef TRACE - vm_print_cmd(i, &commands[i]); -#endif - - line = eval_command(&commands[i].bytes[0], registers, return_values); - - if (line < 0) { /* Link command */ -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: Registers after transaction\n"); - vm_print_registers( registers ); - fprintf(MSG_OUT, "libdvdnav: eval: Doing Link/Jump/Call\n"); -#endif - return 1; - } - - if (line > 0) /* Goto command */ - i = line - 1; - else /* Just continue on the next line */ - i++; - - total++; - } - - memset(return_values, 0, sizeof(link_t)); -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: Registers after transaction\n"); - vm_print_registers( registers ); -#endif - return 0; -} - -#ifdef TRACE - -static char *linkcmd2str(link_cmd_t cmd) { - switch(cmd) { - case LinkNoLink: - return "LinkNoLink"; - case LinkTopC: - return "LinkTopC"; - case LinkNextC: - return "LinkNextC"; - case LinkPrevC: - return "LinkPrevC"; - case LinkTopPG: - return "LinkTopPG"; - case LinkNextPG: - return "LinkNextPG"; - case LinkPrevPG: - return "LinkPrevPG"; - case LinkTopPGC: - return "LinkTopPGC"; - case LinkNextPGC: - return "LinkNextPGC"; - case LinkPrevPGC: - return "LinkPrevPGC"; - case LinkGoUpPGC: - return "LinkGoUpPGC"; - case LinkTailPGC: - return "LinkTailPGC"; - case LinkRSM: - return "LinkRSM"; - case LinkPGCN: - return "LinkPGCN"; - case LinkPTTN: - return "LinkPTTN"; - case LinkPGN: - return "LinkPGN"; - case LinkCN: - return "LinkCN"; - case Exit: - return "Exit"; - case JumpTT: - return "JumpTT"; - case JumpVTS_TT: - return "JumpVTS_TT"; - case JumpVTS_PTT: - return "JumpVTS_PTT"; - case JumpSS_FP: - return "JumpSS_FP"; - case JumpSS_VMGM_MENU: - return "JumpSS_VMGM_MENU"; - case JumpSS_VTSM: - return "JumpSS_VTSM"; - case JumpSS_VMGM_PGC: - return "JumpSS_VMGM_PGC"; - case CallSS_FP: - return "CallSS_FP"; - case CallSS_VMGM_MENU: - return "CallSS_VMGM_MENU"; - case CallSS_VTSM: - return "CallSS_VTSM"; - case CallSS_VMGM_PGC: - return "CallSS_VMGM_PGC"; - case PlayThis: - return "PlayThis"; - } - return "*** (bug)"; -} - -void vm_print_link(link_t value) { - char *cmd = linkcmd2str(value.command); - - switch(value.command) { - case LinkNoLink: - case LinkTopC: - case LinkNextC: - case LinkPrevC: - case LinkTopPG: - case LinkNextPG: - case LinkPrevPG: - case LinkTopPGC: - case LinkNextPGC: - case LinkPrevPGC: - case LinkGoUpPGC: - case LinkTailPGC: - case LinkRSM: - fprintf(MSG_OUT, "libdvdnav: %s (button %d)\n", cmd, value.data1); - break; - case LinkPGCN: - case JumpTT: - case JumpVTS_TT: - case JumpSS_VMGM_MENU: /* == 2 -> Title Menu */ - case JumpSS_VMGM_PGC: - fprintf(MSG_OUT, "libdvdnav: %s %d\n", cmd, value.data1); - break; - case LinkPTTN: - case LinkPGN: - case LinkCN: - fprintf(MSG_OUT, "libdvdnav: %s %d (button %d)\n", cmd, value.data1, value.data2); - break; - case Exit: - case JumpSS_FP: - case PlayThis: /* Humm.. should we have this at all.. */ - fprintf(MSG_OUT, "libdvdnav: %s\n", cmd); - break; - case JumpVTS_PTT: - fprintf(MSG_OUT, "libdvdnav: %s %d:%d\n", cmd, value.data1, value.data2); - break; - case JumpSS_VTSM: - fprintf(MSG_OUT, "libdvdnav: %s vts %d title %d menu %d\n", - cmd, value.data1, value.data2, value.data3); - break; - case CallSS_FP: - fprintf(MSG_OUT, "libdvdnav: %s resume cell %d\n", cmd, value.data1); - break; - case CallSS_VMGM_MENU: /* == 2 -> Title Menu */ - case CallSS_VTSM: - fprintf(MSG_OUT, "libdvdnav: %s %d resume cell %d\n", cmd, value.data1, value.data2); - break; - case CallSS_VMGM_PGC: - fprintf(MSG_OUT, "libdvdnav: %s %d resume cell %d\n", cmd, value.data1, value.data2); - break; - } - } - -void vm_print_registers( registers_t *registers ) { - int32_t i; - fprintf(MSG_OUT, "libdvdnav: # "); - for(i = 0; i < 24; i++) - fprintf(MSG_OUT, " %2d |", i); - fprintf(MSG_OUT, "\nlibdvdnav: SRPMS: "); - for(i = 0; i < 24; i++) - fprintf(MSG_OUT, "%04x|", registers->SPRM[i]); - fprintf(MSG_OUT, "\nlibdvdnav: GRPMS: "); - for(i = 0; i < 16; i++) - fprintf(MSG_OUT, "%04x|", get_GPRM(registers, i) ); - fprintf(MSG_OUT, "\nlibdvdnav: Gmode: "); - for(i = 0; i < 16; i++) - fprintf(MSG_OUT, "%04x|", registers->GPRM_mode[i]); - fprintf(MSG_OUT, "\nlibdvdnav: Gtime: "); - for(i = 0; i < 16; i++) - fprintf(MSG_OUT, "%04lx|", registers->GPRM_time[i].tv_sec & 0xffff); - fprintf(MSG_OUT, "\n"); -} - -#endif - diff -r 427b7da5cbdb -r 1c897db44135 vm/decoder.h --- a/vm/decoder.h Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Martin Norbäck, Håkan Hjort - * - * This file is part of libdvdnav, a DVD navigation library. It is modified - * from a file originally part of the Ogle DVD player. - * - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -#ifndef DECODER_H_INCLUDED -#define DECODER_H_INCLUDED - -/* link command types */ -typedef enum { - LinkNoLink = 0, - - LinkTopC = 1, - LinkNextC = 2, - LinkPrevC = 3, - - LinkTopPG = 5, - LinkNextPG = 6, - LinkPrevPG = 7, - - LinkTopPGC = 9, - LinkNextPGC = 10, - LinkPrevPGC = 11, - LinkGoUpPGC = 12, - LinkTailPGC = 13, - - LinkRSM = 16, - - LinkPGCN, - LinkPTTN, - LinkPGN, - LinkCN, - - Exit, - - JumpTT, /* 22 */ - JumpVTS_TT, - JumpVTS_PTT, - - JumpSS_FP, - JumpSS_VMGM_MENU, - JumpSS_VTSM, - JumpSS_VMGM_PGC, - - CallSS_FP, /* 29 */ - CallSS_VMGM_MENU, - CallSS_VTSM, - CallSS_VMGM_PGC, - - PlayThis -} link_cmd_t; - -/* a link's data set */ -typedef struct { - link_cmd_t command; - uint16_t data1; - uint16_t data2; - uint16_t data3; -} link_t; - -/* the VM registers */ -typedef struct { - uint16_t SPRM[24]; - uint16_t GPRM[16]; - uint8_t GPRM_mode[16]; /* Need to have some thing to indicate normal/counter mode for every GPRM */ - struct timeval GPRM_time[16]; /* For counter mode */ -} registers_t; - -/* a VM command data set */ -typedef struct { - uint64_t instruction; - uint64_t examined; - registers_t *registers; -} command_t; - -/* the big VM function, executing the given commands and writing - * the link where to continue, the return value indicates if a jump - * has been performed */ -int32_t vmEval_CMD(vm_cmd_t commands[], int32_t num_commands, - registers_t *registers, link_t *return_values); - -/* extracts some bits from the command */ -uint32_t vm_getbits(command_t* command, int32_t start, int32_t count); - -#ifdef TRACE -/* for debugging: prints a link in readable form */ -void vm_print_link(link_t value); - -/* for debugging: dumps VM registers */ -void vm_print_registers( registers_t *registers ); -#endif - -#endif /* DECODER_H_INCLUDED */ diff -r 427b7da5cbdb -r 1c897db44135 vm/vm.c --- a/vm/vm.c Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1886 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Håkan Hjort - * Copyright (C) 2001 Rich Wareham - * 2002-2004 the dvdnav project - * - * This file is part of libdvdnav, a DVD navigation library. It is modified - * from a file originally part of the Ogle DVD player. - * - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nav_types.h" -#include "ifo_types.h" -#include "ifo_read.h" -#include "dvd_types.h" - -#include "decoder.h" -#include "remap.h" -#include "vm.h" -#include "dvdnav.h" -#include "dvdnav_internal.h" - -#ifdef _MSC_VER -#include /* read() */ -#endif /* _MSC_VER */ - -/* -#define STRICT -*/ - -/* Local prototypes */ - -/* get_XYZ returns a value. - * set_XYZ sets state using passed parameters. - * returns success/failure. - */ - -/* Play */ -static link_t play_PGC(vm_t *vm); -static link_t play_PGC_PG(vm_t *vm, int pgN); -static link_t play_PGC_post(vm_t *vm); -static link_t play_PG(vm_t *vm); -static link_t play_Cell(vm_t *vm); -static link_t play_Cell_post(vm_t *vm); - -/* Process link - returns 1 if a hop has been performed */ -static int process_command(vm_t *vm,link_t link_values); - -/* Set */ -static int set_TT(vm_t *vm, int tt); -static int set_PTT(vm_t *vm, int tt, int ptt); -static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn); -static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part); -static int set_FP_PGC(vm_t *vm); -static int set_MENU(vm_t *vm, int menu); -static int set_PGCN(vm_t *vm, int pgcN); -static int set_PGN(vm_t *vm); /* Set PGN based on (vm->state).CellN */ -static void set_RSMinfo(vm_t *vm, int cellN, int blockN); - -/* Get */ -static int get_TT(vm_t *vm, int vtsN, int vts_ttn); -static int get_ID(vm_t *vm, int id); -static int get_PGCN(vm_t *vm); - -static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang); -static pgcit_t* get_PGCIT(vm_t *vm); - - -/* Helper functions */ - -#ifdef TRACE -static void vm_print_current_domain_state(vm_t *vm) { - switch((vm->state).domain) { - case VTS_DOMAIN: - fprintf(MSG_OUT, "libdvdnav: Video Title Domain: -\n"); - break; - - case VTSM_DOMAIN: - fprintf(MSG_OUT, "libdvdnav: Video Title Menu Domain: -\n"); - break; - - case VMGM_DOMAIN: - fprintf(MSG_OUT, "libdvdnav: Video Manager Menu Domain: -\n"); - break; - - case FP_DOMAIN: - fprintf(MSG_OUT, "libdvdnav: First Play Domain: -\n"); - break; - - default: - fprintf(MSG_OUT, "libdvdnav: Unknown Domain: -\n"); - break; - } - fprintf(MSG_OUT, "libdvdnav: VTS:%d PGC:%d PG:%u CELL:%u BLOCK:%u VTS_TTN:%u TTN:%u TT_PGCN:%u\n", - (vm->state).vtsN, - get_PGCN(vm), - (vm->state).pgN, - (vm->state).cellN, - (vm->state).blockN, - (vm->state).VTS_TTN_REG, - (vm->state).TTN_REG, - (vm->state).TT_PGCN_REG); -} -#endif - -static void dvd_read_name(char *name, const char *device) { - /* Because we are compiling with _FILE_OFFSET_BITS=64 - * all off_t are 64bit. - */ - off_t off; - int fd, i; - uint8_t data[DVD_VIDEO_LB_LEN]; - - /* Read DVD name */ - fd = open(device, O_RDONLY); - if (fd > 0) { - off = lseek( fd, 32 * (off_t) DVD_VIDEO_LB_LEN, SEEK_SET ); - if( off == ( 32 * (off_t) DVD_VIDEO_LB_LEN ) ) { - off = read( fd, data, DVD_VIDEO_LB_LEN ); - close(fd); - if (off == ( (off_t) DVD_VIDEO_LB_LEN )) { - fprintf(MSG_OUT, "libdvdnav: DVD Title: "); - for(i=25; i < 73; i++ ) { - if((data[i] == 0)) break; - if((data[i] > 32) && (data[i] < 127)) { - fprintf(MSG_OUT, "%c", data[i]); - } else { - fprintf(MSG_OUT, " "); - } - } - strncpy(name, &data[25], 48); - name[48] = 0; - fprintf(MSG_OUT, "\nlibdvdnav: DVD Serial Number: "); - for(i=73; i < 89; i++ ) { - if((data[i] == 0)) break; - if((data[i] > 32) && (data[i] < 127)) { - fprintf(MSG_OUT, "%c", data[i]); - } else { - fprintf(MSG_OUT, " "); - } - } - fprintf(MSG_OUT, "\nlibdvdnav: DVD Title (Alternative): "); - for(i=89; i < 128; i++ ) { - if((data[i] == 0)) break; - if((data[i] > 32) && (data[i] < 127)) { - fprintf(MSG_OUT, "%c", data[i]); - } else { - fprintf(MSG_OUT, " "); - } - } - fprintf(MSG_OUT, "\n"); - } else { - fprintf(MSG_OUT, "libdvdnav: Can't read name block. Probably not a DVD-ROM device.\n"); - } - } else { - fprintf(MSG_OUT, "libdvdnav: Can't seek to block %u\n", 32 ); - } - close(fd); - } else { - fprintf(MSG_OUT, "NAME OPEN FAILED\n"); - } -} - -static int ifoOpenNewVTSI(vm_t *vm, dvd_reader_t *dvd, int vtsN) { - if((vm->state).vtsN == vtsN) { - return 1; /* We alread have it */ - } - - if(vm->vtsi != NULL) - ifoClose(vm->vtsi); - - vm->vtsi = ifoOpenVTSI(dvd, vtsN); - if(vm->vtsi == NULL) { - fprintf(MSG_OUT, "libdvdnav: ifoOpenVTSI failed\n"); - return 0; - } - if(!ifoRead_VTS_PTT_SRPT(vm->vtsi)) { - fprintf(MSG_OUT, "libdvdnav: ifoRead_VTS_PTT_SRPT failed\n"); - return 0; - } - if(!ifoRead_PGCIT(vm->vtsi)) { - fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCIT failed\n"); - return 0; - } - if(!ifoRead_PGCI_UT(vm->vtsi)) { - fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCI_UT failed\n"); - return 0; - } - if(!ifoRead_VOBU_ADMAP(vm->vtsi)) { - fprintf(MSG_OUT, "libdvdnav: ifoRead_VOBU_ADMAP vtsi failed\n"); - return 0; - } - if(!ifoRead_TITLE_VOBU_ADMAP(vm->vtsi)) { - fprintf(MSG_OUT, "libdvdnav: ifoRead_TITLE_VOBU_ADMAP vtsi failed\n"); - return 0; - } - (vm->state).vtsN = vtsN; - - return 1; -} - - -/* Initialisation & Destruction */ - -vm_t* vm_new_vm() { - return (vm_t*)calloc(sizeof(vm_t), sizeof(char)); -} - -void vm_free_vm(vm_t *vm) { - vm_stop(vm); - free(vm); -} - - -/* IFO Access */ - -ifo_handle_t *vm_get_vmgi(vm_t *vm) { - return vm->vmgi; -} - -ifo_handle_t *vm_get_vtsi(vm_t *vm) { - return vm->vtsi; -} - - -/* Reader Access */ - -dvd_reader_t *vm_get_dvd_reader(vm_t *vm) { - return vm->dvd; -} - - -/* Basic Handling */ - -int vm_start(vm_t *vm) { - /* Set pgc to FP (First Play) pgc */ - set_FP_PGC(vm); - process_command(vm, play_PGC(vm)); - return !vm->stopped; -} - -void vm_stop(vm_t *vm) { - if(vm->vmgi) { - ifoClose(vm->vmgi); - vm->vmgi=NULL; - } - if(vm->vtsi) { - ifoClose(vm->vtsi); - vm->vtsi=NULL; - } - if(vm->dvd) { - DVDClose(vm->dvd); - vm->dvd=NULL; - } - vm->stopped = 1; -} - -int vm_reset(vm_t *vm, const char *dvdroot) { - /* Setup State */ - memset((vm->state).registers.SPRM, 0, sizeof((vm->state).registers.SPRM)); - memset((vm->state).registers.GPRM, 0, sizeof((vm->state).registers.GPRM)); - memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode)); - memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode)); - memset((vm->state).registers.GPRM_time, 0, sizeof((vm->state).registers.GPRM_time)); - (vm->state).registers.SPRM[0] = ('e'<<8)|'n'; /* Player Menu Languange code */ - (vm->state).AST_REG = 15; /* 15 why? */ - (vm->state).SPST_REG = 62; /* 62 why? */ - (vm->state).AGL_REG = 1; - (vm->state).TTN_REG = 1; - (vm->state).VTS_TTN_REG = 1; - /* (vm->state).TT_PGCN_REG = 0 */ - (vm->state).PTTN_REG = 1; - (vm->state).HL_BTNN_REG = 1 << 10; - (vm->state).PTL_REG = 15; /* Parental Level */ - (vm->state).registers.SPRM[12] = ('U'<<8)|'S'; /* Parental Management Country Code */ - (vm->state).registers.SPRM[16] = ('e'<<8)|'n'; /* Initial Language Code for Audio */ - (vm->state).registers.SPRM[18] = ('e'<<8)|'n'; /* Initial Language Code for Spu */ - (vm->state).registers.SPRM[20] = 0x1; /* Player Regional Code Mask. Region free! */ - (vm->state).registers.SPRM[14] = 0x100; /* Try Pan&Scan */ - - (vm->state).pgN = 0; - (vm->state).cellN = 0; - (vm->state).cell_restart = 0; - - (vm->state).domain = FP_DOMAIN; - (vm->state).rsm_vtsN = 0; - (vm->state).rsm_cellN = 0; - (vm->state).rsm_blockN = 0; - - (vm->state).vtsN = -1; - - if (vm->dvd && dvdroot) { - /* a new dvd device has been requested */ - vm_stop(vm); - } - if (!vm->dvd) { - vm->dvd = DVDOpen(dvdroot); - if(!vm->dvd) { - fprintf(MSG_OUT, "libdvdnav: vm: failed to open/read the DVD\n"); - return 0; - } - dvd_read_name(vm->dvd_name, dvdroot); - vm->map = remap_loadmap(vm->dvd_name); - vm->vmgi = ifoOpenVMGI(vm->dvd); - if(!vm->vmgi) { - fprintf(MSG_OUT, "libdvdnav: vm: failed to read VIDEO_TS.IFO\n"); - return 0; - } - if(!ifoRead_FP_PGC(vm->vmgi)) { - fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_FP_PGC failed\n"); - return 0; - } - if(!ifoRead_TT_SRPT(vm->vmgi)) { - fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_TT_SRPT failed\n"); - return 0; - } - if(!ifoRead_PGCI_UT(vm->vmgi)) { - fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PGCI_UT failed\n"); - return 0; - } - if(!ifoRead_PTL_MAIT(vm->vmgi)) { - fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PTL_MAIT failed\n"); - /* return 0; Not really used for now.. */ - } - if(!ifoRead_VTS_ATRT(vm->vmgi)) { - fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VTS_ATRT failed\n"); - /* return 0; Not really used for now.. */ - } - if(!ifoRead_VOBU_ADMAP(vm->vmgi)) { - fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VOBU_ADMAP vgmi failed\n"); - /* return 0; Not really used for now.. */ - } - /* ifoRead_TXTDT_MGI(vmgi); Not implemented yet */ - } - if (vm->vmgi) { - int i, mask; - fprintf(MSG_OUT, "libdvdnav: DVD disk reports itself with Region mask 0x%08x. Regions:", - vm->vmgi->vmgi_mat->vmg_category); - for (i = 1, mask = 1; i <= 8; i++, mask <<= 1) - if (((vm->vmgi->vmgi_mat->vmg_category >> 16) & mask) == 0) - fprintf(MSG_OUT, " %d", i); - fprintf(MSG_OUT, "\n"); - } - return 1; -} - - -/* copying and merging */ - -vm_t *vm_new_copy(vm_t *source) { - vm_t *target = vm_new_vm(); - int vtsN; - int pgcN = get_PGCN(source); - int pgN = (source->state).pgN; - - assert(pgcN); - - memcpy(target, source, sizeof(vm_t)); - - /* open a new vtsi handle, because the copy might switch to another VTS */ - target->vtsi = NULL; - vtsN = (target->state).vtsN; - if (vtsN > 0) { - (target->state).vtsN = 0; - if (!ifoOpenNewVTSI(target, target->dvd, vtsN)) - assert(0); - - /* restore pgc pointer into the new vtsi */ - if (!set_PGCN(target, pgcN)) - assert(0); - (target->state).pgN = pgN; - } - - return target; -} - -void vm_merge(vm_t *target, vm_t *source) { - if(target->vtsi) - ifoClose(target->vtsi); - memcpy(target, source, sizeof(vm_t)); - memset(source, 0, sizeof(vm_t)); -} - -void vm_free_copy(vm_t *vm) { - if(vm->vtsi) - ifoClose(vm->vtsi); - free(vm); -} - - -/* regular playback */ - -void vm_position_get(vm_t *vm, vm_position_t *position) { - position->button = (vm->state).HL_BTNN_REG >> 10; - position->vts = (vm->state).vtsN; - position->domain = (vm->state).domain; - position->spu_channel = (vm->state).SPST_REG; - position->audio_channel = (vm->state).AST_REG; - position->angle_channel = (vm->state).AGL_REG; - position->hop_channel = vm->hop_channel; /* Increases by one on each hop */ - position->cell = (vm->state).cellN; - position->cell_restart = (vm->state).cell_restart; - position->cell_start = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector; - position->still = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].still_time; - position->block = (vm->state).blockN; - - /* handle PGC stills at PGC end */ - if ((vm->state).cellN == (vm->state).pgc->nr_of_cells) - position->still += (vm->state).pgc->still_time; - /* still already determined */ - if (position->still) - return; - /* This is a rough fix for some strange still situations on some strange DVDs. - * There are discs (like the German "Back to the Future" RC2) where the only - * indication of a still is a cell playback time higher than the time the frames - * in this cell actually take to play (like 1 frame with 1 minute playback time). - * On the said BTTF disc, for these cells last_sector and last_vobu_start_sector - * are equal and the cells are very short, so we abuse these conditions to - * detect such discs. I consider these discs broken, so the fix is somewhat - * broken, too. */ - if (((vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector == - (vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_vobu_start_sector) && - ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector - - (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector < 1024)) { - int time; - int size = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector - - (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector; - time = ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.hour >> 4 ) * 36000; - time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.hour & 0x0f) * 3600; - time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.minute >> 4 ) * 600; - time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.minute & 0x0f) * 60; - time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second >> 4 ) * 10; - time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second & 0x0f) * 1; - if (!time || size / time > 30) - /* datarate is too high, it might be a very short, but regular cell */ - return; - if (time > 0xff) time = 0xff; - position->still = time; - } -} - -void vm_get_next_cell(vm_t *vm) { - process_command(vm, play_Cell_post(vm)); -} - - -/* Jumping */ - -int vm_jump_pg(vm_t *vm, int pg) { - (vm->state).pgN = pg; - process_command(vm, play_PG(vm)); - return 1; -} - -int vm_jump_cell_block(vm_t *vm, int cell, int block) { - (vm->state).cellN = cell; - process_command(vm, play_Cell(vm)); - /* play_Cell can jump to a different cell in case of angles */ - if ((vm->state).cellN == cell) - (vm->state).blockN = block; - return 1; -} - -int vm_jump_title_part(vm_t *vm, int title, int part) { - link_t link; - - if(!set_PTT(vm, title, part)) - return 0; - /* Some DVDs do not want us to jump directly into a title and have - * PGC pre commands taking us back to some menu. Since we do not like that, - * we do not execute PGC pre commands that would do a jump. */ - /* process_command(vm, play_PGC_PG(vm, (vm->state).pgN)); */ - link = play_PGC_PG(vm, (vm->state).pgN); - if (link.command != PlayThis) - /* jump occured -> ignore it and play the PG anyway */ - process_command(vm, play_PG(vm)); - else - process_command(vm, link); - return 1; -} - -int vm_jump_top_pg(vm_t *vm) { - process_command(vm, play_PG(vm)); - return 1; -} - -int vm_jump_next_pg(vm_t *vm) { - if((vm->state).pgN >= (vm->state).pgc->nr_of_programs) { - /* last program -> move to TailPGC */ - process_command(vm, play_PGC_post(vm)); - return 1; - } else { - vm_jump_pg(vm, (vm->state).pgN + 1); - return 1; - } -} - -int vm_jump_prev_pg(vm_t *vm) { - if ((vm->state).pgN <= 1) { - /* first program -> move to last program of previous PGC */ - if ((vm->state).pgc->prev_pgc_nr && set_PGCN(vm, (vm->state).pgc->prev_pgc_nr)) { - process_command(vm, play_PGC(vm)); - vm_jump_pg(vm, (vm->state).pgc->nr_of_programs); - return 1; - } - return 0; - } else { - vm_jump_pg(vm, (vm->state).pgN - 1); - return 1; - } -} - -int vm_jump_up(vm_t *vm) { - if((vm->state).pgc->goup_pgc_nr && set_PGCN(vm, (vm->state).pgc->goup_pgc_nr)) { - process_command(vm, play_PGC(vm)); - return 1; - } - return 0; -} - -int vm_jump_menu(vm_t *vm, DVDMenuID_t menuid) { - domain_t old_domain = (vm->state).domain; - - switch ((vm->state).domain) { - case VTS_DOMAIN: - set_RSMinfo(vm, 0, (vm->state).blockN); - /* FALL THROUGH */ - case VTSM_DOMAIN: - case VMGM_DOMAIN: - switch(menuid) { - case DVD_MENU_Title: - case DVD_MENU_Escape: - (vm->state).domain = VMGM_DOMAIN; - break; - case DVD_MENU_Root: - case DVD_MENU_Subpicture: - case DVD_MENU_Audio: - case DVD_MENU_Angle: - case DVD_MENU_Part: - (vm->state).domain = VTSM_DOMAIN; - break; - } - if(get_PGCIT(vm) && set_MENU(vm, menuid)) { - process_command(vm, play_PGC(vm)); - return 1; /* Jump */ - } else { - (vm->state).domain = old_domain; - } - break; - case FP_DOMAIN: /* FIXME XXX $$$ What should we do here? */ - break; - } - - return 0; -} - -int vm_jump_resume(vm_t *vm) { - link_t link_values = { LinkRSM, 0, 0, 0 }; - - if (!(vm->state).rsm_vtsN) /* Do we have resume info? */ - return 0; - if (!process_command(vm, link_values)) - return 0; - return 1; -} - -int vm_exec_cmd(vm_t *vm, vm_cmd_t *cmd) { - link_t link_values; - - if(vmEval_CMD(cmd, 1, &(vm->state).registers, &link_values)) - return process_command(vm, link_values); - else - return 0; /* It updated some state thats all... */ -} - - -/* getting information */ - -int vm_get_current_menu(vm_t *vm, int *menuid) { - pgcit_t* pgcit; - int pgcn; - pgcn = (vm->state).pgcN; - pgcit = get_PGCIT(vm); - if(pgcit==NULL) return 0; - *menuid = pgcit->pgci_srp[pgcn - 1].entry_id & 0xf ; - return 1; -} - -int vm_get_current_title_part(vm_t *vm, int *title_result, int *part_result) { - vts_ptt_srpt_t *vts_ptt_srpt; - int title, part = 0, vts_ttn; - int found; - int16_t pgcN, pgN; - - vts_ptt_srpt = vm->vtsi->vts_ptt_srpt; - pgcN = get_PGCN(vm); - pgN = vm->state.pgN; - - found = 0; - for (vts_ttn = 0; (vts_ttn < vts_ptt_srpt->nr_of_srpts) && !found; vts_ttn++) { - for (part = 0; (part < vts_ptt_srpt->title[vts_ttn].nr_of_ptts) && !found; part++) { - if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgcn == pgcN) { - if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgn == pgN) { - found = 1; - break; - } - if (part > 0 && vts_ptt_srpt->title[vts_ttn].ptt[part].pgn > pgN && - vts_ptt_srpt->title[vts_ttn].ptt[part - 1].pgn < pgN) { - part--; - found = 1; - break; - } - } - } - if (found) break; - } - vts_ttn++; - part++; - - if (!found) { - fprintf(MSG_OUT, "libdvdnav: chapter NOT FOUND!\n"); - return 0; - } - - title = get_TT(vm, vm->state.vtsN, vts_ttn); - -#ifdef TRACE - if (title) { - fprintf(MSG_OUT, "libdvdnav: ************ this chapter FOUND!\n"); - fprintf(MSG_OUT, "libdvdnav: VTS_PTT_SRPT - Title %3i part %3i: PGC: %3i PG: %3i\n", - title, part, - vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgcn , - vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgn ); - } -#endif - *title_result = title; - *part_result = part; - return 1; -} - -/* Return the substream id for 'logical' audio stream audioN. - * 0 <= audioN < 8 - */ -int vm_get_audio_stream(vm_t *vm, int audioN) { - int streamN = -1; - - if((vm->state).domain != VTS_DOMAIN) - audioN = 0; - - if(audioN < 8) { - /* Is there any control info for this logical stream */ - if((vm->state).pgc->audio_control[audioN] & (1<<15)) { - streamN = ((vm->state).pgc->audio_control[audioN] >> 8) & 0x07; - } - } - - if((vm->state).domain != VTS_DOMAIN && streamN == -1) - streamN = 0; - - /* FIXME: Should also check in vtsi/vmgi status what kind of stream - * it is (ac3/lpcm/dts/sdds...) to find the right (sub)stream id */ - return streamN; -} - -/* Return the substream id for 'logical' subpicture stream subpN and given mode. - * 0 <= subpN < 32 - * mode == 0 - widescreen - * mode == 1 - letterbox - * mode == 2 - pan&scan - */ -int vm_get_subp_stream(vm_t *vm, int subpN, int mode) { - int streamN = -1; - int source_aspect = vm_get_video_aspect(vm); - - if((vm->state).domain != VTS_DOMAIN) - subpN = 0; - - if(subpN < 32) { /* a valid logical stream */ - /* Is this logical stream present */ - if((vm->state).pgc->subp_control[subpN] & (1<<31)) { - if(source_aspect == 0) /* 4:3 */ - streamN = ((vm->state).pgc->subp_control[subpN] >> 24) & 0x1f; - if(source_aspect == 3) /* 16:9 */ - switch (mode) { - case 0: - streamN = ((vm->state).pgc->subp_control[subpN] >> 16) & 0x1f; - break; - case 1: - streamN = ((vm->state).pgc->subp_control[subpN] >> 8) & 0x1f; - break; - case 2: - streamN = (vm->state).pgc->subp_control[subpN] & 0x1f; - } - } - } - - if((vm->state).domain != VTS_DOMAIN && streamN == -1) - streamN = 0; - - /* FIXME: Should also check in vtsi/vmgi status what kind of stream it is. */ - return streamN; -} - -int vm_get_audio_active_stream(vm_t *vm) { - int audioN; - int streamN; - audioN = (vm->state).AST_REG ; - streamN = vm_get_audio_stream(vm, audioN); - - /* If no such stream, then select the first one that exists. */ - if(streamN == -1) { - for(audioN = 0; audioN < 8; audioN++) { - if((vm->state).pgc->audio_control[audioN] & (1<<15)) { - if ((streamN = vm_get_audio_stream(vm, audioN)) >= 0) - break; - } - } - } - - return streamN; -} - -int vm_get_subp_active_stream(vm_t *vm, int mode) { - int subpN; - int streamN; - subpN = (vm->state).SPST_REG & ~0x40; - streamN = vm_get_subp_stream(vm, subpN, mode); - - /* If no such stream, then select the first one that exists. */ - if(streamN == -1) { - for(subpN = 0; subpN < 32; subpN++) { - if((vm->state).pgc->subp_control[subpN] & (1<<31)) { - if ((streamN = vm_get_subp_stream(vm, subpN, mode)) >= 0) - break; - } - } - } - - if((vm->state).domain == VTS_DOMAIN && !((vm->state).SPST_REG & 0x40)) - /* Bit 7 set means hide, and only let Forced display show */ - return (streamN | 0x80); - else - return streamN; -} - -void vm_get_angle_info(vm_t *vm, int *current, int *num_avail) { - *num_avail = 1; - *current = 1; - - if((vm->state).domain == VTS_DOMAIN) { - title_info_t *title; - /* TTN_REG does not allways point to the correct title.. */ - if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts) - return; - title = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1]; - if(title->title_set_nr != (vm->state).vtsN || - title->vts_ttn != (vm->state).VTS_TTN_REG) - return; - *num_avail = title->nr_of_angles; - *current = (vm->state).AGL_REG; - } -} - -#if 0 -/* currently unused */ -void vm_get_audio_info(vm_t *vm, int *current, int *num_avail) { - switch ((vm->state).domain) { - case VTS_DOMAIN: - *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_audio_streams; - *current = (vm->state).AST_REG; - break; - case VTSM_DOMAIN: - *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_audio_streams; /* 1 */ - *current = 1; - break; - case VMGM_DOMAIN: - case FP_DOMAIN: - *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_audio_streams; /* 1 */ - *current = 1; - break; - } -} - -/* currently unused */ -void vm_get_subp_info(vm_t *vm, int *current, int *num_avail) { - switch ((vm->state).domain) { - case VTS_DOMAIN: - *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_subp_streams; - *current = (vm->state).SPST_REG; - break; - case VTSM_DOMAIN: - *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_subp_streams; /* 1 */ - *current = 0x41; - break; - case VMGM_DOMAIN: - case FP_DOMAIN: - *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_subp_streams; /* 1 */ - *current = 0x41; - break; - } -} - -/* currently unused */ -void vm_get_video_res(vm_t *vm, int *width, int *height) { - video_attr_t attr = vm_get_video_attr(vm); - - if(attr.video_format != 0) - *height = 576; - else - *height = 480; - switch(attr.picture_size) { - case 0: - *width = 720; - break; - case 1: - *width = 704; - break; - case 2: - *width = 352; - break; - case 3: - *width = 352; - *height /= 2; - break; - } -} -#endif - -int vm_get_video_aspect(vm_t *vm) { - int aspect = vm_get_video_attr(vm).display_aspect_ratio; - - assert(aspect == 0 || aspect == 3); - (vm->state).registers.SPRM[14] &= ~(0x3 << 10); - (vm->state).registers.SPRM[14] |= aspect << 10; - - return aspect; -} - -int vm_get_video_scale_permission(vm_t *vm) { - return vm_get_video_attr(vm).permitted_df; -} - -video_attr_t vm_get_video_attr(vm_t *vm) { - switch ((vm->state).domain) { - case VTS_DOMAIN: - return vm->vtsi->vtsi_mat->vts_video_attr; - case VTSM_DOMAIN: - return vm->vtsi->vtsi_mat->vtsm_video_attr; - case VMGM_DOMAIN: - case FP_DOMAIN: - return vm->vmgi->vmgi_mat->vmgm_video_attr; - default: - abort(); - } -} - -audio_attr_t vm_get_audio_attr(vm_t *vm, int streamN) { - switch ((vm->state).domain) { - case VTS_DOMAIN: - return vm->vtsi->vtsi_mat->vts_audio_attr[streamN]; - case VTSM_DOMAIN: - return vm->vtsi->vtsi_mat->vtsm_audio_attr; - case VMGM_DOMAIN: - case FP_DOMAIN: - return vm->vmgi->vmgi_mat->vmgm_audio_attr; - default: - abort(); - } -} - -subp_attr_t vm_get_subp_attr(vm_t *vm, int streamN) { - switch ((vm->state).domain) { - case VTS_DOMAIN: - return vm->vtsi->vtsi_mat->vts_subp_attr[streamN]; - case VTSM_DOMAIN: - return vm->vtsi->vtsi_mat->vtsm_subp_attr; - case VMGM_DOMAIN: - case FP_DOMAIN: - return vm->vmgi->vmgi_mat->vmgm_subp_attr; - default: - abort(); - } -} - - -/* Playback control */ - -static link_t play_PGC(vm_t *vm) { - link_t link_values; - -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: play_PGC:"); - if((vm->state).domain != FP_DOMAIN) { - fprintf(MSG_OUT, " (vm->state).pgcN (%i)\n", get_PGCN(vm)); - } else { - fprintf(MSG_OUT, " first_play_pgc\n"); - } -#endif - - /* This must be set before the pre-commands are executed because they - * might contain a CallSS that will save resume state */ - - /* FIXME: This may be only a temporary fix for something... */ - (vm->state).pgN = 1; - (vm->state).cellN = 0; - (vm->state).blockN = 0; - - /* eval -> updates the state and returns either - - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN) - - just play video i.e first PG - (This is what happens if you fall of the end of the pre_cmds) - - or an error (are there more cases?) */ - if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) { - if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds, - (vm->state).pgc->command_tbl->nr_of_pre, - &(vm->state).registers, &link_values)) { - /* link_values contains the 'jump' return value */ - return link_values; - } else { -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: PGC pre commands didn't do a Jump, Link or Call\n"); -#endif - } - } - return play_PG(vm); -} - -static link_t play_PGC_PG(vm_t *vm, int pgN) { - link_t link_values; - -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: play_PGC_PG:"); - if((vm->state).domain != FP_DOMAIN) { - fprintf(MSG_OUT, " (vm->state).pgcN (%i)\n", get_PGCN(vm)); - } else { - fprintf(MSG_OUT, " first_play_pgc\n"); - } -#endif - - /* This must be set before the pre-commands are executed because they - * might contain a CallSS that will save resume state */ - - /* FIXME: This may be only a temporary fix for something... */ - (vm->state).pgN = pgN; - (vm->state).cellN = 0; - (vm->state).blockN = 0; - - /* eval -> updates the state and returns either - - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN) - - just play video i.e first PG - (This is what happens if you fall of the end of the pre_cmds) - - or an error (are there more cases?) */ - if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) { - if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds, - (vm->state).pgc->command_tbl->nr_of_pre, - &(vm->state).registers, &link_values)) { - /* link_values contains the 'jump' return value */ - return link_values; - } else { -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: PGC pre commands didn't do a Jump, Link or Call\n"); -#endif - } - } - return play_PG(vm); -} - -static link_t play_PGC_post(vm_t *vm) { - link_t link_values; - -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: play_PGC_post:\n"); -#endif - - /* eval -> updates the state and returns either - - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN) - - just go to next PGC - (This is what happens if you fall of the end of the post_cmds) - - or an error (are there more cases?) */ - if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_post && - vmEval_CMD((vm->state).pgc->command_tbl->post_cmds, - (vm->state).pgc->command_tbl->nr_of_post, - &(vm->state).registers, &link_values)) { - return link_values; - } - -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: ** Fell of the end of the pgc, continuing in NextPGC\n"); -#endif - /* Should end up in the STOP_DOMAIN if next_pgc is 0. */ - if(!set_PGCN(vm, (vm->state).pgc->next_pgc_nr)) { - link_values.command = Exit; - return link_values; - } - return play_PGC(vm); -} - -static link_t play_PG(vm_t *vm) { -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i)\n", (vm->state).pgN); -#endif - - assert((vm->state).pgN > 0); - if((vm->state).pgN > (vm->state).pgc->nr_of_programs) { -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i) > pgc->nr_of_programs (%i)\n", - (vm->state).pgN, (vm->state).pgc->nr_of_programs ); -#endif - assert((vm->state).pgN == (vm->state).pgc->nr_of_programs + 1); - return play_PGC_post(vm); - } - - (vm->state).cellN = (vm->state).pgc->program_map[(vm->state).pgN - 1]; - - return play_Cell(vm); -} - -static link_t play_Cell(vm_t *vm) { - static const link_t play_this = {PlayThis, /* Block in Cell */ 0, 0, 0}; - -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: play_Cell: (vm->state).cellN (%i)\n", (vm->state).cellN); -#endif - - assert((vm->state).cellN > 0); - if((vm->state).cellN > (vm->state).pgc->nr_of_cells) { -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: (vm->state).cellN (%i) > pgc->nr_of_cells (%i)\n", - (vm->state).cellN, (vm->state).pgc->nr_of_cells ); -#endif - assert((vm->state).cellN == (vm->state).pgc->nr_of_cells + 1); - return play_PGC_post(vm); - } - - /* Multi angle/Interleaved */ - switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) { - case 0: /* Normal */ - assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0); - break; - case 1: /* The first cell in the block */ - switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) { - case 0: /* Not part of a block */ - assert(0); - break; - case 1: /* Angle block */ - /* Loop and check each cell instead? So we don't get outside the block? */ - (vm->state).cellN += (vm->state).AGL_REG - 1; -#ifdef STRICT - assert((vm->state).cellN <= (vm->state).pgc->nr_of_cells); - assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0); - assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1); -#else - if (!((vm->state).cellN <= (vm->state).pgc->nr_of_cells) || - !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0) || - !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1)) { - fprintf(MSG_OUT, "libdvdnav: Invalid angle block\n"); - (vm->state).cellN -= (vm->state).AGL_REG - 1; - } -#endif - break; - case 2: /* ?? */ - case 3: /* ?? */ - default: - fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n", - (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode, - (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type); - assert(0); - } - break; - case 2: /* Cell in the block */ - case 3: /* Last cell in the block */ - /* These might perhaps happen for RSM or LinkC commands? */ - default: - fprintf(MSG_OUT, "libdvdnav: Cell is in block but did not enter at first cell!\n"); - } - - /* Updates (vm->state).pgN and PTTN_REG */ - if(!set_PGN(vm)) { - /* Should not happen */ - assert(0); - return play_PGC_post(vm); - } - (vm->state).cell_restart++; - (vm->state).blockN = 0; -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: Cell should restart here\n"); -#endif - return play_this; -} - -static link_t play_Cell_post(vm_t *vm) { - cell_playback_t *cell; - -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: play_Cell_post: (vm->state).cellN (%i)\n", (vm->state).cellN); -#endif - - cell = &(vm->state).pgc->cell_playback[(vm->state).cellN - 1]; - - /* Still time is already taken care of before we get called. */ - - /* Deal with a Cell command, if any */ - if(cell->cell_cmd_nr != 0) { - link_t link_values; - -/* These asserts are now not needed. - * Some DVDs have no cell commands listed in the PGC, - * but the Cell itself points to a cell command that does not exist. - * For this situation, just ignore the cell command and continue. - * - * assert((vm->state).pgc->command_tbl != NULL); - * assert((vm->state).pgc->command_tbl->nr_of_cell >= cell->cell_cmd_nr); - */ - - if ((vm->state).pgc->command_tbl != NULL && - (vm->state).pgc->command_tbl->nr_of_cell >= cell->cell_cmd_nr) { -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: Cell command present, executing\n"); -#endif - if(vmEval_CMD(&(vm->state).pgc->command_tbl->cell_cmds[cell->cell_cmd_nr - 1], 1, - &(vm->state).registers, &link_values)) { - return link_values; - } else { -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: Cell command didn't do a Jump, Link or Call\n"); -#endif - } - } else { -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: Invalid Cell command\n"); -#endif - } - } - - /* Where to continue after playing the cell... */ - /* Multi angle/Interleaved */ - switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) { - case 0: /* Normal */ - assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0); - (vm->state).cellN++; - break; - case 1: /* The first cell in the block */ - case 2: /* A cell in the block */ - case 3: /* The last cell in the block */ - default: - switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) { - case 0: /* Not part of a block */ - assert(0); - break; - case 1: /* Angle block */ - /* Skip the 'other' angles */ - (vm->state).cellN++; - while((vm->state).cellN <= (vm->state).pgc->nr_of_cells && - (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode >= 2) { - (vm->state).cellN++; - } - break; - case 2: /* ?? */ - case 3: /* ?? */ - default: - fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n", - (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode, - (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type); - assert(0); - } - break; - } - - /* Figure out the correct pgN for the new cell */ - if(!set_PGN(vm)) { -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: last cell in this PGC\n"); -#endif - return play_PGC_post(vm); - } - return play_Cell(vm); -} - - -/* link processing */ - -static int process_command(vm_t *vm, link_t link_values) { - - while(link_values.command != PlayThis) { - -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: Before printout starts:\n"); - vm_print_link(link_values); - fprintf(MSG_OUT, "libdvdnav: Link values %i %i %i %i\n", link_values.command, - link_values.data1, link_values.data2, link_values.data3); - vm_print_current_domain_state(vm); - fprintf(MSG_OUT, "libdvdnav: Before printout ends.\n"); -#endif - - switch(link_values.command) { - case LinkNoLink: - /* BUTTON number:data1 */ - if(link_values.data1 != 0) - (vm->state).HL_BTNN_REG = link_values.data1 << 10; - return 0; /* no actual jump */ - - case LinkTopC: - /* Restart playing from the beginning of the current Cell. */ - /* BUTTON number:data1 */ - if(link_values.data1 != 0) - (vm->state).HL_BTNN_REG = link_values.data1 << 10; - link_values = play_Cell(vm); - break; - case LinkNextC: - /* Link to Next Cell */ - /* BUTTON number:data1 */ - if(link_values.data1 != 0) - (vm->state).HL_BTNN_REG = link_values.data1 << 10; - (vm->state).cellN += 1; - link_values = play_Cell(vm); - break; - case LinkPrevC: - /* Link to Previous Cell */ - /* BUTTON number:data1 */ - if(link_values.data1 != 0) - (vm->state).HL_BTNN_REG = link_values.data1 << 10; - assert((vm->state).cellN > 1); - (vm->state).cellN -= 1; - link_values = play_Cell(vm); - break; - - case LinkTopPG: - /* Link to Top of current Program */ - /* BUTTON number:data1 */ - if(link_values.data1 != 0) - (vm->state).HL_BTNN_REG = link_values.data1 << 10; - link_values = play_PG(vm); - break; - case LinkNextPG: - /* Link to Next Program */ - /* BUTTON number:data1 */ - if(link_values.data1 != 0) - (vm->state).HL_BTNN_REG = link_values.data1 << 10; - (vm->state).pgN += 1; - link_values = play_PG(vm); - break; - case LinkPrevPG: - /* Link to Previous Program */ - /* BUTTON number:data1 */ - if(link_values.data1 != 0) - (vm->state).HL_BTNN_REG = link_values.data1 << 10; - assert((vm->state).pgN > 1); - (vm->state).pgN -= 1; - link_values = play_PG(vm); - break; - - case LinkTopPGC: - /* Restart playing from beginning of current Program Chain */ - /* BUTTON number:data1 */ - if(link_values.data1 != 0) - (vm->state).HL_BTNN_REG = link_values.data1 << 10; - link_values = play_PGC(vm); - break; - case LinkNextPGC: - /* Link to Next Program Chain */ - /* BUTTON number:data1 */ - if(link_values.data1 != 0) - (vm->state).HL_BTNN_REG = link_values.data1 << 10; - assert((vm->state).pgc->next_pgc_nr != 0); - if(set_PGCN(vm, (vm->state).pgc->next_pgc_nr)) - link_values = play_PGC(vm); - else - link_values.command = Exit; - break; - case LinkPrevPGC: - /* Link to Previous Program Chain */ - /* BUTTON number:data1 */ - if(link_values.data1 != 0) - (vm->state).HL_BTNN_REG = link_values.data1 << 10; - assert((vm->state).pgc->prev_pgc_nr != 0); - if(set_PGCN(vm, (vm->state).pgc->prev_pgc_nr)) - link_values = play_PGC(vm); - else - link_values.command = Exit; - break; - case LinkGoUpPGC: - /* Link to GoUp Program Chain */ - /* BUTTON number:data1 */ - if(link_values.data1 != 0) - (vm->state).HL_BTNN_REG = link_values.data1 << 10; - assert((vm->state).pgc->goup_pgc_nr != 0); - if(set_PGCN(vm, (vm->state).pgc->goup_pgc_nr)) - link_values = play_PGC(vm); - else - link_values.command = Exit; - break; - case LinkTailPGC: - /* Link to Tail of Program Chain */ - /* BUTTON number:data1 */ - if(link_values.data1 != 0) - (vm->state).HL_BTNN_REG = link_values.data1 << 10; - link_values = play_PGC_post(vm); - break; - - case LinkRSM: - { - /* Link to Resume point */ - int i; - - /* Check and see if there is any rsm info!! */ - if (!(vm->state).rsm_vtsN) { - fprintf(MSG_OUT, "libdvdnav: trying to resume without any resume info set\n"); - link_values.command = Exit; - break; - } - - (vm->state).domain = VTS_DOMAIN; - if (!ifoOpenNewVTSI(vm, vm->dvd, (vm->state).rsm_vtsN)) - assert(0); - set_PGCN(vm, (vm->state).rsm_pgcN); - - /* These should never be set in SystemSpace and/or MenuSpace */ - /* (vm->state).TTN_REG = rsm_tt; ?? */ - /* (vm->state).TT_PGCN_REG = (vm->state).rsm_pgcN; ?? */ - for(i = 0; i < 5; i++) { - (vm->state).registers.SPRM[4 + i] = (vm->state).rsm_regs[i]; - } - - if(link_values.data1 != 0) - (vm->state).HL_BTNN_REG = link_values.data1 << 10; - - if((vm->state).rsm_cellN == 0) { - assert((vm->state).cellN); /* Checking if this ever happens */ - (vm->state).pgN = 1; - link_values = play_PG(vm); - } else { - /* (vm->state).pgN = ?? this gets the right value in set_PGN() below */ - (vm->state).cellN = (vm->state).rsm_cellN; - link_values.command = PlayThis; - link_values.data1 = (vm->state).rsm_blockN & 0xffff; - link_values.data2 = (vm->state).rsm_blockN >> 16; - if(!set_PGN(vm)) { - /* Were at the end of the PGC, should not happen for a RSM */ - assert(0); - link_values.command = LinkTailPGC; - link_values.data1 = 0; /* No button */ - } - } - } - break; - case LinkPGCN: - /* Link to Program Chain Number:data1 */ - if(!set_PGCN(vm, link_values.data1)) - assert(0); - link_values = play_PGC(vm); - break; - case LinkPTTN: - /* Link to Part of current Title Number:data1 */ - /* BUTTON number:data2 */ - /* PGC Pre-Commands are not executed */ - assert((vm->state).domain == VTS_DOMAIN); - if(link_values.data2 != 0) - (vm->state).HL_BTNN_REG = link_values.data2 << 10; - if(!set_VTS_PTT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG, link_values.data1)) - assert(0); - link_values = play_PG(vm); - break; - case LinkPGN: - /* Link to Program Number:data1 */ - /* BUTTON number:data2 */ - if(link_values.data2 != 0) - (vm->state).HL_BTNN_REG = link_values.data2 << 10; - /* Update any other state, PTTN perhaps? */ - (vm->state).pgN = link_values.data1; - link_values = play_PG(vm); - break; - case LinkCN: - /* Link to Cell Number:data1 */ - /* BUTTON number:data2 */ - if(link_values.data2 != 0) - (vm->state).HL_BTNN_REG = link_values.data2 << 10; - /* Update any other state, pgN, PTTN perhaps? */ - (vm->state).cellN = link_values.data1; - link_values = play_Cell(vm); - break; - - case Exit: - vm->stopped = 1; - return 0; - - case JumpTT: - /* Jump to VTS Title Domain */ - /* Only allowed from the First Play domain(PGC) */ - /* or the Video Manager domain (VMG) */ - /* Stop SPRM9 Timer */ - /* Set SPRM1 and SPRM2 */ - assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ - if(set_TT(vm, link_values.data1)) - link_values = play_PGC(vm); - else - link_values.command = Exit; - break; - case JumpVTS_TT: - /* Jump to Title:data1 in same VTS Title Domain */ - /* Only allowed from the VTS Menu Domain(VTSM) */ - /* or the Video Title Set Domain(VTS) */ - /* Stop SPRM9 Timer */ - /* Set SPRM1 and SPRM2 */ - assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */ - if(!set_VTS_TT(vm, (vm->state).vtsN, link_values.data1)) - assert(0); - link_values = play_PGC(vm); - break; - case JumpVTS_PTT: - /* Jump to Part:data2 of Title:data1 in same VTS Title Domain */ - /* Only allowed from the VTS Menu Domain(VTSM) */ - /* or the Video Title Set Domain(VTS) */ - /* Stop SPRM9 Timer */ - /* Set SPRM1 and SPRM2 */ - assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */ - if(!set_VTS_PTT(vm, (vm->state).vtsN, link_values.data1, link_values.data2)) - assert(0); - link_values = play_PGC_PG(vm, (vm->state).pgN); - break; - - case JumpSS_FP: - /* Jump to First Play Domain */ - /* Only allowed from the VTS Menu Domain(VTSM) */ - /* or the Video Manager domain (VMG) */ - /* Stop SPRM9 Timer and any GPRM counters */ - assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN); /* ?? */ - if (!set_FP_PGC(vm)) - assert(0); - link_values = play_PGC(vm); - break; - case JumpSS_VMGM_MENU: - /* Jump to Video Manger domain - Title Menu:data1 or any PGC in VMG */ - /* Allowed from anywhere except the VTS Title domain */ - /* Stop SPRM9 Timer and any GPRM counters */ - assert((vm->state).domain != VTS_DOMAIN); /* ?? */ - (vm->state).domain = VMGM_DOMAIN; - if(!set_MENU(vm, link_values.data1)) - assert(0); - link_values = play_PGC(vm); - break; - case JumpSS_VTSM: - /* Jump to a menu in Video Title domain, */ - /* or to a Menu is the current VTS */ - /* Stop SPRM9 Timer and any GPRM counters */ - /* ifoOpenNewVTSI:data1 */ - /* VTS_TTN_REG:data2 */ - /* get_MENU:data3 */ - if(link_values.data1 != 0) { - if (link_values.data1 != (vm->state).vtsN) { - /* the normal case */ - assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ - (vm->state).domain = VTSM_DOMAIN; - if (!ifoOpenNewVTSI(vm, vm->dvd, link_values.data1)) /* Also sets (vm->state).vtsN */ - assert(0); - } else { - /* This happens on some discs like "Captain Scarlet & the Mysterons" or - * the German RC2 of "Anatomie" in VTSM. */ - assert((vm->state).domain == VTSM_DOMAIN || - (vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ - (vm->state).domain = VTSM_DOMAIN; - } - } else { - /* This happens on 'The Fifth Element' region 2. */ - assert((vm->state).domain == VTSM_DOMAIN); - } - /* I don't know what title is supposed to be used for. */ - /* Alien or Aliens has this != 1, I think. */ - /* assert(link_values.data2 == 1); */ - (vm->state).VTS_TTN_REG = link_values.data2; - /* TTN_REG (SPRM4), VTS_TTN_REG (SPRM5), TT_PGCN_REG (SPRM6) are linked, */ - /* so if one changes, the others must change to match it. */ - (vm->state).TTN_REG = get_TT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG); - if(!set_MENU(vm, link_values.data3)) - assert(0); - link_values = play_PGC(vm); - break; - case JumpSS_VMGM_PGC: - /* set_PGCN:data1 */ - /* Stop SPRM9 Timer and any GPRM counters */ - assert((vm->state).domain != VTS_DOMAIN); /* ?? */ - (vm->state).domain = VMGM_DOMAIN; - if(!set_PGCN(vm, link_values.data1)) - assert(0); - link_values = play_PGC(vm); - break; - - case CallSS_FP: - /* set_RSMinfo:data1 */ - assert((vm->state).domain == VTS_DOMAIN); /* ?? */ - /* Must be called before domain is changed */ - set_RSMinfo(vm, link_values.data1, /* We dont have block info */ 0); - set_FP_PGC(vm); - link_values = play_PGC(vm); - break; - case CallSS_VMGM_MENU: - /* set_MENU:data1 */ - /* set_RSMinfo:data2 */ - assert((vm->state).domain == VTS_DOMAIN); /* ?? */ - /* Must be called before domain is changed */ - set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0); - (vm->state).domain = VMGM_DOMAIN; - if(!set_MENU(vm, link_values.data1)) - assert(0); - link_values = play_PGC(vm); - break; - case CallSS_VTSM: - /* set_MENU:data1 */ - /* set_RSMinfo:data2 */ - assert((vm->state).domain == VTS_DOMAIN); /* ?? */ - /* Must be called before domain is changed */ - set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0); - (vm->state).domain = VTSM_DOMAIN; - if(!set_MENU(vm, link_values.data1)) - assert(0); - link_values = play_PGC(vm); - break; - case CallSS_VMGM_PGC: - /* set_PGC:data1 */ - /* set_RSMinfo:data2 */ - assert((vm->state).domain == VTS_DOMAIN); /* ?? */ - /* Must be called before domain is changed */ - set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0); - (vm->state).domain = VMGM_DOMAIN; - if(!set_PGCN(vm, link_values.data1)) - assert(0); - link_values = play_PGC(vm); - break; - case PlayThis: - /* Should never happen. */ - assert(0); - break; - } - -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: After printout starts:\n"); - vm_print_current_domain_state(vm); - fprintf(MSG_OUT, "libdvdnav: After printout ends.\n"); -#endif - - } - (vm->state).blockN = link_values.data1 | (link_values.data2 << 16); - return 1; -} - - -/* Set functions */ - -static int set_TT(vm_t *vm, int tt) { - return set_PTT(vm, tt, 1); -} - -static int set_PTT(vm_t *vm, int tt, int ptt) { - assert(tt <= vm->vmgi->tt_srpt->nr_of_srpts); - return set_VTS_PTT(vm, vm->vmgi->tt_srpt->title[tt - 1].title_set_nr, - vm->vmgi->tt_srpt->title[tt - 1].vts_ttn, ptt); -} - -static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn) { - return set_VTS_PTT(vm, vtsN, vts_ttn, 1); -} - -static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part) { - int pgcN, pgN, res; - - (vm->state).domain = VTS_DOMAIN; - - if (vtsN != (vm->state).vtsN) - if (!ifoOpenNewVTSI(vm, vm->dvd, vtsN)) /* Also sets (vm->state).vtsN */ - return 0; - - if ((vts_ttn < 1) || (vts_ttn > vm->vtsi->vts_ptt_srpt->nr_of_srpts) || - (part < 1) || (part > vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].nr_of_ptts) ) { - return 0; - } - - pgcN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgcn; - pgN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgn; - - (vm->state).TT_PGCN_REG = pgcN; - (vm->state).PTTN_REG = part; - (vm->state).TTN_REG = get_TT(vm, vtsN, vts_ttn); - assert( (vm->state.TTN_REG) != 0 ); - (vm->state).VTS_TTN_REG = vts_ttn; - (vm->state).vtsN = vtsN; /* Not sure about this one. We can get to it easily from TTN_REG */ - /* Any other registers? */ - - res = set_PGCN(vm, pgcN); /* This clobber's state.pgN (sets it to 1), but we don't want clobbering here. */ - (vm->state).pgN = pgN; - return res; -} - -static int set_FP_PGC(vm_t *vm) { - (vm->state).domain = FP_DOMAIN; - if (!vm->vmgi->first_play_pgc) { - return set_PGCN(vm, 1); - } - (vm->state).pgc = vm->vmgi->first_play_pgc; - (vm->state).pgcN = vm->vmgi->vmgi_mat->first_play_pgc; - return 1; -} - - -static int set_MENU(vm_t *vm, int menu) { - assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN); - return set_PGCN(vm, get_ID(vm, menu)); -} - -static int set_PGCN(vm_t *vm, int pgcN) { - pgcit_t *pgcit; - - pgcit = get_PGCIT(vm); - assert(pgcit != NULL); /* ?? Make this return -1 instead */ - - if(pgcN < 1 || pgcN > pgcit->nr_of_pgci_srp) { -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: ** No such pgcN = %d\n", pgcN); -#endif - return 0; - } - - (vm->state).pgc = pgcit->pgci_srp[pgcN - 1].pgc; - (vm->state).pgcN = pgcN; - (vm->state).pgN = 1; - - if((vm->state).domain == VTS_DOMAIN) - (vm->state).TT_PGCN_REG = pgcN; - - return 1; -} - -/* Figure out the correct pgN from the cell and update (vm->state). */ -static int set_PGN(vm_t *vm) { - int new_pgN = 0; - - while(new_pgN < (vm->state).pgc->nr_of_programs - && (vm->state).cellN >= (vm->state).pgc->program_map[new_pgN]) - new_pgN++; - - if(new_pgN == (vm->state).pgc->nr_of_programs) /* We are at the last program */ - if((vm->state).cellN > (vm->state).pgc->nr_of_cells) - return 0; /* We are past the last cell */ - - (vm->state).pgN = new_pgN; - - if((vm->state).domain == VTS_DOMAIN) { - playback_type_t *pb_ty; - if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts) - return 0; /* ?? */ - pb_ty = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1].pb_ty; - if(pb_ty->multi_or_random_pgc_title == /* One_Sequential_PGC_Title */ 0) { - int dummy, part; - vm_get_current_title_part(vm, &dummy, &part); - (vm->state).PTTN_REG = part; - } else { - /* FIXME: Handle RANDOM or SHUFFLE titles. */ - fprintf(MSG_OUT, "libdvdnav: RANDOM or SHUFFLE titles are NOT handled yet.\n"); - } - } - return 1; -} - -/* Must be called before domain is changed (set_PGCN()) */ -static void set_RSMinfo(vm_t *vm, int cellN, int blockN) { - int i; - - if(cellN) { - (vm->state).rsm_cellN = cellN; - (vm->state).rsm_blockN = blockN; - } else { - (vm->state).rsm_cellN = (vm->state).cellN; - (vm->state).rsm_blockN = blockN; - } - (vm->state).rsm_vtsN = (vm->state).vtsN; - (vm->state).rsm_pgcN = get_PGCN(vm); - - /* assert((vm->state).rsm_pgcN == (vm->state).TT_PGCN_REG); for VTS_DOMAIN */ - - for(i = 0; i < 5; i++) { - (vm->state).rsm_regs[i] = (vm->state).registers.SPRM[4 + i]; - } -} - - -/* Get functions */ - -/* Searches the TT tables, to find the current TT. - * returns the current TT. - * returns 0 if not found. - */ -static int get_TT(vm_t *vm, int vtsN, int vts_ttn) { - int i; - int tt=0; - - for(i = 1; i <= vm->vmgi->tt_srpt->nr_of_srpts; i++) { - if( vm->vmgi->tt_srpt->title[i - 1].title_set_nr == vtsN && - vm->vmgi->tt_srpt->title[i - 1].vts_ttn == vts_ttn) { - tt=i; - break; - } - } - return tt; -} - -/* Search for entry_id match of the PGC Category in the current VTS PGCIT table. - * Return pgcN based on entry_id match. - */ -static int get_ID(vm_t *vm, int id) { - int pgcN, i; - pgcit_t *pgcit; - - /* Relies on state to get the correct pgcit. */ - pgcit = get_PGCIT(vm); - assert(pgcit != NULL); -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: ** Searching for menu (0x%x) entry PGC\n", id); -#endif - - /* Force high bit set. */ - id |=0x80; - - /* Get menu/title */ - for(i = 0; i < pgcit->nr_of_pgci_srp; i++) { - if( (pgcit->pgci_srp[i].entry_id) == id) { - pgcN = i + 1; -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: Found menu.\n"); -#endif - return pgcN; - } - } -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: ** No such id/menu (0x%02x) entry PGC\n", id & 0x7f); - for(i = 0; i < pgcit->nr_of_pgci_srp; i++) { - if ( (pgcit->pgci_srp[i].entry_id & 0x80) == 0x80) { - fprintf(MSG_OUT, "libdvdnav: Available menus: 0x%x\n", - pgcit->pgci_srp[i].entry_id & 0x7f); - } - } -#endif - return 0; /* error */ -} - -/* FIXME: we have a pgcN member in the vm's state now, so this should be obsolete */ -static int get_PGCN(vm_t *vm) { - pgcit_t *pgcit; - int pgcN = 1; - - pgcit = get_PGCIT(vm); - - if (pgcit) { - while(pgcN <= pgcit->nr_of_pgci_srp) { - if(pgcit->pgci_srp[pgcN - 1].pgc == (vm->state).pgc) { - assert((vm->state).pgcN == pgcN); - return pgcN; - } - pgcN++; - } - } - fprintf(MSG_OUT, "libdvdnav: get_PGCN failed. Was trying to find pgcN in domain %d\n", - (vm->state).domain); - return 0; /* error */ -} - -static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang) { - int i; - - if(h == NULL || h->pgci_ut == NULL) { - fprintf(MSG_OUT, "libdvdnav: *** pgci_ut handle is NULL ***\n"); - return NULL; /* error? */ - } - - i = 0; - while(i < h->pgci_ut->nr_of_lus - && h->pgci_ut->lu[i].lang_code != lang) - i++; - if(i == h->pgci_ut->nr_of_lus) { - fprintf(MSG_OUT, "libdvdnav: Language '%c%c' not found, using '%c%c' instead\n", - (char)(lang >> 8), (char)(lang & 0xff), - (char)(h->pgci_ut->lu[0].lang_code >> 8), - (char)(h->pgci_ut->lu[0].lang_code & 0xff)); - fprintf(MSG_OUT, "libdvdnav: Menu Languages available: "); - for(i = 0; i < h->pgci_ut->nr_of_lus; i++) { - fprintf(MSG_OUT, "%c%c ", - (char)(h->pgci_ut->lu[i].lang_code >> 8), - (char)(h->pgci_ut->lu[i].lang_code & 0xff)); - } - fprintf(MSG_OUT, "\n"); - i = 0; /* error? */ - } - - return h->pgci_ut->lu[i].pgcit; -} - -/* Uses state to decide what to return */ -static pgcit_t* get_PGCIT(vm_t *vm) { - pgcit_t *pgcit = NULL; - - switch ((vm->state).domain) { - case VTS_DOMAIN: - if(!vm->vtsi) return NULL; - pgcit = vm->vtsi->vts_pgcit; - break; - case VTSM_DOMAIN: - if(!vm->vtsi) return NULL; - pgcit = get_MENU_PGCIT(vm, vm->vtsi, (vm->state).registers.SPRM[0]); - break; - case VMGM_DOMAIN: - case FP_DOMAIN: - pgcit = get_MENU_PGCIT(vm, vm->vmgi, (vm->state).registers.SPRM[0]); - break; - default: - abort(); - } - - return pgcit; -} - -//return the ifo_handle_t describing required title, used to -//identify chapters -ifo_handle_t *vm_get_title_ifo(vm_t *vm, uint32_t title) -{ - ifo_handle_t *ifo = NULL; - uint8_t titleset_nr; - if((title < 1) || (title > vm->vmgi->tt_srpt->nr_of_srpts)) - return NULL; - titleset_nr = vm->vmgi->tt_srpt->title[title-1].title_set_nr; - ifo = ifoOpen(vm->dvd, titleset_nr); - return ifo; -} - -void vm_ifo_close(ifo_handle_t *ifo) -{ - ifoClose(ifo); -} - -/* Debug functions */ - -#ifdef TRACE -void vm_position_print(vm_t *vm, vm_position_t *position) { - fprintf(MSG_OUT, "libdvdnav: But=%x Spu=%x Aud=%x Ang=%x Hop=%x vts=%x dom=%x cell=%x cell_restart=%x cell_start=%x still=%x block=%x\n", - position->button, - position->spu_channel, - position->audio_channel, - position->angle_channel, - position->hop_channel, - position->vts, - position->domain, - position->cell, - position->cell_restart, - position->cell_start, - position->still, - position->block); -} -#endif - diff -r 427b7da5cbdb -r 1c897db44135 vm/vm.h --- a/vm/vm.h Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Håkan Hjort - * Copyright (C) 2001 Rich Wareham - * - * This file is part of libdvdnav, a DVD navigation library. It is modified - * from a file originally part of the Ogle DVD player. - * - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -#ifndef VM_H_INCLUDED -#define VM_H_INCLUDED - -/* DOMAIN enum */ - -typedef enum { - FP_DOMAIN = 1, - VTS_DOMAIN = 2, - VMGM_DOMAIN = 4, - VTSM_DOMAIN = 8 -} domain_t; - -/** - * State: SPRM, GPRM, Domain, pgc, pgN, cellN, ? - */ -typedef struct { - registers_t registers; - - domain_t domain; - int vtsN; /* 0 is vmgm? */ - pgc_t *pgc; /* either this or 'int pgcN' is enough? */ - int pgcN; /* but provide pgcN for quick lookup */ - int pgN; /* is this needed? can allways fid pgN from cellN? */ - int cellN; - int32_t cell_restart; /* get cell to restart */ - int blockN; - - /* Resume info */ - int rsm_vtsN; - int rsm_blockN; /* of nav_packet */ - uint16_t rsm_regs[5]; /* system registers 4-8 */ - int rsm_pgcN; - int rsm_cellN; -} dvd_state_t; - -typedef struct vm_position_s { - int16_t button; /* Button highlighted */ - int32_t vts; /* vts number to use */ - domain_t domain; /* domain to use */ - int32_t spu_channel; /* spu channel to use */ - int32_t angle_channel; /* angle channel to use */ - int32_t audio_channel; /* audio channel to use */ - int32_t hop_channel; /* channel hopping. E.g menu button pressed */ -#if 0 - /* currently unused */ - int32_t title; /* title number */ - int32_t chapter; /* chapter number */ -#endif - int32_t cell; /* cell number */ - int32_t cell_restart; /* get cell to restart */ - int32_t cell_start; /* sector number of start of current cell in use */ - int32_t still; /* is cell still */ - int32_t block; /* block number within cell in use */ -} vm_position_t; - -typedef struct { - dvd_reader_t *dvd; - ifo_handle_t *vmgi; - ifo_handle_t *vtsi; - dvd_state_t state; - int32_t hop_channel; - char dvd_name[50]; - remap_t *map; - int stopped; -} vm_t; - -/* magic number for seeking hops */ -#define HOP_SEEK 0x1000 - - -/* Audio stream number */ -#define AST_REG registers.SPRM[1] -/* Subpicture stream number */ -#define SPST_REG registers.SPRM[2] -/* Angle number */ -#define AGL_REG registers.SPRM[3] -/* Title Track Number */ -#define TTN_REG registers.SPRM[4] -/* VTS Title Track Number */ -#define VTS_TTN_REG registers.SPRM[5] -/* PGC Number for this Title Track */ -#define TT_PGCN_REG registers.SPRM[6] -/* Current Part of Title (PTT) number for (One_Sequential_PGC_Title) */ -#define PTTN_REG registers.SPRM[7] -/* Highlighted Button Number (btn nr 1 == value 1024) */ -#define HL_BTNN_REG registers.SPRM[8] -/* Parental Level */ -#define PTL_REG registers.SPRM[13] - -/* Initialisation & destruction */ -vm_t *vm_new_vm(void); -void vm_free_vm(vm_t *vm); - -/* IFO access */ -ifo_handle_t *vm_get_vmgi(vm_t *vm); -ifo_handle_t *vm_get_vtsi(vm_t *vm); - -/* Reader Access */ -dvd_reader_t *vm_get_dvd_reader(vm_t *vm); - -/* Basic Handling */ -int vm_start(vm_t *vm); -void vm_stop(vm_t *vm); -int vm_reset(vm_t *vm, const char *dvdroot); - -/* copying and merging - useful for try-running an operation */ -vm_t *vm_new_copy(vm_t *vm); -void vm_merge(vm_t *target, vm_t *source); -void vm_free_copy(vm_t *vm); - -/* regular playback */ -void vm_position_get(vm_t *vm, vm_position_t *position); -void vm_get_next_cell(vm_t *vm); - -/* Jumping - all these return 1, if a hop has been performed */ -int vm_jump_pg(vm_t *vm, int pg); -int vm_jump_cell_block(vm_t *vm, int cell, int block); -int vm_jump_title_part(vm_t *vm, int title, int part); -int vm_jump_top_pg(vm_t *vm); -int vm_jump_next_pg(vm_t *vm); -int vm_jump_prev_pg(vm_t *vm); -int vm_jump_up(vm_t *vm); -int vm_jump_menu(vm_t *vm, DVDMenuID_t menuid); -int vm_jump_resume(vm_t *vm); -int vm_exec_cmd(vm_t *vm, vm_cmd_t *cmd); - -/* getting information */ -int vm_get_current_menu(vm_t *vm, int *menuid); -int vm_get_current_title_part(vm_t *vm, int *title_result, int *part_result); -int vm_get_audio_stream(vm_t *vm, int audioN); -int vm_get_subp_stream(vm_t *vm, int subpN, int mode); -int vm_get_audio_active_stream(vm_t *vm); -int vm_get_subp_active_stream(vm_t *vm, int mode); -void vm_get_angle_info(vm_t *vm, int *current, int *num_avail); -#if 0 -/* currently unused */ -void vm_get_audio_info(vm_t *vm, int *current, int *num_avail); -void vm_get_subp_info(vm_t *vm, int *current, int *num_avail); -void vm_get_video_res(vm_t *vm, int *width, int *height); -#endif -int vm_get_video_aspect(vm_t *vm); -int vm_get_video_scale_permission(vm_t *vm); -video_attr_t vm_get_video_attr(vm_t *vm); -audio_attr_t vm_get_audio_attr(vm_t *vm, int streamN); -subp_attr_t vm_get_subp_attr(vm_t *vm, int streamN); -ifo_handle_t *vm_get_title_ifo(vm_t *vm, uint32_t title); -void vm_ifo_close(ifo_handle_t *ifo); - -/* Uncomment for VM command tracing */ -/* #define TRACE */ -#ifdef TRACE -/* Debug */ -void vm_position_print(vm_t *vm, vm_position_t *position); -#endif - - -#endif /* VM_HV_INCLUDED */ diff -r 427b7da5cbdb -r 1c897db44135 vm/vmcmd.c --- a/vm/vmcmd.c Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,549 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Martin Norbäck, Håkan Hjort - * 2002-2004 the dvdnav project - * - * This file is part of libdvdnav, a DVD navigation library. It is modified - * from a file originally part of the Ogle DVD player. - * - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "dvd_types.h" -#include "nav_types.h" -#include "ifo_types.h" -#include "decoder.h" -#include "remap.h" -#include "vm.h" -#include "vmcmd.h" -#include "dvdnav.h" -#include "dvdnav_internal.h" - -/* freebsd compatibility */ -#ifndef PRIu8 -#define PRIu8 "d" -#endif - -/* freebsd compatibility */ -#ifndef PRIu16 -#define PRIu16 "d" -#endif - -static const char cmp_op_table[][4] = { - "", "&", "==", "!=", ">=", ">", "<=", "<" -}; -static const char set_op_table[][4] = { - "", "=", "<->", "+=", "-=", "*=", "/=", "%=", "rnd", "&=", "|=", "^=" -}; - -static const char link_table[][16] = { - "LinkNoLink", "LinkTopC", "LinkNextC", "LinkPrevC", - "", "LinkTopPG", "LinkNextPG", "LinkPrevPG", - "", "LinkTopPGC", "LinkNextPGC", "LinkPrevPGC", - "LinkGoUpPGC", "LinkTailPGC", "", "", - "RSM" -}; - -static const char *const system_reg_table[] = { - "Menu Description Language Code", - "Audio Stream Number", - "Sub-picture Stream Number", - "Angle Number", - "Title Track Number", - "VTS Title Track Number", - "VTS PGC Number", - "PTT Number for One_Sequential_PGC_Title", - "Highlighted Button Number", - "Navigation Timer", - "Title PGC Number for Navigation Timer", - "Audio Mixing Mode for Karaoke", - "Country Code for Parental Management", - "Parental Level", - "Player Configurations for Video", - "Player Configurations for Audio", - "Initial Language Code for Audio", - "Initial Language Code Extension for Audio", - "Initial Language Code for Sub-picture", - "Initial Language Code Extension for Sub-picture", - "Player Regional Code", - "Reserved 21", - "Reserved 22", - "Reserved 23" -}; - -static const char system_reg_abbr_table[][8] = { - "", - "ASTN", - "SPSTN", - "AGLN", - "TTN", - "VTS_TTN", - "TT_PGCN", - "PTTN", - "HL_BTNN", - "NVTMR", - "NV_PGCN", - "", - "CC_PLT", - "PLT", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", -}; - -static void print_system_reg(uint16_t reg) { - if(reg < sizeof(system_reg_abbr_table) / sizeof(system_reg_abbr_table[0])) - fprintf(MSG_OUT, "%s (SRPM:%d)", system_reg_table[reg], reg); - else - fprintf(MSG_OUT, " WARNING: Unknown system register ( reg=%d ) ", reg); -} - -static void print_g_reg(uint8_t reg) { - if(reg < 16) - fprintf(MSG_OUT, "g[%" PRIu8 "]", reg); - else - fprintf(MSG_OUT, " WARNING: Unknown general register "); -} - -static void print_reg(uint8_t reg) { - if(reg & 0x80) - print_system_reg(reg & 0x7f); - else - print_g_reg(reg & 0x7f); -} - -static void print_cmp_op(uint8_t op) { - if(op < sizeof(cmp_op_table) / sizeof(cmp_op_table[0])) - fprintf(MSG_OUT, " %s ", cmp_op_table[op]); - else - fprintf(MSG_OUT, " WARNING: Unknown compare op "); -} - -static void print_set_op(uint8_t op) { - if(op < sizeof(set_op_table) / sizeof(cmp_op_table[0])) - fprintf(MSG_OUT, " %s ", set_op_table[op]); - else - fprintf(MSG_OUT, " WARNING: Unknown set op "); -} - -static void print_reg_or_data(command_t* command, int immediate, int start) { - if(immediate) { - uint32_t i = vm_getbits(command, start, 16); - - fprintf(MSG_OUT, "0x%x", i); - if(isprint(i & 0xff) && isprint((i>>8) & 0xff)) - fprintf(MSG_OUT, " (\"%c%c\")", (char)((i>>8) & 0xff), (char)(i & 0xff)); - } else { - print_reg(vm_getbits(command, start - 8, 8)); - } -} - -static void print_reg_or_data_2(command_t* command, int immediate, int start) { - if(immediate) - fprintf(MSG_OUT, "0x%x", vm_getbits(command, start - 1, 7)); - else - fprintf(MSG_OUT, "g[%" PRIu8 "]", vm_getbits(command, start - 4, 4)); -} - -static void print_reg_or_data_3(command_t* command, int immediate, int start) { - if(immediate) { - uint32_t i = vm_getbits(command, start, 16); - - fprintf(MSG_OUT, "0x%x", i); - if(isprint(i & 0xff) && isprint((i>>8) & 0xff)) - fprintf(MSG_OUT, " (\"%c%c\")", (char)((i>>8) & 0xff), (char)(i & 0xff)); - } else { - print_reg(vm_getbits(command, start, 8)); - } -} - - -static void print_if_version_1(command_t* command) { - uint8_t op = vm_getbits(command, 54, 3); - - if(op) { - fprintf(MSG_OUT, "if ("); - print_g_reg(vm_getbits(command,39,8)); - print_cmp_op(op); - print_reg_or_data(command, vm_getbits(command, 55,1), 31); - fprintf(MSG_OUT, ") "); - } -} - -static void print_if_version_2(command_t* command) { - uint8_t op = vm_getbits(command, 54, 3); - - if(op) { - fprintf(MSG_OUT, "if ("); - print_reg(vm_getbits(command, 15, 8)); - print_cmp_op(op); - print_reg(vm_getbits(command, 7, 8)); - fprintf(MSG_OUT, ") "); - } -} - -static void print_if_version_3(command_t* command) { - uint8_t op = vm_getbits(command, 54, 3); - - if(op) { - fprintf(MSG_OUT, "if ("); - print_g_reg(vm_getbits(command, 43, 4)); - print_cmp_op(op); - print_reg_or_data(command, vm_getbits(command, 55, 1), 15); - fprintf(MSG_OUT, ") "); - } -} - -static void print_if_version_4(command_t* command) { - uint8_t op = vm_getbits(command, 54, 3); - - if(op) { - fprintf(MSG_OUT, "if ("); - print_g_reg(vm_getbits(command, 51, 4)); - print_cmp_op(op); - print_reg_or_data(command, vm_getbits(command, 55, 1), 31); - fprintf(MSG_OUT, ") "); - } -} - -static void print_if_version_5(command_t* command) { - uint8_t op = vm_getbits(command, 54, 3); - int set_immediate = vm_getbits(command, 60, 1); - - if(op) { - if (set_immediate) { - fprintf(MSG_OUT, "if ("); - print_g_reg(vm_getbits(command, 31, 8)); - print_cmp_op(op); - print_reg(vm_getbits(command, 23, 8)); - fprintf(MSG_OUT, ") "); - } else { - fprintf(MSG_OUT, "if ("); - print_g_reg(vm_getbits(command, 39, 8)); - print_cmp_op(op); - print_reg_or_data(command, vm_getbits(command, 55, 1), 31); - fprintf(MSG_OUT, ") "); - } - } -} - -static void print_special_instruction(command_t* command) { - uint8_t op = vm_getbits(command, 51, 4); - - switch(op) { - case 0: /* NOP */ - fprintf(MSG_OUT, "Nop"); - break; - case 1: /* Goto line */ - fprintf(MSG_OUT, "Goto %" PRIu8, vm_getbits(command, 7, 8)); - break; - case 2: /* Break */ - fprintf(MSG_OUT, "Break"); - break; - case 3: /* Parental level */ - fprintf(MSG_OUT, "SetTmpPML %" PRIu8 ", Goto %" PRIu8, - vm_getbits(command, 11, 4), vm_getbits(command, 7, 8)); - break; - default: - fprintf(MSG_OUT, "WARNING: Unknown special instruction (%i)", - vm_getbits(command, 51, 4)); - } -} - -static void print_linksub_instruction(command_t* command) { - uint32_t linkop = vm_getbits(command, 7, 8); - uint32_t button = vm_getbits(command, 15, 6); - - if(linkop < sizeof(link_table)/sizeof(link_table[0])) - fprintf(MSG_OUT, "%s (button %" PRIu8 ")", link_table[linkop], button); - else - fprintf(MSG_OUT, "WARNING: Unknown linksub instruction (%i)", linkop); -} - -static void print_link_instruction(command_t* command, int optional) { - uint8_t op = vm_getbits(command, 51, 4); - - if(optional && op) - fprintf(MSG_OUT, ", "); - - switch(op) { - case 0: - if(!optional) - fprintf(MSG_OUT, "WARNING: NOP (link)!"); - break; - case 1: - print_linksub_instruction(command); - break; - case 4: - fprintf(MSG_OUT, "LinkPGCN %" PRIu16, vm_getbits(command, 14, 15)); - break; - case 5: - fprintf(MSG_OUT, "LinkPTT %" PRIu16 " (button %" PRIu8 ")", - vm_getbits(command, 9, 10), vm_getbits(command, 15, 6)); - break; - case 6: - fprintf(MSG_OUT, "LinkPGN %" PRIu8 " (button %" PRIu8 ")", - vm_getbits(command, 6, 7), vm_getbits(command, 15, 6)); - break; - case 7: - fprintf(MSG_OUT, "LinkCN %" PRIu8 " (button %" PRIu8 ")", - vm_getbits(command, 7, 8), vm_getbits(command, 15, 6)); - break; - default: - fprintf(MSG_OUT, "WARNING: Unknown link instruction"); - } -} - -static void print_jump_instruction(command_t* command) { - switch(vm_getbits(command, 51, 4)) { - case 1: - fprintf(MSG_OUT, "Exit"); - break; - case 2: - fprintf(MSG_OUT, "JumpTT %" PRIu8, vm_getbits(command, 22, 7)); - break; - case 3: - fprintf(MSG_OUT, "JumpVTS_TT %" PRIu8, vm_getbits(command, 22, 7)); - break; - case 5: - fprintf(MSG_OUT, "JumpVTS_PTT %" PRIu8 ":%" PRIu16, - vm_getbits(command, 22, 7), vm_getbits(command, 41, 10)); - break; - case 6: - switch(vm_getbits(command, 23, 2)) { - case 0: - fprintf(MSG_OUT, "JumpSS FP"); - break; - case 1: - fprintf(MSG_OUT, "JumpSS VMGM (menu %" PRIu8 ")", vm_getbits(command, 19, 4)); - break; - case 2: - fprintf(MSG_OUT, "JumpSS VTSM (vts %" PRIu8 ", title %" PRIu8 - ", menu %" PRIu8 ")", vm_getbits(command, 30, 7), vm_getbits(command, 38, 7), vm_getbits(command, 19, 4)); - break; - case 3: - fprintf(MSG_OUT, "JumpSS VMGM (pgc %" PRIu8 ")", vm_getbits(command, 46, 15)); - break; - } - break; - case 8: - switch(vm_getbits(command, 23, 2)) { - case 0: - fprintf(MSG_OUT, "CallSS FP (rsm_cell %" PRIu8 ")", - vm_getbits(command, 31, 8)); - break; - case 1: - fprintf(MSG_OUT, "CallSS VMGM (menu %" PRIu8 - ", rsm_cell %" PRIu8 ")", vm_getbits(command, 19, 4), vm_getbits(command, 31, 8)); - break; - case 2: - fprintf(MSG_OUT, "CallSS VTSM (menu %" PRIu8 - ", rsm_cell %" PRIu8 ")", vm_getbits(command, 19, 4), vm_getbits(command, 31, 8)); - break; - case 3: - fprintf(MSG_OUT, "CallSS VMGM (pgc %" PRIu8 ", rsm_cell %" PRIu8 ")", - vm_getbits(command, 46, 15), vm_getbits(command, 31, 8)); - break; - } - break; - default: - fprintf(MSG_OUT, "WARNING: Unknown Jump/Call instruction"); - } -} - -static void print_system_set(command_t* command) { - int i; -/* FIXME: What about SPRM11 ? Karaoke */ -/* Surely there must be some system set command for that ? */ - - switch(vm_getbits(command, 59, 4)) { - case 1: /* Set system reg 1 &| 2 &| 3 (Audio, Subp. Angle) */ - for(i = 1; i <= 3; i++) { - if(vm_getbits(command, 47 - (i*8), 1)) { - print_system_reg(i); - fprintf(MSG_OUT, " = "); - print_reg_or_data_2(command, vm_getbits(command, 60, 1), 47 - (i*8) ); - fprintf(MSG_OUT, " "); - } - } - break; - case 2: /* Set system reg 9 & 10 (Navigation timer, Title PGC number) */ - print_system_reg(9); - fprintf(MSG_OUT, " = "); - print_reg_or_data(command, vm_getbits(command, 60, 1), 47); - fprintf(MSG_OUT, " "); - print_system_reg(10); - fprintf(MSG_OUT, " = %" PRIu16, vm_getbits(command, 30, 15)); /* ?? */ - break; - case 3: /* Mode: Counter / Register + Set */ - fprintf(MSG_OUT, "SetMode "); - if(vm_getbits(command, 23, 1)) - fprintf(MSG_OUT, "Counter "); - else - fprintf(MSG_OUT, "Register "); - print_g_reg(vm_getbits(command, 19, 4)); - print_set_op(0x1); /* '=' */ - print_reg_or_data(command, vm_getbits(command, 60, 1), 47); - break; - case 6: /* Set system reg 8 (Highlighted button) */ - print_system_reg(8); - if(vm_getbits(command, 60, 1)) /* immediate */ - fprintf(MSG_OUT, " = 0x%x (button no %d)", vm_getbits(command, 31, 16), vm_getbits(command, 31, 6)); - else - fprintf(MSG_OUT, " = g[%" PRIu8 "]", vm_getbits(command, 19, 4)); - break; - default: - fprintf(MSG_OUT, "WARNING: Unknown system set instruction (%i)", - vm_getbits(command, 59, 4)); - } -} - -static void print_set_version_1(command_t* command) { - uint8_t set_op = vm_getbits(command, 59, 4); - - if(set_op) { - print_g_reg(vm_getbits(command, 35, 4)); - print_set_op(set_op); - print_reg_or_data(command, vm_getbits(command, 60, 1), 31); - } else { - fprintf(MSG_OUT, "NOP"); - } -} - -static void print_set_version_2(command_t* command) { - uint8_t set_op = vm_getbits(command, 59, 4); - - if(set_op) { - print_g_reg(vm_getbits(command, 51, 4)); - print_set_op(set_op); - print_reg_or_data(command, vm_getbits(command, 60, 1), 47); - } else { - fprintf(MSG_OUT, "NOP"); - } -} - -static void print_set_version_3(command_t* command) { - uint8_t set_op = vm_getbits(command, 59, 4); - - if(set_op) { - print_g_reg(vm_getbits(command, 51, 4)); - print_set_op(set_op); - print_reg_or_data_3(command, vm_getbits(command, 60, 1), 47); - } else { - fprintf(MSG_OUT, "NOP"); - } -} - - -void vm_print_mnemonic(vm_cmd_t *vm_command) { - command_t command; - command.instruction =( (uint64_t) vm_command->bytes[0] << 56 ) | - ( (uint64_t) vm_command->bytes[1] << 48 ) | - ( (uint64_t) vm_command->bytes[2] << 40 ) | - ( (uint64_t) vm_command->bytes[3] << 32 ) | - ( (uint64_t) vm_command->bytes[4] << 24 ) | - ( (uint64_t) vm_command->bytes[5] << 16 ) | - ( (uint64_t) vm_command->bytes[6] << 8 ) | - (uint64_t) vm_command->bytes[7] ; - command.examined = 0; - - switch(vm_getbits(&command,63,3)) { /* three first bits */ - case 0: /* Special instructions */ - print_if_version_1(&command); - print_special_instruction(&command); - break; - case 1: /* Jump/Call or Link instructions */ - if(vm_getbits(&command,60,1)) { - print_if_version_2(&command); - print_jump_instruction(&command); - } else { - print_if_version_1(&command); - print_link_instruction(&command, 0); /* must be pressent */ - } - break; - case 2: /* Set System Parameters instructions */ - print_if_version_2(&command); - print_system_set(&command); - print_link_instruction(&command, 1); /* either 'if' or 'link' */ - break; - case 3: /* Set General Parameters instructions */ - print_if_version_3(&command); - print_set_version_1(&command); - print_link_instruction(&command, 1); /* either 'if' or 'link' */ - break; - case 4: /* Set, Compare -> LinkSub instructions */ - print_set_version_2(&command); - fprintf(MSG_OUT, ", "); - print_if_version_4(&command); - print_linksub_instruction(&command); - break; - case 5: /* Compare -> (Set and LinkSub) instructions */ - print_if_version_5(&command); - fprintf(MSG_OUT, "{ "); - print_set_version_3(&command); - fprintf(MSG_OUT, ", "); - print_linksub_instruction(&command); - fprintf(MSG_OUT, " }"); - break; - case 6: /* Compare -> Set, always LinkSub instructions */ - print_if_version_5(&command); - fprintf(MSG_OUT, "{ "); - print_set_version_3(&command); - fprintf(MSG_OUT, " } "); - print_linksub_instruction(&command); - break; - default: - fprintf(MSG_OUT, "WARNING: Unknown instruction type (%i)", vm_getbits(&command, 63, 3)); - } - /* Check if there still are bits set that were not examined */ - - if(command.instruction & ~ command.examined) { - fprintf(MSG_OUT, " libdvdnav: vmcmd.c: [WARNING, unknown bits:"); - fprintf(MSG_OUT, " %08"PRIx64, (command.instruction & ~ command.examined) ); - fprintf(MSG_OUT, "]"); - } -} - -void vm_print_cmd(int row, vm_cmd_t *vm_command) { - int i; - - fprintf(MSG_OUT, "(%03d) ", row + 1); - for(i = 0; i < 8; i++) - fprintf(MSG_OUT, "%02x ", vm_command->bytes[i]); - fprintf(MSG_OUT, "| "); - - vm_print_mnemonic(vm_command); - fprintf(MSG_OUT, "\n"); -} - diff -r 427b7da5cbdb -r 1c897db44135 vm/vmcmd.h --- a/vm/vmcmd.h Sun Jun 01 08:39:07 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Martin Norbäck, Håkan Hjort - * - * This file is part of libdvdnav, a DVD navigation library. It is modified - * from a file originally part of the Ogle DVD player. - * - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id$ - * - */ - -#ifndef VMCMD_H_INCLUDED -#define VMCMD_H_INCLUDED - -void vm_print_mnemonic(vm_cmd_t *command); -void vm_print_cmd(int row, vm_cmd_t *command); - -#endif /* VMCMD_H_INCLUDED */