Skip to content

Commit

Permalink
Fixes #10872. Use desired start and end times.
Browse files Browse the repository at this point in the history
The recording quality measurement needs to know when a recording was
supposed to start and end to know how much is actually missing from
the recording. We used to use the scheduled start and end times for
this, but sometimes a recording is intentionally started late or ended
early. This captures that by tracking the 'desired' start and end point.
This is initially set by the scheduler using and pre and post roll
values, and if the user intentionally stops a recording early that
updates the desired end time as well.

Conflicts:

	mythtv/libs/libmythtv/dtvrecorder.h
  • Loading branch information
daniel-kristjansson committed Jul 30, 2012
1 parent e8073bc commit ecc1525
Show file tree
Hide file tree
Showing 11 changed files with 87 additions and 28 deletions.
6 changes: 3 additions & 3 deletions mythtv/libs/libmythtv/NuppelVideoRecorder.cpp
Expand Up @@ -2806,8 +2806,8 @@ void NuppelVideoRecorder::doWriteThread(void)
}
}

void NuppelVideoRecorder::SetNextRecording(const ProgramInfo *progInf,
RingBuffer *rb)
void NuppelVideoRecorder::SetNextRecording(
const RecordingInfo *progInf, RingBuffer *rb)
{
// First we do some of the time consuming stuff we can do now
SavePositionMap(true);
Expand All @@ -2819,7 +2819,7 @@ void NuppelVideoRecorder::SetNextRecording(const ProgramInfo *progInf,
QMutexLocker locker(&nextRingBufferLock);
nextRecording = NULL;
if (progInf)
nextRecording = new ProgramInfo(*progInf);
nextRecording = new RecordingInfo(*progInf);
nextRingBuffer = rb;
}

Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/NuppelVideoRecorder.h
Expand Up @@ -101,7 +101,7 @@ class MTV_PUBLIC NuppelVideoRecorder : public V4LRecorder, public CC608Input
void SetVideoFilters(QString &filters);
void SetTranscoding(bool value) { transcoding = value; };

void SetNextRecording(const ProgramInfo*, RingBuffer*);
void SetNextRecording(const RecordingInfo*, RingBuffer*);
void ResetForNewFile(void);
void FinishRecording(void);
void StartNewFile(void);
Expand Down
4 changes: 2 additions & 2 deletions mythtv/libs/libmythtv/dtvrecorder.cpp
Expand Up @@ -688,7 +688,7 @@ bool DTVRecorder::FindOtherKeyframes(const TSPacket *tspacket)
}

// documented in recorderbase.h
void DTVRecorder::SetNextRecording(const ProgramInfo *progInf, RingBuffer *rb)
void DTVRecorder::SetNextRecording(const RecordingInfo *progInf, RingBuffer *rb)
{
LOG(VB_RECORD, LOG_INFO, LOC + QString("SetNextRecord(0x%1, 0x%2)")
.arg((uint64_t)progInf,0,16).arg((uint64_t)rb,0,16));
Expand All @@ -706,7 +706,7 @@ void DTVRecorder::SetNextRecording(const ProgramInfo *progInf, RingBuffer *rb)

nextRecording = NULL;
if (progInf)
nextRecording = new ProgramInfo(*progInf);
nextRecording = new RecordingInfo(*progInf);

nextRingBuffer = rb;
nextRingBufferLock.unlock();
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/dtvrecorder.h
Expand Up @@ -50,7 +50,7 @@ class DTVRecorder :
void Initialize(void) {;}
int GetVideoFd(void) { return _stream_fd; }

virtual void SetNextRecording(const ProgramInfo*, RingBuffer*);
virtual void SetNextRecording(const RecordingInfo*, RingBuffer*);
virtual void SetStreamData(void);
void SetStreamData(MPEGStreamData* sd);
MPEGStreamData *GetStreamData(void) const { return _stream_data; }
Expand Down
4 changes: 2 additions & 2 deletions mythtv/libs/libmythtv/recorderbase.cpp
Expand Up @@ -82,7 +82,7 @@ void RecorderBase::SetRingBuffer(RingBuffer *rbuf)
weMadeBuffer = false;
}

void RecorderBase::SetRecording(const ProgramInfo *pginfo)
void RecorderBase::SetRecording(const RecordingInfo *pginfo)
{
if (pginfo)
LOG(VB_RECORD, LOG_INFO, LOC + QString("SetRecording(0x%1) title(%2)")
Expand All @@ -92,7 +92,7 @@ void RecorderBase::SetRecording(const ProgramInfo *pginfo)

ProgramInfo *oldrec = curRecording;
if (pginfo)
curRecording = new ProgramInfo(*pginfo);
curRecording = new RecordingInfo(*pginfo);
else
curRecording = NULL;

Expand Down
10 changes: 5 additions & 5 deletions mythtv/libs/libmythtv/recorderbase.h
Expand Up @@ -20,10 +20,10 @@
class FireWireDBOptions;
class GeneralDBOptions;
class RecordingProfile;
class RecordingInfo;
class DVBDBOptions;
class RecorderBase;
class ChannelBase;
class ProgramInfo;
class RingBuffer;
class TVRec;

Expand Down Expand Up @@ -63,7 +63,7 @@ class MTV_PUBLIC RecorderBase : public QRunnable
*
* \sa ChannelNameChanged(const QString&)
*/
void SetRecording(const ProgramInfo *pginfo);
void SetRecording(const RecordingInfo *pginfo);

/** \brief Tells recorder to use an externally created ringbuffer.
*
Expand Down Expand Up @@ -116,7 +116,7 @@ class MTV_PUBLIC RecorderBase : public QRunnable
*
* This calls TVRec::RingBufferChanged() when the switch happens.
*/
virtual void SetNextRecording(const ProgramInfo*, RingBuffer*) = 0;
virtual void SetNextRecording(const RecordingInfo*, RingBuffer*) = 0;

/** \brief This is called between SetOptionsFromProfile() and
* run() to initialize any devices, etc.
Expand Down Expand Up @@ -276,7 +276,7 @@ class MTV_PUBLIC RecorderBase : public QRunnable
uint m_videoWidth;
double m_frameRate;

ProgramInfo *curRecording;
RecordingInfo *curRecording;

// For handling pausing + stop recording
mutable QMutex pauseLock; // also used for request_recording and recording
Expand All @@ -294,7 +294,7 @@ class MTV_PUBLIC RecorderBase : public QRunnable
// For RingBuffer switching
QMutex nextRingBufferLock;
RingBuffer *nextRingBuffer;
ProgramInfo *nextRecording;
RecordingInfo *nextRecording;

// Seektable support
MarkTypes positionMapType;
Expand Down
10 changes: 10 additions & 0 deletions mythtv/libs/libmythtv/recordinginfo.cpp
Expand Up @@ -110,6 +110,8 @@ RecordingInfo::RecordingInfo(
oldrecstatus(_oldrecstatus),
savedrecstatus(rsUnknown),
future(_future),
desiredrecstartts(_recstartts),
desiredrecendts(_recendts),
record(NULL)
{
hostname = _hostname;
Expand Down Expand Up @@ -203,6 +205,8 @@ RecordingInfo::RecordingInfo(
oldrecstatus(rsUnknown),
savedrecstatus(rsUnknown),
future(false),
desiredrecstartts(_recstartts),
desiredrecendts(_recendts),
record(NULL)
{
recpriority = _recpriority;
Expand Down Expand Up @@ -379,6 +383,8 @@ void RecordingInfo::clone(const RecordingInfo &other,
oldrecstatus = other.oldrecstatus;
savedrecstatus = other.savedrecstatus;
future = other.future;
desiredrecstartts = other.desiredrecstartts;
desiredrecendts = other.desiredrecendts;
}
}

Expand All @@ -403,6 +409,8 @@ void RecordingInfo::clone(const ProgramInfo &other,
oldrecstatus = rsUnknown;
savedrecstatus = rsUnknown;
future = false;
desiredrecstartts = QDateTime();
desiredrecendts = QDateTime();
}

void RecordingInfo::clear(void)
Expand All @@ -415,6 +423,8 @@ void RecordingInfo::clear(void)
oldrecstatus = rsUnknown;
savedrecstatus = rsUnknown;
future = false;
desiredrecstartts = QDateTime();
desiredrecendts = QDateTime();
}


Expand Down
11 changes: 11 additions & 0 deletions mythtv/libs/libmythtv/recordinginfo.h
@@ -1,6 +1,9 @@
#ifndef _RECORDING_INFO_H_
#define _RECORDING_INFO_H_

#include <QDateTime>
#include <QString>

#include "mythtvexp.h"
#include "programinfo.h"

Expand Down Expand Up @@ -206,6 +209,12 @@ class MTV_PUBLIC RecordingInfo : public ProgramInfo
void ApplyRecordRecPriorityChange(int);
void ToggleRecord(void);

// Used in determining start and end for RecordingQuality determination
void SetDesiredStartTime(const QDateTime &dt) { desiredrecstartts = dt; }
void SetDesiredEndTime(const QDateTime &dt) { desiredrecendts = dt; }
QDateTime GetDesiredStartTime(void) const { return desiredrecstartts; }
QDateTime GetDesiredEndTime(void) const { return desiredrecendts; }

// these five can be moved to programinfo
void AddHistory(bool resched = true, bool forcedup = false,
bool future = false);//pi
Expand All @@ -231,6 +240,8 @@ class MTV_PUBLIC RecordingInfo : public ProgramInfo
RecStatusType oldrecstatus;
RecStatusType savedrecstatus;
bool future;
QDateTime desiredrecstartts;
QDateTime desiredrecendts;

private:
mutable class RecordingRule *record;
Expand Down
55 changes: 44 additions & 11 deletions mythtv/libs/libmythtv/recordingquality.cpp
Expand Up @@ -3,26 +3,28 @@ using namespace std;

#include "recordingquality.h"
#include "mythcorecontext.h"
#include "recordinginfo.h"
#include "mythmiscutil.h"
#include "mythlogging.h"
#include "programinfo.h"

static void merge_overlapping(RecordingGaps &gaps);
static double score_gaps(const ProgramInfo*, const RecordingGaps&);
static double score_gaps(const RecordingInfo&, const RecordingGaps&);
static QDateTime get_start(const RecordingInfo&);
static QDateTime get_end(const RecordingInfo&);

RecordingQuality::RecordingQuality(
const ProgramInfo *pi, const RecordingGaps &rg,
const RecordingInfo *ri, const RecordingGaps &rg,
const QDateTime &first, const QDateTime &latest) :
m_continuity_error_count(0), m_packet_count(0),
m_overall_score(1.0), m_recording_gaps(rg)
{
if (!pi)
if (!ri)
return;

m_program_key = pi->MakeUniqueKey();
m_program_key = ri->MakeUniqueKey();

// trim start
QDateTime start = pi->GetScheduledStartTime();
QDateTime start = get_start(*ri);
while (!m_recording_gaps.empty() &&
m_recording_gaps.first().GetStart() < start)
{
Expand All @@ -34,7 +36,7 @@ RecordingQuality::RecordingQuality(
}

// trim end
QDateTime end = pi->GetScheduledEndTime();
QDateTime end = get_end(*ri);
while (!m_recording_gaps.empty() &&
m_recording_gaps.back().GetEnd() > end)
{
Expand All @@ -58,7 +60,13 @@ RecordingQuality::RecordingQuality(
stable_sort(m_recording_gaps.begin(), m_recording_gaps.end());
merge_overlapping(m_recording_gaps);

m_overall_score = score_gaps(pi, m_recording_gaps);
m_overall_score = score_gaps(*ri, m_recording_gaps);

LOG(VB_RECORD, LOG_INFO,
QString("RecordingQuality() start(%1) end(%2) score(%3)")
.arg(MythDate::toString(start, MythDate::ISODate))
.arg(MythDate::toString(end, MythDate::ISODate))
.arg(m_overall_score));
}

void RecordingQuality::AddTSStatistics(
Expand Down Expand Up @@ -137,15 +145,15 @@ static void merge_overlapping(RecordingGaps &gaps)
}
}

static double score_gaps(const ProgramInfo *pi, const RecordingGaps &gaps)
static double score_gaps(const RecordingInfo &ri, const RecordingGaps &gaps)
{
RecordingGaps::const_iterator it = gaps.begin();
if (it == gaps.end())
return 1.0;

QDateTime start = pi->GetScheduledStartTime();
QDateTime start = get_start(ri);

double program_length = start.secsTo(pi->GetScheduledEndTime());
double program_length = start.secsTo(get_end(ri));
if (program_length < 1.0)
return 0.0;

Expand Down Expand Up @@ -190,3 +198,28 @@ static double score_gaps(const ProgramInfo *pi, const RecordingGaps &gaps)
return (score > 0.0) ? score : 0.0;
}

static QDateTime get_start(const RecordingInfo &ri)
{
if (ri.GetDesiredStartTime().isValid())
{
return (ri.GetScheduledStartTime() > ri.GetDesiredStartTime()) ?
ri.GetScheduledStartTime() : ri.GetDesiredStartTime();
}
else
{
return ri.GetScheduledStartTime();
}
}

static QDateTime get_end(const RecordingInfo &ri)
{
if (ri.GetDesiredEndTime().isValid())
{
return (ri.GetScheduledEndTime() < ri.GetDesiredEndTime()) ?
ri.GetScheduledEndTime() : ri.GetDesiredEndTime();
}
else
{
return ri.GetScheduledEndTime();
}
}
4 changes: 2 additions & 2 deletions mythtv/libs/libmythtv/recordingquality.h
Expand Up @@ -7,7 +7,7 @@

#include "mythtvexp.h"

class ProgramInfo;
class RecordingInfo;

class RecordingGap
{
Expand All @@ -33,7 +33,7 @@ class MTV_PUBLIC RecordingQuality
{
public:
RecordingQuality(
const ProgramInfo*, const RecordingGaps&,
const RecordingInfo*, const RecordingGaps&,
const QDateTime &firstData, const QDateTime &latestData);

void AddTSStatistics(int continuity_error_count, int packet_count);
Expand Down
7 changes: 6 additions & 1 deletion mythtv/libs/libmythtv/tv_rec.cpp
Expand Up @@ -693,6 +693,8 @@ void TVRec::SetRecordingStatus(

/** \fn TVRec::StopRecording(bool killFile)
* \brief Changes from a recording state to kState_None.
* \note For the sake of recording quality measurements this is
* treated as the desired end point of the recording.
* \sa StartRecording(const ProgramInfo *rec), FinishRecording()
*/
void TVRec::StopRecording(bool killFile)
Expand All @@ -702,6 +704,8 @@ void TVRec::StopRecording(bool killFile)
QMutexLocker lock(&stateChangeLock);
if (killFile)
SetFlags(kFlagKillRec);
else if (curRecording)
curRecording->SetDesiredEndTime(MythDate::current(true));
ChangeState(RemoveRecording(GetState()));
// wait for state change to take effect
WaitForEventThreadSleep();
Expand Down Expand Up @@ -4170,8 +4174,9 @@ void TVRec::TuningRestartRecorder(void)
{
recorder->SetRingBuffer(ringBuffer);
ProgramInfo *progInfo = tvchain->GetProgramAt(-1);
recorder->SetRecording(progInfo);
RecordingInfo recinfo(*progInfo);
delete progInfo;
recorder->SetRecording(&recinfo);
}
recorder->Reset();

Expand Down

0 comments on commit ecc1525

Please sign in to comment.