Index: media/base/state_machine_example.cc |
diff --git a/media/base/state_machine_example.cc b/media/base/state_machine_example.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1addce03b13dc6fccfebaa2824abf1b01e31778d |
--- /dev/null |
+++ b/media/base/state_machine_example.cc |
@@ -0,0 +1,136 @@ |
+// 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 "media/base/simple_state_machine.h" |
+#include "media/base/state.h" |
+#include "media/base/state_machine_driver.h" |
+ |
+namespace media { |
+ |
+class MediaCodec {}; |
+class DecoderBuffer {}; |
+ |
+///////////////////// States |
+ |
+class CodecState : public State { |
+ public: |
+ MediaCodec* GetCodec() const { return media_codec_.get(); }; |
+ void SetCodec(std::unique_ptr<MediaCodec> media_codec) { |
+ media_codec_ = std::move(media_codec); |
+ StateChanged(); |
+ } |
+ |
+ // might have a state variable like okay, error, waiting_for_key. might |
+ // also have a flag like 'stop queueing at keyframe', or 'flush', etc. |
+ // there might be other things here that QueueInputMachine doesn't care about. |
+ |
+ private: |
+ ~CodecState() override {} |
+ std::unique_ptr<MediaCodec> media_codec_; |
+}; |
+ |
+class InputBufferState : public State { |
+ public: |
+ // causes state to be updated. |
+ void QueueBuffer(DecoderBuffer); |
+ |
+ // TODO: does this notify that state has changed? It could, but it's |
+ // unclear that we want to. it would force the decoding machine to run |
+ // until it can dequeue no more, which might or might not be what we want. |
+ // seems like we'd rather have that controlled in some other way. |
+ DecoderBuffer DequeueBuffer(); |
+ |
+ bool IsQueueEmpty() const; |
+ |
+ private: |
+ ~InputBufferState() override {} |
+}; |
+ |
+class SurfaceState : public State { |
+ private: |
+ ~SurfaceState() override {} |
+}; |
+ |
+class CdmState : public State { |
+ private: |
+ ~CdmState() override {} |
+}; |
+ |
+///////////////////// State machines |
+ |
+// Tries to queue pending input from Decode calls. Cares that we have a codec, |
+// that we're not flushing, and (maybe) checks for things like 'queue until |
+// next key frame'. |
+// Note that we could derive from StateMachine directly, but this saves some |
+// boiler plate. |
+using QueueInputMachineBase = SimpleStateMachine<InputBufferState, CodecState>; |
+class QueueInputMachine : public QueueInputMachineBase { |
+ public: |
+ QueueInputMachine(scoped_refptr<InputBufferState>, scoped_refptr<CodecState>); |
+ |
+ void Run() const override; |
+}; |
+ |
+// CodecGetterMachine might want CodecState, SurfaceState, and CdmState. |
+ |
+// QueueInputMachineBase handles registering the machine with the state as a |
+// client, and providing getters for the state objects. |
+QueueInputMachine::QueueInputMachine( |
+ scoped_refptr<InputBufferState> input_buffer_state, |
+ scoped_refptr<CodecState> codec_state) |
+ : QueueInputMachineBase(input_buffer_state, codec_state) {} |
+ |
+void QueueInputMachine::Run() const { |
+ if (Get<InputBufferState>()->IsQueueEmpty()) |
+ return; |
+ |
+ MediaCodec* codec = Get<CodecState>()->GetCodec(); |
+ if (!codec) |
+ return; |
+ |
+ // Check for other things, like if we're allowed to queue input. |
+ |
+ // Pretty much do what QueueInput does. |
+ // if this is an eos, we'd update the codec state to indicate that a flush |
+ // is in progress. |
+} |
+ |
+using CodecGetterMachineBase = |
+ SimpleStateMachine<CodecState, SurfaceState, CdmState>; |
+class CodecGetterMachine : public CodecGetterMachineBase { |
+ public: |
+ CodecGetterMachine(scoped_refptr<CodecState> codec_state, |
+ scoped_refptr<SurfaceState> surface_state, |
+ scoped_refptr<CdmState> cdm_state) |
+ : CodecGetterMachineBase(codec_state, surface_state, cdm_state) {} |
+ |
+ void Run() const override {} |
+}; |
+ |
+///////////////////// Setup code. |
+ |
+void RunSomeExample() { |
+ scoped_refptr<InputBufferState> input_buffer_state(new InputBufferState); |
+ scoped_refptr<CodecState> codec_state(new CodecState); |
+ scoped_refptr<SurfaceState> surface_state(new SurfaceState); |
+ scoped_refptr<CdmState> cdm_state(new CdmState); |
+ |
+ std::unique_ptr<QueueInputMachine> queue_input_machine( |
+ new QueueInputMachine(input_buffer_state, codec_state)); |
+ std::unique_ptr<CodecGetterMachine> codec_getter_machine( |
+ new CodecGetterMachine(codec_state, surface_state, cdm_state)); |
+ |
+ std::unique_ptr<StateMachineDriver> driver(new StateMachineDriver); |
+ driver->AddStateMachine(std::move(queue_input_machine)); |
+ driver->AddStateMachine(std::move(codec_getter_machine)); |
+ // Note that we no longer have ptrs to the machines; |driver| has them. |
+ // That's a little inconvenient if we want to refer to them, such as for |
+ // giving a raw ptr to a timer, for it to call RunImmediately. |
+ // Perhaps AddStateMachine could return a weak ref or raw ptr? |
+ |
+ // This will cause the driver to post a task to run the state machine. |
+ input_buffer_state->QueueBuffer(DecoderBuffer()); |
+} |
+ |
+} // namespace media |