summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/media/web_source_buffer_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/media/web_source_buffer_impl.cc')
-rw-r--r--chromium/third_party/blink/renderer/platform/media/web_source_buffer_impl.cc260
1 files changed, 260 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/platform/media/web_source_buffer_impl.cc b/chromium/third_party/blink/renderer/platform/media/web_source_buffer_impl.cc
new file mode 100644
index 00000000000..d57921238f9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/media/web_source_buffer_impl.cc
@@ -0,0 +1,260 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/media/web_source_buffer_impl.h"
+
+#include <stdint.h>
+
+#include <cmath>
+#include <limits>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/strings/string_number_conversions.h"
+#include "media/base/media_tracks.h"
+#include "media/base/timestamp_constants.h"
+#include "media/filters/chunk_demuxer.h"
+#include "media/filters/source_buffer_parse_warnings.h"
+#include "third_party/blink/public/platform/web_media_player.h"
+#include "third_party/blink/public/platform/web_source_buffer_client.h"
+
+namespace blink {
+
+static WebSourceBufferClient::ParseWarning ParseWarningToBlink(
+ const media::SourceBufferParseWarning warning) {
+#define CHROMIUM_PARSE_WARNING_TO_BLINK_ENUM_CASE(name) \
+ case media::SourceBufferParseWarning::name: \
+ return WebSourceBufferClient::ParseWarning::name
+
+ switch (warning) {
+ CHROMIUM_PARSE_WARNING_TO_BLINK_ENUM_CASE(
+ kKeyframeTimeGreaterThanDependant);
+ CHROMIUM_PARSE_WARNING_TO_BLINK_ENUM_CASE(kMuxedSequenceMode);
+ CHROMIUM_PARSE_WARNING_TO_BLINK_ENUM_CASE(
+ kGroupEndTimestampDecreaseWithinMediaSegment);
+ }
+
+ NOTREACHED();
+ return WebSourceBufferClient::ParseWarning::kKeyframeTimeGreaterThanDependant;
+
+#undef CHROMIUM_PARSE_WARNING_TO_BLINK_ENUM_CASE
+}
+
+static base::TimeDelta DoubleToTimeDelta(double time) {
+ DCHECK(!std::isnan(time));
+ DCHECK_NE(time, -std::numeric_limits<double>::infinity());
+
+ if (time == std::numeric_limits<double>::infinity())
+ return media::kInfiniteDuration;
+
+ constexpr double max_time_in_seconds =
+ base::TimeDelta::FiniteMax().InSecondsF();
+
+ if (time >= max_time_in_seconds)
+ return base::TimeDelta::FiniteMax();
+
+ return base::TimeDelta::FromMicroseconds(
+ time * base::Time::kMicrosecondsPerSecond);
+}
+
+WebSourceBufferImpl::WebSourceBufferImpl(const std::string& id,
+ media::ChunkDemuxer* demuxer)
+ : id_(id),
+ demuxer_(demuxer),
+ client_(nullptr),
+ append_window_end_(media::kInfiniteDuration) {
+ DCHECK(demuxer_);
+ demuxer_->SetTracksWatcher(
+ id, base::BindRepeating(&WebSourceBufferImpl::InitSegmentReceived,
+ base::Unretained(this)));
+ demuxer_->SetParseWarningCallback(
+ id, base::BindRepeating(&WebSourceBufferImpl::NotifyParseWarning,
+ base::Unretained(this)));
+}
+
+WebSourceBufferImpl::~WebSourceBufferImpl() = default;
+
+void WebSourceBufferImpl::SetClient(WebSourceBufferClient* client) {
+ DCHECK(client);
+ DCHECK(!client_);
+ client_ = client;
+}
+
+bool WebSourceBufferImpl::GetGenerateTimestampsFlag() {
+ return demuxer_->GetGenerateTimestampsFlag(id_);
+}
+
+bool WebSourceBufferImpl::SetMode(WebSourceBuffer::AppendMode mode) {
+ if (demuxer_->IsParsingMediaSegment(id_))
+ return false;
+
+ switch (mode) {
+ case WebSourceBuffer::kAppendModeSegments:
+ demuxer_->SetSequenceMode(id_, false);
+ return true;
+ case WebSourceBuffer::kAppendModeSequence:
+ demuxer_->SetSequenceMode(id_, true);
+ return true;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+WebTimeRanges WebSourceBufferImpl::Buffered() {
+ media::Ranges<base::TimeDelta> ranges = demuxer_->GetBufferedRanges(id_);
+ WebTimeRanges result(ranges.size());
+ for (size_t i = 0; i < ranges.size(); i++) {
+ result[i].start = ranges.start(i).InSecondsF();
+ result[i].end = ranges.end(i).InSecondsF();
+ }
+ return result;
+}
+
+double WebSourceBufferImpl::HighestPresentationTimestamp() {
+ return demuxer_->GetHighestPresentationTimestamp(id_).InSecondsF();
+}
+
+bool WebSourceBufferImpl::EvictCodedFrames(double currentPlaybackTime,
+ size_t newDataSize) {
+ return demuxer_->EvictCodedFrames(
+ id_,
+ base::TimeDelta::FromSecondsD(currentPlaybackTime),
+ newDataSize);
+}
+
+bool WebSourceBufferImpl::Append(const unsigned char* data,
+ unsigned length,
+ double* timestamp_offset) {
+ base::TimeDelta old_offset = timestamp_offset_;
+ bool success = demuxer_->AppendData(id_, data, length, append_window_start_,
+ append_window_end_, &timestamp_offset_);
+
+ // Coded frame processing may update the timestamp offset. If the caller
+ // provides a non-nullptr |timestamp_offset| and frame processing changes the
+ // timestamp offset, report the new offset to the caller. Do not update the
+ // caller's offset otherwise, to preserve any pre-existing value that may have
+ // more than microsecond precision.
+ if (timestamp_offset && old_offset != timestamp_offset_)
+ *timestamp_offset = timestamp_offset_.InSecondsF();
+
+ return success;
+}
+
+bool WebSourceBufferImpl::AppendChunks(
+ std::unique_ptr<media::StreamParser::BufferQueue> buffer_queue,
+ double* timestamp_offset) {
+ base::TimeDelta old_offset = timestamp_offset_;
+ bool success =
+ demuxer_->AppendChunks(id_, std::move(buffer_queue), append_window_start_,
+ append_window_end_, &timestamp_offset_);
+
+ // Like in ::Append, timestamp_offset may be updated by coded frame
+ // processing.
+ // TODO(crbug.com/1144908): Consider refactoring this common bit into helper.
+ if (timestamp_offset && old_offset != timestamp_offset_)
+ *timestamp_offset = timestamp_offset_.InSecondsF();
+
+ return success;
+}
+
+void WebSourceBufferImpl::ResetParserState() {
+ demuxer_->ResetParserState(id_,
+ append_window_start_, append_window_end_,
+ &timestamp_offset_);
+
+ // TODO(wolenetz): resetParserState should be able to modify the caller
+ // timestamp offset (just like WebSourceBufferImpl::append).
+ // See http://crbug.com/370229 for further details.
+}
+
+void WebSourceBufferImpl::Remove(double start, double end) {
+ DCHECK_GE(start, 0);
+ DCHECK_GE(end, 0);
+ demuxer_->Remove(id_, DoubleToTimeDelta(start), DoubleToTimeDelta(end));
+}
+
+bool WebSourceBufferImpl::CanChangeType(const WebString& content_type,
+ const WebString& codecs) {
+ return demuxer_->CanChangeType(id_, content_type.Utf8(), codecs.Utf8());
+}
+
+void WebSourceBufferImpl::ChangeType(const WebString& content_type,
+ const WebString& codecs) {
+ // Caller must first call ResetParserState() to flush any pending frames.
+ DCHECK(!demuxer_->IsParsingMediaSegment(id_));
+
+ demuxer_->ChangeType(id_, content_type.Utf8(), codecs.Utf8());
+}
+
+bool WebSourceBufferImpl::SetTimestampOffset(double offset) {
+ if (demuxer_->IsParsingMediaSegment(id_))
+ return false;
+
+ timestamp_offset_ = DoubleToTimeDelta(offset);
+
+ // http://www.w3.org/TR/media-source/#widl-SourceBuffer-timestampOffset
+ // Step 6: If the mode attribute equals "sequence", then set the group start
+ // timestamp to new timestamp offset.
+ demuxer_->SetGroupStartTimestampIfInSequenceMode(id_, timestamp_offset_);
+ return true;
+}
+
+void WebSourceBufferImpl::SetAppendWindowStart(double start) {
+ DCHECK_GE(start, 0);
+ append_window_start_ = DoubleToTimeDelta(start);
+}
+
+void WebSourceBufferImpl::SetAppendWindowEnd(double end) {
+ DCHECK_GE(end, 0);
+ append_window_end_ = DoubleToTimeDelta(end);
+}
+
+void WebSourceBufferImpl::RemovedFromMediaSource() {
+ demuxer_->RemoveId(id_);
+ demuxer_ = nullptr;
+ client_ = nullptr;
+}
+
+WebMediaPlayer::TrackType mediaTrackTypeToBlink(media::MediaTrack::Type type) {
+ switch (type) {
+ case media::MediaTrack::Audio:
+ return WebMediaPlayer::kAudioTrack;
+ case media::MediaTrack::Text:
+ return WebMediaPlayer::kTextTrack;
+ case media::MediaTrack::Video:
+ return WebMediaPlayer::kVideoTrack;
+ }
+ NOTREACHED();
+ return WebMediaPlayer::kAudioTrack;
+}
+
+void WebSourceBufferImpl::InitSegmentReceived(
+ std::unique_ptr<media::MediaTracks> tracks) {
+ DCHECK(tracks.get());
+ DVLOG(1) << __func__ << " tracks=" << tracks->tracks().size();
+
+ std::vector<WebSourceBufferClient::MediaTrackInfo> trackInfoVector;
+ for (const auto& track : tracks->tracks()) {
+ WebSourceBufferClient::MediaTrackInfo trackInfo;
+ trackInfo.track_type = mediaTrackTypeToBlink(track->type());
+ trackInfo.id = WebString::FromUTF8(track->id().value());
+ trackInfo.byte_stream_track_id =
+ WebString::FromUTF8(base::NumberToString(track->bytestream_track_id()));
+ trackInfo.kind = WebString::FromUTF8(track->kind().value());
+ trackInfo.label = WebString::FromUTF8(track->label().value());
+ trackInfo.language = WebString::FromUTF8(track->language().value());
+ trackInfoVector.push_back(trackInfo);
+ }
+
+ client_->InitializationSegmentReceived(trackInfoVector);
+}
+
+void WebSourceBufferImpl::NotifyParseWarning(
+ const media::SourceBufferParseWarning warning) {
+ client_->NotifyParseWarning(ParseWarningToBlink(warning));
+}
+
+} // namespace blink