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).
This commit is contained in:
Klaus Schmidinger
2009-11-22 15:58:00 +01:00
parent 06bf4c453e
commit ea01358b3b
102 changed files with 3162 additions and 514 deletions

View File

@@ -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