Changeset 239857 in webkit
- Timestamp:
- Jan 10, 2019, 8:46:23 PM (8 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 5 edited
-
ChangeLog (modified) (1 diff)
-
platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp (modified) (5 diffs)
-
platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h (modified) (1 diff)
-
platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h (modified) (6 diffs)
-
platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r239854 r239857 1 2019-01-10 Jer Noble <jer.noble@apple.com> 2 3 <video> elements do not enter 'paused' state when playing to end over AirPlay 4 https://bugs.webkit.org/show_bug.cgi?id=193295 5 <rdar://problem/46708670> 6 7 Reviewed by Eric Carlson. 8 9 Adopt the -[AVPlayer timeControlStatus] API, which reports whether the AVPlayer is paused, playing, or blocked waiting 10 for more data before playing. AirPlay devices report this state back from the remote device, and this allows the 11 MediaPlayerPrivateAVFoundationObjC to differentiate between user-generated pauses and simple stalling. 12 13 Adopting this API allows us to remove the heuristic from rateChanged() which inteprets a rate change when the 14 readyState > HAVE_ENOUGH as an intentional pause. 15 16 Drive-by fix: MediaPlayerPrivateAVFoundation had some code to delay calling platformPlay() 17 until the first frame became available. But this code was entirely undermined by the previous 18 behavior of setRate(). Fixing setRate()/setRateDouble() to only start playback if playback was 19 actually requested started making this code work for the first time, and broke some API tests. 20 Thus, we're removing this previously dead code. 21 22 * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp: 23 (WebCore::MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation): 24 (WebCore::MediaPlayerPrivateAVFoundation::play): 25 (WebCore::MediaPlayerPrivateAVFoundation::pause): 26 (WebCore::MediaPlayerPrivateAVFoundation::rateChanged): 27 (WebCore::MediaPlayerPrivateAVFoundation::updateStates): 28 * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h: 29 * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h: 30 * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm: 31 (WebCore::MediaPlayerPrivateAVFoundationObjC::cancelLoad): 32 (WebCore::MediaPlayerPrivateAVFoundationObjC::createAVPlayer): 33 (WebCore::MediaPlayerPrivateAVFoundationObjC::didEnd): 34 (WebCore::MediaPlayerPrivateAVFoundationObjC::platformPlay): 35 (WebCore::MediaPlayerPrivateAVFoundationObjC::platformPause): 36 (WebCore::MediaPlayerPrivateAVFoundationObjC::seekToTime): 37 (WebCore::MediaPlayerPrivateAVFoundationObjC::setRateDouble): 38 (WebCore::MediaPlayerPrivateAVFoundationObjC::setPlayerRate): 39 (WebCore::MediaPlayerPrivateAVFoundationObjC::timeControlStatusDidChange): 40 (WebCore::MediaPlayerPrivateAVFoundationObjC::setShouldObserveTimeControlStatus): 41 (-[WebCoreAVFMovieObserver observeValueForKeyPath:ofObject:change:context:]): 42 1 43 2019-01-10 Myles C. Maxfield <mmaxfield@apple.com> 2 44 -
trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp
r238815 r239857 80 80 , m_ignoreLoadStateChanges(false) 81 81 , m_haveReportedFirstVideoFrame(false) 82 , m_playWhenFramesAvailable(false)83 82 , m_inbandTrackConfigurationPending(false) 84 83 , m_characteristicsChanged(false) … … 217 216 { 218 217 ALWAYS_LOG(LOGIDENTIFIER); 219 220 // If the file has video, don't request playback until the first frame of video is ready to display 221 // or the audio may start playing before we can render video. 222 if (!m_cachedHasVideo || hasAvailableVideoFrame()) 223 platformPlay(); 224 else { 225 INFO_LOG(LOGIDENTIFIER, "waiting for first video frame"); 226 m_playWhenFramesAvailable = true; 227 } 218 platformPlay(); 228 219 } 229 220 … … 231 222 { 232 223 ALWAYS_LOG(LOGIDENTIFIER); 233 m_playWhenFramesAvailable = false;234 224 platformPause(); 235 225 } … … 577 567 setNetworkState(newNetworkState); 578 568 setReadyState(newReadyState); 579 580 if (m_playWhenFramesAvailable && hasAvailableVideoFrame()) {581 m_playWhenFramesAvailable = false;582 platformPlay();583 }584 569 } 585 570 … … 624 609 void MediaPlayerPrivateAVFoundation::rateChanged() 625 610 { 626 627 #if ENABLE(WIRELESS_PLAYBACK_TARGET) && PLATFORM(IOS_FAMILY)628 if (isCurrentPlaybackTargetWireless() && playerItemStatus() >= MediaPlayerAVPlayerItemStatusPlaybackBufferFull) {629 double rate = this->rate();630 if (rate != requestedRate()) {631 m_player->handlePlaybackCommand(rate ? PlatformMediaSession::PlayCommand : PlatformMediaSession::PauseCommand);632 return;633 }634 }635 #endif636 637 611 m_player->rateChanged(); 638 612 } -
trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h
r232613 r239857 370 370 bool m_ignoreLoadStateChanges; 371 371 bool m_haveReportedFirstVideoFrame; 372 bool m_playWhenFramesAvailable;373 372 bool m_inbandTrackConfigurationPending; 374 373 bool m_characteristicsChanged; -
trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h
r239427 r239857 81 81 void setAsset(RetainPtr<id>&&); 82 82 void tracksChanged() override; 83 void didEnd() override; 83 84 84 85 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) … … 114 115 void durationDidChange(const MediaTime&); 115 116 void rateDidChange(double); 117 void timeControlStatusDidChange(int); 116 118 void metadataDidArrive(const RetainPtr<NSArray>&, const MediaTime&); 117 119 void firstFrameAvailableDidChange(bool); … … 182 184 void setVideoFullscreenMode(MediaPlayer::VideoFullscreenMode) override; 183 185 void videoFullscreenStandbyChanged() override; 186 void setPlayerRate(double); 184 187 185 188 #if PLATFORM(IOS_FAMILY) … … 334 337 335 338 bool performTaskAtMediaTime(WTF::Function<void()>&&, MediaTime) final; 339 void setShouldObserveTimeControlStatus(bool); 336 340 337 341 WeakPtrFactory<MediaPlayerPrivateAVFoundationObjC> m_weakPtrFactory; … … 416 420 RefPtr<SharedBuffer> m_keyID; 417 421 double m_cachedRate; 422 bool m_requestedPlaying { false }; 423 double m_requestedRate { 1.0 }; 424 int m_cachedTimeControlStatus { 0 }; 418 425 mutable long long m_cachedTotalBytes; 419 426 unsigned m_pendingStatusChanges; … … 429 436 bool m_cachedCanPlayFastReverse; 430 437 bool m_muted { false }; 438 bool m_shouldObserveTimeControlStatus { false }; 431 439 mutable Optional<bool> m_tracksArePlayable; 432 440 #if ENABLE(WIRELESS_PLAYBACK_TARGET) -
trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm
r239535 r239857 588 588 [m_avPlayer.get() removeObserver:m_objcObserver.get() forKeyPath:keyName]; 589 589 590 setShouldObserveTimeControlStatus(false); 591 590 592 [m_avPlayer replaceCurrentItemWithPlayerItem:nil]; 591 593 m_avPlayer = nil; … … 1012 1014 [m_avPlayer.get() addObserver:m_objcObserver.get() forKeyPath:keyName options:NSKeyValueObservingOptionNew context:(void *)MediaPlayerAVFoundationObservationContextPlayer]; 1013 1015 1016 setShouldObserveTimeControlStatus(true); 1017 1014 1018 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT) 1015 1019 [m_avPlayer.get() setAppliesMediaSelectionCriteriaAutomatically:NO]; … … 1266 1270 #endif 1267 1271 1272 void MediaPlayerPrivateAVFoundationObjC::didEnd() 1273 { 1274 m_requestedPlaying = false; 1275 MediaPlayerPrivateAVFoundation::didEnd(); 1276 } 1277 1268 1278 void MediaPlayerPrivateAVFoundationObjC::platformSetVisible(bool isVisible) 1269 1279 { … … 1281 1291 return; 1282 1292 1283 setDelayCallbacks(true); 1284 m_cachedRate = requestedRate(); 1285 [m_avPlayer.get() setRate:requestedRate()]; 1286 setDelayCallbacks(false); 1293 m_requestedPlaying = true; 1294 setPlayerRate(m_requestedRate); 1287 1295 } 1288 1296 … … 1293 1301 return; 1294 1302 1295 setDelayCallbacks(true); 1296 m_cachedRate = 0; 1297 [m_avPlayer.get() setRate:0]; 1298 setDelayCallbacks(false); 1303 m_requestedPlaying = false; 1304 setPlayerRate(0); 1299 1305 } 1300 1306 … … 1354 1360 auto weakThis = makeWeakPtr(*this); 1355 1361 1362 setShouldObserveTimeControlStatus(false); 1356 1363 [m_avPlayerItem.get() seekToTime:cmTime toleranceBefore:cmBefore toleranceAfter:cmAfter completionHandler:^(BOOL finished) { 1357 1364 callOnMainThread([weakThis, finished] { … … 1360 1367 return; 1361 1368 1369 _this->setShouldObserveTimeControlStatus(true); 1362 1370 _this->seekCompleted(finished); 1363 1371 }); … … 1407 1415 void MediaPlayerPrivateAVFoundationObjC::setRateDouble(double rate) 1408 1416 { 1417 m_requestedRate = rate; 1418 if (m_requestedPlaying) 1419 setPlayerRate(rate); 1420 } 1421 1422 void MediaPlayerPrivateAVFoundationObjC::setPlayerRate(double rate) 1423 { 1409 1424 setDelayCallbacks(true); 1410 1425 m_cachedRate = rate; 1411 [m_avPlayer.get() setRate:rate]; 1426 setShouldObserveTimeControlStatus(false); 1427 [m_avPlayer setRate:rate]; 1428 m_cachedTimeControlStatus = [m_avPlayer timeControlStatus]; 1429 setShouldObserveTimeControlStatus(true); 1412 1430 setDelayCallbacks(false); 1413 1431 } … … 3235 3253 } 3236 3254 3255 void MediaPlayerPrivateAVFoundationObjC::timeControlStatusDidChange(int timeControlStatus) 3256 { 3257 if (m_cachedTimeControlStatus == timeControlStatus) 3258 return; 3259 3260 if (!m_shouldObserveTimeControlStatus) 3261 return; 3262 3263 m_cachedTimeControlStatus = timeControlStatus; 3264 3265 #if ENABLE(WIRELESS_PLAYBACK_TARGET) 3266 if (!isCurrentPlaybackTargetWireless()) 3267 return; 3268 3269 bool playerIsPlaying = m_cachedTimeControlStatus != AVPlayerTimeControlStatusPaused; 3270 if (playerIsPlaying != m_requestedPlaying) 3271 player()->handlePlaybackCommand(playerIsPlaying ? PlatformMediaSession::PlayCommand : PlatformMediaSession::PauseCommand); 3272 #endif 3273 } 3274 3237 3275 #if ENABLE(WIRELESS_PLAYBACK_TARGET) 3238 3276 … … 3309 3347 }]; 3310 3348 return true; 3349 } 3350 3351 void MediaPlayerPrivateAVFoundationObjC::setShouldObserveTimeControlStatus(bool shouldObserve) 3352 { 3353 if (shouldObserve == m_shouldObserveTimeControlStatus) 3354 return; 3355 3356 m_shouldObserveTimeControlStatus = shouldObserve; 3357 if (shouldObserve) 3358 [m_avPlayer addObserver:m_objcObserver.get() forKeyPath:@"timeControlStatus" options:NSKeyValueObservingOptionNew context:(void *)MediaPlayerAVFoundationObservationContextPlayer]; 3359 else 3360 [m_avPlayer removeObserver:m_objcObserver.get() forKeyPath:@"timeControlStatus"]; 3311 3361 } 3312 3362 … … 3474 3524 if ([keyPath isEqualToString:@"rate"]) 3475 3525 player->rateDidChange([newValue doubleValue]); 3526 else if ([keyPath isEqualToString:@"timeControlStatus"]) 3527 player->timeControlStatusDidChange([newValue intValue]); 3476 3528 #if ENABLE(WIRELESS_PLAYBACK_TARGET) 3477 3529 else if ([keyPath isEqualToString:@"externalPlaybackActive"] || [keyPath isEqualToString:@"allowsExternalPlayback"])
Note:
See TracChangeset
for help on using the changeset viewer.