diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
index 5b80c452a3b..8620164b2e2 100644
|
a
|
b
|
MythPlayer::MythPlayer(PlayerFlags flags)
|
| 223 | 223 | rtcbase(0), |
| 224 | 224 | maxtcval(0), maxtcframes(0), |
| 225 | 225 | numdroppedframes(0), |
| | 226 | prior_audiotimecode(0), |
| | 227 | prior_videotimecode(0), |
| 226 | 228 | // LiveTVChain stuff |
| 227 | 229 | m_tv(nullptr), isDummy(false), |
| 228 | 230 | // Counter for buffering messages |
| … |
… |
bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
|
| 415 | 417 | return false; |
| 416 | 418 | } |
| 417 | 419 | rtcbase = 0; |
| | 420 | prior_audiotimecode = 0; |
| | 421 | prior_videotimecode = 0; |
| 418 | 422 | SetEof(kEofStateNone); |
| 419 | 423 | UnpauseBuffer(); |
| 420 | 424 | UnpauseDecoder(); |
| … |
… |
void MythPlayer::ResetAVSync(void)
|
| 1806 | 1810 | prevtc = 0; |
| 1807 | 1811 | avsync_next = avsync_interval; // Frames till next sync check |
| 1808 | 1812 | rtcbase = 0; |
| | 1813 | prior_audiotimecode = 0; |
| | 1814 | prior_videotimecode = 0; |
| 1809 | 1815 | LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + "A/V sync reset"); |
| 1810 | 1816 | } |
| 1811 | 1817 | |
| … |
… |
void MythPlayer::InitAVSync(void)
|
| 1822 | 1828 | // Number of frames over which to average time divergence |
| 1823 | 1829 | avsync_averaging=4; |
| 1824 | 1830 | rtcbase = 0; |
| | 1831 | prior_audiotimecode = 0; |
| | 1832 | prior_videotimecode = 0; |
| 1825 | 1833 | |
| 1826 | 1834 | // Special averaging default of 60 for OpenMAX passthru |
| 1827 | 1835 | QString device = gCoreContext->GetSetting("AudioOutputDevice",""); |
| … |
… |
void wait_for_time(int64_t framedue)
|
| 2170 | 2178 | QThread::usleep(delay); |
| 2171 | 2179 | } |
| 2172 | 2180 | |
| 2173 | | #define AVSYNC_MAX_LATE 1000000 |
| | 2181 | #define AVSYNC_MAX_LATE 10000000 |
| 2174 | 2182 | void MythPlayer::AVSync2(VideoFrame *buffer) |
| 2175 | 2183 | { |
| 2176 | 2184 | if (videoOutput->IsErrored()) |
| … |
… |
void MythPlayer::AVSync2(VideoFrame *buffer)
|
| 2180 | 2188 | SetErrored(tr("Failed to initialize A/V Sync")); |
| 2181 | 2189 | return; |
| 2182 | 2190 | } |
| 2183 | | int64_t audiotimecode = audio.GetAudioTime(); |
| 2184 | 2191 | int64_t videotimecode = 0; |
| 2185 | 2192 | |
| 2186 | 2193 | bool dropframe = false; |
| … |
… |
void MythPlayer::AVSync2(VideoFrame *buffer)
|
| 2191 | 2198 | int64_t unow = 0; |
| 2192 | 2199 | int64_t lateness = 0; |
| 2193 | 2200 | int64_t playspeed1000 = (float)1000 / play_speed; |
| | 2201 | bool reset = false; |
| 2194 | 2202 | |
| 2195 | 2203 | while (framedue == 0) |
| 2196 | 2204 | { |
| 2197 | | bool reset = false; |
| 2198 | 2205 | if (buffer) |
| 2199 | 2206 | { |
| 2200 | 2207 | videotimecode = buffer->timecode & 0x0000ffffffffffff; |
| … |
… |
void MythPlayer::AVSync2(VideoFrame *buffer)
|
| 2210 | 2217 | { |
| 2211 | 2218 | // cater for DVB radio |
| 2212 | 2219 | if (videotimecode == 0) |
| 2213 | | videotimecode = audiotimecode; |
| | 2220 | videotimecode = audio.GetAudioTime();; |
| 2214 | 2221 | // On first frame we get nothing, so exit out. |
| 2215 | 2222 | if (videotimecode == 0) |
| 2216 | 2223 | return; |
| … |
… |
void MythPlayer::AVSync2(VideoFrame *buffer)
|
| 2244 | 2251 | if (lateness > 30000) |
| 2245 | 2252 | dropframe = !FlagIsSet(kMusicChoice) && numdroppedframes < 10; |
| 2246 | 2253 | |
| 2247 | | if (lateness <= 30000 && audiotimecode > 0 && normal_speed && !FlagIsSet(kMusicChoice)) |
| | 2254 | if (lateness <= 30000 && prior_audiotimecode > 0 |
| | 2255 | && prior_videotimecode > 0 && normal_speed && !FlagIsSet(kMusicChoice)) |
| 2248 | 2256 | { |
| 2249 | 2257 | // Get video in sync with audio |
| 2250 | | audio_adjustment = audiotimecode - videotimecode; |
| 2251 | | int sign = audio_adjustment < 0 ? -1 : 1; |
| 2252 | | if (audio_adjustment * sign > 40) |
| | 2258 | audio_adjustment = prior_audiotimecode - prior_videotimecode; |
| | 2259 | // If there is excess audio - throw it away. |
| | 2260 | if (audio_adjustment < -200) |
| 2253 | 2261 | { |
| 2254 | | // adjust by AVSyncIncrementMS milliseconds at a time (range 1-40) |
| 2255 | | rtcbase -= (int64_t)1000000 * avsync2adjustms * sign / playspeed1000; |
| | 2262 | audio.Reset(); |
| | 2263 | audio_adjustment = 0; |
| | 2264 | } |
| | 2265 | int sign = audio_adjustment < 0 ? -1 : 1; |
| | 2266 | int64_t fix_amount = audio_adjustment * sign; |
| | 2267 | if (fix_amount > avsync2adjustms) |
| | 2268 | fix_amount = avsync2adjustms; |
| | 2269 | // Faster catch-up when off by more than 200 ms |
| | 2270 | if (audio_adjustment * sign > 200) |
| | 2271 | // fix the sync within 15 - 20 frames |
| | 2272 | fix_amount = audio_adjustment * sign / 15; |
| | 2273 | int64_t speedup1000 = (float)1000 * play_speed; |
| | 2274 | rtcbase -= (int64_t)1000000 * fix_amount * sign / speedup1000; |
| | 2275 | if (audio_adjustment * sign > 20 || (framesPlayed % 400 == 0)) |
| 2256 | 2276 | LOG(VB_PLAYBACK, LOG_INFO, LOC + |
| 2257 | 2277 | QString("AV Sync, audio ahead by %1 ms").arg(audio_adjustment)); |
| 2258 | | } |
| 2259 | | if (audio_adjustment > 1000) |
| | 2278 | if (audio_adjustment > 200) |
| 2260 | 2279 | pause_audio = true; |
| 2261 | 2280 | } |
| 2262 | 2281 | // sanity check - reset rtcbase if time codes have gone crazy. |
| … |
… |
void MythPlayer::AVSync2(VideoFrame *buffer)
|
| 2277 | 2296 | reset = true; |
| 2278 | 2297 | } |
| 2279 | 2298 | } |
| 2280 | | |
| | 2299 | prior_videotimecode = videotimecode; |
| 2281 | 2300 | disp_timecode = videotimecode; |
| 2282 | 2301 | |
| 2283 | 2302 | output_jmeter && output_jmeter->RecordCycleTime(); |
| … |
… |
void MythPlayer::AVSync2(VideoFrame *buffer)
|
| 2307 | 2326 | audio.Pause(true); |
| 2308 | 2327 | } |
| 2309 | 2328 | |
| 2310 | | LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + |
| 2311 | | QString("A/V timecodes audio=%1 video=%2 frameinterval=%3 " |
| 2312 | | "audioadj=%4 tcoffset=%5 unow=%6 udue=%7") |
| 2313 | | .arg(audiotimecode) |
| 2314 | | .arg(videotimecode) |
| 2315 | | .arg(frame_interval) |
| 2316 | | .arg(audio_adjustment) |
| 2317 | | .arg(tc_wrap[TC_AUDIO]) |
| 2318 | | .arg(unow) |
| 2319 | | .arg(framedue) |
| 2320 | | ); |
| 2321 | 2329 | |
| 2322 | 2330 | if (dropframe) |
| 2323 | 2331 | numdroppedframes++; |
| … |
… |
void MythPlayer::AVSync2(VideoFrame *buffer)
|
| 2338 | 2346 | // the primary PBP will become out of sync |
| 2339 | 2347 | if (!player_ctx->IsPBP() || player_ctx->IsPrimaryPBP()) |
| 2340 | 2348 | wait_for_time(framedue); |
| | 2349 | // get time codes for calculating difference next time |
| | 2350 | prior_audiotimecode = audio.GetAudioTime(); |
| 2341 | 2351 | videoOutput->Show(ps); |
| 2342 | 2352 | if (videoOutput->IsErrored()) |
| 2343 | 2353 | { |
| … |
… |
void MythPlayer::AVSync2(VideoFrame *buffer)
|
| 2373 | 2383 | } |
| 2374 | 2384 | else |
| 2375 | 2385 | wait_for_time(framedue); |
| | 2386 | |
| | 2387 | LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + |
| | 2388 | QString("A/V timecodes audio=%1 video=%2 frameinterval=%3 " |
| | 2389 | "audioadj=%4 tcoffset=%5 unow=%6 udue=%7") |
| | 2390 | .arg(prior_audiotimecode) |
| | 2391 | .arg(prior_videotimecode) |
| | 2392 | .arg(frame_interval) |
| | 2393 | .arg(audio_adjustment) |
| | 2394 | .arg(tc_wrap[TC_AUDIO]) |
| | 2395 | .arg(unow) |
| | 2396 | .arg(framedue) |
| | 2397 | ); |
| | 2398 | |
| 2376 | 2399 | } |
| 2377 | 2400 | |
| 2378 | 2401 | void MythPlayer::RefreshPauseFrame(void) |
| … |
… |
bool MythPlayer::PrebufferEnoughFrames(int min_buffers)
|
| 2451 | 2474 | if (!videoOutput) |
| 2452 | 2475 | return false; |
| 2453 | 2476 | |
| 2454 | | bool paused_now = false; |
| 2455 | 2477 | if (!(min_buffers ? (videoOutput->ValidVideoFrames() >= min_buffers) : |
| 2456 | 2478 | (GetEof() != kEofStateNone) || |
| 2457 | 2479 | (videoOutput->hasHWAcceleration() ? |
| … |
… |
bool MythPlayer::PrebufferEnoughFrames(int min_buffers)
|
| 2467 | 2489 | // for the jerking is detected. |
| 2468 | 2490 | |
| 2469 | 2491 | bool watchingTV = IsWatchingInprogress(); |
| 2470 | | if (!paused_now && (livetv || watchingTV) && !FlagIsSet(kMusicChoice)) |
| | 2492 | if ( (livetv || watchingTV) && !FlagIsSet(kMusicChoice)) |
| 2471 | 2493 | { |
| 2472 | 2494 | uint64_t frameCount = GetCurrentFrameCount(); |
| 2473 | 2495 | uint64_t framesLeft = frameCount - framesPlayed; |
| … |
… |
bool MythPlayer::PrebufferEnoughFrames(int min_buffers)
|
| 2479 | 2501 | .arg(framesPlayed).arg(frameCount)); |
| 2480 | 2502 | audio.Pause(true); |
| 2481 | 2503 | avsync_audiopaused = true; |
| 2482 | | paused_now = true; |
| | 2504 | rtcbase = 0; |
| 2483 | 2505 | } |
| 2484 | 2506 | } |
| 2485 | 2507 | usleep(frame_interval >> 3); |
diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h
index 7358d617a9d..4b295af28fe 100644
|
a
|
b
|
class MTV_PUBLIC MythPlayer
|
| 856 | 856 | int maxtcframes; // number of frames seen since max to date tc |
| 857 | 857 | int64_t avsync2adjustms; // number of milliseconds to adjust for av sync errors |
| 858 | 858 | int numdroppedframes; // number of consecutive dropped frames. |
| | 859 | int64_t prior_audiotimecode; // time code from prior frame |
| | 860 | int64_t prior_videotimecode; // time code from prior frame |
| 859 | 861 | |
| 860 | 862 | // LiveTV |
| 861 | 863 | TV *m_tv; |