12bde8e466a4451c7319e3a072d118917957d6554Steve Block/*
22bde8e466a4451c7319e3a072d118917957d6554Steve Block * Copyright (C) 2011 Apple Inc. All rights reserved.
32bde8e466a4451c7319e3a072d118917957d6554Steve Block *
42bde8e466a4451c7319e3a072d118917957d6554Steve Block * Redistribution and use in source and binary forms, with or without
52bde8e466a4451c7319e3a072d118917957d6554Steve Block * modification, are permitted provided that the following conditions
62bde8e466a4451c7319e3a072d118917957d6554Steve Block * are met:
72bde8e466a4451c7319e3a072d118917957d6554Steve Block * 1. Redistributions of source code must retain the above copyright
82bde8e466a4451c7319e3a072d118917957d6554Steve Block *    notice, this list of conditions and the following disclaimer.
92bde8e466a4451c7319e3a072d118917957d6554Steve Block * 2. Redistributions in binary form must reproduce the above copyright
102bde8e466a4451c7319e3a072d118917957d6554Steve Block *    notice, this list of conditions and the following disclaimer in the
112bde8e466a4451c7319e3a072d118917957d6554Steve Block *    documentation and/or other materials provided with the distribution.
122bde8e466a4451c7319e3a072d118917957d6554Steve Block *
132bde8e466a4451c7319e3a072d118917957d6554Steve Block * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
142bde8e466a4451c7319e3a072d118917957d6554Steve Block * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
152bde8e466a4451c7319e3a072d118917957d6554Steve Block * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
162bde8e466a4451c7319e3a072d118917957d6554Steve Block * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
172bde8e466a4451c7319e3a072d118917957d6554Steve Block * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
182bde8e466a4451c7319e3a072d118917957d6554Steve Block * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
192bde8e466a4451c7319e3a072d118917957d6554Steve Block * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
202bde8e466a4451c7319e3a072d118917957d6554Steve Block * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
212bde8e466a4451c7319e3a072d118917957d6554Steve Block * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
222bde8e466a4451c7319e3a072d118917957d6554Steve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
232bde8e466a4451c7319e3a072d118917957d6554Steve Block * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
242bde8e466a4451c7319e3a072d118917957d6554Steve Block */
252bde8e466a4451c7319e3a072d118917957d6554Steve Block
262bde8e466a4451c7319e3a072d118917957d6554Steve Block#import "config.h"
272bde8e466a4451c7319e3a072d118917957d6554Steve Block
282bde8e466a4451c7319e3a072d118917957d6554Steve Block#if ENABLE(VIDEO) && USE(AVFOUNDATION)
292bde8e466a4451c7319e3a072d118917957d6554Steve Block
302bde8e466a4451c7319e3a072d118917957d6554Steve Block#import "MediaPlayerPrivateAVFoundationObjC.h"
312bde8e466a4451c7319e3a072d118917957d6554Steve Block
322bde8e466a4451c7319e3a072d118917957d6554Steve Block#import "ApplicationCacheResource.h"
332bde8e466a4451c7319e3a072d118917957d6554Steve Block#import "BlockExceptions.h"
342bde8e466a4451c7319e3a072d118917957d6554Steve Block#import "FloatConversion.h"
352bde8e466a4451c7319e3a072d118917957d6554Steve Block#import "FrameView.h"
362bde8e466a4451c7319e3a072d118917957d6554Steve Block#import "FloatConversion.h"
372bde8e466a4451c7319e3a072d118917957d6554Steve Block#import "GraphicsContext.h"
382bde8e466a4451c7319e3a072d118917957d6554Steve Block#import "KURL.h"
392bde8e466a4451c7319e3a072d118917957d6554Steve Block#import "Logging.h"
402bde8e466a4451c7319e3a072d118917957d6554Steve Block#import "SoftLinking.h"
412bde8e466a4451c7319e3a072d118917957d6554Steve Block#import "TimeRanges.h"
422bde8e466a4451c7319e3a072d118917957d6554Steve Block#import "WebCoreSystemInterface.h"
432bde8e466a4451c7319e3a072d118917957d6554Steve Block#import <objc/objc-runtime.h>
442bde8e466a4451c7319e3a072d118917957d6554Steve Block#import <wtf/UnusedParam.h>
452bde8e466a4451c7319e3a072d118917957d6554Steve Block
462bde8e466a4451c7319e3a072d118917957d6554Steve Block#import <CoreMedia/CoreMedia.h>
472bde8e466a4451c7319e3a072d118917957d6554Steve Block#import <AVFoundation/AVFoundation.h>
482bde8e466a4451c7319e3a072d118917957d6554Steve Block
492bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK_FRAMEWORK(AVFoundation)
502bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK_FRAMEWORK(CoreMedia)
512bde8e466a4451c7319e3a072d118917957d6554Steve Block
522bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK(CoreMedia, CMTimeCompare, int32_t, (CMTime time1, CMTime time2), (time1, time2))
532bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK(CoreMedia, CMTimeMakeWithSeconds, CMTime, (Float64 seconds, int32_t preferredTimeScale), (seconds, preferredTimeScale))
542bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK(CoreMedia, CMTimeGetSeconds, Float64, (CMTime time), (time))
552bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK(CoreMedia, CMTimeRangeGetEnd, CMTime, (CMTimeRange range), (range))
562bde8e466a4451c7319e3a072d118917957d6554Steve Block
572bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK_CLASS(AVFoundation, AVPlayer)
582bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK_CLASS(AVFoundation, AVPlayerItem)
592bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK_CLASS(AVFoundation, AVPlayerLayer)
602bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK_CLASS(AVFoundation, AVURLAsset)
612bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK_CLASS(AVFoundation, AVAssetImageGenerator)
622bde8e466a4451c7319e3a072d118917957d6554Steve Block
632bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK_POINTER(AVFoundation, AVMediaCharacteristicVisual, NSString *)
642bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK_POINTER(AVFoundation, AVMediaCharacteristicAudible, NSString *)
652bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK_POINTER(AVFoundation, AVMediaTypeClosedCaption, NSString *)
662bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK_POINTER(AVFoundation, AVPlayerItemDidPlayToEndTimeNotification, NSString *)
672bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK_POINTER(AVFoundation, AVAssetImageGeneratorApertureModeCleanAperture, NSString *)
682bde8e466a4451c7319e3a072d118917957d6554Steve Block
692bde8e466a4451c7319e3a072d118917957d6554Steve BlockSOFT_LINK_CONSTANT(CoreMedia, kCMTimeZero, CMTime)
702bde8e466a4451c7319e3a072d118917957d6554Steve Block
712bde8e466a4451c7319e3a072d118917957d6554Steve Block#define AVPlayer getAVPlayerClass()
722bde8e466a4451c7319e3a072d118917957d6554Steve Block#define AVPlayerItem getAVPlayerItemClass()
732bde8e466a4451c7319e3a072d118917957d6554Steve Block#define AVPlayerLayer getAVPlayerLayerClass()
742bde8e466a4451c7319e3a072d118917957d6554Steve Block#define AVURLAsset getAVURLAssetClass()
752bde8e466a4451c7319e3a072d118917957d6554Steve Block#define AVAssetImageGenerator getAVAssetImageGeneratorClass()
762bde8e466a4451c7319e3a072d118917957d6554Steve Block
772bde8e466a4451c7319e3a072d118917957d6554Steve Block#define AVMediaCharacteristicVisual getAVMediaCharacteristicVisual()
782bde8e466a4451c7319e3a072d118917957d6554Steve Block#define AVMediaCharacteristicAudible getAVMediaCharacteristicAudible()
792bde8e466a4451c7319e3a072d118917957d6554Steve Block#define AVMediaTypeClosedCaption getAVMediaTypeClosedCaption()
802bde8e466a4451c7319e3a072d118917957d6554Steve Block#define AVPlayerItemDidPlayToEndTimeNotification getAVPlayerItemDidPlayToEndTimeNotification()
812bde8e466a4451c7319e3a072d118917957d6554Steve Block#define AVAssetImageGeneratorApertureModeCleanAperture getAVAssetImageGeneratorApertureModeCleanAperture()
822bde8e466a4451c7319e3a072d118917957d6554Steve Block
832bde8e466a4451c7319e3a072d118917957d6554Steve Block#define kCMTimeZero getkCMTimeZero()
842bde8e466a4451c7319e3a072d118917957d6554Steve Block
852bde8e466a4451c7319e3a072d118917957d6554Steve Blockusing namespace WebCore;
862bde8e466a4451c7319e3a072d118917957d6554Steve Blockusing namespace std;
872bde8e466a4451c7319e3a072d118917957d6554Steve Block
882bde8e466a4451c7319e3a072d118917957d6554Steve Blockenum MediaPlayerAVFoundationObservationContext {
892bde8e466a4451c7319e3a072d118917957d6554Steve Block    MediaPlayerAVFoundationObservationContextPlayerItem,
902bde8e466a4451c7319e3a072d118917957d6554Steve Block    MediaPlayerAVFoundationObservationContextPlayer
912bde8e466a4451c7319e3a072d118917957d6554Steve Block};
922bde8e466a4451c7319e3a072d118917957d6554Steve Block
932bde8e466a4451c7319e3a072d118917957d6554Steve Block@interface WebCoreAVFMovieObserver : NSObject
942bde8e466a4451c7319e3a072d118917957d6554Steve Block{
952bde8e466a4451c7319e3a072d118917957d6554Steve Block    MediaPlayerPrivateAVFoundationObjC* m_callback;
962bde8e466a4451c7319e3a072d118917957d6554Steve Block    int m_delayCallbacks;
972bde8e466a4451c7319e3a072d118917957d6554Steve Block}
982bde8e466a4451c7319e3a072d118917957d6554Steve Block-(id)initWithCallback:(MediaPlayerPrivateAVFoundationObjC*)callback;
992bde8e466a4451c7319e3a072d118917957d6554Steve Block-(void)disconnect;
1002bde8e466a4451c7319e3a072d118917957d6554Steve Block-(void)playableKnown;
1012bde8e466a4451c7319e3a072d118917957d6554Steve Block-(void)metadataLoaded;
1022bde8e466a4451c7319e3a072d118917957d6554Steve Block-(void)timeChanged:(double)time;
1032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch-(void)seekCompleted:(BOOL)finished;
1042bde8e466a4451c7319e3a072d118917957d6554Steve Block-(void)didEnd:(NSNotification *)notification;
1052bde8e466a4451c7319e3a072d118917957d6554Steve Block-(void)observeValueForKeyPath:keyPath ofObject:(id)object change:(NSDictionary *)change context:(MediaPlayerAVFoundationObservationContext)context;
1062bde8e466a4451c7319e3a072d118917957d6554Steve Block@end
1072bde8e466a4451c7319e3a072d118917957d6554Steve Block
1082bde8e466a4451c7319e3a072d118917957d6554Steve Blocknamespace WebCore {
1092bde8e466a4451c7319e3a072d118917957d6554Steve Block
1102bde8e466a4451c7319e3a072d118917957d6554Steve Blockstatic NSArray *assetMetadataKeyNames();
1112bde8e466a4451c7319e3a072d118917957d6554Steve Blockstatic NSArray *itemKVOProperties();
1122bde8e466a4451c7319e3a072d118917957d6554Steve Block
1132bde8e466a4451c7319e3a072d118917957d6554Steve Block#if !LOG_DISABLED
1142bde8e466a4451c7319e3a072d118917957d6554Steve Blockstatic const char *boolString(bool val)
1152bde8e466a4451c7319e3a072d118917957d6554Steve Block{
1162bde8e466a4451c7319e3a072d118917957d6554Steve Block    return val ? "true" : "false";
1172bde8e466a4451c7319e3a072d118917957d6554Steve Block}
1182bde8e466a4451c7319e3a072d118917957d6554Steve Block#endif
1192bde8e466a4451c7319e3a072d118917957d6554Steve Block
1202bde8e466a4451c7319e3a072d118917957d6554Steve Blockstatic const float invalidTime = -1.0f;
1212bde8e466a4451c7319e3a072d118917957d6554Steve Block
1222bde8e466a4451c7319e3a072d118917957d6554Steve BlockMediaPlayerPrivateInterface* MediaPlayerPrivateAVFoundationObjC::create(MediaPlayer* player)
1232bde8e466a4451c7319e3a072d118917957d6554Steve Block{
1242bde8e466a4451c7319e3a072d118917957d6554Steve Block    return new MediaPlayerPrivateAVFoundationObjC(player);
1252bde8e466a4451c7319e3a072d118917957d6554Steve Block}
1262bde8e466a4451c7319e3a072d118917957d6554Steve Block
1272bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::registerMediaEngine(MediaEngineRegistrar registrar)
1282bde8e466a4451c7319e3a072d118917957d6554Steve Block{
1292bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (isAvailable())
1302bde8e466a4451c7319e3a072d118917957d6554Steve Block        registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
1312bde8e466a4451c7319e3a072d118917957d6554Steve Block}
1322bde8e466a4451c7319e3a072d118917957d6554Steve Block
1332bde8e466a4451c7319e3a072d118917957d6554Steve BlockMediaPlayerPrivateAVFoundationObjC::MediaPlayerPrivateAVFoundationObjC(MediaPlayer* player)
1342bde8e466a4451c7319e3a072d118917957d6554Steve Block    : MediaPlayerPrivateAVFoundation(player)
1352bde8e466a4451c7319e3a072d118917957d6554Steve Block    , m_objcObserver(AdoptNS, [[WebCoreAVFMovieObserver alloc] initWithCallback:this])
1362bde8e466a4451c7319e3a072d118917957d6554Steve Block    , m_timeObserver(0)
1372bde8e466a4451c7319e3a072d118917957d6554Steve Block{
1382bde8e466a4451c7319e3a072d118917957d6554Steve Block}
1392bde8e466a4451c7319e3a072d118917957d6554Steve Block
1402bde8e466a4451c7319e3a072d118917957d6554Steve BlockMediaPlayerPrivateAVFoundationObjC::~MediaPlayerPrivateAVFoundationObjC()
1412bde8e466a4451c7319e3a072d118917957d6554Steve Block{
1422bde8e466a4451c7319e3a072d118917957d6554Steve Block    cancelLoad();
1432bde8e466a4451c7319e3a072d118917957d6554Steve Block    [m_objcObserver.get() disconnect];
1442bde8e466a4451c7319e3a072d118917957d6554Steve Block}
1452bde8e466a4451c7319e3a072d118917957d6554Steve Block
1462bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::cancelLoad()
1472bde8e466a4451c7319e3a072d118917957d6554Steve Block{
1482bde8e466a4451c7319e3a072d118917957d6554Steve Block    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::cancelLoad(%p)", this);
1492bde8e466a4451c7319e3a072d118917957d6554Steve Block    tearDownVideoRendering();
1502bde8e466a4451c7319e3a072d118917957d6554Steve Block
1512bde8e466a4451c7319e3a072d118917957d6554Steve Block    [[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()];
1522bde8e466a4451c7319e3a072d118917957d6554Steve Block
1532bde8e466a4451c7319e3a072d118917957d6554Steve Block    // Tell our observer to do nothing when our cancellation of pending loading calls its completion handler.
1542bde8e466a4451c7319e3a072d118917957d6554Steve Block    setIgnoreLoadStateChanges(true);
1552bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (m_avAsset) {
1562bde8e466a4451c7319e3a072d118917957d6554Steve Block        [m_avAsset.get() cancelLoading];
1572bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_avAsset = nil;
1582bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
1592bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (m_avPlayerItem) {
1602bde8e466a4451c7319e3a072d118917957d6554Steve Block        for (NSString *keyName in itemKVOProperties())
1612bde8e466a4451c7319e3a072d118917957d6554Steve Block            [m_avPlayerItem.get() removeObserver:m_objcObserver.get() forKeyPath:keyName];
1622bde8e466a4451c7319e3a072d118917957d6554Steve Block
1632bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_avPlayerItem = nil;
1642bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
1652bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (m_avPlayer) {
1662bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (m_timeObserver)
1672bde8e466a4451c7319e3a072d118917957d6554Steve Block            [m_avPlayer.get() removeTimeObserver:m_timeObserver];
1682bde8e466a4451c7319e3a072d118917957d6554Steve Block        [m_avPlayer.get() removeObserver:m_objcObserver.get() forKeyPath:@"rate"];
1692bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_avPlayer = nil;
1702bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
1712bde8e466a4451c7319e3a072d118917957d6554Steve Block    setIgnoreLoadStateChanges(false);
1722bde8e466a4451c7319e3a072d118917957d6554Steve Block}
1732bde8e466a4451c7319e3a072d118917957d6554Steve Block
1742bde8e466a4451c7319e3a072d118917957d6554Steve Blockbool MediaPlayerPrivateAVFoundationObjC::hasLayerRenderer() const
1752bde8e466a4451c7319e3a072d118917957d6554Steve Block{
1762bde8e466a4451c7319e3a072d118917957d6554Steve Block    return m_videoLayer;
1772bde8e466a4451c7319e3a072d118917957d6554Steve Block}
1782bde8e466a4451c7319e3a072d118917957d6554Steve Block
1792bde8e466a4451c7319e3a072d118917957d6554Steve Blockbool MediaPlayerPrivateAVFoundationObjC::hasContextRenderer() const
1802bde8e466a4451c7319e3a072d118917957d6554Steve Block{
1812bde8e466a4451c7319e3a072d118917957d6554Steve Block    return m_imageGenerator;
1822bde8e466a4451c7319e3a072d118917957d6554Steve Block}
1832bde8e466a4451c7319e3a072d118917957d6554Steve Block
1842bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::createContextVideoRenderer()
1852bde8e466a4451c7319e3a072d118917957d6554Steve Block{
1862bde8e466a4451c7319e3a072d118917957d6554Steve Block    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createContextVideoRenderer(%p)", this);
1872bde8e466a4451c7319e3a072d118917957d6554Steve Block
1882bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_avAsset || m_imageGenerator)
1892bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
1902bde8e466a4451c7319e3a072d118917957d6554Steve Block
1912bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:m_avAsset.get()];
1922bde8e466a4451c7319e3a072d118917957d6554Steve Block
1932bde8e466a4451c7319e3a072d118917957d6554Steve Block    [m_imageGenerator.get() setApertureMode:AVAssetImageGeneratorApertureModeCleanAperture];
1942bde8e466a4451c7319e3a072d118917957d6554Steve Block    [m_imageGenerator.get() setAppliesPreferredTrackTransform:YES];
1952bde8e466a4451c7319e3a072d118917957d6554Steve Block
1962bde8e466a4451c7319e3a072d118917957d6554Steve Block    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createImageGenerator(%p) - returning %p", this, m_imageGenerator.get());
1972bde8e466a4451c7319e3a072d118917957d6554Steve Block}
1982bde8e466a4451c7319e3a072d118917957d6554Steve Block
1992bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer()
2002bde8e466a4451c7319e3a072d118917957d6554Steve Block{
2012bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_imageGenerator)
2022bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
2032bde8e466a4451c7319e3a072d118917957d6554Steve Block
2042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer(%p) - destroying  %p", this, m_imageGenerator.get());
2052bde8e466a4451c7319e3a072d118917957d6554Steve Block
2062bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_imageGenerator = 0;
2072bde8e466a4451c7319e3a072d118917957d6554Steve Block}
2082bde8e466a4451c7319e3a072d118917957d6554Steve Block
2092bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::createVideoLayer()
2102bde8e466a4451c7319e3a072d118917957d6554Steve Block{
2112bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_avPlayer)
2122bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
2132bde8e466a4451c7319e3a072d118917957d6554Steve Block
2142bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_videoLayer) {
2152bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_videoLayer.adoptNS([[AVPlayerLayer alloc] init]);
2162bde8e466a4451c7319e3a072d118917957d6554Steve Block        [m_videoLayer.get() setPlayer:m_avPlayer.get()];
2172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createVideoLayer(%p) - returning %p", this, m_videoLayer.get());
2182bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
2192bde8e466a4451c7319e3a072d118917957d6554Steve Block}
2202bde8e466a4451c7319e3a072d118917957d6554Steve Block
2212bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::destroyVideoLayer()
2222bde8e466a4451c7319e3a072d118917957d6554Steve Block{
2232bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_videoLayer)
2242bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
2252bde8e466a4451c7319e3a072d118917957d6554Steve Block
2262bde8e466a4451c7319e3a072d118917957d6554Steve Block    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::destroyVideoLayer(%p) - destroying", this, m_videoLayer.get());
2272bde8e466a4451c7319e3a072d118917957d6554Steve Block
2282bde8e466a4451c7319e3a072d118917957d6554Steve Block    [m_videoLayer.get() setPlayer:nil];
2292bde8e466a4451c7319e3a072d118917957d6554Steve Block
2302bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_videoLayer = 0;
2312bde8e466a4451c7319e3a072d118917957d6554Steve Block}
2322bde8e466a4451c7319e3a072d118917957d6554Steve Block
2332bde8e466a4451c7319e3a072d118917957d6554Steve Blockbool MediaPlayerPrivateAVFoundationObjC::videoLayerIsReadyToDisplay() const
2342bde8e466a4451c7319e3a072d118917957d6554Steve Block{
2352bde8e466a4451c7319e3a072d118917957d6554Steve Block    return (m_videoLayer && [m_videoLayer.get() isReadyForDisplay]);
2362bde8e466a4451c7319e3a072d118917957d6554Steve Block}
2372bde8e466a4451c7319e3a072d118917957d6554Steve Block
2382bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::createAVPlayerForURL(const String& url)
2392bde8e466a4451c7319e3a072d118917957d6554Steve Block{
2402bde8e466a4451c7319e3a072d118917957d6554Steve Block    setDelayCallbacks(true);
2412bde8e466a4451c7319e3a072d118917957d6554Steve Block
2422bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_avAsset) {
2432bde8e466a4451c7319e3a072d118917957d6554Steve Block        NSURL *cocoaURL = KURL(ParsedURLString, url);
2442bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_avAsset.adoptNS([[AVURLAsset alloc] initWithURL:cocoaURL options:nil]);
2452bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
2462bde8e466a4451c7319e3a072d118917957d6554Steve Block
2472bde8e466a4451c7319e3a072d118917957d6554Steve Block    createAVPlayer();
2482bde8e466a4451c7319e3a072d118917957d6554Steve Block}
2492bde8e466a4451c7319e3a072d118917957d6554Steve Block
2502bde8e466a4451c7319e3a072d118917957d6554Steve Block#if ENABLE(OFFLINE_WEB_APPLICATIONS)
2512bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::createAVPlayerForCacheResource(ApplicationCacheResource* resource)
2522bde8e466a4451c7319e3a072d118917957d6554Steve Block{
2532bde8e466a4451c7319e3a072d118917957d6554Steve Block    // AVFoundation can't open arbitrary data pointers, so if this ApplicationCacheResource doesn't
2542bde8e466a4451c7319e3a072d118917957d6554Steve Block    // have a valid local path, just open the resource's original URL.
2552bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (resource->path().isEmpty()) {
2562bde8e466a4451c7319e3a072d118917957d6554Steve Block        createAVPlayerForURL(resource->url());
2572bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
2582bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
2592bde8e466a4451c7319e3a072d118917957d6554Steve Block
2602bde8e466a4451c7319e3a072d118917957d6554Steve Block    setDelayCallbacks(true);
2612bde8e466a4451c7319e3a072d118917957d6554Steve Block
2622bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_avAsset) {
2632bde8e466a4451c7319e3a072d118917957d6554Steve Block        NSURL* localURL = [NSURL fileURLWithPath:resource->path()];
2642bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_avAsset.adoptNS([[AVURLAsset alloc] initWithURL:localURL options:nil]);
2652bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
2662bde8e466a4451c7319e3a072d118917957d6554Steve Block
2672bde8e466a4451c7319e3a072d118917957d6554Steve Block    createAVPlayer();
2682bde8e466a4451c7319e3a072d118917957d6554Steve Block}
2692bde8e466a4451c7319e3a072d118917957d6554Steve Block#endif
2702bde8e466a4451c7319e3a072d118917957d6554Steve Block
2712bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::createAVPlayer()
2722bde8e466a4451c7319e3a072d118917957d6554Steve Block{
2732bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_avPlayer) {
2742bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_avPlayer.adoptNS([[AVPlayer alloc] init]);
2752bde8e466a4451c7319e3a072d118917957d6554Steve Block
2762bde8e466a4451c7319e3a072d118917957d6554Steve Block        [m_avPlayer.get() addObserver:m_objcObserver.get() forKeyPath:@"rate" options:nil context:(void *)MediaPlayerAVFoundationObservationContextPlayer];
2772bde8e466a4451c7319e3a072d118917957d6554Steve Block
2782bde8e466a4451c7319e3a072d118917957d6554Steve Block        // Add a time observer, ask to be called infrequently because we don't really want periodic callbacks but
2792bde8e466a4451c7319e3a072d118917957d6554Steve Block        // our observer will also be called whenever a seek happens.
2802bde8e466a4451c7319e3a072d118917957d6554Steve Block        const double veryLongInterval = 60*60*60*24*30;
2812bde8e466a4451c7319e3a072d118917957d6554Steve Block        WebCoreAVFMovieObserver *observer = m_objcObserver.get();
2822bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_timeObserver = [m_avPlayer.get() addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(veryLongInterval, 10) queue:nil usingBlock:^(CMTime time){
2832bde8e466a4451c7319e3a072d118917957d6554Steve Block            [observer timeChanged:CMTimeGetSeconds(time)];
2842bde8e466a4451c7319e3a072d118917957d6554Steve Block        }];
2852bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
2862bde8e466a4451c7319e3a072d118917957d6554Steve Block
2872bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_avPlayerItem) {
2882bde8e466a4451c7319e3a072d118917957d6554Steve Block        // Create the player item so we can media data.
2892bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_avPlayerItem.adoptNS([[AVPlayerItem alloc] initWithAsset:m_avAsset.get()]);
2902bde8e466a4451c7319e3a072d118917957d6554Steve Block
2912bde8e466a4451c7319e3a072d118917957d6554Steve Block        [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()selector:@selector(didEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:m_avPlayerItem.get()];
2922bde8e466a4451c7319e3a072d118917957d6554Steve Block
2932bde8e466a4451c7319e3a072d118917957d6554Steve Block        for (NSString *keyName in itemKVOProperties())
2942bde8e466a4451c7319e3a072d118917957d6554Steve Block            [m_avPlayerItem.get() addObserver:m_objcObserver.get() forKeyPath:keyName options:nil context:(void *)MediaPlayerAVFoundationObservationContextPlayerItem];
2952bde8e466a4451c7319e3a072d118917957d6554Steve Block
2962bde8e466a4451c7319e3a072d118917957d6554Steve Block        [m_avPlayer.get() replaceCurrentItemWithPlayerItem:m_avPlayerItem.get()];
2972bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
2982bde8e466a4451c7319e3a072d118917957d6554Steve Block
2992bde8e466a4451c7319e3a072d118917957d6554Steve Block    setDelayCallbacks(false);
3002bde8e466a4451c7319e3a072d118917957d6554Steve Block}
3012bde8e466a4451c7319e3a072d118917957d6554Steve Block
3022bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::checkPlayability()
3032bde8e466a4451c7319e3a072d118917957d6554Steve Block{
3042bde8e466a4451c7319e3a072d118917957d6554Steve Block    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::checkPlayability(%p)", this);
3052bde8e466a4451c7319e3a072d118917957d6554Steve Block
3062bde8e466a4451c7319e3a072d118917957d6554Steve Block    [m_avAsset.get() loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:@"playable"] completionHandler:^{
3072bde8e466a4451c7319e3a072d118917957d6554Steve Block        [m_objcObserver.get() playableKnown];
3082bde8e466a4451c7319e3a072d118917957d6554Steve Block    }];
3092bde8e466a4451c7319e3a072d118917957d6554Steve Block}
3102bde8e466a4451c7319e3a072d118917957d6554Steve Block
3112bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::beginLoadingMetadata()
3122bde8e466a4451c7319e3a072d118917957d6554Steve Block{
3132bde8e466a4451c7319e3a072d118917957d6554Steve Block    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::playabilityKnown(%p) - requesting metadata loading", this);
3142bde8e466a4451c7319e3a072d118917957d6554Steve Block    [m_avAsset.get() loadValuesAsynchronouslyForKeys:[assetMetadataKeyNames() retain] completionHandler:^{
3152bde8e466a4451c7319e3a072d118917957d6554Steve Block        [m_objcObserver.get() metadataLoaded];
3162bde8e466a4451c7319e3a072d118917957d6554Steve Block    }];
3172bde8e466a4451c7319e3a072d118917957d6554Steve Block}
3182bde8e466a4451c7319e3a072d118917957d6554Steve Block
3192bde8e466a4451c7319e3a072d118917957d6554Steve BlockMediaPlayerPrivateAVFoundation::ItemStatus MediaPlayerPrivateAVFoundationObjC::playerItemStatus() const
3202bde8e466a4451c7319e3a072d118917957d6554Steve Block{
3212bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_avPlayerItem)
3222bde8e466a4451c7319e3a072d118917957d6554Steve Block        return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusUnknown;
3232bde8e466a4451c7319e3a072d118917957d6554Steve Block
3242bde8e466a4451c7319e3a072d118917957d6554Steve Block    AVPlayerItemStatus status = [m_avPlayerItem.get() status];
3252bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (status == AVPlayerItemStatusUnknown)
3262bde8e466a4451c7319e3a072d118917957d6554Steve Block        return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusUnknown;
3272bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (status == AVPlayerItemStatusFailed)
3282bde8e466a4451c7319e3a072d118917957d6554Steve Block        return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusFailed;
3292bde8e466a4451c7319e3a072d118917957d6554Steve Block    if ([m_avPlayerItem.get() isPlaybackLikelyToKeepUp])
3302bde8e466a4451c7319e3a072d118917957d6554Steve Block        return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp;
3312daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (buffered()->contain(duration()))
3322bde8e466a4451c7319e3a072d118917957d6554Steve Block        return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferFull;
3332daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (buffered()->contain(currentTime()))
3342bde8e466a4451c7319e3a072d118917957d6554Steve Block        return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty;
3352bde8e466a4451c7319e3a072d118917957d6554Steve Block
3362bde8e466a4451c7319e3a072d118917957d6554Steve Block    return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusReadyToPlay;
3372bde8e466a4451c7319e3a072d118917957d6554Steve Block}
3382bde8e466a4451c7319e3a072d118917957d6554Steve Block
3392bde8e466a4451c7319e3a072d118917957d6554Steve BlockPlatformMedia MediaPlayerPrivateAVFoundationObjC::platformMedia() const
3402bde8e466a4451c7319e3a072d118917957d6554Steve Block{
3412bde8e466a4451c7319e3a072d118917957d6554Steve Block    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::platformMedia(%p)", this);
3422bde8e466a4451c7319e3a072d118917957d6554Steve Block    PlatformMedia pm;
3432bde8e466a4451c7319e3a072d118917957d6554Steve Block    pm.type = PlatformMedia::AVFoundationMediaPlayerType;
3442bde8e466a4451c7319e3a072d118917957d6554Steve Block    pm.media.avfMediaPlayer = m_avPlayer.get();
3452bde8e466a4451c7319e3a072d118917957d6554Steve Block    return pm;
3462bde8e466a4451c7319e3a072d118917957d6554Steve Block}
3472bde8e466a4451c7319e3a072d118917957d6554Steve Block
3482bde8e466a4451c7319e3a072d118917957d6554Steve BlockPlatformLayer* MediaPlayerPrivateAVFoundationObjC::platformLayer() const
3492bde8e466a4451c7319e3a072d118917957d6554Steve Block{
3502bde8e466a4451c7319e3a072d118917957d6554Steve Block    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::platformLayer(%p)", this);
3512bde8e466a4451c7319e3a072d118917957d6554Steve Block    return m_videoLayer.get();
3522bde8e466a4451c7319e3a072d118917957d6554Steve Block}
3532bde8e466a4451c7319e3a072d118917957d6554Steve Block
3542daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochvoid MediaPlayerPrivateAVFoundationObjC::platformPlay()
3552bde8e466a4451c7319e3a072d118917957d6554Steve Block{
3562daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::platformPlay(%p)", this);
3572bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!metaDataAvailable())
3582bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
3592bde8e466a4451c7319e3a072d118917957d6554Steve Block
3602bde8e466a4451c7319e3a072d118917957d6554Steve Block    setDelayCallbacks(true);
3612bde8e466a4451c7319e3a072d118917957d6554Steve Block    [m_avPlayer.get() setRate:requestedRate()];
3622bde8e466a4451c7319e3a072d118917957d6554Steve Block    setDelayCallbacks(false);
3632bde8e466a4451c7319e3a072d118917957d6554Steve Block}
3642bde8e466a4451c7319e3a072d118917957d6554Steve Block
3652daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochvoid MediaPlayerPrivateAVFoundationObjC::platformPause()
3662bde8e466a4451c7319e3a072d118917957d6554Steve Block{
3672daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::platformPause(%p)", this);
3682bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!metaDataAvailable())
3692bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
3702bde8e466a4451c7319e3a072d118917957d6554Steve Block
3712bde8e466a4451c7319e3a072d118917957d6554Steve Block    setDelayCallbacks(true);
3722bde8e466a4451c7319e3a072d118917957d6554Steve Block    [m_avPlayer.get() setRate:nil];
3732bde8e466a4451c7319e3a072d118917957d6554Steve Block    setDelayCallbacks(false);
3742bde8e466a4451c7319e3a072d118917957d6554Steve Block}
3752bde8e466a4451c7319e3a072d118917957d6554Steve Block
3762bde8e466a4451c7319e3a072d118917957d6554Steve Blockfloat MediaPlayerPrivateAVFoundationObjC::platformDuration() const
3772bde8e466a4451c7319e3a072d118917957d6554Steve Block{
3782bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!metaDataAvailable() || !m_avPlayerItem)
3792bde8e466a4451c7319e3a072d118917957d6554Steve Block        return 0;
3802bde8e466a4451c7319e3a072d118917957d6554Steve Block
3812bde8e466a4451c7319e3a072d118917957d6554Steve Block    float duration;
3822bde8e466a4451c7319e3a072d118917957d6554Steve Block    CMTime cmDuration = [m_avPlayerItem.get() duration];
3832bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (CMTIME_IS_NUMERIC(cmDuration))
3842bde8e466a4451c7319e3a072d118917957d6554Steve Block        duration = narrowPrecisionToFloat(CMTimeGetSeconds(cmDuration));
3852bde8e466a4451c7319e3a072d118917957d6554Steve Block    else if (CMTIME_IS_INDEFINITE(cmDuration))
3862bde8e466a4451c7319e3a072d118917957d6554Steve Block        duration = numeric_limits<float>::infinity();
3872bde8e466a4451c7319e3a072d118917957d6554Steve Block    else {
3882bde8e466a4451c7319e3a072d118917957d6554Steve Block        LOG(Media, "MediaPlayerPrivateAVFoundationObjC::duration(%p) - invalid duration, returning 0", this);
3892bde8e466a4451c7319e3a072d118917957d6554Steve Block        return 0;
3902bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
3912bde8e466a4451c7319e3a072d118917957d6554Steve Block
3922bde8e466a4451c7319e3a072d118917957d6554Steve Block    return duration;
3932bde8e466a4451c7319e3a072d118917957d6554Steve Block}
3942bde8e466a4451c7319e3a072d118917957d6554Steve Block
3952bde8e466a4451c7319e3a072d118917957d6554Steve Blockfloat MediaPlayerPrivateAVFoundationObjC::currentTime() const
3962bde8e466a4451c7319e3a072d118917957d6554Steve Block{
3972bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!metaDataAvailable() || !m_avPlayerItem)
3982bde8e466a4451c7319e3a072d118917957d6554Steve Block        return 0;
3992bde8e466a4451c7319e3a072d118917957d6554Steve Block
4002bde8e466a4451c7319e3a072d118917957d6554Steve Block    CMTime itemTime = [m_avPlayerItem.get() currentTime];
4012bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (CMTIME_IS_NUMERIC(itemTime))
4022bde8e466a4451c7319e3a072d118917957d6554Steve Block        return narrowPrecisionToFloat(CMTimeGetSeconds(itemTime));
4032bde8e466a4451c7319e3a072d118917957d6554Steve Block
4042bde8e466a4451c7319e3a072d118917957d6554Steve Block    return 0;
4052bde8e466a4451c7319e3a072d118917957d6554Steve Block}
4062bde8e466a4451c7319e3a072d118917957d6554Steve Block
4072bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::seekToTime(float time)
4082bde8e466a4451c7319e3a072d118917957d6554Steve Block{
4092bde8e466a4451c7319e3a072d118917957d6554Steve Block    // setCurrentTime generates several event callbacks, update afterwards.
4102bde8e466a4451c7319e3a072d118917957d6554Steve Block    setDelayCallbacks(true);
4112bde8e466a4451c7319e3a072d118917957d6554Steve Block
4122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    WebCoreAVFMovieObserver *observer = m_objcObserver.get();
4132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    [m_avPlayerItem.get() seekToTime:CMTimeMakeWithSeconds(time, 600) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
4142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        [observer seekCompleted:finished];
4152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    }];
4162bde8e466a4451c7319e3a072d118917957d6554Steve Block
4172bde8e466a4451c7319e3a072d118917957d6554Steve Block    setDelayCallbacks(false);
4182bde8e466a4451c7319e3a072d118917957d6554Steve Block}
4192bde8e466a4451c7319e3a072d118917957d6554Steve Block
4202bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::setVolume(float volume)
4212bde8e466a4451c7319e3a072d118917957d6554Steve Block{
4222bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!metaDataAvailable())
4232bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
4242bde8e466a4451c7319e3a072d118917957d6554Steve Block
4252bde8e466a4451c7319e3a072d118917957d6554Steve Block    [m_avPlayer.get() setVolume:volume];
4262bde8e466a4451c7319e3a072d118917957d6554Steve Block}
4272bde8e466a4451c7319e3a072d118917957d6554Steve Block
4282bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::setClosedCaptionsVisible(bool closedCaptionsVisible)
4292bde8e466a4451c7319e3a072d118917957d6554Steve Block{
4302bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!metaDataAvailable())
4312bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
4322bde8e466a4451c7319e3a072d118917957d6554Steve Block
4332bde8e466a4451c7319e3a072d118917957d6554Steve Block    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::setClosedCaptionsVisible(%p) - setting to %s", this, boolString(closedCaptionsVisible));
4342bde8e466a4451c7319e3a072d118917957d6554Steve Block    [m_avPlayer.get() setClosedCaptionDisplayEnabled:closedCaptionsVisible];
4352bde8e466a4451c7319e3a072d118917957d6554Steve Block}
4362bde8e466a4451c7319e3a072d118917957d6554Steve Block
4372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochvoid MediaPlayerPrivateAVFoundationObjC::updateRate()
4382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
4392daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    setDelayCallbacks(true);
4402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    [m_avPlayer.get() setRate:requestedRate()];
4412daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    setDelayCallbacks(false);
4422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
4432daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
4442bde8e466a4451c7319e3a072d118917957d6554Steve Blockfloat MediaPlayerPrivateAVFoundationObjC::rate() const
4452bde8e466a4451c7319e3a072d118917957d6554Steve Block{
4462bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!metaDataAvailable())
4472bde8e466a4451c7319e3a072d118917957d6554Steve Block        return 0;
4482bde8e466a4451c7319e3a072d118917957d6554Steve Block
4492bde8e466a4451c7319e3a072d118917957d6554Steve Block    return [m_avPlayer.get() rate];
4502bde8e466a4451c7319e3a072d118917957d6554Steve Block}
4512bde8e466a4451c7319e3a072d118917957d6554Steve Block
4522bde8e466a4451c7319e3a072d118917957d6554Steve BlockPassRefPtr<TimeRanges> MediaPlayerPrivateAVFoundationObjC::platformBufferedTimeRanges() const
4532bde8e466a4451c7319e3a072d118917957d6554Steve Block{
4542bde8e466a4451c7319e3a072d118917957d6554Steve Block    RefPtr<TimeRanges> timeRanges = TimeRanges::create();
4552bde8e466a4451c7319e3a072d118917957d6554Steve Block
4562bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_avPlayerItem)
4572bde8e466a4451c7319e3a072d118917957d6554Steve Block        return timeRanges.release();
4582bde8e466a4451c7319e3a072d118917957d6554Steve Block
4592bde8e466a4451c7319e3a072d118917957d6554Steve Block    NSArray *loadedRanges = [m_avPlayerItem.get() loadedTimeRanges];
4602bde8e466a4451c7319e3a072d118917957d6554Steve Block    for (NSValue *thisRangeValue in loadedRanges) {
4612bde8e466a4451c7319e3a072d118917957d6554Steve Block        CMTimeRange timeRange = [thisRangeValue CMTimeRangeValue];
4622bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (CMTIMERANGE_IS_VALID(timeRange) && !CMTIMERANGE_IS_EMPTY(timeRange)) {
4632bde8e466a4451c7319e3a072d118917957d6554Steve Block            float rangeStart = narrowPrecisionToFloat(CMTimeGetSeconds(timeRange.start));
4642bde8e466a4451c7319e3a072d118917957d6554Steve Block            float rangeEnd = narrowPrecisionToFloat(CMTimeGetSeconds(CMTimeRangeGetEnd(timeRange)));
4652bde8e466a4451c7319e3a072d118917957d6554Steve Block            timeRanges->add(rangeStart, rangeEnd);
4662bde8e466a4451c7319e3a072d118917957d6554Steve Block        }
4672bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
4682bde8e466a4451c7319e3a072d118917957d6554Steve Block    return timeRanges.release();
4692bde8e466a4451c7319e3a072d118917957d6554Steve Block}
4702bde8e466a4451c7319e3a072d118917957d6554Steve Block
4712bde8e466a4451c7319e3a072d118917957d6554Steve Blockfloat MediaPlayerPrivateAVFoundationObjC::platformMaxTimeSeekable() const
4722bde8e466a4451c7319e3a072d118917957d6554Steve Block{
4732bde8e466a4451c7319e3a072d118917957d6554Steve Block    NSArray *seekableRanges = [m_avPlayerItem.get() seekableTimeRanges];
4742bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!seekableRanges)
4752bde8e466a4451c7319e3a072d118917957d6554Steve Block        return 0;
4762bde8e466a4451c7319e3a072d118917957d6554Steve Block
4772bde8e466a4451c7319e3a072d118917957d6554Steve Block    float maxTimeSeekable = 0;
4782bde8e466a4451c7319e3a072d118917957d6554Steve Block    for (NSValue *thisRangeValue in seekableRanges) {
4792bde8e466a4451c7319e3a072d118917957d6554Steve Block        CMTimeRange timeRange = [thisRangeValue CMTimeRangeValue];
4802bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (!CMTIMERANGE_IS_VALID(timeRange) || CMTIMERANGE_IS_EMPTY(timeRange))
4812bde8e466a4451c7319e3a072d118917957d6554Steve Block            continue;
4822bde8e466a4451c7319e3a072d118917957d6554Steve Block
4832bde8e466a4451c7319e3a072d118917957d6554Steve Block        float endOfRange = narrowPrecisionToFloat(CMTimeGetSeconds(CMTimeRangeGetEnd(timeRange)));
4842bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (maxTimeSeekable < endOfRange)
4852bde8e466a4451c7319e3a072d118917957d6554Steve Block            maxTimeSeekable = endOfRange;
4862bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
4872bde8e466a4451c7319e3a072d118917957d6554Steve Block    return maxTimeSeekable;
4882bde8e466a4451c7319e3a072d118917957d6554Steve Block}
4892bde8e466a4451c7319e3a072d118917957d6554Steve Block
4902bde8e466a4451c7319e3a072d118917957d6554Steve Blockfloat MediaPlayerPrivateAVFoundationObjC::platformMaxTimeLoaded() const
4912bde8e466a4451c7319e3a072d118917957d6554Steve Block{
4922bde8e466a4451c7319e3a072d118917957d6554Steve Block    NSArray *loadedRanges = [m_avPlayerItem.get() loadedTimeRanges];
4932bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!loadedRanges)
4942bde8e466a4451c7319e3a072d118917957d6554Steve Block        return 0;
4952bde8e466a4451c7319e3a072d118917957d6554Steve Block
4962bde8e466a4451c7319e3a072d118917957d6554Steve Block    float maxTimeLoaded = 0;
4972bde8e466a4451c7319e3a072d118917957d6554Steve Block    for (NSValue *thisRangeValue in loadedRanges) {
4982bde8e466a4451c7319e3a072d118917957d6554Steve Block        CMTimeRange timeRange = [thisRangeValue CMTimeRangeValue];
4992bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (!CMTIMERANGE_IS_VALID(timeRange) || CMTIMERANGE_IS_EMPTY(timeRange))
5002bde8e466a4451c7319e3a072d118917957d6554Steve Block            continue;
5012bde8e466a4451c7319e3a072d118917957d6554Steve Block
5022bde8e466a4451c7319e3a072d118917957d6554Steve Block        float endOfRange = narrowPrecisionToFloat(CMTimeGetSeconds(CMTimeRangeGetEnd(timeRange)));
5032bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (maxTimeLoaded < endOfRange)
5042bde8e466a4451c7319e3a072d118917957d6554Steve Block            maxTimeLoaded = endOfRange;
5052bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
5062bde8e466a4451c7319e3a072d118917957d6554Steve Block
5072bde8e466a4451c7319e3a072d118917957d6554Steve Block    return maxTimeLoaded;
5082bde8e466a4451c7319e3a072d118917957d6554Steve Block}
5092bde8e466a4451c7319e3a072d118917957d6554Steve Block
5102bde8e466a4451c7319e3a072d118917957d6554Steve Blockunsigned MediaPlayerPrivateAVFoundationObjC::totalBytes() const
5112bde8e466a4451c7319e3a072d118917957d6554Steve Block{
5122bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!metaDataAvailable())
5132bde8e466a4451c7319e3a072d118917957d6554Steve Block        return 0;
5142bde8e466a4451c7319e3a072d118917957d6554Steve Block
5152bde8e466a4451c7319e3a072d118917957d6554Steve Block    long long totalMediaSize = 0;
5162bde8e466a4451c7319e3a072d118917957d6554Steve Block    NSArray *tracks = [m_avAsset.get() tracks];
5172bde8e466a4451c7319e3a072d118917957d6554Steve Block    for (AVAssetTrack *thisTrack in tracks)
5182bde8e466a4451c7319e3a072d118917957d6554Steve Block        totalMediaSize += [thisTrack totalSampleDataLength];
5192bde8e466a4451c7319e3a072d118917957d6554Steve Block
5202bde8e466a4451c7319e3a072d118917957d6554Steve Block    return static_cast<unsigned>(totalMediaSize);
5212bde8e466a4451c7319e3a072d118917957d6554Steve Block}
5222bde8e466a4451c7319e3a072d118917957d6554Steve Block
5232bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::setAsset(id asset)
5242bde8e466a4451c7319e3a072d118917957d6554Steve Block{
5252bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_avAsset = asset;
5262bde8e466a4451c7319e3a072d118917957d6554Steve Block}
5272bde8e466a4451c7319e3a072d118917957d6554Steve Block
5282bde8e466a4451c7319e3a072d118917957d6554Steve BlockMediaPlayerPrivateAVFoundation::AVAssetStatus MediaPlayerPrivateAVFoundationObjC::assetStatus() const
5292bde8e466a4451c7319e3a072d118917957d6554Steve Block{
5302bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_avAsset)
5312bde8e466a4451c7319e3a072d118917957d6554Steve Block        return MediaPlayerAVAssetStatusUnknown;
5322bde8e466a4451c7319e3a072d118917957d6554Steve Block
5332bde8e466a4451c7319e3a072d118917957d6554Steve Block    for (NSString *keyName in assetMetadataKeyNames()) {
5342bde8e466a4451c7319e3a072d118917957d6554Steve Block        AVKeyValueStatus keyStatus = [m_avAsset.get() statusOfValueForKey:keyName error:nil];
5352bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (keyStatus < AVKeyValueStatusLoaded)
5362bde8e466a4451c7319e3a072d118917957d6554Steve Block            return MediaPlayerAVAssetStatusLoading;// At least one key is not loaded yet.
5372bde8e466a4451c7319e3a072d118917957d6554Steve Block
5382bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (keyStatus == AVKeyValueStatusFailed)
5392bde8e466a4451c7319e3a072d118917957d6554Steve Block            return MediaPlayerAVAssetStatusFailed; // At least one key could not be loaded.
5402bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (keyStatus == AVKeyValueStatusCancelled)
5412bde8e466a4451c7319e3a072d118917957d6554Steve Block            return MediaPlayerAVAssetStatusCancelled; // Loading of at least one key was cancelled.
5422bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
5432bde8e466a4451c7319e3a072d118917957d6554Steve Block
5442bde8e466a4451c7319e3a072d118917957d6554Steve Block    if ([[m_avAsset.get() valueForKey:@"playable"] boolValue])
5452bde8e466a4451c7319e3a072d118917957d6554Steve Block        return MediaPlayerAVAssetStatusPlayable;
5462bde8e466a4451c7319e3a072d118917957d6554Steve Block
5472bde8e466a4451c7319e3a072d118917957d6554Steve Block    return MediaPlayerAVAssetStatusLoaded;
5482bde8e466a4451c7319e3a072d118917957d6554Steve Block}
5492bde8e466a4451c7319e3a072d118917957d6554Steve Block
5502bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& rect)
5512bde8e466a4451c7319e3a072d118917957d6554Steve Block{
5522bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!metaDataAvailable() || context->paintingDisabled())
5532bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
5542bde8e466a4451c7319e3a072d118917957d6554Steve Block
5552bde8e466a4451c7319e3a072d118917957d6554Steve Block    paint(context, rect);
5562bde8e466a4451c7319e3a072d118917957d6554Steve Block}
5572bde8e466a4451c7319e3a072d118917957d6554Steve Block
5582bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::paint(GraphicsContext* context, const IntRect& rect)
5592bde8e466a4451c7319e3a072d118917957d6554Steve Block{
5602bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!metaDataAvailable() || context->paintingDisabled())
5612bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
5622bde8e466a4451c7319e3a072d118917957d6554Steve Block
5632bde8e466a4451c7319e3a072d118917957d6554Steve Block    setDelayCallbacks(true);
5642bde8e466a4451c7319e3a072d118917957d6554Steve Block    BEGIN_BLOCK_OBJC_EXCEPTIONS;
5652bde8e466a4451c7319e3a072d118917957d6554Steve Block
5662bde8e466a4451c7319e3a072d118917957d6554Steve Block    RetainPtr<CGImageRef> image = createImageForTimeInRect(currentTime(), rect);
5672bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (image) {
5682bde8e466a4451c7319e3a072d118917957d6554Steve Block        context->save();
5692bde8e466a4451c7319e3a072d118917957d6554Steve Block        context->translate(rect.x(), rect.y() + rect.height());
5702bde8e466a4451c7319e3a072d118917957d6554Steve Block        context->scale(FloatSize(1.0f, -1.0f));
5712bde8e466a4451c7319e3a072d118917957d6554Steve Block        context->setImageInterpolationQuality(InterpolationLow);
5722bde8e466a4451c7319e3a072d118917957d6554Steve Block        IntRect paintRect(IntPoint(0, 0), IntSize(rect.width(), rect.height()));
5732bde8e466a4451c7319e3a072d118917957d6554Steve Block        CGContextDrawImage(context->platformContext(), CGRectMake(0, 0, paintRect.width(), paintRect.height()), image.get());
5742bde8e466a4451c7319e3a072d118917957d6554Steve Block        context->restore();
5752bde8e466a4451c7319e3a072d118917957d6554Steve Block        image = 0;
5762bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
5772bde8e466a4451c7319e3a072d118917957d6554Steve Block
5782bde8e466a4451c7319e3a072d118917957d6554Steve Block    END_BLOCK_OBJC_EXCEPTIONS;
5792bde8e466a4451c7319e3a072d118917957d6554Steve Block    setDelayCallbacks(false);
5802bde8e466a4451c7319e3a072d118917957d6554Steve Block
5812bde8e466a4451c7319e3a072d118917957d6554Steve Block    MediaPlayerPrivateAVFoundation::paint(context, rect);
5822bde8e466a4451c7319e3a072d118917957d6554Steve Block}
5832bde8e466a4451c7319e3a072d118917957d6554Steve Block
5842bde8e466a4451c7319e3a072d118917957d6554Steve Blockstatic HashSet<String> mimeTypeCache()
5852bde8e466a4451c7319e3a072d118917957d6554Steve Block{
5862bde8e466a4451c7319e3a072d118917957d6554Steve Block    DEFINE_STATIC_LOCAL(HashSet<String>, cache, ());
5872bde8e466a4451c7319e3a072d118917957d6554Steve Block    static bool typeListInitialized = false;
5882bde8e466a4451c7319e3a072d118917957d6554Steve Block
5892bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (typeListInitialized)
5902bde8e466a4451c7319e3a072d118917957d6554Steve Block        return cache;
5912bde8e466a4451c7319e3a072d118917957d6554Steve Block    typeListInitialized = true;
5922bde8e466a4451c7319e3a072d118917957d6554Steve Block
5932bde8e466a4451c7319e3a072d118917957d6554Steve Block    NSArray *types = [AVURLAsset audiovisualMIMETypes];
5942bde8e466a4451c7319e3a072d118917957d6554Steve Block    for (NSString *mimeType in types)
5952bde8e466a4451c7319e3a072d118917957d6554Steve Block        cache.add(mimeType);
5962bde8e466a4451c7319e3a072d118917957d6554Steve Block
5972bde8e466a4451c7319e3a072d118917957d6554Steve Block    return cache;
5982bde8e466a4451c7319e3a072d118917957d6554Steve Block}
5992bde8e466a4451c7319e3a072d118917957d6554Steve Block
6002bde8e466a4451c7319e3a072d118917957d6554Steve BlockRetainPtr<CGImageRef> MediaPlayerPrivateAVFoundationObjC::createImageForTimeInRect(float time, const IntRect& rect)
6012bde8e466a4451c7319e3a072d118917957d6554Steve Block{
6022bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_imageGenerator)
6032bde8e466a4451c7319e3a072d118917957d6554Steve Block        createContextVideoRenderer();
6042bde8e466a4451c7319e3a072d118917957d6554Steve Block    ASSERT(m_imageGenerator);
6052bde8e466a4451c7319e3a072d118917957d6554Steve Block
6062bde8e466a4451c7319e3a072d118917957d6554Steve Block#if !LOG_DISABLED
6072bde8e466a4451c7319e3a072d118917957d6554Steve Block    double start = WTF::currentTime();
6082bde8e466a4451c7319e3a072d118917957d6554Steve Block#endif
6092bde8e466a4451c7319e3a072d118917957d6554Steve Block
6102bde8e466a4451c7319e3a072d118917957d6554Steve Block    [m_imageGenerator.get() setMaximumSize:CGSize(rect.size())];
6112bde8e466a4451c7319e3a072d118917957d6554Steve Block    CGImageRef image = [m_imageGenerator.get() copyCGImageAtTime:CMTimeMakeWithSeconds(time, 600) actualTime:nil error:nil];
6122bde8e466a4451c7319e3a072d118917957d6554Steve Block
6132bde8e466a4451c7319e3a072d118917957d6554Steve Block#if !LOG_DISABLED
6142bde8e466a4451c7319e3a072d118917957d6554Steve Block    double duration = WTF::currentTime() - start;
6152bde8e466a4451c7319e3a072d118917957d6554Steve Block    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createImageForTimeInRect(%p) - creating image took %.4f", this, narrowPrecisionToFloat(duration));
6162bde8e466a4451c7319e3a072d118917957d6554Steve Block#endif
6172bde8e466a4451c7319e3a072d118917957d6554Steve Block
6182bde8e466a4451c7319e3a072d118917957d6554Steve Block    return image;
6192bde8e466a4451c7319e3a072d118917957d6554Steve Block}
6202bde8e466a4451c7319e3a072d118917957d6554Steve Block
6212bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::getSupportedTypes(HashSet<String>& supportedTypes)
6222bde8e466a4451c7319e3a072d118917957d6554Steve Block{
6232bde8e466a4451c7319e3a072d118917957d6554Steve Block    supportedTypes = mimeTypeCache();
6242bde8e466a4451c7319e3a072d118917957d6554Steve Block}
6252bde8e466a4451c7319e3a072d118917957d6554Steve Block
6262bde8e466a4451c7319e3a072d118917957d6554Steve BlockMediaPlayer::SupportsType MediaPlayerPrivateAVFoundationObjC::supportsType(const String& type, const String& codecs)
6272bde8e466a4451c7319e3a072d118917957d6554Steve Block{
6282daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (!mimeTypeCache().contains(type))
6292daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return MediaPlayer::IsNotSupported;
6302daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
6312daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // The spec says:
6322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // "Implementors are encouraged to return "maybe" unless the type can be confidently established as being supported or not."
6332daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (codecs.isEmpty())
6342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return MediaPlayer::MayBeSupported;
6352bde8e466a4451c7319e3a072d118917957d6554Steve Block
6362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    NSString *typeString = [NSString stringWithFormat:@"%@; codecs=\"%@\"", (NSString *)type, (NSString *)codecs];
6372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return [AVURLAsset isPlayableExtendedMIMEType:typeString] ? MediaPlayer::IsSupported : MediaPlayer::MayBeSupported;;
6382bde8e466a4451c7319e3a072d118917957d6554Steve Block}
6392bde8e466a4451c7319e3a072d118917957d6554Steve Block
6402bde8e466a4451c7319e3a072d118917957d6554Steve Blockbool MediaPlayerPrivateAVFoundationObjC::isAvailable()
6412bde8e466a4451c7319e3a072d118917957d6554Steve Block{
6422bde8e466a4451c7319e3a072d118917957d6554Steve Block    return true;
6432bde8e466a4451c7319e3a072d118917957d6554Steve Block}
6442bde8e466a4451c7319e3a072d118917957d6554Steve Block
6452bde8e466a4451c7319e3a072d118917957d6554Steve Blockfloat MediaPlayerPrivateAVFoundationObjC::mediaTimeForTimeValue(float timeValue) const
6462bde8e466a4451c7319e3a072d118917957d6554Steve Block{
6472bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!metaDataAvailable())
6482bde8e466a4451c7319e3a072d118917957d6554Steve Block        return timeValue;
6492bde8e466a4451c7319e3a072d118917957d6554Steve Block
6502bde8e466a4451c7319e3a072d118917957d6554Steve Block    // FIXME - impossible to implement until rdar://8721510 is fixed.
6512bde8e466a4451c7319e3a072d118917957d6554Steve Block    return timeValue;
6522bde8e466a4451c7319e3a072d118917957d6554Steve Block}
6532bde8e466a4451c7319e3a072d118917957d6554Steve Block
6542bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::tracksChanged()
6552bde8e466a4451c7319e3a072d118917957d6554Steve Block{
6562bde8e466a4451c7319e3a072d118917957d6554Steve Block    // This is called whenever the tracks collection changes so cache hasVideo and hasAudio since we get
6572bde8e466a4451c7319e3a072d118917957d6554Steve Block    // asked about those fairly fequently.
6582bde8e466a4451c7319e3a072d118917957d6554Steve Block    setHasVideo([[m_avAsset.get() tracksWithMediaCharacteristic:AVMediaCharacteristicVisual] count]);
6592bde8e466a4451c7319e3a072d118917957d6554Steve Block    setHasAudio([[m_avAsset.get() tracksWithMediaCharacteristic:AVMediaCharacteristicAudible] count]);
6602bde8e466a4451c7319e3a072d118917957d6554Steve Block    setHasClosedCaptions([[m_avAsset.get() tracksWithMediaType:AVMediaTypeClosedCaption] count]);
6612bde8e466a4451c7319e3a072d118917957d6554Steve Block
6622bde8e466a4451c7319e3a072d118917957d6554Steve Block    sizeChanged();
6632bde8e466a4451c7319e3a072d118917957d6554Steve Block}
6642bde8e466a4451c7319e3a072d118917957d6554Steve Block
6652bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid MediaPlayerPrivateAVFoundationObjC::sizeChanged()
6662bde8e466a4451c7319e3a072d118917957d6554Steve Block{
6672bde8e466a4451c7319e3a072d118917957d6554Steve Block    NSArray *tracks = [m_avAsset.get() tracks];
6682bde8e466a4451c7319e3a072d118917957d6554Steve Block
6692bde8e466a4451c7319e3a072d118917957d6554Steve Block    // Some assets don't report track properties until they are completely ready to play, but we
6702bde8e466a4451c7319e3a072d118917957d6554Steve Block    // want to report a size as early as possible so use presentationSize when an asset has no tracks.
6712bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (![tracks count]) {
6722bde8e466a4451c7319e3a072d118917957d6554Steve Block        setNaturalSize(IntSize([m_avPlayerItem.get() presentationSize]));
6732bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
6742bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
6752bde8e466a4451c7319e3a072d118917957d6554Steve Block
6762bde8e466a4451c7319e3a072d118917957d6554Steve Block    // AVAsset's 'naturalSize' property only considers the movie's first video track, so we need to compute
6772bde8e466a4451c7319e3a072d118917957d6554Steve Block    // the union of all visual track rects.
6782bde8e466a4451c7319e3a072d118917957d6554Steve Block    CGRect trackUnionRect = CGRectZero;
6792bde8e466a4451c7319e3a072d118917957d6554Steve Block    for (AVAssetTrack *track in tracks) {
6802bde8e466a4451c7319e3a072d118917957d6554Steve Block        CGSize trackSize = [track naturalSize];
6812bde8e466a4451c7319e3a072d118917957d6554Steve Block        CGRect trackRect = CGRectMake(0, 0, trackSize.width, trackSize.height);
6822bde8e466a4451c7319e3a072d118917957d6554Steve Block        trackUnionRect = CGRectUnion(trackUnionRect, CGRectApplyAffineTransform(trackRect, [track preferredTransform]));
6832bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
6842bde8e466a4451c7319e3a072d118917957d6554Steve Block
6852bde8e466a4451c7319e3a072d118917957d6554Steve Block    // The movie is always displayed at 0,0 so move the track rect to the origin before using width and height.
6862bde8e466a4451c7319e3a072d118917957d6554Steve Block    trackUnionRect = CGRectOffset(trackUnionRect, trackUnionRect.origin.x, trackUnionRect.origin.y);
6872bde8e466a4451c7319e3a072d118917957d6554Steve Block
6882bde8e466a4451c7319e3a072d118917957d6554Steve Block    // Also look at the asset's preferred transform so we account for a movie matrix.
6892bde8e466a4451c7319e3a072d118917957d6554Steve Block    CGSize naturalSize = CGSizeApplyAffineTransform(trackUnionRect.size, [m_avAsset.get() preferredTransform]);
6902bde8e466a4451c7319e3a072d118917957d6554Steve Block
6912bde8e466a4451c7319e3a072d118917957d6554Steve Block    // Cache the natural size (setNaturalSize will notify the player if it has changed).
6922bde8e466a4451c7319e3a072d118917957d6554Steve Block    setNaturalSize(IntSize(naturalSize));
6932bde8e466a4451c7319e3a072d118917957d6554Steve Block}
6942bde8e466a4451c7319e3a072d118917957d6554Steve Block
6952bde8e466a4451c7319e3a072d118917957d6554Steve BlockNSArray* assetMetadataKeyNames()
6962bde8e466a4451c7319e3a072d118917957d6554Steve Block{
6972bde8e466a4451c7319e3a072d118917957d6554Steve Block    static NSArray* keys;
6982bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!keys) {
6992bde8e466a4451c7319e3a072d118917957d6554Steve Block        keys = [[NSArray alloc] initWithObjects:@"duration",
7002bde8e466a4451c7319e3a072d118917957d6554Steve Block                    @"naturalSize",
7012bde8e466a4451c7319e3a072d118917957d6554Steve Block                    @"preferredTransform",
7022bde8e466a4451c7319e3a072d118917957d6554Steve Block                    @"preferredVolume",
7032bde8e466a4451c7319e3a072d118917957d6554Steve Block                    @"preferredRate",
7042bde8e466a4451c7319e3a072d118917957d6554Steve Block                    @"playable",
7052bde8e466a4451c7319e3a072d118917957d6554Steve Block                    @"tracks",
7062bde8e466a4451c7319e3a072d118917957d6554Steve Block                   nil];
7072bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
7082bde8e466a4451c7319e3a072d118917957d6554Steve Block    return keys;
7092bde8e466a4451c7319e3a072d118917957d6554Steve Block}
7102bde8e466a4451c7319e3a072d118917957d6554Steve Block
7112bde8e466a4451c7319e3a072d118917957d6554Steve BlockNSArray* itemKVOProperties()
7122bde8e466a4451c7319e3a072d118917957d6554Steve Block{
7132bde8e466a4451c7319e3a072d118917957d6554Steve Block    static NSArray* keys;
7142bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!keys) {
7152bde8e466a4451c7319e3a072d118917957d6554Steve Block        keys = [[NSArray alloc] initWithObjects:@"presentationSize",
7162bde8e466a4451c7319e3a072d118917957d6554Steve Block                @"status",
7172bde8e466a4451c7319e3a072d118917957d6554Steve Block                @"asset",
7182bde8e466a4451c7319e3a072d118917957d6554Steve Block                @"tracks",
7192bde8e466a4451c7319e3a072d118917957d6554Steve Block                @"seekableTimeRanges",
7202bde8e466a4451c7319e3a072d118917957d6554Steve Block                @"loadedTimeRanges",
7212bde8e466a4451c7319e3a072d118917957d6554Steve Block                @"playbackLikelyToKeepUp",
7222bde8e466a4451c7319e3a072d118917957d6554Steve Block                @"playbackBufferFull",
7232bde8e466a4451c7319e3a072d118917957d6554Steve Block                @"playbackBufferEmpty",
7242bde8e466a4451c7319e3a072d118917957d6554Steve Block                nil];
7252bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
7262bde8e466a4451c7319e3a072d118917957d6554Steve Block    return keys;
7272bde8e466a4451c7319e3a072d118917957d6554Steve Block}
7282bde8e466a4451c7319e3a072d118917957d6554Steve Block
7292bde8e466a4451c7319e3a072d118917957d6554Steve Block} // namespace WebCore
7302bde8e466a4451c7319e3a072d118917957d6554Steve Block
7312bde8e466a4451c7319e3a072d118917957d6554Steve Block@implementation WebCoreAVFMovieObserver
7322bde8e466a4451c7319e3a072d118917957d6554Steve Block
7332bde8e466a4451c7319e3a072d118917957d6554Steve Block- (id)initWithCallback:(MediaPlayerPrivateAVFoundationObjC*)callback
7342bde8e466a4451c7319e3a072d118917957d6554Steve Block{
7352bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_callback = callback;
7362bde8e466a4451c7319e3a072d118917957d6554Steve Block    return [super init];
7372bde8e466a4451c7319e3a072d118917957d6554Steve Block}
7382bde8e466a4451c7319e3a072d118917957d6554Steve Block
7392bde8e466a4451c7319e3a072d118917957d6554Steve Block- (void)disconnect
7402bde8e466a4451c7319e3a072d118917957d6554Steve Block{
7412bde8e466a4451c7319e3a072d118917957d6554Steve Block    [NSObject cancelPreviousPerformRequestsWithTarget:self];
7422bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_callback = 0;
7432bde8e466a4451c7319e3a072d118917957d6554Steve Block}
7442bde8e466a4451c7319e3a072d118917957d6554Steve Block
7452bde8e466a4451c7319e3a072d118917957d6554Steve Block- (void)metadataLoaded
7462bde8e466a4451c7319e3a072d118917957d6554Steve Block{
7472bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_callback)
7482bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
7492bde8e466a4451c7319e3a072d118917957d6554Steve Block
7502bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::AssetMetadataLoaded);
7512bde8e466a4451c7319e3a072d118917957d6554Steve Block}
7522bde8e466a4451c7319e3a072d118917957d6554Steve Block
7532bde8e466a4451c7319e3a072d118917957d6554Steve Block- (void)playableKnown
7542bde8e466a4451c7319e3a072d118917957d6554Steve Block{
7552bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_callback)
7562bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
7572bde8e466a4451c7319e3a072d118917957d6554Steve Block
7582bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::AssetPlayabilityKnown);
7592bde8e466a4451c7319e3a072d118917957d6554Steve Block}
7602bde8e466a4451c7319e3a072d118917957d6554Steve Block
7612bde8e466a4451c7319e3a072d118917957d6554Steve Block- (void)timeChanged:(double)time
7622bde8e466a4451c7319e3a072d118917957d6554Steve Block{
7632bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_callback)
7642bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
7652bde8e466a4451c7319e3a072d118917957d6554Steve Block
7662bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::PlayerTimeChanged, time);
7672bde8e466a4451c7319e3a072d118917957d6554Steve Block}
7682bde8e466a4451c7319e3a072d118917957d6554Steve Block
7692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch- (void)seekCompleted:(BOOL)finished
7702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
7712daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (!m_callback)
7722daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return;
7732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
7742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::SeekCompleted, static_cast<bool>(finished));
7752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
7762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
7772bde8e466a4451c7319e3a072d118917957d6554Steve Block- (void)didEnd:(NSNotification *)unusedNotification
7782bde8e466a4451c7319e3a072d118917957d6554Steve Block{
7792bde8e466a4451c7319e3a072d118917957d6554Steve Block    UNUSED_PARAM(unusedNotification);
7802bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_callback)
7812bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
7822bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemDidPlayToEndTime);
7832bde8e466a4451c7319e3a072d118917957d6554Steve Block}
7842bde8e466a4451c7319e3a072d118917957d6554Steve Block
7852bde8e466a4451c7319e3a072d118917957d6554Steve Block- (void)observeValueForKeyPath:keyPath ofObject:(id)object change:(NSDictionary *)change context:(MediaPlayerAVFoundationObservationContext)context
7862bde8e466a4451c7319e3a072d118917957d6554Steve Block{
7872bde8e466a4451c7319e3a072d118917957d6554Steve Block    UNUSED_PARAM(change);
7882bde8e466a4451c7319e3a072d118917957d6554Steve Block
7892bde8e466a4451c7319e3a072d118917957d6554Steve Block    LOG(Media, "WebCoreAVFMovieObserver:observeValueForKeyPath(%p) - keyPath = %s", self, [keyPath UTF8String]);
7902bde8e466a4451c7319e3a072d118917957d6554Steve Block
7912bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_callback)
7922bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
7932bde8e466a4451c7319e3a072d118917957d6554Steve Block
7942bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (context == MediaPlayerAVFoundationObservationContextPlayerItem) {
7952bde8e466a4451c7319e3a072d118917957d6554Steve Block        // A value changed for an AVPlayerItem
7962bde8e466a4451c7319e3a072d118917957d6554Steve Block        if ([keyPath isEqualToString:@"status"])
7972bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemStatusChanged);
7982bde8e466a4451c7319e3a072d118917957d6554Steve Block        else if ([keyPath isEqualToString:@"playbackLikelyToKeepUp"])
7992bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemIsPlaybackLikelyToKeepUpChanged);
8002bde8e466a4451c7319e3a072d118917957d6554Steve Block        else if ([keyPath isEqualToString:@"playbackBufferEmpty"])
8012bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemIsPlaybackBufferEmptyChanged);
8022bde8e466a4451c7319e3a072d118917957d6554Steve Block        else if ([keyPath isEqualToString:@"playbackBufferFull"])
8032bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemIsPlaybackBufferFullChanged);
8042bde8e466a4451c7319e3a072d118917957d6554Steve Block        else if ([keyPath isEqualToString:@"asset"])
8052bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_callback->setAsset([object asset]);
8062bde8e466a4451c7319e3a072d118917957d6554Steve Block        else if ([keyPath isEqualToString:@"loadedTimeRanges"])
8072bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemLoadedTimeRangesChanged);
8082bde8e466a4451c7319e3a072d118917957d6554Steve Block        else if ([keyPath isEqualToString:@"seekableTimeRanges"])
8092bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemSeekableTimeRangesChanged);
8102bde8e466a4451c7319e3a072d118917957d6554Steve Block        else if ([keyPath isEqualToString:@"tracks"])
8112bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemTracksChanged);
8122bde8e466a4451c7319e3a072d118917957d6554Steve Block        else if ([keyPath isEqualToString:@"presentationSize"])
8132bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemPresentationSizeChanged);
8142bde8e466a4451c7319e3a072d118917957d6554Steve Block
8152bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
8162bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
8172bde8e466a4451c7319e3a072d118917957d6554Steve Block
8182bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (context == MediaPlayerAVFoundationObservationContextPlayer) {
8192bde8e466a4451c7319e3a072d118917957d6554Steve Block        // A value changed for an AVPlayer.
8202bde8e466a4451c7319e3a072d118917957d6554Steve Block        if ([keyPath isEqualToString:@"rate"])
8212bde8e466a4451c7319e3a072d118917957d6554Steve Block            m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::PlayerRateChanged);
8222bde8e466a4451c7319e3a072d118917957d6554Steve Block}
8232bde8e466a4451c7319e3a072d118917957d6554Steve Block}
8242bde8e466a4451c7319e3a072d118917957d6554Steve Block
8252bde8e466a4451c7319e3a072d118917957d6554Steve Block@end
8262bde8e466a4451c7319e3a072d118917957d6554Steve Block
8272bde8e466a4451c7319e3a072d118917957d6554Steve Block#endif
828