Index: services/media/framework/graph.cc |
diff --git a/services/media/framework/graph.cc b/services/media/framework/graph.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..794985d2823bc0fea7e534dd5e2d34070237fa07 |
--- /dev/null |
+++ b/services/media/framework/graph.cc |
@@ -0,0 +1,219 @@ |
+// 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/graph.h" |
+ |
+namespace mojo { |
+namespace media { |
+ |
+Graph::Graph() { |
+ update_function_ = [this](Stage* stage) { |
+ engine_.RequestUpdate(stage); |
+ }; |
+} |
+ |
+Graph::~Graph() { |
+ Reset(); |
+} |
+ |
+void Graph::RemovePart(PartRef part) { |
+ DCHECK(part.valid()); |
+ |
+ Stage* stage = part.stage_; |
+ |
+ size_t input_count = stage->input_count(); |
+ for (size_t input_index = 0; input_index < input_count; input_index++) { |
+ if (stage->input(input_index).connected()) { |
+ DisconnectInput(InputRef(stage, input_index)); |
+ } |
+ } |
+ |
+ size_t output_count = stage->output_count(); |
+ for (size_t output_index = 0; output_index < output_count; output_index++) { |
+ if (stage->output(output_index).connected()) { |
+ DisconnectOutput(OutputRef(stage, output_index)); |
+ } |
+ } |
+ |
+ stage->SetUpdateCallback(nullptr); |
+ |
+ sources_.remove(stage); |
+ sinks_.remove(stage); |
+ stages_.remove(stage); |
+ |
+ delete stage; |
+} |
+ |
+PartRef Graph::Connect(const OutputRef& output, const InputRef& input) { |
+ DCHECK(output.valid()); |
+ DCHECK(input.valid()); |
+ |
+ if (output.connected()) { |
+ DisconnectOutput(output); |
+ } |
+ if (input.connected()) { |
+ DisconnectInput(input); |
+ } |
+ |
+ output.actual().Connect(input); |
+ input.actual().Connect(output); |
+ |
+ return input.part(); |
+} |
+ |
+PartRef Graph::ConnectParts( |
+ PartRef upstream_part, |
+ PartRef downstream_part) { |
+ DCHECK(upstream_part.valid()); |
+ DCHECK(downstream_part.valid()); |
+ Connect(upstream_part.output(), downstream_part.input()); |
+ return downstream_part; |
+} |
+ |
+PartRef Graph::ConnectOutputToPart( |
+ const OutputRef& output, |
+ PartRef downstream_part) { |
+ DCHECK(output.valid()); |
+ DCHECK(downstream_part.valid()); |
+ Connect(output, downstream_part.input()); |
+ return downstream_part; |
+} |
+ |
+PartRef Graph::ConnectPartToInput( |
+ PartRef upstream_part, |
+ const InputRef& input) { |
+ DCHECK(upstream_part.valid()); |
+ DCHECK(input.valid()); |
+ Connect(upstream_part.output(), input); |
+ return input.part(); |
+} |
+ |
+void Graph::DisconnectOutput(const OutputRef& output) { |
+ DCHECK(output.valid()); |
+ |
+ if (!output.connected()) { |
+ return; |
+ } |
+ |
+ Input& mate = output.mate().actual(); |
+ |
+ if (mate.prepared()) { |
+ CHECK(false) << "attempt to disconnect prepared output"; |
+ return; |
+ } |
+ |
+ mate.Disconnect(); |
+ output.actual().Disconnect(); |
+} |
+ |
+void Graph::DisconnectInput(const InputRef& input) { |
+ DCHECK(input.valid()); |
+ |
+ if (!input.connected()) { |
+ return; |
+ } |
+ |
+ Output& mate = input.mate().actual(); |
+ |
+ if (input.actual().prepared()) { |
+ CHECK(false) << "attempt to disconnect prepared input"; |
+ return; |
+ } |
+ |
+ mate.Disconnect(); |
+ input.actual().Disconnect(); |
+} |
+ |
+void Graph::RemovePartsConnectedToPart(PartRef part) { |
+ DCHECK(part.valid()); |
+ |
+ std::deque<PartRef> to_remove { part }; |
+ |
+ while (!to_remove.empty()) { |
+ PartRef part = to_remove.front(); |
+ to_remove.pop_front(); |
+ |
+ for (size_t i = 0; i < part.input_count(); ++i) { |
+ to_remove.push_back(part.input(i).part()); |
+ } |
+ |
+ for (size_t i = 0; i < part.output_count(); ++i) { |
+ to_remove.push_back(part.output(i).part()); |
+ } |
+ |
+ RemovePart(part); |
+ } |
+} |
+ |
+void Graph::RemovePartsConnectedToOutput(const OutputRef& output) { |
+ DCHECK(output.valid()); |
+ |
+ if (!output.connected()) { |
+ return; |
+ } |
+ |
+ PartRef downstream_part = output.mate().part(); |
+ DisconnectOutput(output); |
+ RemovePartsConnectedToPart(downstream_part); |
+} |
+ |
+void Graph::RemovePartsConnectedToInput(const InputRef& input) { |
+ DCHECK(input.valid()); |
+ |
+ if (!input.connected()) { |
+ return; |
+ } |
+ |
+ PartRef upstream_part = input.mate().part(); |
+ DisconnectInput(input); |
+ RemovePartsConnectedToPart(upstream_part); |
+} |
+ |
+void Graph::Reset() { |
+ sources_.clear(); |
+ sinks_.clear(); |
+ while (!stages_.empty()) { |
+ Stage* stage = stages_.front(); |
+ stages_.pop_front(); |
+ delete stage; |
+ } |
+} |
+ |
+void Graph::Prepare() { |
+ for (Stage* sink : sinks_) { |
+ for (size_t i = 0; i < sink->input_count(); ++i) { |
+ engine_.PrepareInput(InputRef(sink, i)); |
+ } |
+ } |
+} |
+ |
+void Graph::PrepareInput(const InputRef& input) { |
+ DCHECK(input.valid()); |
+ engine_.PrepareInput(input); |
+} |
+ |
+void Graph::PrimeSinks() { |
+ for (Stage* sink : sinks_) { |
+ sink->Prime(); |
+ } |
+} |
+ |
+PartRef Graph::Add(Stage* stage) { |
+ stages_.push_back(stage); |
+ |
+ if (stage->input_count() == 0) { |
+ sources_.push_back(stage); |
+ } |
+ |
+ if (stage->output_count() == 0) { |
+ sinks_.push_back(stage); |
+ } |
+ |
+ stage->SetUpdateCallback(update_function_); |
+ |
+ return PartRef(stage); |
+} |
+ |
+} // namespace media |
+} // namespace mojo |