summaryrefslogtreecommitdiff
path: root/receiver
diff options
context:
space:
mode:
Diffstat (limited to 'receiver')
-rw-r--r--receiver/filehandle.cpp8
-rw-r--r--receiver/filehandle.h26
-rw-r--r--receiver/livereceiver.cpp175
-rw-r--r--receiver/livereceiver.h40
-rw-r--r--receiver/recplayer.cpp171
-rw-r--r--receiver/recplayer.h39
6 files changed, 459 insertions, 0 deletions
diff --git a/receiver/filehandle.cpp b/receiver/filehandle.cpp
new file mode 100644
index 0000000..bc24f53
--- /dev/null
+++ b/receiver/filehandle.cpp
@@ -0,0 +1,8 @@
+/*
+ * File: filehandle.cpp
+ * Author: savop
+ *
+ * Created on 15. Oktober 2009, 10:49
+ */
+
+#include "filehandle.h" \ No newline at end of file
diff --git a/receiver/filehandle.h b/receiver/filehandle.h
new file mode 100644
index 0000000..37f06e8
--- /dev/null
+++ b/receiver/filehandle.h
@@ -0,0 +1,26 @@
+/*
+ * File: filehandle.h
+ * Author: savop
+ *
+ * Created on 15. Oktober 2009, 10:49
+ */
+
+#ifndef _FILEHANDLE_H
+#define _FILEHANDLE_H
+
+#include <upnp/upnp.h>
+#include "../common.h"
+
+class cFileHandle {
+public:
+ virtual void open(UpnpOpenFileMode mode) = 0;
+ virtual int read(char* buf, size_t buflen) = 0;
+ virtual int write(char* buf, size_t buflen) = 0;
+ virtual int seek(off_t offset, int whence) = 0;
+ virtual void close() = 0;
+ virtual ~cFileHandle(){};
+private:
+};
+
+#endif /* _FILEHANDLE_H */
+
diff --git a/receiver/livereceiver.cpp b/receiver/livereceiver.cpp
new file mode 100644
index 0000000..593853f
--- /dev/null
+++ b/receiver/livereceiver.cpp
@@ -0,0 +1,175 @@
+/*
+ * File: livereceiver.cpp
+ * Author: savop
+ *
+ * Created on 4. Juni 2009, 13:28
+ */
+
+#include <vdr/thread.h>
+#include <vdr/remux.h>
+#include <vdr/device.h>
+#include <vdr/channels.h>
+#include <vdr/ringbuffer.h>
+#include "livereceiver.h"
+
+cLiveReceiver* cLiveReceiver::newInstance(cChannel* Channel, int Priority){
+ cDevice *Device = cDevice::GetDevice(Channel, Priority, true);
+
+ if(!Device){
+ ERROR("No matching device found to serve this channel!");
+ return NULL;
+ }
+
+ cLiveReceiver *Receiver = new cLiveReceiver(Channel, Device);
+ if(Receiver){
+ MESSAGE("Receiver for channel \"%s\" created successfully.", Channel->Name());
+ return Receiver;
+ }
+ else {
+ ERROR("Failed to create receiver!");
+ return NULL;
+ }
+}
+
+cLiveReceiver::cLiveReceiver(cChannel *Channel, cDevice *Device)
+: cReceiver( Channel->GetChannelID(), 0, Channel->Vpid(), Channel->Apids(), Channel->Dpids(), Channel->Spids()),
+ mDevice(Device), mChannel(Channel){
+ this->mLiveBuffer = NULL;
+ this->mOutputBuffer = NULL;
+ this->mFrameDetector = NULL;
+}
+
+cLiveReceiver::~cLiveReceiver(void){
+ if(this->IsAttached())
+ this->Detach();
+}
+
+void cLiveReceiver::open(UpnpOpenFileMode){
+ this->mLiveBuffer = new cRingBufferLinear(RECEIVER_LIVEBUFFER_SIZE, RECEIVER_RINGBUFFER_MARGIN, true, "Live TV buffer");
+ this->mOutputBuffer = new cRingBufferLinear(RECEIVER_OUTPUTBUFFER_SIZE, RECEIVER_RINGBUFFER_MARGIN, true, "Streaming buffer");
+
+ this->mLiveBuffer->SetTimeouts(0, 100);
+ this->mOutputBuffer->SetTimeouts(0, 500);
+
+ this->mFrameDetector = new cFrameDetector(this->mChannel->Vpid(), this->mChannel->Vtype());
+
+ this->mPatPmtGenerator.SetChannel(this->mChannel);
+
+ this->mDevice->SwitchChannel(this->mChannel, false);
+ this->mDevice->AttachReceiver(this);
+}
+
+void cLiveReceiver::Activate(bool On){
+ if(On){
+ this->Start();
+ MESSAGE("Live receiver started.");
+ }
+ else {
+ if(this->Running()){
+ this->Cancel(2);
+ }
+ MESSAGE("Live receiver stopped");
+ }
+}
+
+void cLiveReceiver::Receive(uchar* Data, int Length){
+ if(this->Running()){
+ int bytesWrote = this->mLiveBuffer->Put(Data, Length);
+ if(bytesWrote != Length && this->Running()){
+ this->mLiveBuffer->ReportOverflow(Length - bytesWrote);
+ }
+ }
+}
+
+void cLiveReceiver::Action(void){
+ MESSAGE("Started buffering...");
+ while(this->Running()){
+ int bytesRead;
+ //MESSAGE("Buffer is filled with %d bytes", this->mLiveBuffer->Available());
+ uchar* bytes = this->mLiveBuffer->Get(bytesRead);
+ if(bytes){
+ int count = this->mFrameDetector->Analyze(bytes, bytesRead);
+ if(count){
+ //MESSAGE("%d bytes analyzed", count);
+ //MESSAGE("%2.2f FPS", this->mFrameDetector->FramesPerSecond());
+ if(!this->Running() && this->mFrameDetector->IndependentFrame())
+ break;
+ if(this->mFrameDetector->Synced()){
+ //MESSAGE("Frame detector synced to data stream");
+ if(this->mFrameDetector->IndependentFrame()){
+ this->mOutputBuffer->Put(this->mPatPmtGenerator.GetPat(), TS_SIZE);
+ int i = 0;
+ while(uchar* pmt = this->mPatPmtGenerator.GetPmt(i)){
+ this->mOutputBuffer->Put(pmt, TS_SIZE);
+ }
+ }
+ int bytesWrote = this->mOutputBuffer->Put(bytes, count);
+ if(bytesWrote != count){
+ this->mLiveBuffer->ReportOverflow(count - bytesWrote);
+ }
+ //MESSAGE("Wrote %d to output buffer", bytesWrote);
+ if(bytesWrote){
+ this->mLiveBuffer->Del(bytesWrote);
+ }
+ else {
+ cCondWait::SleepMs(100);
+ }
+ }
+ else {
+ ERROR("Cannot sync to stream");
+ }
+ }
+ }
+ }
+ MESSAGE("Receiver was detached from device");
+}
+
+int cLiveReceiver::read(char* buf, size_t buflen){
+ int bytesRead;
+ if(!this->IsAttached())
+ bytesRead = -1;
+ else {
+ while(!this->mOutputBuffer->Available()){
+ WARNING("No data, waiting...");
+ cCondWait::SleepMs(50);
+ if(!this->IsAttached()){
+ MESSAGE("Lost device...");
+ return 0;
+ }
+ }
+
+ uchar* buffer = this->mOutputBuffer->Get(bytesRead);
+ if(buffer){
+ if(buflen > (size_t)bytesRead){
+ memcpy(buf,(char*)buffer,bytesRead);
+ this->mOutputBuffer->Del(bytesRead);
+ }
+ else {
+ memcpy(buf,(char*)buffer,buflen);
+ this->mOutputBuffer->Del(buflen);
+ }
+ }
+
+ }
+ MESSAGE("Read %d bytes from live feed", bytesRead);
+ return bytesRead;
+}
+
+int cLiveReceiver::seek(off_t, int){
+ ERROR("Seeking not supported on broadcasts");
+ return 0;
+}
+
+int cLiveReceiver::write(char*, size_t){
+ ERROR("Writing not allowed on broadcasts");
+ return 0;
+}
+
+void cLiveReceiver::close(){
+ MESSAGE("Closing live receiver");
+ this->Detach();
+ delete this->mOutputBuffer; this->mOutputBuffer = NULL;
+ delete this->mLiveBuffer; this->mLiveBuffer = NULL;
+ this->mFrameDetector = NULL;
+ MESSAGE("Live receiver closed.");
+} \ No newline at end of file
diff --git a/receiver/livereceiver.h b/receiver/livereceiver.h
new file mode 100644
index 0000000..4632733
--- /dev/null
+++ b/receiver/livereceiver.h
@@ -0,0 +1,40 @@
+/*
+ * File: livereceiver.h
+ * Author: savop
+ *
+ * Created on 4. Juni 2009, 13:28
+ */
+
+#ifndef _LIVERECEIVER_H
+#define _LIVERECEIVER_H
+
+#include "../common.h"
+#include "filehandle.h"
+#include <vdr/thread.h>
+#include <vdr/receiver.h>
+
+class cLiveReceiver : public cReceiver, public cThread, public cFileHandle {
+public:
+ static cLiveReceiver* newInstance(cChannel *Channel, int Priority);
+ virtual ~cLiveReceiver(void);
+ virtual void open(UpnpOpenFileMode mode);
+ virtual int read(char* buf, size_t buflen);
+ virtual int write(char* buf, size_t buflen);
+ virtual int seek(off_t offset, int whence);
+ virtual void close();
+protected:
+ virtual void Receive(uchar *Data, int Length);
+ virtual void Activate(bool On);
+ virtual void Action(void);
+private:
+ cLiveReceiver(cChannel *Channel, cDevice *Device);
+ cDevice *mDevice;
+ cChannel *mChannel;
+ cRingBufferLinear *mLiveBuffer;
+ cRingBufferLinear *mOutputBuffer;
+ cFrameDetector *mFrameDetector;
+ cPatPmtGenerator mPatPmtGenerator;
+};
+
+#endif /* _LIVERECEIVER_H */
+
diff --git a/receiver/recplayer.cpp b/receiver/recplayer.cpp
new file mode 100644
index 0000000..d968ae7
--- /dev/null
+++ b/receiver/recplayer.cpp
@@ -0,0 +1,171 @@
+/*
+ * File: recplayer.cpp
+ * Author: savop
+ *
+ * Created on 8. Juni 2009, 11:57
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <vdr/recording.h>
+#include <vdr/tools.h>
+#include "recplayer.h"
+
+cRecordingPlayer *cRecordingPlayer::newInstance(cRecording* Recording){
+ if(Recording->IsPesRecording()){
+ ERROR("Sorry, but only TS is supported, yet!");
+ return NULL;
+ }
+
+ cRecordingPlayer *Player = new cRecordingPlayer(Recording);
+ return Player;
+}
+cRecordingPlayer::~cRecordingPlayer() {
+ delete this->mOffsets;
+}
+
+cRecordingPlayer::cRecordingPlayer(cRecording *Recording) {
+ MESSAGE("Created Recplayer");
+ this->mFile = NULL;
+ this->mTotalLenght = 0;
+ this->mRecording = Recording;
+ this->mOffsets = new off_t[VDR_MAX_FILES_PER_RECORDING];
+ this->mOffset = 0;
+ this->mIndex = 1;
+
+}
+
+void cRecordingPlayer::open(UpnpOpenFileMode){
+ this->Scan();
+}
+
+void cRecordingPlayer::close(){
+ delete [] this->mOffsets;
+ if(this->mFile) fclose(this->mFile);
+}
+
+int cRecordingPlayer::write(char*, size_t){
+ ERROR("Writing not allowed on recordings");
+ return 0;
+}
+
+int cRecordingPlayer::read(char* buf, size_t buflen){
+ FILE *File;
+ off_t fileEndOffset = this->mOffsets[this->mIndex];
+ if(this->mOffset > fileEndOffset){
+ File = this->NextFile();
+ }
+ else {
+ File = this->GetFile();
+ }
+ // do not read more bytes than the actual file has
+ size_t bytesToRead = ((fileEndOffset - this->mOffset) < (off_t)buflen)? fileEndOffset - this->mOffset : buflen;
+ size_t bytesRead = fread((char*)buf, sizeof(char), bytesToRead, File);
+
+ this->mOffset += (off_t)bytesRead;
+
+ return (int)bytesRead;
+}
+
+int cRecordingPlayer::seek(off_t offset, int origin){
+ // Calculate the new offset
+ switch(origin){
+ case SEEK_CUR:
+ if(this->mOffset + offset > this->mTotalLenght){
+ ERROR("Can't read behind end of file!");
+ return -1;
+ }
+ this->mOffset += (off_t)offset;
+ break;
+ case SEEK_END:
+ if(offset > 0){
+ ERROR("Can't read behind end of file!");
+ return -1;
+ }
+ this->mOffset = this->mTotalLenght + offset;
+ break;
+ case SEEK_SET:
+ if(offset > this->mTotalLenght){
+ ERROR("Can't read behind end of file!");
+ return -1;
+ }
+ this->mOffset = (off_t)offset;
+ break;
+ default:
+ ERROR("Unknown seek mode (%d)!", origin);
+ return -1;
+ }
+ // Seek to the very first file;
+ this->SeekInFile(1,0);
+ off_t fileEndOffset = this->mOffsets[this->mIndex];
+ // Spin until the new offset is in range of a specific file
+ while(this->mOffset > (fileEndOffset = this->mOffsets[this->mIndex])){
+ // If its not possible to switch to next file, there was an error
+ if(!this->NextFile()){
+ ERROR("Offset %ld not in the range of a file!", offset);
+ return -1;
+ }
+ }
+ off_t relativeOffset =
+ this->mOffset - (this->mOffsets[this->mIndex-1])
+ ? this->mOffsets[this->mIndex-1]
+ : 0;
+ if(!this->SeekInFile(this->mIndex, relativeOffset)){
+ ERROR("Cannot set offset!");
+ return -1;
+ }
+ return 0;
+}
+
+void cRecordingPlayer::Scan(){
+ MESSAGE("Scanning video files...");
+ // Reset the offsets
+ int i = 1;
+ while(this->mOffsets[i++]) this->mOffsets[i] = 0;
+ MESSAGE("Offsets reseted.");
+
+ i = 0;
+ FILE *File;
+ while((File = this->GetFile(i))){
+ if(VDR_MAX_FILES_PER_RECORDING < i+1){
+ ERROR("Maximum file offsets exceeded!");
+ break;
+ }
+ fseek(File, 0, SEEK_END);
+ off_t offset = ftell(File);
+ MESSAGE("File %d has its last offset at %ld", i, offset);
+ this->mOffsets[i+1] = this->mOffsets[i] + offset;
+ this->mTotalLenght = this->mOffsets[i+1];
+ i++;
+ }
+}
+
+FILE *cRecordingPlayer::GetFile(int Index){
+ // No Index given: set current index
+ if(Index == 0) Index = this->mIndex;
+ // Index not changed: return current file
+ if(this->mIndex == Index && this->mFile) return this->mFile;
+
+ // Index changed: close open file and open new file
+ if(this->mFile) fclose(this->mFile);
+ char *filename = new char[VDR_FILENAME_BUFSIZE];
+ snprintf(filename, VDR_FILENAME_BUFSIZE, VDR_RECORDFILE_PATTERN_TS, this->mRecording->FileName(), Index );
+ MESSAGE("Filename: %s", filename);
+ this->mFile = NULL;
+ if(this->mFile = fopen(filename, "r")){
+ this->mIndex = Index;
+ return this->mFile;
+ }
+ return NULL;
+}
+
+FILE *cRecordingPlayer::NextFile(void){
+ return this->GetFile(this->mIndex++);
+}
+
+int cRecordingPlayer::SeekInFile(int Index, off_t Offset){
+ FILE *File = this->GetFile(Index);
+ fseek(File, Offset, SEEK_SET);
+ return ftell(File);
+}
+
diff --git a/receiver/recplayer.h b/receiver/recplayer.h
new file mode 100644
index 0000000..8295539
--- /dev/null
+++ b/receiver/recplayer.h
@@ -0,0 +1,39 @@
+/*
+ * File: recplayer.h
+ * Author: savop
+ *
+ * Created on 8. Juni 2009, 11:57
+ */
+
+#ifndef _RECPLAYER_H
+#define _RECPLAYER_H
+
+#include "../common.h"
+#include "filehandle.h"
+#include <vdr/recording.h>
+
+class cRecordingPlayer : cFileHandle {
+public:
+ static cRecordingPlayer *newInstance(cRecording *Recording);
+ virtual ~cRecordingPlayer();
+ virtual void open(UpnpOpenFileMode mode);
+ virtual int read(char* buf, size_t buflen);
+ virtual int write(char* buf, size_t buflen);
+ virtual int seek(off_t offset, int origin);
+ virtual void close();
+private:
+ void Scan(void);
+ cRecordingPlayer(cRecording *Recording);
+ FILE* GetFile(int Index = 0);
+ FILE* NextFile(void);
+ int SeekInFile(int Index, off_t Offset);
+ cRecording *mRecording;
+ off_t* mOffsets;
+ off_t mOffset;
+ off_t mTotalLenght;
+ int mIndex;
+ FILE *mFile;
+};
+
+#endif /* _RECPLAYER_H */
+