上篇讲到player的建立流程KODI(原XBMC)二次开发完全解析(二)-------创建player,接着上篇确定哪一个才是真正干活的player。
m_pPlayer->CreatePlayer(newPlayer, *this);//创建player,下篇重点讲 这个就开始创建player,这个m_pPlayer就是xbmc/ApplicationPlayer.h的实例,调用源码如下:
void CApplicationPlayer::CreatePlayer(const std::string &player, IPlayerCallback& callback) CSingleLock lock(m_player_lock); m_pPlayer.reset(CPlayerCoreFactory::GetInstance().CreatePlayer(player, callback));
player就是需要创建的player,继续查看CPlayerCoreFactory::GetInstance().CreatePlayer(player, callback)
IPlayer* CPlayerCoreFactory::CreatePlayer(const std::string& nameId, IPlayerCallback& callback) const CSingleLock lock(m_section); size_t idx = GetPlayerIndex(nameId); if (m_vecPlayerConfigs.empty() || idx > m_vecPlayerConfigs.size()) return m_vecPlayerConfigs[idx]->CreatePlayer(callback);
根据nameId调用PlayerCoreConfig.h创建Player
IPlayer* CreatePlayer(IPlayerCallback& callback) const if (m_type.compare("video") == 0) pPlayer = new CVideoPlayer(callback);//创建VideoPlayer else if (m_type.compare("music") == 0) pPlayer = new PAPlayer(callback); else if (m_type.compare("external") == 0) pPlayer = new CExternalPlayer(callback); else if (m_type.compare("remote") == 0) pPlayer = new UPNP::CUPnPPlayer(callback, m_id.c_str()); pPlayer->m_name = m_name; pPlayer->m_type = m_type; if (pPlayer->Initialize(m_config))
根据type类型,创建需要的player,至此,我们找到了VideoPlayer,这个才是这篇要说的重点,下面先查看VideoPlayer.h文件,位于xbmc/cores/VideoPlayer/VideoPlayer.h
class CVideoPlayer : public IPlayer, public CThread, public IVideoPlayer, public IDispResource, public IRenderMsg CVideoPlayer(IPlayerCallback& callback); virtual bool OpenFile(const CFileItem& file, const CPlayerOptions &options); virtual bool CloseFile(bool reopen = false); virtual bool IsPlaying() const; virtual void Pause() override; virtual bool HasVideo() const; virtual bool HasAudio() const; virtual bool HasRDS() const; virtual bool IsPassthrough() const; virtual void Seek(bool bPlus, bool bLargeStep, bool bChapterOverride); virtual bool SeekScene(bool bPlus = true); virtual void SeekPercentage(float iPercent); virtual float GetPercentage(); virtual float GetCachePercentage(); virtual void SetVolume(float nVolume) override; virtual void SetMute(bool bOnOff) override; virtual void SetDynamicRangeCompression(long drc) override; virtual bool CanRecord(); virtual bool IsRecording(); virtual bool Record(bool bOnOff); virtual void SetAVDelay(float fValue = 0.0f); virtual float GetAVDelay(); virtual bool IsInMenu() const override; virtual bool HasMenu() const override; virtual void SetSubTitleDelay(float fValue = 0.0f); virtual float GetSubTitleDelay(); virtual int GetSubtitleCount(); virtual int GetSubtitle(); virtual void GetSubtitleStreamInfo(int index, SPlayerSubtitleStreamInfo &info); virtual void SetSubtitle(int iStream); virtual bool GetSubtitleVisible(); virtual void SetSubtitleVisible(bool bVisible); virtual void AddSubtitle(const std::string& strSubPath); virtual int GetAudioStreamCount(); virtual int GetAudioStream(); virtual void SetAudioStream(int iStream); virtual int GetVideoStream() const override; virtual int GetVideoStreamCount() const override; virtual void GetVideoStreamInfo(int streamId, SPlayerVideoStreamInfo &info) override; virtual void SetVideoStream(int iStream); virtual TextCacheStruct_t* GetTeletextCache(); virtual void LoadPage(int p, int sp, unsigned char* buffer); virtual std::string GetRadioText(unsigned int line); virtual int GetChapterCount(); virtual int GetChapter(); virtual void GetChapterName(std::string& strChapterName, int chapterIdx=-1); virtual int64_t GetChapterPos(int chapterIdx=-1); virtual int SeekChapter(int iChapter); virtual void SeekTime(int64_t iTime); virtual bool SeekTimeRelative(int64_t iTime); virtual int64_t GetTime(); virtual int64_t GetTotalTime(); virtual void SetSpeed(float speed) override; virtual float GetSpeed() override; virtual bool SupportsTempo() override; virtual bool OnAction(const CAction &action); virtual int GetSourceBitrate(); virtual bool GetStreamDetails(CStreamDetails &details); virtual void GetAudioStreamInfo(int index, SPlayerAudioStreamInfo &info); virtual std::string GetPlayerState(); virtual bool SetPlayerState(const std::string& state); virtual std::string GetPlayingTitle(); virtual bool SwitchChannel(const PVR::CPVRChannelPtr &channel); virtual void FrameMove(); virtual void Render(bool clear, uint32_t alpha = 255, bool gui = true); virtual void FlushRenderer(); virtual void SetRenderViewMode(int mode); float GetRenderAspectRatio(); virtual void TriggerUpdateResolution(); virtual bool IsRenderingVideo(); virtual bool IsRenderingGuiLayer(); virtual bool IsRenderingVideoLayer(); virtual bool Supports(EINTERLACEMETHOD method) override; virtual EINTERLACEMETHOD GetDeinterlacingMethodDefault() override; virtual bool Supports(ESCALINGMETHOD method) override; virtual bool Supports(ERENDERFEATURE feature) override; virtual unsigned int RenderCaptureAlloc(); virtual void RenderCapture(unsigned int captureId, unsigned int width, unsigned int height, int flags); virtual void RenderCaptureRelease(unsigned int captureId); virtual bool RenderCaptureGetPixels(unsigned int captureId, unsigned int millis, uint8_t *buffer, unsigned int size); // IDispResource interface virtual void OnLostDisplay(); virtual void OnResetDisplay(); virtual bool IsCaching() const override; virtual int GetCacheLevel() const override; virtual int OnDVDNavResult(void* pData, int iMessage) override; void GetVideoResolution(unsigned int &width, unsigned int &height) override; friend class CSelectionStreams; virtual void OnStartup(); virtual void VideoParamsChange() override; virtual void GetDebugInfo(std::string &audio, std::string &video, std::string &general) override; virtual void UpdateClockSync(bool enabled) override; virtual void UpdateRenderInfo(CRenderInfo &info) override; virtual void UpdateRenderBuffers(int queued, int discard, int free) override; 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(CDVDStreamInfo& hint); bool OpenTeletextStream(CDVDStreamInfo& hint); bool OpenRadioRDSStream(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(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); bool ShowPVRChannelInfo(); int AddSubtitleFile(const std::string& filename, const std::string& subfilename = ""); void SetSubtitleVisibleInternal(bool bVisible); * one of the DVD_PLAYSPEED defines void SetPlaySpeed(int iSpeed); int GetPlaySpeed() { return m_playSpeed; } 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); int64_t GetTotalTimeInMsec(); bool GetCachingTimes(double& play_left, double& cache_left, double& file_offset); void FlushBuffers(double pts, bool accurate, bool sync); bool IsInMenuInternal() const; void SynchronizeDemuxer(); void CheckAutoSceneSkip(); bool CheckContinuity(CCurrentStream& current, DemuxPacket* pPacket); bool CheckSceneSkip(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(CDVDMsg* pMsg, unsigned int target); bool ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream); bool IsValidStream(CCurrentStream& stream); bool IsBetterStream(CCurrentStream& current, CDemuxStream* stream); void CheckBetterStream(CCurrentStream& current, CDemuxStream* stream); void CheckStreamChanges(CCurrentStream& current, CDemuxStream* stream); bool CheckDelayedChannelEntry(void); void OpenDefaultStreams(bool reset = true); void UpdateApplication(double timeout); void UpdatePlayState(double timeout); void UpdateStreamInfos(); void GetGeneralInfo(std::string& strVideoInfo); double m_UpdateApplication; XbmcThreads::EndTime m_cachingTimer; XbmcThreads::EndTime m_ChannelEntryTimeOut; std::unique_ptr<CProcessInfo> m_processInfo; CCurrentStream m_CurrentAudio; CCurrentStream m_CurrentVideo; CCurrentStream m_CurrentSubtitle; CCurrentStream m_CurrentTeletext; CCurrentStream m_CurrentRadioRDS; CSelectionStreams m_SelectionStreams; std::atomic_int m_playSpeed; std::atomic_int m_newPlaySpeed; double lastpts; // holds last display pts during ff/rw operations std::atomic_bool m_canTempo; CDVDMessageQueue m_messenger; // thread messenger IDVDStreamPlayerVideo *m_VideoPlayerVideo; // video part IDVDStreamPlayerAudio *m_VideoPlayerAudio; // audio part CVideoPlayerSubtitle *m_VideoPlayerSubtitle; // subtitle part CDVDTeletextData *m_VideoPlayerTeletext; // teletext part CDVDRadioRDSData *m_VideoPlayerRadioRDS; // rds part CDVDClock m_clock; // master clock CDVDOverlayContainer m_overlayContainer; CDVDInputStream* m_pInputStream; // input stream for current playing file CDVDDemux* m_pDemuxer; // demuxer for current playing file CDVDDemux* m_pSubtitleDemuxer; CDVDDemuxCC* m_pCCDemuxer; CRenderManager m_renderManager; iSelectedAudioStream = -1; iSelectedVideoStream = -1; int state; // current dvdstate unsigned int iDVDStillTime; // total time in ticks we should display the still before continuing unsigned int 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 friend class CVideoPlayerVideo; friend class CVideoPlayerAudio; friend class OMXPlayerVideo; friend class OMXPlayerAudio; CCriticalSection m_StateSection; XbmcThreads::EndTime m_syncTimer; CPlayerOptions m_PlayerOptions; std::atomic<bool> m_displayLost; struct SOmxPlayerState m_OmxPlayerState; bool m_omxplayer_mode; // using omxplayer acceleration XbmcThreads::EndTime m_player_status_timer;
其中定义了很多诸如seek、pause函数,看完这个就确定我们找的VideoPlayer是没有错误的,而VideoPlayer extends Thread,这个子线程明显就是要解析视频的线程,查看当前thread的Process函数
void CVideoPlayer::Process() CFFmpegLog::SetLogLevel(1); if (!OpenInputStream())//创建输入流 if (CDVDInputStream::IMenus* ptr = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream)) CLog::Log(LOGNOTICE, "VideoPlayer: playing a file with menu's"); if(dynamic_cast<CDVDInputStreamNavigator*>(m_pInputStream)) m_PlayerOptions.starttime = 0; if(!m_PlayerOptions.state.empty()) ptr->SetState(m_PlayerOptions.state); else if(CDVDInputStreamNavigator* nav = dynamic_cast<CDVDInputStreamNavigator*>(m_pInputStream)) nav->EnableSubtitleStream(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_SubtitleOn); CMediaSettings::GetInstance().GetCurrentVideoSettings().m_SubtitleCached = true; if(!OpenDemuxStream())//创建demux // give players a chance to reconsider now codecs are known // allow renderer to switch to fullscreen if requested m_VideoPlayerVideo->EnableFullscreen(m_PlayerOptions.fullscreen); if (!m_OmxPlayerState.av_clock.OMXInitialize(&m_clock)) if (CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE) != ADJUST_REFRESHRATE_OFF) m_OmxPlayerState.av_clock.HDMIClockSync(); m_OmxPlayerState.av_clock.OMXStateIdle(); m_OmxPlayerState.av_clock.OMXStateExecute(); m_OmxPlayerState.av_clock.OMXStop(); m_OmxPlayerState.av_clock.OMXPause(); // look for any EDL files if (m_CurrentVideo.id >= 0 && m_CurrentVideo.hint.fpsrate > 0 && m_CurrentVideo.hint.fpsscale > 0) float fFramesPerSecond = (float)m_CurrentVideo.hint.fpsrate / (float)m_CurrentVideo.hint.fpsscale; m_Edl.ReadEditDecisionLists(m_item.GetPath(), fFramesPerSecond, m_CurrentVideo.hint.height); * Check to see if the demuxer should start at something other than time 0. This will be the case * if there was a start time specified as part of the "Start from where last stopped" (aka * auto-resume) feature or if there is an EDL cut or commercial break that starts at time 0. if (m_PlayerOptions.starttime > 0 || m_PlayerOptions.startpercent > 0) if (m_PlayerOptions.startpercent > 0 && m_pDemuxer) int playerStartTime = (int)( ( (float) m_pDemuxer->GetStreamLength() ) * ( m_PlayerOptions.startpercent/(float)100 ) ); starttime = m_Edl.RestoreCutTime(playerStartTime); starttime = m_Edl.RestoreCutTime(m_PlayerOptions.starttime * 1000); // s to ms CLog::Log(LOGDEBUG, "%s - Start position set to last stopped position: %d", __FUNCTION__, starttime); else if (m_Edl.InCut(starttime, &cut)) if (cut.action == CEdl::CUT) CLog::Log(LOGDEBUG, "%s - Start position set to end of first cut: %d", __FUNCTION__, starttime); else if (cut.action == CEdl::COMM_BREAK) CLog::Log(LOGDEBUG, "%s - Start position set to end of first commercial break: %d", __FUNCTION__, starttime); std::string strTimeString = StringUtils::SecondsToTimeString(cut.end / 1000, TIME_FORMAT_MM_SS); CGUIDialogKaiToast::QueueNotification(g_localizeStrings.Get(25011), strTimeString); if (starttime > 0)//判断上次播放时长,选择从上次播放时开始播放 double startpts = DVD_NOPTS_VALUE; if (m_pDemuxer->SeekTime(starttime, false, &startpts)) CLog::Log(LOGDEBUG, "%s - starting demuxer from: %d", __FUNCTION__, starttime); CLog::Log(LOGDEBUG, "%s - failed to start demuxing from: %d", __FUNCTION__, starttime); if(m_pSubtitleDemuxer->SeekTime(starttime, false, &startpts)) CLog::Log(LOGDEBUG, "%s - starting subtitle demuxer from: %d", __FUNCTION__, starttime); CLog::Log(LOGDEBUG, "%s - failed to start subtitle demuxing from: %d", __FUNCTION__, starttime); m_clock.Discontinuity(DVD_MSEC_TO_TIME(starttime)); // make sure application know our info if(m_PlayerOptions.identify == false) m_callback.OnPlayBackStarted(); // we are done initializing now, set the readyevent SetCaching(CACHESTATE_FLUSH); while (!m_bAbortRequest)//开启循环demux,将数据抛给下层decode if (m_omxplayer_mode && OMXDoProcessing(m_OmxPlayerState, m_playSpeed, m_VideoPlayerVideo, m_VideoPlayerAudio, m_CurrentAudio, m_CurrentVideo, m_HasVideo, m_HasAudio, m_renderManager)) CloseStream(m_CurrentVideo, false); OpenStream(m_CurrentVideo, m_CurrentVideo.demuxerId, m_CurrentVideo.id, m_CurrentVideo.source); CDVDMsgPlayerSeek::CMode mode; mode.time = (int)GetTime(); m_messenger.Put(new CDVDMsgPlayerSeek(mode)); // check if in a cut or commercial break that should be automatically skipped // handle messages send to this thread, like seek or demuxer reset requests // should we open a new input stream? if (OpenInputStream() == false) // should we open a new demuxer? if (m_pInputStream->NextStream() == CDVDInputStream::NEXTSTREAM_NONE) if (m_pInputStream->IsEOF()) if (OpenDemuxStream() == false) // on channel switch we don't want to close stream players at this // time. we'll get the stream change event later if (!m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) || !m_SelectionStreams.m_Streams.empty()) // handle eventual seeks due to playspeed // update application with our state // make sure we run subtitle process here m_VideoPlayerSubtitle->Process(m_clock.GetClock() + m_State.time_offset - m_VideoPlayerVideo->GetSubtitleDelay(), m_State.time_offset); if (CheckDelayedChannelEntry()) // if the queues are full, no need to read more if ((!m_VideoPlayerAudio->AcceptsData() && m_CurrentAudio.id >= 0) || (!m_VideoPlayerVideo->AcceptsData() && m_CurrentVideo.id >= 0)) // always yield to players if they have data levels > 50 percent if((m_VideoPlayerAudio->GetLevel() > 50 || m_CurrentAudio.id < 0) && (m_VideoPlayerVideo->GetLevel() > 50 || m_CurrentVideo.id < 0)) DemuxPacket* pPacket = NULL; CDemuxStream *pStream = NULL; ReadPacket(pPacket, pStream);//开始将流封包,方便传给下一层decode /* probably a empty packet, just free it and move on */ CDVDDemuxUtils::FreeDemuxPacket(pPacket); // when paused, demuxer could be be returning empty if (m_playSpeed == DVD_PLAYSPEED_PAUSE) // check for a still frame state if (CDVDInputStream::IMenus* pStream = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream)) // stills will be skipped if(m_dvd.state == DVDSTATE_STILL) if (m_dvd.iDVDStillTime > 0) if ((XbmcThreads::SystemClockMillis() - m_dvd.iDVDStillStartTime) >= m_dvd.iDVDStillTime) m_dvd.iDVDStillStartTime = 0; m_dvd.state = DVDSTATE_NORMAL; // if there is another stream available, reopen demuxer CDVDInputStream::ENextStream next = m_pInputStream->NextStream(); if(next == CDVDInputStream::NEXTSTREAM_OPEN) SetCaching(CACHESTATE_DONE); CLog::Log(LOGNOTICE, "VideoPlayer: next stream, wait for old streams to be finished"); CloseStream(m_CurrentAudio, true); CloseStream(m_CurrentVideo, true); m_CurrentSubtitle.Clear(); // input stream asked us to just retry if(next == CDVDInputStream::NEXTSTREAM_RETRY) // make sure we tell all players to finish it's data if (m_omxplayer_mode && !m_OmxPlayerState.bOmxSentEOFs) if(m_CurrentAudio.inited) m_OmxPlayerState.bOmxWaitAudio = true; if(m_CurrentVideo.inited) m_OmxPlayerState.bOmxWaitVideo = true; m_OmxPlayerState.bOmxSentEOFs = true; if(m_CurrentAudio.inited) m_VideoPlayerAudio->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF)); if(m_CurrentVideo.inited) m_VideoPlayerVideo->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF)); if(m_CurrentSubtitle.inited) m_VideoPlayerSubtitle->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF)); if(m_CurrentTeletext.inited) m_VideoPlayerTeletext->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF)); if(m_CurrentRadioRDS.inited) m_VideoPlayerRadioRDS->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF)); m_CurrentAudio.inited = false; m_CurrentVideo.inited = false; m_CurrentSubtitle.inited = false; m_CurrentTeletext.inited = false; m_CurrentRadioRDS.inited = false; // if we are caching, start playing it again SetCaching(CACHESTATE_DONE); // while players are still playing, keep going to allow seekbacks if(m_VideoPlayerAudio->HasData() || m_VideoPlayerVideo->HasData()) if (m_omxplayer_mode && OMXStillPlaying(m_OmxPlayerState.bOmxWaitVideo, m_OmxPlayerState.bOmxWaitAudio, m_VideoPlayerVideo->IsEOS(), m_VideoPlayerAudio->IsEOS())) if (!m_pInputStream->IsEOF()) CLog::Log(LOGINFO, "%s - eof reading from demuxer", __FUNCTION__); // it's a valid data packet, reset error counter // see if we can find something better to play CheckBetterStream(m_CurrentAudio, pStream); CheckBetterStream(m_CurrentVideo, pStream); CheckBetterStream(m_CurrentSubtitle, pStream); CheckBetterStream(m_CurrentTeletext, pStream); CheckBetterStream(m_CurrentRadioRDS, pStream); if (CSettings::GetInstance().GetBool(CSettings::SETTING_SUBTITLES_PARSECAPTIONS) && CheckIsCurrent(m_CurrentVideo, pStream, pPacket)) DemuxPacket *pkt = m_pCCDemuxer->Read(first ? pPacket : NULL); if (m_pCCDemuxer->GetNrOfStreams() != m_SelectionStreams.CountSource(STREAM_SUBTITLE, STREAM_SOURCE_VIDEOMUX)) m_SelectionStreams.Clear(STREAM_SUBTITLE, STREAM_SOURCE_VIDEOMUX); m_SelectionStreams.Update(NULL, m_pCCDemuxer, ""); OpenDefaultStreams(false); CDemuxStream *pSubStream = m_pCCDemuxer->GetStream(pkt->iStreamId); if (pSubStream && m_CurrentSubtitle.id == pkt->iStreamId && m_CurrentSubtitle.source == STREAM_SOURCE_VIDEOMUX) ProcessSubData(pSubStream, pkt); CDVDDemuxUtils::FreeDemuxPacket(pkt); if (CDVDInputStream::IMenus* menu = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream)) double correction = menu->GetTimeStampCorrection(); if (pPacket->dts != DVD_NOPTS_VALUE && pPacket->dts > correction) pPacket->dts -= correction; if (pPacket->pts != DVD_NOPTS_VALUE && pPacket->pts > correction) pPacket->pts -= correction; m_clock.Discontinuity(pPacket->dts); ProcessPacket(pStream, pPacket);//将音频流、视频流、字幕流等分开,创建decode的Player并将数据传递给他们 // update the player info for streams if (m_player_status_timer.IsTimePast()) m_player_status_timer.Set(500);
第一步是OpenInputStream,调用
bool CVideoPlayer::OpenInputStream() SAFE_DELETE(m_pInputStream); CLog::Log(LOGNOTICE, "Creating InputStream"); // correct the filename if needed std::string filename(m_item.GetPath()); if (URIUtils::IsProtocol(filename, "dvd") || StringUtils::EqualsNoCase(filename, "iso9660://video_ts/video_ts.ifo")) m_item.SetPath(g_mediaManager.TranslateDevicePath("")); m_pInputStream = CDVDFactoryInputStream::CreateInputStream(this, m_item, true);//创建 if(m_pInputStream == NULL) CLog::Log(LOGERROR, "CVideoPlayer::OpenInputStream - unable to create input stream for [%s]", CURL::GetRedacted(m_item.GetPath()).c_str()); if (!m_pInputStream->Open()) CLog::Log(LOGERROR, "CVideoPlayer::OpenInputStream - error opening [%s]", CURL::GetRedacted(m_item.GetPath()).c_str()); // find any available external subtitles for non dvd files if (!m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD) && !m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) && !m_pInputStream->IsStreamType(DVDSTREAM_TYPE_TV)) // find any available external subtitles std::vector<std::string> filenames; CUtil::ScanForExternalSubtitles(m_item.GetPath(), filenames); // load any subtitles from file item std::string key("subtitle:1"); for(unsigned s = 1; m_item.HasProperty(key); key = StringUtils::Format("subtitle:%u", ++s)) filenames.push_back(m_item.GetProperty(key).asString()); for(unsigned int i=0;i<filenames.size();i++) if (URIUtils::HasExtension(filenames[i], ".idx")) if ( CUtil::FindVobSubPair( filenames, filenames[i], strSubFile ) ) AddSubtitleFile(filenames[i], strSubFile); if ( !CUtil::IsVobSub(filenames, filenames[i] ) ) AddSubtitleFile(filenames[i]); } // end loop over all subtitle files CMediaSettings::GetInstance().GetCurrentVideoSettings().m_SubtitleCached = true; SetAVDelay(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_AudioDelay); SetSubTitleDelay(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_SubtitleDelay); m_ChannelEntryTimeOut.SetInfinite(); if (CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEDISPLAYASCLOCK) && !m_pInputStream->IsRealtime())
调用m_pInputStream = CDVDFactoryInputStream::CreateInputStream(this, m_item, true);创建,查看位于xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp
CDVDInputStream* CDVDFactoryInputStream::CreateInputStream(IVideoPlayer* pPlayer, const CFileItem &fileitem, bool scanforextaudio)//根据文件类型创建不同的InputStream std::string file = fileitem.GetPath(); // find any available external audio tracks std::vector<std::string> filenames; filenames.push_back(file); CUtil::ScanForExternalAudio(file, filenames); CUtil::ScanForExternalDemuxSub(file, filenames); if (filenames.size() >= 2) return CreateInputStream(pPlayer, fileitem, filenames); ADDON::CBinaryAddonCache &addonCache = CServiceBroker::GetBinaryAddonCache(); addonCache.GetAddons(addons, ADDON::ADDON_INPUTSTREAM); for (size_t i=0; i<addons.size(); ++i) std::shared_ptr<ADDON::CInputStream> input(std::static_pointer_cast<ADDON::CInputStream>(addons[i])); if (input->Supports(fileitem)) std::shared_ptr<ADDON::CInputStream> addon = input; addon = std::shared_ptr<ADDON::CInputStream>(new ADDON::CInputStream(*input)); ADDON_STATUS status = addon->Create(); if (status == ADDON_STATUS_OK) unsigned int videoWidth, videoHeight; pPlayer->GetVideoResolution(videoWidth, videoHeight); addon->SetVideoResolution(videoWidth, videoHeight); return new CInputStreamAddon(fileitem, addon); if (fileitem.IsDiscImage()) url.SetFileName("BDMV/index.bdmv"); if(XFILE::CFile::Exists(url.Get())) return new CDVDInputStreamBluray(pPlayer, fileitem); return new CDVDInputStreamNavigator(pPlayer, fileitem); if(file.compare(g_mediaManager.TranslateDevicePath("")) == 0) if(XFILE::CFile::Exists(URIUtils::AddFileToFolder(file, "BDMV", "index.bdmv"))) return new CDVDInputStreamBluray(pPlayer, fileitem); return new CDVDInputStreamNavigator(pPlayer, fileitem); if (fileitem.IsDVDFile(false, true)) return (new CDVDInputStreamNavigator(pPlayer, fileitem)); else if(file.substr(0, 6) == "pvr://") return new CDVDInputStreamPVRManager(pPlayer, fileitem); else if (fileitem.IsType(".bdmv") || fileitem.IsType(".mpls") || file.substr(0, 7) == "bluray:") return new CDVDInputStreamBluray(pPlayer, fileitem); else if(file.substr(0, 6) == "rtp://" || file.substr(0, 7) == "rtsp://" || file.substr(0, 6) == "sdp://" || file.substr(0, 6) == "udp://" || file.substr(0, 6) == "tcp://" || file.substr(0, 6) == "mms://" || file.substr(0, 7) == "mmst://" || file.substr(0, 7) == "mmsh://") return new CDVDInputStreamFFmpeg(fileitem); #ifdef ENABLE_DVDINPUTSTREAM_STACK else if(file.substr(0, 8) == "stack://") return new CDVDInputStreamStack(fileitem); else if(file.substr(0, 7) == "rtmp://" || file.substr(0, 8) == "rtmpt://" || file.substr(0, 8) == "rtmpe://" || file.substr(0, 9) == "rtmpte://" || file.substr(0, 8) == "rtmps://") return new CDVDInputStreamFFmpeg(fileitem); CFileItem finalFileitem(fileitem); if (finalFileitem.IsInternetStream()) if (finalFileitem.ContentLookup()) CURL origUrl(finalFileitem.GetURL()); XFILE::CCurlFile curlFile; // try opening the url to resolve all redirects if any if (curlFile.Open(finalFileitem.GetURL())) CURL finalUrl(curlFile.GetURL()); finalUrl.SetProtocolOptions(origUrl.GetProtocolOptions()); finalUrl.SetUserName(origUrl.GetUserName()); finalUrl.SetPassword(origUrl.GetPassWord()); finalFileitem.SetPath(finalUrl.Get()); catch (XFILE::CRedirectException *pRedirectEx) delete pRedirectEx->m_pNewFileImp; if (finalFileitem.IsType(".m3u8")) return new CDVDInputStreamFFmpeg(finalFileitem); if (finalFileitem.GetMimeType() == "application/vnd.apple.mpegurl") return new CDVDInputStreamFFmpeg(finalFileitem); if (URIUtils::IsProtocol(finalFileitem.GetPath(), "udp")) return new CDVDInputStreamFFmpeg(finalFileitem); // our file interface handles all these types of streams return (new CDVDInputStreamFile(finalFileitem));
其中很容易理解,kodi是一个全能的播放器,会支持许许多多的InputStream,根据类型判断初始化什么播放器,而DVDInputStreamFFmpeg能获取很多种类型的inputStream,下篇我们主要讲高大上的DVDInputStreamDDmpeg。
|