summaryrefslogtreecommitdiff
path: root/receiver
diff options
context:
space:
mode:
authorDenis Loh <denis.loh@gmail.com>2010-01-24 21:28:56 +0100
committerDenis Loh <denis.loh@gmail.com>2010-01-24 21:28:56 +0100
commit2103055b5ebfa389a5bec4c98f414608e959bba4 (patch)
tree791b723044ea16551484ed93991687f7530d702f /receiver
parent60db82604cd0ab407e857b9f11d9588f9076333b (diff)
downloadvdr-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.cpp8
-rw-r--r--receiver/filehandle.h108
-rw-r--r--receiver/livereceiver.cpp8
-rw-r--r--receiver/livereceiver.h104
-rw-r--r--receiver/recplayer.cpp168
-rw-r--r--receiver/recplayer.h57
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 */
-