diff options
author | Luca Muscariello <lumuscar+fdio@cisco.com> | 2017-02-25 23:42:31 +0100 |
---|---|---|
committer | Luca Muscariello <lumuscar+fdio@cisco.com> | 2017-02-25 23:42:31 +0100 |
commit | 05c1a838c881ea502888659848d8792843b28718 (patch) | |
tree | cf0b05b58bd725a1eb6c80325ba986c63dea42aa /Managers | |
parent | 9b30fc10fb1cbebe651e5a107e8ca5b24de54675 (diff) |
Initial commit: video player - viper
Change-Id: Id5aa33598ce34659bad4a7a9ae5006bfb84f9bd1
Signed-off-by: Luca Muscariello <lumuscar+fdio@cisco.com>
Diffstat (limited to 'Managers')
-rw-r--r-- | Managers/IMultimediaManagerBase.h | 39 | ||||
-rw-r--r-- | Managers/IMultimediaManagerObserver.h | 35 | ||||
-rw-r--r-- | Managers/IStreamObserver.h | 46 | ||||
-rw-r--r-- | Managers/MultimediaManager.cpp | 629 | ||||
-rw-r--r-- | Managers/MultimediaManager.h | 140 | ||||
-rw-r--r-- | Managers/MultimediaStream.cpp | 208 | ||||
-rw-r--r-- | Managers/MultimediaStream.h | 89 |
7 files changed, 1186 insertions, 0 deletions
diff --git a/Managers/IMultimediaManagerBase.h b/Managers/IMultimediaManagerBase.h new file mode 100644 index 00000000..f08803ba --- /dev/null +++ b/Managers/IMultimediaManagerBase.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VIPER_MANAGERS_IMULTIMEDIAMANAGERBASE_H_ +#define VIPER_MANAGERS_IMULTIMEDIAMANAGERBASE_H_ + +#include "IMPD.h" + +namespace viper +{ +namespace managers +{ +class IMultimediaManagerBase +{ +public: + virtual bool setVideoQuality(dash::mpd::IPeriod* period, dash::mpd::IAdaptationSet *adaptationSet, dash::mpd::IRepresentation *representation) = 0; + virtual bool setAudioQuality(dash::mpd::IPeriod* period, dash::mpd::IAdaptationSet *adaptationSet, dash::mpd::IRepresentation *representation) = 0; + virtual bool isStarted() = 0; + virtual bool isStopping() = 0; + virtual void shouldAbort(bool isVideo) = 0; + virtual void setTargetDownloadingTime(bool,double) = 0; + +}; +} +} + +#endif //VIPER_MANAGERS_IMULTIMEDIAMANAGERBASE_H_ diff --git a/Managers/IMultimediaManagerObserver.h b/Managers/IMultimediaManagerObserver.h new file mode 100644 index 00000000..eea0bfb1 --- /dev/null +++ b/Managers/IMultimediaManagerObserver.h @@ -0,0 +1,35 @@ +/* + * IMultimediaManagerObserver.h + ***************************************************************************** + * Copyright (C) 2012, bitmovin Softwareentwicklung OG, All Rights Reserved + * + * Email: libdash-dev@vicky.bitmovin.net + * + * This source code and its use and distribution, is subject to the terms + * and conditions of the applicable license agreement. + *****************************************************************************/ + +#ifndef VIPER_MANAGERS_IMULTIMEDIAMANAGEROBSERVER_H_ +#define VIPER_MANAGERS_IMULTIMEDIAMANAGEROBSERVER_H_ + +#include <stdint.h> + +namespace viper +{ +namespace managers +{ +class IMultimediaManagerObserver +{ +public: + virtual ~IMultimediaManagerObserver () {} + virtual void onVideoBufferStateChanged(uint32_t fillstateInPercent) = 0; + virtual void onVideoSegmentBufferStateChanged(uint32_t fillstateInPercent) = 0; + virtual void onAudioBufferStateChanged(uint32_t fillstateInPercent) = 0; + virtual void onAudioSegmentBufferStateChanged(uint32_t fillstateInPercent) = 0; + virtual void onEOS() = 0; + virtual void notifyStatistics(int, uint32_t, int, uint32_t) = 0; + virtual void notifyQualityDownloading(uint32_t) = 0; +}; +} +} +#endif /* VIPER_MANAGERS_IMULTIMEDIAMANAGEROBSERVER_H_ */ diff --git a/Managers/IStreamObserver.h b/Managers/IStreamObserver.h new file mode 100644 index 00000000..d6e8a19c --- /dev/null +++ b/Managers/IStreamObserver.h @@ -0,0 +1,46 @@ +/* + * IStreamObserver.h + ***************************************************************************** + * Copyright (C) 2012, bitmovin Softwareentwicklung OG, All Rights Reserved + * + * Email: libdash-dev@vicky.bitmovin.net + * + * This source code and its use and distribution, is subject to the terms + * and conditions of the applicable license agreement. + *****************************************************************************/ + +#ifndef VIPER_MANAGERS_STREAMOBSERVER_H_ +#define VIPER_MANAGERS_STREAMOBSERVER_H_ + +#include <stdint.h> + +namespace viper +{ +namespace managers +{ +enum StreamType +{ + AUDIO = (1u << 0), + VIDEO = (1u << 1), + SUBTITLE = (1u << 2), +}; + +class IStreamObserver +{ +public: + virtual ~IStreamObserver () {} + virtual void onSegmentDownloaded() = 0; + virtual void onSegmentBufferStateChanged(StreamType type, uint32_t fillstateInPercent, int maxC) = 0; + virtual void onVideoBufferStateChanged(uint32_t fillstateInPercent) = 0; + virtual void onAudioBufferStateChanged(uint32_t fillstateInPercent) = 0; + virtual void setEOS(bool value) = 0; + virtual void notifyStatistics(int segNum, uint32_t bitrate, int fps, uint32_t quality) = 0; + virtual void notifyQualityDownloading(uint32_t quality) = 0; + virtual bool canPush() = 0; + virtual int getBufferLevel() = 0; + +}; +} +} + +#endif /* VIPER_MANAGERS_STREAMOBSERVER_H_ */ diff --git a/Managers/MultimediaManager.cpp b/Managers/MultimediaManager.cpp new file mode 100644 index 00000000..faab66cf --- /dev/null +++ b/Managers/MultimediaManager.cpp @@ -0,0 +1,629 @@ +/* + * MultimediaManager.cpp + ***************************************************************************** + * Copyright (C) 2012, bitmovin Softwareentwicklung OG, All Rights Reserved + * + * Email: libdash-dev@vicky.bitmovin.net + * + * This source code and its use and distribution, is subject to the terms + * and conditions of the applicable license agreement. + *****************************************************************************/ + +#include "MultimediaManager.h" + +#include <fstream> + +using namespace libdash::framework::adaptation; +using namespace libdash::framework::buffer; +using namespace viper::managers; +using namespace dash::mpd; + +#include <queue> + +MultimediaManager::MultimediaManager(ViperGui *viperGui, int segBufSize, std::string downloadPath, bool nodecoding) : + viperGui (viperGui), + segmentBufferSize (segBufSize), + downloadPath (downloadPath), + offset (offset), + mpd (NULL), + period (NULL), + videoAdaptationSet (NULL), + videoRepresentation (NULL), + videoLogic (NULL), + videoStream (NULL), + audioAdaptationSet (NULL), + audioRepresentation (NULL), + audioLogic (NULL), + videoRendererHandle (NULL), + audioRendererHandle (NULL), + audioStream (NULL), + started (false), + stopping (false), + framesDisplayed (0), + segmentsDownloaded (0), + isVideoRendering (false), + isAudioRendering (false), + eos (false), + playing (false), + noDecoding (nodecoding) +{ + InitializeCriticalSection (&this->monitorMutex); + InitializeCriticalSection (&this->monitorBufferMutex); + InitializeCriticalSection (&this->monitor_playing_video_mutex); + InitializeConditionVariable (&this->playingVideoStatusChanged); + InitializeCriticalSection (&this->monitor_playing_audio_mutex); + InitializeConditionVariable (&this->playingAudioStatusChanged); + + this->manager = CreateDashManager(); +} + +MultimediaManager::~MultimediaManager () +{ + this->stop(); + this->manager->Delete(); + DeleteCriticalSection (&this->monitorMutex); + DeleteCriticalSection (&this->monitorBufferMutex); + DeleteCriticalSection (&this->monitor_playing_video_mutex); + DeleteConditionVariable (&this->playingVideoStatusChanged); + DeleteCriticalSection (&this->monitor_playing_audio_mutex); + DeleteConditionVariable (&this->playingAudioStatusChanged); +} + +IMPD* MultimediaManager::getMPD() +{ + return this->mpd; +} + +bool MultimediaManager::init(const std::string& url) +{ + EnterCriticalSection(&this->monitorMutex); + this->mpd = this->manager->Open((char *)url.c_str()); + Debug("url : %s\n", url.c_str()); + if(this->mpd == NULL) + { + LeaveCriticalSection(&this->monitorMutex); + return false; + } + Debug("Done DL the mpd\n"); + LeaveCriticalSection(&this->monitorMutex); + return true; +} + +bool MultimediaManager::initICN(const std::string& url) +{ + EnterCriticalSection(&this->monitorMutex); + libdash::framework::input::IICNConnection* icnConn = new libdash::framework::input::ICNConnectionConsumerApi(20.0, this->beta, this->drop); + icnConn->InitForMPD(url); + int ret = 0; + char * data = (char *)malloc(4096); + int pos = url.find_last_of("/"); + if(pos == std::string::npos) + { + pos = strlen(url.c_str()); + } + else + { + pos = pos + 1; + } + + std::string downloadFile(this->downloadPath + url.substr(pos).c_str()); + FILE *fp; + fp = fopen(downloadFile.c_str(), "w"); + if(fp == NULL) + { + free(data); + delete icnConn; + LeaveCriticalSection(&this->monitorMutex); + return false; + } + ret = icnConn->Read((uint8_t*)data, 4096); + while(ret) + { + fwrite(data, sizeof(char), ret, fp); + ret = icnConn->Read((uint8_t*)data,4096); + } + fclose(fp); + this->mpd = this->manager->Open(const_cast<char*>(downloadFile.c_str()), url); + if(this->mpd == NULL) + { + remove(downloadFile.c_str()); + free(data); + delete icnConn; + LeaveCriticalSection(&this->monitorMutex); + return false; + } + remove(downloadFile.c_str()); + free(data); + delete icnConn; + LeaveCriticalSection(&this->monitorMutex); + return true; +} + +bool MultimediaManager::isStarted() +{ + return this->started; +} + +bool MultimediaManager::isStopping() +{ + return this->stopping; +} + +bool MultimediaManager::isICN() +{ + return this->icn; +} + +void MultimediaManager::start(bool icnEnabled, double icnAlpha, uint32_t nextOffset) +{ + this->icn = icnEnabled; + this->icnAlpha = icnAlpha; + if (this->started) + this->stop(); + if(icnAlpha <= 1 && icnAlpha >=0) + { + qDebug("ICN-enhanced rate estimation: alpha = %f\n",icnAlpha); + + } else { + qDebug("normal rate estimation\n"); + } + EnterCriticalSection(&this->monitorMutex); + if (this->videoAdaptationSet && this->videoRepresentation) + { + this->initVideoRendering(nextOffset); + this->videoStream->setAdaptationLogic(this->videoLogic); + this->videoLogic->setMultimediaManager(this); + this->videoStream->start(); + this->startVideoRenderingThread(); + } + this->started = true; + this->playing = true; + LeaveCriticalSection(&this->monitorMutex); +} + +void MultimediaManager::stop() +{ + if (!this->started) + return; + this->stopping = true; + EnterCriticalSection(&this->monitorMutex); + this->stopVideo(); + this->stopping = false; + this->started = false; + LeaveCriticalSection(&this->monitorMutex); + Debug("VIDEO STOPPED\n"); + this->period = this->mpd->GetPeriods().at(0); + this->videoAdaptationSet = this->period->GetAdaptationSets().at(0); + this->videoRepresentation = this->videoAdaptationSet->GetRepresentation().at(0); + +} + +void MultimediaManager::stopVideo() +{ + if(this->started && this->videoStream) + { + this->videoStream->stop(); + this->stopVideoRenderingThread(); + delete this->videoStream; + delete this->videoLogic; + this->videoStream = NULL; + this->videoLogic = NULL; + } +} + +void MultimediaManager::stopAudio() +{ + if (this->started && this->audioStream) + { + //TODO add audio support + } +} + +bool MultimediaManager::setVideoQuality(IPeriod* period, IAdaptationSet *adaptationSet, IRepresentation *representation) +{ + EnterCriticalSection(&this->monitorMutex); + + this->period = period; + this->videoAdaptationSet = adaptationSet; + this->videoRepresentation = representation; + if (this->videoStream) + this->videoStream->setRepresentation(this->period, this->videoAdaptationSet, this->videoRepresentation); + + LeaveCriticalSection(&this->monitorMutex); + return true; +} + +bool MultimediaManager::setAudioQuality(IPeriod* period, IAdaptationSet *adaptationSet, IRepresentation *representation) +{ + EnterCriticalSection(&this->monitorMutex); + + this->period = period; + this->audioAdaptationSet = adaptationSet; + this->audioRepresentation = representation; + if (this->audioStream) + this->audioStream->setRepresentation(this->period, this->audioAdaptationSet, this->audioRepresentation); + LeaveCriticalSection(&this->monitorMutex); + return true; +} + +bool MultimediaManager::isUserDependent() +{ + if(this->videoLogic) + return this->videoLogic->isUserDependent(); + else + return true; +} + +bool MultimediaManager::setVideoAdaptationLogic(libdash::framework::adaptation::LogicType type, struct libdash::framework::adaptation::AdaptationParameters *params) +{ + if(this->videoAdaptationSet) + { + if(this->videoLogic) + delete(this->videoLogic); + this->videoLogic = AdaptationLogicFactory::create(type, this->mpd, this->period, this->videoAdaptationSet, 1, params); + this->logicName = LogicType_string[type]; + } + else + { + this->videoLogic = NULL; + return true; + } + if(this->videoLogic) + return true; + else + return false; +} + +void MultimediaManager::shouldAbort(bool isVideo) +{ + if(isVideo) + { + this->videoStream->shouldAbort(); + return; + } + else + { + this->audioStream->shouldAbort(); + } +} + +void MultimediaManager::setTargetDownloadingTime(bool isVideo, double target) +{ + if(isVideo) + this->videoStream->setTargetDownloadingTime(target); + else + this->audioStream->setTargetDownloadingTime(target); +} + +bool MultimediaManager::setAudioAdaptationLogic(libdash::framework::adaptation::LogicType type, struct libdash::framework::adaptation::AdaptationParameters *params) +{ + if(this->audioAdaptationSet) + { + this->audioLogic = AdaptationLogicFactory::create(type, this->mpd, this->period, this->audioAdaptationSet, 0, params); + this->logicName = LogicType_string[type]; + } + else + { + this->audioLogic = NULL; + return true; + } + if(this->audioLogic) + return true; + else + return false; +} + +void MultimediaManager::attachManagerObserver(IMultimediaManagerObserver *observer) +{ + this->managerObservers.push_back(observer); +} + +void MultimediaManager::notifyVideoBufferObservers(uint32_t fillstateInPercent) +{ + for (size_t i = 0; i < this->managerObservers.size(); i++) + this->managerObservers.at(i)->onVideoBufferStateChanged(fillstateInPercent); +} + +void MultimediaManager::notifyVideoSegmentBufferObservers(uint32_t fillstateInPercent) +{ + for (size_t i = 0; i < this->managerObservers.size(); i++) + this->managerObservers.at(i)->onVideoSegmentBufferStateChanged(fillstateInPercent); +} + +void MultimediaManager::notifyAudioSegmentBufferObservers(uint32_t fillstateInPercent) +{ + for (size_t i = 0; i < this->managerObservers.size(); i++) + this->managerObservers.at(i)->onAudioSegmentBufferStateChanged(fillstateInPercent); +} + +void MultimediaManager::notifyAudioBufferObservers(uint32_t fillstateInPercent) +{ + for (size_t i = 0; i < this->managerObservers.size(); i++) + this->managerObservers.at(i)->onAudioBufferStateChanged(fillstateInPercent); +} + +void MultimediaManager::initVideoRendering(uint32_t offset) +{ + this->videoStream = new MultimediaStream(viper::managers::VIDEO, this->mpd, this->segmentBufferSize, this->isICN(), this->icnAlpha, this->noDecoding, this->beta, this->drop); + this->videoStream->attachStreamObserver(this); + this->videoStream->setRepresentation(this->period, this->videoAdaptationSet, this->videoRepresentation); + this->videoStream->setPosition(offset); +} + +void MultimediaManager::initAudioPlayback(uint32_t offset) +{ + this->audioStream = new MultimediaStream(viper::managers::AUDIO, this->mpd, this->segmentBufferSize, this->isICN(), this->icnAlpha, this->noDecoding, this->beta, this->drop); + this->audioStream->attachStreamObserver(this); + this->audioStream->setRepresentation(this->period, this->audioAdaptationSet, this->audioRepresentation); + this->audioStream->setPosition(offset); +} + +void MultimediaManager::setLooping(bool looping) +{ + if(this->videoStream) + { + this->videoStream->setLooping(looping); + } + if(this->audioStream) + { + this->audioStream->setLooping(looping); + } +} + +void MultimediaManager::onSegmentDownloaded () +{ + this->segmentsDownloaded++; +} + +void MultimediaManager::onSegmentBufferStateChanged(StreamType type, uint32_t fillstateInPercent, int maxC) +{ + switch (type) + { + case AUDIO: + this->notifyAudioSegmentBufferObservers(fillstateInPercent); + break; + case VIDEO: + this->notifyVideoSegmentBufferObservers(fillstateInPercent); + break; + default: + break; + } +} + +void MultimediaManager::onVideoBufferStateChanged(uint32_t fillstateInPercent) +{ + this->notifyVideoBufferObservers(fillstateInPercent); +} + +void MultimediaManager::onAudioBufferStateChanged(uint32_t fillstateInPercent) +{ + this->notifyAudioBufferObservers(fillstateInPercent); +} + +void MultimediaManager::setFrameRate(double framerate) +{ + this->frameRate = framerate; +} + +void MultimediaManager::setEOS(bool value) +{ + this->eos = value; + if(value) //ie: End of Stream so the rendering thread(s) will finish + { + this->stopping = true; + if(this->videoRendererHandle != NULL) + { + this->stopVideoRenderingThread(); + this->videoRendererHandle = NULL; + } + if(this->audioRendererHandle != NULL) + { + this->stopAudioRenderingThread(); + this->audioRendererHandle = NULL; + } + this->stopping = false; + for(size_t i = 0; i < this->managerObservers.size(); i++) + this->managerObservers.at(i)->onEOS(); + } +} + +bool MultimediaManager::startVideoRenderingThread() +{ + this->isVideoRendering = true; + if(!noDecoding) + this->videoRendererHandle = createThreadPortable (pushVideo, this); + else + this->videoRendererHandle = createThreadPortable (pushVideoNoOut, this); + + if(this->videoRendererHandle == NULL) + return false; + + return true; +} + +void MultimediaManager::stopVideoRenderingThread() +{ + this->isVideoRendering = false; + if (this->videoRendererHandle != NULL) + { + JoinThread(this->videoRendererHandle); + destroyThreadPortable(this->videoRendererHandle); + } +} + +bool MultimediaManager::startAudioRenderingThread() +{ + this->isAudioRendering = true; + if(this->audioRendererHandle == NULL) + return false; + return true; +} + +void MultimediaManager::stopAudioRenderingThread() +{ + this->isAudioRendering = false; + if (this->audioRendererHandle != NULL) + { + JoinThread(this->audioRendererHandle); + destroyThreadPortable(this->audioRendererHandle); + } +} + +bool MultimediaManager::isPlaying() +{ + return this->playing; +} + +void MultimediaManager::onPausePressed() +{ + EnterCriticalSection(&this->monitor_playing_video_mutex); + EnterCriticalSection(&this->monitor_playing_audio_mutex); + this->playing = !this->playing; + WakeAllConditionVariable(&this->playingVideoStatusChanged); + WakeAllConditionVariable(&this->playingAudioStatusChanged); + LeaveCriticalSection(&this->monitor_playing_video_mutex); + LeaveCriticalSection(&this->monitor_playing_audio_mutex); +} + +void* MultimediaManager::pushVideoNoOut(void *data) +{ + MultimediaManager *manager = (MultimediaManager*) data; + manager->lastPointInTime = std::chrono::system_clock::now(); + manager->bufferingLimit = manager->lastPointInTime; + libdash::framework::input::MediaObject *segment = manager->videoStream->getSegment(); + using duration_in_milliSeconds = std::chrono::duration<long int, std::ratio<1,1000>>; + std::chrono::time_point<std::chrono::system_clock> timeOfInsertion; + std::chrono::time_point<std::chrono::system_clock> startTime; + long int actualPosition; + + while(manager->isVideoRendering) + { + if (segment) + { + timeOfInsertion = std::chrono::system_clock::now(); + actualPosition = std::chrono::duration_cast<duration_in_milliSeconds>(manager->bufferingLimit - timeOfInsertion).count(); + if(actualPosition < 0) + { + Debug("MANAGER:\tRebuffered %d ms\n", actualPosition *(-1)); + manager->lastPointInTime = timeOfInsertion; + //TODO Replace the 2 by a variable with segmentDuration + manager->bufferingLimit = manager->lastPointInTime + std::chrono::seconds(2); + } + else + { + //TODO Replace the 2 by a variable with segmentDuration + Debug("MANAGER: INSERT TO BUFFER old_fillness: %f, new_fillness: %f\n", (double)((double)actualPosition/1000.0) / (double) this->segmentBufferSize, (double)((double)(actualPosition + 2000)/1000.0) / (double) manager->segmentBufferSize); + manager->bufferingLimit = manager->bufferingLimit + std::chrono::seconds(2); + manager->lastPointInTime = timeOfInsertion; + } + delete segment; + } + else + { + //noDecoding here means noGUI + if(manager->noDecoding) + manager->setEOS(true); + } + segment = manager->videoStream->getSegment(); + } + return NULL; + +} + +void MultimediaManager::notifyStatistics(int segNum, uint32_t bitrate, int fps, uint32_t quality) +{ + for(size_t i = 0; i < this->managerObservers.size(); i++) + { + this->managerObservers.at(i)->notifyStatistics(segNum, bitrate, fps, quality); + } +} + +void MultimediaManager::notifyQualityDownloading(uint32_t quality) +{ + for(size_t i = 0; i < this->managerObservers.size(); i++) + { + this->managerObservers.at(i)->notifyQualityDownloading(quality); + } +} + +void MultimediaManager::notifyBufferChange() +{ + if(this->videoStream) + { + this->videoStream->notifyBufferChange(this->getUBufferLevel(), this->segmentBufferSize); + } + if(this->audioStream) + { + this->audioStream->notifyBufferChange(this->getUBufferLevel(), this->segmentBufferSize); + } +} + +int MultimediaManager::getBufferLevel() +{ + return (int)this->getUBufferLevel(); +} + +uint32_t MultimediaManager::getUBufferLevel() +{ + int mBufferLevel = 0; + int segmentDurationInMs = 2000; + + if(noDecoding) + { + std::chrono::time_point<std::chrono::system_clock> timeNow = std::chrono::system_clock::now(); + using duration_in_milliSeconds = std::chrono::duration<long int, std::ratio<1,1000>>; + long int actualPos = std::chrono::duration_cast<duration_in_milliSeconds>(this->bufferingLimit - timeNow).count(); + int res = ((double)actualPos) / (double (this->segmentBufferSize * segmentDurationInMs)) * 100; + return res >= 0 ? res > 100 ? 100 : (uint32_t) res : 0; + } + else + { + mBufferLevel = this->viperGui->getBufferDuration(); + int res = ((int)mBufferLevel)/((double) (this->segmentBufferSize * this->viperGui->getSegmentDuration())) * 100; + return res >= 0 ? res > 100 ? 100 : (uint32_t) res : 0; + + } +} + +bool MultimediaManager::canPush() +{ + int segmentDurationInMs = 2000; + while(this->getUBufferLevel() >= 100 && !this->stopping) + { + sleep(segmentDurationInMs / 1000); + } + return true; +} + +void* MultimediaManager::pushVideo(void *data) +{ + MultimediaManager *manager = (MultimediaManager*) data; + libdash::framework::input::MediaObject *segment = manager->videoStream->getSegment(); + long int segmentDurationInMs = 2000; + while(manager->isVideoRendering) + { + if (segment) + { + manager->notifyBufferChange(); + manager->viperGui->writeData(segment); + delete segment; + } + segment = manager->videoStream->getSegment(); + } + return NULL; +} + +void MultimediaManager::setOffset(int offset) +{ + this->offset = offset; +} + +void MultimediaManager::setBeta(float beta) +{ + this->beta = beta; +} + +void MultimediaManager::setDrop(float drop) +{ + this->drop = drop; +} diff --git a/Managers/MultimediaManager.h b/Managers/MultimediaManager.h new file mode 100644 index 00000000..b4187486 --- /dev/null +++ b/Managers/MultimediaManager.h @@ -0,0 +1,140 @@ +/* + * MultimediaManager.h + ***************************************************************************** + * Copyright (C) 2012, bitmovin Softwareentwicklung OG, All Rights Reserved + * + * Email: libdash-dev@vicky.bitmovin.net + * + * This source code and its use and distribution, is subject to the terms + * and conditions of the applicable license agreement. + *****************************************************************************/ + +#ifndef VIPER_MANAGERS_MULTIMEDIAMANAGER_H_ +#define VIPER_MANAGERS_MULTIMEDIAMANAGER_H_ + +#include "IMPD.h" +#include "MultimediaStream.h" +#include "IMultimediaManagerBase.h" +#include "IMultimediaManagerObserver.h" +#include "../Adaptation/IAdaptationLogic.h" +#include "../Adaptation/AdaptationLogicFactory.h" +#include "../Portable/MultiThreading.h" +#include <QtMultimedia/qaudiooutput.h> +#include <cstring> +#include <QtAV/QtAV.h> +#include "Common/ViperBuffer.h" +#include "UI/ViperGui.h" + +namespace viper +{ +namespace managers +{ +class MultimediaManager : public IStreamObserver, public IMultimediaManagerBase +{ +public: + MultimediaManager(ViperGui *viperGui, int segmentBufferSize, std::string downloadPath, bool noDecoding = false); + virtual ~MultimediaManager(); + + bool init (const std::string& url); + bool initICN (const std::string& url); + void start (bool icnEnabled, double icnAlpha, uint32_t nextOffset); + void stop (); + dash::mpd::IMPD* getMPD (); + + bool setVideoQuality (dash::mpd::IPeriod* period, dash::mpd::IAdaptationSet *adaptationSet, dash::mpd::IRepresentation *representation); + bool setAudioQuality (dash::mpd::IPeriod* period, dash::mpd::IAdaptationSet *adaptationSet, dash::mpd::IRepresentation *representation); + + bool setVideoAdaptationLogic (libdash::framework::adaptation::LogicType type, struct libdash::framework::adaptation::AdaptationParameters *params); + bool setAudioAdaptationLogic (libdash::framework::adaptation::LogicType type, struct libdash::framework::adaptation::AdaptationParameters *params); + + void attachManagerObserver (IMultimediaManagerObserver *observer); + + void setFrameRate (double frameRate); + + /* IStreamObserver */ + void onSegmentDownloaded (); + void onSegmentBufferStateChanged (StreamType type, uint32_t fillstateInPercent, int maxC); + void onVideoBufferStateChanged (uint32_t fillstateInPercent); + void onAudioBufferStateChanged (uint32_t fillstateInPercent); + bool isUserDependent (); + bool isStarted (); + bool isStopping (); + bool isICN (); + void setEOS (bool value); + void shouldAbort (bool isVideo); + void setTargetDownloadingTime (bool isVid, double time); + bool isPlaying (); + void onPausePressed (); + void notifyStatistics (int segNum, uint32_t bitrate, int fps, uint32_t quality); + void notifyQualityDownloading (uint32_t quality); + uint32_t getUBufferLevel (); + int getBufferLevel (); + void setLooping (bool looping); + void setOffset(int offset); + void setBeta(float beta); + void setDrop(float drop); + bool canPush (); + CRITICAL_SECTION monitorBufferMutex; + + int offset; + std::chrono::time_point<std::chrono::system_clock> lastPointInTime; + std::chrono::time_point<std::chrono::system_clock> bufferingLimit; + +private: + float beta; + float drop; + std::string downloadPath; + int segmentBufferSize; + ViperGui *viperGui; + dash::IDASHManager *manager; + dash::mpd::IMPD *mpd; + dash::mpd::IPeriod *period; + dash::mpd::IAdaptationSet *videoAdaptationSet; + dash::mpd::IRepresentation *videoRepresentation; + libdash::framework::adaptation::IAdaptationLogic *videoLogic; + MultimediaStream *videoStream; + dash::mpd::IAdaptationSet *audioAdaptationSet; + dash::mpd::IRepresentation *audioRepresentation; + libdash::framework::adaptation::IAdaptationLogic *audioLogic; + MultimediaStream *audioStream; + std::vector<IMultimediaManagerObserver *> managerObservers; + bool started; + bool stopping; + bool icn; + double icnAlpha; + uint64_t framesDisplayed; + uint64_t segmentsDownloaded; + CRITICAL_SECTION monitorMutex; + double frameRate; + THREAD_HANDLE videoRendererHandle; + THREAD_HANDLE audioRendererHandle; + bool isVideoRendering; + bool isAudioRendering; + bool eos; + bool playing; + mutable CRITICAL_SECTION monitor_playing_video_mutex; + mutable CONDITION_VARIABLE playingVideoStatusChanged; + mutable CRITICAL_SECTION monitor_playing_audio_mutex; + mutable CONDITION_VARIABLE playingAudioStatusChanged; + const char *logicName; + bool noDecoding; + void notifyBufferChange (); + bool startVideoRenderingThread (); + void stopVideoRenderingThread (); + static void* pushVideo (void *data); + static void* pushVideoNoOut (void *data); + bool startAudioRenderingThread (); + void stopAudioRenderingThread (); + void initVideoRendering (uint32_t offset); + void initAudioPlayback (uint32_t offset); + void stopVideo (); + void stopAudio (); + void notifyVideoBufferObservers (uint32_t fillstateInPercent); + void notifyVideoSegmentBufferObservers (uint32_t fillstateInPercent); + void notifyAudioBufferObservers (uint32_t fillstateInPercent); + void notifyAudioSegmentBufferObservers (uint32_t fillstateInPercent); +}; +} +} + +#endif /* VIPER_MANAGERS_MULTIMEDIAMANAGER_H_ */ diff --git a/Managers/MultimediaStream.cpp b/Managers/MultimediaStream.cpp new file mode 100644 index 00000000..ed0d967c --- /dev/null +++ b/Managers/MultimediaStream.cpp @@ -0,0 +1,208 @@ +/* + * MultimediaStream.cpp + ***************************************************************************** + * Copyright (C) 2012, bitmovin Softwareentwicklung OG, All Rights Reserved + * + * Email: libdash-dev@vicky.bitmovin.net + * + * This source code and its use and distribution, is subject to the terms + * and conditions of the applicable license agreement. + *****************************************************************************/ + +#include "MultimediaStream.h" + +using namespace viper::managers; +using namespace libdash::framework::adaptation; +using namespace libdash::framework::input; +using namespace libdash::framework::buffer; +using namespace dash::mpd; + +MultimediaStream::MultimediaStream(StreamType type, IMPD *mpd, uint32_t bufferSize, bool icnEnabled, double icnAlpha, bool nodecoding, float beta, float drop) : + type (type), + segmentBufferSize (bufferSize), + dashManager (NULL), + mpd (mpd), + icn (icnEnabled), + icnAlpha (icnAlpha), + noDecoding (nodecoding), + beta (beta), + drop (drop) +{ + this->init(); +} +MultimediaStream::~MultimediaStream () +{ + this->stop(); + delete this->dashManager; +} + +bool MultimediaStream::isICN() +{ + return this->icn; +} + +void MultimediaStream::shouldAbort() +{ + this->dashManager->shouldAbort(); +} + +uint32_t MultimediaStream::getPosition() +{ + return this->dashManager->getPosition(); +} + +void MultimediaStream::setLooping(bool looping) +{ + this->dashManager->setLooping(looping); +} + +void MultimediaStream::setPosition(uint32_t segmentNumber) +{ + this->dashManager->setPosition(segmentNumber); +} + +void MultimediaStream::setPositionInMsec(uint32_t milliSecs) +{ + this->dashManager->setPositionInMsec(milliSecs); +} + +void MultimediaStream::init() +{ + this->dashManager = new DASHManager(this->type, this->segmentBufferSize, this, this->mpd, this->isICN(), this->icnAlpha, this->noDecoding, this->beta, this->drop); +} + +bool MultimediaStream::start() +{ + if(!this->startDownload()) + return false; + + return true; +} + +bool MultimediaStream::startDownload() +{ + dashManager->setAdaptationLogic(this->logic); + if(!dashManager->start()) + return false; + + return true; +} + +void MultimediaStream::stop() +{ + this->stopDownload(); +} + +void MultimediaStream::stopDownload() +{ + this->dashManager->stop(); +} + +void MultimediaStream::clear() +{ + this->dashManager->clear(); +} + +void MultimediaStream::addFrame(QImage *frame) +{ +} + +QImage* MultimediaStream::getFrame() +{ + return NULL; +} + +void MultimediaStream::attachStreamObserver(IStreamObserver *observer) +{ + this->observers.push_back(observer); +} + +void MultimediaStream::setRepresentation(IPeriod *period, IAdaptationSet *adaptationSet, IRepresentation *representation) +{ + this->dashManager->setRepresentation(period, adaptationSet, representation); +} + +void MultimediaStream::enqueueRepresentation(IPeriod *period, IAdaptationSet *adaptationSet, IRepresentation *representation) +{ + this->dashManager->enqueueRepresentation(period, adaptationSet, representation); +} + +void MultimediaStream::setAdaptationLogic(libdash::framework::adaptation::IAdaptationLogic *logic) +{ + this->logic = logic; +} + +void MultimediaStream::onSegmentBufferStateChanged(uint32_t fillstateInPercent, int maxC) +{ + for (size_t i = 0; i < observers.size(); i++) + this->observers.at(i)->onSegmentBufferStateChanged(this->type, fillstateInPercent, maxC); +} + +void MultimediaStream::onBufferStateChanged(BufferType type, uint32_t fillstateInPercent, int maxC) +{ + switch(type) + { + case libdash::framework::buffer::AUDIO: + for (size_t i = 0; i < observers.size(); i++) + this->observers.at(i)->onAudioBufferStateChanged(fillstateInPercent); + break; + case libdash::framework::buffer::VIDEO: + for (size_t i = 0; i < observers.size(); i++) + this->observers.at(i)->onVideoBufferStateChanged(fillstateInPercent); + default: + break; + } +} + +void MultimediaStream::setEOS(bool value) +{ + for(size_t i = 0; i < observers.size(); i++) + this->observers.at(i)->setEOS(value); +} + +void MultimediaStream::setTargetDownloadingTime(double target) +{ + this->dashManager->setTargetDownloadingTime(target); +} + +void MultimediaStream::notifyStatistics(int segNum, uint32_t bitrate, int fps, uint32_t quality) +{ + for(size_t i = 0; i < observers.size(); i++) + this->observers.at(i)->notifyStatistics(segNum, bitrate, fps, quality); +} + +void MultimediaStream::notifyQualityDownloading(uint32_t quality) +{ + for(size_t i = 0; i < observers.size(); i++) + this->observers.at(i)->notifyQualityDownloading(quality); +} + +int MultimediaStream::getBufferLevel() +{ + int bufferFill = 0; + for(size_t i=0; i < observers.size(); i++) + { + bufferFill = this->observers.at(i)->getBufferLevel(); + } + return bufferFill; +} +bool MultimediaStream::canPush() +{ + bool flag = false; + for(size_t i=0; i < observers.size(); i++) + { + flag = flag || this->observers.at(i)->canPush(); + } + return flag; +} + + +libdash::framework::input::MediaObject* MultimediaStream::getSegment() +{ + return this->dashManager->getSegment(); +} + +void MultimediaStream::notifyBufferChange(uint32_t bufferfill, int maxC) +{ + this->dashManager->onBufferStateChanged(libdash::framework::buffer::VIDEO, bufferfill, maxC); +} diff --git a/Managers/MultimediaStream.h b/Managers/MultimediaStream.h new file mode 100644 index 00000000..6918f639 --- /dev/null +++ b/Managers/MultimediaStream.h @@ -0,0 +1,89 @@ +/* + * MultimediaStream.h + ***************************************************************************** + * Copyright (C) 2012, bitmovin Softwareentwicklung OG, All Rights Reserved + * + * Email: libdash-dev@vicky.bitmovin.net + * + * This source code and its use and distribution, is subject to the terms + * and conditions of the applicable license agreement. + *****************************************************************************/ + +#ifndef VIPER_MANAGERS_MULTIMEDIASTREAM_H_ +#define VIPER_MANAGERS_MULTIMEDIASTREAM_H_ + +#include "IMPD.h" +#include "IStreamObserver.h" +#include "../Input/DASHManager.h" +#include "../Buffer/IBufferObserver.h" +#include "../Adaptation/IAdaptationLogic.h" +#include <QtMultimedia/qaudioformat.h> +#include "../Input/IDASHManagerObserver.h" +#include "../Buffer/Buffer.h" +#include <QImage> + +namespace viper +{ +namespace managers +{ +class MultimediaStream : public libdash::framework::input::IDASHManagerObserver, public libdash::framework::buffer::IBufferObserver +{ +public: + MultimediaStream(StreamType type, dash::mpd::IMPD *mpd, uint32_t segmentBufferSize, bool icnEnabled, double icnAlpha, bool nodecoding, float beta, float drop); + virtual ~MultimediaStream(); + + bool start(); + void stop(); + void stopDownload(); + bool startDownload(); + void clear(); + uint32_t getPosition(); + void setPosition(uint32_t segmentNumber); + void setLooping(bool looping); + void setPositionInMsec(uint32_t milliSecs); + + void addFrame(QImage *frame); + QImage* getFrame(); + libdash::framework::input::MediaObject* getSegment(); + + void setEOS(bool value); + + void notifyBufferChange(uint32_t bufferfill, int maxC); + + void setRepresentation(dash::mpd::IPeriod *period, dash::mpd::IAdaptationSet *adaptationSet, dash::mpd::IRepresentation *representation); + void enqueueRepresentation(dash::mpd::IPeriod *period, dash::mpd::IAdaptationSet *adaptationSet, dash::mpd::IRepresentation *representation); + void setAdaptationLogic(libdash::framework::adaptation::IAdaptationLogic *logic); + + void attachStreamObserver(IStreamObserver *observer); + + void onSegmentBufferStateChanged(uint32_t fillstateInPercent, int maxC); + void onBufferStateChanged(libdash::framework::buffer::BufferType type, uint32_t fillstateInPercent, int maxC); + + void notifyStatistics(int segNum, uint32_t bitrate, int fps, uint32_t quality); + void notifyQualityDownloading (uint32_t quality); + bool canPush(); + int getBufferLevel(); + bool isICN(); + void shouldAbort(); + + void setTargetDownloadingTime(double); + +private: + float beta; + float drop; + std::vector<IStreamObserver *> observers; + dash::mpd::IMPD *mpd; + libdash::framework::adaptation::IAdaptationLogic *logic; + libdash::framework::input::DASHManager *dashManager; + uint32_t segmentBufferSize; + StreamType type; + bool icn; + double icnAlpha; + + bool noDecoding; + void init (); +}; +} +} + +#endif /* VIPER_MANAGERS_MULTIMEDIASTREAM_H_ */ |