diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp index 702abc0..a7b7a74 100644 --- a/mythtv/libs/libmythtv/mythplayer.cpp +++ b/mythtv/libs/libmythtv/mythplayer.cpp @@ -79,7 +79,7 @@ const double MythPlayer::kInaccuracyNone = 0; // By default, when seeking, snap to a keyframe if the keyframe's // distance from the target frame is less than 10% of the total seek // distance. -const double MythPlayer::kInaccuracyDefault = 0.1; +const double MythPlayer::kInaccuracyDefault = 0.2; // Allow greater inaccuracy (50%) in the cutlist editor (unless the // editor seek distance is set to 1 frame or 1 keyframe). @@ -202,13 +202,13 @@ MythPlayer::MythPlayer(PlayerFlags flags) decoder_lock(QMutex::Recursive), next_play_speed(1.0f), next_normal_speed(true), play_speed(1.0f), normal_speed(true), - frame_interval((int)(1000000.0f / 30)), m_frame_interval(0), + frame_interval((int)(1000000.0f / 25)), m_frame_interval(0), ffrew_skip(1),ffrew_adjust(0), // Audio and video synchronization stuff videosync(NULL), avsync_delay(0), avsync_adjustment(0), avsync_avg(0), avsync_predictor(0), avsync_predictor_enabled(false), - refreshrate(0), + refreshinterval(0), lastsync(false), repeat_delay(0), disp_timecode(0), avsync_audiopaused(false), // AVSync for Raspberry Pi digital streams @@ -424,6 +424,7 @@ void MythPlayer::PauseVideo(void) needNewPauseFrame = true; videoPaused = true; videoPauseLock.unlock(); + first_time = true; } void MythPlayer::UnpauseVideo(void) @@ -666,9 +667,7 @@ FrameScanType MythPlayer::detectInterlace(FrameScanType newScan, // isn't, we have to guess. scan = kScan_Interlaced; // default to interlaced - if (720 == video_height) // ATSC 720p - scan = kScan_Progressive; - else if (fps > 45) // software deinterlacing + if (fps > 45) // software deinterlacing scan = kScan_Progressive; if (kScan_Detect != newScan) @@ -1773,23 +1772,25 @@ int MythPlayer::NextCaptionTrack(int mode) void MythPlayer::SetFrameInterval(FrameScanType scan, double frame_period) { frame_interval = (int)(1000000.0f * frame_period + 0.5f); +// int frameDelay = m_double_framerate ? frame_interval / 2 : frame_interval; + if (!avsync_predictor_enabled) avsync_predictor = 0; avsync_predictor_enabled = false; LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("SetFrameInterval ps:%1 scan:%2") .arg(play_speed).arg(scan)); - if (play_speed < 1 || play_speed > 2 || refreshrate <= 0) + if (play_speed < 1 || play_speed > 2 || refreshinterval <= 0) return; avsync_predictor_enabled = ((frame_interval-(frame_interval/200)) < - refreshrate); + refreshinterval); } void MythPlayer::ResetAVSync(void) { avsync_avg = 0; - if (!avsync_predictor_enabled || avsync_predictor >= refreshrate) + if (!avsync_predictor_enabled || avsync_predictor >= refreshinterval) avsync_predictor = 0; prevtc = 0; avsync_next = avsync_interval; // Frames till next sync check @@ -1804,7 +1805,7 @@ void MythPlayer::InitAVSync(void) repeat_delay = 0; - refreshrate = MythDisplay::GetDisplayInfo(frame_interval).Rate(); + refreshinterval = MythDisplay::GetDisplayInfo(frame_interval).Rate(); // Number of frames over which to average time divergence avsync_averaging=4; @@ -1831,7 +1832,7 @@ void MythPlayer::InitAVSync(void) QString msg = QString("Video timing method: %1").arg(timing_type); LOG(VB_GENERAL, LOG_INFO, LOC + msg); msg = QString("Display Refresh Rate: %1 Video Frame Rate: %2") - .arg(1000000.0 / refreshrate, 0, 'f', 3) + .arg(1000000.0 / refreshinterval, 0, 'f', 3) .arg(1000000.0 / frame_interval, 0, 'f', 3); LOG(VB_PLAYBACK, LOG_INFO, LOC + msg); @@ -1865,7 +1866,6 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) } float diverge = 0.0f; - int frameDelay = m_double_framerate ? frame_interval / 2 : frame_interval; int vsync_delay_clock = 0; //int64_t currentaudiotime = 0; @@ -1891,21 +1891,19 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) avsync_next = avsync_interval/divisor; } - FrameScanType ps = m_scan; - if (kScan_Detect == m_scan || kScan_Ignore == m_scan) - ps = kScan_Progressive; - bool max_video_behind = diverge < -max_diverge; bool dropframe = false; QString dbg; + dropframe = !m_double_framerate && drop_field; + if (avsync_predictor_enabled) { avsync_predictor += frame_interval; - if (avsync_predictor >= refreshrate) + if (avsync_predictor >= refreshinterval) { - int refreshperiodsinframe = avsync_predictor/refreshrate; - avsync_predictor -= refreshrate * refreshperiodsinframe; + int refreshperiodsinframe = avsync_predictor/refreshinterval; + avsync_predictor -= refreshinterval * refreshperiodsinframe; } else { @@ -1914,6 +1912,9 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) } } + int frameDelay = frame_interval + avsync_adjustment + repeat_delay; + frameDelay = m_double_framerate ? frameDelay / 2 : frameDelay; + if (max_video_behind) { dropframe = true; @@ -1928,6 +1929,10 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) audio.Pause(false); } + FrameScanType ps = m_scan; + if (kScan_Detect == m_scan || kScan_Ignore == m_scan) + ps = kScan_Progressive; + if (!dropframe) { // PGB this was orignally in the calling methods @@ -1967,8 +1972,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + QString("AVSync waitforframe %1 %2") .arg(avsync_adjustment).arg(m_double_framerate)); - vsync_delay_clock = videosync->WaitForFrame - (frameDelay + avsync_adjustment + repeat_delay); + vsync_delay_clock = videosync->WaitForFrame(frameDelay); } else { @@ -1976,7 +1980,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) lastsync = true; } //currentaudiotime = AVSyncGetAudiotime(); - LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + "AVSync show"); + // LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + "AVSync show"); videoOutput->Show(ps); if (videoOutput->IsErrored()) @@ -1987,12 +1991,13 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) return; } - if (m_double_framerate) + if (!drop_field && m_double_framerate) { //second stage of deinterlacer processing ps = (kScan_Intr2ndField == ps) ? kScan_Interlaced : kScan_Intr2ndField; osdLock.lock(); + if (m_double_process && ps != kScan_Progressive) { videofiltersLock.lock(); @@ -2005,8 +2010,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) osdLock.unlock(); // Display the second field if (!player_ctx->IsPBP() || player_ctx->IsPrimaryPBP()) - vsync_delay_clock = videosync->WaitForFrame(frameDelay + - avsync_adjustment); + vsync_delay_clock += videosync->WaitForFrame(repeat_field ? (frameDelay * 2) : frameDelay); videoOutput->Show(ps); } @@ -2019,7 +2023,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) } else { - vsync_delay_clock = videosync->WaitForFrame(frameDelay); + vsync_delay_clock = videosync->WaitForFrame(frame_interval); //currentaudiotime = AVSyncGetAudiotime(); } @@ -2049,12 +2053,12 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) // must be sampled here due to Show delays int64_t currentaudiotime = audio.GetAudioTime(); LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + - QString("A/V timecodes audio %1 video %2 frameinterval %3 " + QString("A/V timecodes audio %1 video %2 framedelay %3 " "avdel %4 avg %5 tcoffset %6 avp %7 avpen %8 avdc %9 " "diverge %10") .arg(currentaudiotime) .arg(timecode) - .arg(frame_interval) + .arg(frameDelay) .arg(timecode - currentaudiotime - (int)(vsync_delay_clock*audio.GetStretchFactor()+500)/1000) .arg(avsync_avg) @@ -2099,7 +2103,10 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) // prevents major jitter when pts resets during dvd title if (avsync_delay > 2000000 && limit_delay) + { avsync_delay = 90000; + avsync_avg = 0; + } avsync_avg = (avsync_delay + (avsync_avg * (avsync_averaging-1))) / avsync_averaging; int avsync_used = avsync_avg; @@ -2108,16 +2115,37 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) /* If the audio time codes and video diverge, shift the video by one interlaced field (1/2 frame) */ - if (!lastsync) + if (true) //(!lastsync) { - if (avsync_used > refreshrate) + diverge = (float)avsync_avg / (float)refreshinterval; + // limit damage to spread any AV shift + if (diverge > 3) + diverge = 3; + if (diverge < -3) + diverge = -3; + // target +/- 0.5 * refreshinterval + + frameDelay = m_double_framerate ? frame_interval / 2 : frame_interval; + repeat_field = false; + drop_field = false; + avsync_adjustment = refreshinterval - frameDelay; + avsync_adjustment = (refreshinterval > frameDelay) ? frameDelay : avsync_adjustment; + + if (avsync_used > frameDelay) { - avsync_adjustment += refreshrate; + avsync_adjustment = 0; + repeat_field = true; } - else if (avsync_used < 0 - refreshrate) + else if (avsync_used < 0 - frameDelay) { - avsync_adjustment -= refreshrate; + // drop field or frame + avsync_adjustment = 0; + drop_field = true; } + + LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + + QString("avsync_used(us) %1 av_adj %2").arg(avsync_used).arg(avsync_adjustment)); + } else lastsync = false; @@ -2175,13 +2203,29 @@ void MythPlayer::DisplayPauseFrame(void) RefreshPauseFrame(); PreProcessNormalFrame(); // Allow interactiveTV to draw on pause frame + // retrieve the next frame + videoOutput->StartDisplayingFrame(); + VideoFrame *frame = videoOutput->GetLastShownFrame(); + + FrameScanType ps = m_scan; + if (kScan_Detect == m_scan || kScan_Ignore == m_scan) + ps = kScan_Progressive; + + if (m_double_process && ps != kScan_Progressive) + { + //second stage of deinterlacer processing + ps = kScan_Intr2ndField; + } + +// ps = kScan_Ignore; + osdLock.lock(); videofiltersLock.lock(); - videoOutput->ProcessFrame(NULL, osd, videoFilters, pip_players); + videoOutput->ProcessFrame(frame, osd, videoFilters, pip_players, ps); videofiltersLock.unlock(); - videoOutput->PrepareFrame(NULL, kScan_Ignore, osd); + videoOutput->PrepareFrame(frame, ps, osd); osdLock.unlock(); - videoOutput->Show(kScan_Ignore); + videoOutput->Show(ps); videosync->Start(); } @@ -2316,10 +2360,6 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer) AutoDeint(frame); detect_letter_box->SwitchTo(frame); - FrameScanType ps = m_scan; - if (kScan_Detect == m_scan || kScan_Ignore == m_scan) - ps = kScan_Progressive; - AVSync(frame, 0); // If PiP then keep this frame for MythPlayer::GetCurrentFrame if (!player_ctx->IsPIP()) @@ -2444,11 +2484,11 @@ void MythPlayer::VideoStart(void) avsync_delay = 0; avsync_avg = 0; avsync_next = avsync_interval; // Frames till next sync check - refreshrate = 0; + refreshinterval = 0; lastsync = false; EnableFrameRateMonitor(); - refreshrate = frame_interval; + refreshinterval = frame_interval; float temp_speed = (play_speed == 0.0) ? audio.GetStretchFactor() : play_speed; int fr_int = (1000000.0 / video_frame_rate / temp_speed); @@ -3787,7 +3827,7 @@ void MythPlayer::ChangeSpeed(void) // If using bob deinterlace, turn on or off if we // changed to or from synchronous playback speed. - bool play_1 = play_speed > 0.99f && play_speed < 1.01f && normal_speed; + bool play_1 = true; //play_speed > 0.99f && play_speed < 1.01f && normal_speed; bool inter = (kScan_Interlaced == m_scan || kScan_Intr2ndField == m_scan); diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h index 1a23e2f..9c9fb64 100644 --- a/mythtv/libs/libmythtv/mythplayer.h +++ b/mythtv/libs/libmythtv/mythplayer.h @@ -656,6 +656,7 @@ class MTV_PUBLIC MythPlayer int64_t decoderSeek; bool decodeOneFrame; bool needNewPauseFrame; + bool first_time; mutable QMutex bufferPauseLock; mutable QMutex videoPauseLock; mutable QMutex pauseLock; @@ -809,8 +810,8 @@ class MTV_PUBLIC MythPlayer float play_speed; bool normal_speed; - int frame_interval;///< always adjusted for play_speed - int m_frame_interval;///< used to detect changes to frame_interval + int frame_interval; ///< always adjusted for play_speed + int m_frame_interval; ///< used to detect changes to frame_interval int ffrew_skip; int ffrew_adjust; @@ -822,10 +823,12 @@ class MTV_PUBLIC MythPlayer int avsync_avg; int avsync_predictor; bool avsync_predictor_enabled; - int refreshrate; + int refreshinterval; // time (us) bool lastsync; bool decode_extra_audio; int repeat_delay; + bool drop_field; + bool repeat_field; int64_t disp_timecode; bool avsync_audiopaused; float max_diverge; // from setting PlayerMaxDiverge default 2 diff --git a/mythtv/libs/libmythtv/videoout_vdpau.cpp b/mythtv/libs/libmythtv/videoout_vdpau.cpp index 07f6e6d..fd8fa59 100644 --- a/mythtv/libs/libmythtv/videoout_vdpau.cpp +++ b/mythtv/libs/libmythtv/videoout_vdpau.cpp @@ -505,9 +505,9 @@ void VideoOutputVDPAU::PrepareFrame(VideoFrame *frame, FrameScanType scan, VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD : VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; } - else if (!frame && m_deinterlacing) + else if (m_deinterlacing && !frame) { - field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; + field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; } m_render->WaitForFlip();