/* * Copyright (C) 2005-2018 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #pragma once #include "DVDClock.h" #include "DVDMessageQueue.h" #include "Edl.h" #include "FileItem.h" #include "IVideoPlayer.h" #include "VideoPlayerAudioID3.h" #include "VideoPlayerRadioRDS.h" #include "VideoPlayerSubtitle.h" #include "VideoPlayerTeletext.h" #include "cores/IPlayer.h" #include "cores/MenuType.h" #include "cores/VideoPlayer/Interface/TimingConstants.h" #include "cores/VideoPlayer/VideoRenderers/RenderManager.h" #include "guilib/DispResource.h" #include "threads/SystemClock.h" #include "threads/Thread.h" #include #include #include #include #include #include struct SPlayerState { SPlayerState() { Clear(); } void Clear() { timestamp = 0; time = 0; startTime = 0; timeMin = 0; timeMax = 0; time_offset = 0; dts = DVD_NOPTS_VALUE; player_state = ""; isInMenu = false; menuType = MenuType::NONE; chapter = 0; chapters.clear(); canpause = false; canseek = false; cantempo = false; caching = false; cache_bytes = 0; cache_level = 0.0; cache_delay = 0.0; cache_offset = 0.0; lastSeek = 0; streamsReady = false; } double timestamp; // last time of update double lastSeek; // time of last seek double time_offset; // difference between time and pts double time; // current playback time double timeMax; double timeMin; time_t startTime; double dts; // last known dts std::string player_state; // full player state bool isInMenu; MenuType menuType; bool streamsReady; int chapter; // current chapter std::vector> chapters; // name and position for chapters bool canpause; // pvr: can pause the current playing item bool canseek; // pvr: can seek in the current playing item bool cantempo; bool caching; int64_t cache_bytes; // number of bytes current's cached double cache_level; // current estimated required cache level double cache_delay; // time until cache is expected to reach estimated level double cache_offset; // percentage of file ahead of current position }; class CDVDInputStream; class CDVDDemux; class CDemuxStreamVideo; class CDemuxStreamAudio; class CStreamInfo; class CDVDDemuxCC; class CVideoPlayer; #define DVDSTATE_NORMAL 0x00000001 // normal dvd state #define DVDSTATE_STILL 0x00000002 // currently displaying a still frame #define DVDSTATE_WAIT 0x00000003 // waiting for demuxer read error #define DVDSTATE_SEEK 0x00000004 // we are finishing a seek request class CCurrentStream { public: int64_t demuxerId; // demuxer's id of current playing stream int id; // id of current playing stream int source; double dts; // last dts from demuxer, used to find discontinuities double dur; // last frame expected duration int dispTime; // display time from input stream CDVDStreamInfo hint; // stream hints, used to notice stream changes void* stream; // pointer or integer, identifying stream playing. if it changes stream changed int changes; // remembered counter from stream to track codec changes bool inited; unsigned int packets; IDVDStreamPlayer::ESyncState syncState; double starttime; double cachetime; double cachetotal; const StreamType type; const int player; // stuff to handle starting after seek double startpts; double lastdts; enum { AV_SYNC_NONE, AV_SYNC_CHECK, AV_SYNC_CONT, AV_SYNC_FORCE } avsync; CCurrentStream(StreamType t, int i) : type(t) , player(i) { Clear(); } void Clear() { id = -1; demuxerId = -1; source = STREAM_SOURCE_NONE; dts = DVD_NOPTS_VALUE; dur = DVD_NOPTS_VALUE; hint.Clear(); stream = NULL; changes = 0; inited = false; packets = 0; syncState = IDVDStreamPlayer::SYNC_STARTING; starttime = DVD_NOPTS_VALUE; startpts = DVD_NOPTS_VALUE; lastdts = DVD_NOPTS_VALUE; avsync = AV_SYNC_FORCE; } double dts_end() { if(dts == DVD_NOPTS_VALUE) return DVD_NOPTS_VALUE; if(dur == DVD_NOPTS_VALUE) return dts; return dts + dur; } }; //------------------------------------------------------------------------------ // selection streams //------------------------------------------------------------------------------ struct SelectionStream { StreamType type = STREAM_NONE; int type_index = 0; std::string filename; std::string filename2; // for vobsub subtitles, 2 files are necessary (idx/sub) std::string language; std::string name; StreamFlags flags = StreamFlags::FLAG_NONE; int source = 0; int id = 0; int64_t demuxerId = -1; std::string codec; int channels = 0; int bitrate = 0; int width = 0; int height = 0; CRect SrcRect; CRect DestRect; CRect VideoRect; std::string stereo_mode; float aspect_ratio = 0.0f; StreamHdrType hdrType = StreamHdrType::HDR_TYPE_NONE; }; class CSelectionStreams { public: CSelectionStreams() = default; int TypeIndexOf(StreamType type, int source, int64_t demuxerId, int id) const; int CountTypeOfSource(StreamType type, StreamSource source) const; int CountType(StreamType type) const; SelectionStream& Get(StreamType type, int index); const SelectionStream& Get(StreamType type, int index) const; bool Get(StreamType type, StreamFlags flag, SelectionStream& out); void Clear(StreamType type, StreamSource source); int Source(StreamSource source, const std::string& filename); void Update(SelectionStream& s); void Update(const std::shared_ptr& input, CDVDDemux* demuxer); void Update(const std::shared_ptr& input, CDVDDemux* demuxer, const std::string& filename2); std::vector Get(StreamType type); template std::vector Get(StreamType type, Compare compare) { std::vector streams = Get(type); std::stable_sort(streams.begin(), streams.end(), compare); return streams; } std::vector m_Streams; protected: SelectionStream m_invalid; }; //------------------------------------------------------------------------------ // main class //------------------------------------------------------------------------------ class CProcessInfo; class CJobQueue; class CVideoPlayer : public IPlayer, public CThread, public IVideoPlayer, public IDispResource, public IRenderLoop, public IRenderMsg { public: explicit CVideoPlayer(IPlayerCallback& callback); ~CVideoPlayer() override; bool OpenFile(const CFileItem& file, const CPlayerOptions &options) override; bool CloseFile(bool reopen = false) override; bool IsPlaying() const override; void Pause() override; bool HasVideo() const override; bool HasAudio() const override; bool HasRDS() const override; bool HasID3() const override; bool IsPassthrough() const override; bool CanSeek() const override; void Seek(bool bPlus, bool bLargeStep, bool bChapterOverride) override; bool SeekScene(bool bPlus = true) override; void SeekPercentage(float iPercent) override; float GetCachePercentage() const override; void SetDynamicRangeCompression(long drc) override; bool CanPause() const override; void SetAVDelay(float fValue = 0.0f) override; float GetAVDelay() override; bool IsInMenu() const override; /*! * \brief Get the supported menu type * \return The supported menu type */ MenuType GetSupportedMenuType() const override; void SetSubTitleDelay(float fValue = 0.0f) override; float GetSubTitleDelay() override; int GetSubtitleCount() const override; int GetSubtitle() override; void GetSubtitleStreamInfo(int index, SubtitleStreamInfo& info) const override; void SetSubtitle(int iStream) override; bool GetSubtitleVisible() const override; void SetSubtitleVisible(bool bVisible) override; /*! * \brief Set the subtitle vertical position, * it depends on current screen resolution * \param value The subtitle position in pixels * \param save If true, the value will be saved to resolution info */ void SetSubtitleVerticalPosition(const int value, bool save) override; void AddSubtitle(const std::string& strSubPath) override; int GetAudioStreamCount() const override; int GetAudioStream() override; void SetAudioStream(int iStream) override; int GetVideoStream() const override; int GetVideoStreamCount() const override; void GetVideoStreamInfo(int streamId, VideoStreamInfo& info) const override; void SetVideoStream(int iStream) override; int GetPrograms(std::vector& programs) override; void SetProgram(int progId) override; int GetProgramsCount() const override; std::shared_ptr GetTeletextCache() override; bool HasTeletextCache() const override; void LoadPage(int p, int sp, unsigned char* buffer) override; int GetChapterCount() const override; int GetChapter() const override; void GetChapterName(std::string& strChapterName, int chapterIdx = -1) const override; int64_t GetChapterPos(int chapterIdx = -1) const override; int SeekChapter(int iChapter) override; void SeekTime(int64_t iTime) override; bool SeekTimeRelative(int64_t iTime) override; void SetSpeed(float speed) override; void SetTempo(float tempo) override; bool SupportsTempo() const override; void FrameAdvance(int frames) override; bool OnAction(const CAction &action) override; void GetAudioStreamInfo(int index, AudioStreamInfo& info) const override; std::string GetPlayerState() override; bool SetPlayerState(const std::string& state) override; void FrameMove() override; void Render(bool clear, uint32_t alpha = 255, bool gui = true) override; void FlushRenderer() override; void SetRenderViewMode(int mode, float zoom, float par, float shift, bool stretch) override; float GetRenderAspectRatio() const override; void TriggerUpdateResolution() override; bool IsRenderingVideo() const override; bool Supports(EINTERLACEMETHOD method) const override; EINTERLACEMETHOD GetDeinterlacingMethodDefault() const override; bool Supports(ESCALINGMETHOD method) const override; bool Supports(ERENDERFEATURE feature) const override; unsigned int RenderCaptureAlloc() override; void RenderCapture(unsigned int captureId, unsigned int width, unsigned int height, int flags) override; void RenderCaptureRelease(unsigned int captureId) override; bool RenderCaptureGetPixels(unsigned int captureId, unsigned int millis, uint8_t *buffer, unsigned int size) override; // IDispResource interface void OnLostDisplay() override; void OnResetDisplay() override; bool IsCaching() const override; int GetCacheLevel() const override; int OnDiscNavResult(void* pData, int iMessage) override; void GetVideoResolution(unsigned int &width, unsigned int &height) override; CVideoSettings GetVideoSettings() const override; void SetVideoSettings(CVideoSettings& settings) override; void SetUpdateStreamDetails(); protected: friend class CSelectionStreams; void OnStartup() override; void OnExit() override; void Process() override; void VideoParamsChange() override; void GetDebugInfo(std::string &audio, std::string &video, std::string &general) override; void UpdateClockSync(bool enabled) override; void UpdateRenderInfo(CRenderInfo &info) override; void UpdateRenderBuffers(int queued, int discard, int free) override; void UpdateGuiRender(bool gui) override; void UpdateVideoRender(bool video) override; void CreatePlayers(); void DestroyPlayers(); void Prepare(); bool OpenStream(CCurrentStream& current, int64_t demuxerId, int iStream, int source, bool reset = true); bool OpenAudioStream(CDVDStreamInfo& hint, bool reset = true); bool OpenVideoStream(CDVDStreamInfo& hint, bool reset = true); bool OpenSubtitleStream(const CDVDStreamInfo& hint); bool OpenTeletextStream(CDVDStreamInfo& hint); bool OpenRadioRDSStream(CDVDStreamInfo& hint); bool OpenAudioID3Stream(CDVDStreamInfo& hint); /** \brief Switches forced subtitles to forced subtitles matching the language of the current audio track. * If these are not available, subtitles are disabled. */ void AdaptForcedSubtitles(); bool CloseStream(CCurrentStream& current, bool bWaitForBuffers); bool CheckIsCurrent(const CCurrentStream& current, CDemuxStream* stream, DemuxPacket* pkg); void ProcessPacket(CDemuxStream* pStream, DemuxPacket* pPacket); void ProcessAudioData(CDemuxStream* pStream, DemuxPacket* pPacket); void ProcessVideoData(CDemuxStream* pStream, DemuxPacket* pPacket); void ProcessSubData(CDemuxStream* pStream, DemuxPacket* pPacket); void ProcessTeletextData(CDemuxStream* pStream, DemuxPacket* pPacket); void ProcessRadioRDSData(CDemuxStream* pStream, DemuxPacket* pPacket); void ProcessAudioID3Data(CDemuxStream* pStream, DemuxPacket* pPacket); int AddSubtitleFile(const std::string& filename, const std::string& subfilename = ""); void SetSubtitleVisibleInternal(bool bVisible); /** * one of the DVD_PLAYSPEED defines */ void SetPlaySpeed(int iSpeed); enum ECacheState { CACHESTATE_DONE = 0, CACHESTATE_FULL, // player is filling up the demux queue CACHESTATE_INIT, // player is waiting for first packet of each stream CACHESTATE_PLAY, // player is waiting for players to not be stalled CACHESTATE_FLUSH, // temporary state player will choose startup between init or full }; void SetCaching(ECacheState state); double GetQueueTime(); bool GetCachingTimes(double& play_left, double& cache_left, double& file_offset); void FlushBuffers(double pts, bool accurate, bool sync); void HandleMessages(); void HandlePlaySpeed(); bool IsInMenuInternal() const; void SynchronizeDemuxer(); void CheckAutoSceneSkip(); bool CheckContinuity(CCurrentStream& current, DemuxPacket* pPacket); bool CheckSceneSkip(const CCurrentStream& current); bool CheckPlayerInit(CCurrentStream& current); void UpdateCorrection(DemuxPacket* pkt, double correction); void UpdateTimestamps(CCurrentStream& current, DemuxPacket* pPacket); IDVDStreamPlayer* GetStreamPlayer(unsigned int player); void SendPlayerMessage(std::shared_ptr pMsg, unsigned int target); bool ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream); bool IsValidStream(const CCurrentStream& stream); bool IsBetterStream(const CCurrentStream& current, CDemuxStream* stream); void CheckBetterStream(CCurrentStream& current, CDemuxStream* stream); void CheckStreamChanges(CCurrentStream& current, CDemuxStream* stream); bool OpenInputStream(); bool OpenDemuxStream(); void CloseDemuxer(); void OpenDefaultStreams(bool reset = true); void UpdatePlayState(double timeout); void GetGeneralInfo(std::string& strVideoInfo); int64_t GetUpdatedTime(); int64_t GetTime(); float GetPercentage(); void UpdateContent(); void UpdateContentState(); void UpdateFileItemStreamDetails(CFileItem& item); bool m_players_created; CFileItem m_item; CPlayerOptions m_playerOptions; bool m_bAbortRequest; bool m_error; bool m_bCloseRequest; ECacheState m_caching; XbmcThreads::EndTime<> m_cachingTimer; std::unique_ptr m_processInfo; CCurrentStream m_CurrentAudio; CCurrentStream m_CurrentVideo; CCurrentStream m_CurrentSubtitle; CCurrentStream m_CurrentTeletext; CCurrentStream m_CurrentRadioRDS; CCurrentStream m_CurrentAudioID3; CSelectionStreams m_SelectionStreams; std::vector m_programs; struct SContent { mutable CCriticalSection m_section; CSelectionStreams m_selectionStreams; std::vector m_programs; int m_videoIndex{-1}; int m_audioIndex{-1}; int m_subtitleIndex{-1}; } m_content; int m_playSpeed; int m_streamPlayerSpeed; int m_demuxerSpeed = DVD_PLAYSPEED_NORMAL; struct SSpeedState { double lastpts; // holds last display pts during ff/rw operations int64_t lasttime; double lastseekpts; double lastabstime; } m_SpeedState; double m_offset_pts; CDVDMessageQueue m_messenger; std::unique_ptr m_outboundEvents; IDVDStreamPlayerVideo *m_VideoPlayerVideo; IDVDStreamPlayerAudio *m_VideoPlayerAudio; CVideoPlayerSubtitle *m_VideoPlayerSubtitle; CDVDTeletextData *m_VideoPlayerTeletext; CDVDRadioRDSData *m_VideoPlayerRadioRDS; std::unique_ptr m_VideoPlayerAudioID3; CDVDClock m_clock; CDVDOverlayContainer m_overlayContainer; std::shared_ptr m_pInputStream; std::unique_ptr m_pDemuxer; std::shared_ptr m_pSubtitleDemuxer; std::unordered_map> m_subtitleDemuxerMap; std::unique_ptr m_pCCDemuxer; CRenderManager m_renderManager; struct SDVDInfo { void Clear() { state = DVDSTATE_NORMAL; iSelectedSPUStream = -1; iSelectedAudioStream = -1; iSelectedVideoStream = -1; iDVDStillTime = std::chrono::milliseconds::zero(); iDVDStillStartTime = {}; syncClock = false; } int state; // current dvdstate bool syncClock; std::chrono::milliseconds iDVDStillTime; // total time in ticks we should display the still before continuing std::chrono::time_point iDVDStillStartTime; // time in ticks when we started the still int iSelectedSPUStream; // mpeg stream id, or -1 if disabled int iSelectedAudioStream; // mpeg stream id, or -1 if disabled int iSelectedVideoStream; // mpeg stream id or angle, -1 if disabled } m_dvd; SPlayerState m_State; mutable CCriticalSection m_StateSection; XbmcThreads::EndTime<> m_syncTimer; CEdl m_Edl; bool m_SkipCommercials; bool m_HasVideo; bool m_HasAudio; bool m_UpdateStreamDetails; std::atomic m_displayLost; };