summaryrefslogtreecommitdiff
path: root/hlsPlayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'hlsPlayer.cpp')
-rw-r--r--hlsPlayer.cpp165
1 files changed, 105 insertions, 60 deletions
diff --git a/hlsPlayer.cpp b/hlsPlayer.cpp
index 08cc717..3f90750 100644
--- a/hlsPlayer.cpp
+++ b/hlsPlayer.cpp
@@ -2,19 +2,22 @@
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
+#include <Poco/Exception.h>
//#include <Poco/StreamCopier.h>
#include <pcrecpp.h>
#include "Plexservice.h"
+static cMutex hlsMutex;
+
//--- cHlsSegmentLoader
cHlsSegmentLoader::cHlsSegmentLoader(std::string startm3u8)
{
+ m_newList = false;
m_bufferFilled = false;
m_lastLoadedSegment = 0;
- m_loadedSegments = 0;
m_segmentsToBuffer = 3;
m_pBuffer = new uchar[8192];
@@ -39,17 +42,16 @@ cHlsSegmentLoader::~cHlsSegmentLoader()
delete m_pRingbuffer;
}
-void cHlsSegmentLoader::Action(void)
+bool cHlsSegmentLoader::LoadM3u8(std::string uri)
{
- if( LoadStartList() ) {
- if( false == LoadIndexList() ) {
- esyslog("[plex]LoadIndexList failed!");
- }
- } else {
- esyslog("[plex]LoadStartList failed!");
- return;
- }
+ LOCK_THREAD;
+ m_startUri = Poco::URI(uri);
+ return m_newList = true;
+}
+void cHlsSegmentLoader::Action(void)
+{
+ if(!LoadLists()) return;
int estSize = EstimateSegmentSize();
m_ringBufferSize = MEGABYTE(estSize*3);
@@ -59,11 +61,39 @@ void cHlsSegmentLoader::Action(void)
m_pRingbuffer = new cRingBufferLinear(m_ringBufferSize, 2*TS_SIZE);
while(Running()) {
- DoLoad();
+ if(m_newList) {
+ hlsMutex.Lock();
+ m_bufferFilled = false;
+ m_lastLoadedSegment = 0;
+ LoadLists();
+ m_newList = false;
+ m_pRingbuffer->Clear();
+ isyslog("[plex] Ringbuffer Cleared, loading new segments");
+ hlsMutex.Unlock();
+ }
+ if (!DoLoad()) {
+ isyslog("[plex] No further segments to load");
+ StopLoader();
+ Cancel();
+ }
cCondWait::SleepMs(3);
}
}
+bool cHlsSegmentLoader::LoadLists(void)
+{
+ if( LoadStartList() ) {
+ if( false == LoadIndexList() ) {
+ esyslog("[plex]LoadIndexList failed!");
+ return false;
+ }
+ } else {
+ esyslog("[plex]LoadStartList failed!");
+ return false;
+ }
+ return true;
+}
+
bool cHlsSegmentLoader::LoadIndexList(void)
{
bool res = false;
@@ -89,8 +119,8 @@ bool cHlsSegmentLoader::LoadIndexList(void)
esyslog("[plex]%s Response Not Valid", __FUNCTION__);
return res;
}
-
- res = m_indexParser.Parse(indexFile);
+ m_indexParser = cM3u8Parser();
+ res = m_indexParser.Parse(indexFile);
if(res) {
// Segment URI is relative to index.m3u8
@@ -123,6 +153,7 @@ bool cHlsSegmentLoader::LoadStartList(void)
return res;
}
+ m_startParser = cM3u8Parser();
res = m_startParser.Parse(startFile);
if(res) {
// Get GUID
@@ -188,13 +219,17 @@ int cHlsSegmentLoader::GetSegmentSize(int segmentIndex)
if(m_indexParser.vPlaylistItems[segmentIndex].size > 0) {
return m_indexParser.vPlaylistItems[segmentIndex].size;
}
- Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_HEAD, GetSegmentUri(segmentIndex));
- AddHeader(req);
- m_pClientSession->sendRequest(req);
- Poco::Net::HTTPResponse reqResponse;
- m_pClientSession->receiveResponse(reqResponse);
-
- return m_indexParser.vPlaylistItems[segmentIndex].size = reqResponse.getContentLength();
+ try {
+ Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_HEAD, GetSegmentUri(segmentIndex));
+ AddHeader(req);
+ m_pClientSession->sendRequest(req);
+ Poco::Net::HTTPResponse reqResponse;
+ m_pClientSession->receiveResponse(reqResponse);
+ return m_indexParser.vPlaylistItems[segmentIndex].size = reqResponse.getContentLength();
+ } catch(Poco::IOException& exc) {
+ esyslog("[plex]%s %s ", __FUNCTION__, exc.displayText().c_str());
+ return INT_MAX;
+ }
}
std::string cHlsSegmentLoader::GetSegmentUri(int segmentIndex) const
@@ -222,24 +257,25 @@ bool cHlsSegmentLoader::ConnectToServer(void)
bool cHlsSegmentLoader::DoLoad(void)
{
+ LOCK_THREAD;
bool result = true;
+ if(m_lastLoadedSegment < m_indexParser.vPlaylistItems.size()) {
+ int nextSegmentSize = GetSegmentSize(m_lastLoadedSegment);
- int nextSegmentSize = GetSegmentSize(m_lastLoadedSegment + 1);
- while(m_pRingbuffer->Free() > nextSegmentSize) {
+ if(m_pRingbuffer->Free() > nextSegmentSize) {
- if(m_lastLoadedSegment + 1 < m_indexParser.vPlaylistItems.size()) {
- std::string segmentUri = GetSegmentUri(++m_lastLoadedSegment);
- result = LoadSegment(segmentUri);
- m_loadedSegments++;
- } else {
- // out of segments
- StopLoader();
- result = false;
+ if(nextSegmentSize <= TS_SIZE) { // skip empty segments
+ nextSegmentSize = GetSegmentSize(m_lastLoadedSegment++);
+ } else {
+ std::string segmentUri = GetSegmentUri(m_lastLoadedSegment++);
+ result = LoadSegment(segmentUri);
+ }
}
- m_bufferFilled = m_lastLoadedSegment >= m_segmentsToBuffer;
- nextSegmentSize = GetSegmentSize(m_lastLoadedSegment + 1);
+ m_bufferFilled = result;
+ } else {
+ result = false;
}
- return m_bufferFilled = result;
+ return result;
}
bool cHlsSegmentLoader::BufferFilled(void)
@@ -250,15 +286,20 @@ bool cHlsSegmentLoader::BufferFilled(void)
bool cHlsSegmentLoader::StopLoader(void)
{
dsyslog("[plex]%s", __FUNCTION__);
- std::string stopUri = "/video/:/transcode/universal/stop?session=" + m_sessionCookie;
- Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_GET, stopUri);
- m_pClientSession->sendRequest(req);
- Poco::Net::HTTPResponse reqResponse;
- m_pClientSession->receiveResponse(reqResponse);
-
- Cancel();
-
- return reqResponse.getStatus() == 200;
+ try {
+ std::string stopUri = "/video/:/transcode/universal/stop?session=" + m_sessionCookie;
+ Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_GET, stopUri);
+ m_pClientSession->sendRequest(req);
+ Poco::Net::HTTPResponse reqResponse;
+ m_pClientSession->receiveResponse(reqResponse);
+
+ Cancel();
+
+ return reqResponse.getStatus() == 200;
+ } catch(Poco::Exception& exc) {
+ esyslog("[plex]%s %s ", __FUNCTION__, exc.displayText().c_str());
+ return false;
+ }
}
void cHlsSegmentLoader::AddHeader(Poco::Net::HTTPRequest& req)
{
@@ -282,11 +323,13 @@ cHlsPlayer::cHlsPlayer(std::string startm3u8, plexclient::Video* Video)
m_pVideo = Video;
m_timeOffset = 0;
m_doJump = false;
+ m_isBuffering = false;
}
cHlsPlayer::~cHlsPlayer()
{
delete m_pSegmentLoader;
+ m_pSegmentLoader = NULL;
}
@@ -296,18 +339,13 @@ void cHlsPlayer::Action(void)
m_pSegmentLoader->Start();
while (Running()) {
- if(m_doJump && m_pSegmentLoader) {
+ if(m_doJump && m_pSegmentLoader && m_pSegmentLoader->BufferFilled()) {
+ LOCK_THREAD;
+
DeviceFreeze();
- int currentOffset = DeviceGetSTC() / (100 * 1000);
- m_pSegmentLoader->StopLoader();
- delete m_pSegmentLoader;
-
- std::string uri = plexclient::Plexservice::GetUniversalTranscodeUrl(m_pVideo, m_jumpOffset);
- m_timeOffset = m_jumpOffset;
m_doJump = false;
-
- m_pSegmentLoader = new cHlsSegmentLoader(uri);
- m_pSegmentLoader->Start();
+ std::string uri = plexclient::Plexservice::GetUniversalTranscodeUrl(m_pVideo, m_jumpOffset);
+ m_pSegmentLoader->LoadM3u8(uri);
DeviceClear();
DevicePlay();
} else if(m_pSegmentLoader && m_pSegmentLoader->BufferFilled()) {
@@ -323,7 +361,7 @@ bool cHlsPlayer::DoPlay(void)
{
cPoller Poller;
if(DevicePoll(Poller, 10)) {
- cMutexLock lock(&s_mutex);
+ hlsMutex.Lock();
// Handle running out of packets. Buffer-> Play-> Pause-> Buffer-> Play
@@ -339,6 +377,7 @@ bool cHlsPlayer::DoPlay(void)
break;
}
}
+ hlsMutex.Unlock();
}
return true;
}
@@ -355,7 +394,7 @@ void cHlsPlayer::Activate(bool On)
bool cHlsPlayer::GetIndex(int& Current, int& Total, bool SnapToIFrame)
{
long stc = DeviceGetSTC();
- Total = m_pVideo->m_pMedia->m_lDuration / 1000 * FramesPerSecond(); // milliseconds
+ Total = m_pVideo->m_pMedia->m_lDuration / 1000 * 25;//FramesPerSecond(); // milliseconds
Current = stc / (100 * 1000) * FramesPerSecond(); // 100ns per Tick
Current += m_timeOffset; // apply offset
return true;
@@ -371,12 +410,11 @@ bool cHlsPlayer::GetReplayMode(bool& Play, bool& Forward, int& Speed)
void cHlsPlayer::Pause(void)
{
+ LOCK_THREAD;
dsyslog("[plex]%s", __FUNCTION__);
if (playMode == pmPause) {
Play();
} else {
- cMutexLock lock(&s_mutex);
-
DeviceFreeze();
playMode = pmPause;
}
@@ -384,10 +422,9 @@ void cHlsPlayer::Pause(void)
void cHlsPlayer::Play(void)
{
+ LOCK_THREAD;
dsyslog("[plex]%s", __FUNCTION__);
if (playMode != pmPlay) {
- cMutexLock lock(&s_mutex);
-
DevicePlay();
playMode = pmPlay;
}
@@ -400,6 +437,8 @@ bool cHlsPlayer::Active(void)
void cHlsPlayer::Stop(void)
{
+ LOCK_THREAD;
+ dsyslog("[plex]%s", __FUNCTION__);
if (m_pSegmentLoader)
m_pSegmentLoader->StopLoader();
Cancel(0);
@@ -413,12 +452,18 @@ double cHlsPlayer::FramesPerSecond(void)
void cHlsPlayer::JumpRelative(int seconds)
{
long stc = DeviceGetSTC();
- int current = stc / (100 * 1000);
- JumpTo(current + seconds);
+ if(stc > 0) {
+ int current = stc / (100 * 1000);
+ JumpTo(current + seconds);
+ } else {
+ JumpTo(m_jumpOffset + seconds);
+ }
}
void cHlsPlayer::JumpTo(int seconds)
{
+ LOCK_THREAD;
+ dsyslog("[plex]%s %d", __FUNCTION__, seconds);
if(seconds < 0) seconds = 0;
m_jumpOffset = seconds;
m_doJump = true;