2 * Copyright (C) 2013 Arne Morten Kvarving
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 * See LICENSES/README.md for more information.
8 #include "AudioDecoder.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
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()
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
)
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
)
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
)
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!
75 tag
.Load(file
.GetDynPath(), XFILE::CMusicFileDirectory::m_tag
, nullptr);
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
);
87 if (channels
<= 0 || sampleRate
<= 0 || addonFormat
== AUDIOENGINE_FMT_INVALID
)
90 "CAudioDecoder::{} - Addon '{}' returned true without set of needed values",
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
)
104 layout
+= Interface_AudioEngine::TranslateAEChannelToKodi(channel
);
107 m_format
.m_channelLayout
= layout
;
110 m_format
.m_channelLayout
= CAEUtil::GuessChLayout(channels
);
116 int CAudioDecoder::ReadPCM(uint8_t* buffer
, size_t size
, size_t* actualsize
)
118 if (!m_ifc
.audiodecoder
->toAddon
->read_pcm
)
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
)
129 m_ifc
.audiodecoder
->toAddon
->seek(m_ifc
.hdl
, time
);
133 bool CAudioDecoder::Load(const std::string
& fileName
,
134 MUSIC_INFO::CMusicInfoTag
& tag
,
137 if (!m_ifc
.audiodecoder
->toAddon
->read_tag
)
140 KODI_ADDON_AUDIODECODER_INFO_TAG ifcTag
= {};
141 bool ret
= m_ifc
.audiodecoder
->toAddon
->read_tag(m_ifc
.hdl
, fileName
.c_str(), &ifcTag
);
146 tag
.SetTitle(ifcTag
.title
);
151 tag
.SetArtist(ifcTag
.artist
);
156 tag
.SetAlbum(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
);
171 tag
.SetGenre(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
);
190 tag
.SetLyrics(ifcTag
.lyrics
);
193 tag
.SetSampleRate(ifcTag
.samplerate
);
194 tag
.SetNoOfChannels(ifcTag
.channels
);
195 tag
.SetBitRate(ifcTag
.bitrate
);
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/"))
209 std::vector
<uint8_t> buf
;
211 if (file
.LoadFile(ifcTag
.cover_art_path
, buf
) > 0)
213 tag
.SetCoverArtInfo(buf
.size(), mimetype
);
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
);
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
);
238 int CAudioDecoder::GetTrackCount(const std::string
& strPath
)
240 if (!m_ifc
.audiodecoder
->toAddon
->track_count
)
243 int result
= m_ifc
.audiodecoder
->toAddon
->track_count(m_ifc
.hdl
, strPath
.c_str());
249 if (!Load(strPath
, XFILE::CMusicFileDirectory::m_tag
, nullptr))
253 XFILE::CMusicFileDirectory::m_tag
.SetTitle(CURL(strPath
).GetFileNameWithoutPath());
254 XFILE::CMusicFileDirectory::m_tag
.SetLoaded(true);