Changeset 85865 in webkit
- Timestamp:
- May 5, 2011 11:17:23 AM (13 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r85864 r85865 1 2011-05-05 Eric Carlson <eric.carlson@apple.com> 2 3 Reviewed by Adam Roben. 4 5 The preload attribute of the video tag is not completely implemented 6 https://bugs.webkit.org/show_bug.cgi?id=43673 7 <rdar://problem/9369746> 8 9 This change implements "preload=metadata" for the AVFoundation backend. 10 Tested manually with manual-tests/media-elements/video-preload.html. 11 12 * html/HTMLMediaElement.cpp: 13 (WebCore::HTMLMediaElement::HTMLMediaElement): Initialize m_havePreparedToPlay. 14 (WebCore::HTMLMediaElement::prepareForLoad): Ditto. 15 (WebCore::HTMLMediaElement::prepareToPlay): New, tell player to prepare to play. 16 (WebCore::HTMLMediaElement::seek): Call prepareToPlay when preload is less than 'auto' 17 because we need to have media data loaded to seek. 18 (WebCore::HTMLMediaElement::updatePlayState): Call prepareToPlay. 19 * html/HTMLMediaElement.h: 20 21 * manual-tests/media-elements/video-preload.html: Make changing urls work. 22 23 * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp: 24 (WebCore::MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation): Remove 25 m_videoFrameHasDrawn and m_delayingLoad as they are no longer used. 26 (WebCore::MediaPlayerPrivateAVFoundation::resumeLoad): Removed. 27 (WebCore::MediaPlayerPrivateAVFoundation::load): Don't initialize m_videoFrameHasDrawn. 28 Move all preload logic to setPreload, call it from here. 29 (WebCore::MediaPlayerPrivateAVFoundation::prepareToPlay): Move all preload logic to 30 setPreload, call it. 31 (WebCore::MediaPlayerPrivateAVFoundation::duration): Don't cache duration = 0, it is 32 unlikely to be correct and isn't worth caching. Use invalidTime() function. 33 (WebCore::MediaPlayerPrivateAVFoundation::seeking): Use invalidTime() function. 34 (WebCore::MediaPlayerPrivateAVFoundation::setNaturalSize): Add logging. 35 (WebCore::MediaPlayerPrivateAVFoundation::updateStates): Update for name change AVAssetStatus 36 to AssetStatus. Always create a AVPlayerItem for live streams because they can't be inspected 37 without one. Set networkState to 'idle' when the playback buffer is full because that is 38 a signal that AVFoundation won't do any more IO. Set readyState to 'HAVE_CURRENT_DATA' 39 when the first frame is available. 40 (WebCore::MediaPlayerPrivateAVFoundation::metadataLoaded): Call tracksChanged so we cache 41 width, height, hasVideo, etc. 42 (WebCore::MediaPlayerPrivateAVFoundation::loadedTimeRangesChanged): Use invalidTime() function. 43 (WebCore::MediaPlayerPrivateAVFoundation::timeChanged): Ditto. 44 (WebCore::MediaPlayerPrivateAVFoundation::seekCompleted): Ditto. 45 (WebCore::MediaPlayerPrivateAVFoundation::repaint): Don't set m_videoFrameHasDrawn, it is done 46 in derived classes. 47 (WebCore::MediaPlayerPrivateAVFoundation::setPreload): Centralize all logic about when to create 48 AVAsset and AVPlayerItem here. 49 * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h: 50 51 * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h: 52 * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm: 53 (WebCore::MediaPlayerPrivateAVFoundationObjC::MediaPlayerPrivateAVFoundationObjC): Initialize 54 m_videoFrameHasDrawn. 55 (WebCore::MediaPlayerPrivateAVFoundationObjC::hasAvailableVideoFrame): New, renamed from 56 videoLayerIsReadyToDisplay. Return true if we have a layer with frames available or 57 if we have painted a frame to the context. 58 (WebCore::MediaPlayerPrivateAVFoundationObjC::createAVAssetForURL): New, create the AVAsset 59 if necessary. 60 (WebCore::MediaPlayerPrivateAVFoundationObjC::createAVAssetForCacheResource): Ditto. 61 (WebCore::MediaPlayerPrivateAVFoundationObjC::createAVPlayer): Restructure logic. 62 (WebCore::MediaPlayerPrivateAVFoundationObjC::createAVPlayerItem): New, create AVPlayerItem. 63 (WebCore::MediaPlayerPrivateAVFoundationObjC::beginLoadingMetadata): Correct logging. 64 (WebCore::MediaPlayerPrivateAVFoundationObjC::playerItemStatus): Return "buffer full" when 65 the buffer is full. 66 (WebCore::MediaPlayerPrivateAVFoundationObjC::platformDuration): Get the duration from the 67 AVAsset when we haven't allocated the AVPlayerItem yet so that we can return duration 68 when we only have metadata. 69 (WebCore::MediaPlayerPrivateAVFoundationObjC::assetStatus): Update for name change. 70 (WebCore::MediaPlayerPrivateAVFoundationObjC::paint): Set m_videoFrameHasDrawn. 71 (WebCore::MediaPlayerPrivateAVFoundationObjC::tracksChanged): Get attributes from AVAsset 72 when when we haven't allocated the AVPlayerItem yet so that we can report attributes 73 when we only have metadata. 74 (WebCore::MediaPlayerPrivateAVFoundationObjC::sizeChanged): Guard against being called before 75 we have allocated the AVPlayerItem. 76 1 77 2011-05-05 Ryosuke Niwa <rniwa@webkit.org> 2 78 -
trunk/Source/WebCore/html/HTMLMediaElement.cpp
r85518 r85865 172 172 , m_loadInitiatedByUserGesture(false) 173 173 , m_completelyLoaded(false) 174 , m_havePreparedToPlay(false) 174 175 { 175 176 LOG(Media, "HTMLMediaElement::HTMLMediaElement"); … … 518 519 m_haveFiredLoadedData = false; 519 520 m_completelyLoaded = false; 521 m_havePreparedToPlay = false; 520 522 m_displayMode = Unknown; 521 523 … … 1083 1085 return m_player ? m_player->supportsSave() : false; 1084 1086 } 1085 1087 1088 void HTMLMediaElement::prepareToPlay() 1089 { 1090 if (m_havePreparedToPlay) 1091 return; 1092 m_havePreparedToPlay = true; 1093 m_player->prepareToPlay(); 1094 } 1095 1086 1096 void HTMLMediaElement::seek(float time, ExceptionCode& ec) 1087 1097 { … … 1095 1105 return; 1096 1106 } 1107 1108 // If the media engine has been told to postpone loading data, let it go ahead now. 1109 if (m_preload < MediaPlayer::Auto && m_readyState < HAVE_FUTURE_DATA) 1110 prepareToPlay(); 1097 1111 1098 1112 // Get the current time before setting m_seeking, m_lastSeekTime is returned once it is set. … … 2197 2211 2198 2212 if (couldPlayIfEnoughData()) 2199 m_player->prepareToPlay();2213 prepareToPlay(); 2200 2214 2201 2215 if (hasMediaControls()) -
trunk/Source/WebCore/html/HTMLMediaElement.h
r85811 r85865 289 289 void cancelPendingEventsAndCallbacks(); 290 290 void waitForSourceChange(); 291 void prepareToPlay(); 291 292 292 293 enum InvalidSourceAction { DoNothing, Complain }; … … 420 421 bool m_loadInitiatedByUserGesture : 1; 421 422 bool m_completelyLoaded : 1; 423 bool m_havePreparedToPlay : 1; 422 424 }; 423 425 -
trunk/Source/WebCore/manual-tests/media-elements/video-preload.html
r85476 r85865 96 96 } 97 97 98 function setURL(url , vidID)99 { 100 var vid = document.getElementById( vidID);98 function setURL(url) 99 { 100 var vid = document.getElementById("vid"); 101 101 102 102 logMsg(vid, "###############"); … … 200 200 <tbody> 201 201 <tr><td>Preload</td><td id="Preload"></td></tr> 202 <tr><td>Error</td><td id="Error"></td></tr> 202 203 <tr><td>Duration</td> <td id="Duration"></td></tr> 203 204 <tr><td>Video Width</td><td id="Video Width"></td></tr> … … 217 218 <br> 218 219 <div class="info"> 219 Enter a url:<input type="text" size="90" maxlength="2048" onchange="setURL(this.value , 'vid-1')" >220 Enter a url:<input type="text" size="90" maxlength="2048" onchange="setURL(this.value)" > 220 221 <br> 221 222 <input id="clear_log" type="button" value="Clear" onclick="clearlog()"> -
trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp
r85518 r85865 31 31 32 32 #include "ApplicationCacheHost.h" 33 #include "ApplicationCacheResource.h" 33 34 #include "DocumentLoader.h" 34 35 #include "FrameView.h" … … 46 47 namespace WebCore { 47 48 48 static const float invalidTime = -1.0f;49 50 49 MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(MediaPlayer* player) 51 50 : m_player(player) 52 51 , m_queuedNotifications() 53 52 , m_queueMutex() 54 , m_mainThreadCallPending(false)55 53 , m_networkState(MediaPlayer::Empty) 56 54 , m_readyState(MediaPlayer::HaveNothing) … … 59 57 , m_cachedMaxTimeLoaded(0) 60 58 , m_cachedMaxTimeSeekable(0) 61 , m_cachedDuration(invalidTime )62 , m_reportedDuration(invalidTime )63 , m_seekTo(invalidTime )59 , m_cachedDuration(invalidTime()) 60 , m_reportedDuration(invalidTime()) 61 , m_seekTo(invalidTime()) 64 62 , m_requestedRate(1) 65 , m_delayCallbacks( false)66 , m_ havePreparedToPlay(false)63 , m_delayCallbacks(0) 64 , m_mainThreadCallPending(false) 67 65 , m_assetIsPlayable(false) 68 66 , m_visible(false) 69 , m_videoFrameHasDrawn(false)70 67 , m_loadingMetadata(false) 71 , m_delayingLoad(false)72 68 , m_isAllowedToRender(false) 73 69 , m_cachedHasAudio(false) … … 168 164 } 169 165 170 void MediaPlayerPrivateAVFoundation::resumeLoad()171 {172 LOG(Media, "MediaPlayerPrivateAVFoundation::resumeLoad(%p)", this);173 174 ASSERT(m_delayingLoad);175 m_delayingLoad = false;176 177 if (m_assetURL.length())178 prepareToPlay();179 }180 181 166 void MediaPlayerPrivateAVFoundation::load(const String& url) 182 167 { … … 192 177 } 193 178 194 m_videoFrameHasDrawn = false;195 179 m_assetURL = url; 196 180 … … 199 183 return; 200 184 201 if (m_preload == MediaPlayer::None) { 202 LOG(Media, "MediaPlayerPrivateAVFoundation::load(%p) - preload==none so returning", this); 203 m_delayingLoad = true; 204 return; 205 } 206 207 prepareToPlay(); 185 setPreload(m_preload); 208 186 } 209 187 … … 233 211 LOG(Media, "MediaPlayerPrivateAVFoundation::prepareToPlay(%p)", this); 234 212 235 m_preload = MediaPlayer::Auto; 236 if (m_havePreparedToPlay) 237 return; 238 m_havePreparedToPlay = true; 239 240 m_delayingLoad = false; 241 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 242 Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : 0; 243 ApplicationCacheHost* cacheHost = frame ? frame->loader()->documentLoader()->applicationCacheHost() : 0; 244 ApplicationCacheResource* resource = 0; 245 if (cacheHost && cacheHost->shouldLoadResourceFromApplicationCache(ResourceRequest(m_assetURL), resource) && resource) 246 createAVPlayerForCacheResource(resource); 247 else 248 #endif 249 createAVPlayerForURL(m_assetURL); 250 checkPlayability(); 213 setPreload(MediaPlayer::Auto); 251 214 } 252 215 … … 270 233 } 271 234 272 void MediaPlayerPrivateAVFoundation::paint(GraphicsContext*, const IntRect&)273 {274 // This is the base class, only need to remember that a frame has been drawn.275 m_videoFrameHasDrawn = true;276 }277 278 235 float MediaPlayerPrivateAVFoundation::duration() const 279 236 { 280 if (!metaDataAvailable()) 237 if (m_cachedDuration != invalidTime()) 238 return m_cachedDuration; 239 240 float duration = platformDuration(); 241 if (!duration || duration == invalidTime()) 281 242 return 0; 282 243 283 if (m_cachedDuration == invalidTime) { 284 m_cachedDuration = platformDuration(); 285 LOG(Media, "MediaPlayerPrivateAVFMac::duration(%p) - caching %f", this, m_cachedDuration); 286 } 287 244 m_cachedDuration = duration; 245 LOG(Media, "MediaPlayerPrivateAVFoundation::duration(%p) - caching %f", this, m_cachedDuration); 288 246 return m_cachedDuration; 289 247 } … … 327 285 return false; 328 286 329 return m_seekTo != invalidTime ;287 return m_seekTo != invalidTime(); 330 288 } 331 289 … … 347 305 void MediaPlayerPrivateAVFoundation::setNaturalSize(IntSize size) 348 306 { 307 LOG(Media, "MediaPlayerPrivateAVFoundation:sizeChanged(%p) - size = %d x %d", this, size.width(), size.height()); 308 349 309 IntSize oldSize = m_cachedNaturalSize; 350 310 m_cachedNaturalSize = size; … … 433 393 else { 434 394 // -loadValuesAsynchronouslyForKeys:completionHandler: has invoked its handler; test status of keys and determine state. 435 A VAssetStatus avAssetStatus =assetStatus();395 AssetStatus assetStatus = this->assetStatus(); 436 396 ItemStatus itemStatus = playerItemStatus(); 437 397 438 m_assetIsPlayable = (a vAssetStatus == MediaPlayerAVAssetStatusPlayable);439 if (m_readyState < MediaPlayer::HaveMetadata && a vAssetStatus > MediaPlayerAVAssetStatusLoading) {398 m_assetIsPlayable = (assetStatus == MediaPlayerAVAssetStatusPlayable); 399 if (m_readyState < MediaPlayer::HaveMetadata && assetStatus > MediaPlayerAVAssetStatusLoading) { 440 400 if (m_assetIsPlayable) { 441 if (itemStatus == MediaPlayerAVPlayerItemStatusUnknown) { 442 if (avAssetStatus == MediaPlayerAVAssetStatusFailed || m_preload > MediaPlayer::MetaData) { 443 // We may have a playable asset that doesn't support inspection prior to playback; go ahead 444 // and create the AVPlayerItem now. When the AVPlayerItem becomes ready to play, we will 445 // have access to its metadata. Or we may have been asked to become ready to play immediately. 401 if (assetStatus >= MediaPlayerAVAssetStatusLoaded) 402 m_readyState = MediaPlayer::HaveMetadata; 403 if (itemStatus <= MediaPlayerAVPlayerItemStatusUnknown) { 404 if (assetStatus == MediaPlayerAVAssetStatusFailed || m_preload > MediaPlayer::MetaData || isLiveStream()) { 405 // The asset is playable but doesn't support inspection prior to playback (eg. streaming files), 406 // or we are supposed to prepare for playback immediately, so create the player item now. 446 407 m_networkState = MediaPlayer::Loading; 447 408 prepareToPlay(); … … 449 410 m_networkState = MediaPlayer::Idle; 450 411 } 451 if (avAssetStatus == MediaPlayerAVAssetStatusLoaded)452 m_readyState = MediaPlayer::HaveMetadata;453 412 } else { 454 413 // FIX ME: fetch the error associated with the @"playable" key to distinguish between format … … 458 417 } 459 418 460 if (a vAssetStatus >= MediaPlayerAVAssetStatusLoaded && itemStatus > MediaPlayerAVPlayerItemStatusUnknown) {419 if (assetStatus >= MediaPlayerAVAssetStatusLoaded && itemStatus > MediaPlayerAVPlayerItemStatusUnknown) { 461 420 if (seeking()) 462 421 m_readyState = m_readyState >= MediaPlayer::HaveMetadata ? MediaPlayer::HaveMetadata : MediaPlayer::HaveNothing; 463 422 else { 464 float maxLoaded = maxTimeLoaded();465 423 switch (itemStatus) { 424 case MediaPlayerAVPlayerItemStatusDoesNotExist: 466 425 case MediaPlayerAVPlayerItemStatusUnknown: 426 case MediaPlayerAVPlayerItemStatusFailed: 467 427 break; 468 case MediaPlayerAVPlayerItemStatusFailed: 469 m_networkState = MediaPlayer::DecodeError; 470 break; 428 471 429 case MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp: 472 430 m_readyState = MediaPlayer::HaveEnoughData; 473 431 break; 432 433 case MediaPlayerAVPlayerItemStatusPlaybackBufferFull: 474 434 case MediaPlayerAVPlayerItemStatusReadyToPlay: 475 case MediaPlayerAVPlayerItemStatusPlaybackBufferFull:476 435 // If the readyState is already HaveEnoughData, don't go lower because of this state change. 477 436 if (m_readyState == MediaPlayer::HaveEnoughData) … … 479 438 480 439 case MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty: 481 if (max Loaded> currentTime())440 if (maxTimeLoaded() > currentTime()) 482 441 m_readyState = MediaPlayer::HaveFutureData; 483 442 else … … 486 445 } 487 446 488 if (itemStatus >= MediaPlayerAVPlayerItemStatusReadyToPlay) 489 m_networkState = (maxLoaded == duration()) ? MediaPlayer::Loaded : MediaPlayer::Loading; 447 if (itemStatus == MediaPlayerAVPlayerItemStatusPlaybackBufferFull) 448 m_networkState = MediaPlayer::Idle; 449 else if (itemStatus == MediaPlayerAVPlayerItemStatusFailed) 450 m_networkState = MediaPlayer::DecodeError; 451 else if (itemStatus != MediaPlayerAVPlayerItemStatusPlaybackBufferFull && itemStatus >= MediaPlayerAVPlayerItemStatusReadyToPlay) 452 m_networkState = (maxTimeLoaded() == duration()) ? MediaPlayer::Loaded : MediaPlayer::Loading; 490 453 } 491 454 } … … 496 459 497 460 if (!m_haveReportedFirstVideoFrame && m_cachedHasVideo && hasAvailableVideoFrame()) { 461 if (m_readyState < MediaPlayer::HaveCurrentData) 462 m_readyState = MediaPlayer::HaveCurrentData; 498 463 m_haveReportedFirstVideoFrame = true; 499 464 m_player->firstVideoFrameAvailable(); … … 531 496 } 532 497 533 bool MediaPlayerPrivateAVFoundation::hasAvailableVideoFrame() const534 {535 if (currentRenderingMode() == MediaRenderingToLayer)536 return videoLayerIsReadyToDisplay();537 538 // When using the software renderer we hope someone will signal that a frame is available so we might as well539 // wait until we know that a frame has been drawn.540 return m_videoFrameHasDrawn;541 }542 543 498 void MediaPlayerPrivateAVFoundation::acceleratedRenderingStateChanged() 544 499 { … … 550 505 { 551 506 m_loadingMetadata = false; 507 tracksChanged(); 552 508 updateStates(); 553 509 } … … 576 532 float dur = duration(); 577 533 if (dur != m_reportedDuration) { 578 if (m_reportedDuration != invalidTime )534 if (m_reportedDuration != invalidTime()) 579 535 m_player->durationChanged(); 580 536 m_reportedDuration = dur; … … 591 547 LOG(Media, "MediaPlayerPrivateAVFoundation::timeChanged(%p) - time = %f", this, time); 592 548 593 if (m_seekTo == invalidTime )549 if (m_seekTo == invalidTime()) 594 550 return; 595 551 … … 601 557 float currentRate = rate(); 602 558 if ((currentRate > 0 && time >= m_seekTo) || (currentRate < 0 && time <= m_seekTo) || (abs(m_seekTo - time) <= smallSeekDelta)) { 603 m_seekTo = invalidTime ;559 m_seekTo = invalidTime(); 604 560 updateStates(); 605 561 m_player->timeChanged(); … … 612 568 613 569 if (finished) 614 m_seekTo = invalidTime ;570 m_seekTo = invalidTime(); 615 571 } 616 572 … … 629 585 void MediaPlayerPrivateAVFoundation::repaint() 630 586 { 631 m_videoFrameHasDrawn = true;632 587 m_player->repaint(); 633 588 } … … 647 602 { 648 603 m_preload = preload; 649 if (m_delayingLoad && m_preload != MediaPlayer::None) 650 resumeLoad(); 604 if (!m_assetURL.length()) 605 return; 606 607 setDelayCallbacks(true); 608 609 if (m_preload >= MediaPlayer::MetaData && assetStatus() == MediaPlayerAVAssetStatusDoesNotExist) { 610 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 611 Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : 0; 612 ApplicationCacheHost* cacheHost = frame ? frame->loader()->documentLoader()->applicationCacheHost() : 0; 613 ApplicationCacheResource* resource; 614 if (cacheHost && cacheHost->shouldLoadResourceFromApplicationCache(ResourceRequest(m_assetURL), resource) && resource) { 615 // AVFoundation can't open arbitrary data pointers, so if this ApplicationCacheResource doesn't 616 // have a valid local path, just open the resource's original URL. 617 if (resource->path().isEmpty()) 618 createAVAssetForURL(resource->url()); 619 else 620 createAVAssetForCacheResource(resource); 621 } else 622 #endif 623 createAVAssetForURL(m_assetURL); 624 625 createAVPlayer(); 626 627 checkPlayability(); 628 } 629 630 // Don't force creation of the player item unless we already know that the asset is playable. If we aren't 631 // there yet, or if we already know it is not playable, creating it now won't help. 632 if (m_preload == MediaPlayer::Auto && m_assetIsPlayable) 633 createAVPlayerItem(); 634 635 setDelayCallbacks(false); 651 636 } 652 637 … … 743 728 case Notification::ItemTracksChanged: 744 729 tracksChanged(); 730 updateStates(); 745 731 break; 746 732 case Notification::ItemStatusChanged: … … 757 743 case Notification::ItemPresentationSizeChanged: 758 744 sizeChanged(); 745 updateStates(); 759 746 break; 760 747 case Notification::ItemIsPlaybackLikelyToKeepUpChanged: -
trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h
r85518 r85865 143 143 virtual unsigned bytesLoaded() const; 144 144 virtual void setSize(const IntSize&); 145 virtual void paint(GraphicsContext*, const IntRect&) ;145 virtual void paint(GraphicsContext*, const IntRect&) = 0; 146 146 virtual void paintCurrentFrameInContext(GraphicsContext*, const IntRect&) = 0; 147 147 virtual void setPreload(MediaPlayer::Preload); 148 virtual bool hasAvailableVideoFrame() const;149 148 #if USE(ACCELERATED_COMPOSITING) 150 149 virtual PlatformLayer* platformLayer() const { return 0; } … … 160 159 161 160 // Required interfaces for concrete derived classes. 162 virtual void createAVPlayerForURL(const String& url) = 0; 161 virtual void createAVAssetForURL(const String&) = 0; 162 virtual void createAVPlayer() = 0; 163 virtual void createAVPlayerItem() = 0; 163 164 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 164 virtual void createAV PlayerForCacheResource(ApplicationCacheResource*) = 0;165 virtual void createAVAssetForCacheResource(ApplicationCacheResource*) = 0; 165 166 #endif 166 167 167 168 enum ItemStatus { 169 MediaPlayerAVPlayerItemStatusDoesNotExist, 168 170 MediaPlayerAVPlayerItemStatusUnknown, 169 171 MediaPlayerAVPlayerItemStatusFailed, … … 175 177 virtual ItemStatus playerItemStatus() const = 0; 176 178 177 enum AVAssetStatus { 179 enum AssetStatus { 180 MediaPlayerAVAssetStatusDoesNotExist, 178 181 MediaPlayerAVAssetStatusUnknown, 179 182 MediaPlayerAVAssetStatusLoading, … … 183 186 MediaPlayerAVAssetStatusPlayable, 184 187 }; 185 virtual A VAssetStatus assetStatus() const = 0;188 virtual AssetStatus assetStatus() const = 0; 186 189 187 190 virtual void platformSetVisible(bool) = 0; … … 207 210 virtual void createVideoLayer() = 0; 208 211 virtual void destroyVideoLayer() = 0; 209 virtual bool videoLayerIsReadyToDisplay() const = 0; 212 213 virtual bool hasAvailableVideoFrame() const = 0; 210 214 211 215 virtual bool hasContextRenderer() const = 0; … … 213 217 214 218 protected: 215 void resumeLoad();216 219 void updateStates(); 217 220 … … 237 240 238 241 static void mainThreadCallback(void*); 242 243 float invalidTime() const { return -1.0f; } 239 244 240 245 private: 241 242 246 MediaPlayer* m_player; 243 247 244 248 Vector<Notification> m_queuedNotifications; 245 249 Mutex m_queueMutex; 246 bool m_mainThreadCallPending;247 250 248 251 mutable RefPtr<TimeRanges> m_cachedLoadedTimeRanges; … … 264 267 float m_requestedRate; 265 268 int m_delayCallbacks; 266 bool m_ havePreparedToPlay;269 bool m_mainThreadCallPending; 267 270 bool m_assetIsPlayable; 268 271 bool m_visible; 269 bool m_videoFrameHasDrawn;270 272 bool m_loadingMetadata; 271 bool m_delayingLoad;272 273 bool m_isAllowedToRender; 273 274 bool m_cachedHasAudio; -
trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h
r85615 r85865 89 89 90 90 virtual void createAVPlayer(); 91 virtual void createAVPlayerForURL(const String& url); 91 virtual void createAVPlayerItem(); 92 virtual void createAVAssetForURL(const String& url); 92 93 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 93 virtual void createAV PlayerForCacheResource(ApplicationCacheResource*);94 virtual void createAVAssetForCacheResource(ApplicationCacheResource*); 94 95 #endif 95 96 virtual MediaPlayerPrivateAVFoundation::ItemStatus playerItemStatus() const; 96 virtual MediaPlayerPrivateAVFoundation::A VAssetStatus assetStatus() const;97 virtual MediaPlayerPrivateAVFoundation::AssetStatus assetStatus() const; 97 98 98 99 virtual void checkPlayability(); … … 108 109 virtual void sizeChanged(); 109 110 111 virtual bool hasAvailableVideoFrame() const; 112 110 113 virtual void createContextVideoRenderer(); 111 114 virtual void destroyContextVideoRenderer(); … … 113 116 virtual void createVideoLayer(); 114 117 virtual void destroyVideoLayer(); 115 virtual bool videoLayerIsReadyToDisplay() const;116 118 117 119 virtual bool hasContextRenderer() const; … … 128 130 RetainPtr<AVAssetImageGenerator> m_imageGenerator; 129 131 id m_timeObserver; 132 bool m_videoFrameHasDrawn; 133 bool m_haveCheckedPlayability; 130 134 }; 131 135 -
trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm
r85518 r85865 139 139 , m_objcObserver(AdoptNS, [[WebCoreAVFMovieObserver alloc] initWithCallback:this]) 140 140 , m_timeObserver(0) 141 , m_videoFrameHasDrawn(false) 142 , m_haveCheckedPlayability(false) 141 143 { 142 144 } … … 235 237 } 236 238 237 bool MediaPlayerPrivateAVFoundationObjC::videoLayerIsReadyToDisplay() const 238 { 239 return (m_videoLayer && [m_videoLayer.get() isReadyForDisplay]); 240 } 241 242 void MediaPlayerPrivateAVFoundationObjC::createAVPlayerForURL(const String& url) 243 { 239 bool MediaPlayerPrivateAVFoundationObjC::hasAvailableVideoFrame() const 240 { 241 return (m_videoFrameHasDrawn || (m_videoLayer && [m_videoLayer.get() isReadyForDisplay])); 242 } 243 244 void MediaPlayerPrivateAVFoundationObjC::createAVAssetForURL(const String& url) 245 { 246 if (m_avAsset) 247 return; 248 249 LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createAVAssetForURL(%p)", this); 250 244 251 setDelayCallbacks(true); 245 252 246 if (!m_avAsset) { 247 NSURL *cocoaURL = KURL(ParsedURLString, url); 248 m_avAsset.adoptNS([[AVURLAsset alloc] initWithURL:cocoaURL options:nil]); 249 } 250 251 createAVPlayer(); 253 NSURL *cocoaURL = KURL(ParsedURLString, url); 254 m_avAsset.adoptNS([[AVURLAsset alloc] initWithURL:cocoaURL options:nil]); 255 m_haveCheckedPlayability = false; 256 257 setDelayCallbacks(false); 252 258 } 253 259 254 260 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 255 void MediaPlayerPrivateAVFoundationObjC::createAVPlayerForCacheResource(ApplicationCacheResource* resource) 256 { 257 // AVFoundation can't open arbitrary data pointers, so if this ApplicationCacheResource doesn't 258 // have a valid local path, just open the resource's original URL. 259 if (resource->path().isEmpty()) { 260 createAVPlayerForURL(resource->url()); 261 return; 262 } 261 void MediaPlayerPrivateAVFoundationObjC::createAVAssetForCacheResource(ApplicationCacheResource* resource) 262 { 263 if (m_avAsset) 264 return; 265 266 LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createAVAssetForCacheResource(%p)", this); 267 268 // AVFoundation can't open arbitrary data pointers. 269 ASSERT(!resource->path().isEmpty()); 263 270 264 271 setDelayCallbacks(true); 265 272 266 if (!m_avAsset) { 267 NSURL* localURL = [NSURL fileURLWithPath:resource->path()]; 268 m_avAsset.adoptNS([[AVURLAsset alloc] initWithURL:localURL options:nil]); 269 } 270 271 createAVPlayer(); 273 NSURL* localURL = [NSURL fileURLWithPath:resource->path()]; 274 m_avAsset.adoptNS([[AVURLAsset alloc] initWithURL:localURL options:nil]); 275 m_haveCheckedPlayability = false; 276 277 setDelayCallbacks(false); 272 278 } 273 279 #endif … … 275 281 void MediaPlayerPrivateAVFoundationObjC::createAVPlayer() 276 282 { 277 if (!m_avPlayer) { 278 m_avPlayer.adoptNS([[AVPlayer alloc] init]); 279 280 [m_avPlayer.get() addObserver:m_objcObserver.get() forKeyPath:@"rate" options:nil context:(void *)MediaPlayerAVFoundationObservationContextPlayer]; 281 282 // Add a time observer, ask to be called infrequently because we don't really want periodic callbacks but 283 // our observer will also be called whenever a seek happens. 284 const double veryLongInterval = 60*60*60*24*30; 285 WebCoreAVFMovieObserver *observer = m_objcObserver.get(); 286 m_timeObserver = [m_avPlayer.get() addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(veryLongInterval, 10) queue:nil usingBlock:^(CMTime time){ 287 [observer timeChanged:CMTimeGetSeconds(time)]; 288 }]; 289 } 290 291 if (!m_avPlayerItem) { 292 // Create the player item so we can media data. 293 m_avPlayerItem.adoptNS([[AVPlayerItem alloc] initWithAsset:m_avAsset.get()]); 294 295 [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()selector:@selector(didEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:m_avPlayerItem.get()]; 296 297 for (NSString *keyName in itemKVOProperties()) 298 [m_avPlayerItem.get() addObserver:m_objcObserver.get() forKeyPath:keyName options:nil context:(void *)MediaPlayerAVFoundationObservationContextPlayerItem]; 299 300 [m_avPlayer.get() replaceCurrentItemWithPlayerItem:m_avPlayerItem.get()]; 301 } 283 if (m_avPlayer) 284 return; 285 286 LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createAVPlayer(%p)", this); 287 288 setDelayCallbacks(true); 289 290 m_avPlayer.adoptNS([[AVPlayer alloc] init]); 291 [m_avPlayer.get() addObserver:m_objcObserver.get() forKeyPath:@"rate" options:nil context:(void *)MediaPlayerAVFoundationObservationContextPlayer]; 292 293 // Add a time observer, ask to be called infrequently because we don't really want periodic callbacks but 294 // our observer will also be called whenever a seek happens. 295 const double veryLongInterval = 60 * 60 * 24 * 30; 296 WebCoreAVFMovieObserver *observer = m_objcObserver.get(); 297 m_timeObserver = [m_avPlayer.get() addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(veryLongInterval, 10) queue:nil usingBlock:^(CMTime time){ 298 [observer timeChanged:CMTimeGetSeconds(time)]; 299 }]; 302 300 303 301 setDelayCallbacks(false); 304 302 } 305 303 304 void MediaPlayerPrivateAVFoundationObjC::createAVPlayerItem() 305 { 306 if (m_avPlayerItem) 307 return; 308 309 LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createAVPlayerItem(%p)", this); 310 311 ASSERT(m_avPlayer); 312 313 setDelayCallbacks(true); 314 315 // Create the player item so we can load media data. 316 m_avPlayerItem.adoptNS([[AVPlayerItem alloc] initWithAsset:m_avAsset.get()]); 317 318 [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get() selector:@selector(didEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:m_avPlayerItem.get()]; 319 320 for (NSString *keyName in itemKVOProperties()) 321 [m_avPlayerItem.get() addObserver:m_objcObserver.get() forKeyPath:keyName options:nil context:(void *)MediaPlayerAVFoundationObservationContextPlayerItem]; 322 323 [m_avPlayer.get() replaceCurrentItemWithPlayerItem:m_avPlayerItem.get()]; 324 325 setDelayCallbacks(false); 326 } 327 306 328 void MediaPlayerPrivateAVFoundationObjC::checkPlayability() 307 329 { 330 if (m_haveCheckedPlayability) 331 return; 332 m_haveCheckedPlayability = true; 333 308 334 LOG(Media, "MediaPlayerPrivateAVFoundationObjC::checkPlayability(%p)", this); 309 335 … … 315 341 void MediaPlayerPrivateAVFoundationObjC::beginLoadingMetadata() 316 342 { 317 LOG(Media, "MediaPlayerPrivateAVFoundationObjC:: playabilityKnown(%p) - requesting metadata loading", this);343 LOG(Media, "MediaPlayerPrivateAVFoundationObjC::beginLoadingMetadata(%p) - requesting metadata loading", this); 318 344 [m_avAsset.get() loadValuesAsynchronouslyForKeys:[assetMetadataKeyNames() retain] completionHandler:^{ 319 345 [m_objcObserver.get() metadataLoaded]; … … 324 350 { 325 351 if (!m_avPlayerItem) 326 return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatus Unknown;352 return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusDoesNotExist; 327 353 328 354 AVPlayerItemStatus status = [m_avPlayerItem.get() status]; … … 333 359 if ([m_avPlayerItem.get() isPlaybackLikelyToKeepUp]) 334 360 return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp; 335 if ( buffered()->contain(duration()))361 if ([m_avPlayerItem.get() isPlaybackBufferFull]) 336 362 return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferFull; 337 if ( buffered()->contain(currentTime()))363 if ([m_avPlayerItem.get() isPlaybackBufferEmpty]) 338 364 return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty; 339 365 … … 386 412 float MediaPlayerPrivateAVFoundationObjC::platformDuration() const 387 413 { 388 if (!m etaDataAvailable() || !m_avPlayerItem)389 return 0;414 if (!m_avAsset) 415 return invalidTime(); 390 416 391 float duration; 392 CMTime cmDuration = [m_avPlayerItem.get() duration]; 417 CMTime cmDuration; 418 419 // Check the AVItem if we have one, some assets never report duration. 420 if (m_avPlayerItem) 421 cmDuration = [m_avPlayerItem.get() duration]; 422 else 423 cmDuration= [m_avAsset.get() duration]; 424 393 425 if (CMTIME_IS_NUMERIC(cmDuration)) 394 duration = narrowPrecisionToFloat(CMTimeGetSeconds(cmDuration)); 395 else if (CMTIME_IS_INDEFINITE(cmDuration)) 396 duration = numeric_limits<float>::infinity(); 397 else { 398 LOG(Media, "MediaPlayerPrivateAVFoundationObjC::duration(%p) - invalid duration, returning 0", this); 399 return 0; 400 } 401 402 return duration; 426 return narrowPrecisionToFloat(CMTimeGetSeconds(cmDuration)); 427 428 if (CMTIME_IS_INDEFINITE(cmDuration)) 429 return numeric_limits<float>::infinity(); 430 431 LOG(Media, "MediaPlayerPrivateAVFoundationObjC::duration(%p) - invalid duration, returning %.0f", this, invalidTime()); 432 return invalidTime(); 403 433 } 404 434 … … 536 566 } 537 567 538 MediaPlayerPrivateAVFoundation::A VAssetStatus MediaPlayerPrivateAVFoundationObjC::assetStatus() const568 MediaPlayerPrivateAVFoundation::AssetStatus MediaPlayerPrivateAVFoundationObjC::assetStatus() const 539 569 { 540 570 if (!m_avAsset) 541 return MediaPlayerAVAssetStatus Unknown;571 return MediaPlayerAVAssetStatusDoesNotExist; 542 572 543 573 for (NSString *keyName in assetMetadataKeyNames()) { … … 548 578 if (keyStatus == AVKeyValueStatusFailed) 549 579 return MediaPlayerAVAssetStatusFailed; // At least one key could not be loaded. 580 550 581 if (keyStatus == AVKeyValueStatusCancelled) 551 582 return MediaPlayerAVAssetStatusCancelled; // Loading of at least one key was cancelled. … … 588 619 setDelayCallbacks(false); 589 620 590 MediaPlayerPrivateAVFoundation::paint(context, rect);621 m_videoFrameHasDrawn = true; 591 622 } 592 623 … … 663 694 void MediaPlayerPrivateAVFoundationObjC::tracksChanged() 664 695 { 696 if (!m_avAsset) 697 return; 698 665 699 // This is called whenever the tracks collection changes so cache hasVideo and hasAudio since we are 666 700 // asked about those fairly fequently. 667 bool hasVideo = false; 668 bool hasAudio = false; 669 bool hasCaptions = false; 670 NSArray *tracks = [m_avPlayerItem.get() tracks]; 671 for (AVPlayerItemTrack *track in tracks) { 672 if ([track isEnabled]) { 673 AVAssetTrack *assetTrack = [track assetTrack]; 674 if ([[assetTrack mediaType] isEqualToString:AVMediaTypeVideo]) 675 hasVideo = true; 676 else if ([[assetTrack mediaType] isEqualToString:AVMediaTypeAudio]) 677 hasAudio = true; 678 else if ([[assetTrack mediaType] isEqualToString:AVMediaTypeClosedCaption]) 679 hasCaptions = true; 701 if (!m_avPlayerItem) { 702 // We don't have a player item yet, so check with the asset because some assets support inspection 703 // prior to becoming ready to play. 704 setHasVideo([[m_avAsset.get() tracksWithMediaCharacteristic:AVMediaCharacteristicVisual] count]); 705 setHasAudio([[m_avAsset.get() tracksWithMediaCharacteristic:AVMediaCharacteristicAudible] count]); 706 setHasClosedCaptions([[m_avAsset.get() tracksWithMediaType:AVMediaTypeClosedCaption] count]); 707 } else { 708 bool hasVideo = false; 709 bool hasAudio = false; 710 bool hasCaptions = false; 711 NSArray *tracks = [m_avPlayerItem.get() tracks]; 712 for (AVPlayerItemTrack *track in tracks) { 713 if ([track isEnabled]) { 714 AVAssetTrack *assetTrack = [track assetTrack]; 715 if ([[assetTrack mediaType] isEqualToString:AVMediaTypeVideo]) 716 hasVideo = true; 717 else if ([[assetTrack mediaType] isEqualToString:AVMediaTypeAudio]) 718 hasAudio = true; 719 else if ([[assetTrack mediaType] isEqualToString:AVMediaTypeClosedCaption]) 720 hasCaptions = true; 721 } 680 722 } 681 } 682 setHasVideo(hasVideo); 683 setHasAudio(hasAudio); 684 setHasClosedCaptions(hasCaptions); 723 setHasVideo(hasVideo); 724 setHasAudio(hasAudio); 725 setHasClosedCaptions(hasCaptions); 726 } 727 728 LOG(Media, "WebCoreAVFMovieObserver:tracksChanged(%p) - hasVideo = %s, hasAudio = %s, hasCaptions = %s", 729 this, boolString(hasVideo()), boolString(hasAudio()), boolString(hasClosedCaptions())); 685 730 686 731 sizeChanged(); … … 689 734 void MediaPlayerPrivateAVFoundationObjC::sizeChanged() 690 735 { 736 if (!m_avAsset) 737 return; 738 691 739 NSArray *tracks = [m_avAsset.get() tracks]; 692 740 693 741 // Some assets don't report track properties until they are completely ready to play, but we 694 742 // want to report a size as early as possible so use presentationSize when an asset has no tracks. 695 if ( ![tracks count]) {743 if (m_avPlayerItem && ![tracks count]) { 696 744 setNaturalSize(IntSize([m_avPlayerItem.get() presentationSize])); 697 745 return;
Note: See TracChangeset
for help on using the changeset viewer.