diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/filesystem/BlurayDirectory.cpp | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/filesystem/BlurayDirectory.cpp')
-rw-r--r-- | xbmc/filesystem/BlurayDirectory.cpp | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/xbmc/filesystem/BlurayDirectory.cpp b/xbmc/filesystem/BlurayDirectory.cpp new file mode 100644 index 0000000..dbfb41b --- /dev/null +++ b/xbmc/filesystem/BlurayDirectory.cpp @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ +#include "BlurayDirectory.h" + +#include "File.h" +#include "FileItem.h" +#include "LangInfo.h" +#include "URL.h" +#include "filesystem/BlurayCallback.h" +#include "filesystem/Directory.h" +#include "guilib/LocalizeStrings.h" +#include "utils/LangCodeExpander.h" +#include "utils/RegExp.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "utils/log.h" +#include "video/VideoInfoTag.h" + +#include <array> +#include <cassert> +#include <climits> +#include <stdlib.h> +#include <string> + +#include <libbluray/bluray-version.h> +#include <libbluray/bluray.h> +#include <libbluray/filesystem.h> +#include <libbluray/log_control.h> + +namespace XFILE +{ + +#define MAIN_TITLE_LENGTH_PERCENT 70 /** Minimum length of main titles, based on longest title */ + +CBlurayDirectory::~CBlurayDirectory() +{ + Dispose(); +} + +void CBlurayDirectory::Dispose() +{ + if(m_bd) + { + bd_close(m_bd); + m_bd = nullptr; + } +} + +std::string CBlurayDirectory::GetBlurayTitle() +{ + return GetDiscInfoString(DiscInfo::TITLE); +} + +std::string CBlurayDirectory::GetBlurayID() +{ + return GetDiscInfoString(DiscInfo::ID); +} + +std::string CBlurayDirectory::GetDiscInfoString(DiscInfo info) +{ + switch (info) + { + case XFILE::CBlurayDirectory::DiscInfo::TITLE: + { + if (!m_blurayInitialized) + return ""; + const BLURAY_DISC_INFO* disc_info = bd_get_disc_info(m_bd); + if (!disc_info || !disc_info->bluray_detected) + return ""; + + std::string title = ""; + +#if (BLURAY_VERSION > BLURAY_VERSION_CODE(1,0,0)) + title = disc_info->disc_name ? disc_info->disc_name : ""; +#endif + + return title; + } + case XFILE::CBlurayDirectory::DiscInfo::ID: + { + if (!m_blurayInitialized) + return ""; + + const BLURAY_DISC_INFO* disc_info = bd_get_disc_info(m_bd); + if (!disc_info || !disc_info->bluray_detected) + return ""; + + std::string id = ""; + +#if (BLURAY_VERSION > BLURAY_VERSION_CODE(1,0,0)) + id = disc_info->udf_volume_id ? disc_info->udf_volume_id : ""; + + if (id.empty()) + { + id = HexToString(disc_info->disc_id, 20); + } +#endif + + return id; + } + default: + break; + } + + return ""; +} + +std::shared_ptr<CFileItem> CBlurayDirectory::GetTitle(const BLURAY_TITLE_INFO* title, + const std::string& label) +{ + std::string buf; + std::string chap; + CFileItemPtr item(new CFileItem("", false)); + CURL path(m_url); + buf = StringUtils::Format("BDMV/PLAYLIST/{:05}.mpls", title->playlist); + path.SetFileName(buf); + item->SetPath(path.Get()); + int duration = (int)(title->duration / 90000); + item->GetVideoInfoTag()->SetDuration(duration); + item->GetVideoInfoTag()->m_iTrack = title->playlist; + buf = StringUtils::Format(label, title->playlist); + item->m_strTitle = buf; + item->SetLabel(buf); + chap = StringUtils::Format(g_localizeStrings.Get(25007), title->chapter_count, + StringUtils::SecondsToTimeString(duration)); + item->SetLabel2(chap); + item->m_dwSize = 0; + item->SetArt("icon", "DefaultVideo.png"); + for(unsigned int i = 0; i < title->clip_count; ++i) + item->m_dwSize += title->clips[i].pkt_count * 192; + + return item; +} + +void CBlurayDirectory::GetTitles(bool main, CFileItemList &items) +{ + std::vector<BLURAY_TITLE_INFO*> titleList; + uint64_t minDuration = 0; + + // Searching for a user provided list of playlists. + if (main) + titleList = GetUserPlaylists(); + + if (!main || titleList.empty()) + { + uint32_t numTitles = bd_get_titles(m_bd, TITLES_RELEVANT, 0); + + for (uint32_t i = 0; i < numTitles; i++) + { + BLURAY_TITLE_INFO* t = bd_get_title_info(m_bd, i, 0); + + if (!t) + { + CLog::Log(LOGDEBUG, "CBlurayDirectory - unable to get title {}", i); + continue; + } + + if (main && t->duration > minDuration) + minDuration = t->duration; + + titleList.emplace_back(t); + } + } + + minDuration = minDuration * MAIN_TITLE_LENGTH_PERCENT / 100; + + for (auto& title : titleList) + { + if (title->duration < minDuration) + continue; + + items.Add(GetTitle(title, main ? g_localizeStrings.Get(25004) /* Main Title */ : g_localizeStrings.Get(25005) /* Title */)); + bd_free_title_info(title); + } +} + +void CBlurayDirectory::GetRoot(CFileItemList &items) +{ + GetTitles(true, items); + + CURL path(m_url); + CFileItemPtr item; + + path.SetFileName(URIUtils::AddFileToFolder(m_url.GetFileName(), "titles")); + item.reset(new CFileItem()); + item->SetPath(path.Get()); + item->m_bIsFolder = true; + item->SetLabel(g_localizeStrings.Get(25002) /* All titles */); + item->SetArt("icon", "DefaultVideoPlaylists.png"); + items.Add(item); + + const BLURAY_DISC_INFO* disc_info = bd_get_disc_info(m_bd); + if (disc_info && disc_info->no_menu_support) + { + CLog::Log(LOGDEBUG, "CBlurayDirectory::GetRoot - no menu support, skipping menu entry"); + return; + } + + path.SetFileName("menu"); + item.reset(new CFileItem()); + item->SetPath(path.Get()); + item->m_bIsFolder = false; + item->SetLabel(g_localizeStrings.Get(25003) /* Menus */); + item->SetArt("icon", "DefaultProgram.png"); + items.Add(item); +} + +bool CBlurayDirectory::GetDirectory(const CURL& url, CFileItemList &items) +{ + Dispose(); + m_url = url; + std::string root = m_url.GetHostName(); + std::string file = m_url.GetFileName(); + URIUtils::RemoveSlashAtEnd(file); + URIUtils::RemoveSlashAtEnd(root); + + if (!InitializeBluray(root)) + return false; + + if(file == "root") + GetRoot(items); + else if(file == "root/titles") + GetTitles(false, items); + else + { + CURL url2 = GetUnderlyingCURL(url); + CDirectory::CHints hints; + hints.flags = m_flags; + if (!CDirectory::GetDirectory(url2, items, hints)) + return false; + } + + items.AddSortMethod(SortByTrackNumber, 554, LABEL_MASKS("%L", "%D", "%L", "")); // FileName, Duration | Foldername, empty + items.AddSortMethod(SortBySize, 553, LABEL_MASKS("%L", "%I", "%L", "%I")); // FileName, Size | Foldername, Size + + return true; +} + +CURL CBlurayDirectory::GetUnderlyingCURL(const CURL& url) +{ + assert(url.IsProtocol("bluray")); + std::string host = url.GetHostName(); + const std::string& filename = url.GetFileName(); + return CURL(host.append(filename)); +} + +bool CBlurayDirectory::InitializeBluray(const std::string &root) +{ + bd_set_debug_handler(CBlurayCallback::bluray_logger); + bd_set_debug_mask(DBG_CRIT | DBG_BLURAY | DBG_NAV); + + m_bd = bd_init(); + + if (!m_bd) + { + CLog::Log(LOGERROR, "CBlurayDirectory::InitializeBluray - failed to initialize libbluray"); + return false; + } + + std::string langCode; + g_LangCodeExpander.ConvertToISO6392T(g_langInfo.GetDVDMenuLanguage(), langCode); + bd_set_player_setting_str(m_bd, BLURAY_PLAYER_SETTING_MENU_LANG, langCode.c_str()); + + if (!bd_open_files(m_bd, const_cast<std::string*>(&root), CBlurayCallback::dir_open, CBlurayCallback::file_open)) + { + CLog::Log(LOGERROR, "CBlurayDirectory::InitializeBluray - failed to open {}", + CURL::GetRedacted(root)); + return false; + } + m_blurayInitialized = true; + + return true; +} + +std::string CBlurayDirectory::HexToString(const uint8_t *buf, int count) +{ + std::array<char, 42> tmp; + + for (int i = 0; i < count; i++) + { + sprintf(tmp.data() + (i * 2), "%02x", buf[i]); + } + + return std::string(std::begin(tmp), std::end(tmp)); +} + +std::vector<BLURAY_TITLE_INFO*> CBlurayDirectory::GetUserPlaylists() +{ + std::string root = m_url.GetHostName(); + std::string discInfPath = URIUtils::AddFileToFolder(root, "disc.inf"); + std::vector<BLURAY_TITLE_INFO*> userTitles; + CFile file; + char buffer[1025]; + + if (file.Open(discInfPath)) + { + CLog::Log(LOGDEBUG, "CBlurayDirectory::GetTitles - disc.inf found"); + + CRegExp pl(true); + if (!pl.RegComp("(\\d+)")) + { + file.Close(); + return userTitles; + } + + uint8_t maxLines = 100; + while ((maxLines > 0) && file.ReadString(buffer, 1024)) + { + maxLines--; + if (StringUtils::StartsWithNoCase(buffer, "playlists")) + { + int pos = 0; + while ((pos = pl.RegFind(buffer, static_cast<unsigned int>(pos))) >= 0) + { + std::string playlist = pl.GetMatch(0); + uint32_t len = static_cast<uint32_t>(playlist.length()); + + if (len <= 5) + { + unsigned long int plNum = strtoul(playlist.c_str(), nullptr, 10); + + BLURAY_TITLE_INFO* t = bd_get_playlist_info(m_bd, static_cast<uint32_t>(plNum), 0); + if (t) + userTitles.emplace_back(t); + } + + if (static_cast<int64_t>(pos) + static_cast<int64_t>(len) > INT_MAX) + break; + else + pos += len; + } + } + } + file.Close(); + } + return userTitles; +} + +} /* namespace XFILE */ |