[WTF] Clean up StringStatics.cpp by using LazyNeverDestroyed<> for Atoms
[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 "SoftLinking.h"
33 #import <AVFoundation/AVAssetTrack.h>
34 #import <AVFoundation/AVMediaSelectionGroup.h>
35 #import <AVFoundation/AVMetadataItem.h>
36 #import <AVFoundation/AVPlayerItem.h>
37 #import <AVFoundation/AVPlayerItemTrack.h>
38 #import <objc/runtime.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_POINTER_OPTIONAL(AVFoundation, AVMediaCharacteristicIsMainProgramContent, NSString *)
55 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVMediaCharacteristicDescribesVideoForAccessibility, NSString *)
56 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVMediaCharacteristicIsAuxiliaryContent, NSString *)
57 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVMediaCharacteristicTranscribesSpokenDialogForAccessibility, NSString *)
58 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVMetadataCommonKeyTitle, NSString *)
59 SOFT_LINK_POINTER_OPTIONAL(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 ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
116             return AudioTrackPrivate::Alternative;
117         if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
118             return AudioTrackPrivate::Description;
119         if ([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 ([option hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
127             return AudioTrackPrivate::Alternative;
128         if ([option hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
129             return AudioTrackPrivate::Description;
130         if ([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 ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
143             return VideoTrackPrivate::Sign;
144         if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicTranscribesSpokenDialogForAccessibility])
145             return VideoTrackPrivate::Captions;
146         if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
147             return VideoTrackPrivate::Alternative;
148         if ([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 ([option hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
156             return VideoTrackPrivate::Sign;
157         if ([option hasMediaCharacteristic:AVMediaCharacteristicTranscribesSpokenDialogForAccessibility])
158             return VideoTrackPrivate::Captions;
159         if ([option hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
160             return VideoTrackPrivate::Alternative;
161         if ([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 String::format("%d", [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     NSArray *commonMetadata = nil;
193     if (m_assetTrack)
194         commonMetadata = [m_assetTrack commonMetadata];
195     else if (m_mediaSelectionOption)
196         commonMetadata = [m_mediaSelectionOption->avMediaSelectionOption() commonMetadata];
197     else
198         ASSERT_NOT_REACHED();
199
200     NSArray *titles = [AVMetadataItem metadataItemsFromArray:commonMetadata withKey:AVMetadataCommonKeyTitle keySpace:AVMetadataKeySpaceCommon];
201     if (![titles count])
202         return emptyAtom();
203
204     // If possible, return a title in one of the user's preferred languages.
205     NSArray *titlesForPreferredLanguages = [AVMetadataItem metadataItemsFromArray:titles filteredAndSortedAccordingToPreferredLanguages:[NSLocale preferredLanguages]];
206     if ([titlesForPreferredLanguages count])
207         return [[titlesForPreferredLanguages objectAtIndex:0] stringValue];
208     return [[titles objectAtIndex:0] stringValue];
209 }
210
211 AtomicString AVTrackPrivateAVFObjCImpl::language() const
212 {
213     if (m_assetTrack)
214         return languageForAVAssetTrack(m_assetTrack.get());
215     if (m_mediaSelectionOption)
216         return languageForAVMediaSelectionOption(m_mediaSelectionOption->avMediaSelectionOption());
217
218     ASSERT_NOT_REACHED();
219     return emptyAtom();
220 }
221
222 String AVTrackPrivateAVFObjCImpl::languageForAVAssetTrack(AVAssetTrack* track)
223 {
224     NSString *language = [track extendedLanguageTag];
225
226     // If the language code is stored as a QuickTime 5-bit packed code there aren't enough bits for a full
227     // RFC 4646 language tag so extendedLanguageTag returns NULL. In this case languageCode will return the
228     // ISO 639-2/T language code so check it.
229     if (!language)
230         language = [track languageCode];
231
232     // Some legacy tracks have "und" as a language, treat that the same as no language at all.
233     if (!language || [language isEqualToString:@"und"])
234         return emptyString();
235
236     return language;
237 }
238
239 String AVTrackPrivateAVFObjCImpl::languageForAVMediaSelectionOption(AVMediaSelectionOption* option)
240 {
241     NSString *language = [option extendedLanguageTag];
242
243     // If the language code is stored as a QuickTime 5-bit packed code there aren't enough bits for a full
244     // RFC 4646 language tag so extendedLanguageTag returns NULL. In this case languageCode will return the
245     // ISO 639-2/T language code so check it.
246     if (!language)
247         language = [[option locale] objectForKey:NSLocaleLanguageCode];
248
249     // Some legacy tracks have "und" as a language, treat that the same as no language at all.
250     if (!language || [language isEqualToString:@"und"])
251         return emptyString();
252     
253     return language;
254 }
255
256 int AVTrackPrivateAVFObjCImpl::trackID() const
257 {
258     if (m_assetTrack)
259         return [m_assetTrack trackID];
260     if (m_mediaSelectionOption)
261         return [[m_mediaSelectionOption->avMediaSelectionOption() optionID] intValue];
262     ASSERT_NOT_REACHED();
263     return 0;
264 }
265
266 }
267
268 #endif // ENABLE(VIDEO_TRACK)