Redesigned pos= parameter patch for streaming recordings and added missing

bits like HEAD and resume.# support
This commit is contained in:
Frank Schmirler 2013-10-01 23:47:25 +02:00
parent c92de13d06
commit d3df5d07a1
7 changed files with 137 additions and 181 deletions

View File

@ -24,7 +24,9 @@ cConnectionHTTP::cConnectionHTTP(void):
m_Streamer(NULL), m_Streamer(NULL),
m_StreamType((eStreamType)StreamdevServerSetup.HTTPStreamType), m_StreamType((eStreamType)StreamdevServerSetup.HTTPStreamType),
m_Channel(NULL), m_Channel(NULL),
m_Recording(NULL), m_RecPlayer(NULL),
m_ReplayPos(0),
m_ReplayFakeRange(false),
m_MenuList(NULL) m_MenuList(NULL)
{ {
Dprintf("constructor hsRequest\n"); Dprintf("constructor hsRequest\n");
@ -35,7 +37,7 @@ cConnectionHTTP::cConnectionHTTP(void):
cConnectionHTTP::~cConnectionHTTP() cConnectionHTTP::~cConnectionHTTP()
{ {
delete m_Streamer; delete m_Streamer;
delete m_Recording; delete m_RecPlayer;
} }
bool cConnectionHTTP::CanAuthenticate(void) bool cConnectionHTTP::CanAuthenticate(void)
@ -197,53 +199,32 @@ bool cConnectionHTTP::ProcessRequest(void)
} }
return HttpResponse(503, true); return HttpResponse(503, true);
} }
else if (m_Recording != NULL) { else if (m_RecPlayer != NULL) {
Dprintf("GET recording\n"); Dprintf("GET recording\n");
cStreamdevRecStreamer* recStreamer = new cStreamdevRecStreamer(m_Recording, this, m_ReplayPos);
m_Streamer = recStreamer;
int64_t from, to; int64_t from, to;
bool hasRange = ParseRange(from, to);
cStreamdevRecStreamer* recStreamer;
if (from == 0 && hasRange && m_ReplayFakeRange) {
recStreamer = new cStreamdevRecStreamer(m_RecPlayer, this);
from += m_ReplayPos;
if (to >= 0)
to += m_ReplayPos;
}
else
recStreamer = new cStreamdevRecStreamer(m_RecPlayer, this, m_ReplayPos);
m_Streamer = recStreamer;
uint64_t total = recStreamer->GetLength(); uint64_t total = recStreamer->GetLength();
if (ParseRange(from, to)) { if (hasRange) {
Dprintf("parsed from-to: %lld - %lld\n", (long long)from, (long long)to);
int64_t length = recStreamer->SetRange(from, 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); Dprintf("range response: %lld-%lld/%lld, len %lld\n", (long long)from, (long long)to, (long long)total, (long long)length);
if (length < 0L) if (length < 0L)
return HttpResponse(416, true, "video/mpeg", "Accept-Ranges: bytes\r\nContent-Range: bytes */%llu", (unsigned long long) total); return HttpResponse(416, true, "video/mpeg", "Accept-Ranges: bytes\r\nContent-Range: bytes */%llu", (unsigned long long) total);
else 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); 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"); return HttpResponse(200, false, "video/mpeg", "Accept-Ranges: bytes");
}
} }
else { else {
return HttpResponse(404, true); return HttpResponse(404, true);
@ -270,13 +251,23 @@ bool cConnectionHTTP::ProcessRequest(void)
} }
return HttpResponse(503, true); return HttpResponse(503, true);
} }
else if (m_Recording != NULL) { else if (m_RecPlayer != NULL) {
Dprintf("HEAD recording\n"); Dprintf("HEAD recording\n");
cStreamdevRecStreamer *recStreamer = new cStreamdevRecStreamer(m_Recording, this, m_ReplayPos);
m_Streamer = recStreamer;
int64_t from, to; int64_t from, to;
bool hasRange = ParseRange(from, to);
cStreamdevRecStreamer* recStreamer;
if (from == 0 && hasRange && m_ReplayFakeRange) {
recStreamer = new cStreamdevRecStreamer(m_RecPlayer, this, m_ReplayPos);
from += m_ReplayPos;
if (to >= 0)
to += m_ReplayPos;
}
else
recStreamer = new cStreamdevRecStreamer(m_RecPlayer, this, m_ReplayPos);
m_Streamer = recStreamer;
uint64_t total = recStreamer->GetLength(); uint64_t total = recStreamer->GetLength();
if (ParseRange(from, to)) { if (hasRange) {
int64_t length = recStreamer->SetRange(from, to); int64_t length = recStreamer->SetRange(from, to);
if (length < 0L) if (length < 0L)
return HttpResponse(416, true, "video/mpeg", "Accept-Ranges: bytes\r\nContent-Range: bytes */%llu", (unsigned long long) total); return HttpResponse(416, true, "video/mpeg", "Accept-Ranges: bytes\r\nContent-Range: bytes */%llu", (unsigned long long) total);
@ -362,7 +353,6 @@ bool cConnectionHTTP::ParseRange(int64_t &From, int64_t &To) const
From = To = 0L; From = To = 0L;
tStrStrMap::const_iterator it = Headers().find(RANGE); tStrStrMap::const_iterator it = Headers().find(RANGE);
if (it != Headers().end()) { if (it != Headers().end()) {
Dprintf("%s: %s\n", it->first.c_str(), it->second.c_str());
size_t b = it->second.find("bytes="); size_t b = it->second.find("bytes=");
if (b != std::string::npos) { if (b != std::string::npos) {
char* e = NULL; char* e = NULL;
@ -482,8 +472,10 @@ cMenuList* cConnectionHTTP::MenuListFromString(const std::string& Path, const st
return NULL; return NULL;
} }
cRecording* cConnectionHTTP::RecordingFromString(const char *FileBase, const char *FileExt) const RecPlayer* cConnectionHTTP::RecPlayerFromString(const char *FileBase, const char *FileExt)
{ {
RecPlayer *recPlayer = NULL;
if (strcasecmp(FileExt, ".rec") != 0) if (strcasecmp(FileExt, ".rec") != 0)
return NULL; return NULL;
@ -498,19 +490,63 @@ cRecording* cConnectionHTTP::RecordingFromString(const char *FileBase, const cha
cThreadLock RecordingsLock(&Recordings); cThreadLock RecordingsLock(&Recordings);
for (cRecording *rec = Recordings.First(); rec; rec = Recordings.Next(rec)) { for (cRecording *rec = Recordings.First(); rec; rec = Recordings.Next(rec)) {
if (stat(rec->FileName(), &st) == 0 && st.st_dev == (dev_t) l && st.st_ino == inode) if (stat(rec->FileName(), &st) == 0 && st.st_dev == (dev_t) l && st.st_ino == inode)
return new cRecording(rec->FileName()); recPlayer = new RecPlayer(rec->FileName());
} }
} }
} }
else if (*p == 0) { else if (*p == 0) {
// get recording by index // get recording by index
cThreadLock RecordingsLock(&Recordings); cThreadLock RecordingsLock(&Recordings);
cRecording* rec = Recordings.Get((int) l - 1); cRecording *rec = Recordings.Get((int) l - 1);
if (rec) if (rec)
return new cRecording(rec->FileName()); recPlayer = new RecPlayer(rec->FileName());
}
if (recPlayer) {
const char *pos = NULL;
tStrStrMap::const_iterator it = m_Params.begin();
while (it != m_Params.end()) {
if (it->first == "pos") {
pos = it->second.c_str();
break;
}
++it;
}
if (pos) {
// With prefix "full_" we try to fool players
// by replying with a content range starting
// at the requested position instead of 0.
// This is a heavy violation of standards.
// Use at your own risk!
if (strncasecmp(pos, "full_", 5) == 0) {
m_ReplayFakeRange = true;
pos += 5;
}
if (strncasecmp(pos, "resume", 6) == 0) {
int id = pos[6] == '.' ? atoi(pos + 7) : 0;
m_ReplayPos = recPlayer->positionFromResume(id);
}
else if (strncasecmp(pos, "mark.", 5) == 0) {
int index = atoi(pos + 5);
m_ReplayPos = recPlayer->positionFromMark(index);
}
else if (strncasecmp(pos, "time.", 5) == 0) {
int seconds = atoi(pos + 5);
m_ReplayPos = recPlayer->positionFromTime(seconds);
}
else if (strncasecmp(pos, "frame.", 6) == 0) {
int frame = atoi(pos + 6);
m_ReplayPos = recPlayer->positionFromFrameNumber(frame);
}
else {
m_ReplayPos = atol(pos);
if (m_ReplayPos > 0L && m_ReplayPos < 100L)
m_ReplayPos = recPlayer->positionFromPercent((int) m_ReplayPos);
}
}
} }
} }
return NULL; return recPlayer;
} }
bool cConnectionHTTP::ProcessURI(const std::string& PathInfo) bool cConnectionHTTP::ProcessURI(const std::string& PathInfo)
@ -552,16 +588,8 @@ bool cConnectionHTTP::ProcessURI(const std::string& PathInfo)
if ((m_MenuList = MenuListFromString(PathInfo.substr(1, file_pos), filespec.c_str(), fileext.c_str())) != NULL) { if ((m_MenuList = MenuListFromString(PathInfo.substr(1, file_pos), filespec.c_str(), fileext.c_str())) != NULL) {
Dprintf("Channel list requested\n"); Dprintf("Channel list requested\n");
return true; return true;
} else if ((m_Recording = RecordingFromString(filespec.c_str(), fileext.c_str())) != NULL) { } else if ((m_RecPlayer = RecPlayerFromString(filespec.c_str(), fileext.c_str())) != NULL) {
Dprintf("Recording %s found\n", m_Recording->Name()); Dprintf("Recording %s found\n", m_RecPlayer->getCurrentRecording()->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; return true;
} else if ((m_Channel = ChannelFromString(filespec.c_str(), &m_Apid[0], &m_Dpid[0])) != NULL) { } 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]); Dprintf("Channel found. Apid/Dpid is %d/%d\n", m_Apid[0], m_Dpid[0]);

View File

@ -34,13 +34,14 @@ private:
int m_Apid[2]; int m_Apid[2];
int m_Dpid[2]; int m_Dpid[2];
// job: replay // job: replay
cRecording *m_Recording; RecPlayer *m_RecPlayer;
std::string m_ReplayPos; int64_t m_ReplayPos;
bool m_ReplayFakeRange;
// job: listing // job: listing
cMenuList *m_MenuList; cMenuList *m_MenuList;
cMenuList* MenuListFromString(const std::string &PathInfo, const std::string &Filebase, const std::string &Fileext) const; cMenuList* MenuListFromString(const std::string &PathInfo, const std::string &Filebase, const std::string &Fileext) const;
cRecording* RecordingFromString(const char* FileBase, const char* FileExt) const; RecPlayer* RecPlayerFromString(const char* FileBase, const char* FileExt);
bool ProcessURI(const std::string &PathInfo); bool ProcessURI(const std::string &PathInfo);
bool HttpResponse(int Code, bool Last, const char* ContentType = NULL, const char* Headers = "", ...); bool HttpResponse(int Code, bool Last, const char* ContentType = NULL, const char* Headers = "", ...);
@ -70,7 +71,6 @@ public:
virtual bool Abort(void) const; virtual bool Abort(void) const;
virtual void Flushed(void); virtual void Flushed(void);
inline std::string GetReplayPos() { return m_ReplayPos; }
}; };
inline bool cConnectionHTTP::Abort(void) const inline bool cConnectionHTTP::Abort(void) const

View File

@ -1150,7 +1150,7 @@ bool cConnectionVTP::CmdPLAY(char *Opts)
if (m_RecPlayer) { if (m_RecPlayer) {
delete m_RecPlayer; delete m_RecPlayer;
} }
m_RecPlayer = new RecPlayer(recording); m_RecPlayer = new RecPlayer(recording->FileName());
return Respond(220, "%llu (Bytes), %u (Frames)", (long long unsigned int) m_RecPlayer->getLengthBytes(), (unsigned int) m_RecPlayer->getLengthFrames()); return Respond(220, "%llu (Bytes), %u (Frames)", (long long unsigned int) m_RecPlayer->getLengthBytes(), (unsigned int) m_RecPlayer->getLengthFrames());
} }
else { else {

View File

@ -19,10 +19,6 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#include <iostream>
#include <fstream>
#include <string>
#include "recplayer.h" #include "recplayer.h"
// for TSPLAY patch detection // for TSPLAY patch detection
@ -32,17 +28,17 @@
#define _XOPEN_SOURCE 600 #define _XOPEN_SOURCE 600
#include <fcntl.h> #include <fcntl.h>
RecPlayer::RecPlayer(cRecording* rec) RecPlayer::RecPlayer(const char* FileName)
{ {
file = NULL; file = NULL;
fileOpen = 0; fileOpen = 0;
lastPosition = 0; lastPosition = 0;
recording = rec; recording = new cRecording(FileName);
for(int i = 1; i < 1000; i++) segments[i] = NULL; for(int i = 1; i < 1000; i++) segments[i] = NULL;
// FIXME find out max file path / name lengths // FIXME find out max file path / name lengths
indexFile = new cIndexFile(recording->FileName(), false, rec->IsPesRecording()); indexFile = new cIndexFile(recording->FileName(), false, recording->IsPesRecording());
if (!indexFile) esyslog("ERROR: Streamdev: Failed to create indexfile!"); if (!indexFile) esyslog("ERROR: Streamdev: Failed to create indexfile!");
scan(); scan();
@ -89,6 +85,8 @@ RecPlayer::~RecPlayer()
int i = 1; int i = 1;
while(segments[i++]) delete segments[i]; while(segments[i++]) delete segments[i];
if (file) fclose(file); if (file) fclose(file);
delete indexFile;
delete recording;
} }
int RecPlayer::openFile(int index) int RecPlayer::openFile(int index)
@ -214,45 +212,39 @@ cRecording* RecPlayer::getCurrentRecording()
return recording; return recording;
} }
int RecPlayer::frameFromResume() #if VDRVERSNUM < 10732
#define ALIGNED_POS(x) (positionFromFrameNumber(indexFile->GetNextIFrame(x, 1)))
#else
#define ALIGNED_POS(x) (positionFromFrameNumber(indexFile->GetClosestIFrame(x)))
#endif
uint64_t RecPlayer::positionFromResume(int ResumeID)
{ {
int frame = 0; int resumeBackup = Setup.ResumeID;
char fileName[2048]; Setup.ResumeID = ResumeID;
snprintf(fileName, 2047, "%s/resume", recording->FileName()); cResumeFile resume(recording->FileName(), recording->IsPesRecording());
std::ifstream ifs; Setup.ResumeID = resumeBackup;
ifs.open(fileName); return ALIGNED_POS(resume.Read());
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) uint64_t RecPlayer::positionFromMark(int MarkIndex)
{ {
char fileName[2048]; cMarks marks;
snprintf(fileName, 2047, "%s/marks", recording->FileName()); if (marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording()) && marks.Count()) {
std::ifstream ifs; cMark *mark = marks.cConfig<cMark>::Get(MarkIndex);
ifs.open(fileName); if (mark)
if (!ifs.is_open()) return 0; return ALIGNED_POS(mark->Position());
std::string sTime; }
for (int i=0; i<=index; i++) { return 0;
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) uint64_t RecPlayer::positionFromTime(int Seconds)
{ {
return 25 * seconds; // 25fps return ALIGNED_POS(SecondsToFrames(Seconds, recording->FramesPerSecond()));
}
uint64_t RecPlayer::positionFromPercent(int Percent)
{
return ALIGNED_POS(getLengthFrames() * Percent / 100L);
} }
uint64_t RecPlayer::positionFromFrameNumber(uint32_t frameNumber) uint64_t RecPlayer::positionFromFrameNumber(uint32_t frameNumber)

View File

@ -36,7 +36,7 @@ class Segment
class RecPlayer class RecPlayer
{ {
public: public:
RecPlayer(cRecording* rec); RecPlayer(const char* FileName);
~RecPlayer(); ~RecPlayer();
uint64_t getLengthBytes(); uint64_t getLengthBytes();
uint32_t getLengthFrames(); uint32_t getLengthFrames();
@ -45,10 +45,11 @@ class RecPlayer
uint64_t getLastPosition(); uint64_t getLastPosition();
cRecording* getCurrentRecording(); cRecording* getCurrentRecording();
void scan(); void scan();
uint64_t positionFromResume(int ResumeID);
uint64_t positionFromMark(int MarkIndex);
uint64_t positionFromTime(int Seconds);
uint64_t positionFromPercent(int Percent);
uint64_t positionFromFrameNumber(uint32_t frameNumber); uint64_t positionFromFrameNumber(uint32_t frameNumber);
int frameFromResume();
int frameFromMark(int index);
int frameFromSeconds(int seconds);
uint32_t frameNumberFromPosition(uint64_t position); uint32_t frameNumberFromPosition(uint64_t position);
bool getNextIFrame(uint32_t frameNumber, uint32_t direction, uint64_t* rfilePosition, uint32_t* rframeNumber, uint32_t* rframeLength); bool getNextIFrame(uint32_t frameNumber, uint32_t direction, uint64_t* rfilePosition, uint32_t* rframeNumber, uint32_t* rframeLength);

View File

@ -12,14 +12,14 @@ using namespace Streamdev;
// --- cStreamdevRecStreamer ------------------------------------------------- // --- cStreamdevRecStreamer -------------------------------------------------
cStreamdevRecStreamer::cStreamdevRecStreamer(cRecording *Rec, const cServerConnection *Connection, std::string pos): cStreamdevRecStreamer::cStreamdevRecStreamer(RecPlayer *RecPlayer, const cServerConnection *Connection, int64_t StartOffset):
cStreamdevStreamer("streamdev-recstreaming", Connection), cStreamdevStreamer("streamdev-recstreaming", Connection),
m_RecPlayer(Rec), m_RecPlayer(RecPlayer),
m_StartOffset(StartOffset),
m_From(0L) m_From(0L)
{ {
Dprintf("New rec streamer\n"); Dprintf("New rec streamer\n");
m_To = (int64_t) m_RecPlayer.getLengthBytes() - 1; m_To = (int64_t) m_RecPlayer->getLengthBytes() - StartOffset - 1;
m_Pos = pos;
} }
cStreamdevRecStreamer::~cStreamdevRecStreamer() cStreamdevRecStreamer::~cStreamdevRecStreamer()
@ -30,7 +30,7 @@ cStreamdevRecStreamer::~cStreamdevRecStreamer()
int64_t cStreamdevRecStreamer::SetRange(int64_t &From, int64_t &To) int64_t cStreamdevRecStreamer::SetRange(int64_t &From, int64_t &To)
{ {
int64_t l = (int64_t) m_RecPlayer.getLengthBytes(); int64_t l = (int64_t) GetLength();
if (From < 0L) { if (From < 0L) {
From += l; From += l;
if (From < 0L) if (From < 0L)
@ -53,73 +53,10 @@ int64_t cStreamdevRecStreamer::SetRange(int64_t &From, int64_t &To)
return m_To - m_From + 1; 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) uchar* cStreamdevRecStreamer::GetFromReceiver(int &Count)
{ {
if (m_From <= m_To) { if (m_From <= m_To) {
Count = (int) m_RecPlayer.getBlock(m_Buffer, m_From, sizeof(m_Buffer)); Count = (int) m_RecPlayer->getBlock(m_Buffer, m_StartOffset + m_From, sizeof(m_Buffer));
return m_Buffer; return m_Buffer;
} }
return NULL; return NULL;

View File

@ -11,10 +11,10 @@
class cStreamdevRecStreamer: public cStreamdevStreamer { class cStreamdevRecStreamer: public cStreamdevStreamer {
private: private:
//Streamdev::cTSRemux *m_Remux; //Streamdev::cTSRemux *m_Remux;
RecPlayer m_RecPlayer; RecPlayer *m_RecPlayer;
int64_t m_StartOffset;
int64_t m_From; int64_t m_From;
int64_t m_To; int64_t m_To;
std::string m_Pos;
uchar m_Buffer[RECBUFSIZE]; uchar m_Buffer[RECBUFSIZE];
protected: protected:
@ -23,12 +23,10 @@ protected:
public: public:
virtual bool IsReceiving(void) const { return m_From <= m_To; }; virtual bool IsReceiving(void) const { return m_From <= m_To; };
inline uint64_t GetLength() { return m_RecPlayer.getLengthBytes(); } uint64_t GetLength() { return m_RecPlayer->getLengthBytes() - m_StartOffset; }
int64_t SetRange(int64_t &From, int64_t &To); int64_t SetRange(int64_t &From, int64_t &To);
virtual cString ToText() const; virtual cString ToText() const;
int64_t GetFromByPos(); cStreamdevRecStreamer(RecPlayer *RecPlayer, const cServerConnection *Connection, int64_t StartOffset = 0L);
int32_t getIFrameBeforeFrame(int32_t frame);
cStreamdevRecStreamer(cRecording *Recording, const cServerConnection *Connection, std::string pos);
virtual ~cStreamdevRecStreamer(); virtual ~cStreamdevRecStreamer();
}; };