405 lines
13 KiB
C++
405 lines
13 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "OmxDataDecoder.h"
|
|
#include "OmxPromiseLayer.h"
|
|
#include "PureOmxPlatformLayer.h"
|
|
#include "OmxCoreLibLinker.h"
|
|
|
|
#ifdef LOG
|
|
# undef LOG
|
|
#endif
|
|
|
|
#define LOG(arg, ...) \
|
|
MOZ_LOG( \
|
|
sPDMLog, mozilla::LogLevel::Debug, \
|
|
("PureOmxPlatformLayer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
|
#define LOG_BUF(arg, ...) \
|
|
MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, \
|
|
("PureOmxBufferData(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
|
|
|
namespace mozilla {
|
|
|
|
#define OMX_FUNC(func) extern typeof(func)* func;
|
|
#include "OmxFunctionList.h"
|
|
#undef OMX_FUNC
|
|
|
|
PureOmxBufferData::PureOmxBufferData(
|
|
const PureOmxPlatformLayer& aPlatformLayer,
|
|
const OMX_PARAM_PORTDEFINITIONTYPE& aPortDef)
|
|
: BufferData(nullptr), mPlatformLayer(aPlatformLayer), mPortDef(aPortDef) {
|
|
LOG_BUF("");
|
|
|
|
if (ShouldUseEGLImage()) {
|
|
// TODO
|
|
LOG_BUF(
|
|
"OMX_UseEGLImage() seems available but using it isn't implemented "
|
|
"yet.");
|
|
}
|
|
|
|
OMX_ERRORTYPE err;
|
|
err = OMX_AllocateBuffer(mPlatformLayer.GetComponent(), &mBuffer,
|
|
mPortDef.nPortIndex, this, mPortDef.nBufferSize);
|
|
if (err != OMX_ErrorNone) {
|
|
LOG_BUF("Failed to allocate the buffer!: 0x%08x", err);
|
|
}
|
|
}
|
|
|
|
PureOmxBufferData::~PureOmxBufferData() {
|
|
LOG_BUF("");
|
|
ReleaseBuffer();
|
|
}
|
|
|
|
void PureOmxBufferData::ReleaseBuffer() {
|
|
LOG_BUF("");
|
|
|
|
if (mBuffer) {
|
|
OMX_ERRORTYPE err;
|
|
err = OMX_FreeBuffer(mPlatformLayer.GetComponent(), mPortDef.nPortIndex,
|
|
mBuffer);
|
|
if (err != OMX_ErrorNone) {
|
|
LOG_BUF("Failed to free the buffer!: 0x%08x", err);
|
|
}
|
|
mBuffer = nullptr;
|
|
}
|
|
}
|
|
|
|
bool PureOmxBufferData::ShouldUseEGLImage() {
|
|
OMX_ERRORTYPE err;
|
|
err = OMX_UseEGLImage(mPlatformLayer.GetComponent(), nullptr,
|
|
mPortDef.nPortIndex, nullptr, nullptr);
|
|
return (err != OMX_ErrorNotImplemented);
|
|
}
|
|
|
|
/* static */
|
|
bool PureOmxPlatformLayer::Init(void) {
|
|
if (!OmxCoreLibLinker::Link()) {
|
|
return false;
|
|
}
|
|
|
|
OMX_ERRORTYPE err = OMX_Init();
|
|
if (err != OMX_ErrorNone) {
|
|
MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug,
|
|
("PureOmxPlatformLayer::%s: Failed to initialize OMXCore: 0x%08x",
|
|
__func__, err));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* static */
|
|
OMX_CALLBACKTYPE PureOmxPlatformLayer::sCallbacks = {
|
|
EventHandler, EmptyBufferDone, FillBufferDone};
|
|
|
|
PureOmxPlatformLayer::PureOmxPlatformLayer(
|
|
OmxDataDecoder* aDataDecoder, OmxPromiseLayer* aPromiseLayer,
|
|
TaskQueue* aTaskQueue, layers::ImageContainer* aImageContainer)
|
|
: mComponent(nullptr),
|
|
mDataDecoder(aDataDecoder),
|
|
mPromiseLayer(aPromiseLayer),
|
|
mTaskQueue(aTaskQueue),
|
|
mImageContainer(aImageContainer) {
|
|
LOG("");
|
|
}
|
|
|
|
PureOmxPlatformLayer::~PureOmxPlatformLayer() { LOG(""); }
|
|
|
|
OMX_ERRORTYPE
|
|
PureOmxPlatformLayer::InitOmxToStateLoaded(const TrackInfo* aInfo) {
|
|
LOG("");
|
|
|
|
if (!aInfo) {
|
|
return OMX_ErrorUndefined;
|
|
}
|
|
mInfo = aInfo;
|
|
|
|
return CreateComponent();
|
|
}
|
|
|
|
OMX_ERRORTYPE
|
|
PureOmxPlatformLayer::EmptyThisBuffer(BufferData* aData) {
|
|
LOG("");
|
|
return OMX_EmptyThisBuffer(mComponent, aData->mBuffer);
|
|
}
|
|
|
|
OMX_ERRORTYPE
|
|
PureOmxPlatformLayer::FillThisBuffer(BufferData* aData) {
|
|
LOG("");
|
|
return OMX_FillThisBuffer(mComponent, aData->mBuffer);
|
|
}
|
|
|
|
OMX_ERRORTYPE
|
|
PureOmxPlatformLayer::SendCommand(OMX_COMMANDTYPE aCmd, OMX_U32 aParam1,
|
|
OMX_PTR aCmdData) {
|
|
LOG("aCmd: 0x%08x", aCmd);
|
|
if (!mComponent) {
|
|
return OMX_ErrorUndefined;
|
|
}
|
|
return OMX_SendCommand(mComponent, aCmd, aParam1, aCmdData);
|
|
}
|
|
|
|
nsresult PureOmxPlatformLayer::FindPortDefinition(
|
|
OMX_DIRTYPE aType, OMX_PARAM_PORTDEFINITIONTYPE& portDef) {
|
|
nsTArray<uint32_t> portIndex;
|
|
GetPortIndices(portIndex);
|
|
for (auto idx : portIndex) {
|
|
InitOmxParameter(&portDef);
|
|
portDef.nPortIndex = idx;
|
|
|
|
OMX_ERRORTYPE err;
|
|
err = GetParameter(OMX_IndexParamPortDefinition, &portDef,
|
|
sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
|
|
if (err != OMX_ErrorNone) {
|
|
return NS_ERROR_FAILURE;
|
|
} else if (portDef.eDir == aType) {
|
|
LOG("Found OMX_IndexParamPortDefinition: port: %d, type: %d",
|
|
portDef.nPortIndex, portDef.eDir);
|
|
return NS_OK;
|
|
}
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsresult PureOmxPlatformLayer::AllocateOmxBuffer(OMX_DIRTYPE aType,
|
|
BUFFERLIST* aBufferList) {
|
|
LOG("aType: %d", aType);
|
|
|
|
OMX_PARAM_PORTDEFINITIONTYPE portDef;
|
|
nsresult result = FindPortDefinition(aType, portDef);
|
|
if (result != NS_OK) {
|
|
return result;
|
|
}
|
|
|
|
LOG("nBufferCountActual: %d, nBufferSize: %d", portDef.nBufferCountActual,
|
|
portDef.nBufferSize);
|
|
|
|
for (OMX_U32 i = 0; i < portDef.nBufferCountActual; ++i) {
|
|
RefPtr<PureOmxBufferData> buffer = new PureOmxBufferData(*this, portDef);
|
|
aBufferList->AppendElement(buffer);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult PureOmxPlatformLayer::ReleaseOmxBuffer(OMX_DIRTYPE aType,
|
|
BUFFERLIST* aBufferList) {
|
|
LOG("aType: 0x%08x", aType);
|
|
|
|
uint32_t len = aBufferList->Length();
|
|
for (uint32_t i = 0; i < len; i++) {
|
|
PureOmxBufferData* buffer =
|
|
static_cast<PureOmxBufferData*>(aBufferList->ElementAt(i).get());
|
|
|
|
// All raw OpenMAX buffers have to be released here to flush
|
|
// OMX_CommandStateSet for switching the state to OMX_StateLoaded.
|
|
// See OmxDataDecoder::DoAsyncShutdown() for more detail.
|
|
buffer->ReleaseBuffer();
|
|
}
|
|
aBufferList->Clear();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
OMX_ERRORTYPE
|
|
PureOmxPlatformLayer::GetState(OMX_STATETYPE* aType) {
|
|
LOG("");
|
|
|
|
if (mComponent) {
|
|
return OMX_GetState(mComponent, aType);
|
|
}
|
|
|
|
return OMX_ErrorUndefined;
|
|
}
|
|
|
|
OMX_ERRORTYPE
|
|
PureOmxPlatformLayer::GetParameter(OMX_INDEXTYPE aParamIndex,
|
|
OMX_PTR aComponentParameterStructure,
|
|
OMX_U32 aComponentParameterSize) {
|
|
LOG("aParamIndex: 0x%08x", aParamIndex);
|
|
|
|
if (!mComponent) {
|
|
return OMX_ErrorUndefined;
|
|
}
|
|
|
|
return OMX_GetParameter(mComponent, aParamIndex,
|
|
aComponentParameterStructure);
|
|
}
|
|
|
|
OMX_ERRORTYPE
|
|
PureOmxPlatformLayer::SetParameter(OMX_INDEXTYPE aParamIndex,
|
|
OMX_PTR aComponentParameterStructure,
|
|
OMX_U32 aComponentParameterSize) {
|
|
LOG("aParamIndex: 0x%08x", aParamIndex);
|
|
|
|
if (!mComponent) {
|
|
return OMX_ErrorUndefined;
|
|
}
|
|
|
|
return OMX_SetParameter(mComponent, aParamIndex,
|
|
aComponentParameterStructure);
|
|
}
|
|
|
|
nsresult PureOmxPlatformLayer::Shutdown() {
|
|
LOG("");
|
|
if (mComponent) {
|
|
OMX_FreeHandle(mComponent);
|
|
mComponent = nullptr;
|
|
}
|
|
mPromiseLayer = nullptr;
|
|
mDataDecoder = nullptr;
|
|
return NS_OK;
|
|
}
|
|
|
|
/* static */
|
|
OMX_ERRORTYPE PureOmxPlatformLayer::EventHandler(OMX_HANDLETYPE hComponent,
|
|
OMX_PTR pAppData,
|
|
OMX_EVENTTYPE eEventType,
|
|
OMX_U32 nData1, OMX_U32 nData2,
|
|
OMX_PTR pEventData) {
|
|
PureOmxPlatformLayer* self = static_cast<PureOmxPlatformLayer*>(pAppData);
|
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
|
"mozilla::PureOmxPlatformLayer::EventHandler",
|
|
[self, eEventType, nData1, nData2, pEventData]() {
|
|
self->EventHandler(eEventType, nData1, nData2, pEventData);
|
|
});
|
|
nsresult rv = self->mTaskQueue->Dispatch(r.forget());
|
|
return NS_SUCCEEDED(rv) ? OMX_ErrorNone : OMX_ErrorUndefined;
|
|
}
|
|
|
|
/* static */
|
|
OMX_ERRORTYPE PureOmxPlatformLayer::EmptyBufferDone(
|
|
OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData,
|
|
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
|
|
PureOmxPlatformLayer* self = static_cast<PureOmxPlatformLayer*>(pAppData);
|
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
|
"mozilla::PureOmxPlatformLayer::EmptyBufferDone",
|
|
[self, pBuffer]() { self->EmptyBufferDone(pBuffer); });
|
|
nsresult rv = self->mTaskQueue->Dispatch(r.forget());
|
|
return NS_SUCCEEDED(rv) ? OMX_ErrorNone : OMX_ErrorUndefined;
|
|
}
|
|
|
|
/* static */
|
|
OMX_ERRORTYPE PureOmxPlatformLayer::FillBufferDone(
|
|
OMX_OUT OMX_HANDLETYPE hComponent, OMX_OUT OMX_PTR pAppData,
|
|
OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) {
|
|
PureOmxPlatformLayer* self = static_cast<PureOmxPlatformLayer*>(pAppData);
|
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
|
"mozilla::PureOmxPlatformLayer::FillBufferDone",
|
|
[self, pBuffer]() { self->FillBufferDone(pBuffer); });
|
|
nsresult rv = self->mTaskQueue->Dispatch(r.forget());
|
|
return NS_SUCCEEDED(rv) ? OMX_ErrorNone : OMX_ErrorUndefined;
|
|
}
|
|
|
|
OMX_ERRORTYPE
|
|
PureOmxPlatformLayer::EventHandler(OMX_EVENTTYPE eEventType, OMX_U32 nData1,
|
|
OMX_U32 nData2, OMX_PTR pEventData) {
|
|
bool handled = mPromiseLayer->Event(eEventType, nData1, nData2);
|
|
LOG("eEventType: 0x%08x, handled: %d", eEventType, handled);
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
OMX_ERRORTYPE
|
|
PureOmxPlatformLayer::EmptyBufferDone(OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
|
|
PureOmxBufferData* buffer =
|
|
static_cast<PureOmxBufferData*>(pBuffer->pAppPrivate);
|
|
OMX_DIRTYPE portDirection = buffer->GetPortDirection();
|
|
LOG("PortDirection: %d", portDirection);
|
|
mPromiseLayer->EmptyFillBufferDone(portDirection, buffer);
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
OMX_ERRORTYPE
|
|
PureOmxPlatformLayer::FillBufferDone(OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) {
|
|
PureOmxBufferData* buffer =
|
|
static_cast<PureOmxBufferData*>(pBuffer->pAppPrivate);
|
|
OMX_DIRTYPE portDirection = buffer->GetPortDirection();
|
|
LOG("PortDirection: %d", portDirection);
|
|
mPromiseLayer->EmptyFillBufferDone(portDirection, buffer);
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
bool PureOmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType) {
|
|
return FindStandardComponent(aMimeType, nullptr);
|
|
}
|
|
|
|
static bool GetStandardComponentRole(const nsACString& aMimeType,
|
|
nsACString& aRole) {
|
|
if (aMimeType.EqualsLiteral("video/avc") ||
|
|
aMimeType.EqualsLiteral("video/mp4") ||
|
|
aMimeType.EqualsLiteral("video/mp4v-es")) {
|
|
aRole.Assign("video_decoder.avc");
|
|
return true;
|
|
} else if (aMimeType.EqualsLiteral("audio/mp4a-latm") ||
|
|
aMimeType.EqualsLiteral("audio/mp4") ||
|
|
aMimeType.EqualsLiteral("audio/aac")) {
|
|
aRole.Assign("audio_decoder.aac");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* static */
|
|
bool PureOmxPlatformLayer::FindStandardComponent(const nsACString& aMimeType,
|
|
nsACString* aComponentName) {
|
|
nsAutoCString role;
|
|
if (!GetStandardComponentRole(aMimeType, role)) return false;
|
|
|
|
OMX_U32 nComponents = 0;
|
|
OMX_ERRORTYPE err;
|
|
err = OMX_GetComponentsOfRole(const_cast<OMX_STRING>(role.Data()),
|
|
&nComponents, nullptr);
|
|
if (err != OMX_ErrorNone || nComponents <= 0) {
|
|
return false;
|
|
}
|
|
if (!aComponentName) {
|
|
return true;
|
|
}
|
|
|
|
// TODO:
|
|
// Only the first component will be used.
|
|
// We should detect the most preferred component.
|
|
OMX_U8* componentNames[1];
|
|
UniquePtr<OMX_U8[]> componentName;
|
|
componentName = MakeUniqueFallible<OMX_U8[]>(OMX_MAX_STRINGNAME_SIZE);
|
|
componentNames[0] = componentName.get();
|
|
nComponents = 1;
|
|
err = OMX_GetComponentsOfRole(const_cast<OMX_STRING>(role.Data()),
|
|
&nComponents, componentNames);
|
|
if (err == OMX_ErrorNone) {
|
|
MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug,
|
|
("PureOmxPlatformLayer::%s: A component has been found for %s: %s",
|
|
__func__, aMimeType.Data(), componentNames[0]));
|
|
aComponentName->Assign(reinterpret_cast<char*>(componentNames[0]));
|
|
}
|
|
|
|
return err == OMX_ErrorNone;
|
|
}
|
|
|
|
OMX_ERRORTYPE
|
|
PureOmxPlatformLayer::CreateComponent(const nsACString* aComponentName) {
|
|
nsAutoCString componentName;
|
|
if (aComponentName) {
|
|
componentName = *aComponentName;
|
|
} else if (!FindStandardComponent(mInfo->mMimeType, &componentName)) {
|
|
return OMX_ErrorComponentNotFound;
|
|
}
|
|
|
|
OMX_ERRORTYPE err;
|
|
err = OMX_GetHandle(&mComponent, const_cast<OMX_STRING>(componentName.Data()),
|
|
this, &sCallbacks);
|
|
|
|
const char* mime = mInfo->mMimeType.Data();
|
|
if (err == OMX_ErrorNone) {
|
|
LOG("Succeeded to create the component for %s", mime);
|
|
} else {
|
|
LOG("Failed to create the component for %s: 0x%08x", mime, err);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
} // namespace mozilla
|