Changeset 85483 in webkit
- Timestamp:
- May 2, 2011 10:21:34 AM (13 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r85480 r85483 1 2011-05-02 Eric Carlson <eric.carlson@apple.com> 2 3 Reviewed by Brady Eidson. 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/7508322> 8 9 Tested manually with manual-tests/media-elements/video-preload.html. 10 11 * html/HTMLMediaElement.cpp: 12 (WebCore::HTMLMediaElement::HTMLMediaElement): Initialize m_havePreparedToPlay. 13 (WebCore::HTMLMediaElement::prepareForLoad): Ditto. 14 (WebCore::HTMLMediaElement::prepareToPlay): New, tell player to prepare to play. 15 (WebCore::HTMLMediaElement::seek): Call prepareToPlay when preload is less than 'metadata' 16 because we need to have media data loaded to seek. 17 (WebCore::HTMLMediaElement::updatePlayState): Call prepareToPlay. 18 * html/HTMLMediaElement.h: 19 20 * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp: 21 (WebCore::MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation): Remove 22 m_videoFrameHasDrawn and m_delayingLoad as they are no longer used. 23 (WebCore::MediaPlayerPrivateAVFoundation::resumeLoad): Removed. 24 (WebCore::MediaPlayerPrivateAVFoundation::load): Don't initialize m_videoFrameHasDrawn. 25 Move all preload logic to setPreload, call it from here. 26 (WebCore::MediaPlayerPrivateAVFoundation::prepareToPlay): Move all preload logic to 27 setPreload, call it. 28 (WebCore::MediaPlayerPrivateAVFoundation::duration): Don't cache duration = 0, it is 29 unlikely to be correct and isn't worth caching. 30 (WebCore::MediaPlayerPrivateAVFoundation::updateStates): Update for name change AVAssetStatus 31 to AssetStatus. Create the AVPlayer once we know an asset is playable but preload is 32 'metadata'. Set networkState to 'idle' when the playback buffer is full because that is 33 a signal that AVFoundation won't do any more IO. Set readyState to 'HAVE_CURRENT_DATA' 34 when the first frame is available. 35 (WebCore::MediaPlayerPrivateAVFoundation::metadataLoaded): Call tracksChanged so we cache 36 width, height, hasVideo, etc. 37 (WebCore::MediaPlayerPrivateAVFoundation::repaint): Don't set m_videoFrameHasDrawn, it is done 38 in derived classes. 39 (WebCore::MediaPlayerPrivateAVFoundation::setPreload): Centralize all logic about when to create 40 AVAsset and AVPlayerItem here. 41 * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h: 42 43 * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h: 44 * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm: 45 (WebCore::MediaPlayerPrivateAVFoundationObjC::MediaPlayerPrivateAVFoundationObjC): Initialize 46 m_videoFrameHasDrawn. 47 (WebCore::MediaPlayerPrivateAVFoundationObjC::hasAvailableVideoFrame): New, renamed from 48 videoLayerIsReadyToDisplay. Return true if we have a layer with frames available or 49 if we have painted a frame to the context. 50 (WebCore::MediaPlayerPrivateAVFoundationObjC::createAVAssetForURL): New, create the AVAsset 51 if necessary. 52 (WebCore::MediaPlayerPrivateAVFoundationObjC::createAVAssetForCacheResource): Ditto. 53 (WebCore::MediaPlayerPrivateAVFoundationObjC::createAVPlayer): Restructure logic. 54 (WebCore::MediaPlayerPrivateAVFoundationObjC::createAVPlayerItem): New, create AVPlayerItem. 55 (WebCore::MediaPlayerPrivateAVFoundationObjC::beginLoadingMetadata): Correct logging. 56 (WebCore::MediaPlayerPrivateAVFoundationObjC::playerItemStatus): Return "buffer full" when 57 the buffer is full. 58 (WebCore::MediaPlayerPrivateAVFoundationObjC::platformDuration): Get the duration from the 59 AVAsset when we haven't allocated the AVPlayerItem yet so that we can return duration 60 when we only have metadata. 61 (WebCore::MediaPlayerPrivateAVFoundationObjC::assetStatus): Update for name change. 62 (WebCore::MediaPlayerPrivateAVFoundationObjC::paint): Set m_videoFrameHasDrawn. 63 (WebCore::MediaPlayerPrivateAVFoundationObjC::tracksChanged): Get attributes from AVAsset 64 when when we haven't allocated the AVPlayerItem yet so that we can report attributes 65 when we only have metadata. 66 (WebCore::MediaPlayerPrivateAVFoundationObjC::sizeChanged): Guard against being called before 67 we have allocated the AVPlayerItem. 68 1 69 2011-05-02 Philippe Normand <pnormand@igalia.com> 2 70 -
trunk/Source/WebCore/html/HTMLMediaElement.cpp
r84816 r85483 171 171 , m_loadInitiatedByUserGesture(false) 172 172 , m_completelyLoaded(false) 173 , m_havePreparedToPlay(false) 173 174 { 174 175 LOG(Media, "HTMLMediaElement::HTMLMediaElement"); … … 517 518 m_haveFiredLoadedData = false; 518 519 m_completelyLoaded = false; 520 m_havePreparedToPlay = false; 519 521 m_displayMode = Unknown; 520 522 … … 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
r84222 r85483 287 287 void cancelPendingEventsAndCallbacks(); 288 288 void waitForSourceChange(); 289 void prepareToPlay(); 289 290 290 291 enum InvalidSourceAction { DoNothing, Complain }; … … 418 419 bool m_loadInitiatedByUserGesture : 1; 419 420 bool m_completelyLoaded : 1; 421 bool m_havePreparedToPlay : 1; 420 422 }; 421 423 -
trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp
r84988 r85483 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 { 237 if (m_cachedDuration != invalidTime()) 238 return m_cachedDuration; 239 280 240 if (!metaDataAvailable()) 281 241 return 0; 282 242 283 if (m_cachedDuration == invalidTime) { 284 m_cachedDuration = platformDuration(); 285 LOG(Media, "MediaPlayerPrivateAVFMac::duration(%p) - caching %f", this, m_cachedDuration); 286 } 287 243 float duration = platformDuration(); 244 if (!duration || duration == invalidTime()) 245 return 0; 246 247 m_cachedDuration = duration; 248 LOG(Media, "MediaPlayerPrivateAVFMac::duration(%p) - caching %f", this, m_cachedDuration); 288 249 return m_cachedDuration; 289 250 } … … 327 288 return false; 328 289 329 return m_seekTo != invalidTime ;290 return m_seekTo != invalidTime(); 330 291 } 331 292 … … 433 394 else { 434 395 // -loadValuesAsynchronouslyForKeys:completionHandler: has invoked its handler; test status of keys and determine state. 435 A VAssetStatus avAssetStatus = assetStatus();396 AssetStatus avAssetStatus = assetStatus(); 436 397 ItemStatus itemStatus = playerItemStatus(); 437 398 … … 439 400 if (m_readyState < MediaPlayer::HaveMetadata && avAssetStatus > MediaPlayerAVAssetStatusLoading) { 440 401 if (m_assetIsPlayable) { 441 if (itemStatus == MediaPlayerAVPlayerItemStatusUnknown) {402 if (itemStatus <= MediaPlayerAVPlayerItemStatusUnknown) { 442 403 if (avAssetStatus == MediaPlayerAVAssetStatusFailed || m_preload > MediaPlayer::MetaData) { 443 404 // We may have a playable asset that doesn't support inspection prior to playback; go ahead … … 446 407 m_networkState = MediaPlayer::Loading; 447 408 prepareToPlay(); 448 } else 409 } else { 410 // The asset is playable, but we don't want to load media data yet so don't allocate 411 // the player item. Even though we don't want to play yet, allocate a player so 412 // we can create a layer as soon as possible. 413 createAVPlayer(); 449 414 m_networkState = MediaPlayer::Idle; 415 } 450 416 } 451 if (avAssetStatus == MediaPlayerAVAssetStatusLoaded) 452 m_readyState = MediaPlayer::HaveMetadata; 417 m_readyState = MediaPlayer::HaveMetadata; 453 418 } else { 454 419 // FIX ME: fetch the error associated with the @"playable" key to distinguish between format … … 464 429 float maxLoaded = maxTimeLoaded(); 465 430 switch (itemStatus) { 431 case MediaPlayerAVPlayerItemStatusDoesNotExist: 466 432 case MediaPlayerAVPlayerItemStatusUnknown: 467 433 break; … … 472 438 m_readyState = MediaPlayer::HaveEnoughData; 473 439 break; 440 441 case MediaPlayerAVPlayerItemStatusPlaybackBufferFull: 442 m_networkState = MediaPlayer::Idle; 443 474 444 case MediaPlayerAVPlayerItemStatusReadyToPlay: 475 case MediaPlayerAVPlayerItemStatusPlaybackBufferFull:476 445 // If the readyState is already HaveEnoughData, don't go lower because of this state change. 477 446 if (m_readyState == MediaPlayer::HaveEnoughData) … … 486 455 } 487 456 488 if (itemStatus >= MediaPlayerAVPlayerItemStatusReadyToPlay)457 if (itemStatus != MediaPlayerAVPlayerItemStatusPlaybackBufferFull && itemStatus >= MediaPlayerAVPlayerItemStatusReadyToPlay) 489 458 m_networkState = (maxLoaded == duration()) ? MediaPlayer::Loaded : MediaPlayer::Loading; 490 459 } … … 496 465 497 466 if (!m_haveReportedFirstVideoFrame && m_cachedHasVideo && hasAvailableVideoFrame()) { 467 if (m_readyState < MediaPlayer::HaveCurrentData) 468 m_readyState = MediaPlayer::HaveCurrentData; 498 469 m_haveReportedFirstVideoFrame = true; 499 470 m_player->firstVideoFrameAvailable(); … … 531 502 } 532 503 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 504 void MediaPlayerPrivateAVFoundation::acceleratedRenderingStateChanged() 544 505 { … … 550 511 { 551 512 m_loadingMetadata = false; 513 tracksChanged(); 552 514 updateStates(); 553 515 } … … 576 538 float dur = duration(); 577 539 if (dur != m_reportedDuration) { 578 if (m_reportedDuration != invalidTime )540 if (m_reportedDuration != invalidTime()) 579 541 m_player->durationChanged(); 580 542 m_reportedDuration = dur; … … 591 553 LOG(Media, "MediaPlayerPrivateAVFoundation::timeChanged(%p) - time = %f", this, time); 592 554 593 if (m_seekTo == invalidTime )555 if (m_seekTo == invalidTime()) 594 556 return; 595 557 … … 601 563 float currentRate = rate(); 602 564 if ((currentRate > 0 && time >= m_seekTo) || (currentRate < 0 && time <= m_seekTo) || (abs(m_seekTo - time) <= smallSeekDelta)) { 603 m_seekTo = invalidTime ;565 m_seekTo = invalidTime(); 604 566 updateStates(); 605 567 m_player->timeChanged(); … … 612 574 613 575 if (finished) 614 m_seekTo = invalidTime ;576 m_seekTo = invalidTime(); 615 577 } 616 578 … … 629 591 void MediaPlayerPrivateAVFoundation::repaint() 630 592 { 631 m_videoFrameHasDrawn = true;632 593 m_player->repaint(); 633 594 } … … 647 608 { 648 609 m_preload = preload; 649 if (m_delayingLoad && m_preload != MediaPlayer::None) 650 resumeLoad(); 610 if (!m_assetURL.length()) 611 return; 612 613 if (m_preload >= MediaPlayer::MetaData && assetStatus() == MediaPlayerAVAssetStatusDoesNotExist) { 614 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 615 Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : 0; 616 ApplicationCacheHost* cacheHost = frame ? frame->loader()->documentLoader()->applicationCacheHost() : 0; 617 ApplicationCacheResource* resource; 618 if (cacheHost && cacheHost->shouldLoadResourceFromApplicationCache(ResourceRequest(m_assetURL), resource) && resource) { 619 // AVFoundation can't open arbitrary data pointers, so if this ApplicationCacheResource doesn't 620 // have a valid local path, just open the resource's original URL. 621 if (resource->path().isEmpty()) 622 createAVAssetForURL(resource->url()); 623 else 624 createAVAssetForCacheResource(resource); 625 } else 626 #endif 627 createAVAssetForURL(m_assetURL); 628 629 checkPlayability(); 630 } 631 632 if (m_preload == MediaPlayer::Auto && playerItemStatus() == MediaPlayerAVPlayerItemStatusDoesNotExist) 633 createAVPlayerItem(); 651 634 } 652 635 -
trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h
r84988 r85483 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
r84988 r85483 87 87 88 88 virtual void createAVPlayer(); 89 virtual void createAVPlayerForURL(const String& url); 89 virtual void createAVPlayerItem(); 90 virtual void createAVAssetForURL(const String& url); 90 91 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 91 virtual void createAV PlayerForCacheResource(ApplicationCacheResource*);92 virtual void createAVAssetForCacheResource(ApplicationCacheResource*); 92 93 #endif 93 94 virtual MediaPlayerPrivateAVFoundation::ItemStatus playerItemStatus() const; 94 virtual MediaPlayerPrivateAVFoundation::A VAssetStatus assetStatus() const;95 virtual MediaPlayerPrivateAVFoundation::AssetStatus assetStatus() const; 95 96 96 97 virtual void checkPlayability(); … … 106 107 virtual void sizeChanged(); 107 108 109 virtual bool hasAvailableVideoFrame() const; 110 108 111 virtual void createContextVideoRenderer(); 109 112 virtual void destroyContextVideoRenderer(); … … 111 114 virtual void createVideoLayer(); 112 115 virtual void destroyVideoLayer(); 113 virtual bool videoLayerIsReadyToDisplay() const;114 116 115 117 virtual bool hasContextRenderer() const; … … 126 128 RetainPtr<AVAssetImageGenerator> m_imageGenerator; 127 129 id m_timeObserver; 130 bool m_videoFrameHasDrawn; 128 131 }; 129 132 -
trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm
r84988 r85483 139 139 , m_objcObserver(AdoptNS, [[WebCoreAVFMovieObserver alloc] initWithCallback:this]) 140 140 , m_timeObserver(0) 141 , m_videoFrameHasDrawn(false) 141 142 { 142 143 } … … 235 236 } 236 237 237 bool MediaPlayerPrivateAVFoundationObjC::videoLayerIsReadyToDisplay() const 238 { 239 return (m_videoLayer && [m_videoLayer.get() isReadyForDisplay]); 240 } 241 242 void MediaPlayerPrivateAVFoundationObjC::createAVPlayerForURL(const String& url) 243 { 238 bool MediaPlayerPrivateAVFoundationObjC::hasAvailableVideoFrame() const 239 { 240 return (m_videoFrameHasDrawn || (m_videoLayer && [m_videoLayer.get() isReadyForDisplay])); 241 } 242 243 void MediaPlayerPrivateAVFoundationObjC::createAVAssetForURL(const String& url) 244 { 245 if (m_avAsset) 246 return; 247 244 248 setDelayCallbacks(true); 245 246 if (!m_avAsset) { 247 NSURL *cocoaURL = KURL(ParsedURLString, url); 248 m_avAsset.adoptNS([[AVURLAsset alloc] initWithURL:cocoaURL options:nil]); 249 } 250 251 createAVPlayer(); 249 NSURL *cocoaURL = KURL(ParsedURLString, url); 250 m_avAsset.adoptNS([[AVURLAsset alloc] initWithURL:cocoaURL options:nil]); 251 setDelayCallbacks(false); 252 252 } 253 253 254 254 #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 } 255 void MediaPlayerPrivateAVFoundationObjC::createAVAssetForCacheResource(ApplicationCacheResource* resource) 256 { 257 if (m_avAsset) 258 return; 259 260 // AVFoundation can't open arbitrary data pointers. 261 ASSERT(!resource->path().isEmpty()); 263 262 264 263 setDelayCallbacks(true); 265 264 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(); 265 NSURL* localURL = [NSURL fileURLWithPath:resource->path()]; 266 m_avAsset.adoptNS([[AVURLAsset alloc] initWithURL:localURL options:nil]); 267 268 setDelayCallbacks(false); 272 269 } 273 270 #endif … … 275 272 void MediaPlayerPrivateAVFoundationObjC::createAVPlayer() 276 273 { 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 } 274 if (m_avPlayer) 275 return; 276 277 setDelayCallbacks(true); 278 279 m_avPlayer.adoptNS([[AVPlayer alloc] init]); 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 setDelayCallbacks(false); 291 } 292 293 void MediaPlayerPrivateAVFoundationObjC::createAVPlayerItem() 294 { 295 if (m_avPlayerItem) 296 return; 297 298 setDelayCallbacks(true); 299 300 // Create the player item so we can media data. 301 m_avPlayerItem.adoptNS([[AVPlayerItem alloc] initWithAsset:m_avAsset.get()]); 302 303 [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()selector:@selector(didEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:m_avPlayerItem.get()]; 304 305 for (NSString *keyName in itemKVOProperties()) 306 [m_avPlayerItem.get() addObserver:m_objcObserver.get() forKeyPath:keyName options:nil context:(void *)MediaPlayerAVFoundationObservationContextPlayerItem]; 307 308 [m_avPlayer.get() replaceCurrentItemWithPlayerItem:m_avPlayerItem.get()]; 302 309 303 310 setDelayCallbacks(false); … … 315 322 void MediaPlayerPrivateAVFoundationObjC::beginLoadingMetadata() 316 323 { 317 LOG(Media, "MediaPlayerPrivateAVFoundationObjC:: playabilityKnown(%p) - requesting metadata loading", this);324 LOG(Media, "MediaPlayerPrivateAVFoundationObjC::beginLoadingMetadata(%p) - requesting metadata loading", this); 318 325 [m_avAsset.get() loadValuesAsynchronouslyForKeys:[assetMetadataKeyNames() retain] completionHandler:^{ 319 326 [m_objcObserver.get() metadataLoaded]; … … 324 331 { 325 332 if (!m_avPlayerItem) 326 return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatus Unknown;333 return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusDoesNotExist; 327 334 328 335 AVPlayerItemStatus status = [m_avPlayerItem.get() status]; … … 333 340 if ([m_avPlayerItem.get() isPlaybackLikelyToKeepUp]) 334 341 return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp; 335 if ( buffered()->contain(duration()))342 if ([m_avPlayerItem.get() isPlaybackBufferFull]) 336 343 return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferFull; 337 if ( buffered()->contain(currentTime()))344 if ([m_avPlayerItem.get() isPlaybackBufferEmpty]) 338 345 return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty; 339 346 … … 386 393 float MediaPlayerPrivateAVFoundationObjC::platformDuration() const 387 394 { 388 if (!metaDataAvailable() || !m_avPlayerItem)389 return 0;395 if (!metaDataAvailable()) 396 return invalidTime(); 390 397 391 float duration; 392 CMTime cmDuration = [m_avPlayerItem.get() duration]; 398 CMTime cmDuration; 399 400 // Check the avitem if we have one, some assets never report duration. 401 if (m_avPlayerItem) 402 cmDuration = [m_avPlayerItem.get() duration]; 403 else 404 cmDuration= [m_avAsset.get() duration]; 405 393 406 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; 407 return narrowPrecisionToFloat(CMTimeGetSeconds(cmDuration)); 408 409 if (CMTIME_IS_INDEFINITE(cmDuration)) 410 return numeric_limits<float>::infinity(); 411 412 LOG(Media, "MediaPlayerPrivateAVFoundationObjC::duration(%p) - invalid duration, returning -1", this); 413 return invalidTime(); 403 414 } 404 415 … … 536 547 } 537 548 538 MediaPlayerPrivateAVFoundation::A VAssetStatus MediaPlayerPrivateAVFoundationObjC::assetStatus() const549 MediaPlayerPrivateAVFoundation::AssetStatus MediaPlayerPrivateAVFoundationObjC::assetStatus() const 539 550 { 540 551 if (!m_avAsset) 541 return MediaPlayerAVAssetStatus Unknown;552 return MediaPlayerAVAssetStatusDoesNotExist; 542 553 543 554 for (NSString *keyName in assetMetadataKeyNames()) { … … 588 599 setDelayCallbacks(false); 589 600 590 MediaPlayerPrivateAVFoundation::paint(context, rect);601 m_videoFrameHasDrawn = true; 591 602 } 592 603 … … 663 674 void MediaPlayerPrivateAVFoundationObjC::tracksChanged() 664 675 { 676 if (!m_avAsset) 677 return; 678 665 679 // This is called whenever the tracks collection changes so cache hasVideo and hasAudio since we are 666 680 // 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; 681 if (!m_avPlayerItem) { 682 // We don't have a player item yet, so check with the asset because some assets support inspection 683 // prior to becoming ready to play. 684 setHasVideo([[m_avAsset.get() tracksWithMediaCharacteristic:AVMediaCharacteristicVisual] count]); 685 setHasAudio([[m_avAsset.get() tracksWithMediaCharacteristic:AVMediaCharacteristicAudible] count]); 686 setHasClosedCaptions([[m_avAsset.get() tracksWithMediaType:AVMediaTypeClosedCaption] count]); 687 } else { 688 bool hasVideo = false; 689 bool hasAudio = false; 690 bool hasCaptions = false; 691 NSArray *tracks = [m_avPlayerItem.get() tracks]; 692 for (AVPlayerItemTrack *track in tracks) { 693 if ([track isEnabled]) { 694 AVAssetTrack *assetTrack = [track assetTrack]; 695 if ([[assetTrack mediaType] isEqualToString:AVMediaTypeVideo]) 696 hasVideo = true; 697 else if ([[assetTrack mediaType] isEqualToString:AVMediaTypeAudio]) 698 hasAudio = true; 699 else if ([[assetTrack mediaType] isEqualToString:AVMediaTypeClosedCaption]) 700 hasCaptions = true; 701 } 680 702 } 681 }682 setHasVideo(hasVideo);683 setHasAudio(hasAudio);684 setHasClosedCaptions(hasCaptions);703 setHasVideo(hasVideo); 704 setHasAudio(hasAudio); 705 setHasClosedCaptions(hasCaptions); 706 } 685 707 686 708 sizeChanged(); … … 689 711 void MediaPlayerPrivateAVFoundationObjC::sizeChanged() 690 712 { 713 if (!m_avAsset) 714 return; 715 691 716 NSArray *tracks = [m_avAsset.get() tracks]; 692 717 693 718 // Some assets don't report track properties until they are completely ready to play, but we 694 719 // want to report a size as early as possible so use presentationSize when an asset has no tracks. 695 if ( ![tracks count]) {720 if (m_avPlayerItem && ![tracks count]) { 696 721 setNaturalSize(IntSize([m_avPlayerItem.get() presentationSize])); 697 722 return;
Note: See TracChangeset
for help on using the changeset viewer.