bool FileRingBuffer::OpenFile(const QString &lfilename, uint retry_ms) { LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("OpenFile(%1, %2 ms)") .arg(lfilename).arg(retry_ms)); rwlock.lockForWrite(); filename = lfilename; if (remotefile) { delete remotefile; remotefile = NULL; } if (fd2 >= 0) { close(fd2); fd2 = -1; } bool is_local = (filename.left(4) != "/dev") && ((filename.left(1) == "/") || QFile::exists(filename)); if (is_local) { char buf[kReadTestSize]; int lasterror = 0; MythTimer openTimer; openTimer.start(); uint openAttempts = 0; do { openAttempts++; lasterror = 0; fd2 = open(filename.toLocal8Bit().constData(), O_RDONLY|O_LARGEFILE|O_STREAMING|O_BINARY); if (fd2 < 0) { if (!check_permissions(filename)) { lasterror = 3; break; } lasterror = 1; usleep(10 * 1000); } else { int ret = read(fd2, buf, kReadTestSize); if (ret != (int)kReadTestSize) { lasterror = 2; close(fd2); fd2 = -1; if (oldfile) break; // if it's an old file it won't grow.. usleep(10 * 1000); } else { if (0 == lseek(fd2, 0, SEEK_SET)) { posix_fadvise(fd2, 0, 0, POSIX_FADV_SEQUENTIAL); posix_fadvise(fd2, 0, 128*1024, POSIX_FADV_WILLNEED); lasterror = 0; break; } lasterror = 4; close(fd2); fd2 = -1; } } } while ((uint)openTimer.elapsed() < retry_ms); switch (lasterror) { case 0: { QFileInfo fi(filename); oldfile = fi.lastModified() .secsTo(QDateTime::currentDateTime()) > 60; QString extension = fi.completeSuffix().toLower(); if (is_subtitle_possible(extension)) subtitlefilename = local_sub_filename(fi); break; } case 1: LOG(VB_GENERAL, LOG_ERR, LOC + QString("OpenFile(): Could not open.")); break; case 2: LOG(VB_GENERAL, LOG_ERR, LOC + QString("OpenFile(): File too small (%1B).") .arg(QFileInfo(filename).size())); break; case 3: LOG(VB_GENERAL, LOG_ERR, LOC + "OpenFile(): Improper permissions."); break; case 4: LOG(VB_GENERAL, LOG_ERR, LOC + "OpenFile(): Cannot seek in file."); break; default: break; } LOG(VB_FILE, LOG_INFO, LOC + QString("OpenFile() made %1 attempts in %2 ms") .arg(openAttempts).arg(openTimer.elapsed())); } else { QString tmpSubName = filename; QString dirName = "."; int dirPos = filename.lastIndexOf(QChar('/')); if (dirPos > 0) { tmpSubName = filename.mid(dirPos + 1); dirName = filename.left(dirPos); } QString baseName = tmpSubName; QString extension = tmpSubName; QStringList auxFiles; int suffixPos = tmpSubName.lastIndexOf(QChar('.')); if (suffixPos > 0) { baseName = tmpSubName.left(suffixPos); extension = tmpSubName.right(suffixPos-1); if (is_subtitle_possible(extension)) { QMutexLocker locker(&subExtLock); QStringList::const_iterator eit = subExt.begin(); for (; eit != subExt.end(); ++eit) auxFiles += baseName + *eit; } } remotefile = new RemoteFile(filename, false, true, retry_ms, &auxFiles); if (!remotefile->isOpen()) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("RingBuffer::RingBuffer(): Failed to open remote " "file (%1)").arg(filename)); delete remotefile; remotefile = NULL; } else { QStringList aux = remotefile->GetAuxiliaryFiles(); if (aux.size()) subtitlefilename = dirName + "/" + aux[0]; } } setswitchtonext = false; ateof = false; commserror = false; numfailures = 0; rawbitrate = 8000; CalcReadAheadThresh(); bool ok = fd2 >= 0 || remotefile; rwlock.unlock(); return ok; }
bool BDRingBuffer::OpenFile(const QString &lfilename, uint retry_ms) { filename = lfilename; VERBOSE(VB_IMPORTANT, LOC + QString("Opened BDRingBuffer device at %1") .arg(filename.toLatin1().data())); // Ask mythiowrapper to update this object on file open progress. Opening // a bluray disc can involve opening several hundred files which can take // several minutes when the disc structure is remote. The callback allows // us to 'kick' the main UI - as the 'please wait' widget is still visible // at this stage mythfile_open_register_callback(filename.toLatin1().data(), this, file_opened_callback); QMutexLocker locker(&m_infoLock); rwlock.lockForWrite(); if (bdnav) close(); QString keyfile = QString("%1/KEYDB.cfg").arg(GetConfDir()); QByteArray keyarray = keyfile.toAscii(); const char *keyfilepath = keyarray.data(); bdnav = bd_open(filename.toLatin1().data(), keyfilepath); if (!bdnav) { rwlock.unlock(); mythfile_open_register_callback(filename.toLatin1().data(), this, NULL); return false; } m_metaDiscLibrary = bd_get_meta(bdnav); if (m_metaDiscLibrary) { VERBOSE(VB_GENERAL, LOC + QString("Disc Title: %1 (%2)") .arg(m_metaDiscLibrary->di_name) .arg(m_metaDiscLibrary->language_code)); VERBOSE(VB_GENERAL, LOC + QString("Alternative Title: %1") .arg(m_metaDiscLibrary->di_alternative)); VERBOSE(VB_GENERAL, LOC + QString("Disc Number: %1 of %2") .arg(m_metaDiscLibrary->di_set_number) .arg(m_metaDiscLibrary->di_num_sets)); } // Check disc to see encryption status, menu and navigation types. m_topMenuSupported = false; m_firstPlaySupported = false; const BLURAY_DISC_INFO *discinfo = bd_get_disc_info(bdnav); if (discinfo) { m_topMenuSupported = discinfo->top_menu_supported; m_firstPlaySupported = discinfo->first_play_supported; VERBOSE(VB_PLAYBACK, LOC + QString("*** Blu-ray Disc Information ***")); VERBOSE(VB_PLAYBACK, LOC + QString("First Play Supported: %1") .arg(discinfo->first_play_supported ? "yes" : "no")); VERBOSE(VB_PLAYBACK, LOC + QString("Top Menu Supported: %1") .arg(discinfo->top_menu_supported ? "yes" : "no")); VERBOSE(VB_PLAYBACK, LOC + QString("Number of HDMV Titles: %1") .arg(discinfo->num_hdmv_titles)); VERBOSE(VB_PLAYBACK, LOC + QString("Number of BD-J Titles: %1") .arg(discinfo->num_bdj_titles)); VERBOSE(VB_PLAYBACK, LOC + QString("Number of Unsupported Titles: %1") .arg(discinfo->num_unsupported_titles)); VERBOSE(VB_PLAYBACK, LOC + QString("AACS present on disc: %1") .arg(discinfo->aacs_detected ? "yes" : "no")); VERBOSE(VB_PLAYBACK, LOC + QString("libaacs used: %1") .arg(discinfo->libaacs_detected ? "yes" : "no")); VERBOSE(VB_PLAYBACK, LOC + QString("AACS handled: %1") .arg(discinfo->aacs_handled ? "yes" : "no")); VERBOSE(VB_PLAYBACK, LOC + QString("BD+ present on disc: %1") .arg(discinfo->bdplus_detected ? "yes" : "no")); VERBOSE(VB_PLAYBACK, LOC + QString("libbdplus used: %1") .arg(discinfo->libbdplus_detected ? "yes" : "no")); VERBOSE(VB_PLAYBACK, LOC + QString("BD+ handled: %1") .arg(discinfo->bdplus_handled ? "yes" : "no")); } // The following settings affect HDMV navigation // (default audio track selection, // parental controls, menu language, etc. They are not yet used. // Set parental level "age" to 99 for now. TODO: Add support for FE level bd_set_player_setting(bdnav, BLURAY_PLAYER_SETTING_PARENTAL, 99); // Set preferred language to FE guide language const char *langpref = gCoreContext->GetSetting( "ISO639Language0", "eng").toLatin1().data(); QString QScountry = gCoreContext->GetLocale()->GetCountryCode().toLower(); const char *country = QScountry.toLatin1().data(); bd_set_player_setting_str( bdnav, BLURAY_PLAYER_SETTING_AUDIO_LANG, langpref); // Set preferred presentation graphics language to the FE guide language bd_set_player_setting_str(bdnav, BLURAY_PLAYER_SETTING_PG_LANG, langpref); // Set preferred menu language to the FE guide language bd_set_player_setting_str(bdnav, BLURAY_PLAYER_SETTING_MENU_LANG, langpref); // Set player country code via MythLocale. (not a region setting) bd_set_player_setting_str( bdnav, BLURAY_PLAYER_SETTING_COUNTRY_CODE, country); int regioncode = 0; regioncode = gCoreContext->GetNumSetting("BlurayRegionCode"); if (regioncode > 0) bd_set_player_setting(bdnav, BLURAY_PLAYER_SETTING_REGION_CODE, regioncode); VERBOSE(VB_IMPORTANT, LOC + QString("Using %1 as keyfile...") .arg(QString(keyfilepath))); // Return an index of relevant titles (excludes dupe clips + titles) VERBOSE(VB_GENERAL, LOC + QString("Retrieving title list (please wait).")); m_numTitles = bd_get_titles(bdnav, TITLES_RELEVANT); VERBOSE(VB_GENERAL, LOC + QString("Found %1 titles.").arg(m_numTitles)); m_mainTitle = 0; m_currentTitleLength = 0; m_titlesize = 0; m_currentTime = 0; m_currentTitleInfo = NULL; m_currentTitleAngleCount = 0; // Mostly event-driven values below m_currentAngle = 0; m_currentTitle = 0; m_currentPlaylist = 0; m_currentPlayitem = 0; m_currentChapter = 0; m_currentAudioStream = 0; m_currentIGStream = 0; m_currentPGTextSTStream = 0; m_currentSecondaryAudioStream = 0; m_currentSecondaryVideoStream = 0; m_PGTextSTEnabled = false; m_secondaryAudioEnabled = false; m_secondaryVideoEnabled = false; m_secondaryVideoIsFullscreen = false; m_stillMode = BLURAY_STILL_NONE; m_stillTime = 0; m_inMenu = false; // First, attempt to initialize the disc in HDMV navigation mode. // If this fails, fall back to the traditional built-in title switching // mode. if (m_tryHDMVNavigation && m_firstPlaySupported && bd_play(bdnav)) { VERBOSE(VB_IMPORTANT, LOC + QString("Using HDMV navigation mode.")); m_isHDMVNavigation = true; // Register the Menu Overlay Callback bd_register_overlay_proc(bdnav, this, HandleOverlayCallback); } else { VERBOSE(VB_IMPORTANT, LOC + QString("Using title navigation mode.")); // Loop through the relevant titles and find the longest uint64_t titleLength = 0; uint64_t margin = 90000 << 4; // approx 30s BLURAY_TITLE_INFO *titleInfo = NULL; for( unsigned i = 0; i < m_numTitles; ++i) { titleInfo = GetTitleInfo(i); if (titleLength == 0 || (titleInfo->duration > (titleLength + margin))) { m_mainTitle = titleInfo->idx; titleLength = titleInfo->duration; } } SwitchTitle(m_mainTitle); } readblocksize = BD_BLOCK_SIZE * 62; setswitchtonext = false; ateof = false; commserror = false; numfailures = 0; rawbitrate = 8000; CalcReadAheadThresh(); rwlock.unlock(); mythfile_open_register_callback(filename.toLatin1().data(), this, NULL); return true; }
bool BDRingBuffer::OpenFile(const QString &lfilename, uint retry_ms) { VERBOSE(VB_IMPORTANT, LOC + QString("Opened BDRingBuffer device at %1") .arg(lfilename.toLatin1().data())); rwlock.lockForWrite(); if (bdnav) { if (m_currentTitleInfo) bd_free_title_info(m_currentTitleInfo); bd_close(bdnav); bdnav = NULL; } filename = lfilename; QString keyfile = QString("%1/KEYDB.cfg").arg(GetConfDir()); QByteArray keyarray = keyfile.toAscii(); const char *keyfilepath = keyarray.data(); bdnav = bd_open(lfilename.toLatin1().data(), keyfilepath); if (!bdnav) { rwlock.unlock(); return false; } // Check disc to see encryption status, menu and navigation types. const BLURAY_DISC_INFO *discinfo = bd_get_disc_info(bdnav); if (discinfo) { VERBOSE(VB_PLAYBACK, QString( "*** Blu-ray Disc Information ***\n" "First Play Supported: %1\n" "Top Menu Supported: %2\n" "Number of HDMV Titles: %3\n" "Number of BD-J Titles: %4\n" "Number of Unsupported Titles: %5\n" "AACS present on disc: %6\n" "libaacs used: %7\n" "AACS handled: %8\n" "BD+ present on disc: %9\n" "libbdplus used: %10\n" "BD+ handled: %11") .arg(discinfo->first_play_supported ? "yes" : "no") .arg(discinfo->top_menu_supported ? "yes" : "no") .arg(discinfo->num_hdmv_titles) .arg(discinfo->num_bdj_titles) .arg(discinfo->num_unsupported_titles) .arg(discinfo->aacs_detected ? "yes" : "no") .arg(discinfo->libaacs_detected ? "yes" : "no") .arg(discinfo->aacs_handled ? "yes" : "no") .arg(discinfo->bdplus_detected ? "yes" : "no") .arg(discinfo->libbdplus_detected ? "yes" : "no") .arg(discinfo->bdplus_handled ? "yes" : "no")); } // The following settings affect HDMV navigation // (default audio track selection, // parental controls, menu language, etc. They are not yet used. // Set parental level "age" to 99 for now. TODO: Add support for FE level bd_set_player_setting(bdnav, BLURAY_PLAYER_SETTING_PARENTAL, 99); // Set preferred language to FE guide language const char *langpref = gCoreContext->GetSetting( "ISO639Language0", "eng").toLatin1().data(); QString QScountry = gCoreContext->GetLocale()->GetCountryCode().toLower(); const char *country = QScountry.toLatin1().data(); bd_set_player_setting_str( bdnav, BLURAY_PLAYER_SETTING_AUDIO_LANG, langpref); // Set preferred presentation graphics language to the FE guide language bd_set_player_setting_str(bdnav, BLURAY_PLAYER_SETTING_PG_LANG, langpref); // Set preferred menu language to the FE guide language bd_set_player_setting_str(bdnav, BLURAY_PLAYER_SETTING_MENU_LANG, langpref); // Set player country code via MythLocale. (not a region setting) bd_set_player_setting_str( bdnav, BLURAY_PLAYER_SETTING_COUNTRY_CODE, country); int regioncode = 0; regioncode = gCoreContext->GetNumSetting("BlurayRegionCode"); if (regioncode > 0) bd_set_player_setting(bdnav, BLURAY_PLAYER_SETTING_REGION_CODE, regioncode); VERBOSE(VB_IMPORTANT, LOC + QString("Using %1 as keyfile...") .arg(QString(keyfilepath))); // Return an index of relevant titles (excludes dupe clips + titles) m_numTitles = bd_get_titles(bdnav, TITLES_RELEVANT); m_mainTitle = 0; m_currentTitleLength = 0; m_titlesize = 0; m_currentTime = 0; m_currentTitleInfo = NULL; m_currentTitleAngleCount = 0; // Mostly event-driven values below m_currentAngle = 0; m_currentTitle = 0; m_currentPlaylist = 0; m_currentPlayitem = 0; m_currentChapter = 0; m_currentAudioStream = 0; m_currentIGStream = 0; m_currentPGTextSTStream = 0; m_currentSecondaryAudioStream = 0; m_currentSecondaryVideoStream = 0; m_PGTextSTEnabled = false; m_secondaryAudioEnabled = false; m_secondaryVideoEnabled = false; m_secondaryVideoIsFullscreen = false; m_still = 0; m_inMenu = false; VERBOSE(VB_IMPORTANT, LOC + QString("Found %1 relevant titles.") .arg(m_numTitles)); // Loop through the relevant titles and find the longest uint64_t titleLength = 0; uint64_t margin = 90000 << 4; // approx 30s BLURAY_TITLE_INFO *titleInfo = NULL; for( unsigned i = 0; i < m_numTitles; ++i) { titleInfo = bd_get_title_info(bdnav, i); if (titleLength == 0 || (titleInfo->duration > (titleLength + margin))) { m_mainTitle = titleInfo->idx; titleLength = titleInfo->duration; } } bd_free_title_info(titleInfo); SwitchTitle(m_mainTitle); #if 0 // First, attempt to initialize the disc in HDMV navigation mode. // If this fails, fall back to the traditional built-in title switching // mode. if (bd_play(bdnav)) { m_is_hdmv_navigation = true; // Initialize the HDMV event queue HandleBDEvents(); // Register the Menu Overlay Callback bd_register_overlay_proc(bdnav, this, HandleOverlayCallback); } #endif readblocksize = BD_BLOCK_SIZE * 62; setswitchtonext = false; ateof = false; commserror = false; numfailures = 0; rawbitrate = 8000; CalcReadAheadThresh(); rwlock.unlock(); return true; }