Merge pull request #26148 from ksooo/fix-secondstotimestring-warning
[xbmc.git] / xbmc / addons / AudioDecoder.cpp
blobf2531a19eb0140c9141cd0e5f740e50820fede4d
1 /*
2 * Copyright (C) 2013 Arne Morten Kvarving
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 * See LICENSES/README.md for more information.
6 */
8 #include "AudioDecoder.h"
10 #include "FileItem.h"
11 #include "addons/addoninfo/AddonInfo.h"
12 #include "addons/addoninfo/AddonType.h"
13 #include "addons/interfaces/AudioEngine.h"
14 #include "cores/AudioEngine/Utils/AEUtil.h"
15 #include "filesystem/File.h"
16 #include "music/tags/MusicInfoTag.h"
17 #include "music/tags/TagLoaderTagLib.h"
18 #include "utils/Mime.h"
19 #include "utils/URIUtils.h"
20 #include "utils/log.h"
22 using namespace ADDON;
23 using namespace KODI::ADDONS;
25 CAudioDecoder::CAudioDecoder(const AddonInfoPtr& addonInfo)
26 : IAddonInstanceHandler(ADDON_INSTANCE_AUDIODECODER, addonInfo)
28 m_CodecName = addonInfo->Type(AddonType::AUDIODECODER)->GetValue("@name").asString();
29 m_strExt = m_CodecName + KODI_ADDON_AUDIODECODER_TRACK_EXT;
30 m_hasTags = addonInfo->Type(AddonType::AUDIODECODER)->GetValue("@tags").asBoolean();
32 // Create all interface parts independent to make API changes easier if
33 // something is added
34 m_ifc.audiodecoder = new AddonInstance_AudioDecoder;
35 m_ifc.audiodecoder->toAddon = new KodiToAddonFuncTable_AudioDecoder();
36 m_ifc.audiodecoder->toKodi = new AddonToKodiFuncTable_AudioDecoder();
37 m_ifc.audiodecoder->toKodi->kodiInstance = this;
40 CAudioDecoder::~CAudioDecoder()
42 DestroyInstance();
44 delete m_ifc.audiodecoder->toKodi;
45 delete m_ifc.audiodecoder->toAddon;
46 delete m_ifc.audiodecoder;
49 bool CAudioDecoder::CreateDecoder()
51 if (CreateInstance() != ADDON_STATUS_OK)
52 return false;
54 return true;
57 bool CAudioDecoder::SupportsFile(const std::string& filename)
59 // Create in case not available, possible as this done by IAddonSupportCheck
60 if ((!m_ifc.hdl && !CreateDecoder()) || !m_ifc.audiodecoder->toAddon->supports_file)
61 return false;
63 return m_ifc.audiodecoder->toAddon->supports_file(m_ifc.hdl, filename.c_str());
66 bool CAudioDecoder::Init(const CFileItem& file, unsigned int filecache)
68 if (!m_ifc.audiodecoder->toAddon->init)
69 return false;
71 /// for replaygain
72 /// @todo About audio decoder in most cases Kodi's one not work, add fallback
73 /// to use addon if this fails. Need API change about addons music info tag!
74 CTagLoaderTagLib tag;
75 tag.Load(file.GetDynPath(), XFILE::CMusicFileDirectory::m_tag, nullptr);
77 int channels = -1;
78 int sampleRate = -1;
79 AudioEngineDataFormat addonFormat = AUDIOENGINE_FMT_INVALID;
80 AudioEngineChannel channelList[AUDIOENGINE_CH_MAX] = {AUDIOENGINE_CH_NULL};
82 bool ret = m_ifc.audiodecoder->toAddon->init(m_ifc.hdl, file.GetDynPath().c_str(), filecache,
83 &channels, &sampleRate, &m_bitsPerSample,
84 &m_TotalTime, &m_bitRate, &addonFormat, channelList);
85 if (ret)
87 if (channels <= 0 || sampleRate <= 0 || addonFormat == AUDIOENGINE_FMT_INVALID)
89 CLog::Log(LOGERROR,
90 "CAudioDecoder::{} - Addon '{}' returned true without set of needed values",
91 __func__, ID());
92 return false;
95 m_format.m_dataFormat = Interface_AudioEngine::TranslateAEFormatToKodi(addonFormat);
96 m_format.m_sampleRate = sampleRate;
97 if (channelList[0] != AUDIOENGINE_CH_NULL)
99 CAEChannelInfo layout;
100 for (const auto& channel : channelList)
102 if (channel == AUDIOENGINE_CH_NULL)
103 break;
104 layout += Interface_AudioEngine::TranslateAEChannelToKodi(channel);
107 m_format.m_channelLayout = layout;
109 else
110 m_format.m_channelLayout = CAEUtil::GuessChLayout(channels);
113 return ret;
116 int CAudioDecoder::ReadPCM(uint8_t* buffer, size_t size, size_t* actualsize)
118 if (!m_ifc.audiodecoder->toAddon->read_pcm)
119 return 0;
121 return m_ifc.audiodecoder->toAddon->read_pcm(m_ifc.hdl, buffer, size, actualsize);
124 bool CAudioDecoder::Seek(int64_t time)
126 if (!m_ifc.audiodecoder->toAddon->seek)
127 return false;
129 m_ifc.audiodecoder->toAddon->seek(m_ifc.hdl, time);
130 return true;
133 bool CAudioDecoder::Load(const std::string& fileName,
134 MUSIC_INFO::CMusicInfoTag& tag,
135 EmbeddedArt* art)
137 if (!m_ifc.audiodecoder->toAddon->read_tag)
138 return false;
140 KODI_ADDON_AUDIODECODER_INFO_TAG ifcTag = {};
141 bool ret = m_ifc.audiodecoder->toAddon->read_tag(m_ifc.hdl, fileName.c_str(), &ifcTag);
142 if (ret)
144 if (ifcTag.title)
146 tag.SetTitle(ifcTag.title);
147 free(ifcTag.title);
149 if (ifcTag.artist)
151 tag.SetArtist(ifcTag.artist);
152 free(ifcTag.artist);
154 if (ifcTag.album)
156 tag.SetAlbum(ifcTag.album);
157 free(ifcTag.album);
159 if (ifcTag.album_artist)
161 tag.SetAlbumArtist(ifcTag.album_artist);
162 free(ifcTag.album_artist);
164 if (ifcTag.media_type)
166 tag.SetType(ifcTag.media_type);
167 free(ifcTag.media_type);
169 if (ifcTag.genre)
171 tag.SetGenre(ifcTag.genre);
172 free(ifcTag.genre);
174 tag.SetDuration(ifcTag.duration);
175 tag.SetTrackNumber(ifcTag.track);
176 tag.SetDiscNumber(ifcTag.disc);
177 if (ifcTag.disc_subtitle)
179 tag.SetDiscSubtitle(ifcTag.disc_subtitle);
180 free(ifcTag.disc_subtitle);
182 tag.SetTotalDiscs(ifcTag.disc_total);
183 if (ifcTag.release_date)
185 tag.SetReleaseDate(ifcTag.release_date);
186 free(ifcTag.release_date);
188 if (ifcTag.lyrics)
190 tag.SetLyrics(ifcTag.lyrics);
191 free(ifcTag.lyrics);
193 tag.SetSampleRate(ifcTag.samplerate);
194 tag.SetNoOfChannels(ifcTag.channels);
195 tag.SetBitRate(ifcTag.bitrate);
196 if (ifcTag.comment)
198 tag.SetComment(ifcTag.comment);
199 free(ifcTag.comment);
202 if (ifcTag.cover_art_path)
204 const std::string mimetype =
205 CMime::GetMimeType(URIUtils::GetExtension(ifcTag.cover_art_path));
206 if (StringUtils::StartsWith(mimetype, "image/"))
208 XFILE::CFile file;
209 std::vector<uint8_t> buf;
211 if (file.LoadFile(ifcTag.cover_art_path, buf) > 0)
213 tag.SetCoverArtInfo(buf.size(), mimetype);
214 if (art)
215 art->Set(reinterpret_cast<const uint8_t*>(buf.data()), buf.size(), mimetype);
218 free(ifcTag.cover_art_path);
220 else if (ifcTag.cover_art_mem_mimetype && ifcTag.cover_art_mem && ifcTag.cover_art_mem_size > 0)
222 tag.SetCoverArtInfo(ifcTag.cover_art_mem_size, ifcTag.cover_art_mem_mimetype);
223 if (art)
224 art->Set(ifcTag.cover_art_mem, ifcTag.cover_art_mem_size, ifcTag.cover_art_mem_mimetype);
227 if (ifcTag.cover_art_mem_mimetype)
228 free(ifcTag.cover_art_mem_mimetype);
229 if (ifcTag.cover_art_mem)
230 free(ifcTag.cover_art_mem);
232 tag.SetLoaded(true);
235 return ret;
238 int CAudioDecoder::GetTrackCount(const std::string& strPath)
240 if (!m_ifc.audiodecoder->toAddon->track_count)
241 return 0;
243 int result = m_ifc.audiodecoder->toAddon->track_count(m_ifc.hdl, strPath.c_str());
245 if (result > 1)
247 if (m_hasTags)
249 if (!Load(strPath, XFILE::CMusicFileDirectory::m_tag, nullptr))
250 return 0;
252 else
253 XFILE::CMusicFileDirectory::m_tag.SetTitle(CURL(strPath).GetFileNameWithoutPath());
254 XFILE::CMusicFileDirectory::m_tag.SetLoaded(true);
257 return result;