1/*
2 * Copyright (C) 2013-2017 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 "MockSourceBufferPrivate.h"
28
29#if ENABLE(MEDIA_SOURCE)
30
31#include "MediaDescription.h"
32#include "MediaPlayer.h"
33#include "MediaSample.h"
34#include "MockBox.h"
35#include "MockMediaPlayerMediaSource.h"
36#include "MockMediaSourcePrivate.h"
37#include "MockTracks.h"
38#include "SourceBufferPrivateClient.h"
39#include <JavaScriptCore/ArrayBuffer.h>
40#include <wtf/StringPrintStream.h>
41
42namespace WebCore {
43
44class MockMediaSample final : public MediaSample {
45public:
46 static Ref<MockMediaSample> create(const MockSampleBox& box) { return adoptRef(*new MockMediaSample(box)); }
47 virtual ~MockMediaSample() = default;
48
49private:
50 MockMediaSample(const MockSampleBox& box)
51 : m_box(box)
52 , m_id(AtomicString::number(box.trackID()))
53 {
54 }
55
56 MediaTime presentationTime() const override { return m_box.presentationTimestamp(); }
57 MediaTime decodeTime() const override { return m_box.decodeTimestamp(); }
58 MediaTime duration() const override { return m_box.duration(); }
59 AtomicString trackID() const override { return m_id; }
60 void setTrackID(const String& id) override { m_id = id; }
61 size_t sizeInBytes() const override { return sizeof(m_box); }
62 SampleFlags flags() const override;
63 PlatformSample platformSample() override;
64 FloatSize presentationSize() const override { return FloatSize(); }
65 void dump(PrintStream&) const override;
66 void offsetTimestampsBy(const MediaTime& offset) override { m_box.offsetTimestampsBy(offset); }
67 void setTimestamps(const MediaTime& presentationTimestamp, const MediaTime& decodeTimestamp) override { m_box.setTimestamps(presentationTimestamp, decodeTimestamp); }
68 bool isDivisable() const override { return false; }
69 std::pair<RefPtr<MediaSample>, RefPtr<MediaSample>> divide(const MediaTime&) override { return {nullptr, nullptr}; }
70 Ref<MediaSample> createNonDisplayingCopy() const override;
71
72 unsigned generation() const { return m_box.generation(); }
73
74 MockSampleBox m_box;
75 AtomicString m_id;
76};
77
78MediaSample::SampleFlags MockMediaSample::flags() const
79{
80 unsigned flags = None;
81 if (m_box.isSync())
82 flags |= IsSync;
83 if (m_box.isNonDisplaying())
84 flags |= IsNonDisplaying;
85 return SampleFlags(flags);
86}
87
88PlatformSample MockMediaSample::platformSample()
89{
90 PlatformSample sample = { PlatformSample::MockSampleBoxType, { &m_box } };
91 return sample;
92}
93
94void MockMediaSample::dump(PrintStream& out) const
95{
96 out.print("{PTS(", presentationTime(), "), DTS(", decodeTime(), "), duration(", duration(), "), flags(", (int)flags(), "), generation(", generation(), ")}");
97}
98
99Ref<MediaSample> MockMediaSample::createNonDisplayingCopy() const
100{
101 auto copy = MockMediaSample::create(m_box);
102 copy->m_box.setFlag(MockSampleBox::IsNonDisplaying);
103 return copy;
104}
105
106class MockMediaDescription final : public MediaDescription {
107public:
108 static Ref<MockMediaDescription> create(const MockTrackBox& box) { return adoptRef(*new MockMediaDescription(box)); }
109 virtual ~MockMediaDescription() = default;
110
111 AtomicString codec() const override { return m_box.codec(); }
112 bool isVideo() const override { return m_box.kind() == MockTrackBox::Video; }
113 bool isAudio() const override { return m_box.kind() == MockTrackBox::Audio; }
114 bool isText() const override { return m_box.kind() == MockTrackBox::Text; }
115
116protected:
117 MockMediaDescription(const MockTrackBox& box) : m_box(box) { }
118 MockTrackBox m_box;
119};
120
121Ref<MockSourceBufferPrivate> MockSourceBufferPrivate::create(MockMediaSourcePrivate* parent)
122{
123 return adoptRef(*new MockSourceBufferPrivate(parent));
124}
125
126MockSourceBufferPrivate::MockSourceBufferPrivate(MockMediaSourcePrivate* parent)
127 : m_mediaSource(parent)
128 , m_client(0)
129{
130}
131
132MockSourceBufferPrivate::~MockSourceBufferPrivate() = default;
133
134void MockSourceBufferPrivate::setClient(SourceBufferPrivateClient* client)
135{
136 m_client = client;
137}
138
139void MockSourceBufferPrivate::append(Vector<unsigned char>&& data)
140{
141 m_inputBuffer.appendVector(data);
142 SourceBufferPrivateClient::AppendResult result = SourceBufferPrivateClient::AppendSucceeded;
143
144 while (m_inputBuffer.size() && result == SourceBufferPrivateClient::AppendSucceeded) {
145 auto buffer = ArrayBuffer::create(m_inputBuffer.data(), m_inputBuffer.size());
146 size_t boxLength = MockBox::peekLength(buffer.ptr());
147 if (boxLength > buffer->byteLength())
148 break;
149
150 String type = MockBox::peekType(buffer.ptr());
151 if (type == MockInitializationBox::type()) {
152 MockInitializationBox initBox = MockInitializationBox(buffer.ptr());
153 didReceiveInitializationSegment(initBox);
154 } else if (type == MockSampleBox::type()) {
155 MockSampleBox sampleBox = MockSampleBox(buffer.ptr());
156 didReceiveSample(sampleBox);
157 } else
158 result = SourceBufferPrivateClient::ParsingFailed;
159
160 m_inputBuffer.remove(0, boxLength);
161 }
162
163 if (m_client)
164 m_client->sourceBufferPrivateAppendComplete(result);
165}
166
167void MockSourceBufferPrivate::didReceiveInitializationSegment(const MockInitializationBox& initBox)
168{
169 if (!m_client)
170 return;
171
172 SourceBufferPrivateClient::InitializationSegment segment;
173 segment.duration = initBox.duration();
174
175 for (auto it = initBox.tracks().begin(); it != initBox.tracks().end(); ++it) {
176 const MockTrackBox& trackBox = *it;
177 if (trackBox.kind() == MockTrackBox::Video) {
178 SourceBufferPrivateClient::InitializationSegment::VideoTrackInformation info;
179 info.track = MockVideoTrackPrivate::create(trackBox);
180 info.description = MockMediaDescription::create(trackBox);
181 segment.videoTracks.append(info);
182 } else if (trackBox.kind() == MockTrackBox::Audio) {
183 SourceBufferPrivateClient::InitializationSegment::AudioTrackInformation info;
184 info.track = MockAudioTrackPrivate::create(trackBox);
185 info.description = MockMediaDescription::create(trackBox);
186 segment.audioTracks.append(info);
187 } else if (trackBox.kind() == MockTrackBox::Text) {
188 SourceBufferPrivateClient::InitializationSegment::TextTrackInformation info;
189 info.track = MockTextTrackPrivate::create(trackBox);
190 info.description = MockMediaDescription::create(trackBox);
191 segment.textTracks.append(info);
192 }
193 }
194
195 m_client->sourceBufferPrivateDidReceiveInitializationSegment(segment);
196}
197
198
199void MockSourceBufferPrivate::didReceiveSample(const MockSampleBox& sampleBox)
200{
201 if (!m_client)
202 return;
203
204 m_client->sourceBufferPrivateDidReceiveSample(MockMediaSample::create(sampleBox));
205}
206
207void MockSourceBufferPrivate::abort()
208{
209}
210
211void MockSourceBufferPrivate::resetParserState()
212{
213}
214
215void MockSourceBufferPrivate::removedFromMediaSource()
216{
217 if (m_mediaSource)
218 m_mediaSource->removeSourceBuffer(this);
219}
220
221MediaPlayer::ReadyState MockSourceBufferPrivate::readyState() const
222{
223 return m_mediaSource ? m_mediaSource->player().readyState() : MediaPlayer::HaveNothing;
224}
225
226void MockSourceBufferPrivate::setReadyState(MediaPlayer::ReadyState readyState)
227{
228 if (m_mediaSource)
229 m_mediaSource->player().setReadyState(readyState);
230}
231
232void MockSourceBufferPrivate::setActive(bool isActive)
233{
234 if (m_mediaSource)
235 m_mediaSource->sourceBufferPrivateDidChangeActiveState(this, isActive);
236}
237
238Vector<String> MockSourceBufferPrivate::enqueuedSamplesForTrackID(const AtomicString&)
239{
240 return m_enqueuedSamples;
241}
242
243bool MockSourceBufferPrivate::canSwitchToType(const ContentType& contentType)
244{
245 MediaEngineSupportParameters parameters;
246 parameters.isMediaSource = true;
247 parameters.type = contentType;
248 return MockMediaPlayerMediaSource::supportsType(parameters) != MediaPlayer::IsNotSupported;
249}
250
251void MockSourceBufferPrivate::enqueueSample(Ref<MediaSample>&& sample, const AtomicString&)
252{
253 if (!m_mediaSource)
254 return;
255
256 PlatformSample platformSample = sample->platformSample();
257 if (platformSample.type != PlatformSample::MockSampleBoxType)
258 return;
259
260 auto* box = platformSample.sample.mockSampleBox;
261 if (!box)
262 return;
263
264 m_mediaSource->incrementTotalVideoFrames();
265 if (box->isCorrupted())
266 m_mediaSource->incrementCorruptedFrames();
267 if (box->isDropped())
268 m_mediaSource->incrementDroppedFrames();
269 if (box->isDelayed())
270 m_mediaSource->incrementTotalFrameDelayBy(MediaTime(1, 1));
271
272 m_enqueuedSamples.append(toString(sample.get()));
273}
274
275bool MockSourceBufferPrivate::hasVideo() const
276{
277 return m_client && m_client->sourceBufferPrivateHasVideo();
278}
279
280bool MockSourceBufferPrivate::hasAudio() const
281{
282 return m_client && m_client->sourceBufferPrivateHasAudio();
283}
284
285MediaTime MockSourceBufferPrivate::fastSeekTimeForMediaTime(const MediaTime& time, const MediaTime& negativeThreshold, const MediaTime& positiveThreshold)
286{
287 if (m_client)
288 return m_client->sourceBufferPrivateFastSeekTimeForMediaTime(time, negativeThreshold, positiveThreshold);
289 return time;
290}
291
292#if !RELEASE_LOG_DISABLED
293const Logger& MockSourceBufferPrivate::sourceBufferLogger() const
294{
295 return m_mediaSource->mediaSourceLogger();
296}
297
298const void* MockSourceBufferPrivate::sourceBufferLogIdentifier()
299{
300 return m_mediaSource->mediaSourceLogIdentifier();
301}
302#endif
303
304}
305
306#endif
307
308