blob: 738ae33ac9c98f131704575d763e6d0d23b3b832 [file] [log] [blame]
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "starboard/raspi/shared/open_max/open_max_component_base.h"
#include <algorithm>
#include "starboard/configuration.h"
#include "starboard/once.h"
namespace starboard {
namespace raspi {
namespace shared {
namespace open_max {
namespace {
const int kInvalidPort = -1;
const OMX_INDEXTYPE kPortTypes[] = {
OMX_IndexParamAudioInit, OMX_IndexParamVideoInit, OMX_IndexParamImageInit,
OMX_IndexParamOtherInit};
SbOnceControl s_open_max_initialization_once = SB_ONCE_INITIALIZER;
void DoInitializeOpenMax() {
OMX_ERRORTYPE error = OMX_Init();
SB_DCHECK(error == OMX_ErrorNone);
}
void InitializeOpenMax() {
bool initialized =
SbOnce(&s_open_max_initialization_once, DoInitializeOpenMax);
SB_DCHECK(initialized);
}
} // namespace
OpenMaxComponentBase::OpenMaxComponentBase(const char* name)
: event_condition_variable_(mutex_),
handle_(NULL),
input_port_(kInvalidPort),
output_port_(kInvalidPort) {
InitializeOpenMax();
OMX_CALLBACKTYPE callbacks;
callbacks.EventHandler = OpenMaxComponentBase::EventHandler;
callbacks.EmptyBufferDone = OpenMaxComponentBase::EmptyBufferDone;
callbacks.FillBufferDone = OpenMaxComponentBase::FillBufferDone;
OMX_ERRORTYPE error =
OMX_GetHandle(&handle_, const_cast<char*>(name), this, &callbacks);
SB_DCHECK(error == OMX_ErrorNone);
for (size_t i = 0; i < SB_ARRAY_SIZE(kPortTypes); ++i) {
OMX_PORT_PARAM_TYPE port;
port.nSize = sizeof(OMX_PORT_PARAM_TYPE);
port.nVersion.nVersion = OMX_VERSION;
error = OMX_GetParameter(handle_, kPortTypes[i], &port);
if (error == OMX_ErrorNone && port.nPorts == 2) {
input_port_ = port.nStartPortNumber;
output_port_ = input_port_ + 1;
SendCommandAndWaitForCompletion(OMX_CommandPortDisable, input_port_);
SendCommandAndWaitForCompletion(OMX_CommandPortDisable, output_port_);
break;
}
}
SB_CHECK(input_port_ != kInvalidPort);
SB_CHECK(output_port_ != kInvalidPort);
SB_DLOG(INFO) << "Opened \"" << name << "\" with port " << input_port_
<< " and " << output_port_;
}
OpenMaxComponentBase::~OpenMaxComponentBase() {
if (!handle_) {
return;
}
OMX_FreeHandle(handle_);
}
void OpenMaxComponentBase::SendCommand(OMX_COMMANDTYPE command, int param) {
OMX_ERRORTYPE error = OMX_SendCommand(handle_, command, param, NULL);
SB_DCHECK(error == OMX_ErrorNone);
}
void OpenMaxComponentBase::WaitForCommandCompletion() {
for (;;) {
ScopedLock scoped_lock(mutex_);
for (EventDescriptions::iterator iter = event_descriptions_.begin();
iter != event_descriptions_.end(); ++iter) {
if (iter->event == OMX_EventCmdComplete) {
event_descriptions_.erase(iter);
return;
}
// Special case for OMX_CommandStateSet.
if (iter->event == OMX_EventError && iter->data1 == OMX_ErrorSameState) {
event_descriptions_.erase(iter);
return;
}
}
event_condition_variable_.Wait();
}
}
void OpenMaxComponentBase::SendCommandAndWaitForCompletion(
OMX_COMMANDTYPE command,
int param) {
SendCommand(command, param);
WaitForCommandCompletion();
}
OMX_ERRORTYPE OpenMaxComponentBase::OnEvent(OMX_EVENTTYPE event,
OMX_U32 data1,
OMX_U32 data2,
OMX_PTR event_data) {
if (event == OMX_EventError && data1 != OMX_ErrorSameState) {
OnErrorEvent(data1, data2, event_data);
return OMX_ErrorNone;
}
if (event == OMX_EventPortSettingsChanged && data1 == output_port_) {
OnOutputSettingChanged();
return OMX_ErrorNone;
}
ScopedLock scoped_lock(mutex_);
EventDescription event_desc;
event_desc.event = event;
event_desc.data1 = data1;
event_desc.data2 = data2;
event_desc.event_data = event_data;
event_descriptions_.push_back(event_desc);
event_condition_variable_.Signal();
return OMX_ErrorNone;
}
// static
OMX_ERRORTYPE OpenMaxComponentBase::EventHandler(OMX_HANDLETYPE handle,
OMX_PTR app_data,
OMX_EVENTTYPE event,
OMX_U32 data1,
OMX_U32 data2,
OMX_PTR event_data) {
SB_DCHECK(app_data != NULL);
OpenMaxComponentBase* component =
reinterpret_cast<OpenMaxComponentBase*>(app_data);
SB_DCHECK(handle == component->handle_);
return component->OnEvent(event, data1, data2, event_data);
}
// static
OMX_ERRORTYPE OpenMaxComponentBase::EmptyBufferDone(
OMX_HANDLETYPE handle,
OMX_PTR app_data,
OMX_BUFFERHEADERTYPE* buffer) {
SB_DCHECK(app_data != NULL);
OpenMaxComponentBase* component =
reinterpret_cast<OpenMaxComponentBase*>(app_data);
SB_DCHECK(handle == component->handle_);
return component->OnEmptyBufferDone(buffer);
}
// static
OMX_ERRORTYPE OpenMaxComponentBase::FillBufferDone(
OMX_HANDLETYPE handle,
OMX_PTR app_data,
OMX_BUFFERHEADERTYPE* buffer) {
SB_DCHECK(app_data != NULL);
OpenMaxComponentBase* component =
reinterpret_cast<OpenMaxComponentBase*>(app_data);
SB_DCHECK(handle == component->handle_);
component->OnFillBufferDone(buffer);
return OMX_ErrorNone;
}
} // namespace open_max
} // namespace shared
} // namespace raspi
} // namespace starboard