Merge pull request #25922 from sarbes/shader-cleanup
[xbmc.git] / xbmc / filesystem / AudioBookFileDirectory.cpp
blobf730ec2df4de562138a3a3890a2613bf6ddebdb3
1 /*
2 * Copyright (C) 2014 Arne Morten Kvarving
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 * See LICENSES/README.md for more information.
6 */
8 #include "AudioBookFileDirectory.h"
10 #include "FileItem.h"
11 #include "FileItemList.h"
12 #include "URL.h"
13 #include "Util.h"
14 #include "cores/FFmpeg.h"
15 #include "filesystem/File.h"
16 #include "guilib/LocalizeStrings.h"
17 #include "imagefiles/ImageFileURL.h"
18 #include "music/tags/MusicInfoTag.h"
19 #include "utils/StringUtils.h"
21 using namespace XFILE;
23 static int cfile_file_read(void *h, uint8_t* buf, int size)
25 CFile* pFile = static_cast<CFile*>(h);
26 return pFile->Read(buf, size);
29 static int64_t cfile_file_seek(void *h, int64_t pos, int whence)
31 CFile* pFile = static_cast<CFile*>(h);
32 if(whence == AVSEEK_SIZE)
33 return pFile->GetLength();
34 else
35 return pFile->Seek(pos, whence & ~AVSEEK_FORCE);
38 CAudioBookFileDirectory::~CAudioBookFileDirectory(void)
40 if (m_fctx)
41 avformat_close_input(&m_fctx);
42 if (m_ioctx)
44 av_free(m_ioctx->buffer);
45 av_free(m_ioctx);
49 bool CAudioBookFileDirectory::GetDirectory(const CURL& url,
50 CFileItemList &items)
52 if (!m_fctx && !ContainsFiles(url))
53 return true;
55 std::string title;
56 std::string author;
57 std::string album;
59 AVDictionaryEntry* tag=nullptr;
60 while ((tag = av_dict_get(m_fctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
62 if (StringUtils::CompareNoCase(tag->key, "title") == 0)
63 title = tag->value;
64 else if (StringUtils::CompareNoCase(tag->key, "album") == 0)
65 album = tag->value;
66 else if (StringUtils::CompareNoCase(tag->key, "artist") == 0)
67 author = tag->value;
70 std::string thumb;
71 if (m_fctx->nb_chapters > 1)
72 thumb = IMAGE_FILES::URLFromFile(url.Get(), "music");
74 for (size_t i=0;i<m_fctx->nb_chapters;++i)
76 tag=nullptr;
77 std::string chaptitle = StringUtils::Format(g_localizeStrings.Get(25010), i + 1);
78 std::string chapauthor;
79 std::string chapalbum;
80 while ((tag=av_dict_get(m_fctx->chapters[i]->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
82 if (StringUtils::CompareNoCase(tag->key, "title") == 0)
83 chaptitle = tag->value;
84 else if (StringUtils::CompareNoCase(tag->key, "artist") == 0)
85 chapauthor = tag->value;
86 else if (StringUtils::CompareNoCase(tag->key, "album") == 0)
87 chapalbum = tag->value;
89 CFileItemPtr item(new CFileItem(url.Get(),false));
90 item->GetMusicInfoTag()->SetTrackNumber(i+1);
91 item->GetMusicInfoTag()->SetLoaded(true);
92 item->GetMusicInfoTag()->SetTitle(chaptitle);
93 if (album.empty())
94 item->GetMusicInfoTag()->SetAlbum(title);
95 else if (chapalbum.empty())
96 item->GetMusicInfoTag()->SetAlbum(album);
97 else
98 item->GetMusicInfoTag()->SetAlbum(chapalbum);
99 if (chapauthor.empty())
100 item->GetMusicInfoTag()->SetArtist(author);
101 else
102 item->GetMusicInfoTag()->SetArtist(chapauthor);
104 item->SetLabel(StringUtils::Format("{0:02}. {1} - {2}", i + 1,
105 item->GetMusicInfoTag()->GetAlbum(),
106 item->GetMusicInfoTag()->GetTitle()));
107 item->SetStartOffset(CUtil::ConvertSecsToMilliSecs(m_fctx->chapters[i]->start *
108 av_q2d(m_fctx->chapters[i]->time_base)));
109 item->SetEndOffset(CUtil::ConvertSecsToMilliSecs(m_fctx->chapters[i]->end *
110 av_q2d(m_fctx->chapters[i]->time_base)));
111 int compare = m_fctx->streams[0]->duration * av_q2d(m_fctx->streams[0]->time_base);
112 if (item->GetEndOffset() < 0 ||
113 item->GetEndOffset() > CUtil::ConvertMilliSecsToSecs(m_fctx->duration))
115 if (i < m_fctx->nb_chapters - 1)
116 item->SetEndOffset(CUtil::ConvertSecsToMilliSecs(
117 m_fctx->chapters[i + 1]->start * av_q2d(m_fctx->chapters[i + 1]->time_base)));
118 else
120 item->SetEndOffset(m_fctx->duration); // mka file
121 if (item->GetEndOffset() < 0)
122 item->SetEndOffset(compare); // m4b file
125 item->GetMusicInfoTag()->SetDuration(
126 CUtil::ConvertMilliSecsToSecsInt(item->GetEndOffset() - item->GetStartOffset()));
127 item->SetProperty("item_start", item->GetStartOffset());
128 item->SetProperty("audio_bookmark", item->GetStartOffset());
129 if (!thumb.empty())
130 item->SetArt("thumb", thumb);
131 items.Add(item);
134 return true;
137 bool CAudioBookFileDirectory::Exists(const CURL& url)
139 return CFile::Exists(url) && ContainsFiles(url);
142 bool CAudioBookFileDirectory::ContainsFiles(const CURL& url)
144 CFile file;
145 if (!file.Open(url))
146 return false;
148 uint8_t* buffer = (uint8_t*)av_malloc(32768);
149 m_ioctx = avio_alloc_context(buffer, 32768, 0, &file, cfile_file_read,
150 nullptr, cfile_file_seek);
152 m_fctx = avformat_alloc_context();
153 m_fctx->pb = m_ioctx;
155 if (file.IoControl(IOCTRL_SEEK_POSSIBLE, nullptr) == 0)
156 m_ioctx->seekable = 0;
158 m_ioctx->max_packet_size = 32768;
160 const AVInputFormat* iformat = nullptr;
161 av_probe_input_buffer(m_ioctx, &iformat, url.Get().c_str(), nullptr, 0, 0);
163 bool contains = false;
164 if (avformat_open_input(&m_fctx, url.Get().c_str(), iformat, nullptr) < 0)
166 if (m_fctx)
167 avformat_close_input(&m_fctx);
168 av_free(m_ioctx->buffer);
169 av_free(m_ioctx);
170 return false;
173 contains = m_fctx->nb_chapters > 1;
175 return contains;