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
28#if PLATFORM(WIN) && ENABLE(VIDEO) && HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
29
30#include "InbandTextTrackPrivateAVCF.h"
31
32#include "FloatConversion.h"
33#include "InbandTextTrackPrivate.h"
34#include "InbandTextTrackPrivateAVF.h"
35#include "Logging.h"
36#include "SoftLinking.h"
37
38#include <AVFoundationCF/AVCFPlayerItemLegibleOutput.h>
39#include <AVFoundationCF/AVFoundationCF.h>
40
41#include <d3d9.h>
42
43// The softlink header files must be included after the AVCF and CoreMedia header files.
44#include "AVFoundationCFSoftLinking.h"
45
46namespace WebCore {
47
48InbandTextTrackPrivateAVCF::InbandTextTrackPrivateAVCF(AVFInbandTrackParent* player, AVCFMediaSelectionOptionRef selection, InbandTextTrackPrivate::CueFormat format)
49    : InbandTextTrackPrivateAVF(player, format)
50    , m_mediaSelectionOption(selection)
51{
52}
53
54void InbandTextTrackPrivateAVCF::disconnect()
55{
56    m_mediaSelectionOption = 0;
57    InbandTextTrackPrivateAVF::disconnect();
58}
59
60InbandTextTrackPrivate::Kind InbandTextTrackPrivateAVCF::kind() const
61{
62    if (!m_mediaSelectionOption)
63        return InbandTextTrackPrivate::None;
64
65    CFStringRef mediaType = AVCFMediaSelectionOptionGetMediaType(mediaSelectionOption());
66
67    if (CFStringCompare(mediaType, AVCFMediaTypeClosedCaption, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
68        return InbandTextTrackPrivate::Captions;
69    if (CFStringCompare(mediaType, AVCFMediaTypeSubtitle, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
70        if (AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicContainsOnlyForcedSubtitles))
71            return InbandTextTrackPrivate::Forced;
72
73        // An "SDH" track is a subtitle track created for the deaf or hard-of-hearing. "captions" in WebVTT are
74        // "labeled as appropriate for the hard-of-hearing", so tag SDH sutitles as "captions".
75        if (AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicTranscribesSpokenDialogForAccessibility))
76            return InbandTextTrackPrivate::Captions;
77        if (AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicDescribesMusicAndSoundForAccessibility))
78            return InbandTextTrackPrivate::Captions;
79
80        return InbandTextTrackPrivate::Subtitles;
81    }
82
83    return InbandTextTrackPrivate::Captions;
84}
85
86bool InbandTextTrackPrivateAVCF::isClosedCaptions() const
87{
88    if (!m_mediaSelectionOption)
89        return false;
90
91    CFStringRef mediaType = AVCFMediaSelectionOptionGetMediaType(mediaSelectionOption());
92
93    return (CFStringCompare(mediaType, AVCFMediaTypeClosedCaption, kCFCompareCaseInsensitive) == kCFCompareEqualTo);
94}
95
96bool InbandTextTrackPrivateAVCF::isSDH() const
97{
98    if (!m_mediaSelectionOption)
99        return false;
100
101    CFStringRef mediaType = AVCFMediaSelectionOptionGetMediaType(mediaSelectionOption());
102
103    if (CFStringCompare(mediaType, AVCFMediaTypeSubtitle, kCFCompareCaseInsensitive) != kCFCompareEqualTo)
104        return false;
105
106    if (AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicTranscribesSpokenDialogForAccessibility)
107        && AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicDescribesMusicAndSoundForAccessibility))
108        return true;
109
110    return false;
111}
112
113bool InbandTextTrackPrivateAVCF::containsOnlyForcedSubtitles() const
114{
115    if (!m_mediaSelectionOption)
116        return false;
117
118    return AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicContainsOnlyForcedSubtitles);
119}
120
121bool InbandTextTrackPrivateAVCF::isMainProgramContent() const
122{
123    if (!m_mediaSelectionOption)
124        return false;
125
126    return AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicIsMainProgramContent);
127}
128
129bool InbandTextTrackPrivateAVCF::isEasyToRead() const
130{
131    if (!m_mediaSelectionOption)
132        return false;
133
134    return AVCFMediaSelectionOptionHasMediaCharacteristic(mediaSelectionOption(), AVCFMediaCharacteristicEasyToRead);
135}
136
137AtomicString InbandTextTrackPrivateAVCF::label() const
138{
139    if (!m_mediaSelectionOption)
140        return emptyAtom;
141
142    RetainPtr<CFStringRef> title;
143
144    RetainPtr<CFArrayRef> commonMetaData = adoptCF(AVCFMediaSelectionOptionCopyCommonMetadata(mediaSelectionOption()));
145    RetainPtr<CFArrayRef> titles = adoptCF(AVCFMetadataItemCopyItemsWithKeyAndKeySpace(commonMetaData.get(), AVCFMetadataCommonKeyTitle, AVCFMetadataKeySpaceCommon));
146    CFIndex titlesCount = CFArrayGetCount(titles.get());
147    if (!titlesCount)
148        return emptyAtom;
149
150    // If possible, return a title in one of the user's preferred languages.
151    RetainPtr<CFArrayRef> preferredLanguages = adoptCF(CFLocaleCopyPreferredLanguages());
152    RetainPtr<CFArrayRef> titlesForPreferredLanguages = adoptCF(AVCFMediaSelectionCopyOptionsFromArrayFilteredAndSortedAccordingToPreferredLanguages(titles.get(), preferredLanguages.get()));
153    CFIndex preferredTitlesCount = CFArrayGetCount(titlesForPreferredLanguages.get());
154    if (preferredTitlesCount) {
155        AVCFMetadataItemRef titleMetadata = static_cast<AVCFMetadataItemRef>(CFArrayGetValueAtIndex(titlesForPreferredLanguages.get(), 0));
156        title = adoptCF(AVCFMetadataItemCopyStringValue(titleMetadata));
157    }
158
159    if (!title) {
160        AVCFMetadataItemRef titleMetadata = static_cast<AVCFMetadataItemRef>(CFArrayGetValueAtIndex(titles.get(), 0));
161        title = adoptCF(AVCFMetadataItemCopyStringValue(titleMetadata));
162    }
163
164    return title ? AtomicString(title.get()) : emptyAtom;
165}
166
167AtomicString InbandTextTrackPrivateAVCF::language() const
168{
169    if (!m_mediaSelectionOption)
170        return emptyAtom;
171
172    RetainPtr<CFLocaleRef> locale = adoptCF(AVCFMediaSelectionOptionCopyLocale(mediaSelectionOption()));
173    return CFLocaleGetIdentifier(locale.get());
174}
175
176bool InbandTextTrackPrivateAVCF::isDefault() const
177{
178    return false;
179}
180
181} // namespace WebCore
182
183#endif
184