01502cdb0beabe3880bf33d5432f2f6526f36c7f
[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
39 #import <pal/cocoa/AVFoundationSoftLink.h>
40
41 @class AVMediaSelectionOption;
42 @interface AVMediaSelectionOption (WebKitInternal)
43 - (id)optionID;
44 @end
45
46 namespace WebCore {
47
48 AVTrackPrivateAVFObjCImpl::AVTrackPrivateAVFObjCImpl(AVPlayerItemTrack* track)
49     : m_playerItemTrack(track)
50     , m_assetTrack([track assetTrack])
51 {
52 }
53
54 AVTrackPrivateAVFObjCImpl::AVTrackPrivateAVFObjCImpl(AVAssetTrack* track)
55     : m_assetTrack(track)
56 {
57 }
58
59 AVTrackPrivateAVFObjCImpl::AVTrackPrivateAVFObjCImpl(MediaSelectionOptionAVFObjC& option)
60     : m_mediaSelectionOption(&option)
61 {
62 }
63
64 AVTrackPrivateAVFObjCImpl::~AVTrackPrivateAVFObjCImpl()
65 {
66 }
67     
68 bool AVTrackPrivateAVFObjCImpl::enabled() const
69 {
70     if (m_playerItemTrack)
71         return [m_playerItemTrack isEnabled];
72     if (m_mediaSelectionOption)
73         return m_mediaSelectionOption->selected();
74     ASSERT_NOT_REACHED();
75     return false;
76 }
77
78 void AVTrackPrivateAVFObjCImpl::setEnabled(bool enabled)
79 {
80     if (m_playerItemTrack)
81         [m_playerItemTrack setEnabled:enabled];
82     else if (m_mediaSelectionOption)
83         m_mediaSelectionOption->setSelected(enabled);
84     else
85         ASSERT_NOT_REACHED();
86 }
87
88 AudioTrackPrivate::Kind AVTrackPrivateAVFObjCImpl::audioKind() const
89 {
90     if (m_assetTrack) {
91         if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
92             return AudioTrackPrivate::Alternative;
93         if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
94             return AudioTrackPrivate::Description;
95         if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
96             return AudioTrackPrivate::Main;
97         return AudioTrackPrivate::None;
98     }
99
100     if (m_mediaSelectionOption) {
101         AVMediaSelectionOption *option = m_mediaSelectionOption->avMediaSelectionOption();
102         if ([option hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
103             return AudioTrackPrivate::Alternative;
104         if ([option hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
105             return AudioTrackPrivate::Description;
106         if ([option hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
107             return AudioTrackPrivate::Main;
108         return AudioTrackPrivate::None;
109     }
110
111     ASSERT_NOT_REACHED();
112     return AudioTrackPrivate::None;
113 }
114
115 VideoTrackPrivate::Kind AVTrackPrivateAVFObjCImpl::videoKind() const
116 {
117     if (m_assetTrack) {
118         if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
119             return VideoTrackPrivate::Sign;
120         if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicTranscribesSpokenDialogForAccessibility])
121             return VideoTrackPrivate::Captions;
122         if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
123             return VideoTrackPrivate::Alternative;
124         if ([m_assetTrack hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
125             return VideoTrackPrivate::Main;
126         return VideoTrackPrivate::None;
127     }
128
129     if (m_mediaSelectionOption) {
130         AVMediaSelectionOption *option = m_mediaSelectionOption->avMediaSelectionOption();
131         if ([option hasMediaCharacteristic:AVMediaCharacteristicDescribesVideoForAccessibility])
132             return VideoTrackPrivate::Sign;
133         if ([option hasMediaCharacteristic:AVMediaCharacteristicTranscribesSpokenDialogForAccessibility])
134             return VideoTrackPrivate::Captions;
135         if ([option hasMediaCharacteristic:AVMediaCharacteristicIsAuxiliaryContent])
136             return VideoTrackPrivate::Alternative;
137         if ([option hasMediaCharacteristic:AVMediaCharacteristicIsMainProgramContent])
138             return VideoTrackPrivate::Main;
139         return VideoTrackPrivate::None;
140     }
141
142     ASSERT_NOT_REACHED();
143     return VideoTrackPrivate::None;
144 }
145
146 int AVTrackPrivateAVFObjCImpl::index() const
147 {
148     if (m_assetTrack)
149         return [[[m_assetTrack asset] tracks] indexOfObject:m_assetTrack.get()];
150     if (m_mediaSelectionOption)
151         return [[[m_playerItem asset] tracks] count] + m_mediaSelectionOption->index();
152     ASSERT_NOT_REACHED();
153     return 0;
154 }
155
156 AtomicString AVTrackPrivateAVFObjCImpl::id() const
157 {
158     if (m_assetTrack)
159         return AtomicString::number([m_assetTrack trackID]);
160     if (m_mediaSelectionOption)
161         return [[m_mediaSelectionOption->avMediaSelectionOption() optionID] stringValue];
162     ASSERT_NOT_REACHED();
163     return emptyAtom();
164 }
165
166 AtomicString AVTrackPrivateAVFObjCImpl::label() const
167 {
168     NSArray *commonMetadata = nil;
169     if (m_assetTrack)
170         commonMetadata = [m_assetTrack commonMetadata];
171     else if (m_mediaSelectionOption)
172         commonMetadata = [m_mediaSelectionOption->avMediaSelectionOption() commonMetadata];
173     else
174         ASSERT_NOT_REACHED();
175
176     NSArray *titles = [PAL::getAVMetadataItemClass() metadataItemsFromArray:commonMetadata withKey:AVMetadataCommonKeyTitle keySpace:AVMetadataKeySpaceCommon];
177     if (![titles count])
178         return emptyAtom();
179
180     // If possible, return a title in one of the user's preferred languages.
181     NSArray *titlesForPreferredLanguages = [PAL::getAVMetadataItemClass() metadataItemsFromArray:titles filteredAndSortedAccordingToPreferredLanguages:[NSLocale preferredLanguages]];
182     if ([titlesForPreferredLanguages count])
183         return [[titlesForPreferredLanguages objectAtIndex:0] stringValue];
184     return [[titles objectAtIndex:0] stringValue];
185 }
186
187 AtomicString AVTrackPrivateAVFObjCImpl::language() const
188 {
189     if (m_assetTrack)
190         return languageForAVAssetTrack(m_assetTrack.get());
191     if (m_mediaSelectionOption)
192         return languageForAVMediaSelectionOption(m_mediaSelectionOption->avMediaSelectionOption());
193
194     ASSERT_NOT_REACHED();
195     return emptyAtom();
196 }
197
198 String AVTrackPrivateAVFObjCImpl::languageForAVAssetTrack(AVAssetTrack* track)
199 {
200     NSString *language = [track extendedLanguageTag];
201
202     // If the language code is stored as a QuickTime 5-bit packed code there aren't enough bits for a full
203     // RFC 4646 language tag so extendedLanguageTag returns NULL. In this case languageCode will return the
204     // ISO 639-2/T language code so check it.
205     if (!language)
206         language = [track languageCode];
207
208     // Some legacy tracks have "und" as a language, treat that the same as no language at all.
209     if (!language || [language isEqualToString:@"und"])
210         return emptyString();
211
212     return language;
213 }
214
215 String AVTrackPrivateAVFObjCImpl::languageForAVMediaSelectionOption(AVMediaSelectionOption* option)
216 {
217     NSString *language = [option extendedLanguageTag];
218
219     // If the language code is stored as a QuickTime 5-bit packed code there aren't enough bits for a full
220     // RFC 4646 language tag so extendedLanguageTag returns NULL. In this case languageCode will return the
221     // ISO 639-2/T language code so check it.
222     if (!language)
223         language = [[option locale] objectForKey:NSLocaleLanguageCode];
224
225     // Some legacy tracks have "und" as a language, treat that the same as no language at all.
226     if (!language || [language isEqualToString:@"und"])
227         return emptyString();
228     
229     return language;
230 }
231
232 int AVTrackPrivateAVFObjCImpl::trackID() const
233 {
234     if (m_assetTrack)
235         return [m_assetTrack trackID];
236     if (m_mediaSelectionOption)
237         return [[m_mediaSelectionOption->avMediaSelectionOption() optionID] intValue];
238     ASSERT_NOT_REACHED();
239     return 0;
240 }
241
242 }
243
244 #endif // ENABLE(VIDEO_TRACK)