Changeset 85865 in webkit


Ignore:
Timestamp:
May 5, 2011 11:17:23 AM (13 years ago)
Author:
eric.carlson@apple.com
Message:

2011-05-05 Eric Carlson <eric.carlson@apple.com>

Reviewed by Adam Roben.

The preload attribute of the video tag is not completely implemented
https://bugs.webkit.org/show_bug.cgi?id=43673
<rdar://problem/9369746>

This change implements "preload=metadata" for the AVFoundation backend.
Tested manually with manual-tests/media-elements/video-preload.html.

  • html/HTMLMediaElement.cpp: (WebCore::HTMLMediaElement::HTMLMediaElement): Initialize m_havePreparedToPlay. (WebCore::HTMLMediaElement::prepareForLoad): Ditto. (WebCore::HTMLMediaElement::prepareToPlay): New, tell player to prepare to play. (WebCore::HTMLMediaElement::seek): Call prepareToPlay when preload is less than 'auto'

because we need to have media data loaded to seek.

(WebCore::HTMLMediaElement::updatePlayState): Call prepareToPlay.

  • html/HTMLMediaElement.h:
  • manual-tests/media-elements/video-preload.html: Make changing urls work.
  • platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp: (WebCore::MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation): Remove

m_videoFrameHasDrawn and m_delayingLoad as they are no longer used.

(WebCore::MediaPlayerPrivateAVFoundation::resumeLoad): Removed.
(WebCore::MediaPlayerPrivateAVFoundation::load): Don't initialize m_videoFrameHasDrawn.

Move all preload logic to setPreload, call it from here.

(WebCore::MediaPlayerPrivateAVFoundation::prepareToPlay): Move all preload logic to

setPreload, call it.

(WebCore::MediaPlayerPrivateAVFoundation::duration): Don't cache duration = 0, it is

unlikely to be correct and isn't worth caching. Use invalidTime() function.

(WebCore::MediaPlayerPrivateAVFoundation::seeking): Use invalidTime() function.
(WebCore::MediaPlayerPrivateAVFoundation::setNaturalSize): Add logging.
(WebCore::MediaPlayerPrivateAVFoundation::updateStates): Update for name change AVAssetStatus

to AssetStatus. Always create a AVPlayerItem for live streams because they can't be inspected
without one. Set networkState to 'idle' when the playback buffer is full because that is
a signal that AVFoundation won't do any more IO. Set readyState to 'HAVE_CURRENT_DATA'
when the first frame is available.

(WebCore::MediaPlayerPrivateAVFoundation::metadataLoaded): Call tracksChanged so we cache

width, height, hasVideo, etc.

(WebCore::MediaPlayerPrivateAVFoundation::loadedTimeRangesChanged): Use invalidTime() function.
(WebCore::MediaPlayerPrivateAVFoundation::timeChanged): Ditto.
(WebCore::MediaPlayerPrivateAVFoundation::seekCompleted): Ditto.
(WebCore::MediaPlayerPrivateAVFoundation::repaint): Don't set m_videoFrameHasDrawn, it is done

in derived classes.

(WebCore::MediaPlayerPrivateAVFoundation::setPreload): Centralize all logic about when to create

AVAsset and AVPlayerItem here.

  • platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h:
  • platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h:
  • platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm: (WebCore::MediaPlayerPrivateAVFoundationObjC::MediaPlayerPrivateAVFoundationObjC): Initialize

m_videoFrameHasDrawn.

(WebCore::MediaPlayerPrivateAVFoundationObjC::hasAvailableVideoFrame): New, renamed from

videoLayerIsReadyToDisplay. Return true if we have a layer with frames available or
if we have painted a frame to the context.

(WebCore::MediaPlayerPrivateAVFoundationObjC::createAVAssetForURL): New, create the AVAsset

if necessary.

(WebCore::MediaPlayerPrivateAVFoundationObjC::createAVAssetForCacheResource): Ditto.
(WebCore::MediaPlayerPrivateAVFoundationObjC::createAVPlayer): Restructure logic.
(WebCore::MediaPlayerPrivateAVFoundationObjC::createAVPlayerItem): New, create AVPlayerItem.
(WebCore::MediaPlayerPrivateAVFoundationObjC::beginLoadingMetadata): Correct logging.
(WebCore::MediaPlayerPrivateAVFoundationObjC::playerItemStatus): Return "buffer full" when

the buffer is full.

(WebCore::MediaPlayerPrivateAVFoundationObjC::platformDuration): Get the duration from the

AVAsset when we haven't allocated the AVPlayerItem yet so that we can return duration
when we only have metadata.

(WebCore::MediaPlayerPrivateAVFoundationObjC::assetStatus): Update for name change.
(WebCore::MediaPlayerPrivateAVFoundationObjC::paint): Set m_videoFrameHasDrawn.
(WebCore::MediaPlayerPrivateAVFoundationObjC::tracksChanged): Get attributes from AVAsset

when when we haven't allocated the AVPlayerItem yet so that we can report attributes
when we only have metadata.

(WebCore::MediaPlayerPrivateAVFoundationObjC::sizeChanged): Guard against being called before

we have allocated the AVPlayerItem.

Location:
trunk/Source/WebCore
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r85864 r85865  
     12011-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
    1772011-05-05  Ryosuke Niwa  <rniwa@webkit.org>
    278
  • trunk/Source/WebCore/html/HTMLMediaElement.cpp

    r85518 r85865  
    172172    , m_loadInitiatedByUserGesture(false)
    173173    , m_completelyLoaded(false)
     174    , m_havePreparedToPlay(false)
    174175{
    175176    LOG(Media, "HTMLMediaElement::HTMLMediaElement");
     
    518519    m_haveFiredLoadedData = false;
    519520    m_completelyLoaded = false;
     521    m_havePreparedToPlay = false;
    520522    m_displayMode = Unknown;
    521523
     
    10831085    return m_player ? m_player->supportsSave() : false;
    10841086}
    1085    
     1087
     1088void HTMLMediaElement::prepareToPlay()
     1089{
     1090    if (m_havePreparedToPlay)
     1091        return;
     1092    m_havePreparedToPlay = true;
     1093    m_player->prepareToPlay();
     1094}
     1095
    10861096void HTMLMediaElement::seek(float time, ExceptionCode& ec)
    10871097{
     
    10951105        return;
    10961106    }
     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();
    10971111
    10981112    // Get the current time before setting m_seeking, m_lastSeekTime is returned once it is set.
     
    21972211
    21982212        if (couldPlayIfEnoughData())
    2199             m_player->prepareToPlay();
     2213            prepareToPlay();
    22002214
    22012215        if (hasMediaControls())
  • trunk/Source/WebCore/html/HTMLMediaElement.h

    r85811 r85865  
    289289    void cancelPendingEventsAndCallbacks();
    290290    void waitForSourceChange();
     291    void prepareToPlay();
    291292
    292293    enum InvalidSourceAction { DoNothing, Complain };
     
    420421    bool m_loadInitiatedByUserGesture : 1;
    421422    bool m_completelyLoaded : 1;
     423    bool m_havePreparedToPlay : 1;
    422424};
    423425
  • trunk/Source/WebCore/manual-tests/media-elements/video-preload.html

    r85476 r85865  
    9696        }
    9797
    98         function setURL(url, vidID)
    99         {
    100             var vid = document.getElementById(vidID);
     98        function setURL(url)
     99        {
     100            var vid = document.getElementById("vid");
    101101
    102102            logMsg(vid, "###############");
     
    200200            <tbody>
    201201                <tr><td>Preload</td><td id="Preload"></td></tr>
     202                <tr><td>Error</td><td id="Error"></td></tr>
    202203                <tr><td>Duration</td> <td id="Duration"></td></tr>
    203204                <tr><td>Video Width</td><td id="Video Width"></td></tr>
     
    217218    <br>
    218219    <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)" >
    220221        <br>
    221222        <input id="clear_log" type="button" value="Clear" onclick="clearlog()">
  • trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp

    r85518 r85865  
    3131
    3232#include "ApplicationCacheHost.h"
     33#include "ApplicationCacheResource.h"
    3334#include "DocumentLoader.h"
    3435#include "FrameView.h"
     
    4647namespace WebCore {
    4748
    48 static const float invalidTime = -1.0f;
    49 
    5049MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(MediaPlayer* player)
    5150    : m_player(player)
    5251    , m_queuedNotifications()
    5352    , m_queueMutex()
    54     , m_mainThreadCallPending(false)
    5553    , m_networkState(MediaPlayer::Empty)
    5654    , m_readyState(MediaPlayer::HaveNothing)
     
    5957    , m_cachedMaxTimeLoaded(0)
    6058    , 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())
    6462    , m_requestedRate(1)
    65     , m_delayCallbacks(false)
    66     , m_havePreparedToPlay(false)
     63    , m_delayCallbacks(0)
     64    , m_mainThreadCallPending(false)
    6765    , m_assetIsPlayable(false)
    6866    , m_visible(false)
    69     , m_videoFrameHasDrawn(false)
    7067    , m_loadingMetadata(false)
    71     , m_delayingLoad(false)
    7268    , m_isAllowedToRender(false)
    7369    , m_cachedHasAudio(false)
     
    168164}
    169165
    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 
    181166void MediaPlayerPrivateAVFoundation::load(const String& url)
    182167{
     
    192177    }
    193178
    194     m_videoFrameHasDrawn = false;
    195179    m_assetURL = url;
    196180
     
    199183        return;
    200184
    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);
    208186}
    209187
     
    233211    LOG(Media, "MediaPlayerPrivateAVFoundation::prepareToPlay(%p)", this);
    234212
    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);
    251214}
    252215
     
    270233}
    271234
    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 
    278235float MediaPlayerPrivateAVFoundation::duration() const
    279236{
    280     if (!metaDataAvailable())
     237    if (m_cachedDuration != invalidTime())
     238        return m_cachedDuration;
     239
     240    float duration = platformDuration();
     241    if (!duration || duration == invalidTime())
    281242        return 0;
    282243
    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);
    288246    return m_cachedDuration;
    289247}
     
    327285        return false;
    328286
    329     return m_seekTo != invalidTime;
     287    return m_seekTo != invalidTime();
    330288}
    331289
     
    347305void MediaPlayerPrivateAVFoundation::setNaturalSize(IntSize size)
    348306{
     307    LOG(Media, "MediaPlayerPrivateAVFoundation:sizeChanged(%p) - size = %d x %d", this, size.width(), size.height());
     308
    349309    IntSize oldSize = m_cachedNaturalSize;
    350310    m_cachedNaturalSize = size;
     
    433393    else {
    434394        // -loadValuesAsynchronouslyForKeys:completionHandler: has invoked its handler; test status of keys and determine state.
    435         AVAssetStatus avAssetStatus = assetStatus();
     395        AssetStatus assetStatus = this->assetStatus();
    436396        ItemStatus itemStatus = playerItemStatus();
    437397       
    438         m_assetIsPlayable = (avAssetStatus == MediaPlayerAVAssetStatusPlayable);
    439         if (m_readyState < MediaPlayer::HaveMetadata && avAssetStatus > MediaPlayerAVAssetStatusLoading) {
     398        m_assetIsPlayable = (assetStatus == MediaPlayerAVAssetStatusPlayable);
     399        if (m_readyState < MediaPlayer::HaveMetadata && assetStatus > MediaPlayerAVAssetStatusLoading) {
    440400            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.
    446407                        m_networkState = MediaPlayer::Loading;
    447408                        prepareToPlay();
     
    449410                        m_networkState = MediaPlayer::Idle;
    450411                }
    451                 if (avAssetStatus == MediaPlayerAVAssetStatusLoaded)
    452                     m_readyState = MediaPlayer::HaveMetadata;
    453412            } else {
    454413                // FIX ME: fetch the error associated with the @"playable" key to distinguish between format
     
    458417        }
    459418       
    460         if (avAssetStatus >= MediaPlayerAVAssetStatusLoaded && itemStatus > MediaPlayerAVPlayerItemStatusUnknown) {
     419        if (assetStatus >= MediaPlayerAVAssetStatusLoaded && itemStatus > MediaPlayerAVPlayerItemStatusUnknown) {
    461420            if (seeking())
    462421                m_readyState = m_readyState >= MediaPlayer::HaveMetadata ? MediaPlayer::HaveMetadata : MediaPlayer::HaveNothing;
    463422            else {
    464                 float maxLoaded = maxTimeLoaded();
    465423                switch (itemStatus) {
     424                case MediaPlayerAVPlayerItemStatusDoesNotExist:
    466425                case MediaPlayerAVPlayerItemStatusUnknown:
     426                case MediaPlayerAVPlayerItemStatusFailed:
    467427                    break;
    468                 case MediaPlayerAVPlayerItemStatusFailed:
    469                     m_networkState = MediaPlayer::DecodeError;
    470                     break;
     428
    471429                case MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp:
    472430                    m_readyState = MediaPlayer::HaveEnoughData;
    473431                    break;
     432
     433                case MediaPlayerAVPlayerItemStatusPlaybackBufferFull:
    474434                case MediaPlayerAVPlayerItemStatusReadyToPlay:
    475                 case MediaPlayerAVPlayerItemStatusPlaybackBufferFull:
    476435                    // If the readyState is already HaveEnoughData, don't go lower because of this state change.
    477436                    if (m_readyState == MediaPlayer::HaveEnoughData)
     
    479438
    480439                case MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty:
    481                     if (maxLoaded > currentTime())
     440                    if (maxTimeLoaded() > currentTime())
    482441                        m_readyState = MediaPlayer::HaveFutureData;
    483442                    else
     
    486445                }
    487446
    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;
    490453            }
    491454        }
     
    496459
    497460    if (!m_haveReportedFirstVideoFrame && m_cachedHasVideo && hasAvailableVideoFrame()) {
     461        if (m_readyState < MediaPlayer::HaveCurrentData)
     462            m_readyState = MediaPlayer::HaveCurrentData;
    498463        m_haveReportedFirstVideoFrame = true;
    499464        m_player->firstVideoFrameAvailable();
     
    531496}
    532497
    533 bool MediaPlayerPrivateAVFoundation::hasAvailableVideoFrame() const
    534 {
    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 well
    539     // wait until we know that a frame has been drawn.
    540     return m_videoFrameHasDrawn;
    541 }
    542 
    543498void MediaPlayerPrivateAVFoundation::acceleratedRenderingStateChanged()
    544499{
     
    550505{
    551506    m_loadingMetadata = false;
     507    tracksChanged();
    552508    updateStates();
    553509}
     
    576532    float dur = duration();
    577533    if (dur != m_reportedDuration) {
    578         if (m_reportedDuration != invalidTime)
     534        if (m_reportedDuration != invalidTime())
    579535            m_player->durationChanged();
    580536        m_reportedDuration = dur;
     
    591547    LOG(Media, "MediaPlayerPrivateAVFoundation::timeChanged(%p) - time = %f", this, time);
    592548
    593     if (m_seekTo == invalidTime)
     549    if (m_seekTo == invalidTime())
    594550        return;
    595551
     
    601557    float currentRate = rate();
    602558    if ((currentRate > 0 && time >= m_seekTo) || (currentRate < 0 && time <= m_seekTo) || (abs(m_seekTo - time) <= smallSeekDelta)) {
    603         m_seekTo = invalidTime;
     559        m_seekTo = invalidTime();
    604560        updateStates();
    605561        m_player->timeChanged();
     
    612568   
    613569    if (finished)
    614         m_seekTo = invalidTime;
     570        m_seekTo = invalidTime();
    615571}
    616572
     
    629585void MediaPlayerPrivateAVFoundation::repaint()
    630586{
    631     m_videoFrameHasDrawn = true;
    632587    m_player->repaint();
    633588}
     
    647602{
    648603    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);
    651636}
    652637
     
    743728    case Notification::ItemTracksChanged:
    744729        tracksChanged();
     730        updateStates();
    745731        break;
    746732    case Notification::ItemStatusChanged:
     
    757743    case Notification::ItemPresentationSizeChanged:
    758744        sizeChanged();
     745        updateStates();
    759746        break;
    760747    case Notification::ItemIsPlaybackLikelyToKeepUpChanged:
  • trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h

    r85518 r85865  
    143143    virtual unsigned bytesLoaded() const;
    144144    virtual void setSize(const IntSize&);
    145     virtual void paint(GraphicsContext*, const IntRect&);
     145    virtual void paint(GraphicsContext*, const IntRect&) = 0;
    146146    virtual void paintCurrentFrameInContext(GraphicsContext*, const IntRect&) = 0;
    147147    virtual void setPreload(MediaPlayer::Preload);
    148     virtual bool hasAvailableVideoFrame() const;
    149148#if USE(ACCELERATED_COMPOSITING)
    150149    virtual PlatformLayer* platformLayer() const { return 0; }
     
    160159
    161160    // 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;
    163164#if ENABLE(OFFLINE_WEB_APPLICATIONS)
    164     virtual void createAVPlayerForCacheResource(ApplicationCacheResource*) = 0;
     165    virtual void createAVAssetForCacheResource(ApplicationCacheResource*) = 0;
    165166#endif
    166167
    167168    enum ItemStatus {
     169        MediaPlayerAVPlayerItemStatusDoesNotExist,
    168170        MediaPlayerAVPlayerItemStatusUnknown,
    169171        MediaPlayerAVPlayerItemStatusFailed,
     
    175177    virtual ItemStatus playerItemStatus() const = 0;
    176178
    177     enum AVAssetStatus {
     179    enum AssetStatus {
     180        MediaPlayerAVAssetStatusDoesNotExist,
    178181        MediaPlayerAVAssetStatusUnknown,
    179182        MediaPlayerAVAssetStatusLoading,
     
    183186        MediaPlayerAVAssetStatusPlayable,
    184187    };
    185     virtual AVAssetStatus assetStatus() const = 0;
     188    virtual AssetStatus assetStatus() const = 0;
    186189
    187190    virtual void platformSetVisible(bool) = 0;
     
    207210    virtual void createVideoLayer() = 0;
    208211    virtual void destroyVideoLayer() = 0;
    209     virtual bool videoLayerIsReadyToDisplay() const = 0;
     212
     213    virtual bool hasAvailableVideoFrame() const = 0;
    210214
    211215    virtual bool hasContextRenderer() const = 0;
     
    213217
    214218protected:
    215     void resumeLoad();
    216219    void updateStates();
    217220
     
    237240
    238241    static void mainThreadCallback(void*);
     242   
     243    float invalidTime() const { return -1.0f; }
    239244
    240245private:
    241 
    242246    MediaPlayer* m_player;
    243247
    244248    Vector<Notification> m_queuedNotifications;
    245249    Mutex m_queueMutex;
    246     bool m_mainThreadCallPending;
    247250
    248251    mutable RefPtr<TimeRanges> m_cachedLoadedTimeRanges;
     
    264267    float m_requestedRate;
    265268    int m_delayCallbacks;
    266     bool m_havePreparedToPlay;
     269    bool m_mainThreadCallPending;
    267270    bool m_assetIsPlayable;
    268271    bool m_visible;
    269     bool m_videoFrameHasDrawn;
    270272    bool m_loadingMetadata;
    271     bool m_delayingLoad;
    272273    bool m_isAllowedToRender;
    273274    bool m_cachedHasAudio;
  • trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h

    r85615 r85865  
    8989
    9090    virtual void createAVPlayer();
    91     virtual void createAVPlayerForURL(const String& url);
     91    virtual void createAVPlayerItem();
     92    virtual void createAVAssetForURL(const String& url);
    9293#if ENABLE(OFFLINE_WEB_APPLICATIONS)
    93     virtual void createAVPlayerForCacheResource(ApplicationCacheResource*);
     94    virtual void createAVAssetForCacheResource(ApplicationCacheResource*);
    9495#endif
    9596    virtual MediaPlayerPrivateAVFoundation::ItemStatus playerItemStatus() const;
    96     virtual MediaPlayerPrivateAVFoundation::AVAssetStatus assetStatus() const;
     97    virtual MediaPlayerPrivateAVFoundation::AssetStatus assetStatus() const;
    9798
    9899    virtual void checkPlayability();
     
    108109    virtual void sizeChanged();
    109110
     111    virtual bool hasAvailableVideoFrame() const;
     112
    110113    virtual void createContextVideoRenderer();
    111114    virtual void destroyContextVideoRenderer();
     
    113116    virtual void createVideoLayer();
    114117    virtual void destroyVideoLayer();
    115     virtual bool videoLayerIsReadyToDisplay() const;
    116118
    117119    virtual bool hasContextRenderer() const;
     
    128130    RetainPtr<AVAssetImageGenerator> m_imageGenerator;
    129131    id m_timeObserver;
     132    bool m_videoFrameHasDrawn;
     133    bool m_haveCheckedPlayability;
    130134};
    131135
  • trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm

    r85518 r85865  
    139139    , m_objcObserver(AdoptNS, [[WebCoreAVFMovieObserver alloc] initWithCallback:this])
    140140    , m_timeObserver(0)
     141    , m_videoFrameHasDrawn(false)
     142    , m_haveCheckedPlayability(false)
    141143{
    142144}
     
    235237}
    236238
    237 bool MediaPlayerPrivateAVFoundationObjC::videoLayerIsReadyToDisplay() const
    238 {
    239     return (m_videoLayer && [m_videoLayer.get() isReadyForDisplay]);
    240 }
    241 
    242 void MediaPlayerPrivateAVFoundationObjC::createAVPlayerForURL(const String& url)
    243 {
     239bool MediaPlayerPrivateAVFoundationObjC::hasAvailableVideoFrame() const
     240{
     241    return (m_videoFrameHasDrawn || (m_videoLayer && [m_videoLayer.get() isReadyForDisplay]));
     242}
     243
     244void MediaPlayerPrivateAVFoundationObjC::createAVAssetForURL(const String& url)
     245{
     246    if (m_avAsset)
     247        return;
     248
     249    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createAVAssetForURL(%p)", this);
     250
    244251    setDelayCallbacks(true);
    245252
    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);
    252258}
    253259
    254260#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     }
     261void 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());
    263270   
    264271    setDelayCallbacks(true);
    265272
    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);
    272278}
    273279#endif
     
    275281void MediaPlayerPrivateAVFoundationObjC::createAVPlayer()
    276282{
    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    }];
    302300
    303301    setDelayCallbacks(false);
    304302}
    305303
     304void 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
    306328void MediaPlayerPrivateAVFoundationObjC::checkPlayability()
    307329{
     330    if (m_haveCheckedPlayability)
     331        return;
     332    m_haveCheckedPlayability = true;
     333
    308334    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::checkPlayability(%p)", this);
    309335
     
    315341void MediaPlayerPrivateAVFoundationObjC::beginLoadingMetadata()
    316342{
    317     LOG(Media, "MediaPlayerPrivateAVFoundationObjC::playabilityKnown(%p) - requesting metadata loading", this);
     343    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::beginLoadingMetadata(%p) - requesting metadata loading", this);
    318344    [m_avAsset.get() loadValuesAsynchronouslyForKeys:[assetMetadataKeyNames() retain] completionHandler:^{
    319345        [m_objcObserver.get() metadataLoaded];
     
    324350{
    325351    if (!m_avPlayerItem)
    326         return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusUnknown;
     352        return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusDoesNotExist;
    327353
    328354    AVPlayerItemStatus status = [m_avPlayerItem.get() status];
     
    333359    if ([m_avPlayerItem.get() isPlaybackLikelyToKeepUp])
    334360        return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp;
    335     if (buffered()->contain(duration()))
     361    if ([m_avPlayerItem.get() isPlaybackBufferFull])
    336362        return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferFull;
    337     if (buffered()->contain(currentTime()))
     363    if ([m_avPlayerItem.get() isPlaybackBufferEmpty])
    338364        return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty;
    339365
     
    386412float MediaPlayerPrivateAVFoundationObjC::platformDuration() const
    387413{
    388     if (!metaDataAvailable() || !m_avPlayerItem)
    389         return 0;
     414    if (!m_avAsset)
     415        return invalidTime();
    390416   
    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
    393425    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();
    403433}
    404434
     
    536566}
    537567
    538 MediaPlayerPrivateAVFoundation::AVAssetStatus MediaPlayerPrivateAVFoundationObjC::assetStatus() const
     568MediaPlayerPrivateAVFoundation::AssetStatus MediaPlayerPrivateAVFoundationObjC::assetStatus() const
    539569{
    540570    if (!m_avAsset)
    541         return MediaPlayerAVAssetStatusUnknown;
     571        return MediaPlayerAVAssetStatusDoesNotExist;
    542572
    543573    for (NSString *keyName in assetMetadataKeyNames()) {
     
    548578        if (keyStatus == AVKeyValueStatusFailed)
    549579            return MediaPlayerAVAssetStatusFailed; // At least one key could not be loaded.
     580
    550581        if (keyStatus == AVKeyValueStatusCancelled)
    551582            return MediaPlayerAVAssetStatusCancelled; // Loading of at least one key was cancelled.
     
    588619    setDelayCallbacks(false);
    589620
    590     MediaPlayerPrivateAVFoundation::paint(context, rect);
     621    m_videoFrameHasDrawn = true;
    591622}
    592623
     
    663694void MediaPlayerPrivateAVFoundationObjC::tracksChanged()
    664695{
     696    if (!m_avAsset)
     697        return;
     698
    665699    // This is called whenever the tracks collection changes so cache hasVideo and hasAudio since we are
    666700    // 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            }
    680722        }
    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()));
    685730
    686731    sizeChanged();
     
    689734void MediaPlayerPrivateAVFoundationObjC::sizeChanged()
    690735{
     736    if (!m_avAsset)
     737        return;
     738
    691739    NSArray *tracks = [m_avAsset.get() tracks];
    692740
    693741    // Some assets don't report track properties until they are completely ready to play, but we
    694742    // 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]) {
    696744        setNaturalSize(IntSize([m_avPlayerItem.get() presentationSize]));
    697745        return;
Note: See TracChangeset for help on using the changeset viewer.