Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(425)

Side by Side Diff: media/video/omx_video_decode_engine.cc

Issue 7066071: Removing defunct OpenMAX code. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src
Patch Set: removed tab Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/video/omx_video_decode_engine.h ('k') | webkit/support/webkit_support.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 // This class interacts with OmxCodec and the VideoDecoderImpl
6 // in the media pipeline.
7 //
8 // THREADING SEMANTICS
9 //
10 // This class is created by OmxVideoDecoder and lives on the thread
11 // that it lives. This class is given the message loop
12 // for the above thread. The OMX callbacks are guaranteed to be
13 // executed on the hosting message loop. Because of that there's no need
14 // for locking anywhere.
15
16 #include "media/video/omx_video_decode_engine.h"
17
18 #include "base/logging.h"
19 #include "base/message_loop.h"
20 #include "base/string_util.h"
21 #include "media/base/buffers.h"
22 #include "media/base/pipeline.h"
23
24 namespace media {
25
26 OmxVideoDecodeEngine::OmxVideoDecodeEngine()
27 : width_(16),
28 height_(16),
29 message_loop_(NULL),
30 input_buffer_count_(0),
31 input_buffer_size_(0),
32 input_port_(0),
33 input_buffers_at_component_(0),
34 input_pending_request_(0),
35 input_queue_has_eos_(false),
36 input_has_fed_eos_(false),
37 input_port_flushed_(false),
38 output_buffer_count_(0),
39 output_buffer_size_(0),
40 output_port_(0),
41 output_buffers_at_component_(0),
42 output_pending_request_(0),
43 output_eos_(false),
44 output_port_flushed_(false),
45 il_state_(kIlNone),
46 expected_il_state_(kIlNone),
47 client_state_(kClientNotInitialized),
48 component_handle_(NULL),
49 need_free_input_buffers_(false),
50 need_free_output_buffers_(false),
51 flush_pending_(false),
52 output_frames_allocated_(false),
53 need_setup_output_port_(false) {
54 // TODO(wjia): change uses_egl_image_ to runtime setup
55 #if ENABLE_EGLIMAGE == 1
56 uses_egl_image_ = true;
57 DLOG(INFO) << "Uses egl image for output";
58 #else
59 uses_egl_image_ = false;
60 DLOG(INFO) << "Uses system memory for output";
61 #endif
62 }
63
64 OmxVideoDecodeEngine::~OmxVideoDecodeEngine() {
65 DCHECK(client_state_ == kClientNotInitialized ||
66 client_state_ == kClientStopped);
67 DCHECK_EQ(il_state_, kIlNone);
68 DCHECK_EQ(0u, input_buffers_.size());
69 DCHECK(free_input_buffers_.empty());
70 DCHECK(available_input_buffers_.empty());
71 DCHECK_EQ(0, input_buffers_at_component_);
72 DCHECK_EQ(0, output_buffers_at_component_);
73 DCHECK(output_frames_.empty());
74 }
75
76 template <typename T>
77 static void ResetParamHeader(const OmxVideoDecodeEngine& dec, T* param) {
78 memset(param, 0, sizeof(T));
79 param->nVersion.nVersion = dec.current_omx_spec_version();
80 param->nSize = sizeof(T);
81 }
82
83 void OmxVideoDecodeEngine::Initialize(
84 MessageLoop* message_loop,
85 VideoDecodeEngine::EventHandler* event_handler,
86 VideoDecodeContext* context,
87 const VideoDecoderConfig& config) {
88 DCHECK_EQ(message_loop, MessageLoop::current());
89
90 message_loop_ = message_loop;
91 event_handler_ = event_handler;
92
93 width_ = config.width();
94 height_ = config.height();
95
96 // TODO(wjia): Find the right way to determine the codec type.
97 OmxConfigurator::MediaFormat input_format, output_format;
98 memset(&input_format, 0, sizeof(input_format));
99 memset(&output_format, 0, sizeof(output_format));
100 input_format.codec = OmxConfigurator::kCodecH264;
101 output_format.codec = OmxConfigurator::kCodecRaw;
102 configurator_.reset(
103 new OmxDecoderConfigurator(input_format, output_format));
104
105 // TODO(jiesun): We already ensure Initialize() is called in thread context,
106 // We should try to merge the following function into this function.
107 client_state_ = kClientInitializing;
108 InitializeTask();
109
110 VideoCodecInfo info;
111 // TODO(jiesun): ridiculous, we never fail initialization?
112 info.success = true;
113 info.provides_buffers = !uses_egl_image_;
114 info.stream_info.surface_type =
115 uses_egl_image_ ? VideoFrame::TYPE_GL_TEXTURE
116 : VideoFrame::TYPE_SYSTEM_MEMORY;
117 info.stream_info.surface_format = GetSurfaceFormat();
118 info.stream_info.surface_width = config.width();
119 info.stream_info.surface_height = config.height();
120 event_handler_->OnInitializeComplete(info);
121 }
122
123 // This method handles only input buffer, without coupling with output
124 void OmxVideoDecodeEngine::ConsumeVideoSample(scoped_refptr<Buffer> buffer) {
125 DCHECK_EQ(message_loop_, MessageLoop::current());
126 DCHECK(!free_input_buffers_.empty());
127 DCHECK_GT(input_pending_request_, 0);
128
129 --input_pending_request_;
130
131 if (!CanAcceptInput()) {
132 FinishEmptyBuffer(buffer);
133 return;
134 }
135
136 if (buffer->IsEndOfStream()) {
137 DLOG(INFO) << "Input queue has EOS";
138 input_queue_has_eos_ = true;
139 }
140
141 OMX_BUFFERHEADERTYPE* omx_buffer = free_input_buffers_.front();
142 free_input_buffers_.pop();
143
144 // setup |omx_buffer|.
145 omx_buffer->pBuffer = const_cast<OMX_U8*>(buffer->GetData());
146 omx_buffer->nFilledLen = buffer->GetDataSize();
147 omx_buffer->nAllocLen = omx_buffer->nFilledLen;
148 if (input_queue_has_eos_)
149 omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
150 else
151 omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
152 omx_buffer->nTimeStamp = buffer->GetTimestamp().InMicroseconds();
153 omx_buffer->pAppPrivate = buffer.get();
154 buffer->AddRef();
155 available_input_buffers_.push(omx_buffer);
156
157 // Try to feed buffers into the decoder.
158 EmptyBufferTask();
159
160 if (flush_pending_ && input_pending_request_ == 0)
161 StartFlush();
162 }
163
164 void OmxVideoDecodeEngine::Flush() {
165 DCHECK_EQ(message_loop_, MessageLoop::current());
166 DCHECK_EQ(il_state_, kIlExecuting);
167
168 if (il_state_ != kIlExecuting) {
169 event_handler_->OnFlushComplete();
170 return;
171 }
172
173 client_state_ = kClientFlushing;
174 expected_il_state_ = kIlPause;
175 OnStateSetEventFunc = &OmxVideoDecodeEngine::PauseFromExecuting;
176 TransitionToState(OMX_StatePause);
177 }
178
179 void OmxVideoDecodeEngine::PauseFromExecuting(OMX_STATETYPE state) {
180 DCHECK_EQ(message_loop_, MessageLoop::current());
181
182 OnStateSetEventFunc = NULL;
183 il_state_ = kIlPause;
184
185 if (input_pending_request_ == 0)
186 StartFlush();
187 else
188 flush_pending_ = true;
189 }
190
191 void OmxVideoDecodeEngine::StartFlush() {
192 DCHECK_EQ(message_loop_, MessageLoop::current());
193 DCHECK_EQ(input_pending_request_, 0);
194 DLOG(INFO) << "StartFlush";
195
196 while (!available_input_buffers_.empty())
197 available_input_buffers_.pop();
198
199 flush_pending_ = false;
200
201 // Flush input port first.
202 OnFlushEventFunc = &OmxVideoDecodeEngine::PortFlushDone;
203 OMX_ERRORTYPE omxresult;
204 omxresult = OMX_SendCommand(component_handle_,
205 OMX_CommandFlush,
206 input_port_, 0);
207 }
208
209 bool OmxVideoDecodeEngine::InputPortFlushed() {
210 DCHECK_EQ(message_loop_, MessageLoop::current());
211 DCHECK_EQ(client_state_, kClientFlushing);
212 // Port flushed is defined by OpenMAX component had signal flush done and
213 // We had all buffers returned from demuxer and OpenMAX component.
214 int free_input_size = static_cast<int>(free_input_buffers_.size());
215 return input_port_flushed_ && free_input_size == input_buffer_count_;
216 }
217
218 bool OmxVideoDecodeEngine::OutputPortFlushed() {
219 DCHECK_EQ(message_loop_, MessageLoop::current());
220 DCHECK_EQ(client_state_, kClientFlushing);
221 // Port flushed is defined by OpenMAX component had signal flush done and
222 // We had all buffers returned from renderer and OpenMAX component.
223 return output_port_flushed_ && output_pending_request_ == 0;
224 }
225
226 void OmxVideoDecodeEngine::ComponentFlushDone() {
227 DCHECK_EQ(message_loop_, MessageLoop::current());
228 DLOG(INFO) << "Component had been flushed!";
229
230 if (input_port_flushed_ && output_port_flushed_) {
231 event_handler_->OnFlushComplete();
232 input_port_flushed_ = false;
233 output_port_flushed_ = false;
234 }
235 }
236
237 void OmxVideoDecodeEngine::PortFlushDone(int port) {
238 DCHECK_EQ(message_loop_, MessageLoop::current());
239 DCHECK_NE(port, static_cast<int>(OMX_ALL));
240
241 if (port == input_port_) {
242 DLOG(INFO) << "Input Port had been flushed";
243 DCHECK_EQ(input_buffers_at_component_, 0);
244 input_port_flushed_ = true;
245 // Flush output port next.
246 OMX_ERRORTYPE omxresult;
247 omxresult = OMX_SendCommand(component_handle_,
248 OMX_CommandFlush,
249 output_port_, 0);
250 return;
251 }
252
253 if (port == output_port_) {
254 DLOG(INFO) << "Output Port had been flushed";
255 DCHECK_EQ(output_buffers_at_component_, 0);
256
257 output_port_flushed_ = true;
258 }
259
260 if (kClientFlushing == client_state_ &&
261 InputPortFlushed() && OutputPortFlushed())
262 ComponentFlushDone();
263 }
264
265 void OmxVideoDecodeEngine::Seek() {
266 DCHECK_EQ(message_loop_, MessageLoop::current());
267
268 DCHECK(client_state_ == kClientFlushing || // After a flush
269 client_state_ == kClientInitializing); // After an initialize.
270
271 if (client_state_ == kClientFlushing) {
272 InitialReadBuffer();
273 OnStateSetEventFunc = &OmxVideoDecodeEngine::DoneSetStateExecuting;
274 TransitionToState(OMX_StateExecuting);
275 }
276
277 event_handler_->OnSeekComplete();
278 }
279
280 int OmxVideoDecodeEngine::current_omx_spec_version() const {
281 return 0x00000101;
282 }
283
284 VideoFrame::Format OmxVideoDecodeEngine::GetSurfaceFormat() const {
285 // TODO(jiesun): Both OmxHeaderType and EGLImage surface type could have
286 // different surface formats.
287 return uses_egl_image_ ? VideoFrame::RGBA : VideoFrame::YV12;
288 }
289
290 void OmxVideoDecodeEngine::Uninitialize() {
291 DCHECK_EQ(message_loop_, MessageLoop::current());
292
293 if (client_state_ == kClientError) {
294 OnStopDone();
295 return;
296 }
297
298 // TODO(wjia): add more state checking
299 if (kClientRunning == client_state_ || kClientFlushing == client_state_) {
300 client_state_ = kClientStopping;
301 DeinitFromExecuting(OMX_StateExecuting);
302 }
303
304 // TODO(wjia): When FillThisBuffer() is added, engine state should be
305 // kStopping here. engine state should be set to kStopped in OnStopDone();
306 // client_state_ = kClientStopping;
307 }
308
309 void OmxVideoDecodeEngine::FinishEmptyBuffer(scoped_refptr<Buffer> buffer) {
310 DCHECK_EQ(message_loop_, MessageLoop::current());
311
312 if (!input_queue_has_eos_) {
313 event_handler_->ProduceVideoSample(buffer);
314 ++input_pending_request_;
315 }
316 }
317
318 void OmxVideoDecodeEngine::FinishFillBuffer(OMX_BUFFERHEADERTYPE* buffer) {
319 DCHECK_EQ(message_loop_, MessageLoop::current());
320 DCHECK(buffer);
321
322 scoped_refptr<VideoFrame> frame;
323 frame = static_cast<VideoFrame*>(buffer->pAppPrivate);
324
325 // We should not flush buffer to renderer during decoder flushing if decoder
326 // provides the buffer allocator.
327 if (kClientFlushing == client_state_ && !uses_egl_image_) return;
328
329 PipelineStatistics statistics;
330 statistics.video_bytes_decoded = buffer->nFilledLen;
331
332 frame->SetTimestamp(base::TimeDelta::FromMicroseconds(buffer->nTimeStamp));
333 frame->SetDuration(frame->GetTimestamp() - last_pts_);
334 last_pts_ = frame->GetTimestamp();
335 event_handler_->ConsumeVideoFrame(frame, statistics);
336 output_pending_request_--;
337 }
338
339 void OmxVideoDecodeEngine::OnStopDone() {
340 DCHECK_EQ(message_loop_, MessageLoop::current());
341
342 event_handler_->OnUninitializeComplete();
343 }
344
345 // Function sequence for initializing
346 void OmxVideoDecodeEngine::InitializeTask() {
347 DCHECK_EQ(il_state_, kIlNone);
348
349 il_state_ = kIlNone;
350 expected_il_state_ = kIlLoaded;
351 output_port_state_ = kPortEnabled;
352 if (!CreateComponent()) {
353 StopOnError();
354 return;
355 }
356 il_state_ = kIlLoaded;
357
358 // TODO(wjia): Disabling output port is to work around racing condition
359 // due to bug in some vendor's driver. But it hits another bug.
360 // So temporarily fall back to enabling output port. Still keep the code
361 // disabling output port here.
362 // No need to respond to this PortDisable event
363 // OnPortDisableEventFunc = NULL;
364 // ChangePort(OMX_CommandPortDisable, output_port_);
365 // if (kClientError == client_state_) {
366 // StopOnError();
367 // return;
368 // }
369 // output_port_state_ = kPortDisabled;
370
371 // Transition component to Idle state
372 OnStateSetEventFunc = &OmxVideoDecodeEngine::DoneSetStateIdle;
373 if (!TransitionToState(OMX_StateIdle)) {
374 StopOnError();
375 return;
376 }
377 expected_il_state_ = kIlIdle;
378
379 if (!AllocateInputBuffers()) {
380 LOG(ERROR) << "OMX_AllocateBuffer() Input buffer error";
381 client_state_ = kClientError;
382 StopOnError();
383 return;
384 }
385 if (!AllocateOutputBuffers()) {
386 LOG(ERROR) << "OMX_AllocateBuffer() Output buffer error";
387 client_state_ = kClientError;
388 return;
389 }
390 }
391
392 // Sequence of actions in this transition:
393 //
394 // 1. Initialize OMX (To be removed.)
395 // 2. Map role name to component name.
396 // 3. Get handle of the OMX component
397 // 4. Get the port information.
398 // 5. Set role for the component.
399 // 6. Input/output ports media format configuration.
400 // 7. Obtain the information about the input port.
401 // 8. Obtain the information about the output port.
402 bool OmxVideoDecodeEngine::CreateComponent() {
403 DCHECK_EQ(message_loop_, MessageLoop::current());
404
405 static OMX_CALLBACKTYPE callback = {
406 &OmxVideoDecodeEngine::EventHandler,
407 &OmxVideoDecodeEngine::EmptyBufferCallback,
408 &OmxVideoDecodeEngine::FillBufferCallback
409 };
410
411 // 1. Initialize the OpenMAX Core.
412 // TODO(hclam): move this out.
413 OMX_ERRORTYPE omxresult = OMX_Init();
414 if (omxresult != OMX_ErrorNone) {
415 LOG(ERROR) << "Failed to init OpenMAX core";
416 client_state_ = kClientError;
417 return false;
418 }
419
420 // 2. Map role name to component name.
421 std::string role_name = configurator_->GetRoleName();
422 OMX_U32 roles = 0;
423 omxresult = OMX_GetComponentsOfRole(
424 const_cast<OMX_STRING>(role_name.c_str()),
425 &roles, 0);
426 if (omxresult != OMX_ErrorNone || roles == 0) {
427 LOG(ERROR) << "Unsupported Role: " << role_name.c_str();
428 client_state_ = kClientError;
429 return false;
430 }
431 const OMX_U32 kMaxRolePerComponent = 20;
432 CHECK(roles < kMaxRolePerComponent);
433
434 OMX_U8** component_names = new OMX_U8*[roles];
435 const int kMaxComponentNameLength = 256;
436 for (size_t i = 0; i < roles; ++i)
437 component_names[i] = new OMX_U8[kMaxComponentNameLength];
438
439 omxresult = OMX_GetComponentsOfRole(
440 const_cast<OMX_STRING>(role_name.c_str()),
441 &roles, component_names);
442
443 // Use first component only. Copy the name of the first component
444 // so that we could free the memory.
445 std::string component_name;
446 if (omxresult == OMX_ErrorNone)
447 component_name = reinterpret_cast<char*>(component_names[0]);
448
449 for (size_t i = 0; i < roles; ++i)
450 delete [] component_names[i];
451 delete [] component_names;
452
453 if (omxresult != OMX_ErrorNone || roles == 0) {
454 LOG(ERROR) << "Unsupported Role: " << role_name.c_str();
455 client_state_ = kClientError;
456 return false;
457 }
458
459 // 3. Get the handle to the component. After OMX_GetHandle(),
460 // the component is in loaded state.
461 OMX_STRING component = const_cast<OMX_STRING>(component_name.c_str());
462 omxresult = OMX_GetHandle(&component_handle_, component, this, &callback);
463 if (omxresult != OMX_ErrorNone) {
464 LOG(ERROR) << "Failed to Load the component: " << component;
465 client_state_ = kClientError;
466 return false;
467 }
468
469 // 4. Get the port information. This will obtain information about the
470 // number of ports and index of the first port.
471 OMX_PORT_PARAM_TYPE port_param;
472 ResetParamHeader(*this, &port_param);
473 omxresult = OMX_GetParameter(component_handle_, OMX_IndexParamVideoInit,
474 &port_param);
475 if (omxresult != OMX_ErrorNone) {
476 LOG(ERROR) << "Failed to get Port Param";
477 client_state_ = kClientError;
478 return false;
479 }
480 input_port_ = port_param.nStartPortNumber;
481 output_port_ = input_port_ + 1;
482
483 // 5. Set role for the component because our component could
484 // have multiple roles.
485 OMX_PARAM_COMPONENTROLETYPE role_type;
486 ResetParamHeader(*this, &role_type);
487 base::strlcpy(reinterpret_cast<char*>(role_type.cRole),
488 role_name.c_str(),
489 OMX_MAX_STRINGNAME_SIZE);
490 role_type.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
491 omxresult = OMX_SetParameter(component_handle_,
492 OMX_IndexParamStandardComponentRole,
493 &role_type);
494 if (omxresult != OMX_ErrorNone) {
495 LOG(ERROR) << "Failed to Set Role";
496 client_state_ = kClientError;
497 return false;
498 }
499
500 // 6. Input/output ports media format configuration.
501 if (!ConfigureIOPorts()) {
502 LOG(ERROR) << "Media format configurations failed";
503 client_state_ = kClientError;
504 return false;
505 }
506
507 // 7. Obtain the information about the input port.
508 // This will have the new mini buffer count in |port_format.nBufferCountMin|.
509 // Save this value to input_buf_count.
510 OMX_PARAM_PORTDEFINITIONTYPE port_format;
511 ResetParamHeader(*this, &port_format);
512 port_format.nPortIndex = input_port_;
513 omxresult = OMX_GetParameter(component_handle_,
514 OMX_IndexParamPortDefinition,
515 &port_format);
516 if (omxresult != OMX_ErrorNone) {
517 LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
518 client_state_ = kClientError;
519 return false;
520 }
521 if (OMX_DirInput != port_format.eDir) {
522 LOG(ERROR) << "Expected input port";
523 client_state_ = kClientError;
524 return false;
525 }
526 input_buffer_count_ = port_format.nBufferCountActual;
527 input_buffer_size_ = port_format.nBufferSize;
528
529 // 8. Obtain the information about the output port.
530 ResetParamHeader(*this, &port_format);
531 port_format.nPortIndex = output_port_;
532 omxresult = OMX_GetParameter(component_handle_,
533 OMX_IndexParamPortDefinition,
534 &port_format);
535 if (omxresult != OMX_ErrorNone) {
536 LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
537 client_state_ = kClientError;
538 return false;
539 }
540 if (OMX_DirOutput != port_format.eDir) {
541 LOG(ERROR) << "Expect Output Port";
542 client_state_ = kClientError;
543 return false;
544 }
545
546 // TODO(wjia): use same buffer recycling for EGLImage and system memory.
547 // Override buffer count when EGLImage is used.
548 if (uses_egl_image_) {
549 // TODO(wjia): remove hard-coded value
550 port_format.nBufferCountActual = port_format.nBufferCountMin =
551 output_buffer_count_ = 4;
552
553 omxresult = OMX_SetParameter(component_handle_,
554 OMX_IndexParamPortDefinition,
555 &port_format);
556 if (omxresult != OMX_ErrorNone) {
557 LOG(ERROR) << "SetParameter(OMX_IndexParamPortDefinition) failed";
558 client_state_ = kClientError;
559 return false;
560 }
561 } else {
562 output_buffer_count_ = port_format.nBufferCountActual;
563 }
564 output_buffer_size_ = port_format.nBufferSize;
565
566 return true;
567 }
568
569 // Event callback during initialization to handle DoneStateSet to idle
570 void OmxVideoDecodeEngine::DoneSetStateIdle(OMX_STATETYPE state) {
571 DCHECK_EQ(message_loop_, MessageLoop::current());
572 DCHECK_EQ(client_state_, kClientInitializing);
573 DCHECK_EQ(OMX_StateIdle, state);
574 DLOG(INFO) << "OMX video decode engine is in Idle";
575
576 il_state_ = kIlIdle;
577
578 // start reading bit stream
579 InitialReadBuffer();
580 OnStateSetEventFunc = &OmxVideoDecodeEngine::DoneSetStateExecuting;
581 if (!TransitionToState(OMX_StateExecuting)) {
582 StopOnError();
583 return;
584 }
585 expected_il_state_ = kIlExecuting;
586 }
587
588 // Event callback during initialization to handle DoneStateSet to executing
589 void OmxVideoDecodeEngine::DoneSetStateExecuting(OMX_STATETYPE state) {
590 DCHECK_EQ(message_loop_, MessageLoop::current());
591 DCHECK(client_state_ == kClientInitializing ||
592 client_state_ == kClientFlushing);
593 DCHECK_EQ(OMX_StateExecuting, state);
594 DLOG(INFO) << "OMX video decode engine is in Executing";
595
596 il_state_ = kIlExecuting;
597 client_state_ = kClientRunning;
598 OnStateSetEventFunc = NULL;
599 EmptyBufferTask();
600 InitialFillBuffer();
601 if (kClientError == client_state_) {
602 StopOnError();
603 return;
604 }
605 }
606
607 // Function for receiving output buffers. Hookup for buffer recycling
608 // and outside allocator.
609 void OmxVideoDecodeEngine::ProduceVideoFrame(
610 scoped_refptr<VideoFrame> video_frame) {
611 DCHECK(video_frame.get() && !video_frame->IsEndOfStream());
612 output_pending_request_++;
613
614 PipelineStatistics statistics;
615
616 if (!CanAcceptOutput()) {
617 if (uses_egl_image_) { // return it to owner.
618 output_pending_request_--;
619 event_handler_->ConsumeVideoFrame(video_frame, statistics);
620 }
621 return;
622 }
623
624 OMX_BUFFERHEADERTYPE* omx_buffer = FindOmxBuffer(video_frame);
625 if (omx_buffer) {
626 statistics.video_bytes_decoded = omx_buffer->nFilledLen;
627
628 if (kClientRunning == client_state_) {
629 SendOutputBufferToComponent(omx_buffer);
630 } else if (kClientFlushing == client_state_) {
631 if (uses_egl_image_) { // return it to owner.
632 output_pending_request_--;
633 event_handler_->ConsumeVideoFrame(video_frame, statistics);
634 }
635 if (InputPortFlushed() && OutputPortFlushed())
636 ComponentFlushDone();
637 }
638 } else {
639 DCHECK(!output_frames_allocated_);
640 DCHECK(uses_egl_image_);
641 output_frames_.push_back(std::make_pair(video_frame,
642 static_cast<OMX_BUFFERHEADERTYPE*>(NULL)));
643 }
644
645 DCHECK(static_cast<int>(output_frames_.size()) <= output_buffer_count_);
646
647 if ((!output_frames_allocated_) &&
648 static_cast<int>(output_frames_.size()) == output_buffer_count_) {
649 output_frames_allocated_ = true;
650
651 if (need_setup_output_port_) {
652 SetupOutputPort();
653 }
654 }
655
656 if (kClientError == client_state_) {
657 StopOnError();
658 return;
659 }
660 }
661
662 // Reconfigure port
663 void OmxVideoDecodeEngine::OnPortSettingsChangedRun(int port,
664 OMX_INDEXTYPE index) {
665 DCHECK_EQ(message_loop_, MessageLoop::current());
666 DCHECK_EQ(client_state_, kClientRunning);
667 DCHECK_EQ(port, output_port_);
668
669 // TODO(wjia): add buffer negotiation between decoder and renderer.
670 if (uses_egl_image_) {
671 DLOG(INFO) << "Port settings are changed";
672 return;
673 }
674
675 // TODO(wjia): remove this checking when all vendors observe same spec.
676 if (index > OMX_IndexComponentStartUnused) {
677 if (index != OMX_IndexParamPortDefinition)
678 return;
679 }
680
681 OMX_PARAM_PORTDEFINITIONTYPE port_format;
682 ResetParamHeader(*this, &port_format);
683 port_format.nPortIndex = output_port_;
684 OMX_ERRORTYPE omxresult;
685 omxresult = OMX_GetParameter(component_handle_,
686 OMX_IndexParamPortDefinition,
687 &port_format);
688 if (omxresult != OMX_ErrorNone) {
689 LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
690 client_state_ = kClientError;
691 StopOnError();
692 return;
693 }
694 if (OMX_DirOutput != port_format.eDir) {
695 LOG(ERROR) << "Expected Output Port";
696 client_state_ = kClientError;
697 StopOnError();
698 return;
699 }
700
701 // Update the output format.
702 OmxConfigurator::MediaFormat output_format;
703 output_format.video_header.height = port_format.format.video.nFrameHeight;
704 output_format.video_header.width = port_format.format.video.nFrameWidth;
705 output_format.video_header.stride = port_format.format.video.nStride;
706 output_buffer_count_ = port_format.nBufferCountActual;
707 output_buffer_size_ = port_format.nBufferSize;
708
709 if (kPortEnabled == output_port_state_) {
710 output_port_state_ = kPortDisabling;
711 OnPortDisableEventFunc = &OmxVideoDecodeEngine::OnPortDisableEventRun;
712 ChangePort(OMX_CommandPortDisable, output_port_);
713 if (kClientError == client_state_) {
714 StopOnError();
715 return;
716 }
717 FreeOutputBuffers();
718 } else {
719 OnPortDisableEventRun(output_port_);
720 }
721 }
722
723 // Post output port disabling
724 void OmxVideoDecodeEngine::OnPortDisableEventRun(int port) {
725 DCHECK_EQ(message_loop_, MessageLoop::current());
726 DCHECK_EQ(client_state_, kClientRunning);
727 DCHECK_EQ(port, output_port_);
728
729 output_port_state_ = kPortDisabled;
730
731 // make sure all eglimages are available before enabling output port
732 if (output_frames_allocated_ || !uses_egl_image_) {
733 SetupOutputPort();
734 if (kClientError == client_state_) {
735 StopOnError();
736 return;
737 }
738 } else {
739 need_setup_output_port_ = true;
740 }
741 }
742
743 // Enable output port and allocate buffers correspondingly
744 void OmxVideoDecodeEngine::SetupOutputPort() {
745 DCHECK_EQ(message_loop_, MessageLoop::current());
746
747 need_setup_output_port_ = false;
748
749 // Enable output port when necessary since the port could be waiting for
750 // buffers, instead of port reconfiguration.
751 if (kPortEnabled != output_port_state_) {
752 output_port_state_ = kPortEnabling;
753 OnPortEnableEventFunc = &OmxVideoDecodeEngine::OnPortEnableEventRun;
754 ChangePort(OMX_CommandPortEnable, output_port_);
755 if (kClientError == client_state_) {
756 return;
757 }
758 }
759
760 // TODO(wjia): add state checking
761 // Update the ports in buffer if necessary
762 if (!AllocateOutputBuffers()) {
763 LOG(ERROR) << "OMX_AllocateBuffer() Output buffer error";
764 client_state_ = kClientError;
765 return;
766 }
767 }
768
769 // Post output port enabling
770 void OmxVideoDecodeEngine::OnPortEnableEventRun(int port) {
771 DCHECK_EQ(message_loop_, MessageLoop::current());
772 DCHECK_EQ(port, output_port_);
773 DCHECK_EQ(client_state_, kClientRunning);
774
775 output_port_state_ = kPortEnabled;
776 last_pts_ = base::TimeDelta::FromMilliseconds(0);
777 OnPortEnableEventFunc = NULL;
778 InitialFillBuffer();
779 if (kClientError == client_state_) {
780 StopOnError();
781 return;
782 }
783 }
784
785 void OmxVideoDecodeEngine::DeinitFromExecuting(OMX_STATETYPE state) {
786 DCHECK_EQ(state, OMX_StateExecuting);
787
788 DLOG(INFO) << "Deinit from Executing";
789 OnStateSetEventFunc = &OmxVideoDecodeEngine::DeinitFromIdle;
790 TransitionToState(OMX_StateIdle);
791 expected_il_state_ = kIlIdle;
792 }
793
794 void OmxVideoDecodeEngine::DeinitFromIdle(OMX_STATETYPE state) {
795 DCHECK_EQ(message_loop_, MessageLoop::current());
796 DCHECK_EQ(state, OMX_StateIdle);
797
798 DLOG(INFO) << "Deinit from Idle";
799 il_state_ = kIlIdle;
800 OnStateSetEventFunc = &OmxVideoDecodeEngine::DeinitFromLoaded;
801 TransitionToState(OMX_StateLoaded);
802 expected_il_state_ = kIlLoaded;
803
804 if (!input_buffers_at_component_)
805 FreeInputBuffers();
806 else
807 need_free_input_buffers_ = true;
808
809 if (!output_buffers_at_component_)
810 FreeOutputBuffers();
811 else
812 need_free_output_buffers_ = true;
813 }
814
815 void OmxVideoDecodeEngine::DeinitFromLoaded(OMX_STATETYPE state) {
816 DCHECK_EQ(message_loop_, MessageLoop::current());
817 DCHECK_EQ(state, OMX_StateLoaded);
818
819 DLOG(INFO) << "Deinit from Loaded";
820 il_state_ = kIlLoaded;
821 if (component_handle_) {
822 OMX_ERRORTYPE result = OMX_FreeHandle(component_handle_);
823 if (result != OMX_ErrorNone)
824 LOG(ERROR) << "OMX_FreeHandle() error. Error code: " << result;
825 component_handle_ = NULL;
826 }
827 il_state_ = expected_il_state_ = kIlNone;
828
829 // kClientStopped is different from kClientNotInitialized. The former can't
830 // accept output buffers, while the latter can.
831 client_state_ = kClientStopped;
832
833 OMX_Deinit();
834
835 OnStopDone();
836 }
837
838 void OmxVideoDecodeEngine::StopOnError() {
839 DCHECK_EQ(message_loop_, MessageLoop::current());
840
841 client_state_ = kClientStopping;
842
843 if (kIlExecuting == expected_il_state_) {
844 DeinitFromExecuting(OMX_StateExecuting);
845 } else if (kIlIdle == expected_il_state_) {
846 DeinitFromIdle(OMX_StateIdle);
847 } else if (kIlLoaded == expected_il_state_) {
848 DeinitFromLoaded(OMX_StateLoaded);
849 } else if (kIlPause == expected_il_state_) {
850 // TODO(jiesun): Make sure this works.
851 DeinitFromExecuting(OMX_StateExecuting);
852 } else {
853 NOTREACHED();
854 }
855 }
856
857 // Call OMX_UseBuffer() to avoid buffer copying when
858 // OMX_EmptyThisBuffer() is called
859 bool OmxVideoDecodeEngine::AllocateInputBuffers() {
860 DCHECK_EQ(message_loop_, MessageLoop::current());
861
862 uint8* data = new uint8[input_buffer_size_];
863 scoped_array<uint8> data_deleter(data);
864
865 for (int i = 0; i < input_buffer_count_; ++i) {
866 OMX_BUFFERHEADERTYPE* buffer;
867 OMX_ERRORTYPE error =
868 OMX_UseBuffer(component_handle_, &buffer, input_port_,
869 this, input_buffer_size_, data);
870 if (error != OMX_ErrorNone)
871 return false;
872 buffer->nInputPortIndex = input_port_;
873 buffer->nOffset = 0;
874 buffer->nFlags = 0;
875 input_buffers_.push_back(buffer);
876 free_input_buffers_.push(buffer);
877 }
878 return true;
879 }
880
881 // This method handles EGLImage and internal buffer cases. Any external
882 // allocation case is similar to EGLImage
883 bool OmxVideoDecodeEngine::AllocateOutputBuffers() {
884 DCHECK_EQ(message_loop_, MessageLoop::current());
885
886 if (uses_egl_image_ && !output_frames_allocated_) {
887 DLOG(INFO) << "Output frames are not allocated yet";
888 need_setup_output_port_ = true;
889 return true;
890 }
891
892 for (int i = 0; i < output_buffer_count_; ++i) {
893 OMX_BUFFERHEADERTYPE* buffer;
894 scoped_refptr<VideoFrame> video_frame;
895 OMX_ERRORTYPE error;
896 if (uses_egl_image_) {
897 OutputFrame output_frame = output_frames_[i];
898 video_frame = output_frame.first;
899 DCHECK(!output_frame.second);
900 error = OMX_UseEGLImage(component_handle_, &buffer, output_port_,
901 video_frame.get(), video_frame->private_buffer());
902 if (error != OMX_ErrorNone)
903 return false;
904 output_frames_[i].second = buffer;
905 } else {
906 error = OMX_AllocateBuffer(component_handle_, &buffer, output_port_,
907 NULL, output_buffer_size_);
908 if (error != OMX_ErrorNone)
909 return false;
910 video_frame = CreateOmxBufferVideoFrame(buffer);
911 output_frames_.push_back(std::make_pair(video_frame, buffer));
912 buffer->pAppPrivate = video_frame.get();
913 }
914 }
915
916 return true;
917 }
918
919 scoped_refptr<VideoFrame> OmxVideoDecodeEngine::CreateOmxBufferVideoFrame(
920 OMX_BUFFERHEADERTYPE* omx_buffer) {
921 scoped_refptr<VideoFrame> video_frame;
922 uint8* data[VideoFrame::kMaxPlanes];
923 int32 strides[VideoFrame::kMaxPlanes];
924
925 memset(data, 0, sizeof(data));
926 memset(strides, 0, sizeof(strides));
927 // TODO(jiesun): chroma format 4:2:0 only and 3 planes.
928 data[0] = omx_buffer->pBuffer;
929 data[1] = data[0] + width_ * height_;
930 data[2] = data[1] + width_ * height_ / 4;
931 strides[0] = width_;
932 strides[1] = strides[2] = width_ >> 1;
933
934 VideoFrame::CreateFrameExternal(
935 VideoFrame::TYPE_SYSTEM_MEMORY,
936 VideoFrame::YV12,
937 width_, height_, 3,
938 data, strides,
939 kNoTimestamp,
940 kNoTimestamp,
941 omx_buffer,
942 &video_frame);
943
944 return video_frame;
945 }
946
947 void OmxVideoDecodeEngine::FreeInputBuffers() {
948 DCHECK_EQ(message_loop_, MessageLoop::current());
949
950 // Empty available buffer queue.
951 while (!free_input_buffers_.empty()) {
952 free_input_buffers_.pop();
953 }
954
955 while (!available_input_buffers_.empty()) {
956 OMX_BUFFERHEADERTYPE* omx_buffer = available_input_buffers_.front();
957 available_input_buffers_.pop();
958 Buffer* stored_buffer = static_cast<Buffer*>(omx_buffer->pAppPrivate);
959 FinishEmptyBuffer(stored_buffer);
960 stored_buffer->Release();
961 }
962
963 // Calls to OMX to free buffers.
964 for (size_t i = 0; i < input_buffers_.size(); ++i)
965 OMX_FreeBuffer(component_handle_, input_port_, input_buffers_[i]);
966 input_buffers_.clear();
967
968 need_free_input_buffers_ = false;
969 }
970
971 void OmxVideoDecodeEngine::FreeOutputBuffers() {
972 DCHECK_EQ(message_loop_, MessageLoop::current());
973
974 // Calls to OMX to free buffers.
975 for (size_t i = 0; i < output_frames_.size(); ++i) {
976 OMX_BUFFERHEADERTYPE* omx_buffer = output_frames_[i].second;
977 CHECK(omx_buffer);
978 OMX_FreeBuffer(component_handle_, output_port_, omx_buffer);
979 }
980 output_frames_.clear();
981 output_frames_allocated_ = false;
982
983 need_free_output_buffers_ = false;
984 }
985
986 bool OmxVideoDecodeEngine::ConfigureIOPorts() {
987 OMX_PARAM_PORTDEFINITIONTYPE input_port_def, output_port_def;
988 OMX_ERRORTYPE omxresult = OMX_ErrorNone;
989 // Get default input port definition.
990 ResetParamHeader(*this, &input_port_def);
991 input_port_def.nPortIndex = input_port_;
992 omxresult = OMX_GetParameter(component_handle_,
993 OMX_IndexParamPortDefinition,
994 &input_port_def);
995 if (omxresult != OMX_ErrorNone) {
996 LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) "
997 << "for input port failed";
998 return false;
999 }
1000 if (OMX_DirInput != input_port_def.eDir) {
1001 LOG(ERROR) << "Expected Input Port";
1002 return false;
1003 }
1004
1005 // Get default output port definition.
1006 ResetParamHeader(*this, &output_port_def);
1007 output_port_def.nPortIndex = output_port_;
1008 omxresult = OMX_GetParameter(component_handle_,
1009 OMX_IndexParamPortDefinition,
1010 &output_port_def);
1011 if (omxresult != OMX_ErrorNone) {
1012 LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) "
1013 << "for output port failed";
1014 return false;
1015 }
1016 if (OMX_DirOutput != output_port_def.eDir) {
1017 LOG(ERROR) << "Expected Output Port";
1018 return false;
1019 }
1020
1021 return configurator_->ConfigureIOPorts(
1022 static_cast<OMX_COMPONENTTYPE*>(component_handle_),
1023 &input_port_def, &output_port_def);
1024 }
1025
1026 bool OmxVideoDecodeEngine::CanEmptyBuffer() {
1027 // We can call empty buffer while we are in executing and EOS has
1028 // not been sent
1029 return (il_state_ == kIlExecuting &&
1030 !input_has_fed_eos_);
1031 }
1032
1033 bool OmxVideoDecodeEngine::CanFillBuffer() {
1034 // Make sure component is in the executing state and end-of-stream
1035 // has not been reached.
1036 return (il_state_ == kIlExecuting &&
1037 !output_eos_ &&
1038 (output_port_state_ == kPortEnabled ||
1039 output_port_state_ == kPortEnabling));
1040 }
1041
1042 bool OmxVideoDecodeEngine::CanAcceptInput() {
1043 // We can't take input buffer when in error state.
1044 return (kClientError != client_state_ &&
1045 kClientStopping != client_state_ &&
1046 kClientStopped != client_state_ &&
1047 !input_queue_has_eos_);
1048 }
1049
1050 bool OmxVideoDecodeEngine::CanAcceptOutput() {
1051 return (kClientError != client_state_ &&
1052 kClientStopping != client_state_ &&
1053 kClientStopped != client_state_ &&
1054 output_port_state_ == kPortEnabled &&
1055 !output_eos_);
1056 }
1057
1058 // TODO(wjia): There are several things need to be done here:
1059 // 1. Merge this method into EmptyThisBuffer();
1060 // 2. Get rid of the while loop, this is not needed because when we call
1061 // OMX_EmptyThisBuffer we assume we *always* have an input buffer.
1062 void OmxVideoDecodeEngine::EmptyBufferTask() {
1063 DCHECK_EQ(message_loop_, MessageLoop::current());
1064
1065 if (!CanEmptyBuffer())
1066 return;
1067
1068 // Loop for all available input data and input buffer for the
1069 // decoder. When input has reached EOS we need to stop.
1070 while (!available_input_buffers_.empty() &&
1071 !input_has_fed_eos_) {
1072 OMX_BUFFERHEADERTYPE* omx_buffer = available_input_buffers_.front();
1073 available_input_buffers_.pop();
1074
1075 input_has_fed_eos_ = omx_buffer->nFlags & OMX_BUFFERFLAG_EOS;
1076 if (input_has_fed_eos_) {
1077 DLOG(INFO) << "Input has fed EOS";
1078 }
1079
1080 // Give this buffer to OMX.
1081 input_buffers_at_component_++;
1082 OMX_ERRORTYPE ret = OMX_EmptyThisBuffer(component_handle_, omx_buffer);
1083 if (ret != OMX_ErrorNone) {
1084 LOG(ERROR) << "OMX_EmptyThisBuffer() failed with result " << ret;
1085 client_state_ = kClientError;
1086 return;
1087 }
1088 }
1089 }
1090
1091 void OmxVideoDecodeEngine::InitialReadBuffer() {
1092 DCHECK_EQ(message_loop_, MessageLoop::current());
1093
1094 input_queue_has_eos_ = false;
1095 input_has_fed_eos_ = false;
1096 output_eos_ = false;
1097
1098 DLOG(INFO) << "OmxVideoDecodeEngine::InitialReadBuffer";
1099 for (size_t i = 0; i < free_input_buffers_.size(); i++)
1100 FinishEmptyBuffer(NULL);
1101 }
1102
1103 void OmxVideoDecodeEngine::InitialFillBuffer() {
1104 DCHECK_EQ(message_loop_, MessageLoop::current());
1105 // DCHECK(output_frames_allocated_);
1106
1107 if (!CanFillBuffer())
1108 return;
1109
1110 DLOG(INFO) << "OmxVideoDecodeEngine::InitialFillBuffer";
1111
1112 // Ask the decoder to fill the output buffers.
1113 for (uint32 i = 0; i < output_frames_.size(); ++i) {
1114 OMX_BUFFERHEADERTYPE* omx_buffer = output_frames_[i].second;
1115 SendOutputBufferToComponent(omx_buffer);
1116 }
1117 }
1118
1119 // helper functions
1120 // Send command to disable/enable port.
1121 void OmxVideoDecodeEngine::ChangePort(OMX_COMMANDTYPE cmd, int port_index) {
1122 DCHECK_EQ(message_loop_, MessageLoop::current());
1123
1124 OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_,
1125 cmd, port_index, 0);
1126 if (omxresult != OMX_ErrorNone) {
1127 LOG(ERROR) << "SendCommand(OMX_CommandPortDisable) failed";
1128 client_state_ = kClientError;
1129 return;
1130 }
1131 }
1132
1133 // Find if omx_buffer exists corresponding to video_frame
1134 OMX_BUFFERHEADERTYPE* OmxVideoDecodeEngine::FindOmxBuffer(
1135 scoped_refptr<VideoFrame> video_frame) {
1136 for (size_t i = 0; i < output_frames_.size(); ++i) {
1137 if (video_frame == output_frames_[i].first)
1138 return output_frames_[i].second;
1139 }
1140 return NULL;
1141 }
1142
1143 OMX_STATETYPE OmxVideoDecodeEngine::GetComponentState() {
1144 OMX_STATETYPE eState;
1145 OMX_ERRORTYPE eError;
1146
1147 eError = OMX_GetState(component_handle_, &eState);
1148 if (OMX_ErrorNone != eError) {
1149 LOG(ERROR) << "OMX_GetState failed";
1150 StopOnError();
1151 }
1152
1153 return eState;
1154 }
1155
1156 // send one output buffer to component
1157 void OmxVideoDecodeEngine::SendOutputBufferToComponent(
1158 OMX_BUFFERHEADERTYPE *omx_buffer) {
1159 DCHECK_EQ(message_loop_, MessageLoop::current());
1160
1161 if (!CanFillBuffer())
1162 return;
1163
1164 // clear EOS flag.
1165 omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
1166 omx_buffer->nOutputPortIndex = output_port_;
1167 output_buffers_at_component_++;
1168 OMX_ERRORTYPE ret = OMX_FillThisBuffer(component_handle_, omx_buffer);
1169
1170 if (OMX_ErrorNone != ret) {
1171 LOG(ERROR) << "OMX_FillThisBuffer() failed with result " << ret;
1172 client_state_ = kClientError;
1173 return;
1174 }
1175 }
1176
1177 // Send state transition command to component.
1178 bool OmxVideoDecodeEngine::TransitionToState(OMX_STATETYPE new_state) {
1179 DCHECK_EQ(message_loop_, MessageLoop::current());
1180
1181 OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_,
1182 OMX_CommandStateSet,
1183 new_state, 0);
1184 if (omxresult != OMX_ErrorNone) {
1185 LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
1186 client_state_ = kClientError;
1187 return false;
1188 }
1189
1190 return true;
1191 }
1192
1193 void OmxVideoDecodeEngine::EmptyBufferDoneTask(OMX_BUFFERHEADERTYPE* buffer) {
1194 DCHECK_EQ(message_loop_, MessageLoop::current());
1195 DCHECK_GT(input_buffers_at_component_, 0);
1196
1197 Buffer* stored_buffer = static_cast<Buffer*>(buffer->pAppPrivate);
1198 buffer->pAppPrivate = NULL;
1199 if (client_state_ != kClientFlushing)
1200 FinishEmptyBuffer(stored_buffer);
1201 stored_buffer->Release();
1202
1203 // Enqueue the available buffer because the decoder has consumed it.
1204 free_input_buffers_.push(buffer);
1205 input_buffers_at_component_--;
1206
1207 if (need_free_input_buffers_ && !input_buffers_at_component_) {
1208 FreeInputBuffers();
1209 return;
1210 }
1211
1212 // Try to feed more data into the decoder.
1213 EmptyBufferTask();
1214
1215 if (client_state_ == kClientFlushing &&
1216 InputPortFlushed() && OutputPortFlushed())
1217 ComponentFlushDone();
1218 }
1219
1220 void OmxVideoDecodeEngine::FillBufferDoneTask(OMX_BUFFERHEADERTYPE* buffer) {
1221 DCHECK_EQ(message_loop_, MessageLoop::current());
1222 DCHECK_GT(output_buffers_at_component_, 0);
1223
1224 output_buffers_at_component_--;
1225
1226 if (need_free_output_buffers_ && !output_buffers_at_component_) {
1227 FreeOutputBuffers();
1228 return;
1229 }
1230
1231 PipelineStatistics statistics;
1232 statistics.video_bytes_decoded = buffer->nFilledLen;
1233
1234 if (!CanAcceptOutput()) {
1235 if (uses_egl_image_) {
1236 scoped_refptr<VideoFrame> frame;
1237 frame = static_cast<VideoFrame*>(buffer->pAppPrivate);
1238 event_handler_->ConsumeVideoFrame(frame, statistics);
1239 output_pending_request_--;
1240 }
1241 return;
1242 }
1243
1244 // This buffer is received with decoded frame. Enqueue it and make it
1245 // ready to be consumed by reads.
1246
1247 if (buffer->nFlags & OMX_BUFFERFLAG_EOS) {
1248 output_eos_ = true;
1249 DLOG(INFO) << "Output has EOS";
1250 }
1251
1252 FinishFillBuffer(buffer);
1253
1254 if (buffer->nFlags & OMX_BUFFERFLAG_EOS) {
1255 // Singal end of stream.
1256 scoped_refptr<VideoFrame> frame;
1257 VideoFrame::CreateEmptyFrame(&frame);
1258 event_handler_->ConsumeVideoFrame(frame, statistics);
1259 }
1260
1261 if (client_state_ == kClientFlushing &&
1262 InputPortFlushed() && OutputPortFlushed())
1263 ComponentFlushDone();
1264 }
1265
1266 void OmxVideoDecodeEngine::EventHandlerCompleteTask(OMX_EVENTTYPE event,
1267 OMX_U32 data1,
1268 OMX_U32 data2) {
1269 switch (event) {
1270 case OMX_EventCmdComplete: {
1271 // If the last command was successful, we have completed
1272 // a state transition. So notify that we have done it
1273 // accordingly.
1274 OMX_COMMANDTYPE cmd = static_cast<OMX_COMMANDTYPE>(data1);
1275 if (cmd == OMX_CommandPortDisable) {
1276 if (OnPortDisableEventFunc)
1277 (this->*OnPortDisableEventFunc)(static_cast<int>(data2));
1278 } else if (cmd == OMX_CommandPortEnable) {
1279 if (OnPortEnableEventFunc)
1280 (this->*OnPortEnableEventFunc)(static_cast<int>(data2));
1281 } else if (cmd == OMX_CommandStateSet) {
1282 (this->*OnStateSetEventFunc)(static_cast<OMX_STATETYPE>(data2));
1283 } else if (cmd == OMX_CommandFlush) {
1284 (this->*OnFlushEventFunc)(data2);
1285 } else {
1286 LOG(ERROR) << "Unknown command completed\n" << data1;
1287 }
1288 break;
1289 }
1290 case OMX_EventError:
1291 if (OMX_ErrorInvalidState == (OMX_ERRORTYPE)data1) {
1292 // TODO(hclam): what to do here?
1293 }
1294 StopOnError();
1295 break;
1296 case OMX_EventPortSettingsChanged:
1297 // TODO(wjia): remove this hack when all vendors observe same spec.
1298 if (data1 < OMX_IndexComponentStartUnused)
1299 OnPortSettingsChangedRun(static_cast<int>(data1),
1300 static_cast<OMX_INDEXTYPE>(data2));
1301 else
1302 OnPortSettingsChangedRun(static_cast<int>(data2),
1303 static_cast<OMX_INDEXTYPE>(data1));
1304 break;
1305 default:
1306 LOG(ERROR) << "Warning - Unknown event received\n";
1307 break;
1308 }
1309 }
1310
1311 // static
1312 OMX_ERRORTYPE OmxVideoDecodeEngine::EventHandler(OMX_HANDLETYPE component,
1313 OMX_PTR priv_data,
1314 OMX_EVENTTYPE event,
1315 OMX_U32 data1,
1316 OMX_U32 data2,
1317 OMX_PTR event_data) {
1318 OmxVideoDecodeEngine* decoder = static_cast<OmxVideoDecodeEngine*>(priv_data);
1319 DCHECK_EQ(component, decoder->component_handle_);
1320 decoder->message_loop_->PostTask(FROM_HERE,
1321 NewRunnableMethod(decoder,
1322 &OmxVideoDecodeEngine::EventHandlerCompleteTask,
1323 event, data1, data2));
1324 return OMX_ErrorNone;
1325 }
1326
1327 // static
1328 OMX_ERRORTYPE OmxVideoDecodeEngine::EmptyBufferCallback(
1329 OMX_HANDLETYPE component,
1330 OMX_PTR priv_data,
1331 OMX_BUFFERHEADERTYPE* buffer) {
1332 OmxVideoDecodeEngine* decoder = static_cast<OmxVideoDecodeEngine*>(priv_data);
1333 DCHECK_EQ(component, decoder->component_handle_);
1334 decoder->message_loop_->PostTask(FROM_HERE,
1335 NewRunnableMethod(decoder,
1336 &OmxVideoDecodeEngine::EmptyBufferDoneTask, buffer));
1337 return OMX_ErrorNone;
1338 }
1339
1340 // static
1341 OMX_ERRORTYPE OmxVideoDecodeEngine::FillBufferCallback(
1342 OMX_HANDLETYPE component,
1343 OMX_PTR priv_data,
1344 OMX_BUFFERHEADERTYPE* buffer) {
1345 OmxVideoDecodeEngine* decoder = static_cast<OmxVideoDecodeEngine*>(priv_data);
1346 DCHECK_EQ(component, decoder->component_handle_);
1347 decoder->message_loop_->PostTask(FROM_HERE,
1348 NewRunnableMethod(decoder,
1349 &OmxVideoDecodeEngine::FillBufferDoneTask, buffer));
1350 return OMX_ErrorNone;
1351 }
1352
1353 } // namespace media
1354
1355 // Disable refcounting for this object because this object only lives
1356 // on the video decoder thread and there's no need to refcount it.
1357 DISABLE_RUNNABLE_METHOD_REFCOUNT(media::OmxVideoDecodeEngine);
OLDNEW
« no previous file with comments | « media/video/omx_video_decode_engine.h ('k') | webkit/support/webkit_support.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698