Unreviewed, rolling out r244627.
[WebKit-https.git] / Source / WebCore / platform / graphics / avfoundation / AVTrackPrivateAVFObjCImpl.mm
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "AVTrackPrivateAVFObjCImpl.h"
28
29 #if ENABLE(VIDEO_TRACK)
30
31 #import "MediaSelectionGroupAVFObjC.h"
32 #import <AVFoundation/AVAssetTrack.h>
33 #import <AVFoundation/AVMediaSelectionGroup.h>
34 #import <AVFoundation/AVMetadataItem.h>
35 #import <AVFoundation/AVPlayerItem.h>
36 #import <AVFoundation/AVPlayerItemTrack.h>
37 #import <objc/runtime.h>
38 #import <wtf/SoftLinking.h>
39
40 @class AVMediaSelectionOption;
41 @interface AVMediaSelectionOption (WebKitInternal)
42 - (id)optionID;
43 @end
44
45 SOFT_LINK_FRAMEWORK_OPTIONAL(AVFoundation)
46
47 SOFT_LINK_CLASS(AVFoundation, AVAssetTrack)
48 SOFT_LINK_CLASS(AVFoundation, AVPlayerItem)
49 SOFT_LINK_CLASS(AVFoundation, AVPlayerItemTrack)
50 SOFT_LINK_CLASS(AVFoundation, AVMediaSelectionGroup)
51 SOFT_LINK_CLASS(AVFoundation, AVMediaSelectionOption)
52 SOFT_LINK_CLASS(AVFoundation, AVMetadataItem)
53
54 SOFT_LINK_CONSTANT_MAY_FAIL(AVFoundation, AVMediaCharacteristicIsMainProgramContent, NSString *)
55 SOFT_LINK_CONSTANT_MAY_FAIL(AVFoundation, AVMediaCharacteristicDescribesVideoForAccessibility, NSString *)
56 SOFT_LINK_CONSTANT_MAY_FAIL(AVFoundation, AVMediaCharacteristicIsAuxiliaryContent, NSString *)
57 SOFT_LINK_CONSTANT_MAY_FAIL(AVFoundation, AVMediaCharacteristicTranscribesSpokenDialogForAccessibility, NSString *)
58 SOFT_LINK_CONSTANT_MAY_FAIL(AVFoundation, AVMetadataCommonKeyTitle, NSString *)
59 SOFT_LINK_CONSTANT_MAY_FAIL(AVFoundation, AVMetadataKeySpaceCommon, NSString *)
60
61 #define AVMetadataItem getAVMetadataItemClass()
62
63 #define AVMediaCharacteristicIsMainProgramContent getAVMediaCharacteristicIsMainProgramContent()
64 #define AVMediaCharacteristicDescribesVideoForAccessibility getAVMediaCharacteristicDescribesVideoForAccessibility()
65 #define AVMediaCharacteristicIsAuxiliaryContent getAVMediaCharacteristicIsAuxiliaryContent()
66 #define AVMediaCharacteristicTranscribesSpokenDialogForAccessibility getAVMediaCharacteristicTranscribesSpokenDialogForAccessibility()
67 #define AVMetadataCommonKeyTitle getAVMetadataCommonKeyTitle()
68 #define AVMetadataKeySpaceCommon getAVMetadataKeySpaceCommon()
69
70 namespace WebCore {
71
72 AVTrackPrivateAVFObjCImpl::AVTrackPrivateAVFObjCImpl(AVPlayerItemTrack* track)
73     : m_playerItemTrack(track)
74     , m_assetTrack([track assetTrack])
75 {
76 }
77
78 AVTrackPrivateAVFObjCImpl::AVTrackPrivateAVFObjCImpl(AVAssetTrack* track)
79     : m_assetTrack(track)
80 {
81 }
82
83 AVTrackPrivateAVFObjCImpl::AVTrackPrivateAVFObjCImpl(MediaSelectionOptionAVFObjC& option)
84     : m_mediaSelectionOption(&option)
85 {
86 }
87
88 AVTrackPrivateAVFObjCImpl::~AVTrackPrivateAVFObjCImpl()
89 {
90 }
91     
92 bool AVTrackPrivateAVFObjCImpl::enabled() const
93 {
94     if (m_playerItemTrack)
95         return [m_playerItemTrack isEnabled];
96     if (m_mediaSelectionOption)
97         return m_mediaSelectionOption->selected();
98     ASSERT_NOT_REACHED();
99     return false;
100 }
101
102 void AVTrackPrivateAVFObjCImpl::setEnabled(bool enabled)
103 {
104     if (m_playerItemTrack)
105         [m_playerItemTrack setEnabled:enabled];
106     else if (m_mediaSelectionOption)
107         m_mediaSelectionOption->setSelected(enabled);
108     else
109         ASSERT_NOT_REACHED();
110 }
111
112 AudioTrackPrivate::Kind AVTrackPrivateAVFObjCImpl::audioKind() const
113 {
114     if (m_assetTrack) {
115         if (canLoadAVMediaCharacteristicIsAuxiliaryContent() && [m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
116             return AudioTrackPrivate::Alternative;
117         if (canLoadAVMediaCharacteristicDescribesVideoForAccessibility() && [m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
118             return AudioTrackPrivate::Description;
119         if (canLoadAVMediaCharacteristicIsMainProgramContent() && [m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
120             return AudioTrackPrivate::Main;
121         return AudioTrackPrivate::None;
122     }
123
124     if (m_mediaSelectionOption) {
125         AVMediaSelectionOption *option = m_mediaSelectionOption->avMediaSelectionOption();
126         if (canLoadAVMediaCharacteristicIsAuxiliaryContent() && [option hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
127             return AudioTrackPrivate::Alternative;
128         if (canLoadAVMediaCharacteristicDescribesVideoForAccessibility() && [option hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
129             return AudioTrackPrivate::Description;
130         if (canLoadAVMediaCharacteristicIsMainProgramContent() && [option hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
131             return AudioTrackPrivate::Main;
132         return AudioTrackPrivate::None;
133     }
134
135     ASSERT_NOT_REACHED();
136     return AudioTrackPrivate::None;
137 }
138
139 VideoTrackPrivate::Kind AVTrackPrivateAVFObjCImpl::videoKind() const
140 {
141     if (m_assetTrack) {
142         if (canLoadAVMediaCharacteristicDescribesVideoForAccessibility() && [m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
143             return VideoTrackPrivate::Sign;
144         if (canLoadAVMediaCharacteristicTranscribesSpokenDialogForAccessibility() && [m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicTranscribesSpokenDialogForAccessibility])
145             return VideoTrackPrivate::Captions;
146         if (canLoadAVMediaCharacteristicIsAuxiliaryContent() && [m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
147             return VideoTrackPrivate::Alternative;
148         if (canLoadAVMediaCharacteristicIsMainProgramContent() && [m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
149             return VideoTrackPrivate::Main;
150         return VideoTrackPrivate::None;
151     }
152
153     if (m_mediaSelectionOption) {
154         AVMediaSelectionOption *option = m_mediaSelectionOption->avMediaSelectionOption();
155         if (canLoadAVMediaCharacteristicDescribesVideoForAccessibility() && [option hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
156             return VideoTrackPrivate::Sign;
157         if (canLoadAVMediaCharacteristicTranscribesSpokenDialogForAccessibility() && [option hasMediaCharacteristic:AVMediaCharacteristicTranscribesSpokenDialogForAccessibility])
158             return VideoTrackPrivate::Captions;
159         if (canLoadAVMediaCharacteristicIsAuxiliaryContent() && [option hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
160             return VideoTrackPrivate::Alternative;
161         if (canLoadAVMediaCharacteristicIsMainProgramContent() && [option hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
162             return VideoTrackPrivate::Main;
163         return VideoTrackPrivate::None;
164     }
165
166     ASSERT_NOT_REACHED();
167     return VideoTrackPrivate::None;
168 }
169
170 int AVTrackPrivateAVFObjCImpl::index() const
171 {
172     if (m_assetTrack)
173         return [[[m_assetTrack asset] tracks] indexOfObject:m_assetTrack.get()];
174     if (m_mediaSelectionOption)
175         return [[[m_playerItem asset] tracks] count] + m_mediaSelectionOption->index();
176     ASSERT_NOT_REACHED();
177     return 0;
178 }
179
180 AtomicString AVTrackPrivateAVFObjCImpl::id() const
181 {
182     if (m_assetTrack)
183         return AtomicString::number([m_assetTrack trackID]);
184     if (m_mediaSelectionOption)
185         return [[m_mediaSelectionOption->avMediaSelectionOption() optionID] stringValue];
186     ASSERT_NOT_REACHED();
187     return emptyAtom();
188 }
189
190 AtomicString AVTrackPrivateAVFObjCImpl::label() const
191 {
192     if (!canLoadAVMetadataCommonKeyTitle() || !canLoadAVMetadataKeySpaceCommon())
193         return emptyAtom();
194
195     NSArray *commonMetadata = nil;
196     if (m_assetTrack)
197         commonMetadata = [m_assetTrack commonMetadata];
198     else if (m_mediaSelectionOption)
199         commonMetadata = [m_mediaSelectionOption->avMediaSelectionOption() commonMetadata];
200     else
201         ASSERT_NOT_REACHED();
202
203     NSArray *titles = [AVMetadataItem metadataItemsFromArray:commonMetadata withKey:AVMetadataCommonKeyTitle keySpace:AVMetadataKeySpaceCommon];
204     if (![titles count])
205         return emptyAtom();
206
207     // If possible, return a title in one of the user's preferred languages.
208     NSArray *titlesForPreferredLanguages = [AVMetadataItem metadataItemsFromArray:titles filteredAndSortedAccordingToPreferredLanguages:[NSLocale preferredLanguages]];
209     if ([titlesForPreferredLanguages count])
210         return [[titlesForPreferredLanguages objectAtIndex:0] stringValue];
211     return [[titles objectAtIndex:0] stringValue];
212 }
213
214 AtomicString AVTrackPrivateAVFObjCImpl::language() const
215 {
216     if (m_assetTrack)
217         return languageForAVAssetTrack(m_assetTrack.get());
218     if (m_mediaSelectionOption)
219         return languageForAVMediaSelectionOption(m_mediaSelectionOption->avMediaSelectionOption());
220
221     ASSERT_NOT_REACHED();
222     return emptyAtom();
223 }
224
225 String AVTrackPrivateAVFObjCImpl::languageForAVAssetTrack(AVAssetTrack* track)
226 {
227     NSString *language = [track extendedLanguageTag];
228
229     // If the language code is stored as a QuickTime 5-bit packed code there aren't enough bits for a full
230     // RFC 4646 language tag so extendedLanguageTag returns NULL. In this case languageCode will return the
231     // ISO 639-2/T language code so check it.
232     if (!language)
233         language = [track languageCode];
234
235     // Some legacy tracks have "und" as a language, treat that the same as no language at all.
236     if (!language || [language isEqualToString:@"und"])
237         return emptyString();
238
239     return language;
240 }
241
242 String AVTrackPrivateAVFObjCImpl::languageForAVMediaSelectionOption(AVMediaSelectionOption* option)
243 {
244     NSString *language = [option extendedLanguageTag];
245
246     // If the language code is stored as a QuickTime 5-bit packed code there aren't enough bits for a full
247     // RFC 4646 language tag so extendedLanguageTag returns NULL. In this case languageCode will return the
248     // ISO 639-2/T language code so check it.
249     if (!language)
250         language = [[option locale] objectForKey:NSLocaleLanguageCode];
251
252     // Some legacy tracks have "und" as a language, treat that the same as no language at all.
253     if (!language || [language isEqualToString:@"und"])
254         return emptyString();
255     
256     return language;
257 }
258
259 int AVTrackPrivateAVFObjCImpl::trackID() const
260 {
261     if (m_assetTrack)
262         return [m_assetTrack trackID];
263     if (m_mediaSelectionOption)
264         return [[m_mediaSelectionOption->avMediaSelectionOption() optionID] intValue];
265     ASSERT_NOT_REACHED();
266     return 0;
267 }
268
269 }
270
271 #endif // ENABLE(VIDEO_TRACK)