| 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
|
|
|