| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // TODO(ajwong): Generalize this class (fix comments, API, and extract | |
| 6 // implemntation) so that it can be used for encoding & decoding of both | |
| 7 // Video and Audio. | |
| 8 // | |
| 9 // An object that works with an OpenMAX component for video decoding. | |
| 10 // Operations on this object are all asynchronous and this object | |
| 11 // requires a message loop that it works on. | |
| 12 // | |
| 13 // OWNERSHIP | |
| 14 // | |
| 15 // The OmxCodec works with external objects | |
| 16 // OmxConfigurator | |
| 17 // This object is given to OmxCodec to perform port configuration. | |
| 18 // This object is provided and destroyed externally. Its references | |
| 19 // are given to OmxCodec and client application is responsible | |
| 20 // for cleaning them. | |
| 21 // | |
| 22 // INTERACTION WITH EXTERNAL OBJECTS | |
| 23 // | |
| 24 // ................ ............ | |
| 25 // | Configurator | <------------- | OmxCodec | | |
| 26 // ................ ............ | |
| 27 // Read / Feed -----------' ' | |
| 28 // .-----------' v Buffer Allocation | |
| 29 // .......... ............... | |
| 30 // | Client | ------------------> | OutputSink | | |
| 31 // .......... Buffer Ready ............... | |
| 32 // | |
| 33 // THREADING | |
| 34 // | |
| 35 // OmxCodec is given a message loop to run on. There is a strong gurantee | |
| 36 // that all callbacks given to it will be executed on this message loop. | |
| 37 // Communicatations with OmxConfigurator and OmxOutputSink are also done | |
| 38 // on this thread. | |
| 39 // | |
| 40 // Public methods can be called on any thread. | |
| 41 // | |
| 42 // USAGES | |
| 43 // | |
| 44 // // Initialization. | |
| 45 // MessageLoop message_loop; | |
| 46 // OmxCodec* decoder = new OmxCodec(&message_loop); | |
| 47 // | |
| 48 // OmxConfigurator::MediaFormat input_format, output_format; | |
| 49 // input_format.codec = OmxCodec::kCodecH264; | |
| 50 // output_format.codec = OmxCodec::kCodecRaw; | |
| 51 // scoped_ptr<OmxConfigurator> configurator( | |
| 52 // new OmxDecoderConfigurator(input_format, output_format)); | |
| 53 // | |
| 54 // decoder->Setup(configurator.get()); | |
| 55 // decoder->SetErrorCallback(NewCallback(this, &Client::ErrorCallback)); | |
| 56 // decoder->SetFormatCallback(NewCallback(this, &Client::FormatCallback)); | |
| 57 // | |
| 58 // // Start is asynchronous. We don't need to wait for it to proceed. | |
| 59 // decoder->Start(); | |
| 60 // | |
| 61 // // We can start giving buffer to the decoder right after start. It will | |
| 62 // // queue the input buffers and output requests and process them until | |
| 63 // // the decoder can actually process them. | |
| 64 // for (int i = 0; i < kInitialBuffers; ++i) { | |
| 65 // OmxInputBuffer* buffer = PrepareInitialInputBuffer(); | |
| 66 // decoder->Feed(buffer, NewCallback(this, &Client::FeedCallback)); | |
| 67 // } | |
| 68 // | |
| 69 // // We can also issue read requests to the decoder. | |
| 70 // decoder->Read(NewCallback(this, &Client::ReadCallback)); | |
| 71 // | |
| 72 // // Make the following call to stop the decoder: | |
| 73 // decoder->Stop(NewCallback(this, &Client::StopCallback)); | |
| 74 // | |
| 75 // A typical FeedCallback will look like: | |
| 76 // void Client::FeedCallback(OmxInputBuffer* buffer) { | |
| 77 // // We have read to the end so stop feeding. | |
| 78 // if (buffer->IsEndOfStream()) | |
| 79 // return; | |
| 80 // PrepareInputBuffer(buffer); | |
| 81 // decoder->Feed(buffer, NewCallback(this, &Client::FeedCallback)); | |
| 82 // } | |
| 83 // | |
| 84 // A typical ReadCallback will look like: | |
| 85 // void Client::ReadCallback(int buffer_id, | |
| 86 // OmxOutputSink::BufferUsedCallback* callback) { | |
| 87 // // Detect end-of-stream state. | |
| 88 // if (buffer_id == OmxCodec::kEosBuffer) | |
| 89 // return; | |
| 90 // | |
| 91 // // Issue a new read immediately. | |
| 92 // decoder->Read(NewCallback(this, &Client::ReadCallback)); | |
| 93 // | |
| 94 // // Pass the buffer to OmxOutputSink. | |
| 95 // output_sink->BufferReady(buffer_id, callback); | |
| 96 // } | |
| 97 // | |
| 98 // EXTERNAL STATES | |
| 99 // | |
| 100 // Client of this class will only see four states from the decoder: | |
| 101 // ......... | |
| 102 // | Error | | |
| 103 // ......... | |
| 104 // ^ | |
| 105 // `-. | |
| 106 // ......... ......... ........ | |
| 107 // | Empty | -> | Start | -> | Stop | | |
| 108 // ......... ......... ........ | |
| 109 // | |
| 110 // How to operate this object in these four states can be described by | |
| 111 // usage above. | |
| 112 // | |
| 113 // INTERNAL STATES | |
| 114 // | |
| 115 // There are multiple internal states to keep track of state transitions | |
| 116 // of the OpenMAX component. The state transitions and the task during | |
| 117 // the transition can be summerized by the following state diagram: | |
| 118 // | |
| 119 // ......... -> .......... -> ........ -> ............. | |
| 120 // | Empty | | Loaded | | Idle | | Executing | | |
| 121 // ......... <- .......... <- ........ <- ............. | |
| 122 // ^ ` | |
| 123 // ` v | |
| 124 // ......... ............. .............. | |
| 125 // | Error | | Port Enable | | Port Disable | | |
| 126 // ......... ............. .............. | |
| 127 // | |
| 128 // We need to perform specific tasks in order to transition from one state | |
| 129 // to another. When an error is received, this object will transition to | |
| 130 // the error state. | |
| 131 | |
| 132 #ifndef MEDIA_OMX_OMX_CODEC_H_ | |
| 133 #define MEDIA_OMX_OMX_CODEC_H_ | |
| 134 | |
| 135 #include <queue> | |
| 136 #include <vector> | |
| 137 | |
| 138 #include "base/callback.h" | |
| 139 #include "base/scoped_ptr.h" | |
| 140 #include "media/omx/omx_configurator.h" | |
| 141 #include "third_party/openmax/il/OMX_Component.h" | |
| 142 #include "third_party/openmax/il/OMX_Core.h" | |
| 143 #include "third_party/openmax/il/OMX_Video.h" | |
| 144 | |
| 145 class MessageLoop; | |
| 146 | |
| 147 namespace media { | |
| 148 | |
| 149 class Buffer; | |
| 150 | |
| 151 class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> { | |
| 152 public: | |
| 153 // TODO(jiesun): remove callback parameters. | |
| 154 typedef Callback2< | |
| 155 const OmxConfigurator::MediaFormat&, | |
| 156 const OmxConfigurator::MediaFormat&>::Type FormatCallback; | |
| 157 typedef Callback1<scoped_refptr<Buffer> >::Type FeedDoneCallback; | |
| 158 typedef Callback1<OMX_BUFFERHEADERTYPE*>::Type FillDoneCallback; | |
| 159 typedef Callback0::Type Callback; | |
| 160 | |
| 161 // Initialize an OmxCodec object that runs on |message_loop|. It is | |
| 162 // guaranteed that callbacks are executed on this message loop. | |
| 163 explicit OmxCodec(MessageLoop* message_loop); | |
| 164 virtual ~OmxCodec(); | |
| 165 | |
| 166 // Setup OmxCodec using |configurator|. |configurator| and |output_sink| | |
| 167 // are not owned by this class and should be cleaned up externally. | |
| 168 void Setup(OmxConfigurator* configurator, | |
| 169 FeedDoneCallback* feed_done_callback, | |
| 170 FillDoneCallback* fill_done_callback); | |
| 171 | |
| 172 // Set the error callback. In case of error the callback will be called. | |
| 173 void SetErrorCallback(Callback* callback); | |
| 174 | |
| 175 // Set the format change callback. In case of input stream changes. | |
| 176 void SetFormatCallback(FormatCallback* callback); | |
| 177 | |
| 178 // Start the decoder, this will start the initialization asynchronously. | |
| 179 // Client can start feeding to and reading from the decoder. | |
| 180 void Start(); | |
| 181 | |
| 182 // Stop the decoder. When the decoder is fully stopped, |callback| | |
| 183 // is called. | |
| 184 void Stop(Callback* callback); | |
| 185 | |
| 186 // Feed the decoder with |buffer|. When the decoder has consumed the | |
| 187 // buffer |feed_done_callback_| is called with |buffer|. | |
| 188 void Feed(scoped_refptr<Buffer> buffer); | |
| 189 | |
| 190 // Flush the decoder and reset its end-of-stream state. | |
| 191 void Flush(Callback* callback); | |
| 192 | |
| 193 // Subclass can provide a different value. | |
| 194 virtual int current_omx_spec_version() const { return 0x00000101; } | |
| 195 | |
| 196 static const int kEosBuffer = -1; | |
| 197 | |
| 198 private: | |
| 199 enum State { | |
| 200 kEmpty, | |
| 201 kLoaded, | |
| 202 kIdle, | |
| 203 kExecuting, | |
| 204 kPortSettingEnable, | |
| 205 kPortSettingDisable, | |
| 206 kError, | |
| 207 }; | |
| 208 | |
| 209 // Getter and setter for the state. | |
| 210 State GetState() const; | |
| 211 void SetState(State state); | |
| 212 State GetNextState() const; | |
| 213 void SetNextState(State state); | |
| 214 | |
| 215 // Methods to be executed in |message_loop_|, they correspond to the | |
| 216 // public methods. | |
| 217 void StartTask(); | |
| 218 void StopTask(Callback* callback); | |
| 219 void FeedTask(scoped_refptr<Buffer> buffer); | |
| 220 | |
| 221 // Helper method to perform tasks when this object is stopped. | |
| 222 void DoneStop(); | |
| 223 | |
| 224 // Helper method to call |error_callback_| after transition to error | |
| 225 // state is done. | |
| 226 void ReportError(); | |
| 227 | |
| 228 // Helper method to call |format_callback_| after a format change. | |
| 229 // used when decoder output port had done with port reconfigure and | |
| 230 // return to enabled state. | |
| 231 void ReportFormatChange( | |
| 232 const OmxConfigurator::MediaFormat& input_format, | |
| 233 const OmxConfigurator::MediaFormat& output_format); | |
| 234 | |
| 235 // Helper method to configure port format at LOADED state. | |
| 236 bool ConfigureIOPorts(); | |
| 237 | |
| 238 // Methods and free input and output buffers. | |
| 239 bool AllocateInputBuffers(); | |
| 240 bool AllocateOutputBuffers(); | |
| 241 void FreeInputBuffers(); | |
| 242 void FreeOutputBuffers(); | |
| 243 void FreeInputQueue(); | |
| 244 | |
| 245 // Transition methods define the specific tasks needs to be done | |
| 246 // in order transition to the next state. | |
| 247 void Transition_EmptyToLoaded(); | |
| 248 void Transition_LoadedToIdle(); | |
| 249 void Transition_IdleToExecuting(); | |
| 250 void Transition_ExecutingToDisable(); | |
| 251 void Transition_DisableToEnable(); | |
| 252 void Transition_DisableToIdle(); | |
| 253 void Transition_EnableToExecuting(); | |
| 254 void Transition_EnableToIdle(); | |
| 255 void Transition_ExecutingToIdle(); | |
| 256 void Transition_IdleToLoaded(); | |
| 257 void Transition_LoadedToEmpty(); | |
| 258 void Transition_Error(); | |
| 259 | |
| 260 // State transition routines. They control which task to perform based | |
| 261 // on the current state and the next state. | |
| 262 void PostStateTransitionTask(State state); | |
| 263 void StateTransitionTask(State state); | |
| 264 | |
| 265 // This method does an automatic state transition after the last | |
| 266 // state transition was completed. For example, after the decoder | |
| 267 // has transitioned from kEmpty to kLoaded, this method will order | |
| 268 // transition from kLoaded to kIdle. | |
| 269 void PostDoneStateTransitionTask(); | |
| 270 void DoneStateTransitionTask(); | |
| 271 | |
| 272 // Determine whether we can issue fill buffer or empty buffer | |
| 273 // to the decoder based on the current state and next state. | |
| 274 bool CanFillBuffer(); | |
| 275 bool CanEmptyBuffer(); | |
| 276 | |
| 277 // Determine whether we can use |input_queue_| and |output_queue_| | |
| 278 // based on the current state. | |
| 279 bool CanAcceptInput(); | |
| 280 bool CanAcceptOutput(); | |
| 281 | |
| 282 // Methods to handle incoming (encoded) buffers. | |
| 283 void EmptyBufferCompleteTask(OMX_BUFFERHEADERTYPE* buffer); | |
| 284 void EmptyBufferTask(); | |
| 285 | |
| 286 // Methods to handle outgoing (decoded) buffers. | |
| 287 void FillBufferCompleteTask(OMX_BUFFERHEADERTYPE* buffer); | |
| 288 | |
| 289 // Take on decoded buffer to fulfill one read request. | |
| 290 void FulfillOneRead(); | |
| 291 | |
| 292 // Callback method to be called from a buffer output sink. | |
| 293 // BufferUsedTask() is the corresponding task that runs on | |
| 294 // |message_loop_|. | |
| 295 void BufferUsedCallback(int buffer_id); | |
| 296 void BufferUsedTask(int buffer_id); | |
| 297 | |
| 298 // Methods that do initial reads to kick start the decoding process. | |
| 299 void InitialFillBuffer(); | |
| 300 void InitialEmptyBuffer(); | |
| 301 | |
| 302 // Member functions to handle events from the OMX component. They | |
| 303 // are called on the thread that the OMX component runs on, thus | |
| 304 // it is not safe to perform any operations on them. They simply | |
| 305 // post a task on |message_loop_| to do the actual work. | |
| 306 void EventHandlerInternal(OMX_HANDLETYPE component, | |
| 307 OMX_EVENTTYPE event, | |
| 308 OMX_U32 data1, OMX_U32 data2, | |
| 309 OMX_PTR event_data); | |
| 310 | |
| 311 void EmptyBufferCallbackInternal(OMX_HANDLETYPE component, | |
| 312 OMX_BUFFERHEADERTYPE* buffer); | |
| 313 | |
| 314 void FillBufferCallbackInternal(OMX_HANDLETYPE component, | |
| 315 OMX_BUFFERHEADERTYPE* buffer); | |
| 316 | |
| 317 // The following three methods are static callback methods | |
| 318 // for the OMX component. When these callbacks are received, the | |
| 319 // call is delegated to the three internal methods above. | |
| 320 static OMX_ERRORTYPE EventHandler(OMX_HANDLETYPE component, | |
| 321 OMX_PTR priv_data, | |
| 322 OMX_EVENTTYPE event, | |
| 323 OMX_U32 data1, OMX_U32 data2, | |
| 324 OMX_PTR event_data); | |
| 325 | |
| 326 static OMX_ERRORTYPE EmptyBufferCallback(OMX_HANDLETYPE component, | |
| 327 OMX_PTR priv_data, | |
| 328 OMX_BUFFERHEADERTYPE* buffer); | |
| 329 | |
| 330 static OMX_ERRORTYPE FillBufferCallback(OMX_HANDLETYPE component, | |
| 331 OMX_PTR priv_data, | |
| 332 OMX_BUFFERHEADERTYPE* buffer); | |
| 333 | |
| 334 std::vector<OMX_BUFFERHEADERTYPE*> input_buffers_; | |
| 335 int input_buffer_count_; | |
| 336 int input_buffer_size_; | |
| 337 int input_port_; | |
| 338 bool input_eos_; | |
| 339 | |
| 340 std::vector<OMX_BUFFERHEADERTYPE*> output_buffers_; | |
| 341 int output_buffer_count_; | |
| 342 int output_buffer_size_; | |
| 343 int output_port_; | |
| 344 bool output_eos_; | |
| 345 | |
| 346 // |state_| records the current state. During state transition | |
| 347 // |next_state_| is the next state that this machine will transition | |
| 348 // to. After a state transition is completed and the state becomes | |
| 349 // stable then |next_state_| equals |state_|. Inequality can be | |
| 350 // used to detect a state transition. | |
| 351 // These two members are read and written only on |message_loop_|. | |
| 352 State state_; | |
| 353 State next_state_; | |
| 354 | |
| 355 OMX_COMPONENTTYPE* component_handle_; | |
| 356 OmxConfigurator* configurator_; | |
| 357 MessageLoop* message_loop_; | |
| 358 | |
| 359 scoped_ptr<FormatCallback> format_callback_; | |
| 360 scoped_ptr<Callback> stop_callback_; | |
| 361 scoped_ptr<Callback> error_callback_; | |
| 362 scoped_ptr<FeedDoneCallback> feed_done_callback_; | |
| 363 scoped_ptr<FillDoneCallback> fill_done_callback_; | |
| 364 | |
| 365 // Input queue for encoded data. | |
| 366 // The input buffers will be sent to OMX component via OMX_EmptyThisBuffer() | |
| 367 std::queue<scoped_refptr<Buffer> > pending_input_queue_; | |
| 368 | |
| 369 // Input queue for encoded data. | |
| 370 // Those buffers have been sent to OMX component, but not returned | |
| 371 // by EmptyBufferDone callback. Once returned from OMX component, they | |
| 372 // will be returned to owner. | |
| 373 std::queue<scoped_refptr<Buffer> > processing_input_queue_; | |
| 374 | |
| 375 // Available input OpenMAX buffers that we can use to issue | |
| 376 // OMX_EmptyThisBuffer() call. | |
| 377 std::queue<OMX_BUFFERHEADERTYPE*> available_input_buffers_; | |
| 378 | |
| 379 // A queue of buffers that carries decoded video frames. They are | |
| 380 // ready to return to client. | |
| 381 // TOOD(hclam): extract it to a separate class. | |
| 382 std::queue<int> output_buffers_ready_; | |
| 383 | |
| 384 private: | |
| 385 DISALLOW_COPY_AND_ASSIGN(OmxCodec); | |
| 386 }; | |
| 387 | |
| 388 } // namespace media | |
| 389 | |
| 390 #endif // MEDIA_OMX_OMX_CODEC_H_ | |
| OLD | NEW |