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