Diff
Modified: branches/safari-600.5-branch/LayoutTests/ChangeLog (178466 => 178467)
--- branches/safari-600.5-branch/LayoutTests/ChangeLog 2015-01-15 01:07:11 UTC (rev 178466)
+++ branches/safari-600.5-branch/LayoutTests/ChangeLog 2015-01-15 01:11:24 UTC (rev 178467)
@@ -1,5 +1,28 @@
2015-01-14 Dana Burkart <dburk...@apple.com>
+ Merged r174823. <rdar://problem/19424155>
+
+ 2014-10-16 Jer Noble <jer.no...@apple.com>
+
+ [Mac] Represent AVMediaSelectionOptions as AudioTracks
+ https://bugs.webkit.org/show_bug.cgi?id=137474
+
+ Reviewed by Brent Fulgham.
+
+ * http/tests/media/hls/hls-audio-tracks-expected.txt: Added.
+ * http/tests/media/hls/hls-audio-tracks.html: Added.
+ * http/tests/media/resources/hls/audio-tracks.m3u8: Added.
+ * http/tests/media/resources/hls/bipbop/iframe_index.m3u8: Added.
+ * http/tests/media/resources/hls/bipbop/main0.ts: Added.
+ * http/tests/media/resources/hls/bipbop/main1.ts: Added.
+ * http/tests/media/resources/hls/bipbop/prog_index.m3u8: Added.
+ * http/tests/media/resources/hls/french/main.aac: Added.
+ * http/tests/media/resources/hls/french/prog_index.m3u8: Added.
+ * http/tests/media/resources/hls/spanish/main.aac: Added.
+ * http/tests/media/resources/hls/spanish/prog_index.m3u8: Added.
+
+2015-01-14 Dana Burkart <dburk...@apple.com>
+
Merged r174402. <rdar://problem/19478358>
2014-10-07 Jer Noble <jer.no...@apple.com>
Copied: branches/safari-600.5-branch/LayoutTests/http/tests/media/hls/hls-audio-tracks-expected.txt (from rev 174823, trunk/LayoutTests/http/tests/media/hls/hls-audio-tracks-expected.txt) (0 => 178467)
--- branches/safari-600.5-branch/LayoutTests/http/tests/media/hls/hls-audio-tracks-expected.txt (rev 0)
+++ branches/safari-600.5-branch/LayoutTests/http/tests/media/hls/hls-audio-tracks-expected.txt 2015-01-15 01:11:24 UTC (rev 178467)
@@ -0,0 +1,8 @@
+
+EVENT(canplaythrough)
+EXPECTED (video.audioTracks.length == '3') OK
+EXPECTED (video.audioTracks[0].enabled == 'true') OK
+EXPECTED (video.audioTracks[1].enabled == 'false') OK
+EXPECTED (video.audioTracks[2].enabled == 'false') OK
+END OF TEST
+
Copied: branches/safari-600.5-branch/LayoutTests/http/tests/media/hls/hls-audio-tracks.html (from rev 174823, trunk/LayoutTests/http/tests/media/hls/hls-audio-tracks.html) (0 => 178467)
--- branches/safari-600.5-branch/LayoutTests/http/tests/media/hls/hls-audio-tracks.html (rev 0)
+++ branches/safari-600.5-branch/LayoutTests/http/tests/media/hls/hls-audio-tracks.html 2015-01-15 01:11:24 UTC (rev 178467)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script src=""
+ <script src=""
+ <script>
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+ }
+
+ function start() {
+ video = document.getElementById('video');
+ waitForEvent('canplaythrough', canplaythrough);
+ video.src = ""
+ }
+
+ function canplaythrough() {
+ testExpected("video.audioTracks.length", 3);
+ testExpected("video.audioTracks[0].enabled", true);
+ testExpected("video.audioTracks[1].enabled", false);
+ testExpected("video.audioTracks[2].enabled", false);
+ endTest();
+ }
+ </script>
+ </head>
+ <body _onload_="start()">
+ <video id="video"></video>
+ </body>
+</html>
Copied: branches/safari-600.5-branch/LayoutTests/http/tests/media/resources/hls/audio-tracks.m3u8 (from rev 174823, trunk/LayoutTests/http/tests/media/resources/hls/audio-tracks.m3u8) (0 => 178467)
--- branches/safari-600.5-branch/LayoutTests/http/tests/media/resources/hls/audio-tracks.m3u8 (rev 0)
+++ branches/safari-600.5-branch/LayoutTests/http/tests/media/resources/hls/audio-tracks.m3u8 2015-01-15 01:11:24 UTC (rev 178467)
@@ -0,0 +1,9 @@
+#EXTM3U
+
+#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="bipbop_audio",LANGUAGE="eng",NAME="English Sound",AUTOSELECT=YES,DEFAULT=YES
+#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="bipbop_audio",LANGUAGE="fre",NAME="French Sound",AUTOSELECT=NO,DEFAULT=NO,URI="french/prog_index.m3u8"
+#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="bipbop_audio",LANGUAGE="spa",NAME="Spanish Sound",AUTOSELECT=NO,DEFAULT=NO,URI="spanish/prog_index.m3u8"
+
+#EXT-X-STREAM-INF:BANDWIDTH=634451,CODECS="mp4a.40.2, avc1.4d401e",RESOLUTION=640x480,AUDIO="bipbop_audio"
+bipbop/prog_index.m3u8
+#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=258613,CODECS="avc1.4d401e",URI="bipbop/iframe_index.m3u8"
Modified: branches/safari-600.5-branch/Source/WebCore/ChangeLog (178466 => 178467)
--- branches/safari-600.5-branch/Source/WebCore/ChangeLog 2015-01-15 01:07:11 UTC (rev 178466)
+++ branches/safari-600.5-branch/Source/WebCore/ChangeLog 2015-01-15 01:11:24 UTC (rev 178467)
@@ -1,5 +1,115 @@
2015-01-14 Dana Burkart <dburk...@apple.com>
+ Merged r174823. <rdar://problem/19424155>
+
+ 2014-10-16 Jer Noble <jer.no...@apple.com>
+
+ [Mac] Represent AVMediaSelectionOptions as AudioTracks
+ https://bugs.webkit.org/show_bug.cgi?id=137474
+
+ Reviewed by Brent Fulgham.
+
+ Test: http/tests/media/hls/hls-audio-tracks.html
+
+ Support selecting audio "tracks" in HLS streams by exposing AVMediaSelectionOptions
+ as entries in the video's AudioTrackList.
+
+ AVMediaSessionGroups and AVPlayerItems don't have KVO or notifications to track when options
+ are selected and deselected, so wrap AVMediaSessionGroup and AVMediaSessionOption in C++
+ wrappers. Each AVMediaSelectionGroup can have only one AVMediaSelectionOption selected at a
+ time, so the wrapper will take care of answering which AVMediaSelectionOption is currently
+ selected, as without KVO notifications, asking the AVMediaSelectionGroup directly is
+ inconsistent. Because setting the selected option multiple times in the same run-loop can
+ cause flakiness, coalesce calls to setSelectedOption() by setting a one-shot timer to do
+ the actual selection in the next run-loop.
+
+ * platform/graphics/avfoundation/MediaSelectionGroupAVFObjC.h: Added.
+ (WebCore::MediaSelectionOptionAVFObjC::avMediaSelectionOption):
+ (WebCore::MediaSelectionOptionAVFObjC::clearGroup): Clear backpointer to group from option.
+ (WebCore::MediaSelectionGroupAVFObjC::selectedOption): Simple accessor.
+ (WebCore::MediaSelectionGroupAVFObjC::options): Simple accessor.
+ (WebCore::MediaSelectionGroupAVFObjC::avMediaSelectionGroup): Simple accessor.
+ * platform/graphics/avfoundation/MediaSelectionGroupAVFObjC.mm: Added.
+ (WebCore::MediaSelectionOptionAVFObjC::create): Simple factory method.
+ (WebCore::MediaSelectionOptionAVFObjC::MediaSelectionOptionAVFObjC): Simple constructor.
+ (WebCore::MediaSelectionOptionAVFObjC::setSelected): Pass through to MediaSelectionGroupAVFObjC.
+ (WebCore::MediaSelectionOptionAVFObjC::selected): Ditto.
+ (WebCore::MediaSelectionOptionAVFObjC::index): Return index of this object in the group's object.
+ (WebCore::MediaSelectionGroupAVFObjC::create):
+ (WebCore::MediaSelectionGroupAVFObjC::MediaSelectionGroupAVFObjC):
+ (WebCore::MediaSelectionGroupAVFObjC::~MediaSelectionGroupAVFObjC):
+ (WebCore::MediaSelectionGroupAVFObjC::updateOptions): Discover added or removed options.
+ (WebCore::MediaSelectionGroupAVFObjC::setSelectedOption): Set a one shot timer to coalesce multiple calls.
+ (WebCore::MediaSelectionGroupAVFObjC::selectionTimerFired): Set the selected AVSelectionOption.
+
+ Modify AVTrackPrivateAVFObjCImpl to support both AVPlayerItemTracks and these new
+ MediaSelectionOptionAVFObjC objects.
+
+ * platform/graphics/avfoundation/AVTrackPrivateAVFObjCImpl.h:
+ (WebCore::AVTrackPrivateAVFObjCImpl::mediaSelectionOption): Simple accessor.
+ * platform/graphics/avfoundation/AVTrackPrivateAVFObjCImpl.mm:
+ (WebCore::AVTrackPrivateAVFObjCImpl::AVTrackPrivateAVFObjCImpl): Simple constructor.
+ (WebCore::AVTrackPrivateAVFObjCImpl::~AVTrackPrivateAVFObjCImpl): Simple destructor.
+ (WebCore::AVTrackPrivateAVFObjCImpl::enabled): Use MediaSelectionOptionAVFObjC, if present.
+ (WebCore::AVTrackPrivateAVFObjCImpl::setEnabled): Ditto.
+ (WebCore::AVTrackPrivateAVFObjCImpl::audioKind): Ditto.
+ (WebCore::AVTrackPrivateAVFObjCImpl::videoKind): Ditto.
+ (WebCore::AVTrackPrivateAVFObjCImpl::index): Ditto.
+ (WebCore::AVTrackPrivateAVFObjCImpl::id): Ditto.
+ (WebCore::AVTrackPrivateAVFObjCImpl::label): Ditto.
+ (WebCore::AVTrackPrivateAVFObjCImpl::language): Ditto.
+ (WebCore::AVTrackPrivateAVFObjCImpl::languageForAVMediaSelectionOption): Ditto.
+ (WebCore::AVTrackPrivateAVFObjCImpl::trackID): Ditto.
+
+ Allow AudioTrackPrivateAVFObjC and VideoTrackPrivateAVFObjC to be created with
+ a MediaSelectionOptionAVFObjC.
+
+ * platform/graphics/avfoundation/objc/AudioTrackPrivateAVFObjC.h:
+ (WebCore::AudioTrackPrivateAVFObjC::create): Takes a MediaSelectionOptionAVFObjC.
+ * platform/graphics/avfoundation/objc/AudioTrackPrivateAVFObjC.mm:
+ (WebCore::AudioTrackPrivateAVFObjC::AudioTrackPrivateAVFObjC): Simple constructor.
+ (WebCore::AudioTrackPrivateAVFObjC::setMediaSelectionOption): Create a new AVTrackPrivateAVFObjCImpl.
+ (WebCore::AudioTrackPrivateAVFObjC::mediaSelectionOption): Simple accessor.
+ * platform/graphics/avfoundation/objc/VideoTrackPrivateAVFObjC.cpp:
+ (WebCore::VideoTrackPrivateAVFObjC::VideoTrackPrivateAVFObjC): Simple constructor.
+ (WebCore::VideoTrackPrivateAVFObjC::setMediaSelectonOption): Create a new AVTrackPrivateAVFObjCImpl.
+ (WebCore::VideoTrackPrivateAVFObjC::mediaSelectionOption): Simple accessor.
+ * platform/graphics/avfoundation/objc/VideoTrackPrivateAVFObjC.h:
+
+ Because IDs are not necessarily unique across AVPlayerItemTracks and AVMediaSelectionOptions,
+ use the index of the track or option instead of it's self-declared ID for ordering for the
+ trackIndex.
+
+ * platform/graphics/avfoundation/objc/AudioTrackPrivateAVFObjC.mm:
+ (WebCore::AudioTrackPrivateAVFObjC::resetPropertiesFromTrack):
+ * platform/graphics/avfoundation/objc/VideoTrackPrivateMediaSourceAVFObjC.mm:
+ (WebCore::VideoTrackPrivateMediaSourceAVFObjC::resetPropertiesFromTrack):
+
+ Rather than making allowing the AVPlayerItem to automatically select the "best"
+ AVMediaSelectionOption, select the automatic options when creating the AVPlayerItem
+ and thereafter allow the users manual selections "stick".
+
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::ensureAVPlayer):
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::ensureAVPlayerItem):
+
+ Determine whether any MediaSelectionOptionsAVFObjC have been added or removed and send trackChange events accordingly.
+
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+ (WebCore::determineChangedTracksFromNewTracksAndOldItems): Added.
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::updateAudioTracks): Search for updated selection options.
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::updateVideoTracks): Ditto.
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::safeMediaSelectionGroupForAudibleMedia): Return selection group, if available.
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::safeMediaSelectionGroupForVisualMedia): Ditto.
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::tracksDidChange): Filter out AVPlayerItemTracks without
+ AVAssetTracks, as these will be represented by MediaSelectionGroupObjCs instead.
+
+ Add new files to project.
+ * WebCore.xcodeproj/project.pbxproj:
+
+2015-01-14 Dana Burkart <dburk...@apple.com>
+
Merged r174402. <rdar://problem/19478358>
2014-10-07 Jer Noble <jer.no...@apple.com>
Modified: branches/safari-600.5-branch/Source/WebCore/WebCore.xcodeproj/project.pbxproj (178466 => 178467)
--- branches/safari-600.5-branch/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2015-01-15 01:07:11 UTC (rev 178466)
+++ branches/safari-600.5-branch/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2015-01-15 01:11:24 UTC (rev 178467)
@@ -5730,6 +5730,8 @@
CDAE8C091746B95700532D78 /* MediaSessionManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDAE8C071746B95700532D78 /* MediaSessionManager.cpp */; };
CDB859F7160D48A400E5B07F /* MediaKeyEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDB859F4160D489900E5B07F /* MediaKeyEvent.cpp */; };
CDB859FA160D494900E5B07F /* JSMediaKeyEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDB859F8160D493E00E5B07F /* JSMediaKeyEvent.cpp */; };
+ CDBEAEAC19D92B6C00BEBA88 /* MediaSelectionGroupAVFObjC.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDBEAEAA19D92B6C00BEBA88 /* MediaSelectionGroupAVFObjC.mm */; };
+ CDBEAEAD19D92B6C00BEBA88 /* MediaSelectionGroupAVFObjC.h in Headers */ = {isa = PBXBuildFile; fileRef = CDBEAEAB19D92B6C00BEBA88 /* MediaSelectionGroupAVFObjC.h */; };
CDC26B40160A8CC60026757B /* MockCDM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDC26B3C160A62B00026757B /* MockCDM.cpp */; };
CDC26B41160A8CCE0026757B /* MockCDM.h in Headers */ = {isa = PBXBuildFile; fileRef = CDC26B3D160A62B00026757B /* MockCDM.h */; };
CDC69DD61632026C007C38DF /* WebCoreFullScreenWarningView.h in Headers */ = {isa = PBXBuildFile; fileRef = CDC69DD41632026C007C38DF /* WebCoreFullScreenWarningView.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -13232,6 +13234,8 @@
CDB859F6160D489900E5B07F /* MediaKeyEvent.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = MediaKeyEvent.idl; sourceTree = "<group>"; };
CDB859F8160D493E00E5B07F /* JSMediaKeyEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMediaKeyEvent.cpp; sourceTree = "<group>"; };
CDB859F9160D493E00E5B07F /* JSMediaKeyEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMediaKeyEvent.h; sourceTree = "<group>"; };
+ CDBEAEAA19D92B6C00BEBA88 /* MediaSelectionGroupAVFObjC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MediaSelectionGroupAVFObjC.mm; sourceTree = "<group>"; };
+ CDBEAEAB19D92B6C00BEBA88 /* MediaSelectionGroupAVFObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaSelectionGroupAVFObjC.h; sourceTree = "<group>"; };
CDC1DD4117CC2C48008CB55D /* mediaControlsApple.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = mediaControlsApple.css; sourceTree = "<group>"; };
CDC26B3C160A62B00026757B /* MockCDM.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MockCDM.cpp; sourceTree = "<group>"; };
CDC26B3D160A62B00026757B /* MockCDM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCDM.h; sourceTree = "<group>"; };
@@ -21788,6 +21792,8 @@
CD8B5A40180D149A008B8E65 /* VideoTrackPrivateMediaSourceAVFObjC.mm */,
CD7E05201651A84100C1201F /* WebCoreAVFResourceLoader.h */,
CD7E05211651A84100C1201F /* WebCoreAVFResourceLoader.mm */,
+ CDBEAEAA19D92B6C00BEBA88 /* MediaSelectionGroupAVFObjC.mm */,
+ CDBEAEAB19D92B6C00BEBA88 /* MediaSelectionGroupAVFObjC.h */,
);
name = objc;
sourceTree = "<group>";
@@ -24011,6 +24017,7 @@
85C78A680ABDE1B40044FC16 /* DOMException.h in Headers */,
BC1A37B5097C715F0019F3D8 /* DOMExtensions.h in Headers */,
BC00F0040E0A185500FD04E3 /* DOMFile.h in Headers */,
+ CDBEAEAD19D92B6C00BEBA88 /* MediaSelectionGroupAVFObjC.h in Headers */,
2E3BC108117D479800B9409A /* DOMFileError.h in Headers */,
2E3BC10B117D47C800B9409A /* DOMFileErrorInternal.h in Headers */,
BC00F0060E0A185500FD04E3 /* DOMFileInternal.h in Headers */,
@@ -28350,6 +28357,7 @@
59A86006119DAF7F00DEF1EF /* JSDeviceOrientationEvent.cpp in Sources */,
590E1B4B11E4EF700069F784 /* JSDeviceOrientationEventCustom.cpp in Sources */,
BCE438A2140C0DC0005E437E /* JSDictionary.cpp in Sources */,
+ CDBEAEAC19D92B6C00BEBA88 /* MediaSelectionGroupAVFObjC.mm in Sources */,
659DDC8209E198BA001BF3C6 /* JSDocument.cpp in Sources */,
49C7BA8D1042F5B10009D447 /* JSDocumentCustom.cpp in Sources */,
1A494EDE0A123F4C00FDAFC1 /* JSDocumentFragment.cpp in Sources */,
Modified: branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/AVTrackPrivateAVFObjCImpl.h (178466 => 178467)
--- branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/AVTrackPrivateAVFObjCImpl.h 2015-01-15 01:07:11 UTC (rev 178466)
+++ branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/AVTrackPrivateAVFObjCImpl.h 2015-01-15 01:11:24 UTC (rev 178467)
@@ -31,20 +31,29 @@
#include "AudioTrackPrivate.h"
#include "VideoTrackPrivate.h"
#include <wtf/OwnPtr.h>
+#include <wtf/Ref.h>
#include <wtf/RetainPtr.h>
OBJC_CLASS AVAssetTrack;
+OBJC_CLASS AVPlayerItem;
OBJC_CLASS AVPlayerItemTrack;
+OBJC_CLASS AVMediaSelectionGroup;
+OBJC_CLASS AVMediaSelectionOption;
namespace WebCore {
+class MediaSelectionOptionAVFObjC;
+
class AVTrackPrivateAVFObjCImpl {
public:
explicit AVTrackPrivateAVFObjCImpl(AVPlayerItemTrack*);
explicit AVTrackPrivateAVFObjCImpl(AVAssetTrack*);
+ explicit AVTrackPrivateAVFObjCImpl(MediaSelectionOptionAVFObjC&);
+ ~AVTrackPrivateAVFObjCImpl();
AVPlayerItemTrack* playerItemTrack() const { return m_playerItemTrack.get(); }
AVAssetTrack* assetTrack() const { return m_assetTrack.get(); }
+ MediaSelectionOptionAVFObjC* mediaSelectionOption() const { return m_mediaSelectionOption.get(); }
bool enabled() const;
void setEnabled(bool);
@@ -52,6 +61,7 @@
AudioTrackPrivate::Kind audioKind() const;
VideoTrackPrivate::Kind videoKind() const;
+ int index() const;
AtomicString id() const;
AtomicString label() const;
AtomicString language() const;
@@ -59,10 +69,13 @@
int trackID() const;
static String languageForAVAssetTrack(AVAssetTrack*);
+ static String languageForAVMediaSelectionOption(AVMediaSelectionOption *);
private:
RetainPtr<AVPlayerItemTrack> m_playerItemTrack;
RetainPtr<AVAssetTrack> m_assetTrack;
+ RetainPtr<AVPlayerItem> m_playerItem;
+ RefPtr<MediaSelectionOptionAVFObjC> m_mediaSelectionOption;
};
}
Modified: branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/AVTrackPrivateAVFObjCImpl.mm (178466 => 178467)
--- branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/AVTrackPrivateAVFObjCImpl.mm 2015-01-15 01:07:11 UTC (rev 178466)
+++ branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/AVTrackPrivateAVFObjCImpl.mm 2015-01-15 01:11:24 UTC (rev 178467)
@@ -28,16 +28,27 @@
#if ENABLE(VIDEO_TRACK)
+#import "MediaSelectionGroupAVFObjC.h"
#import "SoftLinking.h"
-#import <objc/runtime.h>
#import <AVFoundation/AVAssetTrack.h>
+#import <AVFoundation/AVMediaSelectionGroup.h>
+#import <AVFoundation/AVMetadataItem.h>
+#import <AVFoundation/AVPlayerItem.h>
#import <AVFoundation/AVPlayerItemTrack.h>
-#import <AVFoundation/AVMetadataItem.h>
+#import <objc/runtime.h>
+@class AVMediaSelectionOption;
+@interface AVMediaSelectionOption (WebKitInternal)
+- (id)optionID;
+@end
+
SOFT_LINK_FRAMEWORK_OPTIONAL(AVFoundation)
SOFT_LINK_CLASS(AVFoundation, AVAssetTrack)
+SOFT_LINK_CLASS(AVFoundation, AVPlayerItem)
SOFT_LINK_CLASS(AVFoundation, AVPlayerItemTrack)
+SOFT_LINK_CLASS(AVFoundation, AVMediaSelectionGroup)
+SOFT_LINK_CLASS(AVFoundation, AVMediaSelectionOption)
SOFT_LINK_CLASS(AVFoundation, AVMetadataItem)
SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVMediaCharacteristicIsMainProgramContent, NSString *)
@@ -69,48 +80,120 @@
{
}
+AVTrackPrivateAVFObjCImpl::AVTrackPrivateAVFObjCImpl(MediaSelectionOptionAVFObjC& option)
+ : m_mediaSelectionOption(&option)
+{
+}
+
+AVTrackPrivateAVFObjCImpl::~AVTrackPrivateAVFObjCImpl()
+{
+}
+
bool AVTrackPrivateAVFObjCImpl::enabled() const
{
- ASSERT(m_playerItemTrack);
- return [m_playerItemTrack isEnabled];
+ if (m_playerItemTrack)
+ return [m_playerItemTrack isEnabled];
+ if (m_mediaSelectionOption)
+ return m_mediaSelectionOption->selected();
+ ASSERT_NOT_REACHED();
+ return false;
}
void AVTrackPrivateAVFObjCImpl::setEnabled(bool enabled)
{
- ASSERT(m_playerItemTrack);
- [m_playerItemTrack setEnabled:enabled];
+ if (m_playerItemTrack)
+ [m_playerItemTrack setEnabled:enabled];
+ else if (m_mediaSelectionOption)
+ m_mediaSelectionOption->setSelected(enabled);
+ else
+ ASSERT_NOT_REACHED();
}
AudioTrackPrivate::Kind AVTrackPrivateAVFObjCImpl::audioKind() const
{
- if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
- return AudioTrackPrivate::Alternative;
- else if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
- return AudioTrackPrivate::Main;
+ if (m_assetTrack) {
+ if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
+ return AudioTrackPrivate::Alternative;
+ if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
+ return AudioTrackPrivate::Main;
+ return AudioTrackPrivate::None;
+ }
+
+ if (m_mediaSelectionOption) {
+ AVMediaSelectionOption *option = m_mediaSelectionOption->avMediaSelectionOption();
+ if ([option hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
+ return AudioTrackPrivate::Alternative;
+ if ([option hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
+ return AudioTrackPrivate::Main;
+ return AudioTrackPrivate::None;
+ }
+
+ ASSERT_NOT_REACHED();
return AudioTrackPrivate::None;
}
VideoTrackPrivate::Kind AVTrackPrivateAVFObjCImpl::videoKind() const
{
- if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
- return VideoTrackPrivate::Sign;
- else if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicTranscribesSpokenDialogForAccessibility])
- return VideoTrackPrivate::Captions;
- else if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
- return VideoTrackPrivate::Alternative;
- else if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
- return VideoTrackPrivate::Main;
+ if (m_assetTrack) {
+ if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
+ return VideoTrackPrivate::Sign;
+ if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicTranscribesSpokenDialogForAccessibility])
+ return VideoTrackPrivate::Captions;
+ if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
+ return VideoTrackPrivate::Alternative;
+ if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
+ return VideoTrackPrivate::Main;
+ return VideoTrackPrivate::None;
+ }
+
+ if (m_mediaSelectionOption) {
+ AVMediaSelectionOption *option = m_mediaSelectionOption->avMediaSelectionOption();
+ if ([option hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
+ return VideoTrackPrivate::Sign;
+ if ([option hasMediaCharacteristic:AVMediaCharacteristicTranscribesSpokenDialogForAccessibility])
+ return VideoTrackPrivate::Captions;
+ if ([option hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
+ return VideoTrackPrivate::Alternative;
+ if ([option hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
+ return VideoTrackPrivate::Main;
+ return VideoTrackPrivate::None;
+ }
+
+ ASSERT_NOT_REACHED();
return VideoTrackPrivate::None;
}
+int AVTrackPrivateAVFObjCImpl::index() const
+{
+ if (m_assetTrack)
+ return [[[m_assetTrack asset] tracks] indexOfObject:m_assetTrack.get()];
+ if (m_mediaSelectionOption)
+ return [[[m_playerItem asset] tracks] count] + m_mediaSelectionOption->index();
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
AtomicString AVTrackPrivateAVFObjCImpl::id() const
{
- return String::format("%d", [m_assetTrack trackID]);
+ if (m_assetTrack)
+ return String::format("%d", [m_assetTrack trackID]);
+ if (m_mediaSelectionOption)
+ return [[m_mediaSelectionOption->avMediaSelectionOption() optionID] stringValue];
+ ASSERT_NOT_REACHED();
+ return emptyAtom;
}
AtomicString AVTrackPrivateAVFObjCImpl::label() const
{
- NSArray *titles = [AVMetadataItem metadataItemsFromArray:[m_assetTrack commonMetadata] withKey:AVMetadataCommonKeyTitle keySpace:AVMetadataKeySpaceCommon];
+ NSArray *commonMetadata = nil;
+ if (m_assetTrack)
+ commonMetadata = [m_assetTrack commonMetadata];
+ else if (m_mediaSelectionOption)
+ commonMetadata = [m_mediaSelectionOption->avMediaSelectionOption() commonMetadata];
+ else
+ ASSERT_NOT_REACHED();
+
+ NSArray *titles = [AVMetadataItem metadataItemsFromArray:commonMetadata withKey:AVMetadataCommonKeyTitle keySpace:AVMetadataKeySpaceCommon];
if (![titles count])
return emptyAtom;
@@ -123,7 +206,13 @@
AtomicString AVTrackPrivateAVFObjCImpl::language() const
{
- return languageForAVAssetTrack(m_assetTrack.get());
+ if (m_assetTrack)
+ return languageForAVAssetTrack(m_assetTrack.get());
+ if (m_mediaSelectionOption)
+ return languageForAVMediaSelectionOption(m_mediaSelectionOption->avMediaSelectionOption());
+
+ ASSERT_NOT_REACHED();
+ return emptyAtom;
}
String AVTrackPrivateAVFObjCImpl::languageForAVAssetTrack(AVAssetTrack* track)
@@ -143,9 +232,35 @@
return language;
}
+String AVTrackPrivateAVFObjCImpl::languageForAVMediaSelectionOption(AVMediaSelectionOption* option)
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+ NSString *language = [option extendedLanguageTag];
+#else
+ NSString *language = nil;
+#endif
+
+ // If the language code is stored as a QuickTime 5-bit packed code there aren't enough bits for a full
+ // RFC 4646 language tag so extendedLanguageTag returns NULL. In this case languageCode will return the
+ // ISO 639-2/T language code so check it.
+ if (!language)
+ language = [[option locale] objectForKey:NSLocaleLanguageCode];
+
+ // Some legacy tracks have "und" as a language, treat that the same as no language at all.
+ if (!language || [language isEqualToString:@"und"])
+ return emptyString();
+
+ return language;
+}
+
int AVTrackPrivateAVFObjCImpl::trackID() const
{
- return [m_assetTrack trackID];
+ if (m_assetTrack)
+ return [m_assetTrack trackID];
+ if (m_mediaSelectionOption)
+ return [[m_mediaSelectionOption->avMediaSelectionOption() optionID] intValue];
+ ASSERT_NOT_REACHED();
+ return 0;
}
}
Copied: branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/MediaSelectionGroupAVFObjC.h (from rev 174823, trunk/Source/WebCore/platform/graphics/avfoundation/MediaSelectionGroupAVFObjC.h) (0 => 178467)
--- branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/MediaSelectionGroupAVFObjC.h (rev 0)
+++ branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/MediaSelectionGroupAVFObjC.h 2015-01-15 01:11:24 UTC (rev 178467)
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaSelectionGroupAVFObjC_h
+#define MediaSelectionGroupAVFObjC_h
+
+#if ENABLE(VIDEO_TRACK)
+
+#include "Timer.h"
+#include <wtf/HashMap.h>
+#include <wtf/IteratorRange.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/RetainPtr.h>
+
+OBJC_CLASS AVPlayerItem;
+OBJC_CLASS AVMediaSelectionGroup;
+OBJC_CLASS AVMediaSelectionOption;
+
+namespace WebCore {
+
+class MediaSelectionGroupAVFObjC;
+
+class MediaSelectionOptionAVFObjC : public RefCounted<MediaSelectionOptionAVFObjC> {
+public:
+ static PassRefPtr<MediaSelectionOptionAVFObjC> create(MediaSelectionGroupAVFObjC&, AVMediaSelectionOption *);
+
+ void setSelected(bool);
+ bool selected() const;
+
+ int index() const;
+
+ AVMediaSelectionOption *avMediaSelectionOption() const { return m_mediaSelectionOption.get(); }
+
+private:
+ friend class MediaSelectionGroupAVFObjC;
+ MediaSelectionOptionAVFObjC(MediaSelectionGroupAVFObjC&, AVMediaSelectionOption *);
+
+ void clearGroup() { m_group = nullptr; }
+
+ MediaSelectionGroupAVFObjC* m_group;
+ RetainPtr<AVMediaSelectionOption> m_mediaSelectionOption;
+};
+
+class MediaSelectionGroupAVFObjC : public RefCounted<MediaSelectionGroupAVFObjC> {
+public:
+ static PassRefPtr<MediaSelectionGroupAVFObjC> create(AVPlayerItem*, AVMediaSelectionGroup*);
+ ~MediaSelectionGroupAVFObjC();
+
+ void setSelectedOption(MediaSelectionOptionAVFObjC*);
+ MediaSelectionOptionAVFObjC* selectedOption() const { return m_selectedOption; }
+
+ void updateOptions();
+
+ typedef HashMap<AVMediaSelectionOption*, RefPtr<MediaSelectionOptionAVFObjC>> OptionContainer;
+ WTF::IteratorRange<OptionContainer::iterator::Values> options() { return m_options.values(); }
+
+ AVMediaSelectionGroup *avMediaSelectionGroup() const { return m_mediaSelectionGroup.get(); }
+
+private:
+ MediaSelectionGroupAVFObjC(AVPlayerItem*, AVMediaSelectionGroup*);
+
+ void selectionTimerFired(Timer<MediaSelectionGroupAVFObjC>&);
+
+ RetainPtr<AVPlayerItem> m_playerItem;
+ RetainPtr<AVMediaSelectionGroup> m_mediaSelectionGroup;
+ OptionContainer m_options;
+ MediaSelectionOptionAVFObjC* m_selectedOption;
+ Timer<MediaSelectionGroupAVFObjC> m_selectionTimer;
+};
+
+}
+
+#endif // ENABLE(VIDEO_TRACK)
+
+#endif // MediaSelectionGroupAVFObjC_h
Copied: branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/MediaSelectionGroupAVFObjC.mm (from rev 174823, trunk/Source/WebCore/platform/graphics/avfoundation/MediaSelectionGroupAVFObjC.mm) (0 => 178467)
--- branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/MediaSelectionGroupAVFObjC.mm (rev 0)
+++ branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/MediaSelectionGroupAVFObjC.mm 2015-01-15 01:11:24 UTC (rev 178467)
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "MediaSelectionGroupAVFObjC.h"
+
+#if ENABLE(VIDEO_TRACK)
+
+#import "SoftLinking.h"
+#import <AVFoundation/AVAsset.h>
+#import <AVFoundation/AVMediaSelectionGroup.h>
+#import <AVFoundation/AVPlayerItem.h>
+#import <objc/runtime.h>
+#import <wtf/HashMap.h>
+#import <wtf/HashSet.h>
+
+SOFT_LINK_FRAMEWORK_OPTIONAL(AVFoundation)
+
+SOFT_LINK_CLASS(AVFoundation, AVMediaSelectionGroup)
+SOFT_LINK_CLASS(AVFoundation, AVMediaSelectionOption)
+
+namespace WebCore {
+
+PassRefPtr<MediaSelectionOptionAVFObjC> MediaSelectionOptionAVFObjC::create(MediaSelectionGroupAVFObjC& group, AVMediaSelectionOption *option)
+{
+ return adoptRef(new MediaSelectionOptionAVFObjC(group, option));
+}
+
+MediaSelectionOptionAVFObjC::MediaSelectionOptionAVFObjC(MediaSelectionGroupAVFObjC& group, AVMediaSelectionOption *option)
+ : m_group(&group)
+ , m_mediaSelectionOption(option)
+{
+}
+
+void MediaSelectionOptionAVFObjC::setSelected(bool selected)
+{
+ if (!m_group)
+ return;
+
+ if (selected == this->selected())
+ return;
+
+ m_group->setSelectedOption(selected ? this : nullptr);
+}
+
+bool MediaSelectionOptionAVFObjC::selected() const
+{
+ if (!m_group)
+ return false;
+ return this == m_group->selectedOption();
+}
+
+int MediaSelectionOptionAVFObjC::index() const
+{
+ if (!m_group)
+ return 0;
+
+ return [[m_group->avMediaSelectionGroup() options] indexOfObject:m_mediaSelectionOption.get()];
+}
+
+PassRefPtr<MediaSelectionGroupAVFObjC> MediaSelectionGroupAVFObjC::create(AVPlayerItem *item, AVMediaSelectionGroup *group)
+{
+ return adoptRef(new MediaSelectionGroupAVFObjC(item, group));
+}
+
+MediaSelectionGroupAVFObjC::MediaSelectionGroupAVFObjC(AVPlayerItem *item, AVMediaSelectionGroup *group)
+ : m_playerItem(item)
+ , m_mediaSelectionGroup(group)
+ , m_selectedOption(nullptr)
+ , m_selectionTimer(this, &MediaSelectionGroupAVFObjC::selectionTimerFired)
+{
+ updateOptions();
+}
+
+MediaSelectionGroupAVFObjC::~MediaSelectionGroupAVFObjC()
+{
+ for (auto& option : m_options.values())
+ option->clearGroup();
+}
+
+void MediaSelectionGroupAVFObjC::updateOptions()
+{
+ RetainPtr<NSSet> newAVOptions = adoptNS([[NSSet alloc] initWithArray:[getAVMediaSelectionGroupClass() playableMediaSelectionOptionsFromArray:[m_mediaSelectionGroup options]]]);
+ RetainPtr<NSMutableSet> oldAVOptions = adoptNS([[NSMutableSet alloc] initWithCapacity:m_options.size()]);
+ for (auto& avOption : m_options.keys())
+ [oldAVOptions addObject:avOption];
+
+ RetainPtr<NSMutableSet> addedAVOptions = [newAVOptions mutableCopy];
+ [addedAVOptions minusSet:oldAVOptions.get()];
+
+ RetainPtr<NSMutableSet> removedAVOptions = [oldAVOptions mutableCopy];
+ [removedAVOptions minusSet:newAVOptions.get()];
+
+ for (AVMediaSelectionOption* removedAVOption in removedAVOptions.get()) {
+ if (m_selectedOption && removedAVOption == m_selectedOption->avMediaSelectionOption())
+ m_selectedOption = nullptr;
+
+ m_options.remove(removedAVOption);
+ }
+
+ AVMediaSelectionOption* selectedOption = [m_playerItem selectedMediaOptionInMediaSelectionGroup:m_mediaSelectionGroup.get()];
+
+ for (AVMediaSelectionOption* addedAVOption in addedAVOptions.get()) {
+ RefPtr<MediaSelectionOptionAVFObjC> addedOption = MediaSelectionOptionAVFObjC::create(*this, addedAVOption);
+ if (addedAVOption == selectedOption)
+ m_selectedOption = addedOption.get();
+ m_options.set(addedAVOption, addedOption.release());
+ }
+}
+
+void MediaSelectionGroupAVFObjC::setSelectedOption(MediaSelectionOptionAVFObjC* option)
+{
+ if (m_selectedOption == option)
+ return;
+
+ m_selectedOption = option;
+ if (m_selectionTimer.isActive())
+ m_selectionTimer.stop();
+ m_selectionTimer.startOneShot(0);
+}
+
+void MediaSelectionGroupAVFObjC::selectionTimerFired(Timer<MediaSelectionGroupAVFObjC>&)
+{
+ [m_playerItem selectMediaOption:(m_selectedOption ? m_selectedOption->avMediaSelectionOption() : nil) inMediaSelectionGroup:m_mediaSelectionGroup.get()];
+}
+
+}
+
+#endif
Modified: branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/AudioTrackPrivateAVFObjC.h (178466 => 178467)
--- branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/AudioTrackPrivateAVFObjC.h 2015-01-15 01:07:11 UTC (rev 178466)
+++ branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/AudioTrackPrivateAVFObjC.h 2015-01-15 01:11:24 UTC (rev 178467)
@@ -31,12 +31,16 @@
#include "AudioTrackPrivateAVF.h"
#include <wtf/OwnPtr.h>
+OBJC_CLASS AVAssetTrack;
+OBJC_CLASS AVPlayerItem;
OBJC_CLASS AVPlayerItemTrack;
-OBJC_CLASS AVAssetTrack;
+OBJC_CLASS AVMediaSelectionGroup;
+OBJC_CLASS AVMediaSelectionOption;
namespace WebCore {
class AVTrackPrivateAVFObjCImpl;
+class MediaSelectionOptionAVFObjC;
class AudioTrackPrivateAVFObjC : public AudioTrackPrivateAVF {
WTF_MAKE_NONCOPYABLE(AudioTrackPrivateAVFObjC)
@@ -51,6 +55,11 @@
return adoptRef(new AudioTrackPrivateAVFObjC(track));
}
+ static RefPtr<AudioTrackPrivateAVFObjC> create(MediaSelectionOptionAVFObjC& option)
+ {
+ return adoptRef(new AudioTrackPrivateAVFObjC(option));
+ }
+
virtual void setEnabled(bool);
void setPlayerItemTrack(AVPlayerItemTrack*);
@@ -59,9 +68,14 @@
void setAssetTrack(AVAssetTrack*);
AVAssetTrack* assetTrack();
+ void setMediaSelectionOption(MediaSelectionOptionAVFObjC&);
+ MediaSelectionOptionAVFObjC* mediaSelectionOption();
+
private:
+ friend class MediaPlayerPrivateAVFoundationObjC;
AudioTrackPrivateAVFObjC(AVPlayerItemTrack*);
AudioTrackPrivateAVFObjC(AVAssetTrack*);
+ AudioTrackPrivateAVFObjC(MediaSelectionOptionAVFObjC&);
void resetPropertiesFromTrack();
std::unique_ptr<AVTrackPrivateAVFObjCImpl> m_impl;
Modified: branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/AudioTrackPrivateAVFObjC.mm (178466 => 178467)
--- branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/AudioTrackPrivateAVFObjC.mm 2015-01-15 01:07:11 UTC (rev 178466)
+++ branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/AudioTrackPrivateAVFObjC.mm 2015-01-15 01:11:24 UTC (rev 178467)
@@ -26,6 +26,7 @@
#import "config.h"
#import "AudioTrackPrivateAVFObjC.h"
#import "AVTrackPrivateAVFObjCImpl.h"
+#import "MediaSelectionGroupAVFObjC.h"
#if ENABLE(VIDEO_TRACK)
@@ -37,13 +38,19 @@
resetPropertiesFromTrack();
}
+AudioTrackPrivateAVFObjC::AudioTrackPrivateAVFObjC(MediaSelectionOptionAVFObjC& option)
+ : m_impl(std::make_unique<AVTrackPrivateAVFObjCImpl>(option))
+{
+ resetPropertiesFromTrack();
+}
+
void AudioTrackPrivateAVFObjC::resetPropertiesFromTrack()
{
// Don't call this->setEnabled() because it also sets the enabled state of the
// AVPlayerItemTrack
AudioTrackPrivateAVF::setEnabled(m_impl->enabled());
- setTrackIndex(m_impl->trackID());
+ setTrackIndex(m_impl->index());
setKind(m_impl->audioKind());
setId(m_impl->id());
setLabel(m_impl->label());
@@ -78,6 +85,17 @@
return m_impl->assetTrack();
}
+void AudioTrackPrivateAVFObjC::setMediaSelectionOption(MediaSelectionOptionAVFObjC& option)
+{
+ m_impl = std::make_unique<AVTrackPrivateAVFObjCImpl>(option);
+ resetPropertiesFromTrack();
+}
+
+MediaSelectionOptionAVFObjC* AudioTrackPrivateAVFObjC::mediaSelectionOption()
+{
+ return m_impl->mediaSelectionOption();
+}
+
void AudioTrackPrivateAVFObjC::setEnabled(bool enabled)
{
AudioTrackPrivateAVF::setEnabled(enabled);
Modified: branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h (178466 => 178467)
--- branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h 2015-01-15 01:07:11 UTC (rev 178466)
+++ branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h 2015-01-15 01:11:24 UTC (rev 178467)
@@ -63,6 +63,7 @@
class InbandMetadataTextTrackPrivateAVF;
class InbandTextTrackPrivateAVFObjC;
class AudioTrackPrivateAVFObjC;
+class MediaSelectionGroupAVFObjC;
class VideoTrackPrivateAVFObjC;
class MediaPlayerPrivateAVFoundationObjC : public MediaPlayerPrivateAVFoundation {
@@ -240,6 +241,8 @@
#if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
void processMediaSelectionOptions();
AVMediaSelectionGroup* safeMediaSelectionGroupForLegibleMedia();
+ AVMediaSelectionGroup* safeMediaSelectionGroupForAudibleMedia();
+ AVMediaSelectionGroup* safeMediaSelectionGroupForVisualMedia();
#endif
#if ENABLE(DATACUE_VALUE)
@@ -318,7 +321,11 @@
#if ENABLE(VIDEO_TRACK)
Vector<RefPtr<AudioTrackPrivateAVFObjC>> m_audioTracks;
Vector<RefPtr<VideoTrackPrivateAVFObjC>> m_videoTracks;
+#if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
+ RefPtr<MediaSelectionGroupAVFObjC> m_audibleGroup;
+ RefPtr<MediaSelectionGroupAVFObjC> m_visualGroup;
#endif
+#endif
InbandTextTrackPrivateAVF* m_currentTextTrack;
Modified: branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm (178466 => 178467)
--- branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm 2015-01-15 01:07:11 UTC (rev 178466)
+++ branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm 2015-01-15 01:11:24 UTC (rev 178467)
@@ -46,6 +46,7 @@
#import "OutOfBandTextTrackPrivateAVF.h"
#import "URL.h"
#import "Logging.h"
+#import "MediaSelectionGroupAVFObjC.h"
#import "MediaTimeAVFoundation.h"
#import "PlatformTimeRanges.h"
#import "SecurityOrigin.h"
@@ -66,6 +67,7 @@
#import <runtime/Uint8Array.h>
#import <wtf/CurrentTime.h>
#import <wtf/Functional.h>
+#import <wtf/ListHashSet.h>
#import <wtf/NeverDestroyed.h>
#import <wtf/text/CString.h>
#import <wtf/text/StringBuilder.h>
@@ -88,6 +90,12 @@
#import <VideoToolbox/VideoToolbox.h>
#endif
+namespace std {
+template <> struct iterator_traits<HashSet<RefPtr<WebCore::MediaSelectionOptionAVFObjC>>::iterator> {
+ typedef RefPtr<WebCore::MediaSelectionOptionAVFObjC> value_type;
+};
+}
+
@interface WebVideoContainerLayer : CALayer
@end
@@ -123,7 +131,11 @@
typedef AVPlayer AVPlayerType;
typedef AVPlayerItem AVPlayerItemType;
+typedef AVPlayerItemLegibleOutput AVPlayerItemLegibleOutputType;
+typedef AVPlayerItemVideoOutput AVPlayerItemVideoOutputType;
typedef AVMetadataItem AVMetadataItemType;
+typedef AVMediaSelectionGroup AVMediaSelectionGroupType;
+typedef AVMediaSelectionOption AVMediaSelectionOptionType;
SOFT_LINK_FRAMEWORK_OPTIONAL(AVFoundation)
SOFT_LINK_FRAMEWORK_OPTIONAL(CoreMedia)
@@ -853,7 +865,7 @@
#endif
#if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
- [m_avPlayer.get() setAppliesMediaSelectionCriteriaAutomatically:YES];
+ [m_avPlayer.get() setAppliesMediaSelectionCriteriaAutomatically:NO];
#endif
#if ENABLE(IOS_AIRPLAY)
@@ -909,6 +921,12 @@
[m_avPlayerItem.get() addOutput:m_legibleOutput.get()];
#endif
+#if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
+ [m_avPlayerItem selectMediaOptionAutomaticallyInMediaSelectionGroup:safeMediaSelectionGroupForLegibleMedia()];
+ [m_avPlayerItem selectMediaOptionAutomaticallyInMediaSelectionGroup:safeMediaSelectionGroupForAudibleMedia()];
+ [m_avPlayerItem selectMediaOptionAutomaticallyInMediaSelectionGroup:safeMediaSelectionGroupForVisualMedia()];
+#endif
+
setDelayCallbacks(false);
}
@@ -1735,24 +1753,27 @@
}]]]);
RetainPtr<NSMutableSet> oldTracks = adoptNS([[NSMutableSet alloc] initWithCapacity:oldItems.size()]);
- typedef Vector<RefT> ItemVector;
- for (auto i = oldItems.begin(); i != oldItems.end(); ++i)
- [oldTracks addObject:(*i)->playerItemTrack()];
+ for (auto& oldItem : oldItems) {
+ if (oldItem->playerItemTrack())
+ [oldTracks addObject:oldItem->playerItemTrack()];
+ }
+ // Find the added & removed AVPlayerItemTracks:
RetainPtr<NSMutableSet> removedTracks = adoptNS([oldTracks mutableCopy]);
[removedTracks minusSet:newTracks.get()];
RetainPtr<NSMutableSet> addedTracks = adoptNS([newTracks mutableCopy]);
[addedTracks minusSet:oldTracks.get()];
+ typedef Vector<RefT> ItemVector;
ItemVector replacementItems;
ItemVector addedItems;
ItemVector removedItems;
- for (auto i = oldItems.begin(); i != oldItems.end(); ++i) {
- if ([removedTracks containsObject:(*i)->playerItemTrack()])
- removedItems.append(*i);
+ for (auto& oldItem : oldItems) {
+ if (oldItem->playerItemTrack() && [removedTracks containsObject:oldItem->playerItemTrack()])
+ removedItems.append(oldItem);
else
- replacementItems.append(*i);
+ replacementItems.append(oldItem);
}
for (AVPlayerItemTrack* track in addedTracks.get())
@@ -1761,13 +1782,75 @@
replacementItems.appendVector(addedItems);
oldItems.swap(replacementItems);
- for (auto i = removedItems.begin(); i != removedItems.end(); ++i)
- (player->*removedFunction)(*i);
+ for (auto& removedItem : removedItems)
+ (player->*removedFunction)(removedItem);
- for (auto i = addedItems.begin(); i != addedItems.end(); ++i)
- (player->*addedFunction)(*i);
+ for (auto& addedItem : addedItems)
+ (player->*addedFunction)(addedItem);
}
+#if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
+template <typename RefT, typename PassRefT>
+void determineChangedTracksFromNewTracksAndOldItems(MediaSelectionGroupAVFObjC* group, Vector<RefT>& oldItems, RefT (*itemFactory)(MediaSelectionOptionAVFObjC&), MediaPlayer* player, void (MediaPlayer::*removedFunction)(PassRefT), void (MediaPlayer::*addedFunction)(PassRefT))
+{
+ group->updateOptions();
+
+ // Only add selection options which do not have an associated persistant track.
+ ListHashSet<RefPtr<MediaSelectionOptionAVFObjC>> newSelectionOptions;
+ for (auto& option : group->options()) {
+ if (!option)
+ continue;
+ AVMediaSelectionOptionType* avOption = option->avMediaSelectionOption();
+ if (!avOption)
+ continue;
+ if (![avOption respondsToSelector:@selector(track)] || ![avOption performSelector:@selector(track)])
+ newSelectionOptions.add(option);
+ }
+
+ ListHashSet<RefPtr<MediaSelectionOptionAVFObjC>> oldSelectionOptions;
+ for (auto& oldItem : oldItems) {
+ if (MediaSelectionOptionAVFObjC *option = oldItem->mediaSelectionOption())
+ oldSelectionOptions.add(option);
+ }
+
+ // Find the added & removed AVMediaSelectionOptions:
+ ListHashSet<RefPtr<MediaSelectionOptionAVFObjC>> removedSelectionOptions;
+ for (auto& oldOption : oldSelectionOptions) {
+ if (!newSelectionOptions.contains(oldOption))
+ removedSelectionOptions.add(oldOption);
+ }
+
+ ListHashSet<RefPtr<MediaSelectionOptionAVFObjC>> addedSelectionOptions;
+ for (auto& newOption : newSelectionOptions) {
+ if (!oldSelectionOptions.contains(newOption))
+ addedSelectionOptions.add(newOption);
+ }
+
+ typedef Vector<RefT> ItemVector;
+ ItemVector replacementItems;
+ ItemVector addedItems;
+ ItemVector removedItems;
+ for (auto& oldItem : oldItems) {
+ if (oldItem->mediaSelectionOption() && removedSelectionOptions.contains(oldItem->mediaSelectionOption()))
+ removedItems.append(oldItem);
+ else
+ replacementItems.append(oldItem);
+ }
+
+ for (auto& option : addedSelectionOptions)
+ addedItems.append(itemFactory(*option.get()));
+
+ replacementItems.appendVector(addedItems);
+ oldItems.swap(replacementItems);
+
+ for (auto& removedItem : removedItems)
+ (player->*removedFunction)(removedItem);
+
+ for (auto& addedItem : addedItems)
+ (player->*addedFunction)(addedItem);
+}
+#endif
+
void MediaPlayerPrivateAVFoundationObjC::updateAudioTracks()
{
#if !LOG_DISABLED
@@ -1776,6 +1859,19 @@
determineChangedTracksFromNewTracksAndOldItems(m_cachedTracks.get(), AVMediaTypeAudio, m_audioTracks, &AudioTrackPrivateAVFObjC::create, player(), &MediaPlayer::removeAudioTrack, &MediaPlayer::addAudioTrack);
+#if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
+ if (!m_audibleGroup) {
+ if (AVMediaSelectionGroupType *group = safeMediaSelectionGroupForAudibleMedia())
+ m_audibleGroup = MediaSelectionGroupAVFObjC::create(m_avPlayerItem.get(), group);
+ }
+
+ if (m_audibleGroup)
+ determineChangedTracksFromNewTracksAndOldItems(m_audibleGroup.get(), m_audioTracks, &AudioTrackPrivateAVFObjC::create, player(), &MediaPlayer::removeAudioTrack, &MediaPlayer::addAudioTrack);
+#endif
+
+ for (auto& track : m_audioTracks)
+ track->resetPropertiesFromTrack();
+
#if !LOG_DISABLED
LOG(Media, "MediaPlayerPrivateAVFoundationObjC::updateAudioTracks(%p) - audio track count was %lu, is %lu", this, count, m_audioTracks.size());
#endif
@@ -1789,6 +1885,19 @@
determineChangedTracksFromNewTracksAndOldItems(m_cachedTracks.get(), AVMediaTypeVideo, m_videoTracks, &VideoTrackPrivateAVFObjC::create, player(), &MediaPlayer::removeVideoTrack, &MediaPlayer::addVideoTrack);
+#if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
+ if (!m_visualGroup) {
+ if (AVMediaSelectionGroupType *group = safeMediaSelectionGroupForVisualMedia())
+ m_visualGroup = MediaSelectionGroupAVFObjC::create(m_avPlayerItem.get(), group);
+ }
+
+ if (m_visualGroup)
+ determineChangedTracksFromNewTracksAndOldItems(m_visualGroup.get(), m_videoTracks, &VideoTrackPrivateAVFObjC::create, player(), &MediaPlayer::removeVideoTrack, &MediaPlayer::addVideoTrack);
+#endif
+
+ for (auto& track : m_audioTracks)
+ track->resetPropertiesFromTrack();
+
#if !LOG_DISABLED
LOG(Media, "MediaPlayerPrivateAVFoundationObjC::updateVideoTracks(%p) - video track count was %lu, is %lu", this, count, m_videoTracks.size());
#endif
@@ -2193,6 +2302,28 @@
return [m_avAsset.get() mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicLegible];
}
+AVMediaSelectionGroupType* MediaPlayerPrivateAVFoundationObjC::safeMediaSelectionGroupForAudibleMedia()
+{
+ if (!m_avAsset)
+ return nil;
+
+ if ([m_avAsset.get() statusOfValueForKey:@"availableMediaCharacteristicsWithMediaSelectionOptions" error:NULL] != AVKeyValueStatusLoaded)
+ return nil;
+
+ return [m_avAsset.get() mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicAudible];
+}
+
+AVMediaSelectionGroupType* MediaPlayerPrivateAVFoundationObjC::safeMediaSelectionGroupForVisualMedia()
+{
+ if (!m_avAsset)
+ return nil;
+
+ if ([m_avAsset.get() statusOfValueForKey:@"availableMediaCharacteristicsWithMediaSelectionOptions" error:NULL] != AVKeyValueStatusLoaded)
+ return nil;
+
+ return [m_avAsset.get() mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicVisual];
+}
+
void MediaPlayerPrivateAVFoundationObjC::processMediaSelectionOptions()
{
AVMediaSelectionGroupType *legibleGroup = safeMediaSelectionGroupForLegibleMedia();
@@ -2583,7 +2714,14 @@
for (AVPlayerItemTrack *track in m_cachedTracks.get())
[track removeObserver:m_objcObserver.get() forKeyPath:@"enabled"];
- m_cachedTracks = tracks;
+ NSArray *assetTracks = [m_avAsset tracks];
+
+ // Tracks which are not present in the AVAsset are streaming tracks, and will instead be represented by
+ // AVMediaSelectionOptions.
+ m_cachedTracks = [tracks objectsAtIndexes:[tracks indexesOfObjectsPassingTest:^(id obj, NSUInteger, BOOL*) {
+ return [assetTracks containsObject:[obj assetTrack]];
+ }]];
+
for (AVPlayerItemTrack *track in m_cachedTracks.get())
[track addObserver:m_objcObserver.get() forKeyPath:@"enabled" options:NSKeyValueObservingOptionNew context:(void *)MediaPlayerAVFoundationObservationContextPlayerItemTrack];
Modified: branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/VideoTrackPrivateAVFObjC.cpp (178466 => 178467)
--- branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/VideoTrackPrivateAVFObjC.cpp 2015-01-15 01:07:11 UTC (rev 178466)
+++ branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/VideoTrackPrivateAVFObjC.cpp 2015-01-15 01:11:24 UTC (rev 178467)
@@ -26,6 +26,7 @@
#import "config.h"
#import "VideoTrackPrivateAVFObjC.h"
#import "AVTrackPrivateAVFObjCImpl.h"
+#import "MediaSelectionGroupAVFObjC.h"
#if ENABLE(VIDEO_TRACK)
@@ -43,6 +44,12 @@
resetPropertiesFromTrack();
}
+VideoTrackPrivateAVFObjC::VideoTrackPrivateAVFObjC(MediaSelectionOptionAVFObjC& option)
+ : m_impl(std::make_unique<AVTrackPrivateAVFObjCImpl>(option))
+{
+ resetPropertiesFromTrack();
+}
+
void VideoTrackPrivateAVFObjC::resetPropertiesFromTrack()
{
// Don't call this->setSelected() because it also sets the enabled state of the
@@ -78,6 +85,17 @@
return m_impl->assetTrack();
}
+void VideoTrackPrivateAVFObjC::setMediaSelectonOption(MediaSelectionOptionAVFObjC& option)
+{
+ m_impl = std::make_unique<AVTrackPrivateAVFObjCImpl>(option);
+ resetPropertiesFromTrack();
+}
+
+MediaSelectionOptionAVFObjC* VideoTrackPrivateAVFObjC::mediaSelectionOption()
+{
+ return m_impl->mediaSelectionOption();
+}
+
void VideoTrackPrivateAVFObjC::setSelected(bool enabled)
{
VideoTrackPrivateAVF::setSelected(enabled);
Modified: branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/VideoTrackPrivateAVFObjC.h (178466 => 178467)
--- branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/VideoTrackPrivateAVFObjC.h 2015-01-15 01:07:11 UTC (rev 178466)
+++ branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/VideoTrackPrivateAVFObjC.h 2015-01-15 01:11:24 UTC (rev 178467)
@@ -31,11 +31,15 @@
#include "VideoTrackPrivateAVF.h"
OBJC_CLASS AVAssetTrack;
+OBJC_CLASS AVPlayerItem;
OBJC_CLASS AVPlayerItemTrack;
+OBJC_CLASS AVMediaSelectionGroup;
+OBJC_CLASS AVMediaSelectionOption;
namespace WebCore {
class AVTrackPrivateAVFObjCImpl;
+class MediaSelectionOptionAVFObjC;
class VideoTrackPrivateAVFObjC final : public VideoTrackPrivateAVF {
WTF_MAKE_NONCOPYABLE(VideoTrackPrivateAVFObjC)
@@ -50,6 +54,11 @@
return adoptRef(new VideoTrackPrivateAVFObjC(track));
}
+ static RefPtr<VideoTrackPrivateAVFObjC> create(MediaSelectionOptionAVFObjC& option)
+ {
+ return adoptRef(new VideoTrackPrivateAVFObjC(option));
+ }
+
virtual void setSelected(bool) override;
void setPlayerItemTrack(AVPlayerItemTrack*);
@@ -58,9 +67,13 @@
void setAssetTrack(AVAssetTrack*);
AVAssetTrack* assetTrack();
+ void setMediaSelectonOption(MediaSelectionOptionAVFObjC&);
+ MediaSelectionOptionAVFObjC* mediaSelectionOption();
+
private:
explicit VideoTrackPrivateAVFObjC(AVPlayerItemTrack*);
explicit VideoTrackPrivateAVFObjC(AVAssetTrack*);
+ explicit VideoTrackPrivateAVFObjC(MediaSelectionOptionAVFObjC&);
void resetPropertiesFromTrack();
std::unique_ptr<AVTrackPrivateAVFObjCImpl> m_impl;
Modified: branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/VideoTrackPrivateMediaSourceAVFObjC.mm (178466 => 178467)
--- branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/VideoTrackPrivateMediaSourceAVFObjC.mm 2015-01-15 01:07:11 UTC (rev 178466)
+++ branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/VideoTrackPrivateMediaSourceAVFObjC.mm 2015-01-15 01:11:24 UTC (rev 178467)
@@ -47,6 +47,7 @@
{
m_trackID = m_impl->trackID();
+ setTrackIndex(m_impl->index());
setKind(m_impl->videoKind());
setId(m_impl->id());
setLabel(m_impl->label());