Exemple #1
0
bool Dvr::UnDeleteRecording(int RecordedId,
                            int chanid, const QDateTime &recstarttsRaw)
{
    if ((RecordedId <= 0) &&
        (chanid <= 0 || !recstarttsRaw.isValid()))
        throw QString("Recorded ID or Channel ID and StartTime appears invalid.");

    RecordingInfo ri;
    if (RecordedId > 0)
        ri = RecordingInfo(RecordedId);
    else
        ri = RecordingInfo(chanid, recstarttsRaw.toUTC());

    if (ri.GetChanID() && ri.HasPathname())
    {
        QString cmd = QString("UNDELETE_RECORDING %1 %2")
            .arg(ri.GetChanID())
            .arg(ri.GetRecordingStartTime(MythDate::ISODate));
        MythEvent me(cmd);

        gCoreContext->dispatch(me);
        return true;
    }

    return false;
}
Exemple #2
0
DTC::CutList* Dvr::GetRecordedCommBreak ( int RecordedId,
                                          int chanid,
                                          const QDateTime &recstarttsRaw,
                                          const QString &offsettype )
{
    int marktype;
    if ((RecordedId <= 0) &&
        (chanid <= 0 || !recstarttsRaw.isValid()))
        throw QString("Recorded ID or Channel ID and StartTime appears invalid.");

    RecordingInfo ri;
    if (RecordedId > 0)
        ri = RecordingInfo(RecordedId);
    else
        ri = RecordingInfo(chanid, recstarttsRaw.toUTC());

    DTC::CutList* pCutList = new DTC::CutList();
    if (offsettype == "Position")
        marktype = 1;
    else if (offsettype == "Duration")
        marktype = 2;
    else
        marktype = 0;

    FillCommBreak(pCutList, &ri, marktype);

    return pCutList;
}
Exemple #3
0
bool Dvr::SetSavedBookmark( int RecordedId,
                            int chanid,
                            const QDateTime &recstarttsRaw,
                            const QString &offsettype,
                            long Offset )
{
    if ((RecordedId <= 0) &&
        (chanid <= 0 || !recstarttsRaw.isValid()))
        throw QString("Recorded ID or Channel ID and StartTime appears invalid.");

    if (Offset < 0)
        throw QString("Offset must be >= 0.");

    RecordingInfo ri;
    if (RecordedId > 0)
        ri = RecordingInfo(RecordedId);
    else
        ri = RecordingInfo(chanid, recstarttsRaw.toUTC());
    uint64_t position;
    bool isend=true;
    if (offsettype.toLower() == "position"){
        if (!ri.QueryPositionKeyFrame(&position, Offset, isend))
                return false;
    }
    else if (offsettype.toLower() == "duration"){
        if (!ri.QueryDurationKeyFrame(&position, Offset, isend))
                return false;
    }
    else
        position = Offset;
    ri.SaveBookmark(position);
    return true;
}
Exemple #4
0
long Dvr::GetSavedBookmark( int RecordedId,
                            int chanid,
                            const QDateTime &recstarttsRaw,
                            const QString &offsettype )
{
    if ((RecordedId <= 0) &&
        (chanid <= 0 || !recstarttsRaw.isValid()))
        throw QString("Recorded ID or Channel ID and StartTime appears invalid.");

    RecordingInfo ri;
    if (RecordedId > 0)
        ri = RecordingInfo(RecordedId);
    else
        ri = RecordingInfo(chanid, recstarttsRaw.toUTC());
    uint64_t offset;
    bool isend=true;
    uint64_t position = ri.QueryBookmark();
    if (offsettype.toLower() == "position"){
        ri.QueryKeyFramePosition(&offset, position, isend);
        return offset;
    }
    else if (offsettype.toLower() == "duration"){
        ri.QueryKeyFrameDuration(&offset, position, isend);
        return offset;
    }
    else
        return position;
}
Exemple #5
0
bool Dvr::AddDontRecordSchedule(int nChanId, const QDateTime &dStartTime,
                                bool bNeverRecord)
{
    bool bResult = true;

    if (nChanId <= 0 || !dStartTime.isValid())
        throw QString("Program does not exist.");

    ProgramInfo *pi = LoadProgramFromProgram(nChanId, dStartTime.toUTC());

    if (!pi)
        throw QString("Program does not exist.");

    // Why RecordingInfo instead of ProgramInfo? Good question ...
    RecordingInfo recInfo = RecordingInfo(*pi);

    delete pi;

    if (bNeverRecord)
    {
        recInfo.ApplyNeverRecord();
    }
    else
        recInfo.ApplyRecordStateChange(kDontRecord);

    return bResult;
}
Exemple #6
0
void cRecorder::Action(void)
{
  cTimeMs t(MAXBROKENTIMEOUT);
  bool InfoWritten = false;
  bool FirstIframeSeen = false;
  while (Running()) {
        int r;
        uchar *b = ringBuffer->Get(r);
        if (b) {
           int Count = frameDetector->Analyze(b, r);
           if (Count) {
              if (!Running() && frameDetector->IndependentFrame()) // finish the recording before the next independent frame
                 break;
              if (frameDetector->Synced()) {
                 if (!InfoWritten) {
                    cRecordingInfo RecordingInfo(recordingName);
                    if (RecordingInfo.Read()) {
                       if (frameDetector->FramesPerSecond() > 0 && DoubleEqual(RecordingInfo.FramesPerSecond(), DEFAULTFRAMESPERSECOND) && !DoubleEqual(RecordingInfo.FramesPerSecond(), frameDetector->FramesPerSecond())) {
                          RecordingInfo.SetFramesPerSecond(frameDetector->FramesPerSecond());
                          RecordingInfo.Write();
                          Recordings.UpdateByName(recordingName);
                          }
                       }
                    InfoWritten = true;
                    cRecordingUserCommand::InvokeCommand(RUC_STARTRECORDING, recordingName);
                    }
                 if (FirstIframeSeen || frameDetector->IndependentFrame()) {
                    FirstIframeSeen = true; // start recording with the first I-frame
                    if (!NextFile())
                       break;
                    if (index && frameDetector->NewFrame())
                       index->Write(frameDetector->IndependentFrame(), fileName->Number(), fileSize);
                    if (frameDetector->IndependentFrame()) {
                       recordFile->Write(patPmtGenerator.GetPat(), TS_SIZE);
                       fileSize += TS_SIZE;
                       int Index = 0;
                       while (uchar *pmt = patPmtGenerator.GetPmt(Index)) {
                             recordFile->Write(pmt, TS_SIZE);
                             fileSize += TS_SIZE;
                             }
                       }
                    if (recordFile->Write(b, Count) < 0) {
                       LOG_ERROR_STR(fileName->Name());
                       break;
                       }
                    fileSize += Count;
                    t.Set(MAXBROKENTIMEOUT);
                    }
                 }
              ringBuffer->Del(Count);
              }
           }
        if (t.TimedOut()) {
           esyslog("ERROR: video data stream broken");
           ShutdownHandler.RequestEmergencyExit();
           t.Set(MAXBROKENTIMEOUT);
           }
        }
}
Exemple #7
0
bool Dvr::ReactivateRecording(int RecordedId)
{
    if (RecordedId <= 0)
        throw QString("Recorded ID is invalid.");

    RecordingInfo ri = RecordingInfo(RecordedId);

    ri.ReactivateRecording();

    return true;
}
Exemple #8
0
DTC::CutList* Dvr::GetRecordedSeek ( int RecordedId,
                                     const QString &offsettype )
{
    MarkTypes marktype;
    if (RecordedId <= 0)
        throw QString("Recorded ID appears invalid.");

    RecordingInfo ri;
    ri = RecordingInfo(RecordedId);

    DTC::CutList* pCutList = new DTC::CutList();
    if (offsettype == "BYTES")
        marktype = MARK_GOP_BYFRAME;
    else if (offsettype == "DURATION")
        marktype = MARK_DURATION_MS;
    else
        throw QString("Type must be 'BYTES' or 'DURATION'.");

    FillSeek(pCutList, &ri, marktype);

    return pCutList;
}
Exemple #9
0
bool Dvr::StopRecording(int RecordedId)
{
    if (RecordedId <= 0)
        throw QString("Recorded ID is invalid.");

    RecordingInfo ri = RecordingInfo(RecordedId);

    if (ri.GetChanID())
    {
        QString cmd = QString("STOP_RECORDING %1 %2")
                      .arg(ri.GetChanID())
                      .arg(ri.GetRecordingStartTime(MythDate::ISODate));
        MythEvent me(cmd);

        gCoreContext->dispatch(me);
        return true;
    }
    else
        throw QString("RecordID %1 not found").arg(RecordedId);

    return false;
}
Exemple #10
0
/** \fn MythSystemEventHandler::SubstituteMatches(const QStringList &tokens,
                                                  QString &command)
 *  \brief Substitutes %MATCH% variables in given command line.
 *  \sa ProgramInfo::SubstituteMatches(QString &str)
 *
 *  Subsitutes values for %MATCH% type variables in given command string.
 *  Some of these matches come from the tokens list passed in and some
 *  may come from a ProgramInfo if a chanid and starttime are specified
 *  in the tokens list.
 *
 *  \param tokens  Const QStringList containing token list passed with event.
 *  \param command Command line containing %MATCH% variables to be substituted.
 */
void MythSystemEventHandler::SubstituteMatches(const QStringList &tokens,
                                               QString &command)
{
    if (command.isEmpty())
        return;

    LOG(VB_FILE, LOG_DEBUG, LOC + QString("SubstituteMatches: BEFORE: %1")
                                            .arg(command));
    QString args;
    uint chanid = 0;
    QDateTime recstartts;
    QString sender;

    QStringList::const_iterator it = tokens.begin();
    ++it;
    command.replace(QString("%EVENTNAME%"), *it);

    ++it;
    while (it != tokens.end())
    {
        if (!args.isEmpty())
            args += " ";
        args += *it;

        // Check for some token names that we substitute one for one as
        // %MATCH% type variables.
        if ((*it == "CARDID") ||
            (*it == "COMMAND") ||
            (*it == "RECSTATUS") ||
            (*it == "HOSTNAME") ||
            (*it == "SECS") ||
            (*it == "SENDER") ||
            (*it == "PATH"))
        {
            QString token = *it;

            if (++it == tokens.end())
                break;

            if (token == "SENDER")
                sender = *it;

            // The following string is broken up on purpose to indicate
            // what we're replacing is the token surrounded by percent signs
            command.replace(QString("%" "%1" "%").arg(token), *it);

            if (!args.isEmpty())
                args += " ";
            args += *it;
        }

        // Remember any chanid and starttime so we can lookup info about
        // the recording from the database.
        if (*it == "CHANID")
        {
            if (++it == tokens.end())
                break;

            chanid = (*it).toUInt();

            if (!args.isEmpty())
                args += " ";
            args += *it;
        }

        if (*it == "STARTTIME")
        {
            if (++it == tokens.end())
                break;

            recstartts = MythDate::fromString(*it);

            if (!args.isEmpty())
                args += " ";
            args += *it;
        }

        ++it;
    }

    command.replace(QString("%ARGS%"), args);

    ProgramInfo pginfo(chanid, recstartts);
    bool pginfo_loaded = pginfo.GetChanID();
    if (!pginfo_loaded)
    {
        RecordingInfo::LoadStatus status;
        pginfo = RecordingInfo(chanid, recstartts, false, 0, &status);
        pginfo_loaded = RecordingInfo::kFoundProgram == status;
    }

    if (pginfo_loaded)
    {
        pginfo.SubstituteMatches(command);
    }
    else
    {
        command.replace(QString("%CHANID%"), QString::number(chanid));
        command.replace(QString("%STARTTIME%"),
                        MythDate::toString(recstartts, MythDate::kFilename));
        command.replace(QString("%STARTTIMEISO%"),
                        recstartts.toString(Qt::ISODate));
    }

    command.replace(QString("%VERBOSELEVEL%"), QString("%1").arg(verboseMask));

    LOG(VB_FILE, LOG_DEBUG, LOC + QString("SubstituteMatches: AFTER : %1")
                                            .arg(command));
}
Exemple #11
0
bool cRecorder::NextFile(void)
{
  if (recordFile && frameDetector->IndependentFrame()) { // every file shall start with an independent frame
#ifdef USE_HARDLINKCUTTER
     if (fileSize > fileName->MaxFileSize() || RunningLowOnDiskSpace()) {
#else
     if (fileSize > MEGABYTE(off_t(Setup.MaxVideoFileSize)) || RunningLowOnDiskSpace()) {
#endif /* HARDLINKCUTTER */
        recordFile = fileName->NextFile();
        fileSize = 0;
        }
     }
  return recordFile != NULL;
}

void cRecorder::Activate(bool On)
{
  if (On)
     Start();
  else
     Cancel(3);
}

void cRecorder::Receive(uchar *Data, int Length)
{
  if (Running()) {
     int p = ringBuffer->Put(Data, Length);
     if (p != Length && Running())
        ringBuffer->ReportOverflow(Length - p);
     }
}

void cRecorder::Action(void)
{
  time_t t = time(NULL);
  bool InfoWritten = false;
  bool FirstIframeSeen = false;
#ifdef USE_LIVEBUFFER
  double fps = DEFAULTFRAMESPERSECOND;
#endif /*USE_LIVEBUFFER*/
  while (Running()) {
        int r;
        uchar *b = ringBuffer->Get(r);
        if (b) {
           int Count = frameDetector->Analyze(b, r);
           if (Count) {
              if (!Running() && frameDetector->IndependentFrame()) // finish the recording before the next independent frame
                 break;
              if (frameDetector->Synced()) {
#ifdef USE_LIVEBUFFER
                 if(index && (frameDetector->FramesPerSecond() != fps)) {
                    fps = frameDetector->FramesPerSecond();
                    index->SetFramesPerSecond(fps);
                 } // if
#endif /*USE_LIVEBUFFER*/
                 if (!InfoWritten) {
                    cRecordingInfo RecordingInfo(recordingName);
                    if (RecordingInfo.Read()) {
                       if (frameDetector->FramesPerSecond() > 0 && DoubleEqual(RecordingInfo.FramesPerSecond(), DEFAULTFRAMESPERSECOND) && !DoubleEqual(RecordingInfo.FramesPerSecond(), frameDetector->FramesPerSecond())) {
                          RecordingInfo.SetFramesPerSecond(frameDetector->FramesPerSecond());
                          RecordingInfo.Write();
                          Recordings.UpdateByName(recordingName);
                          }
                       }
                    InfoWritten = true;
                    }
/*                 if (frameDetector->NewPayload()) { // We're at the first TS packet of a new payload...
                    if (Buffering)
                       esyslog("ERROR: encountered new payload while buffering - dropping some data!");
                    if (!frameDetector->NewFrame()) { // ...but the frame type is yet unknown, so we need to buffer packets until we see the frame type
                       if (!Buffer) {
                          dsyslog("frame type not in first packet of payload - buffering");
                          if (!(Buffer = MALLOC(uchar, BUFFERSIZE))) {
                             esyslog("ERROR: can't allocate frame type buffer");
                             break;
                             }
                          }
                       BufferIndex = 0;
                       Buffering = true;
                       }
                    }
                 else if (frameDetector->NewFrame()) // now we know the frame type, so stop buffering
                    Buffering = false;
                 if (Buffering) {
                    if (BufferIndex + Count <= BUFFERSIZE) {
                       memcpy(Buffer + BufferIndex, b, Count);
                       BufferIndex += Count;
                       }
                    else
                       esyslog("ERROR: too many bytes for frame type buffer (%d > %d) - dropped %d bytes", BufferIndex + Count, int(BUFFERSIZE), Count);
                    }
                 else if (FirstIframeSeen || frameDetector->IndependentFrame()) {
*/
#ifdef USE_LIVEBUFFER
                    if(!FirstIframeSeen) FillInitialData(b, r);
#endif /*USE_LIVEBUFFER*/
                 if (FirstIframeSeen || frameDetector->IndependentFrame()) {
                    FirstIframeSeen = true; // start recording with the first I-frame
                    if (!NextFile())
                       break;
                    if (index && frameDetector->NewFrame())
                       index->Write(frameDetector->IndependentFrame(), fileName->Number(), fileSize);
                    if (frameDetector->IndependentFrame()) {
                       recordFile->Write(patPmtGenerator.GetPat(), TS_SIZE);
                       fileSize += TS_SIZE;
                       int Index = 0;
                       while (uchar *pmt = patPmtGenerator.GetPmt(Index)) {
                             recordFile->Write(pmt, TS_SIZE);
                             fileSize += TS_SIZE;
                             }
                       }
                    if (recordFile->Write(b, Count) < 0) {
                       LOG_ERROR_STR(fileName->Name());
                       break;
                       }
                    fileSize += Count;
                    t = time(NULL);
                    }
                 }
              ringBuffer->Del(Count);
              }
           }
#ifdef USE_LIVEBUFFER
        if (handleError && (time(NULL) - t > MAXBROKENTIMEOUT)) {
#else
        if (time(NULL) - t > MAXBROKENTIMEOUT) {
#endif
#if REELVDR
           Skins.QueueMessage(mtError, tr("can't record - check your configuration"));
#else
           esyslog("ERROR: video data stream broken. Requesting Emergency Exit.");
           ShutdownHandler.RequestEmergencyExit();
#endif /*REELVDR*/
           t = time(NULL);
           }
        }
}