private void Player_ImageChanged(object sender, EventArgs <Bitmap> e) { if (!active || !synching) { return; } PlayerScreen player = sender as PlayerScreen; if (player == null) { return; } PlayerScreen otherPlayer = GetOtherPlayer(player); if (dynamicSynching) { if (player.IsPlaying) { currentTime = commonTimeline.GetCommonTime(player, player.LocalTime); Synchronize(); } else if (!otherPlayer.IsPlaying) { // Both players have completed a loop and are waiting. currentTime = 0; Synchronize(); } } UpdateHairLines(); if (!view.Merging || e.Value == null) { return; } otherPlayer.SetSyncMergeImage(e.Value, !dualSaveInProgress); }
private void Player_ImageChanged(object sender, EventArgs <Bitmap> e) { if (!active || !synching) { return; } PlayerScreen player = sender as PlayerScreen; if (player == null) { return; } PlayerScreen otherPlayer = GetOtherPlayer(player); if (dynamicSynching) { if (player.IsPlaying) { //log.DebugFormat("Received image from [{0}] ({1}).", GetPlayerIndex(player), player.LocalTime / 1000); currentTime = commonTimeline.GetCommonTime(player, player.LocalTime); if (otherPlayer.IsPlaying && resyncOperations < maxResyncOperations) { //---------------------------------------------------------------------------------- // Test for desync. // This is not the primary synchronization mechanism, videos should synchronize naturally from being started // at the right time, based on their time origin and the fact that their playback rate relative to real time should match. // // However, for videos started automatically, we can't guarantee that one isn't ahead of the other. // We allow ourselves one attempt at resync here. // This kind of resync can easily misfire and cause judder so it's only used very sparingly. //---------------------------------------------------------------------------------- long otherTime = commonTimeline.GetCommonTime(otherPlayer, otherPlayer.LocalTime); long divergence = Math.Abs(currentTime - otherTime); long frameTime = Math.Max(player.LocalFrameTime, otherPlayer.LocalFrameTime); if (divergence > frameTime) { resyncOperations++; log.WarnFormat("Synchronization divergence: [{0}]@{1} vs [{2}]@{3}. Resynchronizing.", GetPlayerIndex(player), currentTime / 1000, GetPlayerIndex(otherPlayer), otherTime / 1000); AlignPlayers(true); } } EnsureBothPlaying(); } else if (!otherPlayer.IsPlaying) { // Both players have completed a loop and are waiting. currentTime = 0; EnsureBothPlaying(); } } UpdateHairLines(); if (!view.Merging || e.Value == null) { return; } otherPlayer.SetSyncMergeImage(e.Value, !dualSaveInProgress); }