Ticket #11713: 11713_v2.patch

File 11713_v2.patch, 31.3 KB (added by Jim Stichnoth, 11 years ago)

Rename preroll==>progstart, and playpos==>lastplaypos.

  • mythtv/libs/libmyth/programinfo.cpp

    diff --git a/mythtv/libs/libmyth/programinfo.cpp b/mythtv/libs/libmyth/programinfo.cpp
    index 8764134..9757c18 100644
    a b uint64_t ProgramInfo::QueryBookmark(uint chanid, const QDateTime &recstartts)  
    26952695    return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
    26962696}
    26972697
     2698/** \brief Gets any progstart position in database,
     2699 *         unless the ignore progstart flag is set.
     2700 *
     2701 *  \return Progstart position in frames if the query is executed
     2702 *          and succeeds, zero otherwise.
     2703 */
     2704uint64_t ProgramInfo::QueryProgStart(void) const
     2705{
     2706    if (programflags & FL_IGNOREPROGSTART)
     2707        return 0;
     2708
     2709    frm_dir_map_t bookmarkmap;
     2710    QueryMarkupMap(bookmarkmap, MARK_UTIL_PROGSTART);
     2711
     2712    return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
     2713}
     2714
     2715/** \brief Gets any lastplaypos position in database,
     2716 *         unless the ignore lastplaypos flag is set.
     2717 *
     2718 *  \return LastPlayPos position in frames if the query is executed
     2719 *          and succeeds, zero otherwise.
     2720 */
     2721uint64_t ProgramInfo::QueryLastPlayPos(void) const
     2722{
     2723    if (programflags & FL_IGNORELASTPLAYPOS)
     2724        return 0;
     2725
     2726    frm_dir_map_t bookmarkmap;
     2727    QueryMarkupMap(bookmarkmap, MARK_UTIL_LASTPLAYPOS);
     2728
     2729    return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
     2730}
     2731
    26982732/** \brief Queries "dvdbookmark" table for bookmarking DVD serial
    26992733 *         number. Deletes old dvd bookmarks if "delbookmark" is set.
    27002734 *
  • mythtv/libs/libmyth/programinfo.h

    diff --git a/mythtv/libs/libmyth/programinfo.h b/mythtv/libs/libmyth/programinfo.h
    index ce8159d..a37ac05 100644
    a b class MPUBLIC ProgramInfo  
    452452
    453453    uint32_t GetProgramFlags(void)        const { return programflags; }
    454454    ProgramInfoType GetProgramInfoType(void) const
    455         { return (ProgramInfoType)((programflags & FL_TYPEMASK) >> 16); }
     455        { return (ProgramInfoType)((programflags & FL_TYPEMASK) >> 20); }
    456456    bool IsGeneric(void) const;
    457457    bool IsInUsePlaying(void)   const { return programflags & FL_INUSEPLAYING;}
    458458    bool IsCommercialFree(void) const { return programflags & FL_CHANCOMMFREE;}
    class MPUBLIC ProgramInfo  
    489489    // Quick sets
    490490    void SetTitle(const QString &t) { title = t; title.detach(); }
    491491    void SetProgramInfoType(ProgramInfoType t)
    492         { programflags &= ~FL_TYPEMASK; programflags |= ((uint32_t)t<<16); }
     492        { programflags &= ~FL_TYPEMASK; programflags |= ((uint32_t)t<<20); }
    493493    void SetPathname(const QString&) const;
    494494    void SetChanID(uint _chanid) { chanid = _chanid; }
    495495    void SetScheduledStartTime(const QDateTime &dt) { startts      = dt;    }
    class MPUBLIC ProgramInfo  
    532532        programflags &= ~FL_IGNOREBOOKMARK;
    533533        programflags |= (ignore) ? FL_IGNOREBOOKMARK : 0;
    534534    }
     535    /// \brief If "ignore" is true QueryProgStart() will return 0, otherwise
     536    ///        QueryProgStart() will return the progstart position if it exists.
     537    void SetIgnoreProgStart(bool ignore)
     538    {
     539        programflags &= ~FL_IGNOREPROGSTART;
     540        programflags |= (ignore) ? FL_IGNOREPROGSTART : 0;
     541    }
     542    /// \brief If "ignore" is true QueryLastPlayPos() will return 0, otherwise
     543    ///        QueryLastPlayPos() will return the last playback position
     544    ///        if it exists.
     545    void SetIgnoreLastPlayPos(bool ignore)
     546    {
     547        programflags &= ~FL_IGNORELASTPLAYPOS;
     548        programflags |= (ignore) ? FL_IGNORELASTPLAYPOS : 0;
     549    }
    535550    virtual void SetRecordingID(uint _recordedid) { recordedid = _recordedid; }
    536551    void SetRecordingStatus(RecStatus::Type status) { recstatus = status; }
    537552    void SetRecordingRuleType(RecordingType type) { rectype   = type;   }
    class MPUBLIC ProgramInfo  
    544559    uint        QueryMplexID(void) const;
    545560    QDateTime   QueryBookmarkTimeStamp(void) const;
    546561    uint64_t    QueryBookmark(void) const;
     562    uint64_t    QueryProgStart(void) const;
     563    uint64_t    QueryLastPlayPos(void) const;
    547564    CategoryType QueryCategoryType(void) const;
    548565    QStringList QueryDVDBookmark(const QString &serialid) const;
    549566    bool        QueryIsEditing(void) const;
    class MPUBLIC ProgramInfo  
    658675    static QMap<QString,bool> QueryJobsRunning(int type);
    659676    static QStringList LoadFromScheduler(const QString &altTable, int recordid);
    660677
    661   protected:
    662678    // Flagging map support methods
    663679    void QueryMarkupMap(frm_dir_map_t&, MarkTypes type,
    664680                        bool merge = false) const;
    class MPUBLIC ProgramInfo  
    667683    void ClearMarkupMap(MarkTypes type = MARK_ALL,
    668684                        int64_t min_frm = -1, int64_t max_frm = -1) const;
    669685
     686  protected:
    670687    // Creates a basename from the start and end times
    671688    QString CreateRecordBasename(const QString &ext) const;
    672689
  • mythtv/libs/libmyth/programtypes.cpp

    diff --git a/mythtv/libs/libmyth/programtypes.cpp b/mythtv/libs/libmyth/programtypes.cpp
    index 26b5357..26d3935 100644
    a b QString toString(MarkTypes type)  
    5353        case MARK_VIDEO_RATE:   return "VIDEO_RATE";
    5454        case MARK_DURATION_MS:  return "DURATION_MS";
    5555        case MARK_TOTAL_FRAMES: return "TOTAL_FRAMES";
     56        case MARK_UTIL_PROGSTART: return "UTIL_PROGSTART";
     57        case MARK_UTIL_LASTPLAYPOS: return "UTIL_LASTPLAYPOS";
    5658    }
    5759
    5860    return "unknown";
  • mythtv/libs/libmyth/programtypes.h

    diff --git a/mythtv/libs/libmyth/programtypes.h b/mythtv/libs/libmyth/programtypes.h
    index d85ee94..373d3ad 100644
    a b typedef enum {  
    7474    MARK_VIDEO_RATE    = 32,
    7575    MARK_DURATION_MS   = 33,
    7676    MARK_TOTAL_FRAMES  = 34,
     77    MARK_UTIL_PROGSTART = 40,
     78    MARK_UTIL_LASTPLAYPOS = 41,
    7779} MarkTypes;
    7880MPUBLIC QString toString(MarkTypes type);
    7981
    typedef enum FlagMask {  
    145147    FL_DUPLICATE      = 0x00002000,
    146148    FL_REACTIVATE     = 0x00004000,
    147149    FL_IGNOREBOOKMARK = 0x00008000,
     150    FL_IGNOREPROGSTART   = 0x00010000,
     151    FL_IGNORELASTPLAYPOS = 0x00020000,
    148152    // if you move the type mask please edit {Set,Get}ProgramInfoType()
    149     FL_TYPEMASK       = 0x000F0000,
    150     FL_INUSERECORDING = 0x00100000,
    151     FL_INUSEPLAYING   = 0x00200000,
    152     FL_INUSEOTHER     = 0x00400000,
     153    FL_TYPEMASK       = 0x00F00000,
     154    FL_INUSERECORDING = 0x01000000,
     155    FL_INUSEPLAYING   = 0x02000000,
     156    FL_INUSEOTHER     = 0x04000000,
    153157} ProgramFlag;
    154158
    155159typedef enum ProgramInfoType {
  • mythtv/libs/libmythtv/mythplayer.cpp

    diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
    index e52b3c9..6c6abfb 100644
    a b void MythPlayer::EventStart(void)  
    28792879    player_ctx->LockPlayingInfo(__FILE__, __LINE__);
    28802880    {
    28812881        if (player_ctx->playingInfo)
     2882        {
     2883            // When initial playback gets underway, we override the ProgramInfo
     2884            // flags such that future calls to GetBookmark() will consider only
     2885            // an actual bookmark and not progstart or lastplaypos information.
    28822886            player_ctx->playingInfo->SetIgnoreBookmark(false);
     2887            player_ctx->playingInfo->SetIgnoreProgStart(true);
     2888            player_ctx->playingInfo->SetIgnoreLastPlayPos(true);
     2889        }
    28832890    }
    28842891    player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    28852892    commBreakMap.LoadMap(player_ctx, framesPlayed);
    uint64_t MythPlayer::GetBookmark(void)  
    36103617    {
    36113618        player_ctx->LockPlayingInfo(__FILE__, __LINE__);
    36123619        if (player_ctx->playingInfo)
     3620        {
    36133621            bookmark = player_ctx->playingInfo->QueryBookmark();
     3622            if (bookmark == 0)
     3623                bookmark = player_ctx->playingInfo->QueryProgStart();
     3624            if (bookmark == 0)
     3625                bookmark = player_ctx->playingInfo->QueryLastPlayPos();
     3626        }
    36143627        player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    36153628    }
    36163629
  • mythtv/libs/libmythtv/recorders/recorderbase.cpp

    diff --git a/mythtv/libs/libmythtv/recorders/recorderbase.cpp b/mythtv/libs/libmythtv/recorders/recorderbase.cpp
    index 669c872..a6fc9fa 100644
    a b RecorderBase::RecorderBase(TVRec *rec)  
    5656      request_pause(false),     paused(false),
    5757      request_recording(false), recording(false),
    5858      nextRingBuffer(NULL),     nextRecording(NULL),
    59       positionMapType(MARK_GOP_BYFRAME)
     59      positionMapType(MARK_GOP_BYFRAME),
     60      estimatedProgStartMS(0), lastSavedKeyframe(0), lastSavedDuration(0)
    6061{
    6162    ClearStatistics();
    6263    QMutexLocker locker(avcodeclock);
    void RecorderBase::SetRecording(const RecordingInfo *pginfo)  
    114115        //       instance which may lead to the possibility that changes made
    115116        //       in the database by one are overwritten by the other
    116117        curRecording = new RecordingInfo(*pginfo);
     118        // Compute an estimate of the actual progstart delay for setting the
     119        // MARK_UTIL_PROGSTART mark.  We can't reliably use
     120        // curRecording->GetRecordingStartTime() because the scheduler rounds it
     121        // to the nearest minute, so we use the current time instead.
     122        estimatedProgStartMS =
     123            MythDate::current().msecsTo(curRecording->GetScheduledStartTime());
    117124        RecordingFile *recFile = curRecording->GetRecordingFile();
    118125        recFile->m_containerFormat = m_containerFormat;
    119126        recFile->Save();
    void RecorderBase::SavePositionMap(bool force, bool finished)  
    579586    bool needToSave = force;
    580587    positionMapLock.lock();
    581588
    582     uint delta_size = positionMapDelta.size();
     589    bool has_delta = !positionMapDelta.empty();
    583590    // set pm_elapsed to a fake large value if the timer hasn't yet started
    584591    uint pm_elapsed = (positionMapTimer.isRunning()) ?
    585592        positionMapTimer.elapsed() : ~0;
    586593    // save on every 1.5 seconds if in the first few frames of a recording
    587594    needToSave |= (positionMap.size() < 30) &&
    588         (delta_size >= 1) && (pm_elapsed >= 1500);
     595        has_delta && (pm_elapsed >= 1500);
    589596    // save every 10 seconds later on
    590     needToSave |= (delta_size >= 1) && (pm_elapsed >= 10000);
     597    needToSave |= has_delta && (pm_elapsed >= 10000);
    591598    // Assume that durationMapDelta is the same size as
    592599    // positionMapDelta and implicitly use the same logic about when
    593600    // to same durationMapDelta.
    void RecorderBase::SavePositionMap(bool force, bool finished)  
    595602    if (curRecording && needToSave)
    596603    {
    597604        positionMapTimer.start();
    598         if (delta_size)
     605        if (has_delta)
    599606        {
    600607            // copy the delta map because most times we are called it will be in
    601608            // another thread and we don't want to lock the main recorder thread
    void RecorderBase::SavePositionMap(bool force, bool finished)  
    609616            curRecording->SavePositionMapDelta(deltaCopy, positionMapType);
    610617            curRecording->SavePositionMapDelta(durationDeltaCopy,
    611618                                               MARK_DURATION_MS);
     619
     620            TryWriteProgStartMark(durationDeltaCopy);
    612621        }
    613622        else
    614623        {
    void RecorderBase::SavePositionMap(bool force, bool finished)  
    626635    }
    627636}
    628637
     638void RecorderBase::TryWriteProgStartMark(const frm_pos_map_t &durationDeltaCopy)
     639{
     640    // Note: all log strings contain "progstart mark" for searching.
     641    if (estimatedProgStartMS <= 0)
     642    {
     643        // Do nothing because no progstart mark is needed.
     644        LOG(VB_RECORD, LOG_DEBUG,
     645            QString("No progstart mark needed because delta=%1")
     646            .arg(estimatedProgStartMS));
     647        return;
     648    }
     649    frm_pos_map_t::const_iterator last_it = durationDeltaCopy.end();
     650    --last_it;
     651    long long bookmarkFrame = 0;
     652    LOG(VB_RECORD, LOG_DEBUG,
     653        QString("durationDeltaCopy.begin() = (%1,%2)")
     654        .arg(durationDeltaCopy.begin().key())
     655        .arg(durationDeltaCopy.begin().value()));
     656    if (estimatedProgStartMS > *last_it)
     657    {
     658        // Do nothing because we haven't reached recstartts yet.
     659        LOG(VB_RECORD, LOG_DEBUG,
     660            QString("No progstart mark yet because estimatedProgStartMS=%1 "
     661                    "and *last_it=%2")
     662            .arg(estimatedProgStartMS).arg(*last_it));
     663    }
     664    else if (lastSavedDuration <= estimatedProgStartMS &&
     665             estimatedProgStartMS < *durationDeltaCopy.begin())
     666    {
     667        // Set progstart mark @ lastSavedKeyframe
     668        LOG(VB_RECORD, LOG_DEBUG,
     669            QString("Set progstart mark=%1 because %2<=%3<%4")
     670            .arg(lastSavedKeyframe).arg(lastSavedDuration)
     671            .arg(estimatedProgStartMS).arg(*durationDeltaCopy.begin()));
     672        bookmarkFrame = lastSavedKeyframe;
     673    }
     674    else if (*durationDeltaCopy.begin() <= estimatedProgStartMS &&
     675             estimatedProgStartMS < *last_it)
     676    {
     677        frm_pos_map_t::const_iterator upper_it = durationDeltaCopy.begin();
     678        for (; upper_it != durationDeltaCopy.end(); ++upper_it)
     679        {
     680            if (*upper_it > estimatedProgStartMS)
     681            {
     682                --upper_it;
     683                // Set progstart mark @ upper_it.key()
     684                LOG(VB_RECORD, LOG_DEBUG,
     685                    QString("Set progstart mark=%1 because "
     686                            "estimatedProgStartMS=%2 and upper_it.value()=%3")
     687                    .arg(upper_it.key()).arg(estimatedProgStartMS)
     688                    .arg(upper_it.value()));
     689                bookmarkFrame = upper_it.key();
     690                break;
     691            }
     692        }
     693    }
     694    else
     695    {
     696        // do nothing
     697        LOG(VB_RECORD, LOG_DEBUG, "No progstart mark due to fallthrough");
     698    }
     699    if (bookmarkFrame)
     700    {
     701        frm_dir_map_t progStartMap;
     702        progStartMap[bookmarkFrame] = MARK_UTIL_PROGSTART;
     703        curRecording->SaveMarkupMap(progStartMap, MARK_UTIL_PROGSTART);
     704    }
     705    lastSavedKeyframe = last_it.key();
     706    lastSavedDuration = last_it.value();
     707    LOG(VB_RECORD, LOG_DEBUG,
     708        QString("Setting lastSavedKeyframe=%1 lastSavedDuration=%2 "
     709                "for progstart mark calculations")
     710        .arg(lastSavedKeyframe).arg(lastSavedDuration));
     711}
     712
    629713void RecorderBase::AspectChange(uint aspect, long long frame)
    630714{
    631715    MarkTypes mark = MARK_ASPECT_4_3;
  • mythtv/libs/libmythtv/recorders/recorderbase.h

    diff --git a/mythtv/libs/libmythtv/recorders/recorderbase.h b/mythtv/libs/libmythtv/recorders/recorderbase.h
    index 8d00836..9931413 100644
    a b class MTV_PUBLIC RecorderBase : public QRunnable  
    292292     */
    293293    void SetTotalFrames(uint64_t total_frames);
    294294
     295    void TryWriteProgStartMark(const frm_pos_map_t &durationDeltaCopy);
     296
    295297    TVRec         *tvrec;
    296298    RingBuffer    *ringBuffer;
    297299    bool           weMadeBuffer;
    class MTV_PUBLIC RecorderBase : public QRunnable  
    341343    frm_pos_map_t  durationMapDelta;
    342344    MythTimer      positionMapTimer;
    343345
     346    // ProgStart mark support
     347    qint64         estimatedProgStartMS;
     348    long long      lastSavedKeyframe;
     349    long long      lastSavedDuration;
     350
    344351    // Statistics
    345352    // Note: Once we enter RecorderBase::run(), only that thread can
    346353    // update these values safely. These values are read in that thread
  • mythtv/libs/libmythtv/tv_play.cpp

    diff --git a/mythtv/libs/libmythtv/tv_play.cpp b/mythtv/libs/libmythtv/tv_play.cpp
    index c9ee3de..138aeb2 100644
    a b const uint TV::kEndOfPlaybackFirstCheckTimer = 60000;  
    137137#else
    138138const uint TV::kEndOfPlaybackFirstCheckTimer = 5000;
    139139#endif
     140const uint TV::kSaveLastPlayPosTimeout       = 30000;
    140141
    141142/**
    142143 * \brief stores last program info. maintains info so long as
    bool TV::StartTV(ProgramInfo *tvrec, uint flags,  
    341342    {
    342343        curProgram = new ProgramInfo(*tvrec);
    343344        curProgram->SetIgnoreBookmark(flags & kStartTVIgnoreBookmark);
     345        curProgram->SetIgnoreProgStart(flags & kStartTVIgnoreProgStart);
     346        curProgram->SetIgnoreLastPlayPos(flags & kStartTVIgnoreLastPlayPos);
    344347    }
    345348
    346349    GetMythMainWindow()->PauseIdleTimer(true);
    TV::TV(void)  
    10641067      endOfPlaybackTimerId(0),      embedCheckTimerId(0),
    10651068      endOfRecPromptTimerId(0),     videoExitDialogTimerId(0),
    10661069      pseudoChangeChanTimerId(0),   speedChangeTimerId(0),
    1067       errorRecoveryTimerId(0),      exitPlayerTimerId(0)
     1070      errorRecoveryTimerId(0),      exitPlayerTimerId(0),
     1071      saveLastPlayPosTimerId(0)
    10681072{
    10691073    LOG(VB_GENERAL, LOG_INFO, LOC + "Creating TV object");
    10701074    ctorTime.start();
    bool TV::Init(bool createWindow)  
    13261330    errorRecoveryTimerId = StartTimer(kErrorRecoveryCheckFrequency, __LINE__);
    13271331    lcdTimerId           = StartTimer(1, __LINE__);
    13281332    speedChangeTimerId   = StartTimer(kSpeedChangeCheckFrequency, __LINE__);
     1333    saveLastPlayPosTimerId = StartTimer(kSaveLastPlayPosTimeout, __LINE__);
    13291334
    13301335    LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "-- end");
    13311336    return true;
    void TV::timerEvent(QTimerEvent *te)  
    27772782        HandleSpeedChangeTimerEvent();
    27782783    else if (timer_id == pipChangeTimerId)
    27792784        HandlePxPTimerEvent();
     2785    else if (timer_id == saveLastPlayPosTimerId)
     2786        HandleSaveLastPlayPosEvent();
    27802787    else
    27812788        handled = false;
    27822789
    void TV::PrepareToExitPlayer(PlayerContext *ctx, int line, BookmarkAction bookma  
    33213328            // Don't consider ourselves at the end if the recording is
    33223329            // in-progress.
    33233330            at_end &= !StateIsRecording(GetState(ctx));
     3331            bool clear_lastplaypos = true;
    33243332            if (at_end && allow_clear_at_end)
    33253333                SetBookmark(ctx, true);
    3326             if (!at_end && allow_set_before_end)
     3334            else if (!at_end && allow_set_before_end)
    33273335                SetBookmark(ctx, false);
     3336            else
     3337                clear_lastplaypos = false;
     3338            // If we are setting a bookmark upon exit (or equivalently clearing
     3339            // it due to exiting at the end), we clean up the unnecessary
     3340            // lastplaypos mark.
     3341            if (clear_lastplaypos && ctx->playingInfo)
     3342                ctx->playingInfo->ClearMarkupMap(MARK_UTIL_LASTPLAYPOS);
    33283343        }
    33293344        if (db_auto_set_watched)
    33303345            ctx->player->SetWatched();
    bool TV::HandleOSDVideoExit(PlayerContext *ctx, QString action)  
    1338313398    return hide;
    1338413399}
    1338513400
     13401void TV::HandleSaveLastPlayPosEvent(void)
     13402{
     13403    // Helper class to save the latest playback position (in a background thread
     13404    // to avoid playback glitches).  The ctor makes a copy of the ProgramInfo
     13405    // struct to avoid race conditions if playback ends and deletes objects
     13406    // before or while the background thread runs.
     13407    class PositionSaver : public QRunnable
     13408    {
     13409    public:
     13410        PositionSaver(const ProgramInfo &pginfo, uint64_t frame) :
     13411            m_pginfo(pginfo), m_frame(frame) {}
     13412        virtual void run(void)
     13413        {
     13414            LOG(VB_PLAYBACK, LOG_DEBUG,
     13415                QString("PositionSaver frame=%1").arg(m_frame));
     13416            frm_dir_map_t lastPlayPosMap;
     13417            lastPlayPosMap[m_frame] = MARK_UTIL_LASTPLAYPOS;
     13418            m_pginfo.ClearMarkupMap(MARK_UTIL_LASTPLAYPOS);
     13419            m_pginfo.SaveMarkupMap(lastPlayPosMap, MARK_UTIL_LASTPLAYPOS);
     13420        }
     13421    private:
     13422        const ProgramInfo m_pginfo;
     13423        const uint64_t m_frame;
     13424    };
     13425
     13426    PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
     13427    for (uint i = 0; mctx && i < player.size(); ++i)
     13428    {
     13429        PlayerContext *ctx = GetPlayer(mctx, i);
     13430        ctx->LockDeletePlayer(__FILE__, __LINE__);
     13431        bool playing = ctx->player && !ctx->player->IsPaused();
     13432        if (playing) // Don't bother saving lastplaypos while paused
     13433        {
     13434            uint64_t framesPlayed = ctx->player->GetFramesPlayed();
     13435            MThreadPool::globalInstance()->
     13436                start(new PositionSaver(*ctx->playingInfo, framesPlayed),
     13437                      "PositionSaver");
     13438        }
     13439        ReturnPlayerLock(ctx);
     13440    }
     13441    ReturnPlayerLock(mctx);
     13442
     13443    QMutexLocker locker(&timerIdLock);
     13444    KillTimer(saveLastPlayPosTimerId);
     13445    saveLastPlayPosTimerId = StartTimer(kSaveLastPlayPosTimeout, __LINE__);
     13446}
     13447
    1338613448void TV::SetLastProgram(const ProgramInfo *rcinfo)
    1338713449{
    1338813450    QMutexLocker locker(&lastProgramLock);
  • mythtv/libs/libmythtv/tv_play.h

    diff --git a/mythtv/libs/libmythtv/tv_play.h b/mythtv/libs/libmythtv/tv_play.h
    index 8ab38b1..339aee5 100644
    a b enum {  
    115115    kStartTVInPlayList       = 0x02,
    116116    kStartTVByNetworkCommand = 0x04,
    117117    kStartTVIgnoreBookmark   = 0x08,
     118    kStartTVIgnoreProgStart  = 0x10,
     119    kStartTVIgnoreLastPlayPos= 0x20,
    118120};
    119121
    120122class AskProgramInfo
    class MTV_PUBLIC TV : public QObject, public MenuItemDisplayer  
    409411    bool HandlePxPTimerEvent(void);
    410412    bool HandleLCDTimerEvent(void);
    411413    void HandleLCDVolumeTimerEvent(void);
     414    void HandleSaveLastPlayPosEvent();
    412415
    413416    // Commands used by frontend UI screens (PlaybackBox, GuideGrid etc)
    414417    void EditSchedule(const PlayerContext*,
    class MTV_PUBLIC TV : public QObject, public MenuItemDisplayer  
    979982    volatile int         speedChangeTimerId;
    980983    volatile int         errorRecoveryTimerId;
    981984    mutable volatile int exitPlayerTimerId;
     985    volatile int         saveLastPlayPosTimerId;
    982986    TimerContextMap      stateChangeTimerId;
    983987    TimerContextMap      signalMonitorTimerId;
    984988
    class MTV_PUBLIC TV : public QObject, public MenuItemDisplayer  
    10951099    static const uint kErrorRecoveryCheckFrequency;
    10961100    static const uint kEndOfRecPromptCheckFrequency;
    10971101    static const uint kEndOfPlaybackFirstCheckTimer;
     1102    static const uint kSaveLastPlayPosTimeout;
    10981103};
    10991104
    11001105#endif
  • mythtv/programs/mythfrontend/playbackbox.cpp

    diff --git a/mythtv/programs/mythfrontend/playbackbox.cpp b/mythtv/programs/mythfrontend/playbackbox.cpp
    index 1050b4a..360d457 100644
    a b bool PlaybackBox::Create()  
    556556    connect(m_recordingList, SIGNAL(itemSelected(MythUIButtonListItem*)),
    557557            SLOT(ItemSelected(MythUIButtonListItem*)));
    558558    connect(m_recordingList, SIGNAL(itemClicked(MythUIButtonListItem*)),
    559             SLOT(PlayFromBookmark(MythUIButtonListItem*)));
     559            SLOT(PlayFromBookmarkOrProgStart(MythUIButtonListItem*)));
    560560    connect(m_recordingList, SIGNAL(itemVisible(MythUIButtonListItem*)),
    561561            SLOT(ItemVisible(MythUIButtonListItem*)));
    562562    connect(m_recordingList, SIGNAL(itemLoaded(MythUIButtonListItem*)),
    void PlaybackBox::playSelectedPlaylist(bool _random)  
    21972197        this, new MythEvent("PLAY_PLAYLIST"));
    21982198}
    21992199
     2200void PlaybackBox::PlayFromBookmarkOrProgStart(MythUIButtonListItem *item)
     2201{
     2202    if (!item)
     2203        item = m_recordingList->GetItemCurrent();
     2204
     2205    if (!item)
     2206        return;
     2207
     2208    ProgramInfo *pginfo = item->GetData().value<ProgramInfo *>();
     2209
     2210    const bool ignoreBookmark = false;
     2211    const bool ignoreProgStart = false;
     2212    const bool ignoreLastPlayPos = true;
     2213    const bool underNetworkControl = false;
     2214    if (pginfo)
     2215        PlayX(*pginfo, ignoreBookmark, ignoreProgStart, ignoreLastPlayPos,
     2216              underNetworkControl);
     2217}
     2218
    22002219void PlaybackBox::PlayFromBookmark(MythUIButtonListItem *item)
    22012220{
    22022221    if (!item)
    void PlaybackBox::PlayFromBookmark(MythUIButtonListItem *item)  
    22072226
    22082227    ProgramInfo *pginfo = item->GetData().value<ProgramInfo *>();
    22092228
     2229    const bool ignoreBookmark = false;
     2230    const bool ignoreProgStart = true;
     2231    const bool ignoreLastPlayPos = true;
     2232    const bool underNetworkControl = false;
    22102233    if (pginfo)
    2211         PlayX(*pginfo, false, false);
     2234        PlayX(*pginfo, ignoreBookmark, ignoreProgStart, ignoreLastPlayPos,
     2235              underNetworkControl);
    22122236}
    22132237
    22142238void PlaybackBox::PlayFromBeginning(MythUIButtonListItem *item)
    void PlaybackBox::PlayFromBeginning(MythUIButtonListItem *item)  
    22212245
    22222246    ProgramInfo *pginfo = item->GetData().value<ProgramInfo *>();
    22232247
     2248    const bool ignoreBookmark = true;
     2249    const bool ignoreProgStart = true;
     2250    const bool ignoreLastPlayPos = true;
     2251    const bool underNetworkControl = false;
     2252    if (pginfo)
     2253        PlayX(*pginfo, ignoreBookmark, ignoreProgStart, ignoreLastPlayPos,
     2254              underNetworkControl);
     2255}
     2256
     2257void PlaybackBox::PlayFromLastPlayPos(MythUIButtonListItem *item)
     2258{
     2259    if (!item)
     2260        item = m_recordingList->GetItemCurrent();
     2261
     2262    if (!item)
     2263        return;
     2264
     2265    ProgramInfo *pginfo = item->GetData().value<ProgramInfo *>();
     2266
     2267    const bool ignoreBookmark = true;
     2268    const bool ignoreProgStart = true;
     2269    const bool ignoreLastPlayPos = false;
     2270    const bool underNetworkControl = false;
    22242271    if (pginfo)
    2225         PlayX(*pginfo, true, false);
     2272        PlayX(*pginfo, ignoreBookmark, ignoreProgStart, ignoreLastPlayPos,
     2273              underNetworkControl);
    22262274}
    22272275
    22282276void PlaybackBox::PlayX(const ProgramInfo &pginfo,
    22292277                        bool ignoreBookmark,
     2278                        bool ignoreProgStart,
     2279                        bool ignoreLastPlayPos,
    22302280                        bool underNetworkControl)
    22312281{
    22322282    if (!m_player)
    22332283    {
    2234         Play(pginfo, false, ignoreBookmark, underNetworkControl);
     2284        Play(pginfo, false, ignoreBookmark, ignoreProgStart, ignoreLastPlayPos,
     2285             underNetworkControl);
    22352286        return;
    22362287    }
    22372288
    void PlaybackBox::PlayX(const ProgramInfo &pginfo,  
    22422293            ignoreBookmark ? "1" : "0");
    22432294        m_player_selected_new_show.push_back(
    22442295            underNetworkControl ? "1" : "0");
     2296        // XXX add anything for ignoreProgStart and ignoreLastPlayPos?
    22452297    }
    22462298    Close();
    22472299}
    void PlaybackBox::selected(MythUIButtonListItem *item)  
    23242376    if (!item)
    23252377        return;
    23262378
    2327     PlayFromBookmark(item);
     2379    PlayFromBookmarkOrProgStart(item);
    23282380}
    23292381
    23302382void PlaybackBox::popupClosed(QString which, int result)
    void PlaybackBox::ShowGroupPopup()  
    24122464
    24132465bool PlaybackBox::Play(
    24142466    const ProgramInfo &rec,
    2415     bool inPlaylist, bool ignoreBookmark, bool underNetworkControl)
     2467    bool inPlaylist, bool ignoreBookmark, bool ignoreProgStart,
     2468    bool ignoreLastPlayPos, bool underNetworkControl)
    24162469{
    24172470    bool playCompleted = false;
    24182471
    bool PlaybackBox::Play(  
    24442497    uint flags =
    24452498        (inPlaylist          ? kStartTVInPlayList       : kStartTVNoFlags) |
    24462499        (underNetworkControl ? kStartTVByNetworkCommand : kStartTVNoFlags) |
     2500        (ignoreLastPlayPos   ? kStartTVIgnoreLastPlayPos: kStartTVNoFlags) |
     2501        (ignoreProgStart     ? kStartTVIgnoreProgStart  : kStartTVNoFlags) |
    24472502        (ignoreBookmark      ? kStartTVIgnoreBookmark   : kStartTVNoFlags);
    24482503
    24492504    playCompleted = TV::StartTV(&tvrec, flags);
    MythMenu* PlaybackBox::createPlayFromMenu()  
    29122967
    29132968    MythMenu *menu = new MythMenu(title, this, "slotmenu");
    29142969
     2970    if (pginfo->IsBookmarkSet())
    29152971        menu->AddItem(tr("Play from bookmark"), SLOT(PlayFromBookmark()));
    29162972    menu->AddItem(tr("Play from beginning"), SLOT(PlayFromBeginning()));
     2973    if (pginfo->QueryLastPlayPos())
     2974        menu->AddItem(tr("Play from last played position"),
     2975                      SLOT(PlayFromLastPlayPos()));
    29172976
    29182977    return menu;
    29192978}
    void PlaybackBox::ShowActionPopup(const ProgramInfo &pginfo)  
    31493208
    31503209    if (!sameProgram)
    31513210    {
    3152         if (pginfo.IsBookmarkSet())
     3211        if (pginfo.IsBookmarkSet() || pginfo.QueryLastPlayPos())
    31533212            m_popupMenu->AddItem(tr("Play from..."), NULL, createPlayFromMenu());
    31543213        else
    3155             m_popupMenu->AddItem(tr("Play"), SLOT(PlayFromBookmark()));
     3214            m_popupMenu->AddItem(tr("Play"),
     3215                                 SLOT(PlayFromBookmarkOrProgStart()));
    31563216    }
    31573217
    31583218    if (!m_player)
    void PlaybackBox::processNetworkControlCommand(const QString &command)  
    37433803
    37443804                pginfo.SetPathname(pginfo.GetPlaybackURL());
    37453805
    3746                 bool ignoreBookmark = (tokens[1] == "PLAY");
    3747                 PlayX(pginfo, ignoreBookmark, true);
     3806                const bool ignoreBookmark = (tokens[1] == "PLAY");
     3807                const bool ignoreProgStart = true;
     3808                const bool ignoreLastPlayPos = true;
     3809                const bool underNetworkControl = true;
     3810                PlayX(pginfo, ignoreBookmark, ignoreProgStart,
     3811                      ignoreLastPlayPos, underNetworkControl);
    37483812            }
    37493813            else
    37503814            {
    bool PlaybackBox::keyPressEvent(QKeyEvent *event)  
    38773941            if (action == "DELETE")
    38783942                deleteSelected(m_recordingList->GetItemCurrent());
    38793943            else if (action == ACTION_PLAYBACK)
    3880                 PlayFromBookmark();
     3944                PlayFromBookmarkOrProgStart();
    38813945            else if (action == "DETAILS" || action == "INFO")
    38823946                ShowDetails();
    38833947            else if (action == "CUSTOMEDIT")
    void PlaybackBox::customEvent(QEvent *event)  
    41544218                else if (pginfo)
    41554219                {
    41564220                    playnext = false;
    4157                     Play(*pginfo, kCheckForPlaylistAction == cat, false, false);
     4221                    const bool ignoreBookmark = false;
     4222                    const bool ignoreProgStart = false;
     4223                    const bool ignoreLastPlayPos = true;
     4224                    const bool underNetworkControl = false;
     4225                    Play(*pginfo, kCheckForPlaylistAction == cat,
     4226                         ignoreBookmark, ignoreProgStart, ignoreLastPlayPos,
     4227                         underNetworkControl);
    41584228                }
    41594229            }
    41604230
    void PlaybackBox::customEvent(QEvent *event)  
    41834253            }
    41844254
    41854255            ProgramInfo *pginfo = FindProgramInUILists(recordingID);
     4256            const bool ignoreBookmark = false;
     4257            const bool ignoreProgStart = true;
     4258            const bool ignoreLastPlayPos = true;
     4259            const bool underNetworkControl = false;
    41864260            if (pginfo)
    4187                 Play(*pginfo, true, false, false);
     4261                Play(*pginfo, true, ignoreBookmark, ignoreProgStart,
     4262                     ignoreLastPlayPos, underNetworkControl);
    41884263        }
    41894264        else if ((message == "SET_PLAYBACK_URL") && (me->ExtraDataCount() == 2))
    41904265        {
  • mythtv/programs/mythfrontend/playbackbox.h

    diff --git a/mythtv/programs/mythfrontend/playbackbox.h b/mythtv/programs/mythfrontend/playbackbox.h
    index 18ae480..44a41e2 100644
    a b class PlaybackBox : public ScheduleCommon  
    140140    void ItemVisible(MythUIButtonListItem *item);
    141141    void ItemLoaded(MythUIButtonListItem *item);
    142142    void selected(MythUIButtonListItem *item);
     143    void PlayFromBookmarkOrProgStart(MythUIButtonListItem *item = NULL);
    143144    void PlayFromBookmark(MythUIButtonListItem *item = NULL);
    144145    void PlayFromBeginning(MythUIButtonListItem *item = NULL);
     146    void PlayFromLastPlayPos(MythUIButtonListItem *item = NULL);
    145147    void deleteSelected(MythUIButtonListItem *item);
    146148
    147149    void SwitchList(void);
    class PlaybackBox : public ScheduleCommon  
    270272
    271273    void PlayX(const ProgramInfo &rec,
    272274               bool ignoreBookmark,
     275               bool ignoreProgStart,
     276               bool ignoreLastPlayPos,
    273277               bool underNetworkControl);
    274278
    275279    bool Play(const ProgramInfo &rec,
    276280              bool inPlaylist,
    277281              bool ignoreBookmark,
     282              bool ignoreProgStart,
     283              bool ignoreLastPlayPos,
    278284              bool underNetworkControl);
    279285
    280286    virtual ProgramInfo *GetCurrentProgram(void) const;