Ticket #13334: 20181020_1038_avsync2.patch
File 20181020_1038_avsync2.patch, 14.4 KB (added by , 6 years ago) |
---|
-
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) 2639 2639 thread_count = 1; 2640 2640 2641 2641 use_frame_timing = false; 2642 if (! private_dec 2643 && ! ringBuffer->IsDVD() 2642 if (! ringBuffer->IsDVD() 2644 2643 && (codec_is_std(video_codec_id) 2645 2644 || codec_is_mediacodec(video_codec_id) 2646 || codec_is_vaapi2(video_codec_id))) 2645 || codec_is_vaapi2(video_codec_id) 2646 || GetCodecDecoderName() == "openmax")) 2647 2647 use_frame_timing = true; 2648 2648 2649 2649 if (FlagIsSet(kDecodeSingleThreaded)) … … bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic) 4013 4013 pts = mpa_pic->pts; 4014 4014 if (pts == AV_NOPTS_VALUE) 4015 4015 pts = mpa_pic->pkt_dts; 4016 if (pts == AV_NOPTS_VALUE) 4017 pts = mpa_pic->reordered_opaque; 4016 4018 if (pts == AV_NOPTS_VALUE) 4017 4019 { 4018 4020 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) 217 217 // Time Code stuff 218 218 prevtc(0), prevrp(0), 219 219 savedAudioTimecodeOffset(0), 220 rtcbase(0), 221 maxtcval(0), maxtcframes(0), 220 222 // LiveTVChain stuff 221 223 m_tv(nullptr), isDummy(false), 222 224 // Counter for buffering messages … … MythPlayer::MythPlayer(PlayerFlags flags) 257 259 uint tmp = mypage.toInt(&valid, 16); 258 260 ttPageNum = (valid) ? tmp : ttPageNum; 259 261 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; 260 267 } 261 268 262 269 MythPlayer::~MythPlayer(void) … … bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio) 403 410 pauseLock.unlock(); 404 411 return false; 405 412 } 406 413 rtcbase = 0; 407 414 SetEof(kEofStateNone); 408 415 UnpauseBuffer(); 409 416 UnpauseDecoder(); … … void MythPlayer::ResetAVSync(void) 1795 1802 avsync_predictor = 0; 1796 1803 prevtc = 0; 1797 1804 avsync_next = avsync_interval; // Frames till next sync check 1805 rtcbase = 0; 1798 1806 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + "A/V sync reset"); 1799 1807 } 1800 1808 … … void MythPlayer::InitAVSync(void) 1810 1818 1811 1819 // Number of frames over which to average time divergence 1812 1820 avsync_averaging=4; 1821 rtcbase = 0; 1813 1822 1814 1823 // Special averaging default of 60 for OpenMAX passthru 1815 1824 QString device = gCoreContext->GetSetting("AudioOutputDevice",""); … … int64_t MythPlayer::AVSyncGetAudiotime(void) 1856 1865 1857 1866 void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) 1858 1867 { 1868 if (gCoreContext->GetNumSetting("PlaybackAVSync2", 0)) 1869 { 1870 AVSync2(buffer); 1871 return; 1872 } 1873 1859 1874 int repeat_pict = 0; 1860 1875 int64_t timecode = audio.GetAudioTime(); 1861 1876 … … void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) 2140 2155 } 2141 2156 } 2142 2157 2158 static int64_t time_to_usecs(timespec *tm); 2159 static void usecs_to_time(int64_t utime, timespec *tm); 2160 2161 2162 int64_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 2169 void 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 2177 void 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 2143 2373 void MythPlayer::RefreshPauseFrame(void) 2144 2374 { 2145 2375 if (needNewPauseFrame) … … void MythPlayer::DisplayNormalFrame(bool check_prebuffer) 2363 2593 detect_letter_box->SwitchTo(frame); 2364 2594 2365 2595 AVSync(frame, false); 2596 2366 2597 // If PiP then keep this frame for MythPlayer::GetCurrentFrame 2367 2598 if (!player_ctx->IsPIP()) 2368 2599 videoOutput->DoneDisplayingFrame(frame); … … void MythPlayer::ChangeSpeed(void) 3838 4069 float last_speed = play_speed; 3839 4070 play_speed = next_play_speed; 3840 4071 normal_speed = next_normal_speed; 4072 rtcbase = 0; 3841 4073 3842 4074 bool skip_changed = UpdateFFRewSkip(); 3843 4075 -
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 2 2 #define MYTHPLAYER_H 3 3 4 4 #include <cstdint> 5 #include <time.h> 5 6 6 7 #include <QCoreApplication> 7 8 #include <QList> … … class MTV_PUBLIC MythPlayer 615 616 void WrapTimecode(int64_t &timecode, TCTypes tc_type); 616 617 void InitAVSync(void); 617 618 virtual void AVSync(VideoFrame *buffer, bool limit_delay = false); 619 // New video sync method 620 void AVSync2(VideoFrame *buffer); 618 621 void ResetAVSync(void); 619 622 int64_t AVSyncGetAudiotime(void); 620 623 void SetFrameInterval(FrameScanType scan, double speed); … … class MTV_PUBLIC MythPlayer 844 847 int64_t tc_lastval[TCTYPESMAX]; 845 848 int64_t savedAudioTimecodeOffset; 846 849 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 847 856 // LiveTV 848 857 TV *m_tv; 849 858 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() 86 86 } 87 87 #endif 88 88 89 static 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 103 static 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 89 119 static HostCheckBoxSetting *OpenGLYV12() 90 120 { 91 121 HostCheckBoxSetting *gc = new HostCheckBoxSetting("OpenGLYV12"); … … void PlaybackSettings::Load(void) 4161 4191 #ifdef USING_VAAPI2 4162 4192 advanced->addChild(VAAPIDevice()); 4163 4193 #endif 4194 HostCheckBoxSetting *avsync2 = PlaybackAVSync2(); 4195 advanced->addChild(avsync2); 4196 avsync2->addTargetedChild("1",AVSync2AdjustMS()); 4164 4197 advanced->addChild(OpenGLYV12()); 4165 4198 advanced->addChild(OpenGLUYVY()); 4166 4199 addChild(advanced);