| // Copyright 2022 The Cobalt Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "cobalt/dom/source_buffer_algorithm.h" |
| |
| #include <algorithm> |
| #include <utility> |
| |
| #include "base/logging.h" |
| #include "base/trace_event/trace_event.h" |
| #include "cobalt/dom/media_source.h" |
| |
| namespace cobalt { |
| namespace dom { |
| |
| SourceBufferAppendAlgorithm::SourceBufferAppendAlgorithm( |
| MediaSource* media_source, ::media::ChunkDemuxer* chunk_demuxer, |
| const std::string& id, const uint8_t* buffer, size_t size_in_bytes, |
| size_t max_append_size_in_bytes, base::TimeDelta append_window_start, |
| base::TimeDelta append_window_end, base::TimeDelta timestamp_offset, |
| UpdateTimestampOffsetCB&& update_timestamp_offset_cb, |
| ScheduleEventCB&& schedule_event_cb, base::OnceClosure&& finalized_cb, |
| SourceBufferMetrics* metrics) |
| : media_source_(media_source), |
| chunk_demuxer_(chunk_demuxer), |
| id_(id), |
| buffer_(buffer), |
| max_append_size_(max_append_size_in_bytes), |
| bytes_remaining_(size_in_bytes), |
| append_window_start_(append_window_start), |
| append_window_end_(append_window_end), |
| timestamp_offset_(timestamp_offset), |
| update_timestamp_offset_cb_(std::move(update_timestamp_offset_cb)), |
| schedule_event_cb_(std::move(schedule_event_cb)), |
| finalized_cb_(std::move(finalized_cb)), |
| metrics_(metrics) { |
| DCHECK(media_source_); |
| DCHECK(chunk_demuxer_); |
| DCHECK_GT(static_cast<int>(max_append_size_), 0); |
| if (bytes_remaining_ > 0) { |
| DCHECK(buffer); |
| } |
| DCHECK(update_timestamp_offset_cb_); |
| DCHECK(schedule_event_cb_); |
| DCHECK(metrics_); |
| TRACE_EVENT1("cobalt::dom", "SourceBufferAppendAlgorithm ctor", |
| "bytes_remaining", bytes_remaining_); |
| } |
| |
| void SourceBufferAppendAlgorithm::Process(bool* finished) { |
| DCHECK(finished); |
| DCHECK(!*finished); |
| |
| size_t append_size = std::min(bytes_remaining_, max_append_size_); |
| |
| TRACE_EVENT1("cobalt::dom", "SourceBufferAppendAlgorithm::Process()", |
| "append_size", append_size); |
| |
| metrics_->StartTracking(); |
| succeeded_ = chunk_demuxer_->AppendData( |
| id_, buffer_, append_size, append_window_start_, append_window_end_, |
| ×tamp_offset_); |
| update_timestamp_offset_cb_.Run(timestamp_offset_); |
| metrics_->EndTracking(succeeded_ ? append_size : 0); |
| |
| if (succeeded_) { |
| buffer_ += append_size; |
| bytes_remaining_ -= append_size; |
| |
| if (bytes_remaining_ == 0) { |
| *finished = true; |
| return; |
| } |
| |
| return; |
| } |
| |
| chunk_demuxer_->ResetParserState(id_, append_window_start_, |
| append_window_end_, ×tamp_offset_); |
| update_timestamp_offset_cb_.Run(timestamp_offset_); |
| *finished = true; |
| } |
| |
| void SourceBufferAppendAlgorithm::Abort() { |
| TRACE_EVENT0("cobalt::dom", "SourceBufferAppendAlgorithm::Abort()"); |
| schedule_event_cb_.Run(base::Tokens::abort()); |
| schedule_event_cb_.Run(base::Tokens::updateend()); |
| } |
| |
| void SourceBufferAppendAlgorithm::Finalize() { |
| TRACE_EVENT1("cobalt::dom", "SourceBufferAppendAlgorithm::Finalize()", |
| "succeeded", succeeded_); |
| if (succeeded_) { |
| schedule_event_cb_.Run(base::Tokens::update()); |
| schedule_event_cb_.Run(base::Tokens::updateend()); |
| } else { |
| schedule_event_cb_.Run(base::Tokens::error()); |
| schedule_event_cb_.Run(base::Tokens::updateend()); |
| media_source_->EndOfStreamAlgorithm(kMediaSourceEndOfStreamErrorDecode); |
| } |
| |
| std::move(finalized_cb_).Run(); |
| } |
| |
| SourceBufferRemoveAlgorithm::SourceBufferRemoveAlgorithm( |
| ::media::ChunkDemuxer* chunk_demuxer, const std::string& id, |
| base::TimeDelta pending_remove_start, base::TimeDelta pending_remove_end, |
| ScheduleEventCB&& schedule_event_cb, base::OnceClosure&& finalized_cb) |
| : chunk_demuxer_(chunk_demuxer), |
| id_(id), |
| pending_remove_start_(pending_remove_start), |
| pending_remove_end_(pending_remove_end), |
| schedule_event_cb_(std::move(schedule_event_cb)), |
| finalized_cb_(std::move(finalized_cb)) { |
| TRACE_EVENT0("cobalt::dom", "SourceBufferRemoveAlgorithm ctor"); |
| DCHECK(chunk_demuxer_); |
| DCHECK(schedule_event_cb_); |
| } |
| |
| void SourceBufferRemoveAlgorithm::Process(bool* finished) { |
| TRACE_EVENT0("cobalt::dom", "SourceBufferRemoveAlgorithm::Process()"); |
| chunk_demuxer_->Remove(id_, pending_remove_start_, pending_remove_end_); |
| *finished = true; |
| } |
| |
| void SourceBufferRemoveAlgorithm::Abort() { |
| TRACE_EVENT0("cobalt::dom", "SourceBufferRemoveAlgorithm::Abort()"); |
| // SourceBufferRemoveAlgorithm cannot be cancelled explicitly by the web app. |
| // This function will only be called when the SourceBuffer is being removed |
| // from the MediaSource and no events should be fired. |
| } |
| |
| void SourceBufferRemoveAlgorithm::Finalize() { |
| TRACE_EVENT0("cobalt::dom", "SourceBufferRemoveAlgorithm::Finalize()"); |
| schedule_event_cb_.Run(base::Tokens::update()); |
| schedule_event_cb_.Run(base::Tokens::updateend()); |
| std::move(finalized_cb_).Run(); |
| } |
| |
| } // namespace dom |
| } // namespace cobalt |