summaryrefslogtreecommitdiffstats
path: root/xbmc/addons/AudioDecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/addons/AudioDecoder.cpp')
-rw-r--r--xbmc/addons/AudioDecoder.cpp258
1 files changed, 258 insertions, 0 deletions
diff --git a/xbmc/addons/AudioDecoder.cpp b/xbmc/addons/AudioDecoder.cpp
new file mode 100644
index 0000000..f2531a1
--- /dev/null
+++ b/xbmc/addons/AudioDecoder.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2013 Arne Morten Kvarving
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "AudioDecoder.h"
+
+#include "FileItem.h"
+#include "addons/addoninfo/AddonInfo.h"
+#include "addons/addoninfo/AddonType.h"
+#include "addons/interfaces/AudioEngine.h"
+#include "cores/AudioEngine/Utils/AEUtil.h"
+#include "filesystem/File.h"
+#include "music/tags/MusicInfoTag.h"
+#include "music/tags/TagLoaderTagLib.h"
+#include "utils/Mime.h"
+#include "utils/URIUtils.h"
+#include "utils/log.h"
+
+using namespace ADDON;
+using namespace KODI::ADDONS;
+
+CAudioDecoder::CAudioDecoder(const AddonInfoPtr& addonInfo)
+ : IAddonInstanceHandler(ADDON_INSTANCE_AUDIODECODER, addonInfo)
+{
+ m_CodecName = addonInfo->Type(AddonType::AUDIODECODER)->GetValue("@name").asString();
+ m_strExt = m_CodecName + KODI_ADDON_AUDIODECODER_TRACK_EXT;
+ m_hasTags = addonInfo->Type(AddonType::AUDIODECODER)->GetValue("@tags").asBoolean();
+
+ // Create all interface parts independent to make API changes easier if
+ // something is added
+ m_ifc.audiodecoder = new AddonInstance_AudioDecoder;
+ m_ifc.audiodecoder->toAddon = new KodiToAddonFuncTable_AudioDecoder();
+ m_ifc.audiodecoder->toKodi = new AddonToKodiFuncTable_AudioDecoder();
+ m_ifc.audiodecoder->toKodi->kodiInstance = this;
+}
+
+CAudioDecoder::~CAudioDecoder()
+{
+ DestroyInstance();
+
+ delete m_ifc.audiodecoder->toKodi;
+ delete m_ifc.audiodecoder->toAddon;
+ delete m_ifc.audiodecoder;
+}
+
+bool CAudioDecoder::CreateDecoder()
+{
+ if (CreateInstance() != ADDON_STATUS_OK)
+ return false;
+
+ return true;
+}
+
+bool CAudioDecoder::SupportsFile(const std::string& filename)
+{
+ // Create in case not available, possible as this done by IAddonSupportCheck
+ if ((!m_ifc.hdl && !CreateDecoder()) || !m_ifc.audiodecoder->toAddon->supports_file)
+ return false;
+
+ return m_ifc.audiodecoder->toAddon->supports_file(m_ifc.hdl, filename.c_str());
+}
+
+bool CAudioDecoder::Init(const CFileItem& file, unsigned int filecache)
+{
+ if (!m_ifc.audiodecoder->toAddon->init)
+ return false;
+
+ /// for replaygain
+ /// @todo About audio decoder in most cases Kodi's one not work, add fallback
+ /// to use addon if this fails. Need API change about addons music info tag!
+ CTagLoaderTagLib tag;
+ tag.Load(file.GetDynPath(), XFILE::CMusicFileDirectory::m_tag, nullptr);
+
+ int channels = -1;
+ int sampleRate = -1;
+ AudioEngineDataFormat addonFormat = AUDIOENGINE_FMT_INVALID;
+ AudioEngineChannel channelList[AUDIOENGINE_CH_MAX] = {AUDIOENGINE_CH_NULL};
+
+ bool ret = m_ifc.audiodecoder->toAddon->init(m_ifc.hdl, file.GetDynPath().c_str(), filecache,
+ &channels, &sampleRate, &m_bitsPerSample,
+ &m_TotalTime, &m_bitRate, &addonFormat, channelList);
+ if (ret)
+ {
+ if (channels <= 0 || sampleRate <= 0 || addonFormat == AUDIOENGINE_FMT_INVALID)
+ {
+ CLog::Log(LOGERROR,
+ "CAudioDecoder::{} - Addon '{}' returned true without set of needed values",
+ __func__, ID());
+ return false;
+ }
+
+ m_format.m_dataFormat = Interface_AudioEngine::TranslateAEFormatToKodi(addonFormat);
+ m_format.m_sampleRate = sampleRate;
+ if (channelList[0] != AUDIOENGINE_CH_NULL)
+ {
+ CAEChannelInfo layout;
+ for (const auto& channel : channelList)
+ {
+ if (channel == AUDIOENGINE_CH_NULL)
+ break;
+ layout += Interface_AudioEngine::TranslateAEChannelToKodi(channel);
+ }
+
+ m_format.m_channelLayout = layout;
+ }
+ else
+ m_format.m_channelLayout = CAEUtil::GuessChLayout(channels);
+ }
+
+ return ret;
+}
+
+int CAudioDecoder::ReadPCM(uint8_t* buffer, size_t size, size_t* actualsize)
+{
+ if (!m_ifc.audiodecoder->toAddon->read_pcm)
+ return 0;
+
+ return m_ifc.audiodecoder->toAddon->read_pcm(m_ifc.hdl, buffer, size, actualsize);
+}
+
+bool CAudioDecoder::Seek(int64_t time)
+{
+ if (!m_ifc.audiodecoder->toAddon->seek)
+ return false;
+
+ m_ifc.audiodecoder->toAddon->seek(m_ifc.hdl, time);
+ return true;
+}
+
+bool CAudioDecoder::Load(const std::string& fileName,
+ MUSIC_INFO::CMusicInfoTag& tag,
+ EmbeddedArt* art)
+{
+ if (!m_ifc.audiodecoder->toAddon->read_tag)
+ return false;
+
+ KODI_ADDON_AUDIODECODER_INFO_TAG ifcTag = {};
+ bool ret = m_ifc.audiodecoder->toAddon->read_tag(m_ifc.hdl, fileName.c_str(), &ifcTag);
+ if (ret)
+ {
+ if (ifcTag.title)
+ {
+ tag.SetTitle(ifcTag.title);
+ free(ifcTag.title);
+ }
+ if (ifcTag.artist)
+ {
+ tag.SetArtist(ifcTag.artist);
+ free(ifcTag.artist);
+ }
+ if (ifcTag.album)
+ {
+ tag.SetAlbum(ifcTag.album);
+ free(ifcTag.album);
+ }
+ if (ifcTag.album_artist)
+ {
+ tag.SetAlbumArtist(ifcTag.album_artist);
+ free(ifcTag.album_artist);
+ }
+ if (ifcTag.media_type)
+ {
+ tag.SetType(ifcTag.media_type);
+ free(ifcTag.media_type);
+ }
+ if (ifcTag.genre)
+ {
+ tag.SetGenre(ifcTag.genre);
+ free(ifcTag.genre);
+ }
+ tag.SetDuration(ifcTag.duration);
+ tag.SetTrackNumber(ifcTag.track);
+ tag.SetDiscNumber(ifcTag.disc);
+ if (ifcTag.disc_subtitle)
+ {
+ tag.SetDiscSubtitle(ifcTag.disc_subtitle);
+ free(ifcTag.disc_subtitle);
+ }
+ tag.SetTotalDiscs(ifcTag.disc_total);
+ if (ifcTag.release_date)
+ {
+ tag.SetReleaseDate(ifcTag.release_date);
+ free(ifcTag.release_date);
+ }
+ if (ifcTag.lyrics)
+ {
+ tag.SetLyrics(ifcTag.lyrics);
+ free(ifcTag.lyrics);
+ }
+ tag.SetSampleRate(ifcTag.samplerate);
+ tag.SetNoOfChannels(ifcTag.channels);
+ tag.SetBitRate(ifcTag.bitrate);
+ if (ifcTag.comment)
+ {
+ tag.SetComment(ifcTag.comment);
+ free(ifcTag.comment);
+ }
+
+ if (ifcTag.cover_art_path)
+ {
+ const std::string mimetype =
+ CMime::GetMimeType(URIUtils::GetExtension(ifcTag.cover_art_path));
+ if (StringUtils::StartsWith(mimetype, "image/"))
+ {
+ XFILE::CFile file;
+ std::vector<uint8_t> buf;
+
+ if (file.LoadFile(ifcTag.cover_art_path, buf) > 0)
+ {
+ tag.SetCoverArtInfo(buf.size(), mimetype);
+ if (art)
+ art->Set(reinterpret_cast<const uint8_t*>(buf.data()), buf.size(), mimetype);
+ }
+ }
+ free(ifcTag.cover_art_path);
+ }
+ else if (ifcTag.cover_art_mem_mimetype && ifcTag.cover_art_mem && ifcTag.cover_art_mem_size > 0)
+ {
+ tag.SetCoverArtInfo(ifcTag.cover_art_mem_size, ifcTag.cover_art_mem_mimetype);
+ if (art)
+ art->Set(ifcTag.cover_art_mem, ifcTag.cover_art_mem_size, ifcTag.cover_art_mem_mimetype);
+ }
+
+ if (ifcTag.cover_art_mem_mimetype)
+ free(ifcTag.cover_art_mem_mimetype);
+ if (ifcTag.cover_art_mem)
+ free(ifcTag.cover_art_mem);
+
+ tag.SetLoaded(true);
+ }
+
+ return ret;
+}
+
+int CAudioDecoder::GetTrackCount(const std::string& strPath)
+{
+ if (!m_ifc.audiodecoder->toAddon->track_count)
+ return 0;
+
+ int result = m_ifc.audiodecoder->toAddon->track_count(m_ifc.hdl, strPath.c_str());
+
+ if (result > 1)
+ {
+ if (m_hasTags)
+ {
+ if (!Load(strPath, XFILE::CMusicFileDirectory::m_tag, nullptr))
+ return 0;
+ }
+ else
+ XFILE::CMusicFileDirectory::m_tag.SetTitle(CURL(strPath).GetFileNameWithoutPath());
+ XFILE::CMusicFileDirectory::m_tag.SetLoaded(true);
+ }
+
+ return result;
+}