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 |