BlinkenArea - GitList
Repositories
Blog
Wiki
Blinker
Code
Commits
Branches
Tags
Search
Tree:
bd35589
Branches
Tags
master
Blinker
src
noarch
Player.cpp
implemented automatic checks for config updates
Stefan Schuermans
commited
bd35589
at 2011-10-24 22:41:59
Player.cpp
Blame
History
Raw
/* Blinker Copyright 2011 Stefan Schuermans <stefan@blinkenarea.org> Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html a blinkenarea.org project */ #include <list> #include <string> #include <BlinkenLib/BlinkenFrame.h> #include <BlinkenLib/BlinkenMovie.h> #include "CallMgr.h" #include "Directory.h" #include "File.h" #include "Module.h" #include "Player.h" #include "SettingFile.h" #include "StreamMgr.h" #include "Time.h" #include "TimeCallee.h" namespace Blinker { /** * @brief constructor * @param[in] callMgr callback manager * @param[in] streamMgr stream manager * @param[in] dirBase base directory */ Player::Player(CallMgr &callMgr, StreamMgr &streamMgr, const Directory &dirBase): Module(callMgr, streamMgr, dirBase), m_fileOutStream(dirBase.getFile("outstream")), m_dirPlaylist(dirBase.getSubdir("playlist")), m_pOutStream(NULL), m_curValid(false), m_curEntry(m_playlist.begin()), m_curFrame(0) { // get output stream getOutStream(); // load playlist updatePlaylistFull(); } /// virtual destructor Player::~Player() { // free all movies while (!m_playlist.empty()) { m_playlist.back().freeMovie(); m_playlist.pop_back(); } // release output stream releaseOutStream(); } /// check for update of configuration void Player::updateConfig() { // output stream name file was modified -> re-get output stream if (m_fileOutStream.checkModified()) { releaseOutStream(); getOutStream(); } // playlist update (directory modified -> full, otherwise -> light) if (m_dirPlaylist.checkModified()) updatePlaylistFull(); else updatePlaylistLight(); } /// callback when requsted time reached void Player::timeCall() { // leave if time is not yet ready to next frame if (Time::now() < m_nextTime) { // request call at time for next frame m_callMgr.requestTimeCall(this, m_nextTime); return; } // go to next frame ++m_curFrame; // process new current frame procFrame(); } /// light update of playlist, i.e. stat all files in current playlist void Player::updatePlaylistLight() { // walk through all files in playlist and check for modification Playlist::iterator itEntry = m_playlist.begin(); bool bCurChg = false; while (itEntry != m_playlist.end()) { // movie changed if (itEntry->m_file.checkModified()) { // check if changed movie is current movie if (itEntry == m_curEntry) { // advance current movie to next movie ++m_curEntry; bCurChg = true; } // remove entry itEntry->freeMovie(); itEntry = m_playlist.erase(itEntry); // re-load entry itEntry->freeMovie(); if (!itEntry->loadMovie()) { // loading movie failed -> remove entry itEntry = m_playlist.erase(itEntry); // do not advance to next file continue; } } // advance to next file ++itEntry; } // while itEntry // current movie entry changed if (bCurChg) { // go to begin of new current movie and start playing now m_curFrame = 0; m_nextTime = Time::now(); procFrame(); } } /// full update of playlist, i.e. scan files in playlist directory void Player::updatePlaylistFull() { // get list of files in playlist directory typedef std::list<std::string> Filelist; Filelist curFiles; m_dirPlaylist.getEntries(Directory::TypeFile, curFiles); // walk through current playlist and file list simultaneously bool bWasEmpty = m_playlist.empty(); Filelist::const_iterator itFile = curFiles.begin(); Playlist::iterator itEntry = m_playlist.begin(); bool bCurChg = false; while (itFile != curFiles.end() || itEntry != m_playlist.end()) { // new movie inserted if (itEntry == m_playlist.end() || (itFile != curFiles.end() && *itFile < itEntry->m_name)) { // load movie Entry entry(*itFile, m_dirPlaylist.getFile(*itFile)); if (entry.loadMovie()) // insert playlist entry m_playlist.insert(itEntry, entry); // advance to next file ++itFile; } // movie removed // movie changed (=> remove and re-insert in next iteration) else if (itFile == curFiles.end() || *itFile > itEntry->m_name || itEntry->m_file.checkModified()) { // check if movie to remove is current movie if (itEntry == m_curEntry) { // advance current movie to next movie ++m_curEntry; bCurChg = true; } // remove entry itEntry->freeMovie(); itEntry = m_playlist.erase(itEntry); // do not advance to next file } // movie stayed in playlist and did not change else { // advance to next file and next entry ++itFile; ++itEntry; } } // while itFile itEntry // current movie entry changed - or - playlist was empty and is not now if (bCurChg || (bWasEmpty && !m_playlist.empty())) { // go to begin of new current movie and start playing now m_curFrame = 0; m_nextTime = Time::now(); procFrame(); } } /// get output stream void Player::getOutStream() { // get name of output stream m_fileOutStream.getStr(m_nameOutStream); // get output stream m_pOutStream = &m_streamMgr.refStream(m_nameOutStream); // send current frame to stream sendFrame(); } /// release output stream void Player::releaseOutStream() { // send no frame information if (m_pOutStream) m_pOutStream->setNoFrame(); // unreference output stream m_pOutStream = NULL; m_streamMgr.unrefStream(m_nameOutStream); } /// process current frame void Player::procFrame() { // movie finished -> next movie // use while loops to handle empty movies / empty playlist m_curValid = true; bool wrapped = false; while (true) { // playlist finished -> re-start from beginning while (m_curEntry == m_playlist.end()) { m_curEntry = m_playlist.begin(); m_curFrame = 0; // detect empty playlist or playlist with only empty movies if (wrapped) { m_curValid = false; break; } wrapped = true; } if (!m_curValid) break; // movie not yet finished -> done if (m_curFrame < BlinkenMovieGetFrameCnt(m_curEntry->m_pMovie)) break; // movie finished -> next movie ++m_curEntry; m_curFrame = 0; } // send new frame to stream sendFrame(); // if a frame is there if (m_curValid) { // calculate time for next frame stBlinkenFrame *pFrame = BlinkenMovieGetFrame(m_curEntry->m_pMovie, m_curFrame); Time duration; duration.fromMs(BlinkenFrameGetDuration(pFrame)); m_nextTime += duration; // request call at time for next frame m_callMgr.requestTimeCall(this, m_nextTime); } } /// send current frame to output stream void Player::sendFrame() { if (m_pOutStream) { // frame avalable -> send it if (m_curValid) { stBlinkenFrame *pFrame = BlinkenMovieGetFrame(m_curEntry->m_pMovie, m_curFrame); m_pOutStream->setFrame(pFrame); } // no frame available -> send this information else m_pOutStream->setNoFrame(); } } /* ################# # Player::Entry # ################# */ /// constructor Player::Entry::Entry(const std::string &name, const File &file): m_name(name), m_file(file), m_pMovie(NULL) { } /// load movie from current file bool Player::Entry::loadMovie() { freeMovie(); m_pMovie = BlinkenMovieLoad(m_file.getPath().c_str()); return m_pMovie; } /// free current movie void Player::Entry::freeMovie() { if (m_pMovie) { BlinkenMovieFree(m_pMovie); m_pMovie = NULL; } } } // namespace Blinker