diff options
author | Denis Loh <denis.loh@gmail.com> | 2010-01-24 21:28:56 +0100 |
---|---|---|
committer | Denis Loh <denis.loh@gmail.com> | 2010-01-24 21:28:56 +0100 |
commit | 2103055b5ebfa389a5bec4c98f414608e959bba4 (patch) | |
tree | 791b723044ea16551484ed93991687f7530d702f /receiver | |
parent | 60db82604cd0ab407e857b9f11d9588f9076333b (diff) | |
download | vdr-plugin-upnp-2103055b5ebfa389a5bec4c98f414608e959bba4.tar.gz vdr-plugin-upnp-2103055b5ebfa389a5bec4c98f414608e959bba4.tar.bz2 |
Added (finally) the record streaming function and some other things
Diffstat (limited to 'receiver')
-rw-r--r-- | receiver/filehandle.cpp | 8 | ||||
-rw-r--r-- | receiver/filehandle.h | 108 | ||||
-rw-r--r-- | receiver/livereceiver.cpp | 8 | ||||
-rw-r--r-- | receiver/livereceiver.h | 104 | ||||
-rw-r--r-- | receiver/recplayer.cpp | 168 | ||||
-rw-r--r-- | receiver/recplayer.h | 57 |
6 files changed, 66 insertions, 387 deletions
diff --git a/receiver/filehandle.cpp b/receiver/filehandle.cpp deleted file mode 100644 index bc24f53..0000000 --- a/receiver/filehandle.cpp +++ /dev/null @@ -1,8 +0,0 @@ -/* - * 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 deleted file mode 100644 index 1dc57bf..0000000 --- a/receiver/filehandle.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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" - -/** - * Interface for File Handles - * - * This class is a pure virtual class to act as an interface for file handles - * used by the webserver. - */ -class cFileHandle { -public: - /** - * Opens the file - * - * Opens the file at the given mode. These can be: - * - \b UPNP_READ, to read from the file - * - \b UPNP_WRITE, to write to the file - * - * @param mode The file mode, i.e. one of the following - * - \b UPNP_READ - * - \b UPNP_WRITE - */ - virtual void open( - UpnpOpenFileMode mode ///< The file mode, i.e. one of the following - ///< - \b UPNP_READ - ///< - \b UPNP_WRITE - ) = 0; - /** - * Reads from the file - * - * Reads from the file a certain amount of bytes and stores them in a buffer - * - * @return returns - * - \b <0, in case of an error - * - \b 0, when reading was successful - * - * @param buf The char buffer - * @param buflen The size of the buffer - */ - virtual int read( - char* buf, ///< The char buffer - size_t buflen ///< The size of the buffer - ) = 0; - /** - * Writes to the file - * - * Writes to the file a certain amount of bytes which are stored in a buffer - * - * @return returns - * - \b <0, in case of an error - * - \b 0, when reading was successful - * - * @param buf The char buffer - * @param buflen The size of the buffer - */ - virtual int write( - char* buf, ///< The char buffer - size_t buflen ///< The size of the buffer - ) = 0; - /** - * Seeks in the file - * - * Seeks in the file where the offset is the relativ position depending on - * the second parameter. This means, in case of - * - * - \b SEEK_SET, the offset is relative to the beginning of the file - * - \b SEEK_CUR, it is relative to the current position or - * - \b SEEK_END, relative to the end of the file. - * - * @return returns - * - \b <0, in case of an error - * - \b 0, when reading was successful - * - * @param offset The byte offset in the file - * @param whence one of the following - * - \b SEEK_SET, - * - \b SEEK_CUR, - * - \b SEEK_END - */ - virtual int seek( - off_t offset, ///< The byte offset in the file - int whence ///< one of the following - ///< - \b SEEK_SET, - ///< - \b SEEK_CUR, - ///< - \b SEEK_END - ) = 0; - /** - * Closes the open file - * - * This will close open file handles and frees the memory obtained by it. - */ - virtual void close() = 0; - virtual ~cFileHandle(){}; -private: -}; - -#endif /* _FILEHANDLE_H */ - diff --git a/receiver/livereceiver.cpp b/receiver/livereceiver.cpp index 8ca560f..a43d197 100644 --- a/receiver/livereceiver.cpp +++ b/receiver/livereceiver.cpp @@ -125,14 +125,18 @@ void cLiveReceiver::Action(void){ } int cLiveReceiver::read(char* buf, size_t buflen){ - int bytesRead; + int bytesRead = 0; if(!this->IsAttached()) bytesRead = -1; else { int WaitTimeout = RECEIVER_WAIT_ON_NODATA_TIMEOUT; // Wait until the buffer size is at least half the requested buffer length - while((unsigned)this->mOutputBuffer->Available() < (buflen / 2) ){ + + double MinBufSize = buflen * RECEIVER_MIN_BUFFER_FILLAGE/100; + int Available = 0; + while((double)(Available = this->mOutputBuffer->Available()) < MinBufSize){ WARNING("Too few data, waiting..."); + WARNING("Only %d bytes available, need %10f more bytes.", Available, (double)(MinBufSize-Available)); cCondWait::SleepMs(RECEIVER_WAIT_ON_NODATA); if(!this->IsAttached()){ MESSAGE(VERBOSE_LIVE_TV, "Lost device..."); diff --git a/receiver/livereceiver.h b/receiver/livereceiver.h deleted file mode 100644 index 92fe140..0000000 --- a/receiver/livereceiver.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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> -#include <vdr/ringbuffer.h> - -#define RECEIVER_WAIT_ON_NODATA 50 // 50 ms -#define RECEIVER_WAIT_ON_NODATA_TIMEOUT 1000 * 2 // 2s - -/** - * A receiver for live TV - * - * This is a receiver object which is attached to a VDR tv card device. - * It is receiving transport stream packages and generates a single MPEG2 - * transport stream which can be distributed through the network. - * - */ -class cLiveReceiver : public cReceiver, public cThread, public cFileHandle { -public: - /** - * Creates a new receiver instance - * - * This will create a new instance of a live receiver for the specified - * channel at the specified priority level. - * - * A negativ priority means that the receiver may being detached from a - * device. - * - * The receiver must be free'd with delete after it is not used anylonger. - * - * @return returns a new liveReceiver instance - */ - static cLiveReceiver* newInstance( - cChannel *Channel, ///< the channel which shall be tuned - int Priority ///< the priority level - ); - virtual ~cLiveReceiver(void); - /*! @copydoc cFileHandle::open(UpnpOpenFileMode) */ - virtual void open(UpnpOpenFileMode mode); - /*! @copydoc cFileHandle::read(char*,size_t) */ - virtual int read(char* buf, size_t buflen); - /*! @copydoc cFileHandle::write(char*,size_t) */ - virtual int write(char* buf, size_t buflen); - /*! @copydoc cFileHandle::seek(off_t,int) */ - virtual int seek(off_t offset, int whence); - /*! @copydoc cFileHandle::close() */ - virtual void close(); -protected: - /** - * Receives data from VDR - * - * This is the interface for receiving packet data from the VDR. It buffers - * the incoming transport stream packets in a linear ringbuffer and returns - * immediatelly - */ - virtual void Receive( - uchar *Data, ///< The data received from VDR - int Length ///< The length of the data packet, usually 188 bytes - ); - /** - * Activates the receiver - * - * This activates the receiver which initializes internal data structures to - * be prepared for receiving data from the VDR - * - * If the parameter is \bc true, the receiver will be activated. If it is - * \bc false, the receiver will be deactivated and stops its threads. - */ - virtual void Activate( - bool On ///< Activates the receiver thread - ); - /** - * The receiver thread action - * - * This actually is the receiver thread, which runs consequitivelly and - * buffers any received video data from the interal incoming buffer to the - * internal outgoing buffer. - * - * While doing so, it tries to syncronize with the stream and creates new - * MPEG2-TS PATs and PMTs for a single MPEG2-TS stream - */ - 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 index 954c9c8..8bf73d4 100644 --- a/receiver/recplayer.cpp +++ b/receiver/recplayer.cpp @@ -21,27 +21,31 @@ cRecordingPlayer *cRecordingPlayer::newInstance(cRecording* Recording){ return Player; } cRecordingPlayer::~cRecordingPlayer() { - delete this->mOffsets; + delete this->mRecordingFile; + delete [] this->mLastOffsets; } -cRecordingPlayer::cRecordingPlayer(cRecording *Recording) { +cRecordingPlayer::cRecordingPlayer(cRecording *Recording) : mRecording(Recording) { MESSAGE(VERBOSE_SDK, "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; - + + this->mRecordingFile = new cFileName(this->mRecording->FileName(), false, false, this->mRecording->IsPesRecording()); + this->mLastOffsets = new off_t[((this->mRecording->IsPesRecording())?VDR_MAX_FILES_PER_PESRECORDING:VDR_MAX_FILES_PER_TSRECORDING)+1]; + this->scanLastOffsets(); } void cRecordingPlayer::open(UpnpOpenFileMode){ - this->Scan(); + // Open() does not work?! + this->mCurrentFile = this->mRecordingFile->SetOffset(1); + if(this->mCurrentFile){ + MESSAGE(VERBOSE_RECORDS, "Record player opened"); + } + else { + ERROR("Error while opening record player file"); + } } void cRecordingPlayer::close(){ - delete [] this->mOffsets; - if(this->mFile) fclose(this->mFile); + this->mRecordingFile->Close(); } int cRecordingPlayer::write(char*, size_t){ @@ -50,122 +54,70 @@ int cRecordingPlayer::write(char*, size_t){ } int cRecordingPlayer::read(char* buf, size_t buflen){ - FILE *File; - off_t fileEndOffset = this->mOffsets[this->mIndex]; - if(this->mOffset > fileEndOffset){ - File = this->NextFile(); + if(!this->mCurrentFile){ + ERROR("Current part of record is not open"); + return -1; } - else { - File = this->GetFile(); + MESSAGE(VERBOSE_RECORDS, "Reading %d from record", buflen); + int bytesread = 0; + while((bytesread = this->mCurrentFile->Read(buf, buflen)) == 0){ // EOF, try next file + if(!(this->mCurrentFile = this->mRecordingFile->NextFile())){ + // no more files to read... finished! + break; + } } - // 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; + return bytesread; } int cRecordingPlayer::seek(off_t offset, int origin){ - // Calculate the new offset + if(!this->mCurrentFile){ + ERROR("Current part of record is not open"); + return -1; + } + + MESSAGE(VERBOSE_RECORDS, "Seeking..."); + + off_t relativeOffset; + off_t curpos = this->mCurrentFile->Seek(0, SEEK_CUR); // this should not change anything + int index; + // recalculate the absolute position in the record 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; + offset = this->mLastOffsets[this->mLastFileNumber] + offset; + break; + case SEEK_CUR: + offset = this->mLastOffsets[this->mRecordingFile->Number()-1] + curpos + offset; break; case SEEK_SET: - if(offset > this->mTotalLenght){ - ERROR("Can't read behind end of file!"); - return -1; - } - this->mOffset = (off_t)offset; + // Nothing to change break; default: - ERROR("Unknown seek mode (%d)!", origin); + ERROR("Seek operation invalid"); 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 %lld not in the range of a file!", offset); - return -1; + // finally, we can seek + // TODO: binary search + for(index = 1; this->mLastOffsets[index]; index++){ + if(this->mLastOffsets[index-1] <= offset && offset <= this->mLastOffsets[index]){ + relativeOffset = offset - this->mLastOffsets[index-1]; + break; } } - 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!"); + if(!(this->mCurrentFile = this->mRecordingFile->SetOffset(index, relativeOffset))){ + // seeking failed!!! should never happen. + this->mCurrentFile = this->mRecordingFile->SetOffset(1); return -1; } - return 0; -} -void cRecordingPlayer::Scan(){ - MESSAGE(VERBOSE_RECORDS, "Scanning video files..."); - // Reset the offsets - int i = 1; - while(this->mOffsets[i++]) this->mOffsets[i] = 0; - MESSAGE(VERBOSE_RECORDS, "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(VERBOSE_RECORDS, "File %d has its last offset at %lld", i, offset); - this->mOffsets[i+1] = this->mOffsets[i] + offset; - this->mTotalLenght = this->mOffsets[i+1]; - i++; - } + return 0; } -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(VERBOSE_BUFFERS, "Filename: %s", filename); - this->mFile = NULL; - if(this->mFile = fopen(filename, "r")){ - this->mIndex = Index; - return this->mFile; +void cRecordingPlayer::scanLastOffsets(){ + // rewind + this->mCurrentFile = this->mRecordingFile->SetOffset(1); + for(int i = 1; (this->mCurrentFile = this->mRecordingFile->NextFile()); i++){ + this->mLastOffsets[i] = this->mLastOffsets[i-1] + this->mCurrentFile->Seek(0, SEEK_END); + this->mLastFileNumber = this->mRecordingFile->Number(); } - 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 deleted file mode 100644 index a2e69ac..0000000 --- a/receiver/recplayer.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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> - -/** - * The recording player - * - * This class provides the ability to play VDR records. The difference between - * usual files and VDR recording files is, that recordings are possibly splitted - * into multiple files. The class will scan those files and tries to dynamically - * navigate in them like it would do, if it is a single file. - * - */ -class cRecordingPlayer : cFileHandle { -public: - /** - * Get a new instance of a recording player - * - * This returns a new instance of a recording player which plays the - * specified VDR recording. - * - * @param Recording the recording to play - * @return the new instance of the recording player - */ - 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 */ - |