Play a specific title/playlist for DVD/BR iso/folder #1736

Closed
wants to merge 3 commits into
from
Jump to file or symbol
Failed to load files and symbols.
+268 −41
Diff settings

Always

Just for now

View
@@ -0,0 +1,98 @@
+USER POINT OF VIEW
+
+I like to think of Optical disks having three file systems
+1) a udf (in iso form) or a native file system (in folder form)
+2) a menu driven file system (dvdnav for DVDs) and not yet implemented for
+BluRays
+3) a title/chapter (mpls/?) file system
+
+and from the user point of view it contains 1 or more movies, episodes,
+"extras" as well as menus (and sometimes extras buried in the menus) and some
+computer mode apps
+
+I (and some others) like to keep the disc intact as the menus are occasionally
+interesting and occasionally (rarely) the only way to play a movie.
+
+Fortunately (and why makemkv is useful) most of the times the interesting bits
+constitute one and only one title, though a few DVDS use chapters to index TV
+show episodes
+
+I would like to propose a mechanism that allows user to select one of three
+choices
+
+1) play the menu ( I like XBMC's option to go straight to the main menu)
+2) play the main title (given the fact that we can't actually tell what it is
+play the longest title)
+3) play a specific video (I have suggested a single title, though after some
+work it should probably be a title/chapter pair)
+
+Given that I am a slow (and error-prone) typist I would like a mechanism to
+reasonably automatically scrape and assign video information to the videos
+
+Method 1)
+ Create a database field that selects which video to play and a
+mechanism to specify it in an nfo file.
+ In order to create the nfo file there needs to be some file system file
+that the scanner can scrap.
+ I have found symlinks to be the easiest, though if one isn't interested
+in the "specials" then tvshow/s1e1e2e3.iso works.
+ The only small difficulty I have with this is it is a 3 step process.
+ scan the files
+ edit the nfos
+ re-scan the files
+
+Method 2)
+ Encode in the file (name or contents) the specification for the video.
+ IF it is encoded in the contents (either as a test file or as a
+symlink) it must contain information relative to either the file or parent
+directory so that the movie/tvshow can be moved around in the physical file
+system.
+ This has the advantage that it is easier for an external tool to
+analyze the disc and create the files and they are playable outside of XBMC
+(with appropriate scripts).
+
+
+IMPLEMENTATION
+
+Method 1)
+ I added a database field playTitle which is a single integer N, with
+N=0 meaning to play the longest title, N>=100000 or absent use the menus
+(eventually with BluRays) and otherwise play title N
+ This field is understood by DVDPlayer and passed to the InputStream (by
+appending ?title=N to the filename as pointed out probably better as
+playtitle:[urlencoded filename]/title=N or bluray: and dvdnav: or) though I
+don't believe there can be any other URL with a title option inside the
+filename at this point)
+ This option is interpreted by the InputStream and appropriate action
+taken
+
+Method 2)
+ I essentially created two sets of new file types .TITNN.ISO (for DVD
+and Bluray) and .TITNN (for DVD Folders - for BluRays the user can directly
+access BDMV/NNNNN.mpls or index.bdmv, but they will lose the option to play
+longest). This how I can play them directly in Linux.
+ The .TITNN.ISO is interpreted by DVDPlayer and the .TITNN is
+interpreted by DVDInputStreamNavigator (courtesy of a previous implementation)
+ I did not add the implementation of getting longest title on DVD yet.
+(as it turns out I have a metadata file in my library(file system) that has
+this info so I scraped it and added it to the nfo file)
+
+
+OTHER POSSIBLE IMPLEMENTATIONS
+
+One of the issues is that one can't represent .../bluray.iso/BDMV/NNNNN.mpls in
+a file system. One could decide to interpret that as
+bluray://[.../bluray.iso/BDMV/NNNNN.mpls]/BDMV/NNNNN.mpls with the
+understanding that .../bluray.iso/BDMV/NNNNN.mpls is a symlink to or an actual
+.iso (or rars or zips or ...) but it is pretty ugly
+
+Using a file.url with a text content representing either an absolute or a
+relative URL has some appeal but that is already taken (though maybe it could
+be taken back) and I suspect it might be pretty hard to get right, but I'm sure
+it would have other applications.
+
+A secondary/scrape-able NFO file say .nfoi (like elupus thought existed). The
+scanner would scrape it as a file and allow it to set filename, pathname,
+playTitle or whatever. There would need to be a database change to record the
+original filename to be able to save the scraped data to a corresponding nfo
+file.
@@ -274,13 +274,25 @@ BLURAY_TITLE_INFO* CDVDInputStreamBluray::GetTitleFile(const std::string& filena
bool CDVDInputStreamBluray::Open(const char* strFile, const std::string& content)
{
+ int title = 100000;
if(m_player == NULL)
return false;
+ CLog::Log(LOGDEBUG, "CDVDInputStreamBluray::Open - opening %s", strFile);
CStdString strPath(strFile);
CStdString filename;
CStdString root;
+ int iPos = strPath.ReverseFind('?');
+ if( iPos > 0
+ && iPos > strPath.ReverseFind('/')
+ && iPos > strPath.ReverseFind('\\')
+ && strPath.Mid(iPos,7).CompareNoCase("?title") )
+ {
+ title = atoi( strPath.Mid(iPos+7).c_str());
+ strPath = strPath.Left(iPos);
+ }
+
if(strPath.Left(7).Equals("bluray:"))
{
CURL url(strPath);
@@ -289,6 +301,7 @@ bool CDVDInputStreamBluray::Open(const char* strFile, const std::string& content
}
else
{
+ filename = URIUtils::GetFileName(strPath);
URIUtils::GetDirectory(strPath,strPath);
URIUtils::RemoveSlashAtEnd(strPath);
@@ -304,7 +317,6 @@ bool CDVDInputStreamBluray::Open(const char* strFile, const std::string& content
URIUtils::RemoveSlashAtEnd(strPath);
}
root = strPath;
- filename = URIUtils::GetFileName(strFile);
}
if (!m_dll)
@@ -315,7 +327,11 @@ bool CDVDInputStreamBluray::Open(const char* strFile, const std::string& content
m_dll->bd_set_debug_handler(DllLibbluray::bluray_logger);
m_dll->bd_set_debug_mask(DBG_CRIT | DBG_BLURAY | DBG_NAV);
- CLog::Log(LOGDEBUG, "CDVDInputStreamBluray::Open - opening %s", root.c_str());
+ if( title == 100000 )
+ CLog::Log(LOGDEBUG, "CDVDInputStreamBluray::Open - opening %s, %s", root.c_str(), filename.c_str());
+ else
+ CLog::Log(LOGDEBUG, "CDVDInputStreamBluray::Open - opening %s, %s title=%d", root.c_str(), filename.c_str(), title);
+
m_bd = m_dll->bd_open(root.c_str(), NULL);
if(!m_bd)
@@ -366,7 +382,10 @@ bool CDVDInputStreamBluray::Open(const char* strFile, const std::string& content
if(filename.Equals("index.bdmv"))
{
m_navmode = false;
- m_title = GetTitleLongest();
+ if( title >= 100000 || title == 0 )
+ m_title = GetTitleLongest();
+ else
+ m_title = m_dll->bd_get_playlist_info(m_bd, abs(title), 0);
}
else if(URIUtils::GetExtension(filename).Equals(".mpls"))
{
@@ -52,6 +52,7 @@ CDVDInputStreamNavigator::CDVDInputStreamNavigator(IDVDPlayer* player) : CDVDInp
m_bEOF = false;
m_icurrentGroupId = 0;
m_lastevent = DVDNAV_NOP;
+ m_bFinishedPGC = false;
memset(m_lastblock, 0, sizeof(m_lastblock));
}
@@ -64,6 +65,7 @@ CDVDInputStreamNavigator::~CDVDInputStreamNavigator()
bool CDVDInputStreamNavigator::Open(const char* strFile, const std::string& content)
{
char* strDVDFile;
+ int start_title = 100000;
m_icurrentGroupId = 0;
if (!CDVDInputStream::Open(strFile, "video/x-dvd-mpeg"))
return false;
@@ -83,6 +85,12 @@ bool CDVDInputStreamNavigator::Open(const char* strFile, const std::string& cont
// at least one path separator character.
strDVDFile = strdup(strFile);
+ char *p = rindex(strDVDFile, '?');
+ if( p && strncasecmp( p, "?title=", 7) == 0 )
+ {
+ start_title = atoi( p+7 );
+ *p = 0;
+ }
int len = strlen(strDVDFile);
if(len >= 13 // +1 on purpose, to include a separator char before the searched string
@@ -94,6 +102,16 @@ bool CDVDInputStreamNavigator::Open(const char* strFile, const std::string& cont
&& strncasecmp(strDVDFile + len - 8, "VIDEO_TS", 8) == 0)
strDVDFile[len - 9] = '\0';
+ len = strlen(strDVDFile);
+ if( start_title < 100000 )
+ ;
+ else if(len >= 6 // .TITNN
+ && strncasecmp(strDVDFile + len - 6, ".TIT", 4) == 0)
+ start_title = atoi( strDVDFile + len - 2 );
+ else if(len >= 6 // .TRKNN // historical reasons
+ && strncasecmp(strDVDFile + len - 6, ".TRK", 4) == 0)
+ start_title = atoi( strDVDFile + len - 2 );
+
#if defined(TARGET_DARWIN_OSX)
// if physical DVDs, libdvdnav wants "/dev/rdiskN" device name for OSX,
// strDVDFile will get realloc'ed and replaced IF this is a physical DVD.
@@ -185,8 +203,29 @@ bool CDVDInputStreamNavigator::Open(const char* strFile, const std::string& cont
return false;
}
+ m_iTitle = m_iTitleCount = 0;
+ m_iPart = m_iPartCount = 0;
+ m_iTime = m_iTotalTime = 0;
+ m_iPlayTitle = 0;
+
+ if( start_title < 100000 )
+ {
+ int len, event, parts;
+ uint8_t buf[2048];
+ uint8_t* buf_ptr = buf;
+ CLog::Log(LOGDEBUG, "*************** setting title to %d", start_title);
+ m_iTitle = start_title;
+ m_iPlayTitle = start_title;
+ m_iPlayTitleTotalTime = 0;
+ // m_dll.dvdnav_part_play(m_dvdnav, 0, 1);
+ m_dll.dvdnav_part_play(m_dvdnav, m_iTitle, 1);
+ // these all get fixed up in DVDNAV_CELL_CHANGE
+ m_iTitleCount = 0;
+ m_iPart = m_iPartCount = 0;
+ m_iTime = m_iTotalTime = 0;
+ }
// jump directly to title menu
- if(g_guiSettings.GetBool("dvds.automenu"))
+ else if(g_guiSettings.GetBool("dvds.automenu"))
{
int len, event;
uint8_t buf[2048];
@@ -208,9 +247,6 @@ bool CDVDInputStreamNavigator::Open(const char* strFile, const std::string& cont
m_iVobUnitCorrection = 0LL;
m_bInMenu = false;
m_holdmode = HOLDMODE_NONE;
- m_iTitle = m_iTitleCount = 0;
- m_iPart = m_iPartCount = 0;
- m_iTime = m_iTotalTime = 0;
return true;
}
@@ -464,9 +500,16 @@ int CDVDInputStreamNavigator::ProcessBlock(BYTE* dest_buffer, int* read)
m_iCellStart = cell_change_event->cell_start; // store cell time as we need that for time later
m_iTime = (int) (m_iCellStart / 90);
m_iTotalTime = (int) (cell_change_event->pgc_length / 90);
+ if( m_iTitle == m_iPlayTitle )
+ m_iPlayTitleTotalTime = m_iTotalTime;
m_icurrentGroupId = cell_change_event->pgN * 1000 + cell_change_event->cellN;
- iNavresult = m_pDVDPlayer->OnDVDNavResult(buf, DVDNAV_CELL_CHANGE);
+ if( m_iPlayTitle && m_bFinishedPGC ) {
+ m_bEOF = true;
+ iNavresult = m_pDVDPlayer->OnDVDNavResult(buf, DVDNAV_STOP);
+ }
+ else
+ iNavresult = m_pDVDPlayer->OnDVDNavResult(buf, DVDNAV_CELL_CHANGE);
}
break;
@@ -516,6 +559,10 @@ int CDVDInputStreamNavigator::ProcessBlock(BYTE* dest_buffer, int* read)
CLog::Log(LOGDEBUG, "DVDNAV_NAV_PACKET - DISCONTINUITY FROM:%"PRId64" TO:%"PRId64" DIFF:%"PRId64, (m_iVobUnitStop * 1000)/90, ((int64_t)pci->pci_gi.vobu_s_ptm*1000)/90, (gap*1000)/90);
}
+ if( m_iTitle == m_iPlayTitle && pci->pci_gi.vobu_e_ptm/90 >= m_iTotalTime-1 )
+ {
+ m_bFinishedPGC = true;
+ }
m_iVobUnitStart = pci->pci_gi.vobu_s_ptm;
m_iVobUnitStop = pci->pci_gi.vobu_e_ptm;
@@ -154,6 +154,7 @@ class CDVDInputStreamNavigator
int m_iTotalTime;
int m_iTime;
+ bool m_bFinishedPGC;
int64_t m_iCellStart; // start time of current cell in pts units (90khz clock)
bool m_bInMenu;
@@ -164,7 +165,8 @@ class CDVDInputStreamNavigator
int m_iTitleCount;
int m_iTitle;
-
+ int m_iPlayTitle;
+ int m_iPlayTitleTotalTime;
int m_iPartCount;
int m_iPart;
@@ -557,6 +557,8 @@ bool CDVDPlayer::OpenInputStream()
{
m_filename = g_mediaManager.TranslateDevicePath("");
}
+
+ int title = 100000;
retry:
// before creating the input stream, if this is an HLS playlist then get the
// most appropriate bitrate based on our network settings
@@ -579,18 +581,37 @@ bool CDVDPlayer::OpenInputStream()
else
m_pInputStream->SetFileItem(m_item);
- if (!m_pInputStream->Open(m_filename.c_str(), m_mimetype))
+ if(title == 100000 && (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD) || m_pInputStream->IsStreamType(DVDSTREAM_TYPE_BLURAY)) && m_item.HasVideoInfoTag())
+ title = m_item.GetVideoInfoTag()->m_iPlayTitle;
+
+ if( title >= 100000 ) // match filename.titnnn.iso
+ {
+ int t, n=-1, len;
+ char *p, *q;
+ p = strdup(m_filename.c_str());
+ len = strlen( p );
+ if( len > 4 && strcasecmp(&p[len-4], ".iso" ) == 0 )
+ {
+ p[len-4] = 0;
+ if( (q = rindex(p, '.'))
+ && strcasecmp( q, ".tit" )
+ && sscanf( q+4, "%d%n", &t, &n ) >= 1
+ && q[n+4] == 0 )
+ title = t;
+ }
+ free( p );
+ }
+ if( title < 100000 )
+ filename.AppendFormat("?title=%d",title);
+
+ if (!m_pInputStream->Open(filename.c_str(), m_mimetype))
{
if(m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
{
CLog::Log(LOGERROR, "CDVDPlayer::OpenInputStream - failed to open [%s] as DVD ISO, trying Bluray", m_filename.c_str());
m_mimetype = "bluray/iso";
filename = m_filename;
filename = filename + "/BDMV/index.bdmv";
- int title = (int)m_item.GetProperty("BlurayStartingTitle").asInteger();
- if( title )
- filename.AppendFormat("?title=%d",title);
-
m_filename = filename;
goto retry;
}
@@ -112,6 +112,7 @@ typedef enum {
FieldSubtitleLanguage,
FieldProductionCode,
FieldTag,
+ FieldPlayTitle,
FieldChannelName,
FieldInstruments,
FieldBiography,
Oops, something went wrong.