Snapshot 2009-07-01

This commit is contained in:
Frank Schmirler
2010-12-02 09:44:53 +01:00
parent 7254a67528
commit 008ea7f151
28 changed files with 3462 additions and 329 deletions

View File

@@ -1,5 +1,5 @@
/*
* $Id: connectionHTTP.c,v 1.16 2009/02/13 07:02:19 schmirl Exp $
* $Id: connectionHTTP.c,v 1.17 2009/06/19 06:32:45 schmirl Exp $
*/
#include <ctype.h>
@@ -211,10 +211,8 @@ bool cConnectionHTTP::CmdGET(const std::string &Opts)
const char* pType = type.c_str();
if (strcasecmp(pType, "PS") == 0) {
m_StreamType = stPS;
#if APIVERSNUM < 10703
} else if (strcasecmp(pType, "PES") == 0) {
m_StreamType = stPES;
#endif
} else if (strcasecmp(pType, "TS") == 0) {
m_StreamType = stTS;
} else if (strcasecmp(pType, "ES") == 0) {
@@ -266,9 +264,7 @@ bool cConnectionHTTP::CmdGET(const std::string &Opts)
{
case stTS: base += "TS/"; break;
case stPS: base += "PS/"; break;
#if APIVERSNUM < 10703
case stPES: base += "PES/"; break;
#endif
case stES: base += "ES/"; break;
case stExtern: base += "Extern/"; break;
default: break;

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@
#define VDR_STREAMDEV_SERVERS_CONNECTIONVTP_H
#include "server/connection.h"
#include "server/recplayer.h"
class cTBSocket;
class cStreamdevLiveStreamer;
@@ -9,6 +10,7 @@ class cStreamdevFilterStreamer;
class cLSTEHandler;
class cLSTCHandler;
class cLSTTHandler;
class cLSTRHandler;
class cConnectionVTP: public cServerConnection {
friend class cLSTEHandler;
@@ -21,16 +23,19 @@ private:
cStreamdevLiveStreamer *m_LiveStreamer;
cTBSocket *m_FilterSocket;
cStreamdevFilterStreamer *m_FilterStreamer;
cTBSocket *m_RecSocket;
cTBSocket *m_DataSocket;
char *m_LastCommand;
eStreamType m_StreamType;
bool m_FiltersSupport;
RecPlayer *m_RecPlayer;
// Members adopted for SVDRP
cRecordings Recordings;
cLSTEHandler *m_LSTEHandler;
cLSTCHandler *m_LSTCHandler;
cLSTTHandler *m_LSTTHandler;
cLSTRHandler *m_LSTRHandler;
protected:
template<class cHandler>
@@ -51,7 +56,9 @@ public:
bool CmdCAPS(char *Opts);
bool CmdPROV(char *Opts);
bool CmdPORT(char *Opts);
bool CmdREAD(char *Opts);
bool CmdTUNE(char *Opts);
bool CmdPLAY(char *Opts);
bool CmdADDP(char *Opts);
bool CmdDELP(char *Opts);
bool CmdADDF(char *Opts);
@@ -64,14 +71,20 @@ public:
bool CmdLSTE(char *Opts);
bool CmdLSTC(char *Opts);
bool CmdLSTT(char *Opts);
bool CmdLSTR(char *Opts);
// Commands adopted from SVDRP
bool CmdSTAT(const char *Option);
bool CmdMODT(const char *Option);
bool CmdNEWT(const char *Option);
bool CmdDELT(const char *Option);
//bool CmdLSTR(char *Opts);
//bool CmdDELR(char *Opts);
bool CmdNEXT(const char *Option);
bool CmdNEWC(const char *Option);
bool CmdMODC(const char *Option);
bool CmdMOVC(const char *Option);
bool CmdDELC(const char *Option);
bool CmdDELR(const char *Option);
bool CmdRENR(const char *Option);
bool Respond(int Code, const char *Message, ...)
__attribute__ ((format (printf, 3, 4)));

View File

@@ -4,6 +4,7 @@
#include <libsi/descriptor.h>
#include "remux/ts2ps.h"
#include "remux/ts2pes.h"
#include "remux/ts2es.h"
#include "remux/extern.h"
@@ -13,7 +14,7 @@
#include "server/livefilter.h"
#include "common.h"
#define TSPATREPACKER
using namespace Streamdev;
// --- cStreamdevLiveReceiver -------------------------------------------------
@@ -64,6 +65,8 @@ private:
int pmtPid;
int pmtSid;
int pmtVersion;
uchar tspat_buf[TS_SIZE];
cStreamdevBuffer siBuffer;
const cChannel *m_Channel;
cStreamdevLiveStreamer *m_Streamer;
@@ -73,9 +76,11 @@ private:
int GetPid(SI::PMT::Stream& stream);
public:
cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel);
uchar* Get(int &Count) { return siBuffer.Get(Count); }
void Del(int Count) { return siBuffer.Del(Count); }
};
cStreamdevPatFilter::cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel)
cStreamdevPatFilter::cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel): siBuffer(10 * TS_SIZE, TS_SIZE)
{
Dprintf("cStreamdevPatFilter(\"%s\")\n", Channel->Name());
assert(Streamer);
@@ -85,6 +90,29 @@ cStreamdevPatFilter::cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const
pmtSid = 0;
pmtVersion = -1;
Set(0x00, 0x00); // PAT
// initialize PAT buffer. Only some values are dynamic (see comments)
memset(tspat_buf, 0xff, TS_SIZE);
tspat_buf[0] = TS_SYNC_BYTE; // Transport packet header sunchronization byte (1000011 = 0x47h)
tspat_buf[1] = 0x40; // Set payload unit start indicator bit
tspat_buf[2] = 0x0; // PID
tspat_buf[3] = 0x10; // Set payload flag, DYNAMIC: Continuity counter
tspat_buf[4] = 0x0; // SI pointer field
tspat_buf[5] = 0x0; // PAT table id
tspat_buf[6] = 0xb0; // Section syntax indicator bit and reserved bits set
tspat_buf[7] = 12 + 1; // Section length (12 bit): PAT_TABLE_LEN + 1
tspat_buf[8] = 0; // DYNAMIC: Transport stream ID (bits 8-15)
tspat_buf[9] = 0; // DYNAMIC: Transport stream ID (bits 0-7)
tspat_buf[10] = 0xc0; // Reserved, DYNAMIC: Version number, DYNAMIC: Current next indicator
tspat_buf[11] = 0x0; // Section number
tspat_buf[12] = 0x0; // Last section number
tspat_buf[13] = 0; // DYNAMIC: Program number (bits 8-15)
tspat_buf[14] = 0; // DYNAMIC: Program number (bits 0-7)
tspat_buf[15] = 0xe0; // Reserved, DYNAMIC: Network ID (bits 8-12)
tspat_buf[16] = 0; // DYNAMIC: Network ID (bits 0-7)
tspat_buf[17] = 0; // DYNAMIC: Checksum
tspat_buf[18] = 0; // DYNAMIC: Checksum
tspat_buf[19] = 0; // DYNAMIC: Checksum
tspat_buf[20] = 0; // DYNAMIC: Checksum
}
static const char * const psStreamTypes[] = {
@@ -224,54 +252,37 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
if (0 != (pmtPid = assoc.getPid())) {
Dprintf("cStreamdevPatFilter: PMT pid for channel %s: %d\n", Channel->Name(), pmtPid);
pmtSid = assoc.getServiceId();
if (Length < TS_SIZE-5) {
// repack PAT to TS frame and send to client
#ifndef TSPATREPACKER
uint8_t pat_ts[TS_SIZE] = {TS_SYNC_BYTE, 0x40 /* pusi=1 */, 0 /* pid=0 */, 0x10 /* adaption=1 */, 0 /* pointer */};
memcpy(pat_ts + 5, Data, Length);
m_Streamer->Put(pat_ts, TS_SIZE);
#else
int ts_id;
unsigned int crc, i, len;
uint8_t *tmp, tspat_buf[TS_SIZE];
static uint8_t ccounter = 0;
ccounter = (ccounter + 1) % 16;
memset(tspat_buf, 0xff, TS_SIZE);
ts_id = Channel->Tid(); // Get transport stream id of the channel
tspat_buf[0] = TS_SYNC_BYTE; // Transport packet header sunchronization byte (1000011 = 0x47h)
tspat_buf[1] = 0x40; // Set payload unit start indicator bit
tspat_buf[2] = 0x0; // PID
tspat_buf[3] = 0x10 | ccounter; // Set payload flag, Continuity counter
tspat_buf[4] = 0x0; // SI pointer field
tspat_buf[5] = 0x0; // PAT table id
tspat_buf[6] = 0xb0; // Section syntax indicator bit and reserved bits set
tspat_buf[7] = 12 + 1; // Section length (12 bit): PAT_TABLE_LEN + 1
tspat_buf[8] = (ts_id >> 8); // Transport stream ID (bits 8-15)
tspat_buf[9] = (ts_id & 0xff); // Transport stream ID (bits 0-7)
tspat_buf[10] = 0xc0 | ((pat.getVersionNumber() << 1) & 0x3e) |
pat.getCurrentNextIndicator();// Version number, Current next indicator
tspat_buf[11] = 0x0; // Section number
tspat_buf[12] = 0x0; // Last section number
tspat_buf[13] = (pmtSid >> 8); // Program number (bits 8-15)
tspat_buf[14] = (pmtSid & 0xff); // Program number (bits 0-7)
tspat_buf[15] = 0xe0 | (pmtPid >> 8); // Network ID (bits 8-12)
tspat_buf[16] = (pmtPid & 0xff); // Network ID (bits 0-7)
crc = 0xffffffff;
len = 12; // PAT_TABLE_LEN
tmp = &tspat_buf[4 + 1]; // TS_HDR_LEN + 1
while (len--) {
crc ^= *tmp++ << 24;
for (i = 0; i < 8; i++)
crc = (crc << 1) ^ ((crc & 0x80000000) ? 0x04c11db7 : 0); // CRC32POLY
}
tspat_buf[17] = crc >> 24 & 0xff; // Checksum
tspat_buf[18] = crc >> 16 & 0xff; // Checksum
tspat_buf[19] = crc >> 8 & 0xff; // Checksum
tspat_buf[20] = crc & 0xff; // Checksum
m_Streamer->Put(tspat_buf, TS_SIZE);
#endif
} else
isyslog("cStreamdevPatFilter: PAT size %d too large to fit in one TS", Length);
// repack PAT to TS frame and send to client
int ts_id;
unsigned int crc, i, len;
uint8_t *tmp;
static uint8_t ccounter = 0;
ccounter = (ccounter + 1) % 16;
ts_id = Channel->Tid(); // Get transport stream id of the channel
tspat_buf[3] = 0x10 | ccounter; // Set payload flag, Continuity counter
tspat_buf[8] = (ts_id >> 8); // Transport stream ID (bits 8-15)
tspat_buf[9] = (ts_id & 0xff); // Transport stream ID (bits 0-7)
tspat_buf[10] = 0xc0 | ((pat.getVersionNumber() << 1) & 0x3e) |
pat.getCurrentNextIndicator();// Version number, Current next indicator
tspat_buf[13] = (pmtSid >> 8); // Program number (bits 8-15)
tspat_buf[14] = (pmtSid & 0xff); // Program number (bits 0-7)
tspat_buf[15] = 0xe0 | (pmtPid >> 8); // Network ID (bits 8-12)
tspat_buf[16] = (pmtPid & 0xff); // Network ID (bits 0-7)
crc = 0xffffffff;
len = 12; // PAT_TABLE_LEN
tmp = &tspat_buf[4 + 1]; // TS_HDR_LEN + 1
while (len--) {
crc ^= *tmp++ << 24;
for (i = 0; i < 8; i++)
crc = (crc << 1) ^ ((crc & 0x80000000) ? 0x04c11db7 : 0); // CRC32POLY
}
tspat_buf[17] = crc >> 24 & 0xff; // Checksum
tspat_buf[18] = crc >> 16 & 0xff; // Checksum
tspat_buf[19] = crc >> 8 & 0xff; // Checksum
tspat_buf[20] = crc & 0xff; // Checksum
int written = siBuffer.PutTS(tspat_buf, TS_SIZE);
if (written != TS_SIZE)
siBuffer.ReportOverflow(TS_SIZE - written);
if (pmtPid != prevPmtPid) {
m_Streamer->SetPids(pmtPid);
Add(pmtPid, 0x02);
@@ -292,7 +303,7 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
if (pmtVersion != -1) {
if (pmtVersion != pmt.getVersionNumber()) {
Dprintf("cStreamdevPatFilter: PMT version changed, detaching all pids\n");
Del(pmtPid, 0x02);
cFilter::Del(pmtPid, 0x02);
pmtPid = 0; // this triggers PAT scan
}
return;
@@ -329,12 +340,7 @@ cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, std::string Paramet
m_Device(NULL),
m_Receiver(NULL),
m_PatFilter(NULL),
#if APIVERSNUM < 10703
m_PESRemux(NULL),
#endif
m_ESRemux(NULL),
m_PSRemux(NULL),
m_ExtRemux(NULL)
m_Remux(NULL)
{
}
@@ -347,12 +353,7 @@ cStreamdevLiveStreamer::~cStreamdevLiveStreamer()
DELETENULL(m_PatFilter);
}
DELETENULL(m_Receiver);
#if APIVERSNUM < 10703
delete m_PESRemux;
#endif
delete m_ESRemux;
delete m_PSRemux;
delete m_ExtRemux;
delete m_Remux;
}
bool cStreamdevLiveStreamer::HasPid(int Pid)
@@ -459,19 +460,17 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str
int pid = ISRADIO(m_Channel) ? m_Channel->Apid(0) : m_Channel->Vpid();
if (Apid != 0)
pid = Apid;
m_ESRemux = new cTS2ESRemux(pid);
m_Remux = new cTS2ESRemux(pid);
return SetPids(pid);
}
#if APIVERSNUM < 10703
case stPES:
m_PESRemux = new cRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
m_Channel->Spids(), false);
m_Remux = new cTS2PESRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
m_Channel->Spids());
return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
#endif
case stPS:
m_PSRemux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
m_Remux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
m_Channel->Spids());
return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
@@ -490,7 +489,7 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str
return true;
case stExtern:
m_ExtRemux = new cExternRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
m_Remux = new cExternRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
m_Channel->Spids(), m_Parameter);
return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
@@ -503,82 +502,39 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str
int cStreamdevLiveStreamer::Put(const uchar *Data, int Count)
{
switch (m_StreamType) {
case stTS:
case stTSPIDS:
return cStreamdevStreamer::Put(Data, Count);
#if APIVERSNUM < 10703
case stPES:
return m_PESRemux->Put(Data, Count);
#endif
case stES:
return m_ESRemux->Put(Data, Count);
case stPS:
return m_PSRemux->Put(Data, Count);
case stExtern:
return m_ExtRemux->Put(Data, Count);
default: // shouldn't happen???
return 0;
// insert si data
if (m_PatFilter) {
int siCount;
uchar *siData = m_PatFilter->Get(siCount);
if (siData) {
if (m_Remux)
siCount = m_Remux->Put(siData, siCount);
else
siCount = cStreamdevStreamer::Put(siData, siCount);
if (siCount)
m_PatFilter->Del(siCount);
}
}
if (m_Remux)
return m_Remux->Put(Data, Count);
else
return cStreamdevStreamer::Put(Data, Count);
}
uchar *cStreamdevLiveStreamer::Get(int &Count)
{
switch (m_StreamType) {
case stTS:
case stTSPIDS:
if (m_Remux)
return m_Remux->Get(Count);
else
return cStreamdevStreamer::Get(Count);
#if APIVERSNUM < 10703
case stPES:
return m_PESRemux->Get(Count);
#endif
case stES:
return m_ESRemux->Get(Count);
case stPS:
return m_PSRemux->Get(Count);
case stExtern:
return m_ExtRemux->Get(Count);
default: // shouldn't happen???
return 0;
}
}
void cStreamdevLiveStreamer::Del(int Count)
{
switch (m_StreamType) {
case stTS:
case stTSPIDS:
if (m_Remux)
m_Remux->Del(Count);
else
cStreamdevStreamer::Del(Count);
break;
#if APIVERSNUM < 10703
case stPES:
m_PESRemux->Del(Count);
break;
#endif
case stES:
m_ESRemux->Del(Count);
break;
case stPS:
m_PSRemux->Del(Count);
break;
case stExtern:
m_ExtRemux->Del(Count);
break;
}
}
void cStreamdevLiveStreamer::Attach(void)

View File

@@ -5,14 +5,12 @@
#include <vdr/receiver.h>
#include "server/streamer.h"
#include "remux/tsremux.h"
#include "common.h"
class cTS2PSRemux;
class cTS2ESRemux;
class cExternRemux;
#if APIVERSNUM < 10703
class cRemux;
#endif
namespace Streamdev {
class cTSRemux;
}
class cStreamdevPatFilter;
class cStreamdevLiveReceiver;
@@ -29,12 +27,7 @@ private:
cDevice *m_Device;
cStreamdevLiveReceiver *m_Receiver;
cStreamdevPatFilter *m_PatFilter;
#if APIVERSNUM < 10703
cRemux *m_PESRemux;
#endif
cTS2ESRemux *m_ESRemux;
cTS2PSRemux *m_PSRemux;
cExternRemux *m_ExtRemux;
Streamdev::cTSRemux *m_Remux;
void StartReceiver(void);
bool HasPid(int Pid);

View File

@@ -201,10 +201,8 @@ std::string cHtmlChannelList::StreamTypeMenu()
(std::string) "[<a href=\"/TS/" + self + "\">TS</a>] ");
typeMenu += (streamType == stPS ? (std::string) "[PS] " :
(std::string) "[<a href=\"/PS/" + self + "\">PS</a>] ");
#if APIVERSNUM < 10703
typeMenu += (streamType == stPES ? (std::string) "[PES] " :
(std::string) "[<a href=\"/PES/" + self + "\">PES</a>] ");
#endif
typeMenu += (streamType == stES ? (std::string) "[ES] " :
(std::string) "[<a href=\"/ES/" + self + "\">ES</a>] ");
typeMenu += (streamType == stExtern ? (std::string) "[Extern] " :
@@ -343,10 +341,8 @@ std::string cHtmlChannelList::ItemText()
switch (streamType) {
case stTS: suffix = (std::string) ".ts"; break;
case stPS: suffix = (std::string) ".vob"; break;
#if APIVERSNUM < 10703
// for Network Media Tank
case stPES: suffix = (std::string) ".vdr"; break;
#endif
default: suffix = "";
}
line += (std::string) "<li value=\"" + (const char*) itoa(current->Number()) + "\">";

288
server/recplayer.c Normal file
View File

@@ -0,0 +1,288 @@
/*
Copyright 2004-2005 Chris Tallon
This file is part of VOMP.
and adopted for streamdev to play recordings
VOMP is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
VOMP is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with VOMP; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "recplayer.h"
#define _XOPEN_SOURCE 600
#include <fcntl.h>
RecPlayer::RecPlayer(cRecording* rec)
{
file = NULL;
fileOpen = 0;
lastPosition = 0;
recording = rec;
for(int i = 1; i < 1000; i++) segments[i] = NULL;
// FIXME find out max file path / name lengths
#if VDRVERSNUM >= 10703
indexFile = new cIndexFile(recording->FileName(), false, rec->IsPesRecording());
#else
indexFile = new cIndexFile(recording->FileName(), false);
#endif
if (!indexFile) esyslog("ERROR: Streamdev: Failed to create indexfile!");
scan();
}
void RecPlayer::scan()
{
if (file) fclose(file);
totalLength = 0;
fileOpen = 0;
totalFrames = 0;
int i = 1;
while(segments[i++]) delete segments[i];
char fileName[2048];
for(i = 1; i < 1000; i++)
{
#if APIVERSNUM < 10703
snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i);
//log->log("RecPlayer", Log::DEBUG, "FILENAME: %s", fileName);
file = fopen(fileName, "r");
#else
snprintf(fileName, 2047, "%s/%05i.ts", recording->FileName(), i);
file = fopen(fileName, "r");
if (!file) {
snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i);
file = fopen(fileName, "r");
}
#endif
if (!file) break;
segments[i] = new Segment();
segments[i]->start = totalLength;
fseek(file, 0, SEEK_END);
totalLength += ftell(file);
totalFrames = indexFile->Last();
//log->log("RecPlayer", Log::DEBUG, "File %i found, totalLength now %llu, numFrames = %lu", i, totalLength, totalFrames);
segments[i]->end = totalLength;
fclose(file);
}
file = NULL;
}
RecPlayer::~RecPlayer()
{
//log->log("RecPlayer", Log::DEBUG, "destructor");
int i = 1;
while(segments[i++]) delete segments[i];
if (file) fclose(file);
}
int RecPlayer::openFile(int index)
{
if (file) fclose(file);
char fileName[2048];
#if APIVERSNUM >= 10703
snprintf(fileName, 2047, "%s/%05i.ts", recording->FileName(), index);
isyslog("openFile called for index %i string:%s", index, fileName);
file = fopen(fileName, "r");
if (file)
{
fileOpen = index;
return 1;
}
#endif
snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), index);
isyslog("openFile called for index %i string:%s", index, fileName);
//log->log("RecPlayer", Log::DEBUG, "openFile called for index %i string:%s", index, fileName);
file = fopen(fileName, "r");
if (file)
{
fileOpen = index;
return 1;
}
//log->log("RecPlayer", Log::DEBUG, "file failed to open");
fileOpen = 0;
return 0;
}
uint64_t RecPlayer::getLengthBytes()
{
return totalLength;
}
uint32_t RecPlayer::getLengthFrames()
{
return totalFrames;
}
unsigned long RecPlayer::getBlock(unsigned char* buffer, uint64_t position, unsigned long amount)
{
if ((amount > totalLength) || (amount > 500000))
{
//log->log("RecPlayer", Log::DEBUG, "Amount %lu requested and rejected", amount);
return 0;
}
if (position >= totalLength)
{
//log->log("RecPlayer", Log::DEBUG, "Client asked for data starting past end of recording!");
return 0;
}
if ((position + amount) > totalLength)
{
//log->log("RecPlayer", Log::DEBUG, "Client asked for some data past the end of recording, adjusting amount");
amount = totalLength - position;
}
// work out what block position is in
int segmentNumber;
for(segmentNumber = 1; segmentNumber < 1000; segmentNumber++)
{
if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break;
// position is in this block
}
// we could be seeking around
if (segmentNumber != fileOpen)
{
if (!openFile(segmentNumber)) return 0;
}
uint64_t currentPosition = position;
uint32_t yetToGet = amount;
uint32_t got = 0;
uint32_t getFromThisSegment = 0;
uint32_t filePosition;
while(got < amount)
{
if (got)
{
// if(got) then we have already got some and we are back around
// advance the file pointer to the next file
if (!openFile(++segmentNumber)) return 0;
}
// is the request completely in this block?
if ((currentPosition + yetToGet) <= segments[segmentNumber]->end)
getFromThisSegment = yetToGet;
else
getFromThisSegment = segments[segmentNumber]->end - currentPosition;
filePosition = currentPosition - segments[segmentNumber]->start;
fseek(file, filePosition, SEEK_SET);
if (fread(&buffer[got], getFromThisSegment, 1, file) != 1) return 0; // umm, big problem.
// Tell linux not to bother keeping the data in the FS cache
posix_fadvise(file->_fileno, filePosition, getFromThisSegment, POSIX_FADV_DONTNEED);
got += getFromThisSegment;
currentPosition += getFromThisSegment;
yetToGet -= getFromThisSegment;
}
lastPosition = position;
return got;
}
uint64_t RecPlayer::getLastPosition()
{
return lastPosition;
}
cRecording* RecPlayer::getCurrentRecording()
{
return recording;
}
uint64_t RecPlayer::positionFromFrameNumber(uint32_t frameNumber)
{
if (!indexFile) return 0;
#if VDRVERSNUM >= 10703
uint16_t retFileNumber;
off_t retFileOffset;
#else
uchar retFileNumber;
int retFileOffset;
#endif
if (!indexFile->Get((int)frameNumber, &retFileNumber, &retFileOffset))
{
return 0;
}
// log->log("RecPlayer", Log::DEBUG, "FN: %u FO: %i", retFileNumber, retFileOffset);
if (!segments[retFileNumber]) return 0;
uint64_t position = segments[retFileNumber]->start + retFileOffset;
// log->log("RecPlayer", Log::DEBUG, "Pos: %llu", position);
return position;
}
uint32_t RecPlayer::frameNumberFromPosition(uint64_t position)
{
if (!indexFile) return 0;
if (position >= totalLength)
{
//log->log("RecPlayer", Log::DEBUG, "Client asked for data starting past end of recording!");
return 0;
}
uint8_t segmentNumber;
for(segmentNumber = 1; segmentNumber < 255; segmentNumber++)
{
if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break;
// position is in this block
}
uint32_t askposition = position - segments[segmentNumber]->start;
return indexFile->Get((int)segmentNumber, askposition);
}
bool RecPlayer::getNextIFrame(uint32_t frameNumber, uint32_t direction, uint64_t* rfilePosition, uint32_t* rframeNumber, uint32_t* rframeLength)
{
// 0 = backwards
// 1 = forwards
if (!indexFile) return false;
int iframeLength;
int indexReturnFrameNumber;
indexReturnFrameNumber = (uint32_t)indexFile->GetNextIFrame(frameNumber, (direction==1 ? true : false), NULL, NULL, &iframeLength);
//log->log("RecPlayer", Log::DEBUG, "GNIF input framenumber:%lu, direction=%lu, output:framenumber=%i, framelength=%i", frameNumber, direction, indexReturnFrameNumber, iframeLength);
if (indexReturnFrameNumber == -1) return false;
*rfilePosition = positionFromFrameNumber(indexReturnFrameNumber);
*rframeNumber = (uint32_t)indexReturnFrameNumber;
*rframeLength = (uint32_t)iframeLength;
return true;
}

63
server/recplayer.h Normal file
View File

@@ -0,0 +1,63 @@
/*
Copyright 2004-2005 Chris Tallon
This file is part of VOMP.
VOMP is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
VOMP is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with VOMP; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef RECPLAYER_H
#define RECPLAYER_H
#include <stdio.h>
#include <vdr/recording.h>
#include "server/streamer.h"
class Segment
{
public:
uint64_t start;
uint64_t end;
};
class RecPlayer
{
public:
RecPlayer(cRecording* rec);
~RecPlayer();
uint64_t getLengthBytes();
uint32_t getLengthFrames();
unsigned long getBlock(unsigned char* buffer, uint64_t position, unsigned long amount);
int openFile(int index);
uint64_t getLastPosition();
cRecording* getCurrentRecording();
void scan();
uint64_t positionFromFrameNumber(uint32_t frameNumber);
uint32_t frameNumberFromPosition(uint64_t position);
bool getNextIFrame(uint32_t frameNumber, uint32_t direction, uint64_t* rfilePosition, uint32_t* rframeNumber, uint32_t* rframeLength);
private:
cRecording* recording;
cIndexFile* indexFile;
FILE* file;
int fileOpen;
Segment* segments[1000];
uint64_t totalLength;
uint64_t lastPosition;
uint32_t totalFrames;
};
#endif

View File

@@ -1,5 +1,5 @@
/*
* $Id: streamer.c,v 1.18 2009/02/13 10:39:22 schmirl Exp $
* $Id: streamer.c,v 1.19 2009/06/19 06:32:45 schmirl Exp $
*/
#include <vdr/ringbuffer.h>
@@ -14,6 +14,13 @@
#include "tools/select.h"
#include "common.h"
// --- cStreamdevBuffer -------------------------------------------------------
cStreamdevBuffer::cStreamdevBuffer(int Size, int Margin, bool Statistics, const char *Description):
cRingBufferLinear(Size, Margin, Statistics, Description)
{
}
// --- cStreamdevWriter -------------------------------------------------------
cStreamdevWriter::cStreamdevWriter(cTBSocket *Socket,
@@ -95,14 +102,13 @@ void cStreamdevWriter::Action(void)
cStreamdevStreamer::cStreamdevStreamer(const char *Name):
cThread(Name),
m_Running(false),
m_Writer(NULL),
m_RingBuffer(new cRingBufferLinear(STREAMERBUFSIZE, TS_SIZE * 2,
m_RingBuffer(new cStreamdevBuffer(STREAMERBUFSIZE, TS_SIZE * 2,
true, "streamdev-streamer")),
m_SendBuffer(new cRingBufferLinear(WRITERBUFSIZE, TS_SIZE * 2))
m_SendBuffer(new cStreamdevBuffer(WRITERBUFSIZE, TS_SIZE * 2))
{
m_RingBuffer->SetTimeouts(0, 100);
m_SendBuffer->SetTimeouts(0, 100);
m_SendBuffer->SetTimeouts(100, 100);
}
cStreamdevStreamer::~cStreamdevStreamer()
@@ -116,7 +122,6 @@ void cStreamdevStreamer::Start(cTBSocket *Socket)
{
Dprintf("start streamer\n");
m_Writer = new cStreamdevWriter(Socket, this);
m_Running = true;
Attach();
}
@@ -135,9 +140,8 @@ void cStreamdevStreamer::Stop(void)
Dprintf("stopping streamer\n");
Cancel(3);
}
if (m_Running) {
if (m_Writer) {
Detach();
m_Running = false;
DELETENULL(m_Writer);
}
}
@@ -152,8 +156,6 @@ void cStreamdevStreamer::Action(void)
int count = Put(block, got);
if (count)
m_RingBuffer->Del(count);
else
cCondWait::SleepMs(100);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* $Id: streamer.h,v 1.10 2009/02/13 10:39:22 schmirl Exp $
* $Id: streamer.h,v 1.11 2009/06/19 06:32:45 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_STREAMER_H
@@ -16,8 +16,34 @@ class cStreamdevStreamer;
#define TS_SIZE 188
#endif
#define STREAMERBUFSIZE MEGABYTE(4)
#define WRITERBUFSIZE KILOBYTE(256)
#define STREAMERBUFSIZE (20000 * TS_SIZE)
#define WRITERBUFSIZE (5000 * TS_SIZE)
// --- cStreamdevBuffer -------------------------------------------------------
class cStreamdevBuffer: public cRingBufferLinear {
public:
// make public
void WaitForPut(void) { cRingBuffer::WaitForPut(); }
// Always write complete TS packets
// (assumes Count is a multiple of TS_SIZE)
int PutTS(const uchar *Data, int Count);
cStreamdevBuffer(int Size, int Margin = 0, bool Statistics = false, const char *Description = NULL);
};
inline int cStreamdevBuffer::PutTS(const uchar *Data, int Count)
{
int free = Free();
if (free < Count)
Count = free;
Count -= Count % TS_SIZE;
if (Count)
Count = Put(Data, Count);
else
WaitForPut();
return Count;
}
// --- cStreamdevWriter -------------------------------------------------------
@@ -38,15 +64,14 @@ public:
class cStreamdevStreamer: public cThread {
private:
bool m_Running;
cStreamdevWriter *m_Writer;
cRingBufferLinear *m_RingBuffer;
cRingBufferLinear *m_SendBuffer;
cStreamdevBuffer *m_RingBuffer;
cStreamdevBuffer *m_SendBuffer;
protected:
virtual void Action(void);
bool IsRunning(void) const { return m_Running; }
bool IsRunning(void) const { return m_Writer; }
public:
cStreamdevStreamer(const char *Name);
@@ -57,10 +82,10 @@ public:
bool Abort(void);
void Activate(bool On);
int Receive(uchar *Data, int Length) { return m_RingBuffer->Put(Data, Length); }
int Receive(uchar *Data, int Length) { return m_RingBuffer->PutTS(Data, Length); }
void ReportOverflow(int Bytes) { m_RingBuffer->ReportOverflow(Bytes); }
virtual int Put(const uchar *Data, int Count) { return m_SendBuffer->Put(Data, Count); }
virtual int Put(const uchar *Data, int Count) { return m_SendBuffer->PutTS(Data, Count); }
virtual uchar *Get(int &Count) { return m_SendBuffer->Get(Count); }
virtual void Del(int Count) { m_SendBuffer->Del(Count); }