Ticket #1772: ajm_multiple_recorders_v2.patch

File ajm_multiple_recorders_v2.patch, 56.7 KB (added by Aaron McCarthy <mccarthy.aaron@…>, 14 years ago)

Enabled multiple recorders per hardware card. Version 2

  • libs/libmythtv/tv_rec.h

    old new  
    169169    void RecordPending(const ProgramInfo *rcinfo, int secsleft);
    170170    RecStatusType StartRecording(const ProgramInfo *rcinfo);
    171171
    172     void StopRecording(void);
     172    void StopRecording(ProgramInfo *rec);
    173173    /// \brief Tells TVRec to finish the current recording as soon as possible.
    174174    void FinishRecording(void)  { SetFlags(kFlagFinishRecording); }
    175175    /// \brief Tells TVRec that the frontend's TV class is ready for messages.
    176176    void FrontendReady(void)    { SetFlags(kFlagFrontendReady); }
    177177    void CancelNextRecording(bool cancel);
    178     ProgramInfo *GetRecording(void);
     178    ProgramList GetRecordings(void);
    179179
    180180    /// \brief Returns true if event loop has not been told to shut down
    181181    bool IsRunning(void)  const { return HasFlags(kFlagRunMainLoop); }
     
    337337
    338338    void SetOption(RecordingProfile &profile, const QString &name);
    339339
     340    void DoneAddingRecording();
     341
    340342    // Various components TVRec coordinates
    341343    RecorderMuxBase  *recorderMux;
    342     RecorderBase     *recorder;
     344    QMap<ProgramInfo *, RecorderBase *>  recorders;
    343345    ChannelBase      *channel;
    344346    SignalMonitor    *signalMonitor;
    345347    EITScanner       *scanner;
     
    383385    QWaitCondition triggerEventLoop;
    384386    QWaitCondition triggerEventSleep;
    385387
     388    // Current recording info SPLIT
     389    ProgramList   curRecordings;
     390    ProgramInfo  *newRecording;
     391    RecorderBase *newRecorder;
     392    QMutex        newRecordingLock;
     393
    386394    // Current recording info
    387395    ProgramInfo *curRecording;
    388396    QDateTime    recordEndTime;
     
    399407    // LiveTV file chain
    400408    LiveTVChain *tvchain;
    401409
     410    // RingBuffer info SPLIT
     411    RingBuffer *newRingBuffer;
     412    QMap<ProgramInfo *, RingBuffer *> ringBuffers;
     413
    402414    // RingBuffer info
    403415    RingBuffer  *ringBuffer;
    404416    QString      rbFilePrefix;
  • libs/libmythtv/tv_rec.cpp

    old new  
    9494static bool is_dishnet_eit(int cardid);
    9595static QString load_profile(QString,void*,ProgramInfo*,RecordingProfile&);
    9696
     97static int comp_recend(ProgramInfo *a, ProgramInfo *b)
     98{
     99    if (a->recendts != b->recendts)
     100    {
     101        if (a->recendts > b->recendts)
     102            return 1;
     103        else
     104            return -1;
     105    }
     106    if (a->recstartts != b->recstartts)
     107    {
     108        if (a->recstartts > b->recstartts)
     109            return 1;
     110        else
     111            return -1;
     112    }
     113    if (a->chansign != b->chansign)
     114    {
     115        if (a->chansign < b->chansign)
     116            return 1;
     117        else
     118            return -1;
     119    }
     120    return 0;
     121}
     122
    97123/** \class TVRec
    98124 *  \brief This is the coordinating class of the \ref recorder_subsystem.
    99125 *
     
    120146 */
    121147TVRec::TVRec(int capturecardnum)
    122148       // Various components TVRec coordinates
    123     : recorderMux(NULL), recorder(NULL), channel(NULL), signalMonitor(NULL),
     149    : recorderMux(NULL), channel(NULL), signalMonitor(NULL),
    124150      scanner(NULL), dvbsiparser(NULL),
    125151      // Configuration variables from database
    126152      transcodeFirst(false), earlyCommFlag(false), runJobOnHostOnly(false),
     
    133159      internalState(kState_None), desiredNextState(kState_None),
    134160      changeState(false), pauseNotify(true),
    135161      stateFlags(0), lastTuningRequest(0),
     162      // Current recording info SPLIT
     163      curRecordings(false), newRecording(NULL), newRecorder(NULL),
    136164      // Current recording info
    137165      curRecording(NULL), autoRunJobs(JOB_NONE),
    138166      // Pending recording info
     
    141169      pseudoLiveTVRecording(NULL),
    142170      // tvchain
    143171      tvchain(NULL),
     172      // RingBuffer info SPLIT
     173      newRingBuffer(NULL),
    144174      // RingBuffer info
    145175      ringBuffer(NULL), rbFilePrefix(""), rbFileExt("mpg")
    146176{
     
    330360    return internalState;
    331361}
    332362
    333 /** \fn TVRec::GetRecording(void)
    334  *  \brief Allocates and returns a ProgramInfo for the current recording.
     363/** \fn TVRec::GetRecordings(void)
     364 *  \brief Allocates and returns a ProgramList for the current recordings.
    335365 *
    336  *  Note: The user of this function must free the %ProgramInfo this returns.
    337  *  \return %ProgramInfo for the current recording, if it exists, blank
    338  *          %ProgramInfo otherwise.
     366 *  Note: The user of this function must free the %ProgramInfo objects
     367 *  this returns.
     368 *  \return %ProgramList for the current recordings, an empty list is
     369 *          returned if there are no current recordings.
    339370 */
    340 ProgramInfo *TVRec::GetRecording(void)
     371ProgramList TVRec::GetRecordings(void)
    341372{
    342373    QMutexLocker lock(&stateChangeLock);
    343374
    344     ProgramInfo *tmppginfo = NULL;
     375    ProgramList retlist(false);
     376
     377    if (changeState)
     378        return retlist;
    345379
    346     if (curRecording && !changeState)
     380    for (ProgramInfo *rec = curRecordings.first();
     381         rec; rec = curRecordings.next())
    347382    {
    348         tmppginfo = new ProgramInfo(*curRecording);
     383        ProgramInfo *tmppginfo = new ProgramInfo(*rec);
    349384        tmppginfo->recstatus = rsRecording;
     385        tmppginfo->cardid = cardid;
     386        retlist.append(tmppginfo);
    350387    }
    351     else
    352         tmppginfo = new ProgramInfo();
    353     tmppginfo->cardid = cardid;
    354388
    355     return tmppginfo;
     389    return retlist;
    356390}
    357391
    358392/** \fn TVRec::RecordPending(const ProgramInfo*, int)
     
    419453 *  \return +1 if the recording started successfully,
    420454 *          -1 if TVRec is busy doing something else, 0 otherwise.
    421455 *  \sa EncoderLink::StartRecording(const ProgramInfo*)
    422  *      RecordPending(const ProgramInfo*, int), StopRecording()
     456 *      RecordPending(const ProgramInfo*, int), StopRecording(ProgramInfo *rec)
    423457 */
    424458RecStatusType TVRec::StartRecording(const ProgramInfo *rcinfo)
    425459{
     
    435469
    436470    // We need to do this check early so we don't cancel an overrecord
    437471    // that we're trying to extend.
    438     if (internalState != kState_WatchingLiveTV &&
    439         curRecording &&
     472    if (internalState != kState_WatchingLiveTV)
     473    {
     474        // change this to rec later
     475        for (ProgramInfo *curRecording = curRecordings.first(); curRecording;
     476             curRecording = curRecordings.next())
     477        {
     478            if (curRecording &&
    440479        curRecording->title == rcinfo->title &&
    441480        curRecording->chanid == rcinfo->chanid &&
    442481        curRecording->startts == rcinfo->startts)
     
    449488        MythEvent me("RECORDING_LIST_CHANGE");
    450489        gContext->dispatch(me);
    451490
    452         recordEndTime = curRecording->recendts.addSecs(post_roll_seconds);
     491                // Resort the list of current recordings so that the recording
     492                // that will end first is at the front of the list
     493                curRecordings.Sort(comp_recend);
     494                recordEndTime = curRecordings.getFirst()->recendts.addSecs(post_roll_seconds);
    453495
    454496        msg = QString("updating recording: %1 %2 %3 %4")
    455497            .arg(curRecording->title).arg(curRecording->chanid)
     
    461503
    462504        retval = rsRecording;
    463505        return retval;
     506            }
     507        }
    464508    }
    465509
    466510    if (pendingRecording)
     
    474518    // Flush out events...
    475519    WaitForEventThreadSleep();
    476520
     521    // SPLIT how does this test if recording is in post-roll?
    477522    // If in post-roll, end recording
     523#if 0
    478524    if (GetState() == kState_RecordingOnly &&
    479525        !HasFlags(kFlagCancelNextRecording))
    480526    {
     
    482528        StopRecording();
    483529        stateChangeLock.lock();
    484530    }
     531#endif
    485532
    486533    if (internalState == kState_None)
    487534    {
     
    493540            tvchain = NULL;
    494541        }
    495542
    496         recordEndTime = GetRecordEndTime(rcinfo);
    497 
    498543        // Tell event loop to begin recording.
    499         curRecording = new ProgramInfo(*rcinfo);
    500         curRecording->MarkAsInUse(true, "recorder");
    501         StartedRecording(curRecording);
     544        newRecordingLock.lock();
     545        newRecording = new ProgramInfo(*rcinfo);
     546        newRecording->MarkAsInUse(true, "recorder");
     547        StartedRecording(newRecording);
    502548
    503549        // Make sure scheduler is allowed to end this recording
    504550        ClearFlags(kFlagCancelNextRecording);
     
    524570
    525571        retval = rsRecording;
    526572    }
     573    else if (!HasFlags(kFlagCancelNextRecording) && true /* OnSameMux (this should be true if the scheduler is working right)*/)
     574    {
     575        // Haven't integrated with LiveTV yet
     576        newRecordingLock.lock();
     577        newRecording = new ProgramInfo(*rcinfo);
     578        newRecording->MarkAsInUse(true, "recorder");
     579        StartedRecording(newRecording);
     580
     581        retval = rsRecording;
     582    }
    527583    else if (!HasFlags(kFlagCancelNextRecording))
    528584    {
    529585        msg = QString("Wanted to record: %1 %2 %3 %4\n"
     
    532588              .arg(rcinfo->recstartts.toString())
    533589              .arg(rcinfo->recendts.toString())
    534590              .arg(StateToString(internalState));
    535         if (curRecording && internalState == kState_RecordingOnly)
     591        if (!curRecordings.isEmpty() && internalState == kState_RecordingOnly)
     592        {
     593            // Change this to rec later
     594            for (ProgramInfo *curRecording = curRecordings.first();
     595                 curRecording; curRecording = curRecordings.next())
     596            {
    536597            msg += QString("\n\t\t\tCurrently recording: %1 %2 %3 %4")
    537598                .arg(curRecording->title).arg(curRecording->chanid)
    538599                .arg(curRecording->recstartts.toString())
    539600                .arg(curRecording->recendts.toString());
     601            }
     602        }
    540603        VERBOSE(VB_IMPORTANT, LOC + msg);
    541604
    542605        retval = rsTunerBusy;
     
    547610    return retval;
    548611}
    549612
    550 /** \fn TVRec::StopRecording(void)
     613/** \fn TVRec::StopRecording(ProgramInfo *rec)
    551614 *  \brief Changes from kState_RecordingOnly to kState_None.
    552615 *  \sa StartRecording(const ProgramInfo *rec), FinishRecording()
    553616 */
    554 void TVRec::StopRecording(void)
     617void TVRec::StopRecording(ProgramInfo *rec)
    555618{
    556     if (StateIsRecording(GetState()))
     619    if (curRecordings.contains(rec))
     620    {
     621        recorders[rec]->StopRecording();
     622        FinishedRecording(rec);
     623        curRecordings.remove(rec);
     624
     625        if (!curRecordings.isEmpty())
     626            recordEndTime = GetRecordEndTime(curRecordings.getFirst());
     627    }
     628
     629    if (curRecordings.isEmpty() && StateIsRecording(GetState()))
    557630    {
    558631        QMutexLocker lock(&stateChangeLock);
    559632        ChangeState(RemoveRecording(GetState()));
     
    750823    else if (TRANSITION(kState_None, kState_RecordingOnly))
    751824    {
    752825        SetPseudoLiveTVRecording(NULL);
    753         tuningRequests.enqueue(TuningRequest(kFlagRecording, curRecording));
     826        tuningRequests.enqueue(TuningRequest(kFlagRecording, newRecording));
    754827        SET_NEXT();
    755828    }
    756829    else if (TRANSITION(kState_RecordingOnly, kState_None))
     
    805878void TVRec::SetOption(RecordingProfile &profile, const QString &name)
    806879{
    807880    int value = profile.byName(name)->getValue().toInt();
    808     recorder->SetOption(name, value);
     881    newRecorder->SetOption(name, value);
    809882}
    810883
    811884/** \fn TVRec::SetupRecorderMux(RecordingProfile&)
     
    9431016 */
    9441017bool TVRec::SetupNewRecorder(RecordingProfile &profile)
    9451018{
    946     recorder = recorderMux->CreateNewRecorder(this);
     1019    newRecorder = recorderMux->CreateNewRecorder(this);
    9471020    if (genOpt.cardtype == "MPEG")
    9481021    {
    9491022#ifdef USING_IVTV
     
    9541027    {
    9551028#ifdef USING_V4L
    9561029        VERBOSE(VB_RECORD, LOC + QString("Creating new HDTVRecorder"));
    957         ringBuffer->SetWriteBufferSize(4*1024*1024);
    958         recorder->SetOption("wait_for_seqstart", genOpt.wait_for_seqstart);
     1030        newRingBuffer->SetWriteBufferSize(4*1024*1024);
     1031        newRecorder->SetOption("wait_for_seqstart", genOpt.wait_for_seqstart);
    9591032#endif // USING_V4L
    9601033    }
    9611034    else if (genOpt.cardtype == "FIREWIRE")
     
    9651038        VERBOSE(VB_RECORD, LOC + QString("Creating new DarwinFirewireRecorder"));
    9661039# else
    9671040        VERBOSE(VB_RECORD, LOC + QString("Creating new FirewireRecorder"));
    968         recorder->SetOption("port",       fwOpt.port);
    969         recorder->SetOption("node",       fwOpt.node);
    970         recorder->SetOption("speed",      fwOpt.speed);
    971         recorder->SetOption("model",      fwOpt.model);
    972         recorder->SetOption("connection", fwOpt.connection);
     1041        newRecorder->SetOption("port",       fwOpt.port);
     1042        newRecorder->SetOption("node",       fwOpt.node);
     1043        newRecorder->SetOption("speed",      fwOpt.speed);
     1044        newRecorder->SetOption("model",      fwOpt.model);
     1045        newRecorder->SetOption("connection", fwOpt.connection);
    9731046# endif // !CONFIG_DARWIN
    9741047#endif // USING_FIREWIRE
    9751048    }
     
    9771050    {
    9781051#ifdef USING_DBOX2
    9791052        VERBOSE(VB_RECORD, LOC + QString("Creating new DBox2Recorder"));
    980         recorder->SetOption("port",     dboxOpt.port);
    981         recorder->SetOption("host",     dboxOpt.host);
    982         recorder->SetOption("httpport", dboxOpt.httpport);
     1053        newRecorder->SetOption("port",     dboxOpt.port);
     1054        newRecorder->SetOption("host",     dboxOpt.host);
     1055        newRecorder->SetOption("httpport", dboxOpt.httpport);
    9831056#endif // USING_DBOX2
    9841057    }
    9851058    else if (genOpt.cardtype == "HDHOMERUN")
    9861059    {
    9871060#ifdef USING_HDHOMERUN
    9881061        VERBOSE(VB_RECORD, LOC + QString("Creating new HDHRRecorder"));
    989         ringBuffer->SetWriteBufferSize(4*1024*1024);
    990         recorder->SetOption("wait_for_seqstart", genOpt.wait_for_seqstart);
     1062        newRingBuffer->SetWriteBufferSize(4*1024*1024);
     1063        newRecorder->SetOption("wait_for_seqstart", genOpt.wait_for_seqstart);
    9911064#endif // USING_HDHOMERUN
    9921065    }
    9931066    else if (genOpt.cardtype == "DVB")
    9941067    {
    9951068#ifdef USING_DVB
    9961069        VERBOSE(VB_RECORD, LOC + QString("Creating new DVBRecorder"));
    997         ringBuffer->SetWriteBufferSize(4*1024*1024);
    998         recorder->SetOption("wait_for_seqstart", genOpt.wait_for_seqstart);
    999         recorder->SetOption("dvb_on_demand",     dvbOpt.dvb_on_demand);
     1070        newRingBuffer->SetWriteBufferSize(4*1024*1024);
     1071        newRecorder->SetOption("wait_for_seqstart", genOpt.wait_for_seqstart);
     1072        newRecorder->SetOption("dvb_on_demand",     dvbOpt.dvb_on_demand);
    10001073#endif // USING_DVB
    10011074    }
    10021075    else
     
    10041077#ifdef USING_V4L
    10051078        // V4L/MJPEG/GO7007 from here on
    10061079        VERBOSE(VB_RECORD, LOC + QString("Creating new NuppelVideoRecorder"));
    1007         recorder->SetOption("skipbtaudio", genOpt.skip_btaudio);
     1080        newRecorder->SetOption("skipbtaudio", genOpt.skip_btaudio);
    10081081#endif // USING_V4L
    10091082    }
    10101083
    1011     if (recorder)
     1084    if (newRecorder)
    10121085    {
    1013         recorder->SetOptionsFromProfile(
     1086        newRecorder->SetOptionsFromProfile(
    10141087            &profile, genOpt.videodev, genOpt.audiodev, genOpt.vbidev);
    1015         recorder->SetRingBuffer(ringBuffer);
    1016         recorder->Initialize();
     1088        newRecorder->SetRingBuffer(newRingBuffer);
     1089        newRecorder->Initialize();
    10171090
    10181091        return true;
    10191092    }
     
    10521125
    10531126    VERBOSE(VB_RECORD, LOC + "TeardownRecorder - Start");
    10541127
     1128    // SPLIT This should shutdown each recorder
     1129    if (!recorders.isEmpty())
     1130    {
     1131        VERBOSE(VB_RECORD, LOC + "There are still recorders attached to mux");
     1132    }
     1133
    10551134    if (recorderMux && HasFlags(kFlagRecorderRunning))
    10561135    {
    10571136        // This is a bad way to calculate this, the framerate
     
    10831162
    10841163        delete recorderMux;
    10851164        recorderMux = NULL;
    1086         delete recorder;
    1087         recorder = NULL;
    10881165    }
    10891166
     1167    // SPLIT this should be deleted
    10901168    if (ringBuffer)
    10911169        ringBuffer->StopReads();
    10921170
     1171    // SPLIT this should be deleted, or atleast move to where each recording
     1172    // is stoped
    10931173    if (curRecording)
    10941174    {
    10951175        if (!killFile)
     
    11551235DVBRecorder *TVRec::GetDVBRecorder(void)
    11561236{
    11571237#ifdef USING_DVB
    1158     return dynamic_cast<DVBRecorder*>(recorder);
     1238    return dynamic_cast<DVBRecorder*>(newRecorder);
    11591239#else // if !USING_DVB
    11601240    return NULL;
    11611241#endif // !USING_DVB
     
    11641244HDTVRecorder *TVRec::GetHDTVRecorder(void)
    11651245{
    11661246#ifdef USING_V4L
    1167     return dynamic_cast<HDTVRecorder*>(recorder);
     1247    return dynamic_cast<HDTVRecorder*>(newRecorder);
    11681248#else // if !USING_V4L
    11691249    return NULL;
    11701250#endif // USING_V4L
     
    11731253HDHRRecorder *TVRec::GetHDHRRecorder(void)
    11741254{
    11751255#ifdef USING_HDHOMERUN
    1176     return dynamic_cast<HDHRRecorder*>(recorder);
     1256    return dynamic_cast<HDHRRecorder*>(newRecorder);
    11771257#else // if !USING_HDHOMERUN
    11781258    return NULL;
    11791259#endif // !USING_HDHOMERUN
     
    13881468
    13891469    while (HasFlags(kFlagRunMainLoop))
    13901470    {
     1471        if (newRecording)
     1472            VERBOSE(VB_RECORD, LOC + QString("Noticed newRecording(%1)").arg(newRecording->title));
     1473
    13911474        // If there is a state change queued up, do it...
    13921475        if (changeState)
    13931476        {
     1477            VERBOSE(VB_RECORD, LOC + "SPLIT: changeState");
    13941478            HandleStateChange();
    13951479            ClearFlags(kFlagFrontendReady | kFlagCancelNextRecording);
    13961480            SetFlags(kFlagAskAllowRecording);
     
    14081492        // Handle any tuning events..
    14091493        HandleTuning();
    14101494
     1495        // SPLIT
     1496        // Additional new recordings on the same mux are added here
     1497        // Setup the recorder
     1498        if (recorderMux && newRecording)
     1499        {
     1500            VERBOSE(VB_RECORD, LOC + "Adding additional recorders");
     1501
     1502            RecordingProfile profile;
     1503            QString profileName = load_profile(genOpt.cardtype, NULL, newRecording, profile);
     1504
     1505            SetRingBuffer(new RingBuffer(newRecording->GetFileName(), true));
     1506
     1507            if (!SetupNewRecorder(profile))
     1508                VERBOSE(VB_RECORD, LOC_ERR + "Failed to add an additional recorder!");
     1509
     1510            newRecorder->SetRecording(newRecording);
     1511
     1512            DoneAddingRecording();
     1513        }
     1514        // End add additional new recordings on the same mux
     1515        // new recordings should be added to the list by now
     1516
    14111517        // If we have a pending recording and AskAllowRecording is set
    14121518        // and the frontend is ready send an ASK_RECORDING query to frontend.
    14131519        if (pendingRecording && HasFlags(kFlagAskAllowRecording))
    14141520        {
     1521            VERBOSE(VB_RECORD, LOC + "SPLIT: Ask Allow Recording");
    14151522            ClearFlags(kFlagAskAllowRecording);
    14161523
    14171524            if (GetState() == kState_WatchingLiveTV)
     
    14411548
    14421549        // If we are recording a program, check if the recording is
    14431550        // over or someone has asked us to finish the recording.
    1444         if (GetState() == kState_RecordingOnly &&
     1551        if (recorderMux && GetState() == kState_RecordingOnly &&
    14451552            (QDateTime::currentDateTime() > recordEndTime ||
    14461553             HasFlags(kFlagFinishRecording)))
    14471554        {
    1448             ChangeState(kState_None);
     1555            VERBOSE(VB_RECORD, LOC + "SPLIT: Finishing Previous Recording");
     1556            StopRecording(curRecordings.first());
     1557            if (curRecordings.isEmpty())
     1558                ChangeState(kState_None);
    14491559            ClearFlags(kFlagFinishRecording);
    14501560        }
    14511561
    1452         if (curRecording)
    1453             curRecording->UpdateInUseMark();
     1562        for (ProgramInfo *rec = curRecordings.first();
     1563             rec; rec = curRecordings.next())
     1564        {
     1565            rec->UpdateInUseMark();
     1566        }
    14541567
    14551568        // Check for the end of the current program..
    14561569        if (GetState() == kState_WatchingLiveTV)
    14571570        {
     1571            VERBOSE(VB_RECORD, LOC + "SPLIT: Watching LiveTV");
    14581572#define LIVETV_END (now >= curRecording->endts)
    14591573// use the following instead to test ringbuffer switching
    14601574//static QDateTime last = QDateTime::currentDateTime();
     
    14981612        // state (either kState_RecordingOnly or kState_None).
    14991613        if (HasFlags(kFlagExitPlayer))
    15001614        {
     1615            VERBOSE(VB_RECORD, LOC + "SPLIT: Exit Player");
    15011616            if (internalState == kState_WatchingLiveTV)
    15021617                ChangeState(kState_None);
    15031618            else if (StateIsPlaying(internalState))
     
    15391654        }
    15401655    }
    15411656 
     1657    VERBOSE(VB_RECORD, LOC + "SPLIT: RunTV exited while loop");
     1658
    15421659    if (GetState() != kState_None)
    15431660    {
    15441661        ChangeState(kState_None);
     
    23162433bool TVRec::SetVideoFiltersForChannel(uint  sourceid,
    23172434                                      const QString &channum)
    23182435{
    2319     if (!recorder)
     2436    if (!newRecorder)
    23202437        return false;
    23212438
    23222439    QString videoFilters = ChannelUtil::GetVideoFilters(sourceid, channum);
    23232440    if (!videoFilters.isEmpty())
    23242441    {
    2325         recorder->SetVideoFilters(videoFilters);
     2442        newRecorder->SetVideoFilters(videoFilters);
    23262443        return true;
    23272444    }
    23282445
     
    23802497 *  \sa EncoderLink::GetFramesWritten(), RemoteEncoder::GetFramesWritten()
    23812498 *  \return Number of frames if query succeeds, -1 otherwise.
    23822499 */
     2500// SPLIT this should take in a ProgramInfo *
    23832501long long TVRec::GetFramesWritten(void)
    23842502{
    23852503    QMutexLocker lock(&stateChangeLock);
    23862504
    2387     if (recorder)
    2388         return recorder->GetFramesWritten();
     2505    if (newRecorder)
     2506        return newRecorder->GetFramesWritten();
    23892507    return -1;
    23902508}
    23912509
     
    24112529 *      RemoteEncoder::GetKeyframePosition(long long)
    24122530 *  \return Byte position of keyframe if query succeeds, -1 otherwise.
    24132531 */
     2532// SPLIT this thould take in a ProgramInfo *
    24142533long long TVRec::GetKeyframePosition(long long desired)
    24152534{
    24162535    QMutexLocker lock(&stateChangeLock);
    24172536
    2418     if (recorder)
    2419         return recorder->GetKeyframePosition(desired);
     2537    if (newRecorder)
     2538        return newRecorder->GetKeyframePosition(desired);
    24202539    return -1;
    24212540}
    24222541
     
    31593278{
    31603279    QMutexLocker lock(&stateChangeLock);
    31613280
    3162     RingBuffer *rb_old = ringBuffer;
    3163     ringBuffer = rb;
     3281    RingBuffer *rb_old = newRingBuffer;
     3282    newRingBuffer = rb;
    31643283
    31653284    if (rb_old && (rb_old != rb))
    31663285    {
     
    32293348    if (HasFlags(kFlagWaitingForRecPause))
    32303349    {
    32313350        VERBOSE(VB_RECORD, LOC + "RaceTrace: 6");
     3351        VERBOSE(VB_RECORD, LOC + QString("RecorderMux = %1").arg((unsigned int)recorderMux));
    32323352        if (!recorderMux->IsPaused())
    32333353            return;
    32343354
    32353355        ClearFlags(kFlagWaitingForRecPause);
    32363356#ifdef USING_DVB
    3237         if (GetDVBRecorder())
     3357        if (GetDVBRecorderMux() && GetDVBRecorder())
    32383358        {
    32393359            // We currently need to close the file descriptor for
    32403360            // DVB signal monitoring to work with some drivers
     
    35253645
    35263646    if (use_dr)
    35273647    {
     3648        VERBOSE(VB_RECORD, LOC + "SPLIT: Using Dummy Recorder");
    35283649        // We need there to be a ringbuffer for these modes
    35293650        bool ok;
    35303651        ProgramInfo *tmp = pseudoLiveTVRecording;
     
    37473868
    37483869    if (tvchain)
    37493870    {
     3871        VERBOSE(VB_RECORD, LOC + "SPLIT: Creating LiveTV RingBuffer");
    37503872        bool ok;
    37513873        if (!ringBuffer)
    37523874        {
     
    37543876            SetFlags(kFlagRingBufferReady);
    37553877        }
    37563878        else
    3757             ok = SwitchLiveTVRingBuffer(true, !had_dummyrec && recorder);
     3879            ok = SwitchLiveTVRingBuffer(true, !had_dummyrec && newRecorder);
    37583880        if (!ok)
    37593881        {
    37603882            VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create RingBuffer 2");
     
    37663888    if (lastTuningRequest.flags & kFlagRecording)
    37673889    {
    37683890        SetRingBuffer(new RingBuffer(rec->GetFileName(), true));
    3769         if (!ringBuffer->IsOpen())
     3891        if (!newRingBuffer->IsOpen())
    37703892        {
    37713893            VERBOSE(VB_IMPORTANT, LOC_ERR +
    37723894                    QString("RingBuffer '%1' not open...")
     
    37773899        }
    37783900    }
    37793901
    3780     if (!ringBuffer)
     3902    if (!newRingBuffer)
    37813903    {
    37823904        VERBOSE(VB_IMPORTANT, LOC_ERR + QString(
    3783                     "Failed to start recorder!  ringBuffer is NULL\n"
     3905                    "Failed to start recorder!  newRingBuffer is NULL\n"
    37843906                    "\t\t\t\t  Tuning request was %1\n")
    37853907                .arg(lastTuningRequest.toString()));
    37863908
     
    38353957        channel->Open(); // Needed because of NVR::MJPEGInit()
    38363958
    38373959    if (rec)
    3838         recorder->SetRecording(rec);
     3960        newRecorder->SetRecording(rec);
     3961
     3962    DoneAddingRecording();
    38393963
    38403964    // Setup for framebuffer capture devices..
    38413965    if (channel)
     
    39054029
    39064030    SwitchLiveTVRingBuffer(true, !had_dummyrec);
    39074031
    3908     recorderMux->Reset();
     4032    newRecorder->Reset();
    39094033    if (had_dummyrec)
    39104034    {
    3911         recorder->SetRingBuffer(ringBuffer);
     4035        newRecorder->SetRingBuffer(newRingBuffer);
    39124036        ProgramInfo *progInfo = tvchain->GetProgramAt(-1);
    3913         recorder->SetRecording(progInfo);
     4037        newRecorder->SetRecording(progInfo);
    39144038        delete progInfo;
    39154039    }
    39164040
     
    41904314    tvchain->AppendNewProgram(pginfo, channel->GetCurrentName(),
    41914315                              channel->GetCurrentInput(), discont);
    41924316
    4193     if (set_rec && recorder)
     4317    if (set_rec && newRecorder)
    41944318    {
    4195         recorder->SetNextRecording(pginfo, rb);
     4319        newRecorder->SetNextRecording(pginfo, rb);
    41964320        if (discont)
    4197             recorder->CheckForRingBufferSwitch();
     4321            newRecorder->CheckForRingBufferSwitch();
    41984322        delete pginfo;
    41994323        SetFlags(kFlagRingBufferReady);
    42004324    }
     
    42094333    return true;
    42104334}
    42114335
     4336void TVRec::DoneAddingRecording()
     4337{
     4338    VERBOSE(VB_RECORD, LOC + QString("Unlocking newRecordingLock for %1")
     4339                                .arg(newRecording->title));
     4340    curRecordings.append(newRecording);
     4341    curRecordings.Sort(comp_recend);
     4342    recordEndTime = GetRecordEndTime(curRecordings.getFirst());
     4343    ringBuffers[newRecording] = newRingBuffer;
     4344    recorders[newRecording] = newRecorder;
     4345    newRecording = NULL;
     4346    newRingBuffer = NULL;
     4347    newRecorder = NULL;
     4348    newRecordingLock.unlock();
     4349}
     4350
    42124351QString TuningRequest::toString(void) const
    42134352{
    42144353    return QString("Program(%1) channel(%2) input(%3) flags(%4)")
  • libs/libmythtv/recorderbase.h

    old new  
    5757     */
    5858    void SetRingBuffer(RingBuffer *rbuf);
    5959
     60    /** \brief StopRecording() removes this recorder from the list of
     61     *         current recorders in RecorderMuxBase recorder list.
     62     */
     63    virtual void StopRecording();
     64
    6065    /** \brief Set an specific option.
    6166     *
    6267     *   Base options include: codec, audiodevice, videodevice, vbidevice,
  • libs/libmythtv/recordermuxbase.h

    old new  
    3838    RecorderMuxBase(TVRec *rec);
    3939    virtual ~RecorderMuxBase();
    4040
     41    void RemoveRecording(RecorderBase *rec);
     42
    4143    /// \brief Sets the video frame rate.
    4244    void SetFrameRate(double rate)
    4345    {
     
    157159    virtual bool PauseAndWait(int timeout = 100);
    158160
    159161    TVRec         *tvrec;
    160     RecorderBase  *recorder;    // SPLIT this should be a QPtrList<RecorderBase>
     162    QPtrList<RecorderBase>  recorders;
     163    QMutex                  recLock;
    161164
    162165    QString        audiodevice;
    163166    QString        videodevice;
  • libs/libmythtv/recorderbase.cpp

    old new  
    101101                    "SetStrOption(...%1): Option not in profile.").arg(name));
    102102}
    103103
     104void RecorderBase::StopRecording()
     105{
     106    recMux->RemoveRecording(this);
     107}
     108
    104109void RecorderBase::CheckForRingBufferSwitch(void)
    105110{
    106111    nextRingBufferLock.lock();
  • libs/libmythtv/recordermuxbase.cpp

    old new  
    1313#define LOC_ERR QString("RecMuxBase(%1) Error: ").arg(videodevice)
    1414
    1515RecorderMuxBase::RecorderMuxBase(TVRec *rec)
    16     : tvrec(rec), recorder(NULL),
     16    : tvrec(rec),
    1717      audiodevice("/dev/dsp"), videodevice("/dev/video"), vbidevice("/dev/vbi"),
    1818      vbimode(0), ntsc(true), ntsc_framerate(true), video_frame_rate(29.97),
    1919      request_pause(false), paused(false)
     
    2424
    2525RecorderMuxBase::~RecorderMuxBase(void)
    2626{
     27    recLock.lock();
     28    recorders.setAutoDelete(true);
     29    recLock.unlock();
     30}
     31
     32void RecorderMuxBase::RemoveRecording(RecorderBase *rec)
     33{
     34    QMutexLocker locker(&recLock);
     35
     36    QString msg = QString("Trying to remove %1 from:").arg((unsigned int)rec);
     37    for (RecorderBase *r = recorders.first(); r; r = recorders.next())
     38        msg += QString("\n%1").arg((unsigned int)r);
     39    VERBOSE(VB_RECORD, msg);
     40
     41    rec->FinishRecording();
     42    recorders.remove(rec);
     43    if (recorders.isEmpty())
     44        StopRecording();
    2745}
    2846
    2947void RecorderMuxBase::SetOption(const QString &name, const QString &value)
  • libs/libmythtv/programinfo.cpp

    old new  
    15241524                           const ProgramInfo        *pg,
    15251525                           const ScheduledRecording *schd)
    15261526{
     1527    VERBOSE(VB_RECORD, QString("Inserting \"%1\" into recorded").arg(pg->title));
    15271528    query.prepare("LOCK TABLES recorded WRITE");
    15281529    if (!query.exec())
    15291530    {
     
    38933894 *                                                                           *
    38943895 * ************************************************************************* */
    38953896
     3897void ProgramList::ToStringList(QStringList &list) const
     3898{
     3899    char tmp[64];
     3900
     3901    // you can't iterate over a const QPtrList, copy it and iterate over
     3902    // the copy to keep this function const
     3903    ProgramList t(*this);
     3904
     3905    INT_TO_LIST(t.count());
     3906    for (ProgramInfo *pginfo = t.first(); pginfo; pginfo = t.next())
     3907    {
     3908        pginfo->ToStringList(list);
     3909    }
     3910}
     3911
     3912bool ProgramList::FromStringList(QStringList &list, int offset)
     3913{
     3914    QStringList::iterator it = list.at(offset);
     3915    return FromStringList(list, it);
     3916}
     3917
     3918bool ProgramList::FromStringList(QStringList &list, QStringList::iterator &it)
     3919{
     3920    const char *listerror = "ProgramList::FromStringList, not enough items "
     3921                            "in list.\n";
     3922    QStringList::iterator listend = list.end();
     3923    QString ts;
     3924    int progCount;
     3925
     3926    INT_FROM_LIST(progCount)
     3927
     3928    for (int i = 0; i < progCount; i++)
     3929    {
     3930        ProgramInfo *pginfo = new ProgramInfo;
     3931        pginfo->FromStringList(list, it);
     3932        append(pginfo);
     3933    }
     3934
     3935    return true;
     3936}
     3937
    38963938bool ProgramList::FromScheduler(bool &hasConflicts, QString rectable,
    38973939                                int recordid)
    38983940{
  • libs/libmythtv/programinfo.h

    old new  
    338338        return at(index);
    339339    };
    340340
     341    void ToStringList(QStringList &list) const;
     342    bool FromStringList(QStringList &list, int offset);
     343    bool FromStringList(QStringList &list, QStringList::iterator &it);
     344
    341345    bool FromScheduler(bool &hasConflicts, QString altTable = "", int recordid=-1);
    342346    bool FromScheduler(void) {
    343347        bool dummyConflicts;
  • libs/libmythtv/mpegrecorder.cpp

    old new  
    4040#endif
    4141}
    4242
    43 #define LOC QString("MPEGRec(%1): ").arg(videodevice)
    44 #define LOC_WARN QString("MPEGRec(%1) Warning: ").arg(videodevice)
    45 #define LOC_ERR QString("MPEGRec(%1) Error: ").arg(videodevice)
     43#define LOC QString("MPEGRec(%1): ").arg((unsigned int)this)
     44#define LOC_WARN QString("MPEGRec(%1) Warning: ").arg((unsigned int)this)
     45#define LOC_ERR QString("MPEGRec(%1) Error: ").arg((unsigned int)this)
    4646
    4747MpegRecorder::MpegRecorder(TVRec *rec, MpegRecorderMux *mux) :
    4848    RecorderBase(rec, mux),
     
    5454    // Position map support
    5555    positionMapLock(false)
    5656{
     57    VERBOSE(VB_RECORD, LOC + QString("MpegRecorder ctor"));
    5758}
    5859
    5960MpegRecorder::~MpegRecorder()
  • libs/libmythtv/mpegrecordermux.cpp

    old new  
    486486        if (PauseAndWait(100))
    487487            continue;
    488488
    489         if ((deviceIsMpegFile) && (dynamic_cast<MpegRecorder*>(recorder)->framesWritten))
     489        // This code limits the rate at which frames are written from an MPEG
     490        // file.  Use a local count of the total number of frames written by
     491        // this mux thread.
     492        if (deviceIsMpegFile && framesWritten)
    490493        {
    491494            elapsed = (elapsedTimer.elapsed() / 1000.0) + 1;
    492             while ((dynamic_cast<MpegRecorder*>(recorder)->framesWritten / elapsed) > 30)
     495            while ((framesWritten / elapsed) > 30)
    493496            {
    494497                usleep(50000);
    495498                elapsed = (elapsedTimer.elapsed() / 1000.0) + 1;
     
    557560        }
    558561    }
    559562
    560     recorder->FinishRecording();
    561 
    562563    delete[] buffer;
    563564    recording = false;
    564565
     
    567568
    568569RecorderBase *MpegRecorderMux::CreateNewRecorder(TVRec *tvrec)
    569570{
    570     recorder = new MpegRecorder(tvrec, this);
    571     return recorder;
     571    MpegRecorder *rec = new MpegRecorder(tvrec, this);
     572    recLock.lock();
     573    recorders.append(rec);
     574    recLock.unlock();
     575    return rec;
    572576}
    573577
    574578bool MpegRecorderMux::SetupRecording(void)
    575579{
    576580    leftovers = 0xFFFFFFFF;
    577     VERBOSE(VB_RECORD, QString("recorder = %1").arg((int)recorder));
    578     dynamic_cast<MpegRecorder*>(recorder)->numgops = 0;
    579     dynamic_cast<MpegRecorder*>(recorder)->lastseqstart = 0;
     581    VERBOSE(VB_RECORD, QString("recorder = %1").arg((unsigned int)this));
    580582    return true;
    581583}
    582584
     
    594596
    595597    while (bufptr < buffer + len)
    596598    {
     599        recLock.lock();
     600
    597601        v = *bufptr++;
    598602        if (state == 0x000001)
    599603        {
     
    601605           
    602606            if (state == PACK_HEADER)
    603607            {
    604                 long long startpos = recorder->ringBuffer->GetWritePosition();
    605                 startpos += buildbuffersize + bufptr - bufstart - 4;
    606                 dynamic_cast<MpegRecorder*>(recorder)->lastpackheaderpos = startpos;
     608                long long startpos = buildbuffersize + bufptr - bufstart - 4;
     609
     610                for (MpegRecorder *rec = dynamic_cast<MpegRecorder*>(recorders.first());             rec; rec = dynamic_cast<MpegRecorder*>(recorders.next()))
     611                {
     612                    rec->lastpackheaderpos = rec->ringBuffer->GetWritePosition() + startpos;
     613                }
    607614
    608615                int curpos = bufptr - bufstart - 4;
    609616                if (curpos < 0)
     
    611618                    // header was split
    612619                    buildbuffersize += curpos;
    613620                    if (buildbuffersize > 0)
    614                         recorder->ringBuffer->Write(buildbuffer, buildbuffersize);
     621                    {
     622                        for (MpegRecorder *rec = dynamic_cast<MpegRecorder*>(recorders.first());              rec; rec = dynamic_cast<MpegRecorder*>(recorders.next()))
     623                        {
     624                            rec->ringBuffer->Write(buildbuffer, buildbuffersize);
     625                        }
     626                    }
    615627
    616628                    buildbuffersize = 4;
    617629                    memcpy(buildbuffer, &state, 4);
     
    628640                    leftlen -= curpos;
    629641
    630642                    if (buildbuffersize > 0)
    631                         recorder->ringBuffer->Write(buildbuffer, buildbuffersize);
     643                    {
     644                        for (MpegRecorder *rec = dynamic_cast<MpegRecorder*>(recorders.first());              rec; rec = dynamic_cast<MpegRecorder*>(recorders.next()))
     645                        {
     646                            rec->ringBuffer->Write(buildbuffer, buildbuffersize);
     647                        }
     648                    }
    632649
    633650                    buildbuffersize = 0;
    634651                }
     
    636653
    637654            if (state == SEQ_START)
    638655            {
    639                 dynamic_cast<MpegRecorder*>(recorder)->lastseqstart = dynamic_cast<MpegRecorder*>(recorder)->lastpackheaderpos;
     656                for (MpegRecorder *rec = dynamic_cast<MpegRecorder*>(recorders.first());              rec; rec = dynamic_cast<MpegRecorder*>(recorders.next()))
     657                {
     658                    rec->lastseqstart = rec->lastpackheaderpos;
     659                }
    640660            }
    641661
    642             if (state == GOP_START && dynamic_cast<MpegRecorder*>(recorder)->lastseqstart == dynamic_cast<MpegRecorder*>(recorder)->lastpackheaderpos)
     662            for (MpegRecorder *rec = dynamic_cast<MpegRecorder*>(recorders.first());              rec; rec = dynamic_cast<MpegRecorder*>(recorders.next()))
    643663            {
    644                 dynamic_cast<MpegRecorder*>(recorder)->framesWritten = dynamic_cast<MpegRecorder*>(recorder)->numgops * keyframedist;
    645                 dynamic_cast<MpegRecorder*>(recorder)->numgops++;
    646                 dynamic_cast<MpegRecorder*>(recorder)->HandleKeyframe();
     664                if (state == GOP_START &&
     665                    rec->lastseqstart == rec->lastpackheaderpos)
     666                {
     667                    if (rec == dynamic_cast<MpegRecorder*>(recorders.getFirst()))
     668                    {
     669                        // count the number of frames written by this mux
     670                        framesWritten = numgops * keyframedist;
     671                        numgops++;
     672                    }
     673
     674                    rec->framesWritten = rec->numgops * keyframedist;
     675                    rec->numgops++;
     676                    rec->HandleKeyframe();
     677                }
    647678            }
    648679        }
    649680        else
    650681            state = ((state << 8) | v) & 0xFFFFFF;
     682
     683        recLock.unlock();
    651684    }
    652685
    653686    leftovers = state;
    654687
    655688    if (buildbuffersize + leftlen > kBuildBufferMaxSize)
    656689    {
    657         recorder->ringBuffer->Write(buildbuffer, buildbuffersize);
     690        recLock.lock();
     691        for (MpegRecorder *rec = dynamic_cast<MpegRecorder*>(recorders.first());
     692             rec; rec = dynamic_cast<MpegRecorder*>(recorders.next()))
     693        {
     694            rec->ringBuffer->Write(buildbuffer, buildbuffersize);
     695        }
     696        recLock.unlock();
    658697        buildbuffersize = 0;
    659698    }
    660699
     
    670709
    671710void MpegRecorderMux::Reset(void)
    672711{
    673     dynamic_cast<MpegRecorder*>(recorder)->Reset();
     712    // reset all recorders
     713    recLock.lock();
     714    for (MpegRecorder *rec = dynamic_cast<MpegRecorder*>(recorders.first());
     715         rec; rec = dynamic_cast<MpegRecorder*>(recorders.next()))
     716    {
     717        rec->Reset();
     718    }
     719    recLock.unlock();
    674720
    675721    leftovers = 0xFFFFFFFF;
    676722    buildbuffersize = 0;
  • libs/libmythtv/NuppelVideoRecorderMux.cpp

    old new  
    125125
    126126    go7007 = false;
    127127    resetcapture = false;
     128
     129    recorder = NULL;
    128130}
    129131
    130132NuppelVideoRecorderMux::~NuppelVideoRecorderMux(void)
  • libs/libmythtv/NuppelVideoRecorderMux.h

    old new  
    195195
    196196    bool go7007;
    197197    bool resetcapture;
     198
     199    // SPLIT delete this
     200    RecorderBase *recorder;
    198201};
    199202
    200203#endif
  • programs/mythbackend/encoderlink.cpp

    old new  
    162162 *  \brief Returns true if rec is actually being recorded by TVRec.
    163163 * 
    164164 *   This waits for TVRec to enter a state other than kState_ChangingState
    165  *   Then it checks TVRec::GetRecording() against rec.
    166  *  \param rec Recording to check against TVRec::GetRecording().
     165 *   Then it checks TVRec::GetRecordings() against rec.
     166 *  \param rec Recording to check against TVRec::GetRecordings().
    167167 *  \sa IsRecording(const ProgramInfo*)
    168168 */
    169169bool EncoderLink::MatchesRecording(const ProgramInfo *rec)
    170170{
    171171    bool retval = false;
    172     ProgramInfo *tvrec = NULL;
     172    ProgramList tvrecList;
    173173
    174174    if (local)
    175175    {
     
    177177            usleep(100);
    178178
    179179        if (IsBusyRecording())
    180             tvrec = tv->GetRecording();
     180            tvrecList = tv->GetRecordings();
    181181
    182         if (tvrec)
     182        for (ProgramInfo *tvrec = tvrecList.first(); tvrec; tvrec = tvrecList.current())
    183183        {
    184184            if (tvrec->chanid == rec->chanid &&
    185185                tvrec->recstartts == rec->recstartts)
     
    187187                retval = true;
    188188            }
    189189
     190            tvrecList.removeFirst();
    190191            delete tvrec;
    191192        }
    192193    }
     
    394395 *
    395396 *  \return +1 if the recording started successfully,
    396397 *          -1 if TVRec is busy doing something else, 0 otherwise.
    397  *  \sa RecordPending(const ProgramInfo*, int), StopRecording()
     398 *  \sa RecordPending(const ProgramInfo*, int), StopRecording(ProgramInfo *)
    398399 */
    399400RecStatusType EncoderLink::StartRecording(const ProgramInfo *rec)
    400401{
     
    424425    return retval;
    425426}
    426427
    427 /** \fn EncoderLink::GetRecording()
    428  *  \brief Returns TVRec's current recording.
     428/** \fn EncoderLink::GetRecordings()
     429 *  \brief Returns TVRec's current recordings.
    429430 *
    430  *   Caller is responsible for deleting the ProgramInfo when done with it.
     431 *   Caller is responsible for deleting the %ProgramInfo items in the
     432 *   %ProgramList when done with it.
    431433 *  \return Returns TVRec's current recording if it succeeds, NULL otherwise.
    432434 */
    433 ProgramInfo *EncoderLink::GetRecording(void)
     435ProgramList EncoderLink::GetRecordings(void)
    434436{
    435     ProgramInfo *info = NULL;
    436 
    437437    if (local)
    438         info = tv->GetRecording();
     438        return tv->GetRecordings();
    439439    else if (sock)
    440         info = sock->GetRecording(m_capturecardnum);
    441 
    442     return info;
     440        return sock->GetRecordings(m_capturecardnum);
     441    else
     442        return ProgramList(false);
    443443}
    444444
    445 /** \fn EncoderLink::StopRecording()
     445/** \fn EncoderLink::StopRecording(ProgramInfo *)
    446446 *  \brief Tells TVRec to stop recording immediately.
    447447 *         <b>This only works on local recorders.</b>
    448448 *  \sa StartRecording(const ProgramInfo *rec), FinishRecording()
    449449 */
    450 void EncoderLink::StopRecording(void)
     450void EncoderLink::StopRecording(ProgramInfo *rec)
    451451{
    452452    endRecordingTime = QDateTime::currentDateTime().addDays(-2);
    453453    startRecordingTime = endRecordingTime;
     
    455455
    456456    if (local)
    457457    {
    458         tv->StopRecording();
     458        tv->StopRecording(rec);
    459459        return;
    460460    }
    461461}
     
    463463/** \fn EncoderLink::FinishRecording()
    464464 *  \brief Tells TVRec to stop recording, but only after "overrecord" seconds.
    465465 *         <b>This only works on local recorders.</b>
    466  *  \sa StopRecording()
     466 *  \sa StopRecording(ProgramInfo *)
    467467 */
    468468void EncoderLink::FinishRecording(void)
    469469{
  • programs/mythbackend/encoderlink.h

    old new  
    6161    bool MatchesRecording(const ProgramInfo *rec);
    6262    void RecordPending(const ProgramInfo *rec, int secsleft);
    6363    RecStatusType StartRecording(const ProgramInfo *rec);
    64     void StopRecording(void);
     64    void StopRecording(ProgramInfo *rec);
    6565    void FinishRecording(void);
    6666    void FrontendReady(void);
    6767    void CancelNextRecording(bool);
    6868    bool WouldConflict(const ProgramInfo *rec);
    6969
    7070    bool IsReallyRecording(void);
    71     ProgramInfo *GetRecording(void);
     71    ProgramList GetRecordings(void);
    7272    float GetFramerate(void);
    7373    long long GetFramesWritten(void);
    7474    long long GetFilePosition(void);
  • programs/mythbackend/mainserver.cpp

    old new  
    10121012                       "LEFT JOIN record ON recorded.recordid = record.recordid "
    10131013                       "LEFT JOIN channel ON recorded.chanid = channel.chanid "
    10141014                       "LEFT JOIN recordedprogram ON (recorded.chanid = recordedprogram.chanid "
    1015                               "AND recorded.starttime = recordedprogram.starttime) "
     1015                              "AND recorded.starttime = recordedprogram.starttime "
     1016                              "AND recorded.title = recordedprogram.title) "
    10161017                       "WHERE (recorded.deletepending = 0 OR "
    10171018                              "DATE_ADD(recorded.lastmodified, "
    10181019                                       "INTERVAL 5 MINUTE) <= NOW()) "
     
    15671568
    15681569            if (num > 0)
    15691570            {
    1570                 (*encoderList)[num]->StopRecording();
     1571                (*encoderList)[num]->StopRecording(pginfo);
    15711572                pginfo->recstatus = rsRecorded;
    15721573                if (m_sched)
    15731574                    m_sched->UpdateRecStatus(pginfo);
     
    16061607        {
    16071608            recnum = iter.key();
    16081609
    1609             elink->StopRecording();
     1610            elink->StopRecording(pginfo);
    16101611
    16111612            while (elink->IsBusyRecording() ||
    16121613                   elink->GetState() == kState_ChangingState)
     
    16661667
    16671668            if (num > 0)
    16681669            {
    1669                 (*encoderList)[num]->StopRecording();
     1670                (*encoderList)[num]->StopRecording(pginfo);
    16701671                pginfo->recstatus = rsRecorded;
    16711672                if (m_sched)
    16721673                    m_sched->UpdateRecStatus(pginfo);
     
    16961697        {
    16971698            resultCode = iter.key();
    16981699
    1699             elink->StopRecording();
     1700            elink->StopRecording(pginfo);
    17001701
    17011702            while (elink->IsBusyRecording() ||
    17021703                   elink->GetState() == kState_ChangingState)
     
    24382439        long long value = enc->GetMaxBitrate();
    24392440        encodeLongLong(retlist, value);
    24402441    }
    2441     else if (command == "GET_CURRENT_RECORDING")
     2442    else if (command == "GET_CURRENT_RECORDINGS")
    24422443    {
    2443         ProgramInfo *info = enc->GetRecording();
    2444         info->ToStringList(retlist);
    2445         delete info;
     2444        ProgramList info = enc->GetRecordings();
     2445        info.ToStringList(retlist);
     2446
     2447        for (ProgramInfo *pginfo = info.first(); pginfo; pginfo = info.next())
     2448            delete pginfo;
    24462449    }
    24472450    else if (command == "GET_KEYFRAME_POS")
    24482451    {
     
    24692472        if (!retlist.size())
    24702473            retlist << "ok";
    24712474    }
    2472     else if (command == "GET_RECORDING")
     2475    else if (command == "GET_RECORDINGS")
    24732476    {
    2474         ProgramInfo *pginfo = enc->GetRecording();
    2475         if (pginfo)
    2476         {
    2477             pginfo->ToStringList(retlist);
     2477        ProgramList info = enc->GetRecordings();
     2478        info.ToStringList(retlist);
     2479
     2480        for (ProgramInfo *pginfo = info.first(); pginfo; pginfo = info.next())
    24782481            delete pginfo;
    2479         }
    2480         else
    2481         {
    2482             ProgramInfo dummy;
    2483             dummy.ToStringList(retlist);
    2484         }
    24852482    }
    24862483    else if (command == "FRONTEND_READY")
    24872484    {
     
    27872784        long long value = enc->GetMaxBitrate();
    27882785        encodeLongLong(retlist, value);
    27892786    }
    2790     else if (command == "GET_CURRENT_RECORDING")
     2787    else if (command == "GET_CURRENT_RECORDINGS")
    27912788    {
    2792         ProgramInfo *info = enc->GetRecording();
    2793         info->ToStringList(retlist);
    2794         delete info;
     2789        ProgramList info = enc->GetRecordings();
     2790        info.ToStringList(retlist);
     2791
     2792        for (ProgramInfo *pginfo = info.first(); pginfo; pginfo = info.next())
     2793            delete pginfo;
    27952794    }
    27962795
    27972796    SendResponse(pbssock, retlist);
     
    36993698    {
    37003699        EncoderLink *elink = iter.data();
    37013700        elink->CancelNextRecording(true);
    3702         ProgramInfo *pinfo = elink->GetRecording();
    3703         pinfo->ToStringList(strlist);
    3704         delete pinfo;
     3701        ProgramList info = elink->GetRecordings();
     3702        info.ToStringList(strlist);
     3703
     3704        for (ProgramInfo *pginfo = info.first(); pginfo; pginfo = info.next())
     3705            delete pginfo;
    37053706    }
    37063707
    37073708    WriteStringList(masterServerSock, strlist);
     
    38713872                case kState_RecordingOnly:
    38723873                case kState_WatchingRecording:
    38733874                {
    3874                     ProgramInfo *pInfo = elink->GetRecording();
     3875                    ProgramList info = elink->GetRecordings();
    38753876
    3876                     if (pInfo)
     3877                    for (ProgramInfo *pInfo = info.first(); pInfo; pInfo = info.next())
    38773878                    {
    38783879                        FillProgramInfo(pDoc, encoder, pInfo);
    38793880                        delete pInfo;
  • programs/mythbackend/playbacksock.cpp

    old new  
    217217    return ret;
    218218}
    219219
    220 /** \fn *PlaybackSock::GetRecording(int)
    221  *  \brief Returns the ProgramInfo being used by any current recording.
     220/** \fn *PlaybackSock::GetRecordings(int)
     221 *  \brief Returns the ProgramList being used by any current recording.
    222222 *
    223  *   Caller is responsible for deleting the ProgramInfo when done with it.
     223 *   Caller is responsible for deleting the ProgramInfo in the ProgramList
     224 *   when done with it.
    224225 *  \param capturecardnum cardid of recorder
    225226 */
    226 ProgramInfo *PlaybackSock::GetRecording(int capturecardnum)
     227ProgramList PlaybackSock::GetRecordings(int capturecardnum)
    227228{
    228229    QStringList strlist = QString("QUERY_REMOTEENCODER %1")
    229230        .arg(capturecardnum);
    230231
    231     strlist << "GET_CURRENT_RECORDING";
     232    strlist << "GET_CURRENT_RECORDINGS";
    232233
    233234    SendReceiveStringList(strlist);
    234235
    235     ProgramInfo *info = new ProgramInfo();
    236     info->FromStringList(strlist, 0);
     236    ProgramList info(false);
     237    info.FromStringList(strlist, 0);
    237238    return info;
    238239}
    239240
  • programs/mythbackend/playbacksock.h

    old new  
    5454    bool IsBusy(int capturecardnum);
    5555    int GetEncoderState(int capturecardnum);
    5656    long long GetMaxBitrate(int capturecardnum);
    57     ProgramInfo *GetRecording(int capturecardnum);
     57    ProgramList GetRecordings(int capturecardnum);
    5858    bool EncoderIsRecording(int capturecardnum, const ProgramInfo *pginfo);
    5959    RecStatusType StartRecording(int capturecardnum,
    6060                                 const ProgramInfo *pginfo);
  • libs/libmythtv/dtvrecordermux.cpp

    old new  
    1111#include "programinfo.h"
    1212#include "mpegtables.h"
    1313#include "dtvrecordermux.h"
     14#include "dtvrecorder.h"
    1415#include "recorderbase.h"
    1516#include "tv_rec.h"
    1617
     
    9091// documented in recorderbase.h
    9192void DTVRecorderMux::Reset(void)
    9293{
    93     recorder->Reset();
     94    // reset all recorders
     95    recLock.lock();
     96    for (DTVRecorder *rec = dynamic_cast<DTVRecorder*>(recorders.first());
     97         rec; rec = dynamic_cast<DTVRecorder*>(recorders.next()))
     98    {
     99        rec->Reset();
     100    }
    94101
    95102    //_recording
    96103    _error                      = false;
  • libs/libmythtv/dvbrecordermux.cpp

    old new  
    243243
    244244RecorderBase *DVBRecorderMux::CreateNewRecorder(TVRec *tvrec)
    245245{
    246     recorder = new DVBRecorder(tvrec, this);
    247     return recorder;
     246    DVBRecorder *rec = new DVBRecorder(tvrec, this);
     247    recLock.lock();
     248    recorders.append(rec);
     249    recLock.unlock();
     250    return rec;
    248251}
    249252
    250253void DVBRecorderMux::CloseFilters(void)
     
    475478
    476479    Close();
    477480
    478     recorder->FinishRecording();
    479 
    480481    _recording = false;
    481482}
    482483
     
    486487    {
    487488        QMutexLocker read_lock(&_pid_lock);
    488489        uint next_cc;
    489         if (_pat && _pmt && recorder)
     490        if (_pat && _pmt)
    490491        {
     492            recLock.lock();
     493
    491494            next_cc = (_pat->tsheader()->ContinuityCounter()+1)&0xf;
    492495            _pat->tsheader()->SetContinuityCounter(next_cc);
    493             dynamic_cast<DVBRecorder*>(recorder)->BufferedWrite(*(reinterpret_cast<TSPacket*>(_pat->tsheader())));
     496            for (DVBRecorder *rec = dynamic_cast<DVBRecorder*>(recorders.first());
     497                 rec; rec = dynamic_cast<DVBRecorder*>(recorders.next()))
     498            {
     499                rec->BufferedWrite(*(reinterpret_cast<TSPacket*>(_pat->tsheader())));
     500            }
    494501
    495502            unsigned char buf[8 * 1024];
    496503            uint cc = _pmt->tsheader()->ContinuityCounter();
    497504            uint size = _pmt->WriteAsTSPackets(buf, cc);
    498505            _pmt->tsheader()->SetContinuityCounter(cc);
    499506
    500             for (uint i = 0; i < size ; i += TSPacket::SIZE)
    501                 dynamic_cast<DVBRecorder*>(recorder)->BufferedWrite(*(reinterpret_cast<TSPacket*>(&buf[i])));
     507            for (DVBRecorder *rec = dynamic_cast<DVBRecorder*>(recorders.first());
     508                 rec; rec = dynamic_cast<DVBRecorder*>(recorders.next()))
     509            {
     510                for (uint i = 0; i < size ; i += TSPacket::SIZE)
     511                    rec->BufferedWrite(*(reinterpret_cast<TSPacket*>(&buf[i])));
     512            }
    502513
    503514            _ts_packets_until_psip_sync = TSPACKETS_BETWEEN_PSIP_SYNC;
     515
     516            recLock.unlock();
    504517        }
    505518    }
    506519    else
     
    750763
    751764    // Check for keyframes and count frames
    752765    if (info->isVideo)
    753         dynamic_cast<DVBRecorder*>(recorder)->_buffer_packets = !dynamic_cast<DVBRecorder*>(recorder)->FindKeyframes(&tspacket);
     766    {
     767        recLock.lock();
     768        for (DVBRecorder *rec = dynamic_cast<DVBRecorder*>(recorders.first());
     769             rec; rec = dynamic_cast<DVBRecorder*>(recorders.next()))
     770        {
     771            rec->_buffer_packets = !rec->FindKeyframes(&tspacket);
     772        }
     773        recLock.unlock();
     774    }
    754775
     776    // SPLIT this needs to be modified
    755777    // Sync recording start to first keyframe
     778#if 0
    756779    if (_wait_for_keyframe_option && dynamic_cast<DVBRecorder*>(recorder)->_first_keyframe<0)
    757780        return;
     781#endif
    758782
    759783    // Sync streams to the first Payload Unit Start Indicator
    760784    // _after_ first keyframe iff _wait_for_keyframe_option is true
     
    772796    WritePATPMT();
    773797
    774798    // Write Data
    775     dynamic_cast<DVBRecorder*>(recorder)->BufferedWrite(tspacket);
     799    recLock.lock();
     800    for (DVBRecorder *rec = dynamic_cast<DVBRecorder*>(recorders.first());
     801         rec; rec = dynamic_cast<DVBRecorder*>(recorders.next()))
     802    {
     803        rec->BufferedWrite(tspacket);
     804    }
     805    recLock.unlock();
    776806}
    777807
    778808void DVBRecorderMux::GetTimeStamp(const TSPacket& tspacket)
  • libs/libmythtv/hdtvrecordermux.cpp

    old new  
    115115      _atsc_stream_data(NULL),
    116116      _resync_count(0)
    117117{
     118    recorder = NULL;
    118119    SetStreamData(new ATSCStreamData(-1, DEFAULT_SUBCHANNEL));
    119120
    120121    _buffer_size = TSPacket::SIZE * 1500;
  • libs/libmythtv/hdtvrecordermux.h

    old new  
    106106        unsigned char  * writePtr;
    107107        unsigned char  * endPtr;
    108108    } ringbuf;
     109
     110    RecorderBase *recorder;
    109111};
    110112
    111113#endif