| // Copyright 2016 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 "services/media/framework/engine.h" |
| |
| namespace mojo { |
| namespace media { |
| |
| Engine::Engine() {} |
| |
| Engine::~Engine() { |
| base::AutoLock lock(lock_); |
| } |
| |
| void Engine::PrepareInput(const InputRef& input) { |
| VisitUpstream(input, [](const InputRef& input, const OutputRef& output, |
| const Stage::UpstreamCallback& callback) { |
| DCHECK(!input.actual().prepared()); |
| PayloadAllocator* allocator = input.stage_->PrepareInput(input.index_); |
| input.actual().set_prepared(true); |
| output.stage_->PrepareOutput(output.index_, allocator, callback); |
| }); |
| } |
| |
| void Engine::UnprepareInput(const InputRef& input) { |
| VisitUpstream(input, [](const InputRef& input, const OutputRef& output, |
| const Stage::UpstreamCallback& callback) { |
| DCHECK(input.actual().prepared()); |
| input.stage_->UnprepareInput(input.index_); |
| output.stage_->UnprepareOutput(output.index_, callback); |
| }); |
| } |
| |
| void Engine::FlushOutput(const OutputRef& output) { |
| if (!output.connected()) { |
| return; |
| } |
| VisitDownstream(output, [](const OutputRef& output, const InputRef& input, |
| const Stage::DownstreamCallback& callback) { |
| DCHECK(input.actual().prepared()); |
| output.stage_->FlushOutput(output.index_); |
| input.stage_->FlushInput(input.index_, callback); |
| }); |
| } |
| |
| void Engine::RequestUpdate(Stage* stage) { |
| DCHECK(stage); |
| base::AutoLock lock(lock_); |
| Update(stage); |
| Update(); |
| } |
| |
| void Engine::PushToSupplyBacklog(Stage* stage) { |
| lock_.AssertAcquired(); |
| DCHECK(stage); |
| |
| packets_produced_ = true; |
| if (!stage->in_supply_backlog_) { |
| supply_backlog_.push(stage); |
| stage->in_supply_backlog_ = true; |
| } |
| } |
| |
| void Engine::PushToDemandBacklog(Stage* stage) { |
| lock_.AssertAcquired(); |
| DCHECK(stage); |
| |
| if (!stage->in_demand_backlog_) { |
| demand_backlog_.push(stage); |
| stage->in_demand_backlog_ = true; |
| } |
| } |
| |
| void Engine::VisitUpstream(const InputRef& input, |
| const UpstreamVisitor& vistor) { |
| base::AutoLock lock(lock_); |
| |
| std::queue<InputRef> backlog; |
| backlog.push(input); |
| |
| while (!backlog.empty()) { |
| InputRef input = backlog.front(); |
| backlog.pop(); |
| DCHECK(input.valid()); |
| DCHECK(input.connected()); |
| |
| const OutputRef& output = input.mate(); |
| Stage* output_stage = output.stage_; |
| |
| vistor(input, output, [output_stage, &backlog](size_t input_index) { |
| backlog.push(InputRef(output_stage, input_index)); |
| }); |
| } |
| } |
| |
| void Engine::VisitDownstream(const OutputRef& output, |
| const DownstreamVisitor& vistor) { |
| base::AutoLock lock(lock_); |
| |
| std::queue<OutputRef> backlog; |
| backlog.push(output); |
| |
| while (!backlog.empty()) { |
| OutputRef output = backlog.front(); |
| backlog.pop(); |
| DCHECK(output.valid()); |
| DCHECK(output.connected()); |
| |
| const InputRef& input = output.mate(); |
| Stage* input_stage = input.stage_; |
| |
| vistor(output, input, [input_stage, &backlog](size_t output_index) { |
| backlog.push(OutputRef(input_stage, output_index)); |
| }); |
| } |
| } |
| |
| void Engine::Update() { |
| lock_.AssertAcquired(); |
| |
| while (true) { |
| Stage* stage = PopFromSupplyBacklog(); |
| if (stage != nullptr) { |
| Update(stage); |
| continue; |
| } |
| |
| stage = PopFromDemandBacklog(); |
| if (stage != nullptr) { |
| Update(stage); |
| continue; |
| } |
| |
| break; |
| } |
| } |
| |
| void Engine::Update(Stage* stage) { |
| lock_.AssertAcquired(); |
| |
| DCHECK(stage); |
| |
| packets_produced_ = false; |
| |
| stage->Update(this); |
| |
| // If the stage produced packets, it may need to reevaluate demand later. |
| if (packets_produced_) { |
| PushToDemandBacklog(stage); |
| } |
| } |
| |
| Stage* Engine::PopFromSupplyBacklog() { |
| lock_.AssertAcquired(); |
| |
| if (supply_backlog_.empty()) { |
| return nullptr; |
| } |
| |
| Stage* stage = supply_backlog_.front(); |
| supply_backlog_.pop(); |
| DCHECK(stage->in_supply_backlog_); |
| stage->in_supply_backlog_ = false; |
| return stage; |
| } |
| |
| Stage* Engine::PopFromDemandBacklog() { |
| lock_.AssertAcquired(); |
| |
| if (demand_backlog_.empty()) { |
| return nullptr; |
| } |
| |
| Stage* stage = demand_backlog_.top(); |
| demand_backlog_.pop(); |
| DCHECK(stage->in_demand_backlog_); |
| stage->in_demand_backlog_ = false; |
| return stage; |
| } |
| |
| } // namespace media |
| } // namespace mojo |