diff options
Diffstat (limited to 'recording.c')
-rw-r--r-- | recording.c | 350 |
1 files changed, 349 insertions, 1 deletions
diff --git a/recording.c b/recording.c index c65aaaf..7bc896c 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.62 2002/05/13 16:31:21 kls Exp $ + * $Id: recording.c 1.63 2002/06/16 11:29:27 kls Exp $ */ #include "recording.h" @@ -16,6 +16,7 @@ #include <unistd.h> #include "i18n.h" #include "interface.h" +#include "remux.h" //XXX+ I_FRAME #include "tools.h" #include "videodir.h" @@ -732,3 +733,350 @@ void cRecordingUserCommand::InvokeCommand(const char *State, const char *Recordi delete cmd; } } + +// --- XXX+ + +//XXX+ somewhere else??? +// --- cIndexFile ------------------------------------------------------------ + +#define INDEXFILESUFFIX "/index.vdr" + +// The maximum time to wait before giving up while catching up on an index file: +#define MAXINDEXCATCHUP 2 // seconds + +cIndexFile::cIndexFile(const char *FileName, bool Record) +:resumeFile(FileName) +{ + f = -1; + fileName = NULL; + size = 0; + last = -1; + index = NULL; + if (FileName) { + fileName = new char[strlen(FileName) + strlen(INDEXFILESUFFIX) + 1]; + if (fileName) { + strcpy(fileName, FileName); + char *pFileExt = fileName + strlen(fileName); + strcpy(pFileExt, INDEXFILESUFFIX); + int delta = 0; + if (access(fileName, R_OK) == 0) { + struct stat buf; + if (stat(fileName, &buf) == 0) { + delta = buf.st_size % sizeof(tIndex); + if (delta) { + delta = sizeof(tIndex) - delta; + esyslog("ERROR: invalid file size (%ld) in '%s'", buf.st_size, fileName); + } + last = (buf.st_size + delta) / sizeof(tIndex) - 1; + if (!Record && last >= 0) { + size = last + 1; + index = new tIndex[size]; + if (index) { + f = open(fileName, O_RDONLY); + if (f >= 0) { + if ((int)safe_read(f, index, buf.st_size) != buf.st_size) { + esyslog("ERROR: can't read from file '%s'", fileName); + delete index; + index = NULL; + close(f); + f = -1; + } + // we don't close f here, see CatchUp()! + } + else + LOG_ERROR_STR(fileName); + } + else + esyslog("ERROR: can't allocate %d bytes for index '%s'", size * sizeof(tIndex), fileName); + } + } + else + LOG_ERROR; + } + else if (!Record) + isyslog("missing index file %s", fileName); + if (Record) { + if ((f = open(fileName, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) >= 0) { + if (delta) { + esyslog("ERROR: padding index file with %d '0' bytes", delta); + while (delta--) + writechar(f, 0); + } + } + else + LOG_ERROR_STR(fileName); + } + } + else + esyslog("ERROR: can't copy file name '%s'", FileName); + } +} + +cIndexFile::~cIndexFile() +{ + if (f >= 0) + close(f); + delete fileName; + delete index; +} + +bool cIndexFile::CatchUp(int Index) +{ + if (index && f >= 0) { + for (int i = 0; i <= MAXINDEXCATCHUP && (Index < 0 || Index >= last); i++) { + struct stat buf; + if (fstat(f, &buf) == 0) { + int newLast = buf.st_size / sizeof(tIndex) - 1; + if (newLast > last) { + if (size <= newLast) { + size *= 2; + if (size <= newLast) + size = newLast + 1; + } + index = (tIndex *)realloc(index, size * sizeof(tIndex)); + if (index) { + int offset = (last + 1) * sizeof(tIndex); + int delta = (newLast - last) * sizeof(tIndex); + if (lseek(f, offset, SEEK_SET) == offset) { + if (safe_read(f, &index[last + 1], delta) != delta) { + esyslog("ERROR: can't read from index"); + delete index; + index = NULL; + close(f); + f = -1; + break; + } + last = newLast; + } + else + LOG_ERROR_STR(fileName); + } + else + esyslog("ERROR: can't realloc() index"); + } + } + else + LOG_ERROR_STR(fileName); + if (Index >= last) + sleep(1); + else + return true; + } + } + return false; +} + +bool cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset) +{ + if (f >= 0) { + tIndex i = { FileOffset, PictureType, FileNumber, 0 }; + if (safe_write(f, &i, sizeof(i)) < 0) { + LOG_ERROR_STR(fileName); + close(f); + f = -1; + return false; + } + last++; + } + return f >= 0; +} + +bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType, int *Length) +{ + if (index) { + CatchUp(Index); + if (Index >= 0 && Index <= last) { + *FileNumber = index[Index].number; + *FileOffset = index[Index].offset; + if (PictureType) + *PictureType = index[Index].type; + if (Length) { + int fn = index[Index + 1].number; + int fo = index[Index + 1].offset; + if (fn == *FileNumber) + *Length = fo - *FileOffset; + else + *Length = -1; // this means "everything up to EOF" (the buffer's Read function will act accordingly) + } + return true; + } + } + return false; +} + +int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length, bool StayOffEnd) +{ + if (index) { + CatchUp(); + int d = Forward ? 1 : -1; + for (;;) { + Index += d; + if (Index >= 0 && Index < last - ((Forward && StayOffEnd) ? 100 : 0)) { + if (index[Index].type == I_FRAME) { + if (FileNumber) + *FileNumber = index[Index].number; + else + FileNumber = &index[Index].number; + if (FileOffset) + *FileOffset = index[Index].offset; + else + FileOffset = &index[Index].offset; + if (Length) { + // all recordings end with a non-I_FRAME, so the following should be safe: + int fn = index[Index + 1].number; + int fo = index[Index + 1].offset; + if (fn == *FileNumber) + *Length = fo - *FileOffset; + else { + esyslog("ERROR: 'I' frame at end of file #%d", *FileNumber); + *Length = -1; + } + } + return Index; + } + } + else + break; + } + } + return -1; +} + +int cIndexFile::Get(uchar FileNumber, int FileOffset) +{ + if (index) { + CatchUp(); + //TODO implement binary search! + int i; + for (i = 0; i < last; i++) { + if (index[i].number > FileNumber || (index[i].number == FileNumber) && index[i].offset >= FileOffset) + break; + } + return i; + } + return -1; +} + +// --- cFileName ------------------------------------------------------------- + +#include <errno.h> +#include <unistd.h> +#include "videodir.h" + +#define MAXFILESPERRECORDING 255 +#define RECORDFILESUFFIX "/%03d.vdr" +#define RECORDFILESUFFIXLEN 20 // some additional bytes for safety... + +cFileName::cFileName(const char *FileName, bool Record, bool Blocking) +{ + file = -1; + fileNumber = 0; + record = Record; + blocking = Blocking; + // Prepare the file name: + fileName = new char[strlen(FileName) + RECORDFILESUFFIXLEN]; + if (!fileName) { + esyslog("ERROR: can't copy file name '%s'", fileName); + return; + } + strcpy(fileName, FileName); + pFileNumber = fileName + strlen(fileName); + SetOffset(1); +} + +cFileName::~cFileName() +{ + Close(); + delete fileName; +} + +int cFileName::Open(void) +{ + if (file < 0) { + int BlockingFlag = blocking ? 0 : O_NONBLOCK; + if (record) { + dsyslog("recording to '%s'", fileName); + file = OpenVideoFile(fileName, O_RDWR | O_CREAT | BlockingFlag); + if (file < 0) + LOG_ERROR_STR(fileName); + } + else { + if (access(fileName, R_OK) == 0) { + dsyslog("playing '%s'", fileName); + file = open(fileName, O_RDONLY | BlockingFlag); + if (file < 0) + LOG_ERROR_STR(fileName); + } + else if (errno != ENOENT) + LOG_ERROR_STR(fileName); + } + } + return file; +} + +void cFileName::Close(void) +{ + if (file >= 0) { + if ((record && CloseVideoFile(file) < 0) || (!record && close(file) < 0)) + LOG_ERROR_STR(fileName); + file = -1; + } +} + +int cFileName::SetOffset(int Number, int Offset) +{ + if (fileNumber != Number) + Close(); + if (0 < Number && Number <= MAXFILESPERRECORDING) { + fileNumber = Number; + sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); + if (record) { + if (access(fileName, F_OK) == 0) // file exists, let's try next suffix + return SetOffset(Number + 1); + else if (errno != ENOENT) { // something serious has happened + LOG_ERROR_STR(fileName); + return -1; + } + // found a non existing file suffix + } + if (Open() >= 0) { + if (!record && Offset >= 0 && lseek(file, Offset, SEEK_SET) != Offset) { + LOG_ERROR_STR(fileName); + return -1; + } + } + return file; + } + esyslog("ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING); + return -1; +} + +int cFileName::NextFile(void) +{ + return SetOffset(fileNumber + 1); +} + +const char *IndexToHMSF(int Index, bool WithFrame) +{ + static char buffer[16]; + int f = (Index % FRAMESPERSEC) + 1; + int s = (Index / FRAMESPERSEC); + int m = s / 60 % 60; + int h = s / 3600; + s %= 60; + snprintf(buffer, sizeof(buffer), WithFrame ? "%d:%02d:%02d.%02d" : "%d:%02d:%02d", h, m, s, f); + return buffer; +} + +int HMSFToIndex(const char *HMSF) +{ + int h, m, s, f = 0; + if (3 <= sscanf(HMSF, "%d:%d:%d.%d", &h, &m, &s, &f)) + return (h * 3600 + m * 60 + s) * FRAMESPERSEC + f - 1; + return 0; +} + +int SecondsToFrames(int Seconds) +{ + return Seconds * FRAMESPERSEC; +} |