diff options
author | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-02 00:07:02 +0000 |
---|---|---|
committer | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-02 00:07:02 +0000 |
commit | a35b38811d89d54a718f7025f9acad24a5806939 (patch) | |
tree | 080c0c38199816c67f3b9287874cae0492b933f2 /media/omx/omx_codec.h | |
parent | 68cefdc3b5f14256807812c6819298acbf25c803 (diff) | |
download | chromium_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.h | 319 |
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_ |