vdr-plugin-vnsiserver/ 0000755 0001750 0001750 00000000000 14153173470 014702 5 ustar tobias tobias vdr-plugin-vnsiserver/requestpacket.c 0000644 0001750 0001750 00000007017 14153173470 017733 0 ustar tobias tobias /*
* vdr-plugin-vnsi - KODI server plugin for VDR
*
* Copyright (C) 2007 Chris Tallon
* Copyright (C) 2010 Alwin Esch (Team XBMC)
* Copyright (C) 2010, 2011 Alexander Pipelka
* Copyright (C) 2015 Team KODI
*
* http://kodi.tv
*
* This Program 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, or (at your option)
* any later version.
*
* This Program 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 KODI; see the file COPYING. If not, see
* .
*
*/
#include "requestpacket.h"
#include "vnsicommand.h"
#include "config.h"
#include
#include
#ifndef __FreeBSD__
#include
#else
#include
#define __be64_to_cpu be64toh
#define __cpu_to_be64 htobe64
#endif
cRequestPacket::cRequestPacket(uint32_t requestID, uint32_t opcode, uint8_t* data, size_t dataLength)
: userData(data), userDataLength(dataLength), opCode(opcode), requestID(requestID)
{
packetPos = 0;
channelID = 0;
streamID = 0;
flag = 0;
}
cRequestPacket::~cRequestPacket()
{
delete[] userData;
}
bool cRequestPacket::end() const
{
return (packetPos >= userDataLength);
}
char* cRequestPacket::extract_String()
{
char *p = (char *)&userData[packetPos];
const char *end = (const char *)memchr(p, '\0', userDataLength - packetPos);
if (end == NULL)
/* string is not terminated - fail */
throw MalformedVNSIPacket();
int length = end - p;
packetPos += length + 1;
return p;
}
uint8_t cRequestPacket::extract_U8()
{
if ((packetPos + sizeof(uint8_t)) > userDataLength)
throw MalformedVNSIPacket();
uint8_t uc = userData[packetPos];
packetPos += sizeof(uint8_t);
return uc;
}
uint32_t cRequestPacket::extract_U32()
{
if ((packetPos + sizeof(uint32_t)) > userDataLength)
throw MalformedVNSIPacket();
uint32_t ul;
memcpy(&ul, &userData[packetPos], sizeof(uint32_t));
ul = ntohl(ul);
packetPos += sizeof(uint32_t);
return ul;
}
uint64_t cRequestPacket::extract_U64()
{
if ((packetPos + sizeof(uint64_t)) > userDataLength)
throw MalformedVNSIPacket();
uint64_t ull;
memcpy(&ull, &userData[packetPos], sizeof(uint64_t));
ull = __be64_to_cpu(ull);
packetPos += sizeof(uint64_t);
return ull;
}
int64_t cRequestPacket::extract_S64()
{
if ((packetPos + sizeof(int64_t)) > userDataLength)
throw MalformedVNSIPacket();
int64_t ll;
memcpy(&ll, &userData[packetPos], sizeof(int64_t));
ll = __be64_to_cpu(ll);
packetPos += sizeof(int64_t);
return ll;
}
double cRequestPacket::extract_Double()
{
if ((packetPos + sizeof(uint64_t)) > userDataLength)
throw MalformedVNSIPacket();
uint64_t ull;
memcpy(&ull, &userData[packetPos], sizeof(uint64_t));
ull = __be64_to_cpu(ull);
double d;
memcpy(&d, &ull, sizeof(double));
packetPos += sizeof(uint64_t);
return d;
}
int32_t cRequestPacket::extract_S32()
{
if ((packetPos + sizeof(int32_t)) > userDataLength)
throw MalformedVNSIPacket();
int32_t l;
memcpy(&l, &userData[packetPos], sizeof(int32_t));
l = ntohl(l);
packetPos += sizeof(int32_t);
return l;
}
uint8_t* cRequestPacket::getData()
{
return userData;
}
vdr-plugin-vnsiserver/recplayer.c 0000644 0001750 0001750 00000016743 14153173470 017047 0 ustar tobias tobias /*
* vdr-plugin-vnsi - KODI server plugin for VDR
*
* Copyright (C) 2004-2005 Chris Tallon
* Copyright (C) 2010 Alwin Esch (Team XBMC)
* Copyright (C) 2010, 2011 Alexander Pipelka
* Copyright (C) 2015 Team KODI
*
* http://kodi.tv
*
* This Program 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, or (at your option)
* any later version.
*
* This Program 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 KODI; see the file COPYING. If not, see
* .
*
*/
/*
* This code is taken from VOMP for VDR plugin.
*/
#include "recplayer.h"
#include
#include
#include
#include
#ifndef O_NOATIME
#define O_NOATIME 0
#endif
cRecPlayer::cRecPlayer(const cRecording* rec, bool inProgress)
:m_inProgress(inProgress),
m_recordingFilename(rec->FileName()),
m_pesrecording(rec->IsPesRecording()),
m_indexFile(m_recordingFilename.c_str(), false, m_pesrecording),
m_file(-1), m_fileOpen(-1)
{
// FIXME find out max file path / name lengths
if(m_pesrecording)
INFOLOG("recording '%s' is a PES recording", m_recordingFilename.c_str());
m_fps = rec->FramesPerSecond();
scan();
}
void cRecPlayer::cleanup() {
m_segments.clear();
}
void cRecPlayer::scan()
{
struct stat s;
closeFile();
m_totalLength = 0;
m_fileOpen = -1;
m_totalFrames = 0;
cleanup();
for(int i = 0; ; i++) // i think we only need one possible loop
{
fileNameFromIndex(i);
if(stat(m_fileName, &s) == -1) {
break;
}
cSegment segment;
segment.start = m_totalLength;
segment.end = segment.start + s.st_size;
m_segments.push_back(segment);
m_totalLength += s.st_size;
INFOLOG("File %i found, size: %lu, totalLength now %lu", i, s.st_size, m_totalLength);
}
m_totalFrames = m_indexFile.Last();
INFOLOG("total frames: %u", m_totalFrames);
}
void cRecPlayer::reScan()
{
struct stat s;
m_totalLength = 0;
for(size_t i = 0; ; i++) // i think we only need one possible loop
{
fileNameFromIndex(i);
if(stat(m_fileName, &s) == -1) {
break;
}
cSegment* segment;
if (m_segments.size() < i+1)
{
m_segments.push_back(cSegment());
segment = &m_segments.back();
segment->start = m_totalLength;
}
else
segment = &m_segments[i];
segment->end = segment->start + s.st_size;
m_totalLength += s.st_size;
}
m_totalFrames = m_indexFile.Last();
}
cRecPlayer::~cRecPlayer()
{
cleanup();
closeFile();
}
char* cRecPlayer::fileNameFromIndex(int index) {
if (m_pesrecording)
snprintf(m_fileName, sizeof(m_fileName), "%s/%03i.vdr", m_recordingFilename.c_str(), index+1);
else
snprintf(m_fileName, sizeof(m_fileName), "%s/%05i.ts", m_recordingFilename.c_str(), index+1);
return m_fileName;
}
bool cRecPlayer::openFile(int index)
{
if (index == m_fileOpen) return true;
closeFile();
fileNameFromIndex(index);
INFOLOG("openFile called for index %i string:%s", index, m_fileName);
m_file = open(m_fileName, O_RDONLY);
if (m_file == -1)
{
INFOLOG("file failed to open");
m_fileOpen = -1;
return false;
}
m_fileOpen = index;
return true;
}
void cRecPlayer::closeFile()
{
if(m_file == -1) {
return;
}
INFOLOG("file closed");
close(m_file);
m_file = -1;
m_fileOpen = -1;
}
uint64_t cRecPlayer::getLengthBytes()
{
return m_totalLength;
}
uint32_t cRecPlayer::getLengthFrames()
{
return m_totalFrames;
}
double cRecPlayer::getFPS()
{
return m_fps;
}
int cRecPlayer::getBlock(unsigned char* buffer, uint64_t position, int amount)
{
// dont let the block be larger than 256 kb
if (amount > 512*1024)
amount = 512*1024;
if ((uint64_t)amount > m_totalLength)
amount = m_totalLength;
if (position >= m_totalLength)
{
reScan();
if (position >= m_totalLength)
{
return 0;
}
}
if ((position + amount) > m_totalLength)
amount = m_totalLength - position;
// work out what block "position" is in
std::vector::iterator begin = m_segments.begin(),
end = m_segments.end(), segmentIterator = end;
for (std::vector::iterator i = begin; i != end; ++i) {
if ((position >= i->start) && (position < i->end)) {
segmentIterator = i;
break;
}
}
// segment not found / invalid position
if (segmentIterator == end)
return 0;
// open file (if not already open)
if (!openFile(std::distance(begin, segmentIterator)))
return 0;
// work out position in current file
uint64_t filePosition = position - segmentIterator->start;
// seek to position
if(lseek(m_file, filePosition, SEEK_SET) == -1)
{
ERRORLOG("unable to seek to position: %lu", filePosition);
return 0;
}
// try to read the block
int bytes_read = read(m_file, buffer, amount);
// we may got stuck at end of segment
if ((bytes_read == 0) && (position < m_totalLength))
bytes_read += getBlock(buffer, position+1 , amount);
if(bytes_read <= 0)
{
return 0;
}
if (!m_inProgress)
{
#ifndef __FreeBSD__
// Tell linux not to bother keeping the data in the FS cache
posix_fadvise(m_file, filePosition, bytes_read, POSIX_FADV_DONTNEED);
#endif
}
return bytes_read;
}
uint64_t cRecPlayer::positionFromFrameNumber(uint32_t frameNumber)
{
uint16_t retFileNumber;
off_t retFileOffset;
bool retPicType;
int retLength;
if (!m_indexFile.Get((int)frameNumber, &retFileNumber, &retFileOffset, &retPicType, &retLength))
return 0;
if (retFileNumber >= m_segments.size())
return 0;
uint64_t position = m_segments[retFileNumber].start + retFileOffset;
return position;
}
uint32_t cRecPlayer::frameNumberFromPosition(uint64_t position)
{
if (position >= m_totalLength)
{
DEBUGLOG("Client asked for data starting past end of recording!");
return m_totalFrames;
}
std::vector::iterator begin = m_segments.begin(),
end = m_segments.end(), segmentIterator = end;
for (std::vector::iterator i = begin; i != end; ++i) {
if ((position >= i->start) && (position < i->end)) {
segmentIterator = i;
break;
}
}
if (segmentIterator == end)
return m_totalFrames;
uint32_t askposition = position - segmentIterator->start;
int segmentNumber = std::distance(begin, segmentIterator);
return m_indexFile.Get((int)segmentNumber, askposition);
}
bool cRecPlayer::getNextIFrame(uint32_t frameNumber, uint32_t direction, uint64_t* rfilePosition, uint32_t* rframeNumber, uint32_t* rframeLength)
{
// 0 = backwards
// 1 = forwards
uint16_t waste1;
off_t waste2;
int iframeLength;
int indexReturnFrameNumber;
indexReturnFrameNumber = (uint32_t)m_indexFile.GetNextIFrame(frameNumber, (direction==1 ? true : false), &waste1, &waste2, &iframeLength);
DEBUGLOG("GNIF input framenumber:%u, direction=%u, 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;
}
vdr-plugin-vnsiserver/responsepacket.c 0000644 0001750 0001750 00000016473 14153173470 020107 0 ustar tobias tobias /*
* vdr-plugin-vnsi - KODI server plugin for VDR
*
* Copyright (C) 2007 Chris Tallon
* Copyright (C) 2010 Alwin Esch (Team XBMC)
* Copyright (C) 2010, 2011 Alexander Pipelka
* Copyright (C) 2015 Team KODI
*
* http://kodi.tv
*
* This Program 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, or (at your option)
* any later version.
*
* This Program 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 KODI; see the file COPYING. If not, see
* .
*
*/
/*
* This code is taken from VOMP for VDR plugin.
*/
#include "responsepacket.h"
#include "vnsicommand.h"
#include "config.h"
#include
#include
#include
#ifndef __FreeBSD__
#include
#else
#include
#define __be64_to_cpu be64toh
#define __cpu_to_be64 htobe64
#endif
/* Packet format for an RR channel response:
4 bytes = channel ID = 1 (request/response channel)
4 bytes = request ID (from serialNumber)
4 bytes = length of the rest of the packet
? bytes = rest of packet. depends on packet
*/
cResponsePacket::cResponsePacket()
{
buffer = NULL;
bufSize = 0;
bufUsed = 0;
}
cResponsePacket::~cResponsePacket()
{
if (buffer) free(buffer);
}
void cResponsePacket::initBuffers()
{
if (buffer == NULL) {
bufSize = 512;
buffer = (uint8_t*)malloc(bufSize);
}
}
void cResponsePacket::init(uint32_t requestID)
{
initBuffers();
uint32_t ul;
ul = htonl(VNSI_CHANNEL_REQUEST_RESPONSE); // RR channel
memcpy(&buffer[0], &ul, sizeof(uint32_t));
ul = htonl(requestID);
memcpy(&buffer[4], &ul, sizeof(uint32_t));
ul = 0;
memcpy(&buffer[userDataLenPos], &ul, sizeof(uint32_t));
bufUsed = headerLength;
}
void cResponsePacket::initScan(uint32_t opCode)
{
initBuffers();
uint32_t ul;
ul = htonl(VNSI_CHANNEL_SCAN); // RR channel
memcpy(&buffer[0], &ul, sizeof(uint32_t));
ul = htonl(opCode);
memcpy(&buffer[4], &ul, sizeof(uint32_t));
ul = 0;
memcpy(&buffer[userDataLenPos], &ul, sizeof(uint32_t));
bufUsed = headerLength;
}
void cResponsePacket::initStatus(uint32_t opCode)
{
initBuffers();
uint32_t ul;
ul = htonl(VNSI_CHANNEL_STATUS); // RR channel
memcpy(&buffer[0], &ul, sizeof(uint32_t));
ul = htonl(opCode);
memcpy(&buffer[4], &ul, sizeof(uint32_t));
ul = 0;
memcpy(&buffer[userDataLenPos], &ul, sizeof(uint32_t));
bufUsed = headerLength;
}
void cResponsePacket::initStream(uint32_t opCode, uint32_t streamID, uint32_t duration, int64_t pts, int64_t dts, uint32_t serial)
{
initBuffers();
uint32_t ul;
uint64_t ull;
ul = htonl(VNSI_CHANNEL_STREAM); // stream channel
memcpy(&buffer[0], &ul, sizeof(uint32_t));
ul = htonl(opCode); // Stream packet operation code
memcpy(&buffer[4], &ul, sizeof(uint32_t));
ul = htonl(streamID); // Stream ID
memcpy(&buffer[8], &ul, sizeof(uint32_t));
ul = htonl(duration); // Duration
memcpy(&buffer[12], &ul, sizeof(uint32_t));
ull = __cpu_to_be64(pts); // PTS
memcpy(&buffer[16], &ull, sizeof(uint64_t));
ull = __cpu_to_be64(dts); // DTS
memcpy(&buffer[24], &ull, sizeof(uint64_t));
ul = htonl(serial);
memcpy(&buffer[32], &ul, sizeof(uint32_t));
ul = 0;
memcpy(&buffer[userDataLenPosStream], &ul, sizeof(uint32_t));
bufUsed = headerLengthStream;
}
void cResponsePacket::initOsd(uint32_t opCode, int32_t wnd, int32_t color, int32_t x0, int32_t y0, int32_t x1, int32_t y1)
{
initBuffers();
uint32_t ul;
int32_t l;
ul = htonl(VNSI_CHANNEL_OSD); // stream OSD
memcpy(&buffer[0], &ul, sizeof(uint32_t));
ul = htonl(opCode); // OSD operation code
memcpy(&buffer[4], &ul, sizeof(uint32_t));
l = htonl(wnd); // Window
memcpy(&buffer[8], &l, sizeof(int32_t));
l = htonl(color); // Color
memcpy(&buffer[12], &l, sizeof(int32_t));
l = htonl(x0); // x0
memcpy(&buffer[16], &l, sizeof(int32_t));
l = htonl(y0); // y0
memcpy(&buffer[20], &l, sizeof(int32_t));
l = htonl(x1); // x1
memcpy(&buffer[24], &l, sizeof(int32_t));
l = htonl(y1); // y1
memcpy(&buffer[28], &l, sizeof(int32_t));
ul = 0;
memcpy(&buffer[userDataLenPosOSD], &ul, sizeof(uint32_t));
bufUsed = headerLengthOSD;
}
void cResponsePacket::finalise()
{
uint32_t ul = htonl(bufUsed - headerLength);
memcpy(&buffer[userDataLenPos], &ul, sizeof(uint32_t));
}
void cResponsePacket::finaliseStream()
{
uint32_t ul = htonl(bufUsed - headerLengthStream);
memcpy(&buffer[userDataLenPosStream], &ul, sizeof(uint32_t));
}
void cResponsePacket::finaliseOSD()
{
uint32_t ul = htonl(bufUsed - headerLengthOSD);
memcpy(&buffer[userDataLenPosOSD], &ul, sizeof(uint32_t));
}
bool cResponsePacket::copyin(const uint8_t* src, uint32_t len)
{
if (!checkExtend(len)) return false;
memcpy(buffer + bufUsed, src, len);
bufUsed += len;
return true;
}
uint8_t* cResponsePacket::reserve(uint32_t len) {
if (!checkExtend(len)) return 0;
uint8_t* result = buffer + bufUsed;
bufUsed += len;
return result;
}
bool cResponsePacket::unreserve(uint32_t len) {
if(bufUsed < len) return false;
bufUsed -= len;
return true;
}
bool cResponsePacket::add_String(const char* string)
{
uint32_t len = strlen(string) + 1;
if (!checkExtend(len)) return false;
memcpy(buffer + bufUsed, string, len);
bufUsed += len;
return true;
}
bool cResponsePacket::add_U32(uint32_t ul)
{
if (!checkExtend(sizeof(uint32_t))) return false;
uint32_t tmp = htonl(ul);
memcpy(&buffer[bufUsed], &tmp, sizeof(uint32_t));
bufUsed += sizeof(uint32_t);
return true;
}
bool cResponsePacket::add_U8(uint8_t c)
{
if (!checkExtend(sizeof(uint8_t))) return false;
buffer[bufUsed] = c;
bufUsed += sizeof(uint8_t);
return true;
}
bool cResponsePacket::add_S32(int32_t l)
{
if (!checkExtend(sizeof(int32_t))) return false;
int32_t tmp = htonl(l);
memcpy(&buffer[bufUsed], &tmp, sizeof(int32_t));
bufUsed += sizeof(int32_t);
return true;
}
bool cResponsePacket::add_U64(uint64_t ull)
{
if (!checkExtend(sizeof(uint64_t))) return false;
uint64_t tmp = __cpu_to_be64(ull);
memcpy(&buffer[bufUsed], &tmp, sizeof(uint64_t));
bufUsed += sizeof(uint64_t);
return true;
}
bool cResponsePacket::add_double(double d)
{
if (!checkExtend(sizeof(double))) return false;
uint64_t ull;
memcpy(&ull, &d, sizeof(double));
ull = __cpu_to_be64(ull);
memcpy(&buffer[bufUsed], &ull, sizeof(uint64_t));
bufUsed += sizeof(uint64_t);
return true;
}
bool cResponsePacket::checkExtend(uint32_t by)
{
if ((bufUsed + by) < bufSize) return true;
if (512 > by) by = 512;
uint8_t* newBuf = (uint8_t*)realloc(buffer, bufSize + by);
if (!newBuf) return false;
buffer = newBuf;
bufSize += by;
return true;
}
vdr-plugin-vnsiserver/demuxer.c 0000644 0001750 0001750 00000036011 14153173470 016520 0 ustar tobias tobias /*
* vdr-plugin-vnsi - KODI server plugin for VDR
*
* Copyright (C) 2005-2012 Team XBMC
* Copyright (C) 2015 Team KODI
*
* http://kodi.tv
*
* This Program 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, or (at your option)
* any later version.
*
* This Program 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 KODI; see the file COPYING. If not, see
* .
*
*/
#include "config.h"
#include "demuxer.h"
#include "parser.h"
#include "videobuffer.h"
#include
#include
cStreamInfo::cStreamInfo()
{
}
cStreamInfo::cStreamInfo(const cStreamInfo& info)
{
pID = info.pID;
type = info.type;
content = info.content;
subtitlingType = info.subtitlingType;
compositionPageId = info.compositionPageId;
ancillaryPageId = info.ancillaryPageId;
handleRDS = info.handleRDS;
SetLanguage(info.language);
}
void cStreamInfo::SetLanguage(const char* lang)
{
language[0] = lang[0];
language[1] = lang[1];
language[2] = lang[2];
language[3] = 0;
}
cVNSIDemuxer::cVNSIDemuxer(bool bAllowRDS)
: m_bAllowRDS(bAllowRDS)
{
}
cVNSIDemuxer::~cVNSIDemuxer()
{
}
void cVNSIDemuxer::Open(const cChannel &channel, cVideoBuffer *videoBuffer)
{
cMutexLock lock(&m_Mutex);
m_CurrentChannel = channel;
m_VideoBuffer = videoBuffer;
if (m_CurrentChannel.Vpid())
m_WaitIFrame = true;
else
m_WaitIFrame = false;
m_PtsWrap.m_Wrap = false;
m_PtsWrap.m_NoOfWraps = 0;
m_PtsWrap.m_ConfirmCount = 0;
m_MuxPacketSerial = 0;
m_Error = ERROR_DEMUX_NODATA;
m_SetRefTime = true;
m_seenFirstPacket = false;
}
void cVNSIDemuxer::Close()
{
cMutexLock lock(&m_Mutex);
for (auto *i : m_Streams)
{
DEBUGLOG("Deleting stream parser for pid=%i and type=%i", i->GetPID(), i->Type());
delete i;
}
m_Streams.clear();
m_StreamInfos.clear();
}
int cVNSIDemuxer::Read(sStreamPacket *packet, sStreamPacket *packet_side_data)
{
uint8_t *buf;
int len;
cTSStream *stream;
cMutexLock lock(&m_Mutex);
if (!m_CurrentChannel.Vpid())
m_WaitIFrame = false;
// clear packet
if (!packet)
return -1;
packet->data = NULL;
packet->streamChange = false;
packet->pmtChange = false;
// read TS Packet from buffer
len = m_VideoBuffer->Read(&buf, TS_SIZE, m_endTime, m_wrapTime);
// eof
if (len == -2)
return -2;
else if (len != TS_SIZE)
return -1;
m_Error &= ~ERROR_DEMUX_NODATA;
int ts_pid = TsPid(buf);
// parse PAT/PMT
if (ts_pid == PATPID)
{
m_PatPmtParser.ParsePat(buf, TS_SIZE);
}
#if APIVERSNUM >= 10733
else if (m_PatPmtParser.IsPmtPid(ts_pid))
#else
else if (ts_pid == m_PatPmtParser.PmtPid())
#endif
{
int patVersion, pmtVersion;
m_PatPmtParser.ParsePmt(buf, TS_SIZE);
if (m_PatPmtParser.GetVersions(patVersion, pmtVersion))
{
cChannel pmtChannel(m_CurrentChannel);
SetChannelPids(&pmtChannel, &m_PatPmtParser);
SetChannelStreamInfos(&pmtChannel);
m_PatPmtParser.Reset();
if (EnsureParsers())
{
packet->pmtChange = true;
return 1;
}
}
}
else if (stream = FindStream(ts_pid))
{
int error = stream->ProcessTSPacket(buf, packet, packet_side_data, m_WaitIFrame);
if (error == 0)
{
m_WaitIFrame = false;
m_seenFirstPacket = true;
packet->serial = m_MuxPacketSerial;
if (m_SetRefTime)
{
m_refTime = m_VideoBuffer->GetRefTime();
packet->reftime = m_refTime;
m_SetRefTime = false;
}
return 1;
}
else if (error < 0)
{
m_Error |= abs(error);
if (m_Error & (ERROR_PES_SCRAMBLE | ERROR_TS_SCRAMBLE))
{
if (m_seenFirstPacket)
{
ResetParsers();
m_Error |= ERROR_CAM_ERROR;
m_WaitIFrame = true;
}
}
}
}
return 0;
}
bool cVNSIDemuxer::SeekTime(int64_t time)
{
off_t pos, pos_min, pos_max, pos_limit, start_pos;
int64_t ts, ts_min, ts_max, last_ts;
int no_change;
if (!m_VideoBuffer->HasBuffer())
return false;
cMutexLock lock(&m_Mutex);
// INFOLOG("----- seek to time: %ld", time);
// rescale to 90khz
time = cTSStream::Rescale(time, 90000, DVD_TIME_BASE);
m_VideoBuffer->GetPositions(&pos, &pos_min, &pos_max);
// INFOLOG("----- seek to time: %ld", time);
// INFOLOG("------pos: %ld, pos min: %ld, pos max: %ld", pos, pos_min, pos_max);
if (!GetTimeAtPos(&pos_min, &ts_min))
{
ResetParsers();
m_WaitIFrame = true;
return false;
}
// INFOLOG("----time at min: %ld", ts_min);
if (ts_min >= time)
{
m_VideoBuffer->SetPos(pos_min);
ResetParsers();
m_WaitIFrame = true;
m_MuxPacketSerial++;
return true;
}
int64_t timecur;
GetTimeAtPos(&pos, &timecur);
// get time at end of buffer
unsigned int step= 1024;
bool gotTime;
do
{
pos_max -= step;
gotTime = GetTimeAtPos(&pos_max, &ts_max);
step += step;
} while (!gotTime && pos_max >= step);
if (!gotTime)
{
ResetParsers();
m_WaitIFrame = true;
return false;
}
if (ts_max <= time)
{
ResetParsers();
m_WaitIFrame = true;
m_MuxPacketSerial++;
return true;
}
// INFOLOG(" - time in buffer: %ld", cTSStream::Rescale(ts_max-ts_min, DVD_TIME_BASE, 90000)/1000000);
// bisect seek
if(ts_min > ts_max)
{
ResetParsers();
m_WaitIFrame = true;
return false;
}
else if (ts_min == ts_max)
{
pos_limit = pos_min;
}
else
pos_limit = pos_max;
no_change = 0;
ts = time;
last_ts = 0;
while (pos_min < pos_limit)
{
if (no_change==0)
{
// interpolate position
pos = cTSStream::Rescale(time - ts_min, pos_max - pos_min, ts_max - ts_min)
+ pos_min - (pos_max - pos_limit);
}
else if (no_change==1)
{
// bisection, if interpolation failed to change min or max pos last time
pos = (pos_min + pos_limit) >> 1;
}
else
{
// linear search if bisection failed
pos = pos_min;
}
// clamp calculated pos into boundaries
if( pos <= pos_min)
pos = pos_min + 1;
else if (pos > pos_limit)
pos = pos_limit;
start_pos = pos;
// get time stamp at pos
if (!GetTimeAtPos(&pos, &ts))
{
ResetParsers();
m_WaitIFrame = true;
return false;
}
pos = m_VideoBuffer->GetPosCur();
// determine method for next calculation of pos
if ((last_ts == ts) || (pos >= pos_max))
no_change++;
else
no_change=0;
// INFOLOG("--- pos: %ld, \t time: %ld, diff time: %ld", pos, ts, time-ts);
// 0.4 sec is close enough
if (abs(time - ts) <= 36000)
{
break;
}
// target is to the left
else if (time <= ts)
{
pos_limit = start_pos - 1;
pos_max = pos;
ts_max = ts;
}
// target is to the right
if (time >= ts)
{
pos_min = pos;
ts_min = ts;
}
last_ts = ts;
}
// INFOLOG("----pos found: %ld", pos);
// INFOLOG("----time at pos: %ld, diff time: %ld", ts, cTSStream::Rescale(timecur-ts, DVD_TIME_BASE, 90000));
m_VideoBuffer->SetPos(pos);
ResetParsers();
m_WaitIFrame = true;
m_MuxPacketSerial++;
return true;
}
void cVNSIDemuxer::BufferStatus(bool ×hift, uint32_t &start, uint32_t &end)
{
cMutexLock lock(&m_Mutex);
timeshift = m_VideoBuffer->HasBuffer();
if (timeshift)
{
m_VideoBuffer->GetBufferTime(m_endTime, m_wrapTime);
if (!m_wrapTime)
{
start = m_refTime;
}
else
{
start = m_endTime - (m_wrapTime - m_refTime);
}
end = m_endTime;
}
else
{
start = 0;
end = 0;
}
}
cTSStream *cVNSIDemuxer::GetFirstStream()
{
m_StreamsIterator = m_Streams.begin();
if (m_StreamsIterator != m_Streams.end())
return *m_StreamsIterator;
else
return NULL;
}
cTSStream *cVNSIDemuxer::GetNextStream()
{
++m_StreamsIterator;
if (m_StreamsIterator != m_Streams.end())
return *m_StreamsIterator;
else
return NULL;
}
cTSStream *cVNSIDemuxer::FindStream(int Pid)
{
for (auto *i : m_Streams)
{
if (Pid == i->GetPID())
return i;
}
return NULL;
}
void cVNSIDemuxer::ResetParsers()
{
for (auto *i : m_Streams)
{
i->ResetParser();
}
m_seenFirstPacket = false;
}
static bool Contains(const std::list &list, int pID, eStreamType type)
{
for (const auto &i : list)
if (i.pID == pID && i.type == type)
return true;
return false;
}
bool cVNSIDemuxer::EnsureParsers()
{
bool streamChange = false;
auto it = m_Streams.begin();
while (it != m_Streams.end())
{
if (!Contains(m_StreamInfos, (*it)->GetPID(), (*it)->Type()))
{
INFOLOG("Deleting stream for pid=%i and type=%i", (*it)->GetPID(), (*it)->Type());
it = m_Streams.erase(it);
streamChange = true;
}
else
++it;
}
for (const auto &i : m_StreamInfos)
{
cTSStream *stream = FindStream(i.pID);
if (stream)
{
// TODO: check for change in lang
stream->SetLanguage(i.language);
continue;
}
if (i.type == stH264)
{
stream = new cTSStream(stH264, i.pID, &m_PtsWrap);
}
else if (i.type == stHEVC)
{
stream = new cTSStream(stHEVC, i.pID, &m_PtsWrap);
}
else if (i.type == stMPEG2VIDEO)
{
stream = new cTSStream(stMPEG2VIDEO, i.pID, &m_PtsWrap);
}
else if (i.type == stMPEG2AUDIO)
{
stream = new cTSStream(stMPEG2AUDIO, i.pID, &m_PtsWrap, i.handleRDS);
stream->SetLanguage(i.language);
}
else if (i.type == stAACADTS)
{
stream = new cTSStream(stAACADTS, i.pID, &m_PtsWrap);
stream->SetLanguage(i.language);
}
else if (i.type == stAACLATM)
{
stream = new cTSStream(stAACLATM, i.pID, &m_PtsWrap);
stream->SetLanguage(i.language);
}
else if (i.type == stAC3)
{
stream = new cTSStream(stAC3, i.pID, &m_PtsWrap);
stream->SetLanguage(i.language);
}
else if (i.type == stEAC3)
{
stream = new cTSStream(stEAC3, i.pID, &m_PtsWrap);
stream->SetLanguage(i.language);
}
else if (i.type == stDVBSUB)
{
stream = new cTSStream(stDVBSUB, i.pID, &m_PtsWrap);
stream->SetLanguage(i.language);
#if APIVERSNUM >= 10709
stream->SetSubtitlingDescriptor(i.subtitlingType, i.compositionPageId, i.ancillaryPageId);
#endif
}
else if (i.type == stTELETEXT)
{
stream = new cTSStream(stTELETEXT, i.pID, &m_PtsWrap);
}
else
continue;
m_Streams.push_back(stream);
INFOLOG("Created stream for pid=%i and type=%i", stream->GetPID(), stream->Type());
streamChange = true;
}
m_StreamInfos.clear();
return streamChange;
}
void cVNSIDemuxer::SetChannelStreamInfos(const cChannel *channel)
{
m_StreamInfos.clear();
cStreamInfo newStream;
bool containsVideo = false;
int index = 0;
if (channel->Vpid())
{
newStream.pID = channel->Vpid();
#if APIVERSNUM >= 10701
if (channel->Vtype() == 0x1B)
newStream.type = stH264;
else if (channel->Vtype() == 0x24)
newStream.type = stHEVC;
else
#endif
newStream.type = stMPEG2VIDEO;
m_StreamInfos.push_back(newStream);
containsVideo = true;
}
const int *DPids = channel->Dpids();
index = 0;
for ( ; *DPids; DPids++)
{
newStream.pID = *DPids;
newStream.type = stAC3;
if (channel->Dtype(index) == SI::EnhancedAC3DescriptorTag)
newStream.type = stEAC3;
newStream.SetLanguage(channel->Dlang(index));
m_StreamInfos.push_back(newStream);
index++;
}
const int *APids = channel->Apids();
index = 0;
for ( ; *APids; APids++)
{
newStream.pID = *APids;
newStream.type = stMPEG2AUDIO;
if (channel->Atype(index) == 0x0F)
newStream.type = stAACADTS;
else if (channel->Atype(index) == 0x11)
newStream.type = stAACLATM;
newStream.handleRDS = m_bAllowRDS && newStream.type == stMPEG2AUDIO && !containsVideo ? true : false; // Relevant for RDS, if present only on mpeg 2 audio, use only if RDS is allowed
newStream.SetLanguage(channel->Alang(index));
m_StreamInfos.push_back(newStream);
index++;
}
const int *SPids = channel->Spids();
if (SPids)
{
index = 0;
for ( ; *SPids; SPids++)
{
newStream.pID = *SPids;
newStream.type = stDVBSUB;
newStream.SetLanguage(channel->Slang(index));
newStream.subtitlingType = channel->SubtitlingType(index);
newStream.compositionPageId = channel->CompositionPageId(index);
newStream.ancillaryPageId = channel->AncillaryPageId(index);
m_StreamInfos.push_back(newStream);
}
index++;
}
if (channel->Tpid())
{
newStream.pID = channel->Tpid();
newStream.type = stTELETEXT;
m_StreamInfos.push_back(newStream);
}
}
void cVNSIDemuxer::SetChannelPids(cChannel *channel, cPatPmtParser *patPmtParser)
{
int Apids[MAXAPIDS + 1] = { 0 };
int Atypes[MAXAPIDS + 1] = { 0 };
int Dpids[MAXDPIDS + 1] = { 0 };
int Dtypes[MAXDPIDS + 1] = { 0 };
int Spids[MAXSPIDS + 1] = { 0 };
char ALangs[MAXAPIDS][MAXLANGCODE2] = { 0 };
char DLangs[MAXDPIDS][MAXLANGCODE2] = { 0 };
char SLangs[MAXSPIDS][MAXLANGCODE2] = { 0 };
int index = 0;
const int *aPids = patPmtParser->Apids();
index = 0;
for ( ; *aPids; aPids++)
{
Apids[index] = patPmtParser->Apid(index);
Atypes[index] = patPmtParser->Atype(index);
strn0cpy(ALangs[index], patPmtParser->Alang(index), MAXLANGCODE2);
index++;
}
const int *dPids = patPmtParser->Dpids();
index = 0;
for ( ; *dPids; dPids++)
{
Dpids[index] = patPmtParser->Dpid(index);
Dtypes[index] = patPmtParser->Dtype(index);
strn0cpy(DLangs[index], patPmtParser->Dlang(index), MAXLANGCODE2);
index++;
}
const int *sPids = patPmtParser->Spids();
index = 0;
for ( ; *sPids; sPids++)
{
Spids[index] = patPmtParser->Spid(index);
strn0cpy(SLangs[index], patPmtParser->Slang(index), MAXLANGCODE2);
index++;
}
int Vpid = patPmtParser->Vpid();
int Ppid = patPmtParser->Ppid();
int VType = patPmtParser->Vtype();
int Tpid = m_CurrentChannel.Tpid();
channel->SetPids(Vpid, Ppid, VType,
Apids, Atypes, ALangs,
Dpids, Dtypes, DLangs,
Spids, SLangs,
Tpid);
}
bool cVNSIDemuxer::GetTimeAtPos(off_t *pos, int64_t *time)
{
uint8_t *buf;
int len;
cTSStream *stream;
int ts_pid;
m_VideoBuffer->SetPos(*pos);
ResetParsers();
while ((len = m_VideoBuffer->Read(&buf, TS_SIZE, m_endTime, m_wrapTime)) == TS_SIZE)
{
ts_pid = TsPid(buf);
if (stream = FindStream(ts_pid))
{
// only consider video or audio streams
if ((stream->Content() == scVIDEO || stream->Content() == scAUDIO) &&
stream->ReadTime(buf, time))
{
return true;
}
}
}
return false;
}
uint16_t cVNSIDemuxer::GetError()
{
uint16_t ret = m_Error;
m_Error = ERROR_DEMUX_NODATA;
return ret;
}
vdr-plugin-vnsiserver/videobuffer.c 0000644 0001750 0001750 00000051143 14153173470 017352 0 ustar tobias tobias /*
* vdr-plugin-vnsi - KODI server plugin for VDR
*
* Copyright (C) 2005-2012 Team XBMC
* Copyright (C) 2015 Team KODI
*
* http://kodi.tv
*
* This Program 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, or (at your option)
* any later version.
*
* This Program 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 KODI; see the file COPYING. If not, see
* .
*
*/
#include "videobuffer.h"
#include "config.h"
#include "vnsi.h"
#include "recplayer.h"
#include
#include
#include
#include
#include
#include
#include
class cVideoBufferSimple : public cVideoBuffer
{
friend class cVideoBuffer;
public:
virtual void Put(const uint8_t *buf, unsigned int size);
virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime);
protected:
cVideoBufferSimple();
cRingBufferLinear m_Buffer;
int m_BytesConsumed;
};
cVideoBufferSimple::cVideoBufferSimple()
:m_Buffer(MEGABYTE(5), TS_SIZE * 2, false)
{
m_Buffer.SetTimeouts(0, 100);
m_BytesConsumed = 0;
}
void cVideoBufferSimple::Put(const uint8_t *buf, unsigned int size)
{
m_Buffer.Put(buf, size);
}
int cVideoBufferSimple::ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime)
{
int readBytes;
if (m_BytesConsumed)
{
m_Buffer.Del(m_BytesConsumed);
}
m_BytesConsumed = 0;
*buf = m_Buffer.Get(readBytes);
if (!(*buf) || readBytes < TS_SIZE)
{
usleep(100);
return 0;
}
/* Make sure we are looking at a TS packet */
while (readBytes > TS_SIZE)
{
if ((*buf)[0] == TS_SYNC_BYTE && (*buf)[TS_SIZE] == TS_SYNC_BYTE)
break;
m_BytesConsumed++;
(*buf)++;
readBytes--;
}
if ((*buf)[0] != TS_SYNC_BYTE)
{
m_Buffer.Del(m_BytesConsumed);
m_BytesConsumed = 0;
return 0;
}
m_BytesConsumed += TS_SIZE;
endTime = 0;
wrapTime = 0;
return TS_SIZE;
}
//-----------------------------------------------------------------------------
#define MARGIN 40000
class cVideoBufferTimeshift : public cVideoBuffer
{
friend class cVideoBuffer;
public:
virtual off_t GetPosMin();
virtual off_t GetPosMax();
virtual off_t GetPosCur();
virtual void GetPositions(off_t *cur, off_t *min, off_t *max);
virtual bool HasBuffer() { return true; };
virtual void GetBufferTime(time_t &endTime, time_t &wrapTime);
protected:
cVideoBufferTimeshift();
virtual bool Init() = 0;
virtual off_t Available();
off_t m_BufferSize;
off_t m_WritePtr;
off_t m_ReadPtr;
bool m_BufferFull;
unsigned int m_Margin;
unsigned int m_BytesConsumed;
cMutex m_Mutex;
};
cVideoBufferTimeshift::cVideoBufferTimeshift()
{
m_Margin = TS_SIZE*2;
m_BufferFull = false;
m_ReadPtr = 0;
m_WritePtr = 0;
m_BytesConsumed = 0;
}
off_t cVideoBufferTimeshift::GetPosMin()
{
off_t ret;
if (!m_BufferFull)
return 0;
ret = m_WritePtr + MARGIN * 2;
if (ret >= m_BufferSize)
ret -= m_BufferSize;
return ret;
}
off_t cVideoBufferTimeshift::GetPosMax()
{
off_t ret = m_WritePtr;
if (ret < GetPosMin())
ret += m_BufferSize;
return ret;
}
off_t cVideoBufferTimeshift::GetPosCur()
{
off_t ret = m_ReadPtr;
if (ret < GetPosMin())
ret += m_BufferSize;
return ret;
}
void cVideoBufferTimeshift::GetPositions(off_t *cur, off_t *min, off_t *max)
{
cMutexLock lock(&m_Mutex);
*cur = GetPosCur();
*min = GetPosMin();
*min = (*min > *cur) ? *cur : *min;
*max = GetPosMax();
}
off_t cVideoBufferTimeshift::Available()
{
cMutexLock lock(&m_Mutex);
off_t ret;
if (m_ReadPtr <= m_WritePtr)
ret = m_WritePtr - m_ReadPtr;
else
ret = m_BufferSize - (m_ReadPtr - m_WritePtr);
return ret;
}
void cVideoBufferTimeshift::GetBufferTime(time_t &endTime, time_t &wrapTime)
{
cMutexLock lock(&m_Mutex);
endTime = m_bufferEndTime;
wrapTime = m_bufferWrapTime;
}
//-----------------------------------------------------------------------------
class cVideoBufferRAM : public cVideoBufferTimeshift
{
friend class cVideoBuffer;
public:
virtual void Put(const uint8_t *buf, unsigned int size);
virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime);
virtual void SetPos(off_t pos);
protected:
cVideoBufferRAM();
virtual ~cVideoBufferRAM();
virtual bool Init();
uint8_t *m_Buffer;
uint8_t *m_BufferPtr;
};
cVideoBufferRAM::cVideoBufferRAM()
{
m_Buffer = 0;
}
cVideoBufferRAM::~cVideoBufferRAM()
{
free(m_Buffer);
}
bool cVideoBufferRAM::Init()
{
m_BufferSize = (off_t)TimeshiftBufferSize*100*1000*1000;
INFOLOG("allocated timeshift buffer with size: %ld", m_BufferSize);
m_Buffer = (uint8_t*)malloc(m_BufferSize + m_Margin);
m_BufferPtr = m_Buffer + m_Margin;
if (!m_Buffer)
return false;
else
return true;
}
void cVideoBufferRAM::SetPos(off_t pos)
{
cMutexLock lock(&m_Mutex);
m_ReadPtr = pos;
if (m_ReadPtr >= m_BufferSize)
m_ReadPtr -= m_BufferSize;
m_BytesConsumed = 0;
}
void cVideoBufferRAM::Put(const uint8_t *buf, unsigned int size)
{
if (Available() + MARGIN >= m_BufferSize)
{
return;
}
if ((m_BufferSize - m_WritePtr) <= size)
{
int bytes = m_BufferSize - m_WritePtr;
memcpy(m_BufferPtr+m_WritePtr, buf, bytes);
size -= bytes;
buf += bytes;
cMutexLock lock(&m_Mutex);
m_WritePtr = 0;
}
memcpy(m_BufferPtr+m_WritePtr, buf, size);
cMutexLock lock(&m_Mutex);
m_WritePtr += size;
if (!m_BufferFull)
{
if ((m_WritePtr + 2*MARGIN) > m_BufferSize)
{
m_BufferFull = true;
time(&m_bufferWrapTime);
}
}
time(&m_bufferEndTime);
}
int cVideoBufferRAM::ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime)
{
// move read pointer
if (m_BytesConsumed)
{
cMutexLock lock(&m_Mutex);
m_ReadPtr += m_BytesConsumed;
if (m_ReadPtr >= m_BufferSize)
m_ReadPtr -= m_BufferSize;
endTime = m_bufferEndTime;
wrapTime = m_bufferWrapTime;
}
m_BytesConsumed = 0;
// check if we have anything to read
off_t readBytes = Available();
if (readBytes < m_Margin)
{
return 0;
}
// if we are close to end, copy margin to front
if (m_ReadPtr > (m_BufferSize - m_Margin))
{
int bytesToCopy = m_BufferSize - m_ReadPtr;
memmove(m_Buffer + (m_Margin - bytesToCopy), m_BufferPtr + m_ReadPtr, bytesToCopy);
*buf = m_Buffer + (m_Margin - bytesToCopy);
}
else
*buf = m_BufferPtr + m_ReadPtr;
// Make sure we are looking at a TS packet
while (readBytes > TS_SIZE)
{
if ((*buf)[0] == TS_SYNC_BYTE && (*buf)[TS_SIZE] == TS_SYNC_BYTE)
break;
m_BytesConsumed++;
(*buf)++;
readBytes--;
}
if ((*buf)[0] != TS_SYNC_BYTE)
{
return 0;
}
m_BytesConsumed += TS_SIZE;
return TS_SIZE;
}
//-----------------------------------------------------------------------------
class cVideoBufferFile : public cVideoBufferTimeshift
{
friend class cVideoBuffer;
public:
virtual off_t GetPosMax();
virtual void Put(const uint8_t *buf, unsigned int size);
virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime);
virtual void SetPos(off_t pos);
protected:
cVideoBufferFile();
cVideoBufferFile(int clientID);
virtual ~cVideoBufferFile();
virtual bool Init();
virtual int ReadBytes(uint8_t *buf, off_t pos, unsigned int size);
int m_ClientID;
cString m_Filename;
int m_Fd;
uint8_t *m_ReadCache;
unsigned int m_ReadCachePtr;
unsigned int m_ReadCacheSize;
unsigned int m_ReadCacheMaxSize;
};
cVideoBufferFile::cVideoBufferFile()
{
}
cVideoBufferFile::cVideoBufferFile(int clientID)
{
m_ClientID = clientID;
m_Fd = 0;
m_ReadCacheSize = 0;
m_ReadCache = 0;
}
cVideoBufferFile::~cVideoBufferFile()
{
if (m_Fd)
{
close(m_Fd);
unlink(m_Filename);
m_Fd = 0;
}
if (m_ReadCache)
free(m_ReadCache);
}
bool cVideoBufferFile::Init()
{
m_ReadCache = 0;
m_ReadCacheMaxSize = 32000;
m_ReadCache = (uint8_t*)malloc(m_ReadCacheMaxSize);
if (!m_ReadCache)
return false;
m_BufferSize = (off_t)TimeshiftBufferFileSize*1000*1000*1000;
struct stat sb;
if ((*TimeshiftBufferDir) && stat(TimeshiftBufferDir, &sb) == 0 && S_ISDIR(sb.st_mode))
{
m_Filename = cString::sprintf("%s/Timeshift-%d.vnsi", TimeshiftBufferDir, m_ClientID);
}
else
#if VDRVERSNUM >= 20102
m_Filename = cString::sprintf("%s/Timeshift-%d.vnsi", cVideoDirectory::Name(), m_ClientID);
#else
m_Filename = cString::sprintf("%s/Timeshift-%d.vnsi", VideoDirectory, m_ClientID);
#endif
m_Fd = open(m_Filename, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
if (m_Fd == -1)
{
ERRORLOG("Could not open file: %s", (const char*)m_Filename);
return false;
}
m_WritePtr = lseek(m_Fd, m_BufferSize - 1, SEEK_SET);
if (m_WritePtr == -1)
{
ERRORLOG("(Init) Could not seek file: %s", (const char*)m_Filename);
return false;
}
char tmp = '0';
if (safe_write(m_Fd, &tmp, 1) < 0)
{
ERRORLOG("(Init) Could not write to file: %s", (const char*)m_Filename);
return false;
}
m_WritePtr = 0;
m_ReadPtr = 0;
m_ReadCacheSize = 0;
return true;
}
void cVideoBufferFile::SetPos(off_t pos)
{
cMutexLock lock(&m_Mutex);
m_ReadPtr = pos;
if (m_ReadPtr >= m_BufferSize)
m_ReadPtr -= m_BufferSize;
m_BytesConsumed = 0;
m_ReadCacheSize = 0;
}
off_t cVideoBufferFile::GetPosMax()
{
off_t posMax = cVideoBufferTimeshift::GetPosMax();
if (posMax >= m_ReadCacheMaxSize)
posMax -= m_ReadCacheMaxSize;
else
posMax = 0;
return posMax;
}
void cVideoBufferFile::Put(const uint8_t *buf, unsigned int size)
{
if (Available() + MARGIN >= m_BufferSize)
{
return;
}
if ((m_BufferSize - m_WritePtr) <= size)
{
int bytes = m_BufferSize - m_WritePtr;
int p = 0;
off_t ptr = m_WritePtr;
while(bytes > 0)
{
p = pwrite(m_Fd, buf, bytes, ptr);
if (p < 0)
{
ERRORLOG("Could not write to file: %s", (const char*)m_Filename);
return;
}
size -= p;
bytes -= p;
buf += p;
ptr += p;
}
cMutexLock lock(&m_Mutex);
m_WritePtr = 0;
}
off_t ptr = m_WritePtr;
int bytes = size;
int p;
while(bytes > 0)
{
p = pwrite(m_Fd, buf, bytes, ptr);
if (p < 0)
{
ERRORLOG("Could not write to file: %s", (const char*)m_Filename);
return;
}
bytes -= p;
buf += p;
ptr += p;
}
cMutexLock lock(&m_Mutex);
m_WritePtr += size;
if (!m_BufferFull)
{
if ((m_WritePtr + 2*MARGIN) > m_BufferSize)
{
m_BufferFull = true;
time(&m_bufferWrapTime);
}
}
time(&m_bufferEndTime);
}
int cVideoBufferFile::ReadBytes(uint8_t *buf, off_t pos, unsigned int size)
{
int p;
for (;;)
{
p = pread(m_Fd, buf, size, pos);
if (p < 0 && errno == EINTR)
{
continue;
}
return p;
}
}
int cVideoBufferFile::ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime)
{
// move read pointer
if (m_BytesConsumed)
{
cMutexLock lock(&m_Mutex);
m_ReadPtr += m_BytesConsumed;
if (m_ReadPtr >= m_BufferSize)
m_ReadPtr -= m_BufferSize;
m_ReadCachePtr += m_BytesConsumed;
endTime = m_bufferEndTime;
wrapTime = m_bufferWrapTime;
}
m_BytesConsumed = 0;
// check if we have anything to read
off_t readBytes;
if (m_ReadCacheSize && ((m_ReadCachePtr + m_Margin) <= m_ReadCacheSize))
{
readBytes = m_ReadCacheSize - m_ReadCachePtr;
*buf = m_ReadCache + m_ReadCachePtr;
}
else if ((readBytes = Available()) >= m_ReadCacheMaxSize)
{
if (m_ReadPtr + m_ReadCacheMaxSize <= m_BufferSize)
{
m_ReadCacheSize = ReadBytes(m_ReadCache, m_ReadPtr, m_ReadCacheMaxSize);
if (m_ReadCacheSize < 0)
{
ERRORLOG("Could not read file: %s", (const char*)m_Filename);
return 0;
}
if (m_ReadCacheSize < m_Margin)
{
ERRORLOG("Could not read file (margin): %s , read: %d", (const char*)m_Filename, m_ReadCacheSize);
m_ReadCacheSize = 0;
return 0;
}
readBytes = m_ReadCacheSize;
*buf = m_ReadCache;
m_ReadCachePtr = 0;
}
else
{
m_ReadCacheSize = ReadBytes(m_ReadCache, m_ReadPtr, m_BufferSize - m_ReadPtr);
if ((m_ReadCacheSize < m_Margin) && (m_ReadCacheSize != (m_BufferSize - m_ReadPtr)))
{
ERRORLOG("Could not read file (end): %s", (const char*)m_Filename);
m_ReadCacheSize = 0;
return 0;
}
readBytes = ReadBytes(m_ReadCache + m_ReadCacheSize, 0, m_ReadCacheMaxSize - m_ReadCacheSize);
if (readBytes < 0)
{
ERRORLOG("Could not read file (end): %s", (const char*)m_Filename);
m_ReadCacheSize = 0;
return 0;
}
m_ReadCacheSize += readBytes;
if (m_ReadCacheSize < m_Margin)
{
ERRORLOG("Could not read file (margin): %s", (const char*)m_Filename);
m_ReadCacheSize = 0;
return 0;
}
readBytes = m_ReadCacheSize;
*buf = m_ReadCache;
m_ReadCachePtr = 0;
}
}
else
return 0;
// Make sure we are looking at a TS packet
while (readBytes > TS_SIZE)
{
if ((*buf)[0] == TS_SYNC_BYTE && (*buf)[TS_SIZE] == TS_SYNC_BYTE)
break;
m_BytesConsumed++;
(*buf)++;
readBytes--;
}
if ((*buf)[0] != TS_SYNC_BYTE)
{
return 0;
}
m_BytesConsumed += TS_SIZE;
return TS_SIZE;
}
//-----------------------------------------------------------------------------
class cVideoBufferRecording : public cVideoBufferFile
{
friend class cVideoBuffer;
public:
virtual off_t GetPosMax();
virtual void Put(const uint8_t *buf, unsigned int size);
virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime);
virtual time_t GetRefTime();
protected:
cVideoBufferRecording(const cRecording *rec);
virtual ~cVideoBufferRecording();
virtual bool Init();
virtual off_t Available();
off_t GetPosEnd();
cRecPlayer *m_RecPlayer;
const cRecording *m_Recording;
cTimeMs m_ScanTimer;
};
cVideoBufferRecording::cVideoBufferRecording(const cRecording *rec)
{
m_Recording = rec;
m_ReadCacheSize = 0;
m_ReadCache = 0;
}
cVideoBufferRecording::~cVideoBufferRecording()
{
INFOLOG("delete cVideoBufferRecording");
if (m_RecPlayer)
delete m_RecPlayer;
}
off_t cVideoBufferRecording::GetPosMax()
{
m_RecPlayer->reScan();
m_WritePtr = m_RecPlayer->getLengthBytes();
return cVideoBufferFile::GetPosMax();
}
void cVideoBufferRecording::Put(const uint8_t *buf, unsigned int size)
{
}
bool cVideoBufferRecording::Init()
{
m_ReadCacheMaxSize = 32000;
m_ReadCache = (uint8_t*)malloc(m_ReadCacheMaxSize);
if (!m_ReadCache)
return false;
m_RecPlayer = new cRecPlayer(m_Recording, true);
if (!m_RecPlayer)
return false;
m_WritePtr = 0;
m_ReadPtr = 0;
m_ReadCacheSize = 0;
m_InputAttached = false;
m_ScanTimer.Set(0);
return true;
}
time_t cVideoBufferRecording::GetRefTime()
{
return m_Recording->Start();
}
off_t cVideoBufferRecording::Available()
{
if (m_ScanTimer.TimedOut())
{
m_RecPlayer->reScan();
m_ScanTimer.Set(1000);
}
m_BufferSize = m_WritePtr = m_RecPlayer->getLengthBytes();
return cVideoBufferTimeshift::Available();
}
int cVideoBufferRecording::ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime)
{
// move read pointer
if (m_BytesConsumed)
{
m_ReadPtr += m_BytesConsumed;
if (m_ReadPtr >= m_BufferSize)
{
m_ReadPtr -= m_BufferSize;
ERRORLOG("cVideoBufferRecording::ReadBlock - unknown error");
}
m_ReadCachePtr += m_BytesConsumed;
}
m_BytesConsumed = 0;
// check if we have anything to read
off_t readBytes;
if (m_ReadCacheSize && ((m_ReadCachePtr + m_Margin) <= m_ReadCacheSize))
{
readBytes = m_ReadCacheSize - m_ReadCachePtr;
*buf = m_ReadCache + m_ReadCachePtr;
}
else if ((readBytes = Available()) >= m_ReadCacheMaxSize)
{
if (m_ReadPtr + m_ReadCacheMaxSize <= m_BufferSize)
{
m_ReadCacheSize = m_RecPlayer->getBlock(m_ReadCache, m_ReadPtr, m_ReadCacheMaxSize);
if (m_ReadCacheSize < 0)
{
ERRORLOG("Could not read file, size: %d", m_ReadCacheSize);
m_ReadCacheSize = 0;
return 0;
}
readBytes = m_ReadCacheSize;
*buf = m_ReadCache;
m_ReadCachePtr = 0;
}
else
{
ERRORLOG("cVideoBufferRecording::ReadBlock - unknown error");
return 0;
}
}
else
return 0;
// Make sure we are looking at a TS packet
while (readBytes > TS_SIZE)
{
if ((*buf)[0] == TS_SYNC_BYTE && (*buf)[TS_SIZE] == TS_SYNC_BYTE)
break;
m_BytesConsumed++;
(*buf)++;
readBytes--;
}
if ((*buf)[0] != TS_SYNC_BYTE)
{
return 0;
}
m_BytesConsumed += TS_SIZE;
time(&endTime);
wrapTime = 0;
return TS_SIZE;
}
//-----------------------------------------------------------------------------
class cVideoBufferTest : public cVideoBufferFile
{
friend class cVideoBuffer;
public:
virtual off_t GetPosMax();
virtual void Put(const uint8_t *buf, unsigned int size);
protected:
cVideoBufferTest(cString filename);
virtual ~cVideoBufferTest();
virtual bool Init();
virtual off_t Available();
off_t GetPosEnd();
};
cVideoBufferTest::cVideoBufferTest(cString filename)
{
m_Filename = filename;
m_Fd = 0;
m_ReadCacheSize = 0;
}
cVideoBufferTest::~cVideoBufferTest()
{
if (m_Fd)
{
close(m_Fd);
m_Fd = 0;
}
}
off_t cVideoBufferTest::GetPosMax()
{
m_WritePtr = GetPosEnd();
return cVideoBufferTimeshift::GetPosMax();
}
off_t cVideoBufferTest::GetPosEnd()
{
off_t cur = lseek(m_Fd, 0, SEEK_CUR);
off_t end = lseek(m_Fd, 0, SEEK_END);
lseek(m_Fd, cur, SEEK_SET);
return end;
}
void cVideoBufferTest::Put(const uint8_t *buf, unsigned int size)
{
}
bool cVideoBufferTest::Init()
{
m_ReadCache = 0;
m_ReadCacheMaxSize = 8000;
m_ReadCache = (uint8_t*)malloc(m_ReadCacheMaxSize);
if (!m_ReadCache)
return false;
m_Fd = open(m_Filename, O_RDONLY);
if (m_Fd == -1)
{
ERRORLOG("Could not open file: %s", (const char*)m_Filename);
return false;
}
m_WritePtr = 0;
m_ReadPtr = 0;
m_ReadCacheSize = 0;
m_InputAttached = false;
return true;
}
off_t cVideoBufferTest::Available()
{
m_BufferSize = m_WritePtr = GetPosEnd();
return cVideoBufferTimeshift::Available();
}
//-----------------------------------------------------------------------------
cVideoBuffer::cVideoBuffer()
{
m_CheckEof = false;
m_InputAttached = true;
m_bufferEndTime = 0;
m_bufferWrapTime = 0;
}
cVideoBuffer::~cVideoBuffer()
{
}
cVideoBuffer* cVideoBuffer::Create(int clientID, uint8_t timeshift)
{
// no time shift
if (TimeshiftMode == 0 || timeshift == 0)
{
cVideoBufferSimple *buffer = new cVideoBufferSimple();
return buffer;
}
// buffer in ram
else if (TimeshiftMode == 1)
{
cVideoBufferRAM *buffer = new cVideoBufferRAM();
if (!buffer->Init())
{
delete buffer;
return NULL;
}
else
return buffer;
}
// buffer in file
else if (TimeshiftMode == 2)
{
cVideoBufferFile *buffer = new cVideoBufferFile(clientID);
if (!buffer->Init())
{
delete buffer;
return NULL;
}
else
return buffer;
}
else
return NULL;
}
cVideoBuffer* cVideoBuffer::Create(cString filename)
{
INFOLOG("Open recording: %s", (const char*)filename);
cVideoBufferTest *buffer = new cVideoBufferTest(filename);
if (!buffer->Init())
{
delete buffer;
return NULL;
}
else
return buffer;
}
cVideoBuffer* cVideoBuffer::Create(const cRecording *rec)
{
INFOLOG("Open recording: %s", rec->FileName());
cVideoBufferRecording *buffer = new cVideoBufferRecording(rec);
if (!buffer->Init())
{
delete buffer;
return NULL;
}
else
return buffer;
}
int cVideoBuffer::Read(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime)
{
int count = ReadBlock(buf, size, endTime, wrapTime);
// check for end of file
if (!m_InputAttached && count != TS_SIZE)
{
if (m_CheckEof && m_Timer.TimedOut())
{
INFOLOG("Recoding - end of file");
return -2;
}
else if (!m_CheckEof)
{
m_CheckEof = true;
m_Timer.Set(3000);
}
}
else
m_CheckEof = false;
return count;
}
void cVideoBuffer::AttachInput(bool attach)
{
m_InputAttached = attach;
}
time_t cVideoBuffer::GetRefTime()
{
time_t t;
time(&t);
return t;
}
void cVideoBuffer::GetBufferTime(time_t &endTime, time_t &wrapTime)
{
endTime = 0;
wrapTime = 0;
}
vdr-plugin-vnsiserver/requestpacket.h 0000644 0001750 0001750 00000004226 14153173470 017737 0 ustar tobias tobias /*
* vdr-plugin-vnsi - KODI server plugin for VDR
*
* Copyright (C) 2007 Chris Tallon
* Copyright (C) 2010 Alwin Esch (Team XBMC)
* Copyright (C) 2010, 2011 Alexander Pipelka
* Copyright (C) 2015 Team KODI
*
* http://kodi.tv
*
* This Program 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, or (at your option)
* any later version.
*
* This Program 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 KODI; see the file COPYING. If not, see
* .
*
*/
#ifndef VNSI_REQUESTPACKET_H
#define VNSI_REQUESTPACKET_H
#include
#include
#include
class MalformedVNSIPacket : public std::runtime_error {
public:
MalformedVNSIPacket()
:std::runtime_error("Malformed VNSI packet") {}
};
class cRequestPacket
{
public:
cRequestPacket(uint32_t requestID, uint32_t opcode, uint8_t* data, size_t dataLength);
~cRequestPacket();
size_t getDataLength() const { return userDataLength; }
uint32_t getChannelID() const { return channelID; }
uint32_t getRequestID() const { return requestID; }
uint32_t getStreamID() const { return streamID; }
uint32_t getFlag() const { return flag; }
uint32_t getOpCode() const { return opCode; }
char* extract_String();
uint8_t extract_U8();
uint32_t extract_U32();
uint64_t extract_U64();
int64_t extract_S64();
int32_t extract_S32();
double extract_Double();
bool end() const;
// If you call this, the memory becomes yours. Free with free()
uint8_t* getData();
private:
uint8_t* userData;
size_t userDataLength;
size_t packetPos;
uint32_t opCode;
uint32_t channelID;
uint32_t requestID;
uint32_t streamID;
uint32_t flag; // stream only
};
#endif // VNSI_REQUESTPACKET_H
vdr-plugin-vnsiserver/po/ 0000755 0001750 0001750 00000000000 14153173470 015320 5 ustar tobias tobias vdr-plugin-vnsiserver/po/de_DE.po 0000644 0001750 0001750 00000004236 14153173470 016625 0 ustar tobias tobias # VDR VNSI plugin language source file.
# Copyright (C) 2015 Alwin Esch
# This file is distributed under the same license as the VDR package.
#
msgid ""
msgstr ""
"Project-Id-Version: VNSI-Server 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-08-12 00:35+0200\n"
"PO-Revision-Date: 2015-01-23 21:46+0100\n"
"Last-Translator: Alwin Esch\n"
"Language-Team: German\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-15\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Your scanner version doesnt support services - Please upgrade."
msgstr "Die Version des Scanners unterstützt keine Dienste - Bitte aktualisieren."
msgid "Your scanner version is to old - Please upgrade."
msgstr "Die Version des Scanners ist zu alt - Bitte aktualisieren."
msgid "Off"
msgstr "Aus"
msgid "RAM"
msgstr "RAM"
msgid "File"
msgstr "Datei"
msgid "Time Shift Mode"
msgstr "Time Shift Modus"
msgid "TS Buffersize (RAM) (1-80) x 100MB"
msgstr "TS Puffergröße (RAM) (1-80) x 100MB"
msgid "TS Buffersize (File) (1-10) x 1GB"
msgstr "TS Puffergröße (Datei) (1-10) x 1GB"
msgid "TS Buffer Directory"
msgstr "TS-Puffer-Verzeichnis"
msgid "Play Recording instead of live"
msgstr "Wiedergeben als Aufzeichnung statt Live"
msgid "Group series recordings"
msgstr "Serienaufnahmen gruppieren"
msgid "Avoid EPG scan while streaming"
msgstr "Keine EPG suche während der Wiedergabe durchführen"
msgid "Disable scramble timeout"
msgstr "Entschlüsselungs-Timeout deaktivieren"
msgid "Disable cam blacklist"
msgstr "Cam-Blacklist deaktivieren"
msgid "scene"
msgstr "Szene"
msgid "comskip"
msgstr "Werbung"
msgid "cut"
msgstr "Schnitt"
msgid "EDL Mode"
msgstr "EDL-Modus"
msgid "Recording with the same name exists"
msgstr "Aufnahme mit der selben größe existiert"
msgid "Error while read last filenumber"
msgstr "Fehler beim lesen der letzen Dateinummer"
msgid "Error while accessing vdrfile"
msgstr "Fehler beim zugriff auf VDR-Datei"
msgid "Error while accessing indexfile"
msgstr "Fehler beim Zugriff der Indexdatei"
msgid "Deleted recording vanished"
msgstr "Gelöschte Aufnahme verschwunden"
#~ msgid "PMT Timeout (0-10)"
#~ msgstr "PMT Auszeit (0-10)"
vdr-plugin-vnsiserver/po/lt_LT.po 0000644 0001750 0001750 00000003712 14153173470 016701 0 ustar tobias tobias # VDR VNSI plugin language source file.
# Copyright (C) 2015 Alwin Esch
# This file is distributed under the same license as the VDR package.
#
msgid ""
msgstr ""
"Project-Id-Version: VNSI-Server 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-08-12 00:35+0200\n"
"PO-Revision-Date: 2015-02-11 22:30+0200\n"
"Last-Translator: Valdemaras Pipiras\n"
"Language-Team: Lithuanian\n"
"Language: lt\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Your scanner version doesnt support services - Please upgrade."
msgstr ""
msgid "Your scanner version is to old - Please upgrade."
msgstr ""
msgid "Off"
msgstr "Išjungta"
msgid "RAM"
msgstr "RAM"
msgid "File"
msgstr "Failas"
msgid "Time Shift Mode"
msgstr "Atidėto žiūrėjimo (TS) būsena"
msgid "TS Buffersize (RAM) (1-80) x 100MB"
msgstr "TS buferio dydis (RAM) (1-80) x 100MB"
msgid "TS Buffersize (File) (1-10) x 1GB"
msgstr "TS buferio dydis (Failas) (1-10) x 1GB"
msgid "TS Buffer Directory"
msgstr "TS katalogas buferiavimui"
msgid "Play Recording instead of live"
msgstr "Groti įrašą vietoj gyvos transliacijos"
msgid "Group series recordings"
msgstr ""
msgid "Avoid EPG scan while streaming"
msgstr "Vengti EPG skanavimo kol vyksta transliacija"
msgid "Disable scramble timeout"
msgstr ""
msgid "Disable cam blacklist"
msgstr ""
msgid "scene"
msgstr ""
msgid "comskip"
msgstr ""
msgid "cut"
msgstr ""
msgid "EDL Mode"
msgstr ""
msgid "Recording with the same name exists"
msgstr "Jau yra įrašų tokiu pat pavadinimu"
msgid "Error while read last filenumber"
msgstr "Klaida nuskaitant paskutinių failų skaičių"
msgid "Error while accessing vdrfile"
msgstr "Klaida bandant atidaryti VDR failą"
msgid "Error while accessing indexfile"
msgstr "Klaida bandant atidaryti index failą"
msgid "Deleted recording vanished"
msgstr "Ištrintas įrašas galutinai išvalytas"
#~ msgid "PMT Timeout (0-10)"
#~ msgstr "PMT (0-10)"
vdr-plugin-vnsiserver/recplayer.h 0000644 0001750 0001750 00000004250 14153173470 017042 0 ustar tobias tobias /*
* vdr-plugin-vnsi - KODI server plugin for VDR
*
* Copyright (C) 2004-2005 Chris Tallon
* Copyright (C) 2010 Alwin Esch (Team XBMC)
* Copyright (C) 2010, 2011 Alexander Pipelka
* Copyright (C) 2015 Team KODI
*
* http://kodi.tv
*
* This Program 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, or (at your option)
* any later version.
*
* This Program 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 KODI; see the file COPYING. If not, see
* .
*
*/
/*
* This code is taken from VOMP for VDR plugin.
*/
#ifndef VNSI_RECPLAYER_H
#define VNSI_RECPLAYER_H
#include
#include
#include "config.h"
#include
#include
class cSegment
{
public:
uint64_t start;
uint64_t end;
};
class cRecPlayer
{
public:
cRecPlayer(const cRecording* rec, bool inProgress = false);
~cRecPlayer();
uint64_t getLengthBytes();
uint32_t getLengthFrames();
double getFPS();
int getBlock(unsigned char* buffer, uint64_t position, int amount);
bool openFile(int index);
void closeFile();
void scan();
void reScan();
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:
void cleanup();
char* fileNameFromIndex(int index);
void checkBufferSize(int s);
const bool m_inProgress;
const std::string m_recordingFilename;
const bool m_pesrecording;
cIndexFile m_indexFile;
int m_file;
int m_fileOpen;
char m_fileName[512];
std::vector m_segments;
uint64_t m_totalLength;
uint32_t m_totalFrames;
double m_fps;
};
#endif // VNSI_RECPLAYER_H
vdr-plugin-vnsiserver/vnsiserver/ 0000755 0001750 0001750 00000000000 14153173470 017110 5 ustar tobias tobias vdr-plugin-vnsiserver/vnsiserver/allowed_hosts.conf 0000644 0001750 0001750 00000000725 14153173470 022632 0 ustar tobias tobias #
# allowed_hosts.conf This file describes a number of host addresses that
# are allowed to connect to the streamdev server running
# with the Video Disk Recorder (VDR) on this system.
# Syntax:
#
# IP-Address[/Netmask]
#
127.0.0.1 # always accept localhost
192.168.0.0/24 # any host on the local net
#204.152.189.113 # a specific host
#0.0.0.0/0 # any host on any net (USE THIS WITH CARE!)
vdr-plugin-vnsiserver/bitstream.h 0000644 0001750 0001750 00000003577 14153173470 017061 0 ustar tobias tobias /*
* vdr-plugin-vnsi - KODI server plugin for VDR
*
* Copyright (C) 2010 Alwin Esch (Team XBMC)
* Copyright (C) 2015 Team KODI
*
* http://kodi.tv
*
* This Program 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, or (at your option)
* any later version.
*
* This Program 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 KODI; see the file COPYING. If not, see
* .
*
*/
#ifndef VNSI_BITSTREAM_H
#define VNSI_BITSTREAM_H
#include
#include
class cBitstream
{
private:
uint8_t *const m_data;
size_t m_offset = 0;
const size_t m_len;
bool m_error = false;
const bool m_doEP3 = false;
public:
constexpr cBitstream(uint8_t *data, size_t bits)
:m_data(data), m_len(bits)
{
}
// this is a bitstream that has embedded emulation_prevention_three_byte
// sequences that need to be removed as used in HECV.
// Data must start at byte 2
constexpr cBitstream(uint8_t *data, size_t bits, bool doEP3)
:m_data(data),
m_offset(16), // skip header and use as sentinel for EP3 detection
m_len(bits),
m_doEP3(true)
{
}
void skipBits(unsigned int num);
unsigned int readBits(int num);
unsigned int showBits(int num);
unsigned int readBits1() { return readBits(1); }
unsigned int readGolombUE(int maxbits = 32);
signed int readGolombSE();
constexpr size_t length() const { return m_len; }
constexpr bool isError() const { return m_error; }
};
#endif // VNSI_BITSTREAM_H
vdr-plugin-vnsiserver/recordingscache.h 0000644 0001750 0001750 00000002736 14153173470 020206 0 ustar tobias tobias /*
* vdr-plugin-vnsi - KODI server plugin for VDR
*
* Copyright (C) 2011 Alexander Pipelka
* Copyright (C) 2015 Team KODI
*
* http://kodi.tv
*
* This Program 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, or (at your option)
* any later version.
*
* This Program 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 KODI; see the file COPYING. If not, see
* .
*
*/
#ifndef VNSI_RECORDINGSCACHE_H
#define VNSI_RECORDINGSCACHE_H
#include
#include