blob: d4cfe418d5c6120657de0d0bc02036fb10a820fa [file] [log] [blame]
/*
* Copyright (C) 2013-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "MockSourceBufferPrivate.h"
#if ENABLE(MEDIA_SOURCE)
#include "Logging.h"
#include "MediaDescription.h"
#include "MediaPlayer.h"
#include "MediaSample.h"
#include "MockBox.h"
#include "MockMediaPlayerMediaSource.h"
#include "MockMediaSourcePrivate.h"
#include "MockTracks.h"
#include "SourceBufferPrivateClient.h"
#include <JavaScriptCore/ArrayBuffer.h>
#include <wtf/StringPrintStream.h>
namespace WebCore {
class MockMediaSample final : public MediaSample {
public:
static Ref<MockMediaSample> create(const MockSampleBox& box) { return adoptRef(*new MockMediaSample(box)); }
virtual ~MockMediaSample() = default;
private:
MockMediaSample(const MockSampleBox& box)
: m_box(box)
, m_id(AtomString::number(box.trackID()))
{
}
MediaTime presentationTime() const override { return m_box.presentationTimestamp(); }
MediaTime decodeTime() const override { return m_box.decodeTimestamp(); }
MediaTime duration() const override { return m_box.duration(); }
AtomString trackID() const override { return m_id; }
size_t sizeInBytes() const override { return sizeof(m_box); }
SampleFlags flags() const override;
PlatformSample platformSample() const override;
PlatformSample::Type platformSampleType() const override { return PlatformSample::MockSampleBoxType; }
FloatSize presentationSize() const override { return FloatSize(); }
void dump(PrintStream&) const override;
void offsetTimestampsBy(const MediaTime& offset) override { m_box.offsetTimestampsBy(offset); }
void setTimestamps(const MediaTime& presentationTimestamp, const MediaTime& decodeTimestamp) override { m_box.setTimestamps(presentationTimestamp, decodeTimestamp); }
Ref<MediaSample> createNonDisplayingCopy() const override;
unsigned generation() const { return m_box.generation(); }
MockSampleBox m_box;
AtomString m_id;
};
MediaSample::SampleFlags MockMediaSample::flags() const
{
unsigned flags = None;
if (m_box.isSync())
flags |= IsSync;
if (m_box.isNonDisplaying())
flags |= IsNonDisplaying;
return SampleFlags(flags);
}
PlatformSample MockMediaSample::platformSample() const
{
PlatformSample sample = { PlatformSample::MockSampleBoxType, { &m_box } };
return sample;
}
void MockMediaSample::dump(PrintStream& out) const
{
out.print("{PTS(", presentationTime(), "), DTS(", decodeTime(), "), duration(", duration(), "), flags(", (int)flags(), "), generation(", generation(), ")}");
}
Ref<MediaSample> MockMediaSample::createNonDisplayingCopy() const
{
auto copy = MockMediaSample::create(m_box);
copy->m_box.setFlag(MockSampleBox::IsNonDisplaying);
return copy;
}
class MockMediaDescription final : public MediaDescription {
public:
static Ref<MockMediaDescription> create(const MockTrackBox& box) { return adoptRef(*new MockMediaDescription(box)); }
virtual ~MockMediaDescription() = default;
AtomString codec() const override { return m_box.codec(); }
bool isVideo() const override { return m_box.kind() == MockTrackBox::Video; }
bool isAudio() const override { return m_box.kind() == MockTrackBox::Audio; }
bool isText() const override { return m_box.kind() == MockTrackBox::Text; }
private:
MockMediaDescription(const MockTrackBox& box) : m_box(box) { }
MockTrackBox m_box;
};
Ref<MockSourceBufferPrivate> MockSourceBufferPrivate::create(MockMediaSourcePrivate* parent)
{
return adoptRef(*new MockSourceBufferPrivate(parent));
}
MockSourceBufferPrivate::MockSourceBufferPrivate(MockMediaSourcePrivate* parent)
: m_mediaSource(parent)
#if !RELEASE_LOG_DISABLED
, m_logger(parent->logger())
, m_logIdentifier(parent->nextSourceBufferLogIdentifier())
#endif
{
}
MockSourceBufferPrivate::~MockSourceBufferPrivate() = default;
void MockSourceBufferPrivate::append(Vector<uint8_t>&& data)
{
m_inputBuffer.appendVector(data);
SourceBufferPrivateClient::AppendResult result = SourceBufferPrivateClient::AppendResult::AppendSucceeded;
while (m_inputBuffer.size() && result == SourceBufferPrivateClient::AppendResult::AppendSucceeded) {
auto buffer = ArrayBuffer::create(m_inputBuffer.data(), m_inputBuffer.size());
uint64_t boxLength = MockBox::peekLength(buffer.ptr());
if (boxLength > buffer->byteLength())
break;
String type = MockBox::peekType(buffer.ptr());
if (type == MockInitializationBox::type()) {
MockInitializationBox initBox = MockInitializationBox(buffer.ptr());
didReceiveInitializationSegment(initBox);
} else if (type == MockSampleBox::type()) {
MockSampleBox sampleBox = MockSampleBox(buffer.ptr());
didReceiveSample(sampleBox);
} else
result = SourceBufferPrivateClient::AppendResult::ParsingFailed;
m_inputBuffer.remove(0, boxLength);
}
// Resolve the changes in TrackBuffers' buffered ranges
// into the SourceBuffer's buffered ranges
updateBufferedFromTrackBuffers(m_mediaSource->isEnded());
if (m_client)
m_client->sourceBufferPrivateAppendComplete(result);
}
void MockSourceBufferPrivate::didReceiveInitializationSegment(const MockInitializationBox& initBox)
{
if (!m_client)
return;
SourceBufferPrivateClient::InitializationSegment segment;
segment.duration = initBox.duration();
for (auto it = initBox.tracks().begin(); it != initBox.tracks().end(); ++it) {
const MockTrackBox& trackBox = *it;
if (trackBox.kind() == MockTrackBox::Video) {
SourceBufferPrivateClient::InitializationSegment::VideoTrackInformation info;
info.track = MockVideoTrackPrivate::create(trackBox);
info.description = MockMediaDescription::create(trackBox);
segment.videoTracks.append(info);
} else if (trackBox.kind() == MockTrackBox::Audio) {
SourceBufferPrivateClient::InitializationSegment::AudioTrackInformation info;
info.track = MockAudioTrackPrivate::create(trackBox);
info.description = MockMediaDescription::create(trackBox);
segment.audioTracks.append(info);
} else if (trackBox.kind() == MockTrackBox::Text) {
SourceBufferPrivateClient::InitializationSegment::TextTrackInformation info;
info.track = MockTextTrackPrivate::create(trackBox);
info.description = MockMediaDescription::create(trackBox);
segment.textTracks.append(info);
}
}
SourceBufferPrivate::didReceiveInitializationSegment(WTFMove(segment), []() { });
}
void MockSourceBufferPrivate::didReceiveSample(const MockSampleBox& sampleBox)
{
if (!m_client)
return;
SourceBufferPrivate::didReceiveSample(MockMediaSample::create(sampleBox));
}
void MockSourceBufferPrivate::abort()
{
}
void MockSourceBufferPrivate::resetParserState()
{
}
void MockSourceBufferPrivate::removedFromMediaSource()
{
if (m_mediaSource)
m_mediaSource->removeSourceBuffer(this);
}
MediaPlayer::ReadyState MockSourceBufferPrivate::readyState() const
{
return m_mediaSource ? m_mediaSource->player().readyState() : MediaPlayer::ReadyState::HaveNothing;
}
void MockSourceBufferPrivate::setReadyState(MediaPlayer::ReadyState readyState)
{
if (m_mediaSource)
m_mediaSource->player().setReadyState(readyState);
}
void MockSourceBufferPrivate::setActive(bool isActive)
{
m_isActive = isActive;
if (m_mediaSource)
m_mediaSource->sourceBufferPrivateDidChangeActiveState(this, isActive);
}
bool MockSourceBufferPrivate::isActive() const
{
return m_isActive;
}
void MockSourceBufferPrivate::enqueuedSamplesForTrackID(const AtomString&, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
{
completionHandler(copyToVector(m_enqueuedSamples));
}
MediaTime MockSourceBufferPrivate::minimumUpcomingPresentationTimeForTrackID(const AtomString&)
{
return m_minimumUpcomingPresentationTime;
}
void MockSourceBufferPrivate::setMaximumQueueDepthForTrackID(const AtomString&, uint64_t maxQueueDepth)
{
m_maxQueueDepth = maxQueueDepth;
}
bool MockSourceBufferPrivate::canSetMinimumUpcomingPresentationTime(const AtomString&) const
{
return true;
}
void MockSourceBufferPrivate::setMinimumUpcomingPresentationTime(const AtomString&, const MediaTime& presentationTime)
{
m_minimumUpcomingPresentationTime = presentationTime;
}
void MockSourceBufferPrivate::clearMinimumUpcomingPresentationTime(const AtomString&)
{
m_minimumUpcomingPresentationTime = MediaTime::invalidTime();
}
bool MockSourceBufferPrivate::canSwitchToType(const ContentType& contentType)
{
MediaEngineSupportParameters parameters;
parameters.isMediaSource = true;
parameters.type = contentType;
return MockMediaPlayerMediaSource::supportsType(parameters) != MediaPlayer::SupportsType::IsNotSupported;
}
bool MockSourceBufferPrivate::isSeeking() const
{
return m_mediaSource && m_mediaSource->isSeeking();
}
MediaTime MockSourceBufferPrivate::currentMediaTime() const
{
if (!m_mediaSource)
return { };
return m_mediaSource->currentMediaTime();
}
MediaTime MockSourceBufferPrivate::duration() const
{
if (!m_mediaSource)
return { };
return m_mediaSource->duration();
}
void MockSourceBufferPrivate::enqueueSample(Ref<MediaSample>&& sample, const AtomString&)
{
if (!m_mediaSource)
return;
PlatformSample platformSample = sample->platformSample();
if (platformSample.type != PlatformSample::MockSampleBoxType)
return;
auto* box = platformSample.sample.mockSampleBox;
if (!box)
return;
m_mediaSource->incrementTotalVideoFrames();
if (box->isCorrupted())
m_mediaSource->incrementCorruptedFrames();
if (box->isDropped())
m_mediaSource->incrementDroppedFrames();
if (box->isDelayed())
m_mediaSource->incrementTotalFrameDelayBy(MediaTime(1, 1));
m_enqueuedSamples.append(toString(sample.get()));
}
#if !RELEASE_LOG_DISABLED
WTFLogChannel& MockSourceBufferPrivate::logChannel() const
{
return LogMediaSource;
}
#endif
}
#endif