Ticket #13334: 20181020_1038_avsync2.patch

File 20181020_1038_avsync2.patch, 14.4 KB (added by Peter Bennett, 6 years ago)

Support for private decoders (e.g. Raspberry Pi OpenMax?) fixed.

  • mythtv/libs/libmythtv/avformatdecoder.cpp

    diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
    index 9af5a4ac12d..905f4119b0a 100644
    a b int AvFormatDecoder::ScanStreams(bool novideo) 
    26392639                thread_count = 1;
    26402640
    26412641            use_frame_timing = false;
    2642             if (! private_dec
    2643                 && ! ringBuffer->IsDVD()
     2642            if (! ringBuffer->IsDVD()
    26442643                && (codec_is_std(video_codec_id)
    26452644                    || codec_is_mediacodec(video_codec_id)
    2646                     || codec_is_vaapi2(video_codec_id)))
     2645                    || codec_is_vaapi2(video_codec_id)
     2646                    || GetCodecDecoderName() == "openmax"))
    26472647                use_frame_timing = true;
    26482648
    26492649            if (FlagIsSet(kDecodeSingleThreaded))
    bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic) 
    40134013        pts = mpa_pic->pts;
    40144014        if (pts == AV_NOPTS_VALUE)
    40154015            pts = mpa_pic->pkt_dts;
     4016        if (pts == AV_NOPTS_VALUE)
     4017            pts = mpa_pic->reordered_opaque;
    40164018        if (pts == AV_NOPTS_VALUE)
    40174019        {
    40184020            LOG(VB_GENERAL, LOG_ERR, LOC + "No PTS found - unable to process video.");
  • mythtv/libs/libmythtv/mythplayer.cpp

    diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
    index 3f0ab1c4405..6706e01655e 100644
    a b MythPlayer::MythPlayer(PlayerFlags flags) 
    217217      // Time Code stuff
    218218      prevtc(0),                    prevrp(0),
    219219      savedAudioTimecodeOffset(0),
     220      rtcbase(0),
     221      maxtcval(0), maxtcframes(0),
    220222      // LiveTVChain stuff
    221223      m_tv(nullptr),                isDummy(false),
    222224      // Counter for buffering messages
    MythPlayer::MythPlayer(PlayerFlags flags) 
    257259    uint tmp = mypage.toInt(&valid, 16);
    258260    ttPageNum = (valid) ? tmp : ttPageNum;
    259261    cc608.SetTTPageNum(ttPageNum);
     262    avsync2adjustms = (int64_t)gCoreContext->GetNumSetting("AVSync2AdjustMS", 10);
     263    if (avsync2adjustms < 1)
     264        avsync2adjustms = 1;
     265    if (avsync2adjustms > 40)
     266        avsync2adjustms = 40;
    260267}
    261268
    262269MythPlayer::~MythPlayer(void)
    bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio) 
    403410        pauseLock.unlock();
    404411        return false;
    405412    }
    406 
     413    rtcbase = 0;
    407414    SetEof(kEofStateNone);
    408415    UnpauseBuffer();
    409416    UnpauseDecoder();
    void MythPlayer::ResetAVSync(void) 
    17951802        avsync_predictor = 0;
    17961803    prevtc = 0;
    17971804    avsync_next = avsync_interval;      // Frames till next sync check
     1805    rtcbase = 0;
    17981806    LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + "A/V sync reset");
    17991807}
    18001808
    void MythPlayer::InitAVSync(void) 
    18101818
    18111819    // Number of frames over which to average time divergence
    18121820    avsync_averaging=4;
     1821    rtcbase = 0;
    18131822
    18141823    // Special averaging default of 60 for OpenMAX passthru
    18151824    QString device = gCoreContext->GetSetting("AudioOutputDevice","");
    int64_t MythPlayer::AVSyncGetAudiotime(void) 
    18561865
    18571866void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
    18581867{
     1868    if (gCoreContext->GetNumSetting("PlaybackAVSync2", 0))
     1869    {
     1870        AVSync2(buffer);
     1871        return;
     1872    }
     1873
    18591874    int repeat_pict  = 0;
    18601875    int64_t timecode = audio.GetAudioTime();
    18611876
    void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) 
    21402155    }
    21412156}
    21422157
     2158static int64_t time_to_usecs(timespec *tm);
     2159static void usecs_to_time(int64_t utime, timespec *tm);
     2160
     2161
     2162int64_t time_to_usecs(timespec *tm)
     2163{
     2164    // add 315576000000000 (10 years) to prevent it going negative
     2165    return (int64_t) (tm->tv_sec) * 1000000
     2166       + tm->tv_nsec / 1000 + (int64_t) 315576000000000;
     2167}
     2168
     2169void usecs_to_time(int64_t utime, timespec *tm)
     2170{
     2171    utime -= (int64_t) 315576000000000;
     2172    tm->tv_sec = (time_t)(utime / 1000000);
     2173    tm->tv_nsec = (utime - tm->tv_sec * 1000000) * 1000;
     2174}
     2175
     2176#define AVSYNC_MAX_LATE 1000000
     2177void MythPlayer::AVSync2(VideoFrame *buffer)
     2178{
     2179    if (videoOutput->IsErrored())
     2180    {
     2181        LOG(VB_GENERAL, LOG_ERR, LOC +
     2182            "AVSync: Unknown error in videoOutput, aborting playback.");
     2183        SetErrored(tr("Failed to initialize A/V Sync"));
     2184        return;
     2185    }
     2186    int64_t audiotimecode = audio.GetAudioTime();
     2187    int64_t videotimecode = 0;
     2188
     2189    bool dropframe = false;
     2190    bool pause_audio = false;
     2191    int64_t framedue = 0;
     2192    int64_t audio_adjustment = 0;
     2193    timespec now;
     2194    int64_t unow = 0;
     2195    int64_t lateness = 0;
     2196    int64_t playspeed1000 = (float)1000 / play_speed;
     2197
     2198    while (framedue == 0)
     2199    {
     2200        bool reset = false;
     2201        if (buffer)
     2202        {
     2203            videotimecode = buffer->timecode & 0x0000ffffffffffff;
     2204            // Detect bogus timecodes from DVD and ignore them.
     2205            if (videotimecode != buffer->timecode)
     2206                videotimecode = maxtcval;
     2207        }
     2208        else
     2209            videotimecode = audiotimecode;
     2210        // first time or after a seek - setup of rtcbase
     2211        if (rtcbase == 0)
     2212        {
     2213            if (clock_gettime(CLOCK_MONOTONIC,&now) != 0)
     2214            {
     2215                LOG(VB_GENERAL, LOG_ERR, LOC +
     2216                    QString("AVSync: Error %1 in clock_gettime, aborting playback.").arg(errno));
     2217                SetErrored(tr("Failed to initialize A/V Sync"));
     2218                return;
     2219            }
     2220            unow = time_to_usecs(&now);
     2221            rtcbase = unow - videotimecode * playspeed1000;
     2222            maxtcval = 0;
     2223            maxtcframes = 0;
     2224        }
     2225
     2226        int64_t tcincr = videotimecode - maxtcval;
     2227        if (tcincr > 0 || tcincr < -100)
     2228        {
     2229            maxtcval = videotimecode;
     2230            maxtcframes = 0;
     2231        }
     2232        else
     2233        {
     2234            maxtcframes++;
     2235            videotimecode = maxtcval + maxtcframes * frame_interval/1000;
     2236        }
     2237
     2238        clock_gettime(CLOCK_MONOTONIC,&now);
     2239        unow = time_to_usecs(&now);
     2240        if (play_speed > 0.0f)
     2241            framedue = rtcbase + videotimecode * playspeed1000;
     2242        else
     2243            framedue = unow + frame_interval / 2;
     2244
     2245        lateness = unow - framedue;
     2246        dropframe = false;
     2247        if (lateness > 30000)
     2248            dropframe = !FlagIsSet(kMusicChoice);
     2249
     2250        if (lateness <= 30000 && audiotimecode > 0 && normal_speed)
     2251        {
     2252            // Get video in sync with audio
     2253            audio_adjustment = audiotimecode - videotimecode;
     2254            int sign = audio_adjustment < 0 ? -1 : 1;
     2255            if (audio_adjustment * sign > 40)
     2256            {
     2257                // adjust by AVSyncIncrementMS milliseconds at a time (range 1-40)
     2258                rtcbase -= (int64_t)1000000 * avsync2adjustms * sign / playspeed1000;
     2259                LOG(VB_PLAYBACK, LOG_INFO, LOC +
     2260                    QString("AV Sync, audio ahead by %1 ms").arg(audio_adjustment));
     2261            }
     2262        }
     2263        // sanity check - reset rtcbase if time codes have gone crazy.
     2264        if (lateness > AVSYNC_MAX_LATE || lateness < - AVSYNC_MAX_LATE)
     2265        {
     2266            framedue = 0;
     2267            rtcbase = 0;
     2268            if (reset)
     2269            {
     2270                LOG(VB_GENERAL, LOG_ERR, LOC +
     2271                    QString("Resetting AV Sync2 failed, lateness = %1").arg(lateness));
     2272                SetErrored(tr("Failed to initialize A/V Sync"));
     2273                return;
     2274            }
     2275            LOG(VB_PLAYBACK, LOG_INFO, LOC +
     2276                QString("Resetting AV Sync2, lateness = %1").arg(lateness));
     2277            reset = true;
     2278        }
     2279    }
     2280
     2281    disp_timecode = videotimecode;
     2282
     2283    FrameScanType ps = m_scan;
     2284    if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
     2285        ps = kScan_Progressive;
     2286
     2287    if (buffer && !dropframe)
     2288    {
     2289        osdLock.lock();
     2290        videofiltersLock.lock();
     2291        videoOutput->ProcessFrame(buffer, osd, videoFilters, pip_players, ps);
     2292        videofiltersLock.unlock();
     2293        osdLock.unlock();
     2294    }
     2295
     2296    if (!pause_audio && avsync_audiopaused)
     2297    {
     2298        avsync_audiopaused = false;
     2299        audio.Pause(false);
     2300    }
     2301    LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
     2302        QString("A/V timecodes audio=%1 video=%2 frameinterval=%3 "
     2303                "audioadj=%4 tcoffset=%5 unow=%6 udue=%7")
     2304            .arg(audiotimecode)
     2305            .arg(videotimecode)
     2306            .arg(frame_interval)
     2307            .arg(audio_adjustment)
     2308            .arg(tc_wrap[TC_AUDIO])
     2309            .arg(unow)
     2310            .arg(framedue)
     2311                );
     2312    if (dropframe)
     2313        LOG(VB_PLAYBACK, LOG_INFO, LOC +
     2314            QString("dropping frame to catch up, lateness=%1 usec")
     2315                .arg(lateness));
     2316    else if (!FlagIsSet(kVideoIsNull) && buffer)
     2317    {
     2318        // if we get here, we're actually going to do video output
     2319        osdLock.lock();
     2320        videoOutput->PrepareFrame(buffer, ps, osd);
     2321        osdLock.unlock();
     2322        // Don't wait for sync if this is a secondary PBP otherwise
     2323        // the primary PBP will become out of sync
     2324        if (!player_ctx->IsPBP() || player_ctx->IsPrimaryPBP())
     2325        {
     2326            timespec tm;
     2327            usecs_to_time(framedue, &tm);
     2328            clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tm, NULL);
     2329        }
     2330        videoOutput->Show(ps);
     2331        if (videoOutput->IsErrored())
     2332        {
     2333            LOG(VB_GENERAL, LOG_ERR, LOC + "Error condition detected "
     2334                    "in videoOutput after Show(), aborting playback.");
     2335            SetErrored(tr("Serious error detected in Video Output"));
     2336            return;
     2337        }
     2338        if (m_double_framerate)
     2339        {
     2340            //second stage of deinterlacer processing
     2341            ps = (kScan_Intr2ndField == ps) ?
     2342                kScan_Interlaced : kScan_Intr2ndField;
     2343            osdLock.lock();
     2344            if (m_double_process && ps != kScan_Progressive)
     2345            {
     2346                videofiltersLock.lock();
     2347                videoOutput->ProcessFrame(
     2348                        buffer, osd, videoFilters, pip_players, ps);
     2349                videofiltersLock.unlock();
     2350            }
     2351
     2352            videoOutput->PrepareFrame(buffer, ps, osd);
     2353            osdLock.unlock();
     2354            // Display the second field
     2355            if (!player_ctx->IsPBP() || player_ctx->IsPrimaryPBP())
     2356            {
     2357                int64_t due = framedue + frame_interval / 2;
     2358                timespec tm;
     2359                usecs_to_time(due, &tm);
     2360                clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tm, NULL);
     2361            }
     2362            videoOutput->Show(ps);
     2363        }
     2364    }
     2365    else
     2366    {
     2367        timespec tm;
     2368        usecs_to_time(framedue, &tm);
     2369        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tm, NULL);
     2370    }
     2371}
     2372
    21432373void MythPlayer::RefreshPauseFrame(void)
    21442374{
    21452375    if (needNewPauseFrame)
    void MythPlayer::DisplayNormalFrame(bool check_prebuffer) 
    23632593    detect_letter_box->SwitchTo(frame);
    23642594
    23652595    AVSync(frame, false);
     2596
    23662597    // If PiP then keep this frame for MythPlayer::GetCurrentFrame
    23672598    if (!player_ctx->IsPIP())
    23682599        videoOutput->DoneDisplayingFrame(frame);
    void MythPlayer::ChangeSpeed(void) 
    38384069    float last_speed = play_speed;
    38394070    play_speed   = next_play_speed;
    38404071    normal_speed = next_normal_speed;
     4072    rtcbase = 0;
    38414073
    38424074    bool skip_changed = UpdateFFRewSkip();
    38434075
  • mythtv/libs/libmythtv/mythplayer.h

    diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h
    index 90128fca85b..2f019a74b34 100644
    a b  
    22#define MYTHPLAYER_H
    33
    44#include <cstdint>
     5#include <time.h>
    56
    67#include <QCoreApplication>
    78#include <QList>
    class MTV_PUBLIC MythPlayer 
    615616    void  WrapTimecode(int64_t &timecode, TCTypes tc_type);
    616617    void  InitAVSync(void);
    617618    virtual void AVSync(VideoFrame *buffer, bool limit_delay = false);
     619    // New video sync method
     620    void AVSync2(VideoFrame *buffer);
    618621    void  ResetAVSync(void);
    619622    int64_t AVSyncGetAudiotime(void);
    620623    void  SetFrameInterval(FrameScanType scan, double speed);
    class MTV_PUBLIC MythPlayer 
    844847    int64_t    tc_lastval[TCTYPESMAX];
    845848    int64_t    savedAudioTimecodeOffset;
    846849
     850    // AVSync2
     851    int64_t   rtcbase;        // real time clock base for presentation time (microsecs)
     852    int64_t   maxtcval;       // maximum to date video tc
     853    int       maxtcframes;    // number of frames seen since max to date tc
     854    int64_t   avsync2adjustms; // number of milliseconds to adjust for av sync errors
     855
    847856    // LiveTV
    848857    TV *m_tv;
    849858    bool isDummy;
  • mythtv/programs/mythfrontend/globalsettings.cpp

    diff --git a/mythtv/programs/mythfrontend/globalsettings.cpp b/mythtv/programs/mythfrontend/globalsettings.cpp
    index 124f5170dfe..df8cca0d147 100644
    a b static HostTextEditSetting *VAAPIDevice() 
    8686}
    8787#endif
    8888
     89static HostCheckBoxSetting *PlaybackAVSync2()
     90{
     91    HostCheckBoxSetting *gc = new HostCheckBoxSetting("PlaybackAVSync2");
     92
     93    gc->setLabel(PlaybackSettings::tr("Enable new timestamp based playback speed (AVSync2)"));
     94
     95    gc->setHelpText(PlaybackSettings::tr("Simplified timing and synchronization method. "
     96        "This may offer smoother video playback. Note there is a setting that can be used "
     97        "for fine tuning playback (press right arrow)."));
     98    gc->setValue(false);
     99
     100    return gc;
     101}
     102
     103static HostSpinBoxSetting *AVSync2AdjustMS()
     104// was previously *DecodeExtraAudio()
     105{
     106    HostSpinBoxSetting *gc = new HostSpinBoxSetting("AVSync2AdjustMS",1,40,1,1);
     107
     108    gc->setLabel(PlaybackSettings::tr("AVSync2 audio correction (ms)"));
     109
     110    gc->setValue(10);
     111
     112    gc->setHelpText(PlaybackSettings::tr(
     113        "When using AVSync2, if video playback is speeding up and slowing down every few seconds, reduce "
     114        "this value. For quicker recovery of audio sync after jumps, increase this value. "
     115        "Values can be from 1 to 40. Default is 10."));
     116    return gc;
     117}
     118
    89119static HostCheckBoxSetting *OpenGLYV12()
    90120{
    91121    HostCheckBoxSetting *gc = new HostCheckBoxSetting("OpenGLYV12");
    void PlaybackSettings::Load(void) 
    41614191#ifdef USING_VAAPI2
    41624192    advanced->addChild(VAAPIDevice());
    41634193#endif
     4194    HostCheckBoxSetting *avsync2 = PlaybackAVSync2();
     4195    advanced->addChild(avsync2);
     4196    avsync2->addTargetedChild("1",AVSync2AdjustMS());
    41644197    advanced->addChild(OpenGLYV12());
    41654198    advanced->addChild(OpenGLUYVY());
    41664199    addChild(advanced);