Ticket #7964: timestretch-predictive-frame-skip.patch

File timestretch-predictive-frame-skip.patch, 9.5 KB (added by jppoet@…, 14 years ago)

Predictively drop frames based on playback speed

  • libs/libmythtv/NuppelVideoPlayer.cpp

    old new NuppelVideoPlayer::NuppelVideoPlayer(boo 
    255255    text_size = 8 * (sizeof(teletextsubtitle) + VT_WIDTH);
    256256    for (int i = 0; i < MAXTBUFFER; i++)
    257257        txtbuffers[i].buffer = new unsigned char[text_size + 1];
     258
     259    m_skip_frame_idx = m_skip_frame_extra_idx = 0;
     260    m_skip_frame = m_skip_frame_extra = 0;
    258261}
    259262
    260263NuppelVideoPlayer::~NuppelVideoPlayer(void)
    bool NuppelVideoPlayer::Play(float speed 
    500503    audio_lock.lock();
    501504    if (audioOutput && unpauseaudio)
    502505        audio_paused = false;
    503    
     506
    504507    audio_lock.unlock();
    505508    if (player_ctx->buffer)
    506509        player_ctx->buffer->Unpause();
    bool NuppelVideoPlayer::IsPaused(bool *i 
    534537void NuppelVideoPlayer::PauseVideo(bool wait)
    535538{
    536539    QMutexLocker locker(&pauseUnpauseLock);
    537    
     540
    538541    if (wait)
    539542        video_actually_paused = false;
    540543    pausevideo = true;
    541    
     544
    542545    for (uint i = 0; wait && !video_actually_paused; i++)
    543546    {
    544547        videoThreadPaused.wait(&pauseUnpauseLock, 250);
    void NuppelVideoPlayer::AutoDeint(VideoF 
    10231026    m_scan_locked  = false;
    10241027}
    10251028
     1029void NuppelVideoPlayer::PredictFrameSkip(FrameScanType scan)
     1030{
     1031    if (play_speed > 1.0)
     1032    {
     1033        float skip_frame, extra_skip;
     1034        skip_frame = (video_frame_rate /
     1035                      ((play_speed * video_frame_rate) -
     1036                       video_frame_rate));
     1037        VERBOSE(VB_PLAYBACK, "skip_frame " << skip_frame);
     1038        if (kScan_Progressive != scan)
     1039            skip_frame *= 2;
     1040        VERBOSE(VB_IMPORTANT, QString("kScan = %1, scan = %2")
     1041                .arg(kScan_Progressive).arg(scan));
     1042        VERBOSE(VB_PLAYBACK, "skip_frame " << skip_frame);
     1043        m_skip_frame = skip_frame;
     1044        VERBOSE(VB_PLAYBACK, "m_skip_frame " << m_skip_frame);
     1045        VERBOSE(VB_PLAYBACK, " diff " << skip_frame - m_skip_frame);
     1046        if (skip_frame - (float)m_skip_frame < 0.0001)
     1047        {
     1048            m_skip_frame_extra = 0;
     1049            m_skip_frame_extra_idx = 0;
     1050        }
     1051        else
     1052        {
     1053            m_skip_frame_extra = (1.0 /
     1054                                  (skip_frame - (float)m_skip_frame))
     1055                                 * (float)m_skip_frame;
     1056            --m_skip_frame_extra; // Seems better to skip to often, than not often enough
     1057            VERBOSE(VB_PLAYBACK, "m_skip_frame_extra " << m_skip_frame_extra);
     1058            m_skip_frame_extra_idx = -2;
     1059        }
     1060
     1061        m_skip_frame_idx = 0;
     1062        ++m_skip_frame;
     1063        VERBOSE(VB_PLAYBACK, "m_skip_frame " << m_skip_frame);
     1064
     1065        VERBOSE(VB_PLAYBACK, LOC + QString("Adjusted play speed %1,  "
     1066                                           "skip frame %2 & %3 "
     1067                                           "(rate %4)")
     1068                .arg(play_speed).arg(m_skip_frame)
     1069                .arg(m_skip_frame_extra).arg(video_frame_rate));
     1070    }
     1071    else
     1072    {
     1073        m_skip_frame_idx = m_skip_frame_extra_idx = 0;
     1074        m_skip_frame = m_skip_frame_extra = 0;
     1075    }
     1076}
     1077
    10261078void NuppelVideoPlayer::SetScanType(FrameScanType scan)
    10271079{
    10281080    QMutexLocker locker(&videofiltersLock);
    void NuppelVideoPlayer::SetScanType(Fram 
    10461098    {
    10471099        m_scan = scan;
    10481100        videosync->SetFrameInterval(frame_interval, false);
     1101        PredictFrameSkip(scan);
    10491102        return;
    10501103    }
    10511104
    void NuppelVideoPlayer::SetScanType(Fram 
    10891142    if (osd)
    10901143    {
    10911144        osd->SetFrameInterval(
    1092             (m_double_framerate && m_double_process) ?
    1093             (frame_interval>>1) : frame_interval);
     1145                              (m_double_framerate && m_double_process) ?
     1146                              (frame_interval>>1) : frame_interval);
    10941147    }
    10951148
     1149    if (m_scan != scan)
     1150        PredictFrameSkip(scan);
     1151
    10961152    m_scan = scan;
    10971153}
    10981154
    void NuppelVideoPlayer::OpenDummy(void) 
    11501206    isDummy = true;
    11511207
    11521208    float displayAspect =
    1153         gContext->GetFloatSettingOnHost("XineramaMonitorAspectRatio", 
     1209        gContext->GetFloatSettingOnHost("XineramaMonitorAspectRatio",
    11541210                                        gContext->GetHostName(), 1.3333);
    11551211
    11561212    if (!videoOutput)
    void NuppelVideoPlayer::AVSync(void) 
    24062462    if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
    24072463        ps = kScan_Progressive;
    24082464
    2409     if (diverge < -MAXDIVERGE)
     2465    if (m_skip_frame_extra && ++m_skip_frame_extra_idx == m_skip_frame_extra)
     2466    {
     2467        m_skip_frame_extra_idx = 0;
     2468
     2469        /* Copied from (diverge < -MAXDIVERGE), below.  Can it be optimized? */
     2470        // Reset A/V Sync
     2471        lastsync = true;
     2472
     2473        if (buffer && !using_null_videoout &&
     2474            videoOutput->hasHWAcceleration() &&
     2475           !videoOutput->IsSyncLocked())
     2476        {
     2477            // If we are using certain hardware decoders, so we've already done
     2478            // the decoding; display the frame, but don't wait for A/V Sync.
     2479            // Excludes HW decoder/render methods that are locked to
     2480            // the vertical sync (e.g. VDPAU)
     2481            videoOutput->PrepareFrame(buffer, kScan_Intr2ndField);
     2482            videoOutput->Show(kScan_Intr2ndField);
     2483            VERBOSE(VB_PLAYBACK, LOC + "skipping A/V wait.");
     2484        }
     2485    }
     2486    if (m_skip_frame && ++m_skip_frame_idx == m_skip_frame)
     2487    {
     2488        m_skip_frame_idx = 0;
     2489
     2490        /* Copied from (diverge < -MAXDIVERGE), below.  Can it be optimized? */
     2491        // Reset A/V Sync
     2492        lastsync = true;
     2493
     2494        if (buffer && !using_null_videoout &&
     2495            videoOutput->hasHWAcceleration() &&
     2496           !videoOutput->IsSyncLocked())
     2497        {
     2498            // If we are using certain hardware decoders, so we've already done
     2499            // the decoding; display the frame, but don't wait for A/V Sync.
     2500            // Excludes HW decoder/render methods that are locked to
     2501            // the vertical sync (e.g. VDPAU)
     2502            videoOutput->PrepareFrame(buffer, kScan_Intr2ndField);
     2503            videoOutput->Show(kScan_Intr2ndField);
     2504            VERBOSE(VB_PLAYBACK, LOC + "skipping A/V wait.");
     2505        }
     2506    }
     2507    else if (diverge < -MAXDIVERGE)
    24102508    {
    24112509        // If video is way behind of audio, adjust for it...
    24122510        QString dbg = QString("Video is %1 frames behind audio (too slow), ")
    void NuppelVideoPlayer::AVSync(void) 
    24142512
    24152513        // Reset A/V Sync
    24162514        lastsync = true;
     2515        m_skip_frame_idx = 0;
     2516        m_skip_frame_extra_idx = -2;
    24172517
    24182518        if (buffer && !using_null_videoout &&
    24192519            videoOutput->hasHWAcceleration() &&
    void NuppelVideoPlayer::AVSync(void) 
    25242624        VERBOSE(VB_PLAYBACK, LOC +
    25252625                QString("Video is %1 frames ahead of audio,\n"
    25262626                        "\t\t\tdoubling video frame interval to slow down.").arg(diverge));
     2627        m_skip_frame_idx = 0;
     2628        m_skip_frame_extra_idx = -2;
    25272629    }
    25282630
    25292631    audio_lock.lock();
    void NuppelVideoPlayer::AVSync(void) 
    25932695            avsync_avg = 0;
    25942696            avsync_oldavg = 0;
    25952697        }
    2596     } 
     2698    }
    25972699    else
    25982700        audio_lock.unlock();
    25992701}
    bool NuppelVideoPlayer::StartPlaying(boo 
    35953697
    35963698            play_speed = next_play_speed;
    35973699            normal_speed = next_normal_speed;
     3700
    35983701            VERBOSE(VB_PLAYBACK, LOC + "Changing speed to " << play_speed);
    35993702
     3703            PredictFrameSkip(m_scan);
     3704
    36003705            if (play_speed == 0.0)
    36013706            {
    36023707                DoPause();
    void NuppelVideoPlayer::DoPlay(void) 
    44424547        audio_lock.unlock();
    44434548    }
    44444549
     4550
    44454551    VERBOSE(VB_PLAYBACK, LOC + "DoPlay() -- setting unpaused");
    44464552    paused = actuallypaused = false;
    44474553}
    int NuppelVideoPlayer::SetTrack(uint typ 
    68616967        if (decoder)
    68626968        {
    68636969            msg = decoder->GetTrackDesc(type, GetTrack(type));
    6864            
     6970
    68656971            if (player_ctx->buffer->isDVD())
    68666972                player_ctx->buffer->DVD()->SetTrack(type, trackNo);
    68676973        }
    bool NuppelVideoPlayer::GoToDVDMenu(QStr 
    75927698{
    75937699    if (!player_ctx->buffer->isDVD())
    75947700        return false;
    7595    
     7701
    75967702    textDisplayMode = kDisplayNone;
    75977703    bool ret = player_ctx->buffer->DVD()->GoToMenu(str);
    7598    
     7704
    75997705    if (!ret)
    76007706    {
    76017707        if (osd)
    bool NuppelVideoPlayer::GoToDVDMenu(QStr 
    76037709        VERBOSE(VB_GENERAL, "No DVD Menu available.");
    76047710        return false;
    76057711    }
    7606    
     7712
    76077713    return true;
    76087714}
    76097715
    static unsigned dbg_ident(const NuppelVi 
    80568162}
    80578163
    80588164/* vim: set expandtab tabstop=4 shiftwidth=4: */
     8165
  • libs/libmythtv/NuppelVideoPlayer.h

    old new class MPUBLIC NuppelVideoPlayer : public 
    151151    void ClearBookmark(void);
    152152    void SetForcedAspectRatio(int mpeg2_aspect_value, int letterbox_permission);
    153153
     154    void PredictFrameSkip(FrameScanType scan);
     155
    154156    void NextScanType(void)
    155157        { SetScanType((FrameScanType)(((int)m_scan + 1) & 0x3)); }
    156158    void SetScanType(FrameScanType);
    class MPUBLIC NuppelVideoPlayer : public 
    803805    bool       decode_extra_audio;
    804806    float      m_stored_audio_stretchfactor;
    805807    bool       audio_paused;
     808    int        m_skip_frame_idx;
     809    int        m_skip_frame;
     810    int        m_skip_frame_extra;
     811    int        m_skip_frame_extra_idx;
    806812
    807813    // Audio warping stuff
    808814    bool       usevideotimebase;