diff options
author | Denis Loh <denis.loh@gmail.com> | 2009-10-24 14:24:17 +0200 |
---|---|---|
committer | Denis Loh <denis.loh@gmail.com> | 2009-10-24 14:24:17 +0200 |
commit | 1cf955a715830130b7add8c1183d65b0f442fd23 (patch) | |
tree | c9d03961e9f83b1100ef6010a4a53063f127aa5d /receiver | |
download | vdr-plugin-upnp-1cf955a715830130b7add8c1183d65b0f442fd23.tar.gz vdr-plugin-upnp-1cf955a715830130b7add8c1183d65b0f442fd23.tar.bz2 |
Initial commit
Diffstat (limited to 'receiver')
-rw-r--r-- | receiver/filehandle.cpp | 8 | ||||
-rw-r--r-- | receiver/filehandle.h | 26 | ||||
-rw-r--r-- | receiver/livereceiver.cpp | 175 | ||||
-rw-r--r-- | receiver/livereceiver.h | 40 | ||||
-rw-r--r-- | receiver/recplayer.cpp | 171 | ||||
-rw-r--r-- | receiver/recplayer.h | 39 |
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 */ + |