summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorFrank Schmirler <vdr@schmirler.de>2013-09-26 09:31:35 +0200
committerFrank Schmirler <vdr@schmirler.de>2013-09-27 17:33:18 +0200
commitc92de13d0666bcad050989c0d81d67878876ac52 (patch)
tree792f1460191367819b707b5faf6a8bafe7220cd0 /server
parentd7652d89ca79e30c6296ec71882b2de6b7728c63 (diff)
downloadvdr-plugin-streamdev-c92de13d0666bcad050989c0d81d67878876ac52.tar.gz
vdr-plugin-streamdev-c92de13d0666bcad050989c0d81d67878876ac52.tar.bz2
Select start position for replaying a recording by parameter pos=
Based on offset_5.diff from hivdr@vdrportal with the following modifications: - indenting - replaced isyslog with Dprintf - left out HTTP header "Server:" for the moment
Diffstat (limited to 'server')
-rw-r--r--server/connectionHTTP.c47
-rw-r--r--server/connectionHTTP.h2
-rw-r--r--server/recplayer.c45
-rw-r--r--server/recplayer.h3
-rw-r--r--server/recstreamer.c66
-rw-r--r--server/recstreamer.h5
6 files changed, 163 insertions, 5 deletions
diff --git a/server/connectionHTTP.c b/server/connectionHTTP.c
index c3b3f90..73029d7 100644
--- a/server/connectionHTTP.c
+++ b/server/connectionHTTP.c
@@ -199,19 +199,51 @@ bool cConnectionHTTP::ProcessRequest(void)
}
else if (m_Recording != NULL) {
Dprintf("GET recording\n");
- cStreamdevRecStreamer* recStreamer = new cStreamdevRecStreamer(m_Recording, this);
+ cStreamdevRecStreamer* recStreamer = new cStreamdevRecStreamer(m_Recording, this, m_ReplayPos);
m_Streamer = recStreamer;
int64_t from, to;
uint64_t total = recStreamer->GetLength();
if (ParseRange(from, to)) {
+ Dprintf("parsed from-to: %lld - %lld\n", (long long)from, (long long)to);
int64_t length = recStreamer->SetRange(from, to);
+ int64_t fromByPos = recStreamer->GetFromByPos();
+ if (fromByPos > 0) {
+ if (from == 0) {
+ from = fromByPos;
+ to = total - 1;
+ Dprintf("from byte: %lld\n", (long long)from);
+ }
+ else if (m_ReplayPos.find("full_") != 0) {
+ from += fromByPos;
+ to += fromByPos;
+ }
+ Dprintf("part of recording: %lld-%lld/%lld\n", (long long)from, (long long)to, (long long)total);
+ length = recStreamer->SetRange(from, to);
+ Dprintf("part of recording: %lld-%lld/%lld, len %lld\n", (long long)from, (long long)to, (long long)total, (long long)length);
+ }
+ if (m_ReplayPos.find("full_") != 0 && fromByPos > 0) {
+ from -= fromByPos;
+ to -= fromByPos;
+ total -= fromByPos;
+ }
+ Dprintf("range response: %lld-%lld/%lld, len %lld\n", (long long)from, (long long)to, (long long)total, (long long)length);
if (length < 0L)
return HttpResponse(416, true, "video/mpeg", "Accept-Ranges: bytes\r\nContent-Range: bytes */%llu", (unsigned long long) total);
else
return HttpResponse(206, false, "video/mpeg", "Accept-Ranges: bytes\r\nContent-Range: bytes %lld-%lld/%llu\r\nContent-Length: %lld", (long long) from, (long long) to, (unsigned long long) total, (long long) length);
}
- else
+ else {
+ int64_t fromByPos = recStreamer->GetFromByPos();
+ if (fromByPos > 0) {
+ from = fromByPos;
+ to = total - 1;
+ Dprintf("from byte: %lld\n", (long long)from);
+ int64_t length = recStreamer->SetRange(from, to);
+ Dprintf("part of recording: %lld-%lld/%lld, len %lld\n", (long long)from, (long long)to, (long long)total, (long long)length);
+ }
+
return HttpResponse(200, false, "video/mpeg", "Accept-Ranges: bytes");
+ }
}
else {
return HttpResponse(404, true);
@@ -240,7 +272,7 @@ bool cConnectionHTTP::ProcessRequest(void)
}
else if (m_Recording != NULL) {
Dprintf("HEAD recording\n");
- cStreamdevRecStreamer *recStreamer = new cStreamdevRecStreamer(m_Recording, this);
+ cStreamdevRecStreamer *recStreamer = new cStreamdevRecStreamer(m_Recording, this, m_ReplayPos);
m_Streamer = recStreamer;
int64_t from, to;
uint64_t total = recStreamer->GetLength();
@@ -330,6 +362,7 @@ bool cConnectionHTTP::ParseRange(int64_t &From, int64_t &To) const
From = To = 0L;
tStrStrMap::const_iterator it = Headers().find(RANGE);
if (it != Headers().end()) {
+ Dprintf("%s: %s\n", it->first.c_str(), it->second.c_str());
size_t b = it->second.find("bytes=");
if (b != std::string::npos) {
char* e = NULL;
@@ -521,6 +554,14 @@ bool cConnectionHTTP::ProcessURI(const std::string& PathInfo)
return true;
} else if ((m_Recording = RecordingFromString(filespec.c_str(), fileext.c_str())) != NULL) {
Dprintf("Recording %s found\n", m_Recording->Name());
+ tStrStrMap::iterator it = m_Params.begin();
+ while (it != m_Params.end()) {
+ if (it->first == "pos") {
+ m_ReplayPos = it->second;
+ Dprintf("pos: %s\n", m_ReplayPos.c_str());
+ break;
+ }
+ }
return true;
} else if ((m_Channel = ChannelFromString(filespec.c_str(), &m_Apid[0], &m_Dpid[0])) != NULL) {
Dprintf("Channel found. Apid/Dpid is %d/%d\n", m_Apid[0], m_Dpid[0]);
diff --git a/server/connectionHTTP.h b/server/connectionHTTP.h
index e946242..3161cfc 100644
--- a/server/connectionHTTP.h
+++ b/server/connectionHTTP.h
@@ -35,6 +35,7 @@ private:
int m_Dpid[2];
// job: replay
cRecording *m_Recording;
+ std::string m_ReplayPos;
// job: listing
cMenuList *m_MenuList;
@@ -69,6 +70,7 @@ public:
virtual bool Abort(void) const;
virtual void Flushed(void);
+ inline std::string GetReplayPos() { return m_ReplayPos; }
};
inline bool cConnectionHTTP::Abort(void) const
diff --git a/server/recplayer.c b/server/recplayer.c
index f4fe1cd..f85ed45 100644
--- a/server/recplayer.c
+++ b/server/recplayer.c
@@ -19,6 +19,10 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <iostream>
+#include <fstream>
+#include <string>
+
#include "recplayer.h"
// for TSPLAY patch detection
@@ -210,6 +214,47 @@ cRecording* RecPlayer::getCurrentRecording()
return recording;
}
+int RecPlayer::frameFromResume()
+{
+ int frame = 0;
+ char fileName[2048];
+ snprintf(fileName, 2047, "%s/resume", recording->FileName());
+ std::ifstream ifs;
+ ifs.open(fileName);
+ if (!ifs.is_open()) return 0;
+ std::string sFrame;
+ getline(ifs, sFrame);
+ ifs.close();
+ sFrame=sFrame.substr(2);
+ frame=atoi(sFrame.c_str());
+ return frame;
+}
+
+int RecPlayer::frameFromMark(int index)
+{
+ char fileName[2048];
+ snprintf(fileName, 2047, "%s/marks", recording->FileName());
+ std::ifstream ifs;
+ ifs.open(fileName);
+ if (!ifs.is_open()) return 0;
+ std::string sTime;
+ for (int i=0; i<=index; i++) {
+ getline(ifs, sTime);
+ if (ifs.eof()) break;
+ }
+ ifs.close();
+ int seconds = 0, minutes = 0, hours = 0;
+ hours = atoi(sTime.substr(0, sTime.find(":")).c_str());
+ minutes = atoi(sTime.substr(sTime.find(":") + 1, 2).c_str());
+ seconds = atoi(sTime.substr(sTime.rfind(":") + 1, 2).c_str());
+ return frameFromSeconds(seconds + minutes * 60 + hours * 3600);
+}
+
+int RecPlayer::frameFromSeconds(int seconds)
+{
+ return 25 * seconds; // 25fps
+}
+
uint64_t RecPlayer::positionFromFrameNumber(uint32_t frameNumber)
{
if (!indexFile) return 0;
diff --git a/server/recplayer.h b/server/recplayer.h
index 3da6c89..d0a3ff9 100644
--- a/server/recplayer.h
+++ b/server/recplayer.h
@@ -46,6 +46,9 @@ class RecPlayer
cRecording* getCurrentRecording();
void scan();
uint64_t positionFromFrameNumber(uint32_t frameNumber);
+ int frameFromResume();
+ int frameFromMark(int index);
+ int frameFromSeconds(int seconds);
uint32_t frameNumberFromPosition(uint64_t position);
bool getNextIFrame(uint32_t frameNumber, uint32_t direction, uint64_t* rfilePosition, uint32_t* rframeNumber, uint32_t* rframeLength);
diff --git a/server/recstreamer.c b/server/recstreamer.c
index 73af53b..8a5a7ad 100644
--- a/server/recstreamer.c
+++ b/server/recstreamer.c
@@ -12,13 +12,14 @@ using namespace Streamdev;
// --- cStreamdevRecStreamer -------------------------------------------------
-cStreamdevRecStreamer::cStreamdevRecStreamer(cRecording *Rec, const cServerConnection *Connection):
+cStreamdevRecStreamer::cStreamdevRecStreamer(cRecording *Rec, const cServerConnection *Connection, std::string pos):
cStreamdevStreamer("streamdev-recstreaming", Connection),
m_RecPlayer(Rec),
m_From(0L)
{
Dprintf("New rec streamer\n");
m_To = (int64_t) m_RecPlayer.getLengthBytes() - 1;
+ m_Pos = pos;
}
cStreamdevRecStreamer::~cStreamdevRecStreamer()
@@ -52,6 +53,69 @@ int64_t cStreamdevRecStreamer::SetRange(int64_t &From, int64_t &To)
return m_To - m_From + 1;
}
+int32_t cStreamdevRecStreamer::getIFrameBeforeFrame(int32_t frame)
+{
+ uint32_t iframe, len;
+ uint64_t pos;
+ m_RecPlayer.getNextIFrame(frame + 1, 0, &pos, &iframe, &len);
+ Dprintf("pos: frame %i -> start at iFrame %i\n", frame, iframe);
+ return iframe;
+}
+
+int64_t cStreamdevRecStreamer::GetFromByPos()
+{
+ if (m_Pos.empty()) return 0;
+
+ std::string pos = m_Pos;
+
+ // cut prefix (if any)
+ if (pos.find('_') != std::string::npos) {
+ pos = pos.substr(pos.find('_') + 1);
+ }
+
+ // resume file
+ if (pos == "resume") {
+ int frame = getIFrameBeforeFrame(m_RecPlayer.frameFromResume());
+ Dprintf("pos: frame from resume: %i\n", frame);
+ return m_RecPlayer.positionFromFrameNumber(frame);
+ }
+
+ // mark
+ if (pos.find("mark.") == 0) {
+ int index = atoi(pos.substr(5).c_str());
+ int frame = getIFrameBeforeFrame(m_RecPlayer.frameFromMark(index));
+ Dprintf("pos: mark %i - frame %i\n", index, frame);
+ return m_RecPlayer.positionFromFrameNumber(frame);
+ }
+
+ // time
+ if (pos.find("time.") == 0) {
+ int seconds = atoi(pos.substr(5).c_str());
+ int frame = getIFrameBeforeFrame(m_RecPlayer.frameFromSeconds(seconds));
+ Dprintf("pos: %i seconds - frame %i\n", seconds, frame);
+ return m_RecPlayer.positionFromFrameNumber(frame);
+ }
+
+ // frame number
+ if (pos.find("frame.") == 0) {
+ int frame = getIFrameBeforeFrame(atoi(pos.substr(6).c_str()));
+ Dprintf("pos: frame %i\n", frame);
+ return m_RecPlayer.positionFromFrameNumber(frame);
+ }
+
+ // default: byte index or percent
+ // as "%" is the url escape character, interpret <100 as percent
+ // if (pos.find("%") != std::string::npos) {
+ // int percent = atoi(pos.substr(0, pos.find("%")).c_str());
+ int64_t number = atol(pos.c_str());
+ if (number < 100) {
+ Dprintf("pos: %lld percent\n", (long long)number);
+ int64_t offset = m_RecPlayer.getLengthBytes() * number / 100;
+ return offset;
+ }
+ return number;
+}
+
uchar* cStreamdevRecStreamer::GetFromReceiver(int &Count)
{
if (m_From <= m_To) {
diff --git a/server/recstreamer.h b/server/recstreamer.h
index 83df8c1..6c53a61 100644
--- a/server/recstreamer.h
+++ b/server/recstreamer.h
@@ -14,6 +14,7 @@ private:
RecPlayer m_RecPlayer;
int64_t m_From;
int64_t m_To;
+ std::string m_Pos;
uchar m_Buffer[RECBUFSIZE];
protected:
@@ -25,7 +26,9 @@ public:
inline uint64_t GetLength() { return m_RecPlayer.getLengthBytes(); }
int64_t SetRange(int64_t &From, int64_t &To);
virtual cString ToText() const;
- cStreamdevRecStreamer(cRecording *Recording, const cServerConnection *Connection);
+ int64_t GetFromByPos();
+ int32_t getIFrameBeforeFrame(int32_t frame);
+ cStreamdevRecStreamer(cRecording *Recording, const cServerConnection *Connection, std::string pos);
virtual ~cStreamdevRecStreamer();
};