1/*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "config.h"
33#include "VideoTrack.h"
34
35#if ENABLE(VIDEO_TRACK)
36
37#include "HTMLMediaElement.h"
38#include "VideoTrackList.h"
39#include <wtf/NeverDestroyed.h>
40
41#if ENABLE(MEDIA_SOURCE)
42#include "SourceBuffer.h"
43#endif
44
45namespace WebCore {
46
47const AtomicString& VideoTrack::alternativeKeyword()
48{
49 static NeverDestroyed<const AtomicString> alternative("alternative", AtomicString::ConstructFromLiteral);
50 return alternative;
51}
52
53const AtomicString& VideoTrack::captionsKeyword()
54{
55 static NeverDestroyed<const AtomicString> captions("captions", AtomicString::ConstructFromLiteral);
56 return captions;
57}
58
59const AtomicString& VideoTrack::mainKeyword()
60{
61 static NeverDestroyed<const AtomicString> captions("main", AtomicString::ConstructFromLiteral);
62 return captions;
63}
64
65const AtomicString& VideoTrack::signKeyword()
66{
67 static NeverDestroyed<const AtomicString> sign("sign", AtomicString::ConstructFromLiteral);
68 return sign;
69}
70
71const AtomicString& VideoTrack::subtitlesKeyword()
72{
73 static NeverDestroyed<const AtomicString> subtitles("subtitles", AtomicString::ConstructFromLiteral);
74 return subtitles;
75}
76
77const AtomicString& VideoTrack::commentaryKeyword()
78{
79 static NeverDestroyed<const AtomicString> commentary("commentary", AtomicString::ConstructFromLiteral);
80 return commentary;
81}
82
83VideoTrack::VideoTrack(VideoTrackClient& client, VideoTrackPrivate& trackPrivate)
84 : MediaTrackBase(MediaTrackBase::VideoTrack, trackPrivate.id(), trackPrivate.label(), trackPrivate.language())
85 , m_client(&client)
86 , m_private(trackPrivate)
87 , m_selected(trackPrivate.selected())
88{
89#if !RELEASE_LOG_DISABLED
90 m_private->setLogger(logger(), logIdentifier());
91#endif
92 m_private->setClient(this);
93 updateKindFromPrivate();
94}
95
96VideoTrack::~VideoTrack()
97{
98 m_private->setClient(nullptr);
99}
100
101void VideoTrack::setPrivate(VideoTrackPrivate& trackPrivate)
102{
103 if (m_private.ptr() == &trackPrivate)
104 return;
105
106 m_private->setClient(nullptr);
107 m_private = trackPrivate;
108 m_private->setClient(this);
109#if !RELEASE_LOG_DISABLED
110 m_private->setLogger(logger(), logIdentifier());
111#endif
112
113 m_private->setSelected(m_selected);
114 updateKindFromPrivate();
115}
116
117bool VideoTrack::isValidKind(const AtomicString& value) const
118{
119 return value == alternativeKeyword()
120 || value == commentaryKeyword()
121 || value == captionsKeyword()
122 || value == mainKeyword()
123 || value == signKeyword()
124 || value == subtitlesKeyword();
125}
126
127void VideoTrack::setSelected(const bool selected)
128{
129 if (m_selected == selected)
130 return;
131
132 m_selected = selected;
133 m_private->setSelected(selected);
134
135 if (m_client)
136 m_client->videoTrackSelectedChanged(*this);
137}
138
139size_t VideoTrack::inbandTrackIndex()
140{
141 return m_private->trackIndex();
142}
143
144void VideoTrack::selectedChanged(bool selected)
145{
146 setSelected(selected);
147}
148
149void VideoTrack::idChanged(const AtomicString& id)
150{
151 setId(id);
152}
153
154void VideoTrack::labelChanged(const AtomicString& label)
155{
156 setLabel(label);
157}
158
159void VideoTrack::languageChanged(const AtomicString& language)
160{
161 setLanguage(language);
162}
163
164void VideoTrack::willRemove()
165{
166 auto element = makeRefPtr(mediaElement());
167 if (!element)
168 return;
169 element->removeVideoTrack(*this);
170}
171
172#if ENABLE(MEDIA_SOURCE)
173
174void VideoTrack::setKind(const AtomicString& kind)
175{
176 // 10.1 kind, on setting:
177 // 1. If the value being assigned to this attribute does not match one of the video track kinds,
178 // then abort these steps.
179 if (!isValidKind(kind))
180 return;
181
182 // 2. Update this attribute to the new value.
183 setKindInternal(kind);
184
185 // 3. If the sourceBuffer attribute on this track is not null, then queue a task to fire a simple
186 // event named change at sourceBuffer.videoTracks.
187 if (m_sourceBuffer)
188 m_sourceBuffer->videoTracks().scheduleChangeEvent();
189
190 // 4. Queue a task to fire a simple event named change at the VideoTrackList object referenced by
191 // the videoTracks attribute on the HTMLMediaElement.
192 mediaElement()->ensureVideoTracks().scheduleChangeEvent();
193}
194
195void VideoTrack::setLanguage(const AtomicString& language)
196{
197 // 10.1 language, on setting:
198 // 1. If the value being assigned to this attribute is not an empty string or a BCP 47 language
199 // tag[BCP47], then abort these steps.
200 // BCP 47 validation is done in TrackBase::setLanguage() which is
201 // shared between all tracks that support setting language.
202
203 // 2. Update this attribute to the new value.
204 MediaTrackBase::setLanguage(language);
205
206 // 3. If the sourceBuffer attribute on this track is not null, then queue a task to fire a simple
207 // event named change at sourceBuffer.videoTracks.
208 if (m_sourceBuffer)
209 m_sourceBuffer->videoTracks().scheduleChangeEvent();
210
211 // 4. Queue a task to fire a simple event named change at the VideoTrackList object referenced by
212 // the videoTracks attribute on the HTMLMediaElement.
213 if (mediaElement())
214 mediaElement()->ensureVideoTracks().scheduleChangeEvent();
215}
216
217#endif
218
219void VideoTrack::updateKindFromPrivate()
220{
221 switch (m_private->kind()) {
222 case VideoTrackPrivate::Alternative:
223 setKindInternal(VideoTrack::alternativeKeyword());
224 return;
225 case VideoTrackPrivate::Captions:
226 setKindInternal(VideoTrack::captionsKeyword());
227 return;
228 case VideoTrackPrivate::Main:
229 setKindInternal(VideoTrack::mainKeyword());
230 return;
231 case VideoTrackPrivate::Sign:
232 setKindInternal(VideoTrack::signKeyword());
233 return;
234 case VideoTrackPrivate::Subtitles:
235 setKindInternal(VideoTrack::subtitlesKeyword());
236 return;
237 case VideoTrackPrivate::Commentary:
238 setKindInternal(VideoTrack::commentaryKeyword());
239 return;
240 case VideoTrackPrivate::None:
241 setKindInternal(emptyString());
242 return;
243 }
244 ASSERT_NOT_REACHED();
245}
246
247void VideoTrack::setMediaElement(HTMLMediaElement* element)
248{
249 TrackBase::setMediaElement(element);
250#if !RELEASE_LOG_DISABLED
251 m_private->setLogger(logger(), logIdentifier());
252#endif
253}
254
255} // namespace WebCore
256
257#endif
258