Ticket #7964: frame-skip-v1.4.patch

File frame-skip-v1.4.patch, 14.8 KB (added by jpoet, 14 years ago)

Much smoother at non 1.25x,1.5x speeds

  • libs/libmythtv/NuppelVideoPlayer.cpp

    old new NuppelVideoPlayer::NuppelVideoPlayer(boo 
    254254    for (int i = 0; i < MAXTBUFFER; i++)
    255255        txtbuffers[i].buffer = new unsigned char[text_size + 1];
    256256
     257    m_frame_show_idx = 0;
     258
    257259    memset(&CC708DelayedDeletes, 0, sizeof(CC708DelayedDeletes));
    258260}
    259261
    void NuppelVideoPlayer::AutoDeint(VideoF 
    10161018    m_scan_locked  = false;
    10171019}
    10181020
     1021void NuppelVideoPlayer::PredictFrameSkip(FrameScanType scan)
     1022{
     1023    m_frame_show.clear();
     1024
     1025    if (play_speed <= 1 || play_speed > 2 || scan != kScan_Progressive)
     1026        return;
     1027
     1028    // For every frame shown, what percent should be skipped?
     1029
     1030    switch ((int)(play_speed * 100.0 + 0.5))
     1031    {
     1032      case 105:
     1033        m_frame_show.push_back(20); // skip 5%, 20:1
     1034        break;
     1035      case 110:
     1036        m_frame_show.push_back(10); // skip 10%, 10:1
     1037        break;
     1038      case 115:
     1039        m_frame_show.push_back(7); // skip 15%
     1040        m_frame_show.push_back(7); // 20:3
     1041        m_frame_show.push_back(6);
     1042        break;
     1043      case 120:
     1044        m_frame_show.push_back(5); // skip 20%, 5:1
     1045        break;
     1046      case 125:
     1047        m_frame_show.push_back(4); // skip 25%, 4:1
     1048        break;
     1049      case 130:
     1050        m_frame_show.push_back(4); // skip 30%
     1051        m_frame_show.push_back(3); // 10:3
     1052        m_frame_show.push_back(3);
     1053        break;
     1054      case 135:
     1055        m_frame_show.push_back(4); // skip 35%
     1056        m_frame_show.push_back(3); // 20:7
     1057        m_frame_show.push_back(3); // round down 10:3
     1058        break;
     1059      case 140:
     1060        m_frame_show.push_back(3); // skip 40%
     1061        m_frame_show.push_back(2); // 5:2
     1062        break;
     1063      case 145:
     1064        m_frame_show.push_back(3); // skip 45%
     1065        m_frame_show.push_back(2); // 20:9, round down 5:2
     1066        break;
     1067      case 150:
     1068        m_frame_show.push_back(2);  // skip 50%, 2:1
     1069        break;
     1070      case 155:
     1071        m_frame_show.push_back(2); // skip 55%, 20:11, round down 2:1
     1072        break;
     1073      case 160:
     1074        m_frame_show.push_back(2); // skip 60%
     1075        m_frame_show.push_back(2); // 5:3
     1076        m_frame_show.push_back(1);
     1077        break;
     1078      case 165:
     1079        m_frame_show.push_back(2); // skip 65%
     1080        m_frame_show.push_back(2); // 20:13
     1081        m_frame_show.push_back(1); // round down 5:3
     1082        break;
     1083      case 170:
     1084        m_frame_show.push_back(2); // skip 70%
     1085        m_frame_show.push_back(2); // 10:7
     1086        m_frame_show.push_back(1); // round down 5:3
     1087        break;
     1088      case 175:
     1089        m_frame_show.push_back(2); // skip 75%
     1090        m_frame_show.push_back(1); // 4:3
     1091        m_frame_show.push_back(1);
     1092        break;
     1093      case 180:
     1094        m_frame_show.push_back(2); // skip 80%
     1095        m_frame_show.push_back(1); // 5:4
     1096        m_frame_show.push_back(1);
     1097        m_frame_show.push_back(1);
     1098        break;
     1099      case 185:
     1100        m_frame_show.push_back(2); // skip 85%
     1101        m_frame_show.push_back(1); // 20:17
     1102        m_frame_show.push_back(1); // round down 5:4
     1103        m_frame_show.push_back(1);
     1104        break;
     1105      case 190:
     1106        m_frame_show.push_back(2); // skip 90%
     1107        m_frame_show.push_back(1); // 10:9
     1108        m_frame_show.push_back(1); // round down 5:4
     1109        m_frame_show.push_back(1);
     1110        break;
     1111      case 195:
     1112        m_frame_show.push_back(2); // skip 95%
     1113        m_frame_show.push_back(1); // 20:19, round down 10:9, again 5:4
     1114        m_frame_show.push_back(1);
     1115        m_frame_show.push_back(1);
     1116        break;
     1117      case 200:
     1118        m_frame_show.push_back(1); // skip 100%, 1:1
     1119        break;
     1120    }
     1121
     1122    QString msg = QString("PredictFrameSkip: speed %1 ").arg(play_speed);
     1123    bool    delim = false;
     1124
     1125    for (m_frame_show_iter = m_frame_show.begin();
     1126         m_frame_show_iter != m_frame_show.end(); ++m_frame_show_iter)
     1127    {
     1128        msg += QString("%1%2").arg(delim ? ":" : "").arg(*m_frame_show_iter);
     1129        delim = true;
     1130    }
     1131
     1132    VERBOSE(VB_PLAYBACK, msg);
     1133
     1134    m_frame_show_iter = m_frame_show.begin();
     1135    m_frame_show_idx = 0;
     1136}
     1137
    10191138void NuppelVideoPlayer::SetScanType(FrameScanType scan)
    10201139{
    10211140    QMutexLocker locker(&videofiltersLock);
    void NuppelVideoPlayer::SetScanType(Fram 
    10391158    {
    10401159        m_scan = scan;
    10411160        videosync->SetFrameInterval(frame_interval, false);
     1161        PredictFrameSkip(scan);
    10421162        return;
    10431163    }
    10441164
    void NuppelVideoPlayer::SetScanType(Fram 
    10861206            (frame_interval>>1) : frame_interval);
    10871207    }
    10881208
     1209    if (m_scan != scan)
     1210        PredictFrameSkip(scan);
     1211
    10891212    m_scan = scan;
    10901213}
    10911214
    void NuppelVideoPlayer::AVSync(void) 
    23792502        ps = kScan_Progressive;
    23802503
    23812504    bool dropframe = false;
    2382     if (diverge < -MAXDIVERGE)
    2383     {
    2384         dropframe = true;
    2385         // If video is way behind of audio, adjust for it...
    2386         QString dbg = QString("Video is %1 frames behind audio (too slow), ")
    2387             .arg(-diverge);
    23882505
    2389         // Reset A/V Sync
    2390         lastsync = true;
    2391 
    2392         if (buffer && !using_null_videoout &&
    2393             videoOutput->hasHWAcceleration() &&
    2394            !videoOutput->IsSyncLocked())
    2395         {
    2396             // If we are using certain hardware decoders, so we've already done
    2397             // the decoding; display the frame, but don't wait for A/V Sync.
    2398             // Excludes HW decoder/render methods that are locked to
    2399             // the vertical sync (e.g. VDPAU)
    2400             videoOutput->PrepareFrame(buffer, kScan_Intr2ndField);
    2401             videoOutput->Show(kScan_Intr2ndField);
    2402             VERBOSE(VB_PLAYBACK, LOC + dbg + "skipping A/V wait.");
    2403         }
    2404         else
     2506    if (!m_frame_show.empty())
     2507    {
     2508        if (m_frame_show_idx++ == *m_frame_show_iter)
    24052509        {
    2406             // If we are using software decoding, skip this frame altogether.
    2407             VERBOSE(VB_PLAYBACK, LOC + dbg + "dropping frame to catch up.");
     2510            dropframe = true;
     2511
     2512            m_frame_show_idx = 0;
     2513            if (++m_frame_show_iter == m_frame_show.end())
     2514                m_frame_show_iter = m_frame_show.begin();
    24082515        }
    24092516    }
    2410     else if (!using_null_videoout)
    2411     {
    2412         // if we get here, we're actually going to do video output
    2413         if (buffer)
    2414             videoOutput->PrepareFrame(buffer, ps);
    24152517
    2416         VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString("AVSync waitforframe %1 %2")
    2417                 .arg(avsync_adjustment).arg(m_double_framerate));
    2418         videosync->WaitForFrame(avsync_adjustment + repeat_delay);
    2419         VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, "AVSync show");
    2420         if (!resetvideo)
    2421             videoOutput->Show(ps);
    2422 
    2423         if (videoOutput->IsErrored())
     2518    if (!dropframe)
     2519    {
     2520        if (diverge < -MAXDIVERGE)
    24242521        {
    2425             VERBOSE(VB_IMPORTANT, "NVP: Error condition detected "
    2426                     "in videoOutput after Show(), aborting playback.");
    2427             SetErrored(QObject::tr("Serious error detected in Video Output"));
    2428             return;
     2522            dropframe = true;
     2523            // If video is way behind of audio, adjust for it...
     2524            QString dbg = QString("Video is %1 frames behind audio (too slow), ")
     2525                          .arg(-diverge);
     2526
     2527            // Reset A/V Sync
     2528            lastsync = true;
     2529
     2530            if (buffer && !using_null_videoout &&
     2531                videoOutput->hasHWAcceleration() &&
     2532                !videoOutput->IsSyncLocked())
     2533            {
     2534                // If we are using certain hardware decoders, so we've already done
     2535                // the decoding; display the frame, but don't wait for A/V Sync.
     2536                // Excludes HW decoder/render methods that are locked to
     2537                // the vertical sync (e.g. VDPAU)
     2538                videoOutput->PrepareFrame(buffer, kScan_Intr2ndField);
     2539                videoOutput->Show(kScan_Intr2ndField);
     2540                VERBOSE(VB_PLAYBACK, LOC + dbg + "skipping A/V wait.");
     2541            }
     2542            else
     2543            {
     2544                // If we are using software decoding, skip this frame altogether.
     2545                VERBOSE(VB_PLAYBACK, LOC + dbg + "dropping frame to catch up.");
     2546            }
    24292547        }
    2430 
    2431         if (m_double_framerate)
     2548        else if (!using_null_videoout)
    24322549        {
    2433             //second stage of deinterlacer processing
    2434             ps = (kScan_Intr2ndField == ps) ?
    2435                 kScan_Interlaced : kScan_Intr2ndField;
    2436 
    2437             if (m_double_process && ps != kScan_Progressive)
    2438             {
    2439                 videofiltersLock.lock();
    2440                 if (player_ctx->buffer->isDVD() &&
    2441                     player_ctx->buffer->DVD()->InStillFrame() &&
    2442                     videoOutput->ValidVideoFrames() < 3)
    2443                 {
    2444                     videoOutput->ProcessFrame(buffer, NULL, NULL,
    2445                                               pip_players, ps);
    2446                 }
    2447                 else
     2550            // if we get here, we're actually going to do video output
     2551            if (buffer)
     2552                videoOutput->PrepareFrame(buffer, ps);
     2553
     2554            VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString("AVSync waitforframe %1 %2")
     2555                    .arg(avsync_adjustment).arg(m_double_framerate));
     2556            videosync->WaitForFrame(avsync_adjustment + repeat_delay);
     2557            VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, "AVSync show");
     2558            if (!resetvideo)
     2559                videoOutput->Show(ps);
     2560
     2561            if (videoOutput->IsErrored())
     2562            {
     2563                VERBOSE(VB_IMPORTANT, "NVP: Error condition detected "
     2564                        "in videoOutput after Show(), aborting playback.");
     2565                SetErrored(QObject::tr("Serious error detected in Video Output"));
     2566                return;
     2567            }
     2568
     2569            if (m_double_framerate)
     2570            {
     2571                //second stage of deinterlacer processing
     2572                ps = (kScan_Intr2ndField == ps) ?
     2573                     kScan_Interlaced : kScan_Intr2ndField;
     2574
     2575                if (m_double_process && ps != kScan_Progressive)
    24482576                {
    2449                     videoOutput->ProcessFrame(
    2450                         buffer, osd, videoFilters, pip_players, ps);
     2577                    videofiltersLock.lock();
     2578                    if (player_ctx->buffer->isDVD() &&
     2579                        player_ctx->buffer->DVD()->InStillFrame() &&
     2580                        videoOutput->ValidVideoFrames() < 3)
     2581                    {
     2582                        videoOutput->ProcessFrame(buffer, NULL, NULL,
     2583                                                  pip_players, ps);
     2584                    }
     2585                    else
     2586                    {
     2587                        videoOutput->ProcessFrame
     2588                            (buffer, osd, videoFilters, pip_players, ps);
     2589                    }
     2590                    videofiltersLock.unlock();
    24512591                }
    2452                 videofiltersLock.unlock();
    2453             }
    24542592
    2455             if (buffer)
    2456                 videoOutput->PrepareFrame(buffer, ps);
     2593                if (buffer)
     2594                    videoOutput->PrepareFrame(buffer, ps);
    24572595
    2458             // Display the second field
    2459             videosync->AdvanceTrigger();
     2596                // Display the second field
     2597                videosync->AdvanceTrigger();
    24602598#ifdef NEW_AVSYNC
    2461             videosync->WaitForFrame(avsync_adjustment);
     2599                videosync->WaitForFrame(avsync_adjustment);
    24622600#else
    2463             videosync->WaitForFrame(0);
     2601                videosync->WaitForFrame(0);
    24642602#endif
    2465             if (!resetvideo)
    2466             {
    2467                 videoOutput->Show(ps);
     2603                if (!resetvideo)
     2604                {
     2605                    videoOutput->Show(ps);
     2606                }
    24682607            }
    2469         }
    24702608
    2471         repeat_delay = frame_interval * buffer->repeat_pict * 0.5;
     2609            repeat_delay = frame_interval * buffer->repeat_pict * 0.5;
    24722610
    2473         if (repeat_delay)
    2474             VERBOSE(VB_TIMESTAMP, QString("A/V repeat_pict, adding %1 repeat "
    2475                     "delay").arg(repeat_delay));
    2476     }
    2477     else
    2478     {
    2479         videosync->WaitForFrame(0);
     2611            if (repeat_delay)
     2612                VERBOSE(VB_TIMESTAMP,
     2613                        QString("A/V repeat_pict, adding %1 repeat "
     2614                                "delay").arg(repeat_delay));
     2615        }
     2616        else
     2617        {
     2618            videosync->WaitForFrame(0);
     2619        }
    24802620    }
    24812621
    24822622    if (output_jmeter && output_jmeter->RecordCycleTime())
    24832623    {
    2484         VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, QString("A/V avsync_delay: %1, "
    2485                 "avsync_avg: %2, warpfactor: %3, warpfactor_avg: %4")
     2624        VERBOSE(VB_PLAYBACK+VB_TIMESTAMP,
     2625                QString("A/V avsync_delay: %1, "
     2626                        "avsync_avg: %2, warpfactor: %3, warpfactor_avg: %4")
    24862627                .arg(avsync_delay / 1000).arg(avsync_avg / 1000)
    24872628                .arg(warpfactor).arg(warpfactor_avg));
    24882629    }
    void NuppelVideoPlayer::AVSync(void) 
    25042645        lastsync = true;
    25052646        VERBOSE(VB_PLAYBACK, LOC +
    25062647                QString("Video is %1 frames ahead of audio,\n"
    2507                         "\t\t\tdoubling video frame interval to slow down.").arg(diverge));
     2648                        "\t\t\tdoubling video frame interval to slow down.")
     2649                .arg(diverge));
    25082650    }
    25092651
    25102652    audio_lock.lock();
    void NuppelVideoPlayer::AVSync(void) 
    25222664                .arg(buffer->timecode - currentaudiotime)
    25232665                .arg(avsync_avg)
    25242666                .arg(tc_wrap[TC_AUDIO])
    2525                  );
     2667                );
    25262668#endif
    25272669        if (currentaudiotime != 0 && buffer->timecode != 0)
    25282670        { // currentaudiotime == 0 after a seek
    bool NuppelVideoPlayer::StartPlaying(boo 
    35523694
    35533695            play_speed = next_play_speed;
    35543696            normal_speed = next_normal_speed;
     3697
    35553698            VERBOSE(VB_PLAYBACK, LOC + "Changing speed to " << play_speed);
    35563699
     3700            PredictFrameSkip(m_scan);
     3701
    35573702            if (play_speed == 0.0)
    35583703            {
    35593704                DoPause();
  • libs/libmythtv/NuppelVideoPlayer.h

    old new class MPUBLIC NuppelVideoPlayer : public 
    431431    FrameScanType detectInterlace(FrameScanType newScan, FrameScanType scan,
    432432                                  float fps, int video_height);
    433433    void AutoDeint(VideoFrame*);
     434    void PredictFrameSkip(FrameScanType scan);
    434435
    435436    // Private Sets
    436437    void SetPlayingInfo(const ProgramInfo &pginfo);
    class MPUBLIC NuppelVideoPlayer : public 
    805806    bool       audio_paused;
    806807    int        repeat_delay;
    807808
     809    QVector<int>  m_frame_show;
     810    QVector<int>::iterator m_frame_show_iter;
     811    int        m_frame_show_idx;
     812
    808813    // Audio warping stuff
    809814    float      warpfactor;
    810815    float      warpfactor_avg;