diff options
18 files changed, 967 insertions, 9 deletions
diff --git a/addons/kodi.binary.instance.videocodec/addon.xml.in b/addons/kodi.binary.instance.videocodec/addon.xml.in new file mode 100644 index 0000000000..c3b035cc16 --- /dev/null +++ b/addons/kodi.binary.instance.videocodec/addon.xml.in @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<addon id="kodi.binary.instance.videocodec" version="@ADDON_INSTANCE_VERSION_VIDEOCODEC@" provider-name="Team Kodi"> + <backwards-compatibility abi="@ADDON_INSTANCE_VERSION_VIDEOCODEC_MIN@"/> + <requires> + <import addon="xbmc.core" version="0.1.0"/> + </requires> +</addon> diff --git a/system/addon-manifest.xml b/system/addon-manifest.xml index b70114bf7d..79012d73ad 100644 --- a/system/addon-manifest.xml +++ b/system/addon-manifest.xml @@ -18,6 +18,7 @@ <addon>kodi.binary.instance.pvr</addon> <addon>kodi.binary.instance.screensaver</addon> <addon>kodi.binary.instance.vfs</addon> + <addon>kodi.binary.instance.videocodec</addon> <addon>kodi.binary.instance.visualization</addon> <addon>kodi.resource</addon> <addon>metadata.album.universal</addon> diff --git a/xbmc/addons/AddonInfo.h b/xbmc/addons/AddonInfo.h index dc4d321950..a94bb64381 100644 --- a/xbmc/addons/AddonInfo.h +++ b/xbmc/addons/AddonInfo.h @@ -66,6 +66,7 @@ namespace ADDON ADDON_SCRIPT_LIBRARY, ADDON_SCRIPT_MODULE, ADDON_GAME_CONTROLLER, + ADDON_VIDEOCODEC, /** * @brief virtual addon types diff --git a/xbmc/addons/AddonProvider.h b/xbmc/addons/AddonProvider.h new file mode 100644 index 0000000000..3b8392369b --- /dev/null +++ b/xbmc/addons/AddonProvider.h @@ -0,0 +1,46 @@ +#pragma once + +/* +* Copyright (C) 2017 Team XBMC +* http://xbmc.org +* +* This Program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This Program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with XBMC; see the file COPYING. If not, see +* <http://www.gnu.org/licenses/>. +* +*/ + +/* +* CAddonProvider +* IUnknown implementation to retrieve sub-addons from already active addons +* See Inputstream.cpp/h for an explaric use case +*/ + +namespace kodi { namespace addon { class IAddonInstance; } } + +namespace ADDON +{ + class CBinaryAddonBase; + typedef std::shared_ptr<CBinaryAddonBase> BinaryAddonBasePtr; + + class IAddonProvider + { + public: + enum INSTANCE_TYPE + { + INSTANCE_VIDEOCODEC + }; + virtual void getAddonInstance(INSTANCE_TYPE instance_type, ADDON::BinaryAddonBasePtr& addonBase, kodi::addon::IAddonInstance*& parentInstance) = 0; + }; + + } //Namespace diff --git a/xbmc/addons/CMakeLists.txt b/xbmc/addons/CMakeLists.txt index 8145bce0de..169dead9a8 100644 --- a/xbmc/addons/CMakeLists.txt +++ b/xbmc/addons/CMakeLists.txt @@ -41,6 +41,7 @@ set(HEADERS Addon.h AddonInfo.h AddonInstaller.h AddonManager.h + AddonProvider.h AddonStatusHandler.h AddonSystemSettings.h AddonVersion.h diff --git a/xbmc/addons/binary-addons/AddonInstanceHandler.h b/xbmc/addons/binary-addons/AddonInstanceHandler.h index f18524ab26..048f770b6a 100644 --- a/xbmc/addons/binary-addons/AddonInstanceHandler.h +++ b/xbmc/addons/binary-addons/AddonInstanceHandler.h @@ -48,6 +48,7 @@ namespace ADDON bool CreateInstance(KODI_HANDLE instance); void DestroyInstance(); const AddonDllPtr& Addon() { return m_addon; } + BinaryAddonBasePtr GetAddonBase() { return m_addonBase; }; private: ADDON_TYPE m_type; diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCodec.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCodec.h new file mode 100644 index 0000000000..85de3eccf9 --- /dev/null +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCodec.h @@ -0,0 +1,33 @@ +#pragma once +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Kodi; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +enum STREAMCODEC_PROFILE +{ + CodecProfileUnknown = 0, + CodecProfileNotNeeded, + H264CodecProfileBaseline, + H264CodecProfileMain, + H264CodecProfileExtended, + H264CodecProfileHigh, + H264CodecProfileHigh10, + H264CodecProfileHigh422, + H264CodecProfileHigh444Predictive +}; diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCrypto.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCrypto.h new file mode 100644 index 0000000000..52ef860262 --- /dev/null +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCrypto.h @@ -0,0 +1,33 @@ +#pragma once +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Kodi; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +typedef struct CRYPTO_INFO +{ + enum CRYPTO_KEY_SYSTEM : uint16_t + { + CRYPTO_KEY_SYSTEM_NONE = 0, + CRYPTO_KEY_SYSTEM_WIDEVINE, + CRYPTO_KEY_SYSTEM_PLAYREADY, + CRYPTO_KEY_SYSTEM_COUNT + } m_CryptoKeySystem; /*!< @brief keysystem for encrypted media, KEY_SYSTEM_NONE for unencrypted media */ + const char *m_CryptoSessionId; /*!< @brief The crypto session key id */ + uint16_t m_CryptoSessionIdSize; /*!< @brief The size of the crypto session key id */ +} CRYPTO_INFO; diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h index bdb80bb742..ebafa9d838 100644 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h @@ -25,6 +25,8 @@ */ #include "../AddonBase.h" +#include "../StreamCrypto.h" +#include "../StreamCodec.h" #ifdef BUILD_KODI_ADDON #include "../DVDDemuxPacket.h" @@ -107,8 +109,15 @@ extern "C" { TYPE_TELETEXT } m_streamType; + enum Codec_FEATURES + { + FEATURE_DECODE = 1 + }; + unsigned int m_features; + char m_codecName[32]; /*!< @brief (required) name of codec according to ffmpeg */ char m_codecInternalName[32]; /*!< @brief (optional) internal name of codec (selectionstream info) */ + STREAMCODEC_PROFILE m_codecProfile; /*!< @brief (optional) the profile of the codec */ unsigned int m_pID; /*!< @brief (required) physical index */ const uint8_t *m_ExtraData; @@ -127,6 +136,8 @@ extern "C" { unsigned int m_BitRate; /*!< @brief (required) bit rate */ unsigned int m_BitsPerSample; /*!< @brief (required) bits per sample */ unsigned int m_BlockAlign; + + CRYPTO_INFO m_cryptoInfo; } INPUTSTREAM_INFO; /*! @@ -144,6 +155,7 @@ extern "C" { { KODI_HANDLE kodiInstance; DemuxPacket* (*allocate_demux_packet)(void* kodiInstance, int data_size); + DemuxPacket* (*allocate_encrypted_demux_packet)(void* kodiInstance, unsigned int data_size, unsigned int encrypted_subsample_count); void (*free_demux_packet)(void* kodiInstance, DemuxPacket* packet); } AddonToKodiFuncTable_InputStream; @@ -241,7 +253,7 @@ namespace addon * Get IDs of available streams * @remarks */ - virtual INPUTSTREAM_IDS GetStreamIds() { return INPUTSTREAM_IDS(); } + virtual INPUTSTREAM_IDS GetStreamIds() = 0; /*! * Get stream properties of a stream. @@ -249,7 +261,7 @@ namespace addon * @return struc of stream properties * @remarks */ - virtual INPUTSTREAM_INFO GetStream(int streamid) { return INPUTSTREAM_INFO(); } + virtual INPUTSTREAM_INFO GetStream(int streamid) = 0; /*! * Enable or disable a stream. @@ -258,7 +270,7 @@ namespace addon * @param enable true for enable, false for disable * @remarks */ - virtual void EnableStream(int streamid, bool enable) { } + virtual void EnableStream(int streamid, bool enable) = 0; /*! * Reset the demultiplexer in the add-on. @@ -403,6 +415,16 @@ namespace addon } /*! + * @brief Allocate a demux packet. Free with FreeDemuxPacket + * @param dataSize The size of the data that will go into the packet + * @return The allocated packet + */ + DemuxPacket* AllocateEncryptedDemuxPacket(int dataSize, unsigned int encryptedSubsampleCount) + { + return m_instanceData->toKodi.allocate_encrypted_demux_packet(m_instanceData->toKodi.kodiInstance, dataSize, encryptedSubsampleCount); + } + + /*! * @brief Free a packet that was allocated with AllocateDemuxPacket * @param packet The packet to free */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VideoCodec.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VideoCodec.h new file mode 100644 index 0000000000..2800fc0edf --- /dev/null +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VideoCodec.h @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2017 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "../AddonBase.h" +#include "../StreamCrypto.h" +#include "../StreamCodec.h" + +#ifdef BUILD_KODI_ADDON +#include "../DVDDemuxPacket.h" +#else +#include "cores/VideoPlayer/DVDDemuxers/DVDDemuxPacket.h" +#endif + +namespace kodi { namespace addon { class CInstanceVideoCodec; } } + +extern "C" +{ + enum VIDEOCODEC_FORMAT + { + UnknownVideoFormat = 0, + VideoFormatYV12, + VideoFormatI420, + MaxVideoFormats + }; + + + struct VIDEOCODEC_INITDATA + { + enum Codec { + CodecUnknown = 0, + CodecVp8, + CodecH264, + CodecVp9 + } codec; + + STREAMCODEC_PROFILE codecProfile; + + //UnknownVideoFormat is terminator + VIDEOCODEC_FORMAT *videoFormats; + + uint32_t width, height; + + const uint8_t *extraData; + unsigned int extraDataSize; + + CRYPTO_INFO cryptoInfo; + }; + + struct VIDEOCODEC_PICTURE + { + enum VideoPlane { + YPlane = 0, + UPlane, + VPlane, + MaxPlanes = 3, + }; + + enum Flags : uint32_t { + FLAG_DROP, + FLAG_DRAIN + }; + + VIDEOCODEC_FORMAT videoFormat; + uint32_t flags; + + uint32_t width, height; + + uint8_t *decodedData; + size_t decodedDataSize; + + uint32_t planeOffsets[VideoPlane::MaxPlanes]; + uint32_t stride[VideoPlane::MaxPlanes]; + + int64_t pts; + }; + + enum VIDEOCODEC_RETVAL + { + VC_NONE = 0, //< noop + VC_ERROR, //< an error occured, no other messages will be returned + VC_BUFFER, //< the decoder needs more data + VC_PICTURE, //< the decoder got a picture + VC_EOF, //< the decoder signals EOF + }; + + // this are properties given to the addon on create + // at this time we have no parameters for the addon + typedef struct AddonProps_VideoCodec + { + int dummy; + } AddonProps_VideoCodec; + + struct AddonInstance_VideoCodec; + typedef struct KodiToAddonFuncTable_VideoCodec + { + kodi::addon::CInstanceVideoCodec* addonInstance; + + //! \brief Opens a codec + bool (__cdecl* open) (const AddonInstance_VideoCodec* instance, VIDEOCODEC_INITDATA *initData); + + //! \brief Reconfigures a codec + bool (__cdecl* reconfigure) (const AddonInstance_VideoCodec* instance, VIDEOCODEC_INITDATA *initData); + + //! \brief Feed codec if requested from GetPicture() (return VC_BUFFER) + bool (__cdecl* add_data) (const AddonInstance_VideoCodec* instance, const DemuxPacket *packet); + + //! \brief Get a decoded picture / request new data + VIDEOCODEC_RETVAL (__cdecl* get_picture) (const AddonInstance_VideoCodec* instance, VIDEOCODEC_PICTURE *picture); + + //! \brief Get the name of this video decoder + const char *(__cdecl* get_name) (const AddonInstance_VideoCodec* instance); + + //! \brief Reset the codec + void (__cdecl* reset)(const AddonInstance_VideoCodec* instance); + } KodiToAddonFuncTable_VideoCodec; + + typedef struct AddonToKodiFuncTable_VideoCodec + { + KODI_HANDLE kodiInstance; + bool(*get_frame_buffer)(void* kodiInstance, VIDEOCODEC_PICTURE *picture); + } AddonToKodiFuncTable_VideoCodec; + + typedef struct AddonInstance_VideoCodec + { + AddonProps_VideoCodec props; + AddonToKodiFuncTable_VideoCodec toKodi; + KodiToAddonFuncTable_VideoCodec toAddon; + } AddonInstance_VideoCodec; +} + +namespace kodi +{ + namespace addon + { + + class CInstanceVideoCodec : public IAddonInstance + { + public: + CInstanceVideoCodec(KODI_HANDLE instance) + : IAddonInstance(ADDON_INSTANCE_VIDEOCODEC) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceVideoCodec: Creation of multiple together with single instance way is not allowed!"); + + SetAddonStruct(instance); + } + + virtual ~CInstanceVideoCodec() = default; + + //! \copydoc CInstanceVideoCodec::Open + virtual bool Open(VIDEOCODEC_INITDATA &initData) { return false; }; + + //! \copydoc CInstanceVideoCodec::Reconfigure + virtual bool Reconfigure(VIDEOCODEC_INITDATA &initData) { return false; }; + + //! \copydoc CInstanceVideoCodec::AddData + virtual bool AddData(const DemuxPacket &packet) { return false; }; + + //! \copydoc CInstanceVideoCodec::GetPicture + virtual VIDEOCODEC_RETVAL GetPicture(VIDEOCODEC_PICTURE &picture) { return VC_ERROR; }; + + //! \copydoc CInstanceVideoCodec::GetName + virtual const char *GetName() { return nullptr; }; + + //! \copydoc CInstanceVideoCodec::Reset + virtual void Reset() {}; + + /*! + * @brief AddonToKodi interface + */ + + //! \copydoc CInstanceVideoCodec::GetFrameBuffer + bool GetFrameBuffer(VIDEOCODEC_PICTURE &picture) + { + return m_instanceData->toKodi.get_frame_buffer(m_instanceData->toKodi.kodiInstance, &picture); + } + + private: + void SetAddonStruct(KODI_HANDLE instance) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstanceVideoCodec: Creation with empty addon structure not allowed, table must be given from Kodi!"); + + m_instanceData = static_cast<AddonInstance_VideoCodec*>(instance); + + m_instanceData->toAddon.addonInstance = this; + m_instanceData->toAddon.open = ADDON_Open; + m_instanceData->toAddon.reconfigure = ADDON_Reconfigure; + m_instanceData->toAddon.add_data = ADDON_AddData; + m_instanceData->toAddon.get_picture = ADDON_GetPicture; + m_instanceData->toAddon.get_name = ADDON_GetName; + m_instanceData->toAddon.reset = ADDON_Reset; + } + + inline static bool ADDON_Open(const AddonInstance_VideoCodec* instance, VIDEOCODEC_INITDATA *initData) + { + return instance->toAddon.addonInstance->Open(*initData); + } + + inline static bool ADDON_Reconfigure(const AddonInstance_VideoCodec* instance, VIDEOCODEC_INITDATA *initData) + { + return instance->toAddon.addonInstance->Reconfigure(*initData); + } + + inline static bool ADDON_AddData(const AddonInstance_VideoCodec* instance, const DemuxPacket *packet) + { + return instance->toAddon.addonInstance->AddData(*packet); + } + + inline static VIDEOCODEC_RETVAL ADDON_GetPicture(const AddonInstance_VideoCodec* instance, VIDEOCODEC_PICTURE *picture) + { + return instance->toAddon.addonInstance->GetPicture(*picture); + } + + inline static const char *ADDON_GetName(const AddonInstance_VideoCodec* instance) + { + return instance->toAddon.addonInstance->GetName(); + } + + inline static void ADDON_Reset(const AddonInstance_VideoCodec* instance) + { + return instance->toAddon.addonInstance->Reset(); + } + + AddonInstance_VideoCodec* m_instanceData; + }; + } // namespace addon +} // namespace kodi diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h index 34c2861a99..72394d1fde 100644 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h @@ -141,6 +141,13 @@ #define ADDON_INSTANCE_VERSION_VISUALIZATION_XML_ID "kodi.binary.instance.visualization" #define ADDON_INSTANCE_VERSION_VISUALIZATION_DEPENDS "addon-instance/Visualization.h" +#define ADDON_INSTANCE_VERSION_VIDEOCODEC "1.0.0" +#define ADDON_INSTANCE_VERSION_VIDEOCODEC_MIN "1.0.0" +#define ADDON_INSTANCE_VERSION_VIDEOCODEC_XML_ID "kodi.binary.instance.videocodec" +#define ADDON_INSTANCE_VERSION_VIDEOCODEC_DEPENDS "addon-instance/VideoCodec.h" \ + "StreamCodec.h" \ + "StreamCrypto.h" + /// /// The currently available instance types for Kodi add-ons /// @@ -172,6 +179,7 @@ typedef enum ADDON_TYPE ADDON_INSTANCE_VISUALIZATION = 109, ADDON_INSTANCE_VFS = 110, ADDON_INSTANCE_IMAGEDECODER = 111, + ADDON_INSTANCE_VIDEOCODEC = 112, } ADDON_TYPE; #ifdef __cplusplus @@ -264,6 +272,10 @@ inline const char* GetTypeVersion(int type) case ADDON_INSTANCE_VISUALIZATION: return ADDON_INSTANCE_VERSION_VISUALIZATION; #endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_VIDEOCODEC_USED) + case ADDON_INSTANCE_VIDEOCODEC: + return ADDON_INSTANCE_VERSION_VIDEOCODEC; +#endif } return "0.0.0"; } @@ -317,6 +329,8 @@ inline const char* GetTypeMinVersion(int type) return ADDON_INSTANCE_VERSION_VFS_MIN; case ADDON_INSTANCE_VISUALIZATION: return ADDON_INSTANCE_VERSION_VISUALIZATION_MIN; + case ADDON_INSTANCE_VIDEOCODEC: + return ADDON_INSTANCE_VERSION_VIDEOCODEC_MIN; } return "0.0.0"; } @@ -367,6 +381,8 @@ inline const char* GetTypeName(int type) return "ScreenSaver"; case ADDON_INSTANCE_VISUALIZATION: return "Visualization"; + case ADDON_INSTANCE_VIDEOCODEC: + return "VideoCodec"; } return "unknown"; } @@ -418,6 +434,8 @@ inline int GetTypeId(const char* name) return ADDON_INSTANCE_VFS; else if (strcmp(name, "visualization") == 0) return ADDON_INSTANCE_VISUALIZATION; + else if (strcmp(name, "videocodec") == 0) + return ADDON_INSTANCE_VIDEOCODEC; } return -1; } diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp index 85a3a22f18..734dce22de 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp @@ -22,11 +22,14 @@ #include "utils/log.h" #include "DVDFactoryCodec.h" +#include "Video/AddonVideoCodec.h" #include "Video/DVDVideoCodec.h" #include "Audio/DVDAudioCodec.h" #include "Overlay/DVDOverlayCodec.h" #include "cores/VideoPlayer/DVDCodecs/DVDCodecs.h" +#include "addons/AddonProvider.h" + #include "Video/DVDVideoCodecFFmpeg.h" #include "Audio/DVDAudioCodecFFmpeg.h" @@ -67,6 +70,22 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, CProces options.m_opaque_pointer = info.opaque_pointer; + // addon handler for this stream ? + + if (hint.externalInterfaces) + { + ADDON::BinaryAddonBasePtr addonInfo; + kodi::addon::IAddonInstance* parentInstance; + hint.externalInterfaces->getAddonInstance(ADDON::IAddonProvider::INSTANCE_VIDEOCODEC, addonInfo, parentInstance); + if (addonInfo && parentInstance) + { + pCodec.reset(new CAddonVideoCodec(processInfo, addonInfo, parentInstance)); + if (pCodec && pCodec->Open(hint, options)) + return pCodec.release(); + } + return nullptr; + } + // platform specifig video decoders if (!(hint.codecOptions & CODEC_FORCE_SOFTWARE)) { diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/AddonVideoCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AddonVideoCodec.cpp new file mode 100644 index 0000000000..55359206a6 --- /dev/null +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AddonVideoCodec.cpp @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "AddonVideoCodec.h" +#include "addons/binary-addons/BinaryAddonBase.h" +#include "cores/VideoPlayer/DVDStreamInfo.h" +#include "cores/VideoPlayer/DVDDemuxers/DemuxCrypto.h" +#include "cores/VideoPlayer/DVDCodecs/DVDCodecs.h" +#include "cores/VideoPlayer/TimingConstants.h" +#include "utils/log.h" +#include "settings/AdvancedSettings.h" + +using namespace kodi::addon; + +#define ALIGN(value, alignment) (((value)+(alignment-1))&~(alignment-1)) + +class BufferPool +{ +public: + ~BufferPool() + { + for (BUFFER &buf : freeBuffer) + free(buf.mem); + for (BUFFER &buf : usedBuffer) + free(buf.mem); + } + + bool GetBuffer(VIDEOCODEC_PICTURE &picture) + { + if (freeBuffer.empty()) + freeBuffer.resize(1); + + BUFFER &buf(freeBuffer.back()); + if (buf.memSize < picture.decodedDataSize) + { + buf.memSize = picture.decodedDataSize; + buf.mem = malloc(buf.memSize); + if (buf.mem == nullptr) + { + buf.memSize = 0; + picture.decodedData = nullptr; + return false; + } + } + picture.decodedData = (uint8_t*)buf.mem; + + usedBuffer.push_back(buf); + freeBuffer.pop_back(); + return true; + } + + void ReleaseBuffer(void *bufferPtr) + { + std::vector<BUFFER>::iterator res(std::find(usedBuffer.begin(), usedBuffer.end(), bufferPtr)); + if (res == usedBuffer.end()) + return; + freeBuffer.push_back(*res); + usedBuffer.erase(res); + } + +private: + struct BUFFER + { + BUFFER():mem(nullptr), memSize(0) {}; + BUFFER(void* m, size_t s) :mem(m), memSize(s) {}; + bool operator == (const void* data) const { return mem == data; }; + + void *mem; + size_t memSize; + }; + std::vector<BUFFER> freeBuffer, usedBuffer; +}; + +CAddonVideoCodec::CAddonVideoCodec(CProcessInfo &processInfo, ADDON::BinaryAddonBasePtr& addonInfo, kodi::addon::IAddonInstance* parentInstance) + : CDVDVideoCodec(processInfo), + IAddonInstanceHandler(ADDON_INSTANCE_VIDEOCODEC, addonInfo, parentInstance) + , m_codecFlags(0) + , m_displayAspect(0.0f) + , m_lastPictureBuffer(nullptr) + , m_bufferPool(new BufferPool()) +{ + m_struct = { { 0 } }; + m_struct.toKodi.kodiInstance = this; + m_struct.toKodi.get_frame_buffer = get_frame_buffer; + if (!CreateInstance(&m_struct) || !m_struct.toAddon.open) + { + CLog::Log(LOGERROR, "CInputStreamAddon: Failed to create add-on instance for '%s'", addonInfo->ID().c_str()); + return; + } + m_processInfo.SetVideoDecoderName(GetName(), false); +} + +CAddonVideoCodec::~CAddonVideoCodec() +{ + DestroyInstance(); + + m_bufferPool->ReleaseBuffer(m_lastPictureBuffer); + + delete m_bufferPool; +} + +bool CAddonVideoCodec::CopyToInitData(VIDEOCODEC_INITDATA &initData, CDVDStreamInfo &hints) +{ + initData.codecProfile = STREAMCODEC_PROFILE::CodecProfileNotNeeded; + switch (hints.codec) + { + case AV_CODEC_ID_H264: + initData.codec = VIDEOCODEC_INITDATA::CodecH264; + switch (hints.profile) + { + case 0: + case FF_PROFILE_UNKNOWN: + initData.codecProfile = STREAMCODEC_PROFILE::CodecProfileUnknown; + break; + case FF_PROFILE_H264_BASELINE: + initData.codecProfile = STREAMCODEC_PROFILE::H264CodecProfileBaseline; + break; + case FF_PROFILE_H264_MAIN: + initData.codecProfile = STREAMCODEC_PROFILE::H264CodecProfileMain; + break; + case FF_PROFILE_H264_EXTENDED: + initData.codecProfile = STREAMCODEC_PROFILE::H264CodecProfileExtended; + break; + case FF_PROFILE_H264_HIGH: + initData.codecProfile = STREAMCODEC_PROFILE::H264CodecProfileHigh; + break; + case FF_PROFILE_H264_HIGH_10: + initData.codecProfile = STREAMCODEC_PROFILE::H264CodecProfileHigh10; + break; + case FF_PROFILE_H264_HIGH_422: + initData.codecProfile = STREAMCODEC_PROFILE::H264CodecProfileHigh422; + break; + case FF_PROFILE_H264_HIGH_444_PREDICTIVE: + initData.codecProfile = STREAMCODEC_PROFILE::H264CodecProfileHigh444Predictive; + break; + default: + return false; + } + break; + case AV_CODEC_ID_VP8: + initData.codec = VIDEOCODEC_INITDATA::CodecVp8; + break; + case AV_CODEC_ID_VP9: + initData.codec = VIDEOCODEC_INITDATA::CodecVp9; + break; + default: + return false; + } + if (hints.cryptoSession) + { + switch (hints.cryptoSession->keySystem) + { + case CRYPTO_SESSION_SYSTEM_NONE: + initData.cryptoInfo.m_CryptoKeySystem = CRYPTO_INFO::CRYPTO_KEY_SYSTEM_NONE; + break; + case CRYPTO_SESSION_SYSTEM_WIDEVINE: + initData.cryptoInfo.m_CryptoKeySystem = CRYPTO_INFO::CRYPTO_KEY_SYSTEM_WIDEVINE; + break; + case CRYPTO_SESSION_SYSTEM_PLAYREADY: + initData.cryptoInfo.m_CryptoKeySystem = CRYPTO_INFO::CRYPTO_KEY_SYSTEM_PLAYREADY; + break; + default: + return false; + } + initData.cryptoInfo.m_CryptoSessionIdSize = hints.cryptoSession->sessionIdSize; + //We assume that we need this sessionid only for the directly following call + initData.cryptoInfo.m_CryptoSessionId = hints.cryptoSession->sessionId; + } + + initData.extraData = reinterpret_cast<const uint8_t*>(hints.extradata); + initData.extraDataSize = hints.extrasize; + initData.width = hints.width; + initData.height = hints.height; + initData.videoFormats = m_formats; + + m_displayAspect = (hints.aspect > 0.0 && !hints.forced_aspect) ? static_cast<float>(hints.aspect) : 0.0f; + m_width = hints.width; + m_height = hints.height; + + m_processInfo.SetVideoDimensions(hints.width, hints.height); + + return true; +} + +bool CAddonVideoCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) +{ + if (!m_struct.toAddon.open) + return false; + + unsigned int nformats(0); + for (auto fmt : options.m_formats) + if (fmt == RENDER_FMT_YUV420P) + { + m_formats[nformats++] = VideoFormatYV12; + break; + } + m_formats[nformats] = UnknownVideoFormat; + + if (nformats == 0) + return false; + + VIDEOCODEC_INITDATA initData; + if (!CopyToInitData(initData, hints)) + return false; + + m_lastPictureBuffer = nullptr; + + return m_struct.toAddon.open(&m_struct, &initData); +} + +bool CAddonVideoCodec::Reconfigure(CDVDStreamInfo &hints) +{ + if (!m_struct.toAddon.reconfigure) + return false; + + VIDEOCODEC_INITDATA initData; + if (!CopyToInitData(initData, hints)) + return false; + + return m_struct.toAddon.reconfigure(&m_struct, &initData); +} + +bool CAddonVideoCodec::AddData(const DemuxPacket &packet) +{ + if (!m_struct.toAddon.add_data) + return false; + + return m_struct.toAddon.add_data(&m_struct, &packet); +} + +CDVDVideoCodec::VCReturn CAddonVideoCodec::GetPicture(VideoPicture* pVideoPicture) +{ + if (!m_struct.toAddon.get_picture) + return CDVDVideoCodec::VC_ERROR; + + VIDEOCODEC_PICTURE picture; + picture.flags = (m_codecFlags & DVD_CODEC_CTRL_DRAIN) ? VIDEOCODEC_PICTURE::FLAG_DRAIN : 0; + + switch (m_struct.toAddon.get_picture(&m_struct, &picture)) + { + case VIDEOCODEC_RETVAL::VC_NONE: + return CDVDVideoCodec::VC_NONE; + case VIDEOCODEC_RETVAL::VC_ERROR: + return CDVDVideoCodec::VC_ERROR; + case VIDEOCODEC_RETVAL::VC_BUFFER: + return CDVDVideoCodec::VC_BUFFER; + case VIDEOCODEC_RETVAL::VC_PICTURE: + pVideoPicture->data[0] = picture.decodedData + picture.planeOffsets[0]; + pVideoPicture->data[1] = picture.decodedData + picture.planeOffsets[1]; + pVideoPicture->data[2] = picture.decodedData + picture.planeOffsets[2]; + pVideoPicture->iLineSize[0] = picture.stride[0]; + pVideoPicture->iLineSize[1] = picture.stride[1]; + pVideoPicture->iLineSize[2] = picture.stride[2]; + pVideoPicture->iWidth = picture.width; + pVideoPicture->iHeight = picture.height; + pVideoPicture->pts = DVD_NOPTS_VALUE; + pVideoPicture->dts = DVD_NOPTS_VALUE; + pVideoPicture->color_range = 0; + pVideoPicture->color_matrix = 4; + pVideoPicture->iFlags = DVP_FLAG_ALLOCATED; + if (m_codecFlags & DVD_CODEC_CTRL_DROP) + pVideoPicture->iFlags |= DVP_FLAG_DROPPED; + pVideoPicture->format = RENDER_FMT_YUV420P; + + pVideoPicture->iDisplayWidth = pVideoPicture->iWidth; + pVideoPicture->iDisplayHeight = pVideoPicture->iHeight; + if (m_displayAspect > 0.0) + { + pVideoPicture->iDisplayWidth = ((int)lrint(pVideoPicture->iHeight * m_displayAspect)) & ~3; + if (pVideoPicture->iDisplayWidth > pVideoPicture->iWidth) + { + pVideoPicture->iDisplayWidth = pVideoPicture->iWidth; + pVideoPicture->iDisplayHeight = ((int)lrint(pVideoPicture->iWidth / m_displayAspect)) & ~3; + } + } + + if (g_advancedSettings.CanLogComponent(LOGVIDEO)) + CLog::Log(LOGDEBUG, "CAddonVideoCodec: GetPicture::VC_PICTURE with pts %llu", picture.pts); + + m_bufferPool->ReleaseBuffer(m_lastPictureBuffer); + m_lastPictureBuffer = picture.decodedData; + + if (picture.width != m_width || picture.height != m_height) + { + m_width = picture.width; + m_height = picture.height; + m_processInfo.SetVideoDimensions(m_width, m_height); + } + + return CDVDVideoCodec::VC_PICTURE; + case VIDEOCODEC_RETVAL::VC_EOF: + return CDVDVideoCodec::VC_EOF; + default: + return CDVDVideoCodec::VC_ERROR; + } +} + +const char* CAddonVideoCodec::GetName() +{ + if (m_struct.toAddon.get_name) + return m_struct.toAddon.get_name(&m_struct); + return ""; +} + +void CAddonVideoCodec::Reset() +{ + if (!m_struct.toAddon.reset) + return; + + CLog::Log(LOGDEBUG, "CAddonVideoCodec: Reset"); + + // Get the remaining pictures out of the external decoder + VIDEOCODEC_PICTURE picture; + picture.flags = VIDEOCODEC_PICTURE::FLAG_DRAIN; + + VIDEOCODEC_RETVAL ret; + while ((ret = m_struct.toAddon.get_picture(&m_struct, &picture)) != VIDEOCODEC_RETVAL::VC_EOF) + { + if (ret == VIDEOCODEC_RETVAL::VC_PICTURE) + { + m_bufferPool->ReleaseBuffer(m_lastPictureBuffer); + m_lastPictureBuffer = picture.decodedData; + } + } + m_bufferPool->ReleaseBuffer(m_lastPictureBuffer); + m_lastPictureBuffer = nullptr; + + m_struct.toAddon.reset(&m_struct); +} + +bool CAddonVideoCodec::GetFrameBuffer(VIDEOCODEC_PICTURE &picture) +{ + return m_bufferPool->GetBuffer(picture); +} + +/********************* ADDON-TO-KODI **********************/ + +bool CAddonVideoCodec::get_frame_buffer(void* kodiInstance, VIDEOCODEC_PICTURE *picture) +{ + if (!kodiInstance) + return false; + + return static_cast<CAddonVideoCodec*>(kodiInstance)->GetFrameBuffer(*picture); +} diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/AddonVideoCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AddonVideoCodec.h new file mode 100644 index 0000000000..449dc15af4 --- /dev/null +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AddonVideoCodec.h @@ -0,0 +1,66 @@ +#pragma once +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "DVDVideoCodec.h" +#include "addons/AddonProvider.h" +#include "addons/binary-addons/AddonInstanceHandler.h" +#include "addons/kodi-addon-dev-kit/include/kodi/addon-instance/VideoCodec.h" + +class BufferPool; + +class CAddonVideoCodec + : public CDVDVideoCodec + , public ADDON::IAddonInstanceHandler +{ +public: + CAddonVideoCodec(CProcessInfo &processInfo, ADDON::BinaryAddonBasePtr& addonInfo, kodi::addon::IAddonInstance* parentInstance); + ~CAddonVideoCodec(); + + virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) override; + virtual bool Reconfigure(CDVDStreamInfo &hints) override; + virtual bool AddData(const DemuxPacket &packet) override; + virtual void Reset() override; + virtual VCReturn GetPicture(VideoPicture* pVideoPicture) override; + virtual const char* GetName() override; + virtual void SetCodecControl(int flags) override { m_codecFlags = flags; } + +private: + bool CopyToInitData(VIDEOCODEC_INITDATA &initData, CDVDStreamInfo &hints); + + /*! + * @brief All picture members can be expected to be set correctly except decodedData and pts. + * GetFrameBuffer has to set decodedData to a valid memory adress and return true. + * In case buffer allocation fails, return false. + */ + bool GetFrameBuffer(VIDEOCODEC_PICTURE &picture); + + static bool get_frame_buffer(void* kodiInstance, VIDEOCODEC_PICTURE *picture); + + AddonInstance_VideoCodec m_struct; + int m_codecFlags; + VIDEOCODEC_FORMAT m_formats[VIDEOCODEC_FORMAT::MaxVideoFormats + 1]; + float m_displayAspect; + unsigned int m_width, m_height; + + void * m_lastPictureBuffer; + + BufferPool *m_bufferPool; +}; diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/CMakeLists.txt b/xbmc/cores/VideoPlayer/DVDCodecs/Video/CMakeLists.txt index c3bafb4780..f4f5b07ad2 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/CMakeLists.txt +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/CMakeLists.txt @@ -1,7 +1,9 @@ -set(SOURCES DVDVideoCodec.cpp +set(SOURCES AddonVideoCodec.cpp + DVDVideoCodec.cpp DVDVideoCodecFFmpeg.cpp) -set(HEADERS DVDVideoCodec.h +set(HEADERS AddonVideoCodec.h + DVDVideoCodec.h DVDVideoCodecFFmpeg.h) if(NOT ENABLE_EXTERNAL_LIBAV) diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp index 05066127a0..0d9311837c 100644 --- a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp +++ b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp @@ -22,14 +22,34 @@ #include "TimingConstants.h" #include "addons/binary-addons/AddonDll.h" #include "addons/binary-addons/BinaryAddonBase.h" +#include "addons/kodi-addon-dev-kit/include/kodi/addon-instance/VideoCodec.h" #include "cores/VideoPlayer/DVDClock.h" #include "cores/VideoPlayer/DVDDemuxers/DVDDemux.h" #include "cores/VideoPlayer/DVDDemuxers/DVDDemuxUtils.h" +#include "cores/VideoPlayer/DVDDemuxers/DemuxCrypto.h" #include "filesystem/SpecialProtocol.h" #include "utils/StringUtils.h" #include "utils/URIUtils.h" +CInputStreamProvider::CInputStreamProvider(ADDON::BinaryAddonBasePtr addonBase, kodi::addon::IAddonInstance* parentInstance) + : m_addonBase(addonBase) + , m_parentInstance(parentInstance) +{ +} + +void CInputStreamProvider::getAddonInstance(INSTANCE_TYPE instance_type, ADDON::BinaryAddonBasePtr& addonBase, kodi::addon::IAddonInstance*& parentInstance) +{ + if (instance_type == ADDON::IAddonProvider::INSTANCE_VIDEOCODEC) + { + addonBase = m_addonBase; + parentInstance = m_parentInstance; + } +} + +/*****************************************************************************************************************/ + using namespace ADDON; +using namespace kodi::addon; CInputStreamAddon::CInputStreamAddon(BinaryAddonBasePtr& addonBase, IVideoPlayer* player, const CFileItem& fileitem) : IAddonInstanceHandler(ADDON_INSTANCE_INPUTSTREAM, addonBase), @@ -45,8 +65,8 @@ CInputStreamAddon::CInputStreamAddon(BinaryAddonBasePtr& addonBase, IVideoPlayer StringUtils::Trim(key); key = name + "." + key; } - m_struct = {{ 0 }}; + m_caps.m_mask = 0; } CInputStreamAddon::~CInputStreamAddon() @@ -102,6 +122,7 @@ bool CInputStreamAddon::Open() m_struct.toKodi.kodiInstance = this; m_struct.toKodi.free_demux_packet = cb_free_demux_packet; m_struct.toKodi.allocate_demux_packet = cb_allocate_demux_packet; + m_struct.toKodi.allocate_encrypted_demux_packet = cb_allocate_encrypted_demux_packet; if (!CreateInstance(&m_struct) || !m_struct.toAddon.open) return false; @@ -306,7 +327,6 @@ CDemuxStream* CInputStreamAddon::GetStream(int streamId) const auto stream = m_streams.find(streamId); if (stream != m_streams.end()) return stream->second; - return nullptr; } @@ -427,6 +447,7 @@ void CInputStreamAddon::UpdateStreams() videoStream->fAspect = stream.m_Aspect; videoStream->stereo_mode = "mono"; videoStream->iBitRate = stream.m_BitRate; + videoStream->profile = ConvertVideoCodecProfile(stream.m_codecProfile); demuxStream = videoStream; } else if (stream.m_streamType == INPUTSTREAM_INFO::TYPE_SUBTITLE) @@ -453,6 +474,26 @@ void CInputStreamAddon::UpdateStreams() demuxStream->ExtraData[j] = stream.m_ExtraData[j]; } + if (stream.m_cryptoInfo.m_CryptoKeySystem != CRYPTO_INFO::CRYPTO_KEY_SYSTEM_NONE && + stream.m_cryptoInfo.m_CryptoKeySystem < CRYPTO_INFO::CRYPTO_KEY_SYSTEM_COUNT) + { + static const CryptoSessionSystem map[] = + { + CRYPTO_SESSION_SYSTEM_NONE, + CRYPTO_SESSION_SYSTEM_WIDEVINE, + CRYPTO_SESSION_SYSTEM_PLAYREADY + }; + demuxStream->cryptoSession = std::shared_ptr<DemuxCryptoSession>(new DemuxCryptoSession( + map[stream.m_cryptoInfo.m_CryptoKeySystem], stream.m_cryptoInfo.m_CryptoSessionIdSize, stream.m_cryptoInfo.m_CryptoSessionId)); + + if ((stream.m_features & INPUTSTREAM_INFO::FEATURE_DECODE) != 0) + { + if (!m_subAddonProvider) + m_subAddonProvider = std::shared_ptr<CInputStreamProvider>(new CInputStreamProvider(GetAddonBase(), m_struct.toAddon.addonInstance)); + + demuxStream->externalInterfaces = m_subAddonProvider; + } + } m_streams[demuxStream->uniqueId] = demuxStream; } } @@ -464,6 +505,29 @@ void CInputStreamAddon::DisposeStreams() m_streams.clear(); } +int CInputStreamAddon::ConvertVideoCodecProfile(STREAMCODEC_PROFILE profile) +{ + switch (profile) + { + case H264CodecProfileBaseline: + return FF_PROFILE_H264_BASELINE; + case H264CodecProfileMain: + return FF_PROFILE_H264_MAIN; + case H264CodecProfileExtended: + return FF_PROFILE_H264_EXTENDED; + case H264CodecProfileHigh: + return FF_PROFILE_H264_HIGH; + case H264CodecProfileHigh10: + return FF_PROFILE_H264_HIGH_10; + case H264CodecProfileHigh422: + return FF_PROFILE_H264_HIGH_422; + case H264CodecProfileHigh444Predictive: + return FF_PROFILE_H264_HIGH_444_PREDICTIVE; + default: + return FF_PROFILE_UNKNOWN; + } +} + /*! * Callbacks from add-on to kodi */ @@ -473,8 +537,14 @@ DemuxPacket* CInputStreamAddon::cb_allocate_demux_packet(void* kodiInstance, int return CDVDDemuxUtils::AllocateDemuxPacket(data_size); } +DemuxPacket* CInputStreamAddon::cb_allocate_encrypted_demux_packet(void* kodiInstance, unsigned int dataSize, unsigned int encryptedSubsampleCount) +{ + return CDVDDemuxUtils::AllocateDemuxPacket(dataSize, encryptedSubsampleCount); +} + void CInputStreamAddon::cb_free_demux_packet(void* kodiInstance, DemuxPacket* packet) { CDVDDemuxUtils::FreeDemuxPacket(packet); } + //@} diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h index f893b5cc0d..4f23448422 100644 --- a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h +++ b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h @@ -25,9 +25,23 @@ #include "DVDInputStream.h" #include "IVideoPlayer.h" +#include "addons/AddonProvider.h" #include "addons/binary-addons/AddonInstanceHandler.h" #include "addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h" +class CInputStreamProvider + : public ADDON::IAddonProvider +{ +public: + CInputStreamProvider(ADDON::BinaryAddonBasePtr addonBase, kodi::addon::IAddonInstance* parentInstance); + + virtual void getAddonInstance(INSTANCE_TYPE instance_type, ADDON::BinaryAddonBasePtr& addonBase, kodi::addon::IAddonInstance*& parentInstance) override; + +private: + ADDON::BinaryAddonBasePtr m_addonBase; + kodi::addon::IAddonInstance* m_parentInstance; +}; + //! \brief Input stream class class CInputStreamAddon : public ADDON::IAddonInstanceHandler, @@ -81,6 +95,7 @@ public: protected: void UpdateStreams(); void DisposeStreams(); + int ConvertVideoCodecProfile(STREAMCODEC_PROFILE profile); IVideoPlayer* m_player; @@ -90,6 +105,7 @@ private: std::map<int, CDemuxStream*> m_streams; AddonInstance_InputStream m_struct; + std::shared_ptr<CInputStreamProvider> m_subAddonProvider; /*! * Callbacks from add-on to kodi @@ -104,6 +120,15 @@ private: static DemuxPacket* cb_allocate_demux_packet(void* kodiInstance, int iDataSize = 0); /*! + * @brief Allocate an encrypted demux packet. Free with FreeDemuxPacket + * @param kodiInstance A pointer to the add-on. + * @param dataSize The size of the data that will go into the packet + * @param encryptedSubsampleCount The number of subsample description blocks to allocate + * @return The allocated packet. + */ + static DemuxPacket* cb_allocate_encrypted_demux_packet(void* kodiInstance, unsigned int dataSize, unsigned int encryptedSubsampleCount); + + /*! * @brief Free a packet that was allocated with AllocateDemuxPacket * @param kodiInstance A pointer to the add-on. * @param pPacket The packet to free. diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp index 0be22dab20..4745351b28 100644 --- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp @@ -405,9 +405,14 @@ void CGUIDialogVideoSettings::VideoStreamsOptionFiller(std::shared_ptr<const CSe } if (info.videoCodecName.empty()) - strItem += StringUtils::Format(" (%ix%i)", info.width, info.height); + strItem += StringUtils::Format(" (%ix%i", info.width, info.height); else - strItem += StringUtils::Format(" (%s, %ix%i)", info.videoCodecName.c_str(), info.width, info.height); + strItem += StringUtils::Format(" (%s, %ix%i", info.videoCodecName.c_str(), info.width, info.height); + + if (info.bitrate) + strItem += StringUtils::Format(", %i bps)", info.bitrate); + else + strItem += ")"; strItem += StringUtils::Format(" (%i/%i)", i + 1, videoStreamCount); list.push_back(make_pair(strItem, i)); |