summaryrefslogtreecommitdiff
path: root/recording.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <Klaus (dot) Schmidinger (at) tvdr (dot) de>2009-11-22 15:58:00 +0100
committerKlaus Schmidinger <Klaus (dot) Schmidinger (at) tvdr (dot) de>2009-11-22 15:58:00 +0100
commitea01358b3bca9d55402ba632c95cdd6458abfdb3 (patch)
tree3a92e952e0c8de3cf109748da749b2841fed0da0 /recording.c
parent06bf4c453e22a9bf03f5ec46f7b45593e2cb326c (diff)
downloadvdr-patches-ea01358b3bca9d55402ba632c95cdd6458abfdb3.tar.gz
vdr-patches-ea01358b3bca9d55402ba632c95cdd6458abfdb3.tar.bz2
Version 1.7.10
- Updated the Italian OSD texts (thanks to Diego Pierotto). - Fixed wrong bracketing in cChannel::SubtitlingType() etc. (thanks to Rolf Ahrenberg). - Fixed not logging changes for channels that have no number (reported by Timothy D. Lenz). - Changed the project's URLs and email to tvdr.de. - Added Lithuanian language translations (thanks to Valdemaras Pipiras). - Updated Chinese language texts (thanks to Nan Feng). - Only checking DVB_API_VERSION to be >=5 in order to stay compileable in case the DVB API version number is increased (the API claims to always be backward compatible). - Fixed saving terminal settings when running in background (thanks to Manuel Reimer). - Fixed cFrameDetector::Analyze() to handle video streams where the frame type is not detectable from the first TS packet of a frame. - Fixed writing the PCR pid into the PMT in cPatPmtGenerator::GeneratePmt() (reported by Rene van den Braken). - Added Slovakian language texts (thanks to Milan Hrala). - Fixed EntriesOnSameFileSystem() to avoid using f_fsid, which may be 0 (thanks to Frank Schmirler). - Fixed starting a recording at an I-frame. - Fixed generating the index for recordings from channels that put a whole GOP into one payload unit. - The index file for TS recordings is now regenerated on-the-fly if a recording is replayed that has no index. This can also be used to re-create a broken index file by manually deleting the index file and then replaying the recording (at least until the index file has been generated). - The cRingBufferLinear::Read() function now returns -1 and sets errno to EAGAIN if the buffer is already full. - Fixed handling DVB subtitles for PES recordings (thanks to Rolf Ahrenberg). - Added the audio id to the call of PlayAudio() in cDevice::PlayTsAudio() (thanks to Andreas Schaefers). - Fixed references to old *.vdr file names in MANUAL (reported by Arthur Konovalov). - Reverted "Removed limitation to PAL resolution from SPU handling" because it cause nothing but trouble. Besides, the core VDR doesn't use this, anyway. - Fixed the default value for "Pause key handling" in the MANUAL (reported by Diego Pierotto).
Diffstat (limited to 'recording.c')
-rw-r--r--recording.c150
1 files changed, 149 insertions, 1 deletions
diff --git a/recording.c b/recording.c
index f3c2c5a..ab94c32 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 2.17 2009/08/16 10:39:43 kls Exp $
+ * $Id: recording.c 2.18 2009/11/22 11:20:53 kls Exp $
*/
#include "recording.h"
@@ -21,6 +21,7 @@
#include "i18n.h"
#include "interface.h"
#include "remux.h"
+#include "ringbuffer.h"
#include "skins.h"
#include "tools.h"
#include "videodir.h"
@@ -1309,6 +1310,124 @@ void cRecordingUserCommand::InvokeCommand(const char *State, const char *Recordi
}
}
+// --- cIndexFileGenerator ---------------------------------------------------
+
+#define IFG_BUFFER_SIZE KILOBYTE(100)
+
+class cIndexFileGenerator : public cThread {
+private:
+ cString recordingName;
+protected:
+ virtual void Action(void);
+public:
+ cIndexFileGenerator(const char *RecordingName);
+ ~cIndexFileGenerator();
+ };
+
+cIndexFileGenerator::cIndexFileGenerator(const char *RecordingName)
+:cThread("index file generator")
+,recordingName(RecordingName)
+{
+ Start();
+}
+
+cIndexFileGenerator::~cIndexFileGenerator()
+{
+ Cancel(3);
+}
+
+void cIndexFileGenerator::Action(void)
+{
+ bool IndexFileComplete = false;
+ bool Rewind = false;
+ cFileName FileName(recordingName, false);
+ cUnbufferedFile *ReplayFile = FileName.Open();
+ cRingBufferLinear Buffer(IFG_BUFFER_SIZE, MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE);
+ cPatPmtParser PatPmtParser;
+ cFrameDetector FrameDetector;
+ cIndexFile IndexFile(recordingName, true);
+ int BufferChunks = KILOBYTE(1); // no need to read a lot at the beginning when parsing PAT/PMT
+ off_t FileSize = 0;
+ off_t FrameOffset = -1;
+ Skins.QueueMessage(mtInfo, tr("Regenerating index file"));
+ while (Running()) {
+ // Rewind input file:
+ if (Rewind) {
+ ReplayFile = FileName.SetOffset(1);
+ Buffer.Clear();
+ Rewind = false;
+ }
+ // Process data:
+ int Length;
+ uchar *Data = Buffer.Get(Length);
+ if (Data) {
+ if (FrameDetector.Synced()) {
+ // Step 3 - generate the index:
+ if (TsPid(Data) == PATPID)
+ FrameOffset = FileSize; // the PAT/PMT is at the beginning of an I-frame
+ int Processed = FrameDetector.Analyze(Data, Length);
+ if (Processed > 0) {
+ if (FrameDetector.NewFrame()) {
+ IndexFile.Write(FrameDetector.IndependentFrame(), FileName.Number(), FrameOffset >= 0 ? FrameOffset : FileSize);
+ FrameOffset = -1;
+ }
+ FileSize += Processed;
+ Buffer.Del(Processed);
+ }
+ }
+ else if (PatPmtParser.Vpid()) {
+ // Step 2 - sync FrameDetector:
+ int Processed = FrameDetector.Analyze(Data, Length);
+ if (Processed > 0) {
+ if (FrameDetector.Synced()) {
+ // Synced FrameDetector, so rewind for actual processing:
+ FrameDetector.Reset();
+ Rewind = true;
+ }
+ Buffer.Del(Processed);
+ }
+ }
+ else {
+ // Step 1 - parse PAT/PMT:
+ uchar *p = Data;
+ while (Length >= TS_SIZE) {
+ int Pid = TsPid(p);
+ if (Pid == 0)
+ PatPmtParser.ParsePat(p, TS_SIZE);
+ else if (Pid == PatPmtParser.PmtPid())
+ PatPmtParser.ParsePmt(p, TS_SIZE);
+ Length -= TS_SIZE;
+ p += TS_SIZE;
+ if (PatPmtParser.Vpid()) {
+ // Found Vpid, so rewind to sync FrameDetector:
+ FrameDetector.SetPid(PatPmtParser.Vpid(), PatPmtParser.Vtype());
+ BufferChunks = IFG_BUFFER_SIZE;
+ Rewind = true;
+ break;
+ }
+ }
+ Buffer.Del(p - Data);
+ }
+ }
+ // Read data:
+ else if (ReplayFile) {
+ int Result = Buffer.Read(ReplayFile, BufferChunks);
+ if (Result == 0) // EOF
+ ReplayFile = FileName.NextFile();
+ }
+ // Recording has been processed:
+ else {
+ IndexFileComplete = true;
+ break;
+ }
+ }
+ // Delete the index file if the recording has not been processed entirely:
+ if (IndexFileComplete)
+ Skins.QueueMessage(mtInfo, tr("Index file regeneration complete"));
+ else
+ IndexFile.Delete();
+}
+
// --- cIndexFile ------------------------------------------------------------
#define INDEXFILESUFFIX "/index"
@@ -1343,6 +1462,9 @@ struct tIndexTs {
}
};
+#define MAXWAITFORINDEXFILE 10 // max. time to wait for the regenerated index file (seconds)
+#define INDEXFILECHECKINTERVAL 500 // ms between checks for existence of the regenerated index file
+
cIndexFile::cIndexFile(const char *FileName, bool Record, bool IsPesRecording)
:resumeFile(FileName, IsPesRecording)
{
@@ -1352,6 +1474,7 @@ cIndexFile::cIndexFile(const char *FileName, bool Record, bool IsPesRecording)
last = -1;
index = NULL;
isPesRecording = IsPesRecording;
+ indexFileGenerator = NULL;
if (FileName) {
const char *Suffix = isPesRecording ? INDEXFILESUFFIX ".vdr" : INDEXFILESUFFIX;
fileName = MALLOC(char, strlen(FileName) + strlen(Suffix) + 1);
@@ -1360,6 +1483,18 @@ cIndexFile::cIndexFile(const char *FileName, bool Record, bool IsPesRecording)
char *pFileExt = fileName + strlen(fileName);
strcpy(pFileExt, Suffix);
int delta = 0;
+ if (!Record && access(fileName, R_OK) != 0) {
+ // Index file doesn't exist, so try to regenerate it:
+ if (!isPesRecording) { // sorry, can only do this for TS recordings
+ resumeFile.Delete(); // just in case
+ indexFileGenerator = new cIndexFileGenerator(FileName);
+ // Wait until the index file exists:
+ time_t tmax = time(NULL) + MAXWAITFORINDEXFILE;
+ do {
+ cCondWait::SleepMs(INDEXFILECHECKINTERVAL); // start with a sleep, to give it a head start
+ } while (access(fileName, R_OK) != 0 && time(NULL) < tmax);
+ }
+ }
if (access(fileName, R_OK) == 0) {
struct stat buf;
if (stat(fileName, &buf) == 0) {
@@ -1421,6 +1556,7 @@ cIndexFile::~cIndexFile()
close(f);
free(fileName);
free(index);
+ delete indexFileGenerator;
}
void cIndexFile::ConvertFromPes(tIndexTs *IndexTs, int Count)
@@ -1598,6 +1734,18 @@ bool cIndexFile::IsStillRecording()
return f >= 0;
}
+void cIndexFile::Delete(void)
+{
+ if (fileName) {
+ dsyslog("deleting index file '%s'", fileName);
+ if (f >= 0) {
+ close(f);
+ f = -1;
+ }
+ unlink(fileName);
+ }
+}
+
// --- cFileName -------------------------------------------------------------
#define MAXFILESPERRECORDINGPES 255