summaryrefslogtreecommitdiffstats
path: root/media/omx/omx_codec.h
diff options
context:
space:
mode:
authorajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-02 00:07:02 +0000
committerajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-02 00:07:02 +0000
commita35b38811d89d54a718f7025f9acad24a5806939 (patch)
tree080c0c38199816c67f3b9287874cae0492b933f2 /media/omx/omx_codec.h
parent68cefdc3b5f14256807812c6819298acbf25c803 (diff)
downloadchromium_src-a35b38811d89d54a718f7025f9acad24a5806939.zip
chromium_src-a35b38811d89d54a718f7025f9acad24a5806939.tar.gz
chromium_src-a35b38811d89d54a718f7025f9acad24a5806939.tar.bz2
Rename OmxVideoDecoder, and break up the omx library files from the omx_test target.
Review URL: http://codereview.chromium.org/449070 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33516 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/omx/omx_codec.h')
-rw-r--r--media/omx/omx_codec.h319
1 files changed, 319 insertions, 0 deletions
diff --git a/media/omx/omx_codec.h b/media/omx/omx_codec.h
new file mode 100644
index 0000000..9a0804f
--- /dev/null
+++ b/media/omx/omx_codec.h
@@ -0,0 +1,319 @@
+// Copyright (c) 2009 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.
+
+// TODO(ajwong): Generalize this class (fix comments, API, and extract
+// implemntation) so that it can be used for encoding & decoding of both
+// Video and Audio.
+//
+// An object that works with an OpenMAX component for video decoding.
+// Operations on this object are all asynchronous and this object
+// requires a message loop that it works on.
+//
+// USAGES
+//
+// // Initialization.
+// MessageLoop message_loop;
+// OmxCodec* decoder = new OmxCodec(&message_loop);
+// decoder->Setup(component_name, kCodecH264);
+// decoder->SetErrorCallback(NewCallback(this, &Client::ErrorCallback));
+//
+// // Start is asynchronous. But we don't need to wait for it to proceed.
+// decoder->Start();
+//
+// // We can start giving buffer to the decoder right after start. It will
+// // queue the input buffers and output requests and process them until
+// // the decoder can actually process them.
+// for (int i = 0; i < kInitialBuffers; ++i) {
+// InputBuffer* buffer = PrepareInitialInputBuffer();
+// decoder->Feed(buffer, NewCallback(this, &Client::FeedCallback));
+// }
+//
+// // We can also issue read requests to the decoder.
+// decoder->Read(NewCallback(this, &Client::ReadCallback));
+//
+// // Make the following call to stop the decoder:
+// decoder->Stop(NewCallback(this, &Client::StopCallback));
+//
+// A typical FeedCallback will look like:
+// void Client::FeedCallback(InputBuffer* buffer) {
+// // We have read to the end so stop feeding.
+// if (buffer->Eos())
+// return;
+// PrepareInputBuffer(buffer);
+// decoder->Feed(buffer, NewCallback(this, &Client::FeedCallback));
+// }
+//
+// EXTERNAL STATES
+//
+// Client of this class will only see four states from the decoder:
+// .........
+// | Error |
+// .........
+// ^
+// `-.
+// ......... ......... ........
+// | Empty | -> | Start | -> | Stop |
+// ......... ......... ........
+//
+// How to operate this object in these four states can be described by
+// usage above.
+//
+// INTERNAL STATES
+//
+// There are multiple internal states to keep track of state transitions
+// of the OpenMAX component. The state transitions and the task during
+// the transition can be summerized by the following state diagram:
+//
+// ......... -> .......... -> ........ -> .............
+// | Empty | | Loaded | | Idle | | Executing |
+// ......... <- .......... <- ........ <- .............
+// ^ `
+// ` v
+// ......... ............. ..............
+// | Error | | Port Enable | | Port Disable |
+// ......... ............. ..............
+//
+// We need to perform specific tasks in order to transition from one state
+// to another. When an error is received, this object will transition to
+// the error state.
+
+#ifndef MEDIA_OMX_CODEC_H_
+#define MEDIA_OMX_CODEC_H_
+
+#include <queue>
+#include <vector>
+
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+#include "third_party/openmax/il/OMX_Component.h"
+#include "third_party/openmax/il/OMX_Core.h"
+
+class InputBuffer;
+class MessageLoop;
+
+namespace media {
+
+class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
+ public:
+ typedef Callback1<InputBuffer*>::Type FeedCallback;
+ typedef Callback2<uint8*, int>::Type ReadCallback;
+ typedef Callback0::Type Callback;
+
+ enum Codec {
+ kCodecNone,
+ kCodecH264,
+ kCodecMpeg4,
+ kCodecH263,
+ kCodecVc1,
+ };
+
+ OmxCodec(MessageLoop* message_loop);
+ virtual ~OmxCodec();
+
+ // Set the component name and input codec format.
+ // TODO(hclam): Add input format and output format. Also remove |component|.
+ void Setup(const char* component, Codec codec);
+
+ // Set the error callback. In case of error the callback will be called.
+ void SetErrorCallback(Callback* callback);
+
+ // Start the decoder, this will start the initialization asynchronously.
+ // Client can start feeding to and reading from the decoder.
+ void Start();
+
+ // Stop the decoder. When the decoder is fully stopped, |callback|
+ // is called.
+ void Stop(Callback* callback);
+
+ // Read decoded buffer from the decoder. When there is decoded data
+ // ready to be consumed |callback| is called.
+ void Read(ReadCallback* callback);
+
+ // Feed the decoder with |buffer|. When the decoder has consumed the
+ // buffer |callback| is called with |buffer| being the parameter.
+ void Feed(InputBuffer* buffer, FeedCallback* callback);
+
+ // Flush the decoder and reset its end-of-stream state.
+ void Flush(Callback* callback);
+
+ // Getters for private members.
+ OMX_COMPONENTTYPE* decoder_handle() { return decoder_handle_; }
+ Codec codec() { return codec_; }
+ int input_port() { return input_port_; }
+ int output_port() { return output_port_; }
+
+ // Subclass can provide a different value.
+ virtual int current_omx_spec_version() const { return 0x00000101; }
+
+ protected:
+ // Returns the component name given the codec.
+ virtual const char* GetComponentName(Codec codec) { return ""; }
+
+ // Inherit from subclass to allow device specific configurations.
+ virtual bool DeviceSpecificConfig() { return true; }
+
+ private:
+ enum State {
+ kEmpty,
+ kLoaded,
+ kIdle,
+ kExecuting,
+ kPortSettingEnable,
+ kPortSettingDisable,
+ kError,
+ };
+
+ // Getter and setter for the state.
+ State GetState() const;
+ void SetState(State state);
+ State GetNextState() const;
+ void SetNextState(State state);
+
+ // Methods to be executed in |message_loop_|, they correspond to the
+ // public methods.
+ void StartTask();
+ void StopTask(Callback* callback);
+ void ReadTask(ReadCallback* callback);
+ void FeedTask(InputBuffer* buffer, FeedCallback* callback);
+
+ // Helper method to perform tasks when this object is stopped.
+ void DoneStop();
+
+ // Helper method to call |error_callback_| after transition to error
+ // state is done.
+ void ReportError();
+
+ // Methods and free input and output buffers.
+ bool AllocateInputBuffers();
+ bool AllocateOutputBuffers();
+ void FreeInputBuffers();
+ void FreeOutputBuffers();
+ void FreeInputQueue();
+ void FreeOutputQueue();
+
+ // Transition methods define the specific tasks needs to be done
+ // in order transition to the next state.
+ void Transition_EmptyToLoaded();
+ void Transition_LoadedToIdle();
+ void Transition_IdleToExecuting();
+ void Transition_ExecutingToDisable();
+ void Transition_DisableToEnable();
+ void Transition_DisableToIdle();
+ void Transition_EnableToExecuting();
+ void Transition_EnableToIdle();
+ void Transition_ExecutingToIdle();
+ void Transition_IdleToLoaded();
+ void Transition_LoadedToEmpty();
+ void Transition_Error();
+
+ // State transition routines. They control which task to perform based
+ // on the current state and the next state.
+ void PostStateTransitionTask(State state);
+ void StateTransitionTask(State state);
+
+ // This method does an automatic state transition after the last
+ // state transition was completed. For example, after the decoder
+ // has transitioned from kEmpty to kLoaded, this method will order
+ // transition from kLoaded to kIdle.
+ void PostDoneStateTransitionTask();
+ void DoneStateTransitionTask();
+
+ // Determine whether we can issue fill buffer or empty buffer
+ // to the decoder based on the current state and next state.
+ bool CanFillBuffer();
+ bool CanEmptyBuffer();
+
+ // Determine whether we can use |input_queue_| and |output_queue_|
+ // based on the current state.
+ bool CanAcceptInput();
+ bool CanAcceptOutput();
+
+ // Methods to handle incoming (encoded) buffers.
+ void EmptyBufferCompleteTask(OMX_BUFFERHEADERTYPE* buffer);
+ void EmptyBufferTask();
+
+ // Methods to handle outgoing (decoded) buffers.
+ void FillBufferCompleteTask(OMX_BUFFERHEADERTYPE* buffer);
+ void FillBufferTask();
+
+ // Methods that do initial reads to kick start the decoding process.
+ void InitialFillBuffer();
+ void InitialEmptyBuffer();
+
+ // Member functions to handle events from the OMX component. They
+ // are called on the thread that the OMX component runs on, thus
+ // it is not safe to perform any operations on them. They simply
+ // post a task on |message_loop_| to do the actual work.
+ void EventHandlerInternal(OMX_HANDLETYPE component,
+ OMX_EVENTTYPE event,
+ OMX_U32 data1, OMX_U32 data2,
+ OMX_PTR event_data);
+
+ void EmptyBufferCallbackInternal(OMX_HANDLETYPE component,
+ OMX_BUFFERHEADERTYPE* buffer);
+
+ void FillBufferCallbackInternal(OMX_HANDLETYPE component,
+ OMX_BUFFERHEADERTYPE* buffer);
+
+ // The following three methods are static callback methods
+ // for the OMX component. When these callbacks are received, the
+ // call is delegated to the three internal methods above.
+ static OMX_ERRORTYPE EventHandler(OMX_HANDLETYPE component,
+ OMX_PTR priv_data,
+ OMX_EVENTTYPE event,
+ OMX_U32 data1, OMX_U32 data2,
+ OMX_PTR event_data);
+
+ static OMX_ERRORTYPE EmptyBufferCallback(OMX_HANDLETYPE component,
+ OMX_PTR priv_data,
+ OMX_BUFFERHEADERTYPE* buffer);
+
+ static OMX_ERRORTYPE FillBufferCallback(OMX_HANDLETYPE component,
+ OMX_PTR priv_data,
+ OMX_BUFFERHEADERTYPE* buffer);
+
+ std::vector<OMX_BUFFERHEADERTYPE*> input_buffers_;
+ int input_buffer_count_;
+ int input_buffer_size_;
+ int input_port_;
+ bool input_eos_;
+
+ std::vector<OMX_BUFFERHEADERTYPE*> output_buffers_;
+ int output_buffer_count_;
+ int output_buffer_size_;
+ int output_port_;
+ bool output_eos_;
+
+ OMX_COMPONENTTYPE* decoder_handle_;
+
+ // |state_| records the current state. During state transition
+ // |next_state_| is the next state that this machine will transition
+ // to. After a state transition is completed and the state becomes
+ // stable then |next_state_| equals |state_|. Inequality can be
+ // used to detect a state transition.
+ // These two members are read and written only on |message_loop_|.
+ State state_;
+ State next_state_;
+
+ // TODO(hclam): We should keep a list of component names.
+ const char* component_;
+ Codec codec_;
+ MessageLoop* message_loop_;
+
+ scoped_ptr<Callback> stop_callback_;
+ scoped_ptr<Callback> error_callback_;
+
+ // Input and output queue for encoded data and decoded frames.
+ typedef std::pair<InputBuffer*, FeedCallback*> InputUnit;
+ std::queue<InputUnit> input_queue_;
+ std::queue<ReadCallback*> output_queue_;
+
+ // Input and output buffers that we can use to feed the decoder.
+ std::queue<OMX_BUFFERHEADERTYPE*> available_input_buffers_;
+ std::queue<OMX_BUFFERHEADERTYPE*> available_output_buffers_;
+};
+
+} // namespace media
+
+#endif // MEDIA_OMX_CODEC_H_