48bee8a18c59284baf3fd647a9a067e2278a60b7
[WebKit-https.git] / Source / WebCore / platform / graphics / avfoundation / cf / InbandTextTrackPrivateAVCF.cpp
1 /*
2  * Copyright (C) 2013, 2015 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
28 #if PLATFORM(WIN) && ENABLE(VIDEO) && HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
29
30 #include "InbandTextTrackPrivateAVCF.h"
31
32 #include "FloatConversion.h"
33 #include "ISOVTTCue.h"
34 #include "InbandTextTrackPrivate.h"
35 #include "InbandTextTrackPrivateAVF.h"
36 #include "Logging.h"
37 #include "MediaTimeAVFoundation.h"
38 #include "SoftLinking.h"
39 #include <JavaScriptCore/ArrayBuffer.h>
40
41 #include <AVFoundationCF/AVCFPlayerItemLegibleOutput.h>
42 #include <AVFoundationCF/AVFoundationCF.h>
43
44 #include <d3d9.h>
45
46 // The softlink header files must be included after the AVCF and CoreMedia header files.
47 #include "AVFoundationCFSoftLinking.h"
48
49 namespace WebCore {
50
51 InbandTextTrackPrivateAVCF::InbandTextTrackPrivateAVCF(AVFInbandTrackParent* player, AVCFMediaSelectionOptionRef selection, InbandTextTrackPrivate::CueFormat format)
52     : InbandTextTrackPrivateAVF(player, format)
53     , m_mediaSelectionOption(selection)
54 {
55 }
56
57 void InbandTextTrackPrivateAVCF::disconnect()
58 {
59     m_mediaSelectionOption = 0;
60     InbandTextTrackPrivateAVF::disconnect();
61 }
62
63 InbandTextTrackPrivate::Kind InbandTextTrackPrivateAVCF::kind() const
64 {
65     if (!m_mediaSelectionOption)
66         return InbandTextTrackPrivate::None;
67
68     CFStringRef mediaType = AVCFMediaSelectionOptionGetMediaType(mediaSelectionOption());
69     
70     if (CFStringCompare(mediaType, AVCFMediaTypeClosedCaption, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
71         return InbandTextTrackPrivate::Captions;
72     if (CFStringCompare(mediaType, AVCFMediaTypeSubtitle, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
73         if (AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicContainsOnlyForcedSubtitles))
74             return InbandTextTrackPrivate::Forced;
75
76         // An "SDH" track is a subtitle track created for the deaf or hard-of-hearing. "captions" in WebVTT are
77         // "labeled as appropriate for the hard-of-hearing", so tag SDH sutitles as "captions".
78         if (AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicTranscribesSpokenDialogForAccessibility))
79             return InbandTextTrackPrivate::Captions;
80         if (AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicDescribesMusicAndSoundForAccessibility))
81             return InbandTextTrackPrivate::Captions;
82         
83         return InbandTextTrackPrivate::Subtitles;
84     }
85
86     return InbandTextTrackPrivate::Captions;
87 }
88
89 bool InbandTextTrackPrivateAVCF::isClosedCaptions() const
90 {
91     if (!m_mediaSelectionOption)
92         return false;
93
94     CFStringRef mediaType = AVCFMediaSelectionOptionGetMediaType(mediaSelectionOption());
95
96     return (CFStringCompare(mediaType, AVCFMediaTypeClosedCaption, kCFCompareCaseInsensitive) == kCFCompareEqualTo);
97 }
98
99 bool InbandTextTrackPrivateAVCF::isSDH() const
100 {
101     if (!m_mediaSelectionOption)
102         return false;
103     
104     CFStringRef mediaType = AVCFMediaSelectionOptionGetMediaType(mediaSelectionOption());
105
106     if (CFStringCompare(mediaType, AVCFMediaTypeSubtitle, kCFCompareCaseInsensitive) != kCFCompareEqualTo)
107         return false;
108
109     if (AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicTranscribesSpokenDialogForAccessibility)
110         && AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicDescribesMusicAndSoundForAccessibility))
111         return true;
112
113     return false;
114 }
115     
116 bool InbandTextTrackPrivateAVCF::containsOnlyForcedSubtitles() const
117 {
118     if (!m_mediaSelectionOption)
119         return false;
120     
121     return AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicContainsOnlyForcedSubtitles);
122 }
123
124 bool InbandTextTrackPrivateAVCF::isMainProgramContent() const
125 {
126     if (!m_mediaSelectionOption)
127         return false;
128     
129     return AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicIsMainProgramContent);
130 }
131
132 bool InbandTextTrackPrivateAVCF::isEasyToRead() const
133 {
134     if (!m_mediaSelectionOption)
135         return false;
136
137     return AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicEasyToRead);
138 }
139
140 AtomicString InbandTextTrackPrivateAVCF::label() const
141 {
142     if (!m_mediaSelectionOption)
143         return emptyAtom;
144
145     RetainPtr<CFStringRef> title;
146
147     RetainPtr<CFArrayRef> commonMetaData = adoptCF(AVCFMediaSelectionOptionCopyCommonMetadata(mediaSelectionOption()));
148     RetainPtr<CFArrayRef> titles = adoptCF(AVCFMetadataItemCopyItemsWithKeyAndKeySpace(commonMetaData.get(), AVCFMetadataCommonKeyTitle, AVCFMetadataKeySpaceCommon));
149     if (!titles)
150         return emptyAtom;
151
152     CFIndex titlesCount = CFArrayGetCount(titles.get());
153     if (!titlesCount)
154         return emptyAtom;
155
156     // If possible, return a title in one of the user's preferred languages.
157     RetainPtr<CFArrayRef> preferredLanguages = adoptCF(CFLocaleCopyPreferredLanguages());
158     RetainPtr<CFArrayRef> titlesForPreferredLanguages = adoptCF(AVCFMediaSelectionCopyOptionsFromArrayFilteredAndSortedAccordingToPreferredLanguages(titles.get(), preferredLanguages.get()));
159     CFIndex preferredTitlesCount = CFArrayGetCount(titlesForPreferredLanguages.get());
160     if (preferredTitlesCount) {
161         AVCFMetadataItemRef titleMetadata = static_cast<AVCFMetadataItemRef>(CFArrayGetValueAtIndex(titlesForPreferredLanguages.get(), 0));
162         title = adoptCF(AVCFMetadataItemCopyStringValue(titleMetadata));
163     }
164
165     if (!title) {
166         AVCFMetadataItemRef titleMetadata = static_cast<AVCFMetadataItemRef>(CFArrayGetValueAtIndex(titles.get(), 0));
167         title = adoptCF(AVCFMetadataItemCopyStringValue(titleMetadata));
168     }
169
170     return title ? AtomicString(title.get()) : emptyAtom;
171 }
172
173 AtomicString InbandTextTrackPrivateAVCF::language() const
174 {
175     if (!m_mediaSelectionOption)
176         return emptyAtom;
177
178     RetainPtr<CFLocaleRef> locale = adoptCF(AVCFMediaSelectionOptionCopyLocale(mediaSelectionOption()));
179     if (!locale)
180         return emptyAtom;
181
182     return CFLocaleGetIdentifier(locale.get());
183 }
184
185 bool InbandTextTrackPrivateAVCF::isDefault() const
186 {
187     return false;
188 }
189
190 bool InbandTextTrackPrivateAVCF::readNativeSampleBuffer(CFArrayRef nativeSamples, CFIndex index, RefPtr<ArrayBuffer>& buffer, MediaTime& duration, CMFormatDescriptionRef& formatDescription)
191 {
192 #if HAVE(AVCFPLAYERITEM_CALLBACK_VERSION_2)
193     const AVCFPlayerItemLegibleOutputSample* sampleBuffer = reinterpret_cast<const AVCFPlayerItemLegibleOutputSample*>(CFArrayGetValueAtIndex(nativeSamples, index));
194     if (!sampleBuffer)
195         return false;
196
197     duration = toMediaTime(sampleBuffer->duration);
198     formatDescription = sampleBuffer->formatDescription;
199
200     size_t bufferLength = CFDataGetLength(sampleBuffer->buffer);
201     if (bufferLength < ISOBox::boxHeaderSize()) {
202         LOG(Media, "InbandTextTrackPrivateLegacyAVCF::readNativeSampleBuffer(%p) - ERROR: CFBuffer size length unexpectedly small (%zu)!!", this, bufferLength);
203         return false;
204     }
205
206     m_sampleInputBuffer.resize(m_sampleInputBuffer.size() + bufferLength);
207     CFDataGetBytes(sampleBuffer->buffer, CFRangeMake(0, bufferLength), reinterpret_cast<UInt8*>(m_sampleInputBuffer.data()) + m_sampleInputBuffer.size() - bufferLength);
208
209     buffer = ArrayBuffer::create(m_sampleInputBuffer.data(), m_sampleInputBuffer.size());
210
211     return true;
212 #else
213     return InbandTextTrackPrivateAVF::readNativeSampleBuffer(nativeSamples, index, buffer, duration, formatDescription);
214 #endif
215 }
216
217 } // namespace WebCore
218
219 #endif