diff options
author | Ryan Rector <rmrector@gmail.com> | 2023-09-19 18:08:11 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-19 18:08:11 -0600 |
commit | c57bca141aeb7cf21da0182dc540816aba199394 (patch) | |
tree | 99eec943e78186a60ede5e50009966c9288e809c | |
parent | 86baa0ad30bfd5402b539a008360ecd0bcca3b39 (diff) | |
parent | 0bfa18e486e8db6a28435393fdf2ec84d2050e1c (diff) |
Merge pull request #23639 from rmrector/chapter-thumb-gen
[guilib][vfs][imagecache] Load video chapter images into texture cache when viewed, like standard images
-rw-r--r-- | xbmc/TextureCache.cpp | 2 | ||||
-rw-r--r-- | xbmc/TextureCacheJob.cpp | 6 | ||||
-rw-r--r-- | xbmc/cores/VideoPlayer/DVDFileInfo.cpp | 281 | ||||
-rw-r--r-- | xbmc/cores/VideoPlayer/DVDFileInfo.h | 6 | ||||
-rw-r--r-- | xbmc/imagefiles/SpecialImageLoaderFactory.cpp | 2 | ||||
-rw-r--r-- | xbmc/imagefiles/SpecialImageLoaderFactory.h | 2 | ||||
-rw-r--r-- | xbmc/video/CMakeLists.txt | 6 | ||||
-rw-r--r-- | xbmc/video/VideoChapterImageFileLoader.cpp | 54 | ||||
-rw-r--r-- | xbmc/video/VideoChapterImageFileLoader.h | 31 | ||||
-rw-r--r-- | xbmc/video/VideoThumbLoader.cpp | 50 | ||||
-rw-r--r-- | xbmc/video/VideoThumbLoader.h | 36 | ||||
-rw-r--r-- | xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp | 69 | ||||
-rw-r--r-- | xbmc/video/dialogs/GUIDialogVideoBookmarks.h | 11 |
13 files changed, 149 insertions, 407 deletions
diff --git a/xbmc/TextureCache.cpp b/xbmc/TextureCache.cpp index e0a5e2d906..ab5fff51e7 100644 --- a/xbmc/TextureCache.cpp +++ b/xbmc/TextureCache.cpp @@ -296,7 +296,7 @@ void CTextureCache::OnCachingComplete(bool success, CTextureCacheJob *job) { if (success) { - if (job->m_oldHash == job->m_details.hash) + if (job->m_details.id != -1 && job->m_oldHash == job->m_details.hash) SetCachedTextureValid(job->m_url, job->m_details.updateable); else AddCachedTexture(job->m_url, job->m_details); diff --git a/xbmc/TextureCacheJob.cpp b/xbmc/TextureCacheJob.cpp index 0139993f3a..66edb39202 100644 --- a/xbmc/TextureCacheJob.cpp +++ b/xbmc/TextureCacheJob.cpp @@ -212,6 +212,12 @@ std::string CTextureCacheJob::DecodeImageURL(const std::string &url, unsigned in scalingAlgorithm = CPictureScalingAlgorithm::FromString(thumbURL.GetOption("scaling_algorithm")); } + if (StringUtils::StartsWith(url, "chapter://")) + { + // workaround for chapter thumbnail paths, which don't yet conform to the image:// path. + additional_info = "videochapter"; + } + // Handle special case about audiodecoder addon music files, e.g. SACD if (StringUtils::EndsWith(URIUtils::GetExtension(image), KODI_ADDON_AUDIODECODER_TRACK_EXT)) { diff --git a/xbmc/cores/VideoPlayer/DVDFileInfo.cpp b/xbmc/cores/VideoPlayer/DVDFileInfo.cpp index 73e5729e72..eb62cf24ea 100644 --- a/xbmc/cores/VideoPlayer/DVDFileInfo.cpp +++ b/xbmc/cores/VideoPlayer/DVDFileInfo.cpp @@ -87,190 +87,8 @@ int DegreeToOrientation(int degrees) } } -bool CDVDFileInfo::ExtractThumb(const CFileItem& fileItem, CTextureDetails& details, int64_t pos) -{ - const std::string redactPath = CURL::GetRedacted(fileItem.GetPath()); - auto start = std::chrono::steady_clock::now(); - - CFileItem item(fileItem); - item.SetMimeTypeForInternetFile(); - auto pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, item); - if (!pInputStream) - { - CLog::Log(LOGERROR, "InputStream: Error creating stream for {}", redactPath); - return false; - } - - if (!pInputStream->Open()) - { - CLog::Log(LOGERROR, "InputStream: Error opening, {}", redactPath); - return false; - } - - CDVDDemux *pDemuxer = NULL; - - try - { - pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(pInputStream, true); - if(!pDemuxer) - { - CLog::Log(LOGERROR, "{} - Error creating demuxer", __FUNCTION__); - return false; - } - } - catch(...) - { - CLog::Log(LOGERROR, "{} - Exception thrown when opening demuxer", __FUNCTION__); - if (pDemuxer) - delete pDemuxer; - - return false; - } - - int nVideoStream = -1; - int64_t demuxerId = -1; - for (CDemuxStream* pStream : pDemuxer->GetStreams()) - { - if (pStream) - { - // ignore if it's a picture attachment (e.g. jpeg artwork) - if (pStream->type == STREAM_VIDEO && !(pStream->flags & AV_DISPOSITION_ATTACHED_PIC)) - { - nVideoStream = pStream->uniqueId; - demuxerId = pStream->demuxerId; - } - else - pDemuxer->EnableStream(pStream->demuxerId, pStream->uniqueId, false); - } - } - - bool bOk = false; - int packetsTried = 0; - - if (nVideoStream != -1) - { - std::unique_ptr<CProcessInfo> pProcessInfo(CProcessInfo::CreateInstance()); - std::vector<AVPixelFormat> pixFmts; - pixFmts.push_back(AV_PIX_FMT_YUV420P); - pProcessInfo->SetPixFormats(pixFmts); - - CDVDStreamInfo hint(*pDemuxer->GetStream(demuxerId, nVideoStream), true); - hint.codecOptions = CODEC_FORCE_SOFTWARE; - - std::unique_ptr<CDVDVideoCodec> pVideoCodec = - CDVDFactoryCodec::CreateVideoCodec(hint, *pProcessInfo); - - if (pVideoCodec) - { - int nTotalLen = pDemuxer->GetStreamLength(); - int64_t nSeekTo = (pos == -1) ? nTotalLen / 3 : pos; - - CLog::Log(LOGDEBUG, "{} - seeking to pos {}ms (total: {}ms) in {}", __FUNCTION__, nSeekTo, - nTotalLen, redactPath); - - if (pDemuxer->SeekTime(static_cast<double>(nSeekTo), true)) - { - CDVDVideoCodec::VCReturn iDecoderState = CDVDVideoCodec::VC_NONE; - VideoPicture picture = {}; - - // num streams * 160 frames, should get a valid frame, if not abort. - int abort_index = pDemuxer->GetNrOfStreams() * 160; - do - { - DemuxPacket* pPacket = pDemuxer->Read(); - packetsTried++; - - if (!pPacket) - break; - - if (pPacket->iStreamId != nVideoStream) - { - CDVDDemuxUtils::FreeDemuxPacket(pPacket); - continue; - } - - pVideoCodec->AddData(*pPacket); - CDVDDemuxUtils::FreeDemuxPacket(pPacket); - - iDecoderState = CDVDVideoCodec::VC_NONE; - while (iDecoderState == CDVDVideoCodec::VC_NONE) - { - iDecoderState = pVideoCodec->GetPicture(&picture); - } - - if (iDecoderState == CDVDVideoCodec::VC_PICTURE) - { - if(!(picture.iFlags & DVP_FLAG_DROPPED)) - break; - } - - } while (abort_index--); - - if (iDecoderState == CDVDVideoCodec::VC_PICTURE && !(picture.iFlags & DVP_FLAG_DROPPED)) - { - { - unsigned int nWidth = std::min(picture.iDisplayWidth, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_imageRes); - double aspect = (double)picture.iDisplayWidth / (double)picture.iDisplayHeight; - if(hint.forced_aspect && hint.aspect != 0) - aspect = hint.aspect; - unsigned int nHeight = (unsigned int)((double)nWidth / aspect); - - // We pass the buffers to sws_scale uses 16 aligned widths when using intrinsics - int sizeNeeded = FFALIGN(nWidth, 16) * nHeight * 4; - uint8_t *pOutBuf = static_cast<uint8_t*>(av_malloc(sizeNeeded)); - struct SwsContext *context = sws_getContext(picture.iWidth, picture.iHeight, - AV_PIX_FMT_YUV420P, nWidth, nHeight, AV_PIX_FMT_BGRA, SWS_FAST_BILINEAR, NULL, NULL, NULL); - - if (context) - { - uint8_t *planes[YuvImage::MAX_PLANES]; - int stride[YuvImage::MAX_PLANES]; - picture.videoBuffer->GetPlanes(planes); - picture.videoBuffer->GetStrides(stride); - uint8_t *src[4]= { planes[0], planes[1], planes[2], 0 }; - int srcStride[] = { stride[0], stride[1], stride[2], 0 }; - uint8_t *dst[] = { pOutBuf, 0, 0, 0 }; - int dstStride[] = { (int)nWidth*4, 0, 0, 0 }; - int orientation = DegreeToOrientation(hint.orientation); - sws_scale(context, src, srcStride, 0, picture.iHeight, dst, dstStride); - sws_freeContext(context); - - details.width = nWidth; - details.height = nHeight; - CPicture::CacheTexture(pOutBuf, nWidth, nHeight, nWidth * 4, orientation, nWidth, nHeight, CTextureCache::GetCachedPath(details.file)); - bOk = true; - } - av_free(pOutBuf); - } - } - else - { - CLog::Log(LOGDEBUG, "{} - decode failed in {} after {} packets.", __FUNCTION__, - redactPath, packetsTried); - } - } - } - } - - if (pDemuxer) - delete pDemuxer; - - if(!bOk) - { - XFILE::CFile file; - if(file.OpenForWrite(CTextureCache::GetCachedPath(details.file))) - file.Close(); - } - - auto end = std::chrono::steady_clock::now(); - auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); - CLog::Log(LOGDEBUG, "{} - measured {} ms to extract thumb from file <{}> in {} packets. ", - __FUNCTION__, duration.count(), redactPath, packetsTried); - - return bOk; -} - -std::unique_ptr<CTexture> CDVDFileInfo::ExtractThumbToTexture(const CFileItem& fileItem) +std::unique_ptr<CTexture> CDVDFileInfo::ExtractThumbToTexture(const CFileItem& fileItem, + int chapterNumber) { if (!CanExtract(fileItem)) return {}; @@ -293,29 +111,16 @@ std::unique_ptr<CTexture> CDVDFileInfo::ExtractThumbToTexture(const CFileItem& f return {}; } - CDVDDemux* pDemuxer = NULL; - - try - { - pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(pInputStream, true); - if (!pDemuxer) - { - CLog::LogF(LOGERROR, "Error creating demuxer"); - return {}; - } - } - catch (...) + std::unique_ptr<CDVDDemux> demuxer{CDVDFactoryDemuxer::CreateDemuxer(pInputStream, true)}; + if (!demuxer) { - CLog::LogF(LOGERROR, "Exception thrown when opening demuxer"); - if (pDemuxer) - delete pDemuxer; - + CLog::LogF(LOGERROR, "Error creating demuxer"); return {}; } int nVideoStream = -1; int64_t demuxerId = -1; - for (CDemuxStream* pStream : pDemuxer->GetStreams()) + for (CDemuxStream* pStream : demuxer->GetStreams()) { if (pStream) { @@ -326,7 +131,7 @@ std::unique_ptr<CTexture> CDVDFileInfo::ExtractThumbToTexture(const CFileItem& f demuxerId = pStream->demuxerId; } else - pDemuxer->EnableStream(pStream->demuxerId, pStream->uniqueId, false); + demuxer->EnableStream(pStream->demuxerId, pStream->uniqueId, false); } } @@ -340,7 +145,7 @@ std::unique_ptr<CTexture> CDVDFileInfo::ExtractThumbToTexture(const CFileItem& f pixFmts.push_back(AV_PIX_FMT_YUV420P); pProcessInfo->SetPixFormats(pixFmts); - CDVDStreamInfo hint(*pDemuxer->GetStream(demuxerId, nVideoStream), true); + CDVDStreamInfo hint(*demuxer->GetStream(demuxerId, nVideoStream), true); hint.codecOptions = CODEC_FORCE_SOFTWARE; std::unique_ptr<CDVDVideoCodec> pVideoCodec = @@ -348,22 +153,25 @@ std::unique_ptr<CTexture> CDVDFileInfo::ExtractThumbToTexture(const CFileItem& f if (pVideoCodec) { - int nTotalLen = pDemuxer->GetStreamLength(); - int64_t nSeekTo = nTotalLen / 3; + int nTotalLen = demuxer->GetStreamLength(); + + bool seekToChapter = chapterNumber > 0 && demuxer->GetChapterCount() > 0; + int64_t nSeekTo = + seekToChapter ? demuxer->GetChapterPos(chapterNumber) * 1000 : nTotalLen / 3; CLog::LogF(LOGDEBUG, "seeking to pos {}ms (total: {}ms) in {}", nSeekTo, nTotalLen, redactPath); - if (pDemuxer->SeekTime(static_cast<double>(nSeekTo), true)) + if (demuxer->SeekTime(static_cast<double>(nSeekTo), true)) { CDVDVideoCodec::VCReturn iDecoderState = CDVDVideoCodec::VC_NONE; VideoPicture picture = {}; // num streams * 160 frames, should get a valid frame, if not abort. - int abort_index = pDemuxer->GetNrOfStreams() * 160; + int abort_index = demuxer->GetNrOfStreams() * 160; do { - DemuxPacket* pPacket = pDemuxer->Read(); + DemuxPacket* pPacket = demuxer->Read(); packetsTried++; if (!pPacket) @@ -394,35 +202,33 @@ std::unique_ptr<CTexture> CDVDFileInfo::ExtractThumbToTexture(const CFileItem& f if (iDecoderState == CDVDVideoCodec::VC_PICTURE && !(picture.iFlags & DVP_FLAG_DROPPED)) { + unsigned int nWidth = + std::min(picture.iDisplayWidth, + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_imageRes); + double aspect = (double)picture.iDisplayWidth / (double)picture.iDisplayHeight; + if (hint.forced_aspect && hint.aspect != 0) + aspect = hint.aspect; + unsigned int nHeight = (unsigned int)((double)nWidth / aspect); + + result = CTexture::CreateTexture(nWidth, nHeight); + result->SetAlpha(false); + struct SwsContext* context = + sws_getContext(picture.iWidth, picture.iHeight, AV_PIX_FMT_YUV420P, nWidth, nHeight, + AV_PIX_FMT_BGRA, SWS_FAST_BILINEAR, NULL, NULL, NULL); + + if (context) { - unsigned int nWidth = - std::min(picture.iDisplayWidth, - CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_imageRes); - double aspect = (double)picture.iDisplayWidth / (double)picture.iDisplayHeight; - if (hint.forced_aspect && hint.aspect != 0) - aspect = hint.aspect; - unsigned int nHeight = (unsigned int)((double)nWidth / aspect); - - result = CTexture::CreateTexture(nWidth, nHeight); - result->SetAlpha(false); - struct SwsContext* context = - sws_getContext(picture.iWidth, picture.iHeight, AV_PIX_FMT_YUV420P, nWidth, nHeight, - AV_PIX_FMT_BGRA, SWS_FAST_BILINEAR, NULL, NULL, NULL); - - if (context) - { - uint8_t* planes[YuvImage::MAX_PLANES]; - int stride[YuvImage::MAX_PLANES]; - picture.videoBuffer->GetPlanes(planes); - picture.videoBuffer->GetStrides(stride); - uint8_t* src[4] = {planes[0], planes[1], planes[2], 0}; - int srcStride[] = {stride[0], stride[1], stride[2], 0}; - uint8_t* dst[] = {result->GetPixels(), 0, 0, 0}; - int dstStride[] = {static_cast<int>(result->GetPitch()), 0, 0, 0}; - result->SetOrientation(DegreeToOrientation(hint.orientation)); - sws_scale(context, src, srcStride, 0, picture.iHeight, dst, dstStride); - sws_freeContext(context); - } + uint8_t* planes[YuvImage::MAX_PLANES]; + int stride[YuvImage::MAX_PLANES]; + picture.videoBuffer->GetPlanes(planes); + picture.videoBuffer->GetStrides(stride); + uint8_t* src[4] = {planes[0], planes[1], planes[2], 0}; + int srcStride[] = {stride[0], stride[1], stride[2], 0}; + uint8_t* dst[] = {result->GetPixels(), 0, 0, 0}; + int dstStride[] = {static_cast<int>(result->GetPitch()), 0, 0, 0}; + result->SetOrientation(DegreeToOrientation(hint.orientation)); + sws_scale(context, src, srcStride, 0, picture.iHeight, dst, dstStride); + sws_freeContext(context); } } else @@ -433,9 +239,6 @@ std::unique_ptr<CTexture> CDVDFileInfo::ExtractThumbToTexture(const CFileItem& f } } - if (pDemuxer) - delete pDemuxer; - auto end = std::chrono::steady_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); CLog::LogF(LOGDEBUG, "measured {} ms to extract thumb from file <{}> in {} packets. ", diff --git a/xbmc/cores/VideoPlayer/DVDFileInfo.h b/xbmc/cores/VideoPlayer/DVDFileInfo.h index bbb9776326..0129d6ac4c 100644 --- a/xbmc/cores/VideoPlayer/DVDFileInfo.h +++ b/xbmc/cores/VideoPlayer/DVDFileInfo.h @@ -23,10 +23,8 @@ class CTextureDetails; class CDVDFileInfo { public: - // Extract a thumbnail image from the media referenced by fileItem - static bool ExtractThumb(const CFileItem& fileItem, CTextureDetails& details, int64_t pos); - - static std::unique_ptr<CTexture> ExtractThumbToTexture(const CFileItem& fileItem); + static std::unique_ptr<CTexture> ExtractThumbToTexture(const CFileItem& fileItem, + int chapterNumber = 0); /*! * @brief Can a thumbnail image and file stream details be extracted from this file item? diff --git a/xbmc/imagefiles/SpecialImageLoaderFactory.cpp b/xbmc/imagefiles/SpecialImageLoaderFactory.cpp index 0fae961884..c143ad1ef4 100644 --- a/xbmc/imagefiles/SpecialImageLoaderFactory.cpp +++ b/xbmc/imagefiles/SpecialImageLoaderFactory.cpp @@ -11,6 +11,7 @@ #include "guilib/Texture.h" #include "music/MusicEmbeddedImageFileLoader.h" #include "pictures/PictureFolderImageFileLoader.h" +#include "video/VideoChapterImageFileLoader.h" #include "video/VideoEmbeddedImageFileLoader.h" #include "video/VideoGeneratedImageFileLoader.h" @@ -22,6 +23,7 @@ CSpecialImageLoaderFactory::CSpecialImageLoaderFactory() m_specialImageLoaders[1] = std::make_unique<MUSIC_INFO::CMusicEmbeddedImageFileLoader>(); m_specialImageLoaders[2] = std::make_unique<VIDEO::CVideoGeneratedImageFileLoader>(); m_specialImageLoaders[3] = std::make_unique<CPictureFolderImageFileLoader>(); + m_specialImageLoaders[4] = std::make_unique<VIDEO::CVideoChapterImageFileLoader>(); } std::unique_ptr<CTexture> CSpecialImageLoaderFactory::Load(const std::string& specialType, diff --git a/xbmc/imagefiles/SpecialImageLoaderFactory.h b/xbmc/imagefiles/SpecialImageLoaderFactory.h index d633c617f1..e5bb7b6259 100644 --- a/xbmc/imagefiles/SpecialImageLoaderFactory.h +++ b/xbmc/imagefiles/SpecialImageLoaderFactory.h @@ -29,6 +29,6 @@ public: unsigned int preferredHeight) const; private: - std::array<std::unique_ptr<ISpecialImageFileLoader>, 4> m_specialImageLoaders{}; + std::array<std::unique_ptr<ISpecialImageFileLoader>, 5> m_specialImageLoaders{}; }; } // namespace IMAGE_FILES diff --git a/xbmc/video/CMakeLists.txt b/xbmc/video/CMakeLists.txt index b5068599b7..06e559c938 100644 --- a/xbmc/video/CMakeLists.txt +++ b/xbmc/video/CMakeLists.txt @@ -3,7 +3,7 @@ set(SOURCES Bookmark.cpp GUIViewStateVideo.cpp PlayerController.cpp Teletext.cpp - VideoItemArtworkHandler.cpp + VideoChapterImageFileLoader.cpp VideoDatabase.cpp VideoDbUrl.cpp VideoEmbeddedImageFileLoader.cpp @@ -11,6 +11,7 @@ set(SOURCES Bookmark.cpp VideoInfoDownloader.cpp VideoInfoScanner.cpp VideoInfoTag.cpp + VideoItemArtworkHandler.cpp VideoLibraryQueue.cpp VideoThumbLoader.cpp VideoUtils.cpp @@ -23,7 +24,7 @@ set(HEADERS Bookmark.h PlayerController.h Teletext.h TeletextDefines.h - VideoItemArtworkHandler.h + VideoChapterImageFileLoader.h VideoDatabase.h VideoDbUrl.h VideoEmbeddedImageFileLoader.h @@ -31,6 +32,7 @@ set(HEADERS Bookmark.h VideoInfoDownloader.h VideoInfoScanner.h VideoInfoTag.h + VideoItemArtworkHandler.h VideoLibraryQueue.h VideoThumbLoader.h VideoUtils.h diff --git a/xbmc/video/VideoChapterImageFileLoader.cpp b/xbmc/video/VideoChapterImageFileLoader.cpp new file mode 100644 index 0000000000..5cb0704ff4 --- /dev/null +++ b/xbmc/video/VideoChapterImageFileLoader.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023 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 "VideoChapterImageFileLoader.h" + +#include "DVDFileInfo.h" +#include "FileItem.h" +#include "ServiceBroker.h" +#include "guilib/Texture.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/log.h" + +bool VIDEO::CVideoChapterImageFileLoader::CanLoad(const std::string& specialType) const +{ + return specialType == "videochapter"; +} + +std::unique_ptr<CTexture> VIDEO::CVideoChapterImageFileLoader::Load( + const std::string& specialType, + const std::string& goofyChapterPath, + unsigned int, + unsigned int) const +{ + // "goofy" chapter path because these paths don't yet conform to 'image://' path standard + + // 10 = length of "chapter://" string prefix from GUIDialogVideoBookmarks + size_t lastSlashPos = goofyChapterPath.rfind("/"); + std::string cleanname = goofyChapterPath.substr(10, lastSlashPos - 10); + + int chapterNum = 0; + try + { + chapterNum = std::stoi(goofyChapterPath.substr(lastSlashPos + 1)); + } + catch (...) + { + // invalid_argument because these paths can come from anywhere + // out_of_range mostly for the same reason - 32k+ seems high for a chapter count + return {}; + } + if (chapterNum < 1) + { + return {}; + } + + CFileItem item{cleanname, false}; + return CDVDFileInfo::ExtractThumbToTexture(item, chapterNum); +} diff --git a/xbmc/video/VideoChapterImageFileLoader.h b/xbmc/video/VideoChapterImageFileLoader.h new file mode 100644 index 0000000000..9cd2eab496 --- /dev/null +++ b/xbmc/video/VideoChapterImageFileLoader.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2023 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. + */ + +#pragma once + +#include "imagefiles/SpecialImageFileLoader.h" + +namespace VIDEO +{ +/*! + * @brief Generates a texture for a thumbnail of a video chapter. +*/ +class CVideoChapterImageFileLoader : public IMAGE_FILES::ISpecialImageFileLoader +{ +public: + CVideoChapterImageFileLoader() = default; + ~CVideoChapterImageFileLoader() override = default; + + bool CanLoad(const std::string& specialType) const override; + std::unique_ptr<CTexture> Load(const std::string& specialType, + const std::string& goofyChapterPath, + unsigned int preferredWidth, + unsigned int preferredHeight) const override; +}; + +} // namespace VIDEO diff --git a/xbmc/video/VideoThumbLoader.cpp b/xbmc/video/VideoThumbLoader.cpp index 7bce9f300e..91d1e7a436 100644 --- a/xbmc/video/VideoThumbLoader.cpp +++ b/xbmc/video/VideoThumbLoader.cpp @@ -37,56 +37,6 @@ using namespace XFILE; using namespace VIDEO; -CChapterThumbExtractor::CChapterThumbExtractor(const CFileItem& item, - const std::string& listpath, - const std::string& target, - int64_t pos) - : m_target(target), m_listpath(listpath), m_item(item) -{ - m_pos = pos; - - if (item.IsVideoDb() && item.HasVideoInfoTag()) - m_item.SetPath(item.GetVideoInfoTag()->m_strFileNameAndPath); - - if (m_item.IsStack()) - m_item.SetPath(CStackDirectory::GetFirstStackedFile(m_item.GetPath())); -} - -CChapterThumbExtractor::~CChapterThumbExtractor() = default; - -bool CChapterThumbExtractor::operator==(const CJob* job) const -{ - if (strcmp(job->GetType(),GetType()) == 0) - { - const CChapterThumbExtractor* jobExtract = dynamic_cast<const CChapterThumbExtractor*>(job); - if (jobExtract && jobExtract->m_listpath == m_listpath - && jobExtract->m_target == m_target) - return true; - } - return false; -} - -bool CChapterThumbExtractor::DoWork() -{ - if (!CDVDFileInfo::CanExtract(m_item)) - return false; - - bool result=false; - CLog::LogF(LOGDEBUG, "trying to extract thumb from video file {}", - CURL::GetRedacted(m_item.GetPath())); - // construct the thumb cache file - CTextureDetails details; - details.file = CTextureCache::GetCacheFile(m_target) + ".jpg"; - result = CDVDFileInfo::ExtractThumb(m_item, details, m_pos); - if (!result) - return false; - - CServiceBroker::GetTextureCache()->AddCachedTexture(m_target, details); - m_item.SetArt("thumb", m_target); - - return true; -} - CVideoThumbLoader::CVideoThumbLoader() : CThumbLoader() { m_videoDatabase = new CVideoDatabase(); diff --git a/xbmc/video/VideoThumbLoader.h b/xbmc/video/VideoThumbLoader.h index 9cf0a9482f..f5505fe860 100644 --- a/xbmc/video/VideoThumbLoader.h +++ b/xbmc/video/VideoThumbLoader.h @@ -10,7 +10,6 @@ #include "FileItem.h" #include "ThumbLoader.h" -#include "utils/JobManager.h" #include <map> #include <vector> @@ -22,41 +21,6 @@ class EmbeddedArt; using ArtMap = std::map<std::string, std::string>; using ArtCache = std::map<std::pair<MediaType, int>, ArtMap>; -/*! - \ingroup thumbs,jobs - \brief Thumb extractor job class - - Used by the "chapter browser" GUI window to generate chapter thumbs. - - \sa CVideoThumbLoader and CJob - */ -class CChapterThumbExtractor : public CJob -{ -public: - CChapterThumbExtractor(const CFileItem& item, - const std::string& listpath, - const std::string& strTarget = "", - int64_t pos = -1); - ~CChapterThumbExtractor() override; - - /*! - \brief Work function that extracts thumb. - */ - bool DoWork() override; - - const char* GetType() const override - { - return kJobTypeMediaFlags; - } - - bool operator==(const CJob* job) const override; - - std::string m_target; ///< thumbpath - std::string m_listpath; ///< path used in fileitem list - CFileItem m_item; - int64_t m_pos; ///< position to extract thumb from -}; - class CVideoThumbLoader : public CThumbLoader { public: diff --git a/xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp b/xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp index c4428817ae..425344219e 100644 --- a/xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp @@ -35,7 +35,6 @@ #include "utils/Variant.h" #include "utils/log.h" #include "video/VideoDatabase.h" -#include "video/VideoThumbLoader.h" #include "view/ViewState.h" #include <mutex> @@ -51,12 +50,10 @@ #define CONTROL_THUMBS 11 CGUIDialogVideoBookmarks::CGUIDialogVideoBookmarks() - : CGUIDialog(WINDOW_DIALOG_VIDEO_BOOKMARKS, "VideoOSDBookmarks.xml"), - CJobQueue(false, 1, CJob::PRIORITY_NORMAL) + : CGUIDialog(WINDOW_DIALOG_VIDEO_BOOKMARKS, "VideoOSDBookmarks.xml") { m_vecItems = new CFileItemList; m_loadType = LOAD_EVERY_TIME; - m_jobsStarted = 0; } CGUIDialogVideoBookmarks::~CGUIDialogVideoBookmarks() @@ -137,9 +134,6 @@ bool CGUIDialogVideoBookmarks::OnMessage(CGUIMessage& message) case 0: OnRefreshList(); break; - case 1: - UpdateItem(message.GetParam2()); - break; default: break; } @@ -202,30 +196,6 @@ void CGUIDialogVideoBookmarks::Delete(int item) Update(); } -void CGUIDialogVideoBookmarks::UpdateItem(unsigned int chapterIdx) -{ - std::unique_lock<CCriticalSection> lock(m_refreshSection); - - int itemPos = 0; - for (const auto& item : *m_vecItems) - { - if (chapterIdx == item->GetProperty("chapter").asInteger()) - break; - itemPos++; - } - - if (itemPos < m_vecItems->Size()) - { - std::string time = StringUtils::Format("chapter://{}/{}", m_filePath, chapterIdx); - std::string cachefile = CServiceBroker::GetTextureCache()->GetCachedPath( - CServiceBroker::GetTextureCache()->GetCacheFile(time) + ".jpg"); - if (CFileUtils::Exists(cachefile)) - { - (*m_vecItems)[itemPos]->SetArt("thumb", cachefile); - } - } -} - void CGUIDialogVideoBookmarks::OnRefreshList() { m_bookmarks.clear(); @@ -285,18 +255,11 @@ void CGUIDialogVideoBookmarks::OnRefreshList() CFileItemPtr item(new CFileItem(chapterName)); item->SetLabel2(time); - std::string chapterPath = StringUtils::Format("chapter://{}/{}", m_filePath, i); - std::string cachefile = CServiceBroker::GetTextureCache()->GetCachedPath( - CServiceBroker::GetTextureCache()->GetCacheFile(chapterPath) + ".jpg"); - if (CFileUtils::Exists(cachefile)) - item->SetArt("thumb", cachefile); - else if (i > m_jobsStarted && CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_MYVIDEOS_EXTRACTCHAPTERTHUMBS)) + if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + CSettings::SETTING_MYVIDEOS_EXTRACTCHAPTERTHUMBS)) { - CFileItem item(m_filePath, false); - CJob* job = new CChapterThumbExtractor(item, m_filePath, chapterPath, pos * 1000); - AddJob(job); - m_mapJobsChapter[job] = i; - m_jobsStarted++; + std::string chapterPath = StringUtils::Format("chapter://{}/{}", m_filePath, i); + item->SetArt("thumb", chapterPath); } item->SetProperty("chapter", i); @@ -478,16 +441,11 @@ void CGUIDialogVideoBookmarks::OnWindowLoaded() m_viewControl.Reset(); m_viewControl.SetParentWindow(GetID()); m_viewControl.AddView(GetControl(CONTROL_THUMBS)); - m_jobsStarted = 0; - m_mapJobsChapter.clear(); m_vecItems->Clear(); } void CGUIDialogVideoBookmarks::OnWindowUnload() { - //stop running thumb extraction jobs - CancelJobs(); - m_mapJobsChapter.clear(); m_vecItems->Clear(); CGUIDialog::OnWindowUnload(); m_viewControl.Reset(); @@ -571,20 +529,3 @@ bool CGUIDialogVideoBookmarks::OnAddEpisodeBookmark() } return bReturn; } - -void CGUIDialogVideoBookmarks::OnJobComplete(unsigned int jobID, - bool success, CJob* job) -{ - if (success && IsActive()) - { - MAPJOBSCHAPS::iterator iter = m_mapJobsChapter.find(job); - if (iter != m_mapJobsChapter.end()) - { - unsigned int chapterIdx = (*iter).second; - CGUIMessage m(GUI_MSG_REFRESH_LIST, GetID(), 0, 1, chapterIdx); - CServiceBroker::GetAppMessenger()->SendGUIMessage(m); - m_mapJobsChapter.erase(iter); - } - } - CJobQueue::OnJobComplete(jobID, success, job); -} diff --git a/xbmc/video/dialogs/GUIDialogVideoBookmarks.h b/xbmc/video/dialogs/GUIDialogVideoBookmarks.h index 801afcdd37..09fa5e3e98 100644 --- a/xbmc/video/dialogs/GUIDialogVideoBookmarks.h +++ b/xbmc/video/dialogs/GUIDialogVideoBookmarks.h @@ -9,16 +9,13 @@ #pragma once #include "guilib/GUIDialog.h" -#include "utils/JobManager.h" #include "video/VideoDatabase.h" #include "view/GUIViewControl.h" class CFileItemList; -class CGUIDialogVideoBookmarks : public CGUIDialog, public CJobQueue +class CGUIDialogVideoBookmarks : public CGUIDialog { - typedef std::map<CJob*, unsigned int> MAPJOBSCHAPS; - public: CGUIDialogVideoBookmarks(void); ~CGUIDialogVideoBookmarks(void) override; @@ -60,17 +57,11 @@ protected: void OnPopupMenu(int item); CGUIControl *GetFirstFocusableControl(int id) override; - void OnJobComplete(unsigned int jobID, bool success, CJob* job) override; - CFileItemList* m_vecItems; CGUIViewControl m_viewControl; VECBOOKMARKS m_bookmarks; private: - void UpdateItem(unsigned int chapterIdx); - - int m_jobsStarted; std::string m_filePath; CCriticalSection m_refreshSection; - MAPJOBSCHAPS m_mapJobsChapter; }; |