Merge "Suppress unused paramter warnings in omx hal 1.0"
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index a98a207..ad70470 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -10,8 +10,9 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia libutils libbinder libstagefright_foundation \
libjpeg libgui libcutils liblog \
+ libhidlmemory \
android.hardware.media.omx@1.0 \
- android.hardware.media.omx@1.0-utils
+ android.hardware.media.omx@1.0-utils \
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
diff --git a/drm/libmediadrm/Android.mk b/drm/libmediadrm/Android.mk
index 8e3cc40..7176582 100644
--- a/drm/libmediadrm/Android.mk
+++ b/drm/libmediadrm/Android.mk
@@ -6,12 +6,24 @@
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
+LOCAL_AIDL_INCLUDES := \
+ frameworks/base/media/java
+
+LOCAL_SRC_FILES := \
+ ../../../base/media/java/android/media/ICas.aidl \
+ ../../../base/media/java/android/media/ICasListener.aidl \
+ ../../../base/media/java/android/media/IDescrambler.aidl \
+ ../../../base/media/java/android/media/IMediaCasService.aidl \
+
+LOCAL_SRC_FILES += \
+ CasImpl.cpp \
+ DescramblerImpl.cpp \
DrmSessionManager.cpp \
ICrypto.cpp \
IDrm.cpp \
IDrmClient.cpp \
IMediaDrmService.cpp \
+ MediaCasDefs.cpp \
SharedLibrary.cpp
ifneq ($(DISABLE_TREBLE_DRM), true)
LOCAL_SRC_FILES += \
diff --git a/drm/libmediadrm/CasImpl.cpp b/drm/libmediadrm/CasImpl.cpp
new file mode 100644
index 0000000..de15244
--- /dev/null
+++ b/drm/libmediadrm/CasImpl.cpp
@@ -0,0 +1,201 @@
+
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CasImpl"
+
+#include <android/media/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <media/CasImpl.h>
+#include <media/SharedLibrary.h>
+#include <utils/Log.h>
+
+namespace android {
+
+static Status getBinderStatus(status_t err) {
+ if (err == OK) {
+ return Status::ok();
+ }
+ if (err == BAD_VALUE) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ }
+ if (err == INVALID_OPERATION) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ }
+ return Status::fromServiceSpecificError(err);
+}
+
+static String8 sessionIdToString(const CasSessionId &sessionId) {
+ String8 result;
+ for (size_t i = 0; i < sessionId.size(); i++) {
+ result.appendFormat("%02x ", sessionId[i]);
+ }
+ if (result.isEmpty()) {
+ result.append("(null)");
+ }
+ return result;
+}
+
+CasImpl::CasImpl(const sp<ICasListener> &listener)
+ : mPlugin(NULL), mListener(listener) {
+ ALOGV("CTOR: mPlugin=%p", mPlugin);
+}
+
+CasImpl::~CasImpl() {
+ ALOGV("DTOR: mPlugin=%p", mPlugin);
+ release();
+}
+
+//static
+void CasImpl::OnEvent(
+ void *appData,
+ int32_t event,
+ int32_t arg,
+ uint8_t *data,
+ size_t size) {
+ if (appData == NULL) {
+ ALOGE("Invalid appData!");
+ return;
+ }
+ CasImpl *casImpl = static_cast<CasImpl *>(appData);
+ casImpl->onEvent(event, arg, data, size);
+}
+
+void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin *plugin) {
+ mLibrary = library;
+ mPlugin = plugin;
+}
+
+void CasImpl::onEvent(
+ int32_t event, int32_t arg, uint8_t *data, size_t size) {
+ if (mListener == NULL) {
+ return;
+ }
+
+ std::unique_ptr<CasData> eventData;
+ if (data != NULL && size > 0) {
+ eventData.reset(new CasData(data, data + size));
+ }
+
+ mListener->onEvent(event, arg, eventData);
+}
+
+Status CasImpl::setPrivateData(const CasData& pvtData) {
+ ALOGV("setPrivateData");
+ return getBinderStatus(mPlugin->setPrivateData(pvtData));
+}
+
+Status CasImpl::openSession(int32_t program_number, CasSessionId* sessionId) {
+ ALOGV("openSession: program_number=%d", program_number);
+
+ status_t err = mPlugin->openSession(program_number, sessionId);
+
+ ALOGV("openSession: session opened for program_number=%d, sessionId=%s",
+ program_number, sessionIdToString(*sessionId).string());
+
+ return getBinderStatus(err);
+}
+
+Status CasImpl::openSessionForStream(
+ int32_t program_number,
+ int32_t elementary_PID,
+ CasSessionId* sessionId) {
+ ALOGV("openSession: program_number=%d, elementary_PID=%d",
+ program_number, elementary_PID);
+
+ status_t err = mPlugin->openSession(
+ program_number, elementary_PID, sessionId);
+
+ ALOGV("openSession: session opened for "
+ "program_number=%d, elementary_PID=%d, sessionId=%s",
+ program_number, elementary_PID,
+ sessionIdToString(*sessionId).string());
+
+ return getBinderStatus(err);
+}
+
+Status CasImpl::setSessionPrivateData(
+ const CasSessionId &sessionId, const CasData& pvtData) {
+ ALOGV("setSessionPrivateData: sessionId=%s",
+ sessionIdToString(sessionId).string());
+
+ return getBinderStatus(mPlugin->setSessionPrivateData(sessionId, pvtData));
+}
+
+Status CasImpl::closeSession(const CasSessionId &sessionId) {
+ ALOGV("closeSession: sessionId=%s",
+ sessionIdToString(sessionId).string());
+
+ return getBinderStatus(mPlugin->closeSession(sessionId));
+}
+
+Status CasImpl::processEcm(const CasSessionId &sessionId, const ParcelableCasData& ecm) {
+ ALOGV("processEcm: sessionId=%s",
+ sessionIdToString(sessionId).string());
+
+ return getBinderStatus(mPlugin->processEcm(sessionId, ecm));
+}
+
+Status CasImpl::processEmm(const ParcelableCasData& emm) {
+ ALOGV("processEmm");
+
+ return getBinderStatus(mPlugin->processEmm(emm));
+}
+
+Status CasImpl::sendEvent(
+ int32_t event, int32_t arg, const ::std::unique_ptr<CasData> &eventData) {
+ ALOGV("sendEvent");
+
+ status_t err;
+ if (eventData == nullptr) {
+ err = mPlugin->sendEvent(event, arg, CasData());
+ } else {
+ err = mPlugin->sendEvent(event, arg, *eventData);
+ }
+ return getBinderStatus(err);
+}
+
+Status CasImpl::provision(const String16& provisionString) {
+ ALOGV("provision: provisionString=%s", String8(provisionString).string());
+
+ return getBinderStatus(mPlugin->provision(String8(provisionString)));
+}
+
+Status CasImpl::refreshEntitlements(
+ int32_t refreshType, const ::std::unique_ptr<CasData> &refreshData) {
+ ALOGV("refreshEntitlements");
+
+ status_t err;
+ if (refreshData == nullptr) {
+ err = mPlugin->refreshEntitlements(refreshType, CasData());
+ } else {
+ err = mPlugin->refreshEntitlements(refreshType, *refreshData);
+ }
+ return getBinderStatus(err);
+}
+
+Status CasImpl::release() {
+ ALOGV("release: mPlugin=%p", mPlugin);
+
+ if (mPlugin != NULL) {
+ delete mPlugin;
+ mPlugin = NULL;
+ }
+ return Status::ok();
+}
+
+} // namespace android
+
diff --git a/drm/libmediadrm/DescramblerImpl.cpp b/drm/libmediadrm/DescramblerImpl.cpp
new file mode 100644
index 0000000..94e09e2
--- /dev/null
+++ b/drm/libmediadrm/DescramblerImpl.cpp
@@ -0,0 +1,107 @@
+
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DescramblerImpl"
+
+#include <media/cas/DescramblerAPI.h>
+#include <media/DescramblerImpl.h>
+#include <media/SharedLibrary.h>
+#include <utils/Log.h>
+#include <binder/IMemory.h>
+
+namespace android {
+
+static Status getBinderStatus(status_t err) {
+ if (err == OK) {
+ return Status::ok();
+ }
+ if (err == BAD_VALUE) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ }
+ if (err == INVALID_OPERATION) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ }
+ return Status::fromServiceSpecificError(err);
+}
+
+static String8 sessionIdToString(const CasSessionId &sessionId) {
+ String8 result;
+ for (size_t i = 0; i < sessionId.size(); i++) {
+ result.appendFormat("%02x ", sessionId[i]);
+ }
+ if (result.isEmpty()) {
+ result.append("(null)");
+ }
+ return result;
+}
+
+DescramblerImpl::DescramblerImpl(
+ const sp<SharedLibrary>& library, DescramblerPlugin *plugin) :
+ mLibrary(library), mPlugin(plugin) {
+ ALOGV("CTOR: mPlugin=%p", mPlugin);
+}
+
+DescramblerImpl::~DescramblerImpl() {
+ ALOGV("DTOR: mPlugin=%p", mPlugin);
+ release();
+}
+
+Status DescramblerImpl::setMediaCasSession(const CasSessionId& sessionId) {
+ ALOGV("setMediaCasSession: sessionId=%s",
+ sessionIdToString(sessionId).string());
+
+ return getBinderStatus(mPlugin->setMediaCasSession(sessionId));
+}
+
+Status DescramblerImpl::requiresSecureDecoderComponent(
+ const String16& mime, bool *result) {
+ *result = mPlugin->requiresSecureDecoderComponent(String8(mime));
+
+ return getBinderStatus(OK);
+}
+
+Status DescramblerImpl::descramble(
+ const DescrambleInfo& info, int32_t *result) {
+ ALOGV("descramble");
+
+ *result = mPlugin->descramble(
+ info.dstType != DescrambleInfo::kDestinationTypeVmPointer,
+ info.scramblingControl,
+ info.numSubSamples,
+ info.subSamples,
+ info.srcMem->pointer(),
+ info.srcOffset,
+ info.dstType == DescrambleInfo::kDestinationTypeVmPointer ?
+ info.srcMem->pointer() : info.dstPtr,
+ info.dstOffset,
+ NULL);
+
+ return getBinderStatus(*result >= 0 ? OK : *result);
+}
+
+Status DescramblerImpl::release() {
+ ALOGV("release: mPlugin=%p", mPlugin);
+
+ if (mPlugin != NULL) {
+ delete mPlugin;
+ mPlugin = NULL;
+ }
+ return Status::ok();
+}
+
+} // namespace android
+
diff --git a/drm/libmediadrm/MediaCasDefs.cpp b/drm/libmediadrm/MediaCasDefs.cpp
new file mode 100644
index 0000000..9c2ba38
--- /dev/null
+++ b/drm/libmediadrm/MediaCasDefs.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaCas"
+
+#include <media/MediaCasDefs.h>
+#include <utils/Log.h>
+#include <binder/IMemory.h>
+
+namespace android {
+namespace media {
+
+///////////////////////////////////////////////////////////////////////////////
+namespace MediaCas {
+
+status_t ParcelableCasData::readFromParcel(const Parcel* parcel) {
+ return parcel->readByteVector(this);
+}
+
+status_t ParcelableCasData::writeToParcel(Parcel* parcel) const {
+ return parcel->writeByteVector(*this);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+status_t ParcelableCasPluginDescriptor::readFromParcel(const Parcel* /*parcel*/) {
+ ALOGE("CAPluginDescriptor::readFromParcel() shouldn't be called");
+ return INVALID_OPERATION;
+}
+
+status_t ParcelableCasPluginDescriptor::writeToParcel(Parcel* parcel) const {
+ status_t err = parcel->writeInt32(mCASystemId);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return parcel->writeString16(mName);
+}
+
+} // namespace MediaCas
+///////////////////////////////////////////////////////////////////////////////
+
+namespace MediaDescrambler {
+
+DescrambleInfo::DescrambleInfo() {}
+
+DescrambleInfo::~DescrambleInfo() {}
+
+status_t DescrambleInfo::readFromParcel(const Parcel* parcel) {
+ status_t err = parcel->readInt32((int32_t*)&dstType);
+ if (err != OK) {
+ return err;
+ }
+ if (dstType != kDestinationTypeNativeHandle
+ && dstType != kDestinationTypeVmPointer) {
+ return BAD_VALUE;
+ }
+
+ err = parcel->readInt32((int32_t*)&scramblingControl);
+ if (err != OK) {
+ return err;
+ }
+
+ err = parcel->readUint32((uint32_t*)&numSubSamples);
+ if (err != OK) {
+ return err;
+ }
+ if (numSubSamples > 0xffff) {
+ return BAD_VALUE;
+ }
+
+ subSamples = new DescramblerPlugin::SubSample[numSubSamples];
+ if (subSamples == NULL) {
+ return NO_MEMORY;
+ }
+
+ for (size_t i = 0; i < numSubSamples; i++) {
+ err = parcel->readUint32(&subSamples[i].mNumBytesOfClearData);
+ if (err != OK) {
+ return err;
+ }
+ err = parcel->readUint32(&subSamples[i].mNumBytesOfEncryptedData);
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ srcMem = interface_cast<IMemory>(parcel->readStrongBinder());
+ if (srcMem == NULL) {
+ return BAD_VALUE;
+ }
+
+ err = parcel->readInt32(&srcOffset);
+ if (err != OK) {
+ return err;
+ }
+
+ native_handle_t *nativeHandle = NULL;
+ if (dstType == kDestinationTypeNativeHandle) {
+ nativeHandle = parcel->readNativeHandle();
+ dstPtr = static_cast<void *>(nativeHandle);
+ } else {
+ dstPtr = NULL;
+ }
+
+ err = parcel->readInt32(&dstOffset);
+ if (err != OK) {
+ return err;
+ }
+
+ return OK;
+}
+
+status_t DescrambleInfo::writeToParcel(Parcel* parcel) const {
+ if (dstType != kDestinationTypeNativeHandle
+ && dstType != kDestinationTypeVmPointer) {
+ return BAD_VALUE;
+ }
+
+ status_t err = parcel->writeInt32((int32_t)dstType);
+ if (err != OK) {
+ return err;
+ }
+
+ err = parcel->writeInt32(scramblingControl);
+ if (err != OK) {
+ return err;
+ }
+
+ err = parcel->writeUint32(numSubSamples);
+ if (err != OK) {
+ return err;
+ }
+
+ for (size_t i = 0; i < numSubSamples; i++) {
+ err = parcel->writeUint32(subSamples[i].mNumBytesOfClearData);
+ if (err != OK) {
+ return err;
+ }
+ err = parcel->writeUint32(subSamples[i].mNumBytesOfEncryptedData);
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ err = parcel->writeStrongBinder(IInterface::asBinder(srcMem));
+ if (err != OK) {
+ return err;
+ }
+
+ err = parcel->writeInt32(srcOffset);
+ if (err != OK) {
+ return err;
+ }
+
+ if (dstType == kDestinationTypeNativeHandle) {
+ parcel->writeNativeHandle(static_cast<native_handle_t *>(dstPtr));
+ }
+
+ err = parcel->writeInt32(dstOffset);
+ if (err != OK) {
+ return err;
+ }
+
+ return OK;
+}
+
+} // namespace MediaDescrambler
+
+} // namespace media
+} // namespace android
+
diff --git a/drm/libmediadrm/SharedLibrary.cpp b/drm/libmediadrm/SharedLibrary.cpp
index 74b3a71..bebafa8 100644
--- a/drm/libmediadrm/SharedLibrary.cpp
+++ b/drm/libmediadrm/SharedLibrary.cpp
@@ -43,6 +43,9 @@
if (!mLibHandle) {
return NULL;
}
+ // Clear last error before we load the symbol again,
+ // in case the caller didn't retrieve it.
+ (void)dlerror();
return dlsym(mLibHandle, symbol);
}
diff --git a/include/media/CasImpl.h b/include/media/CasImpl.h
new file mode 100644
index 0000000..80c901e
--- /dev/null
+++ b/include/media/CasImpl.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef CAS_IMPL_H_
+#define CAS_IMPL_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <android/media/BnCas.h>
+
+namespace android {
+namespace media {
+class ICasListener;
+}
+using namespace media;
+using namespace MediaCas;
+using binder::Status;
+class CasPlugin;
+class SharedLibrary;
+
+class CasImpl : public BnCas {
+public:
+ CasImpl(const sp<ICasListener> &listener);
+ virtual ~CasImpl();
+
+ static void OnEvent(
+ void *appData,
+ int32_t event,
+ int32_t arg,
+ uint8_t *data,
+ size_t size);
+
+ void init(const sp<SharedLibrary>& library, CasPlugin *plugin);
+ void onEvent(
+ int32_t event,
+ int32_t arg,
+ uint8_t *data,
+ size_t size);
+
+ // ICas inherits
+
+ virtual Status setPrivateData(
+ const CasData& pvtData) override;
+
+ virtual Status openSession(
+ int32_t program_number, CasSessionId* _aidl_return) override;
+
+ virtual Status openSessionForStream(
+ int32_t program_number,
+ int32_t elementary_PID,
+ CasSessionId* _aidl_return) override;
+
+ virtual Status closeSession(const CasSessionId& sessionId) override;
+
+ virtual Status setSessionPrivateData(
+ const CasSessionId& sessionId,
+ const CasData& pvtData) override;
+
+ virtual Status processEcm(
+ const CasSessionId& sessionId, const ParcelableCasData& ecm) override;
+
+ virtual Status processEmm(const ParcelableCasData& emm) override;
+
+ virtual Status sendEvent(
+ int32_t event, int32_t arg, const ::std::unique_ptr<CasData> &eventData) override;
+
+ virtual Status provision(const String16& provisionString) override;
+
+ virtual Status refreshEntitlements(
+ int32_t refreshType, const ::std::unique_ptr<CasData> &refreshData) override;
+
+ virtual Status release() override;
+
+private:
+ sp<SharedLibrary> mLibrary;
+ CasPlugin *mPlugin;
+ sp<ICasListener> mListener;
+
+ DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
+};
+
+} // namespace android
+
+#endif // CAS_IMPL_H_
diff --git a/include/media/DescramblerImpl.h b/include/media/DescramblerImpl.h
new file mode 100644
index 0000000..c1c79b3
--- /dev/null
+++ b/include/media/DescramblerImpl.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef DESCRAMBLER_IMPL_H_
+#define DESCRAMBLER_IMPL_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <android/media/BnDescrambler.h>
+
+namespace android {
+using namespace media;
+using namespace MediaDescrambler;
+using binder::Status;
+class DescramblerPlugin;
+class SharedLibrary;
+
+class DescramblerImpl : public BnDescrambler {
+public:
+ DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin *plugin);
+ virtual ~DescramblerImpl();
+
+ virtual Status setMediaCasSession(
+ const CasSessionId& sessionId) override;
+
+ virtual Status requiresSecureDecoderComponent(
+ const String16& mime, bool *result) override;
+
+ virtual Status descramble(
+ const DescrambleInfo& descrambleInfo, int32_t *result) override;
+
+ virtual Status release() override;
+
+private:
+ sp<SharedLibrary> mLibrary;
+ DescramblerPlugin *mPlugin;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
+};
+
+} // namespace android
+
+#endif // DESCRAMBLER_IMPL_H_
diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
index 06db359..cf1b9fb 100644
--- a/include/media/IMediaExtractor.h
+++ b/include/media/IMediaExtractor.h
@@ -24,6 +24,10 @@
namespace android {
class MetaData;
+namespace media {
+class ICas;
+};
+using namespace media;
class IMediaExtractor : public IInterface {
public:
@@ -57,6 +61,9 @@
// for DRM
virtual char* getDrmTrackInfo(size_t trackID, int *len) = 0;
+
+ virtual status_t setMediaCas(const sp<ICas> &cas) = 0;
+
virtual void setUID(uid_t uid) = 0;
virtual const char * name() = 0;
diff --git a/include/media/MediaCasDefs.h b/include/media/MediaCasDefs.h
new file mode 100644
index 0000000..8c5a967
--- /dev/null
+++ b/include/media/MediaCasDefs.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef MEDIA_CAS_DEFS_H_
+#define MEDIA_CAS_DEFS_H_
+
+#include <binder/Parcel.h>
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+class IMemory;
+namespace media {
+
+namespace MediaCas {
+class ParcelableCasData : public CasData,
+ public Parcelable {
+public:
+ ParcelableCasData() {}
+ ParcelableCasData(const uint8_t *data, size_t size) :
+ CasData(data, data + size) {}
+ virtual ~ParcelableCasData() {}
+ status_t readFromParcel(const Parcel* parcel) override;
+ status_t writeToParcel(Parcel* parcel) const override;
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(ParcelableCasData);
+};
+
+class ParcelableCasPluginDescriptor : public Parcelable {
+public:
+ ParcelableCasPluginDescriptor(int32_t CA_system_id, const char *name)
+ : mCASystemId(CA_system_id), mName(name) {}
+
+ ParcelableCasPluginDescriptor() : mCASystemId(0) {}
+
+ ParcelableCasPluginDescriptor(ParcelableCasPluginDescriptor&& desc) = default;
+
+ virtual ~ParcelableCasPluginDescriptor() {}
+
+ status_t readFromParcel(const Parcel* parcel) override;
+ status_t writeToParcel(Parcel* parcel) const override;
+
+private:
+ int32_t mCASystemId;
+ String16 mName;
+ DISALLOW_EVIL_CONSTRUCTORS(ParcelableCasPluginDescriptor);
+};
+}
+
+namespace MediaDescrambler {
+class DescrambleInfo : public Parcelable {
+public:
+ enum DestinationType {
+ kDestinationTypeVmPointer, // non-secure
+ kDestinationTypeNativeHandle // secure
+ };
+
+ DestinationType dstType;
+ DescramblerPlugin::ScramblingControl scramblingControl;
+ size_t numSubSamples;
+ DescramblerPlugin::SubSample *subSamples;
+ sp<IMemory> srcMem;
+ int32_t srcOffset;
+ void *dstPtr;
+ int32_t dstOffset;
+
+ DescrambleInfo();
+ virtual ~DescrambleInfo();
+ status_t readFromParcel(const Parcel* parcel) override;
+ status_t writeToParcel(Parcel* parcel) const override;
+
+private:
+
+ DISALLOW_EVIL_CONSTRUCTORS(DescrambleInfo);
+};
+}
+
+} // namespace media
+} // namespace android
+
+
+#endif // MEDIA_CAS_DEFS_H_
diff --git a/include/media/MediaDefs.h b/include/media/MediaDefs.h
index 0682413..7f17013 100644
--- a/include/media/MediaDefs.h
+++ b/include/media/MediaDefs.h
@@ -31,6 +31,7 @@
extern const char *MEDIA_MIMETYPE_VIDEO_MPEG2;
extern const char *MEDIA_MIMETYPE_VIDEO_RAW;
extern const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION;
+extern const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
@@ -50,6 +51,7 @@
extern const char *MEDIA_MIMETYPE_AUDIO_MSGSM;
extern const char *MEDIA_MIMETYPE_AUDIO_AC3;
extern const char *MEDIA_MIMETYPE_AUDIO_EAC3;
+extern const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED;
extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 20b26e2..fd3ff26 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -47,6 +47,10 @@
struct PersistentSurface;
class SoftwareRenderer;
class Surface;
+namespace media {
+class IDescrambler;
+};
+using namespace media;
struct MediaCodec : public AHandler {
enum ConfigureFlags {
@@ -91,6 +95,13 @@
const sp<ICrypto> &crypto,
uint32_t flags);
+ status_t configure(
+ const sp<AMessage> &format,
+ const sp<Surface> &nativeWindow,
+ const sp<ICrypto> &crypto,
+ const sp<IDescrambler> &descrambler,
+ uint32_t flags);
+
status_t releaseCrypto();
status_t setCallback(const sp<AMessage> &callback);
@@ -345,6 +356,8 @@
sp<ICrypto> mCrypto;
+ sp<IDescrambler> mDescrambler;
+
List<sp<ABuffer> > mCSD;
sp<AMessage> mActivityNotify;
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 9ce6cc5..073391f 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -23,7 +23,10 @@
#include <media/MediaAnalyticsItem.h>
namespace android {
-
+namespace media {
+class ICas;
+};
+using namespace media;
class DataSource;
struct MediaSource;
class MetaData;
@@ -67,6 +70,9 @@
}
virtual void setUID(uid_t /*uid*/) {
}
+ virtual status_t setMediaCas(const sp<ICas> &cas) override {
+ return INVALID_OPERATION;
+ }
virtual const char * name() { return "<unspecified>"; }
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index ad0d37b..3e3cc17 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -28,6 +28,10 @@
#include <utils/Vector.h>
namespace android {
+namespace media {
+class ICas;
+}
+using namespace media;
struct ABuffer;
struct AMessage;
@@ -60,6 +64,8 @@
status_t setDataSource(const sp<DataSource> &datasource);
+ status_t setMediaCas(const sp<ICas> &cas);
+
size_t countTracks() const;
status_t getTrackFormat(size_t index, sp<AMessage> *format, uint32_t flags = 0) const;
@@ -109,6 +115,7 @@
sp<DataSource> mDataSource;
sp<IMediaExtractor> mImpl;
+ sp<ICas> mCas;
Vector<TrackInfo> mSelectedTracks;
int64_t mTotalBitrate; // in bits/sec
diff --git a/media/libaudiohal/DeviceHalHidl.cpp b/media/libaudiohal/DeviceHalHidl.cpp
index dcedfd3..71fbd98 100644
--- a/media/libaudiohal/DeviceHalHidl.cpp
+++ b/media/libaudiohal/DeviceHalHidl.cpp
@@ -21,6 +21,7 @@
#include <android/hardware/audio/2.0/IPrimaryDevice.h>
#include <cutils/native_handle.h>
+#include <hwbinder/IPCThreadState.h>
#include <utils/Log.h>
#include "DeviceHalHidl.h"
@@ -101,6 +102,10 @@
}
DeviceHalHidl::~DeviceHalHidl() {
+ if (mDevice != 0) {
+ mDevice.clear();
+ hardware::IPCThreadState::self()->flushCommands();
+ }
}
status_t DeviceHalHidl::getSupportedDevices(uint32_t*) {
diff --git a/media/libaudiohal/EffectHalHidl.cpp b/media/libaudiohal/EffectHalHidl.cpp
index d17f8bd..db115ef 100644
--- a/media/libaudiohal/EffectHalHidl.cpp
+++ b/media/libaudiohal/EffectHalHidl.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "EffectHalHidl"
//#define LOG_NDEBUG 0
+#include <hwbinder/IPCThreadState.h>
#include <media/EffectsFactoryApi.h>
#include <utils/Log.h>
@@ -44,7 +45,11 @@
}
EffectHalHidl::~EffectHalHidl() {
- close();
+ if (mEffect != 0) {
+ close();
+ mEffect.clear();
+ hardware::IPCThreadState::self()->flushCommands();
+ }
}
// static
diff --git a/media/libaudiohal/StreamHalHidl.cpp b/media/libaudiohal/StreamHalHidl.cpp
index b66ba2b..2a7a67f 100644
--- a/media/libaudiohal/StreamHalHidl.cpp
+++ b/media/libaudiohal/StreamHalHidl.cpp
@@ -18,6 +18,7 @@
//#define LOG_NDEBUG 0
#include <android/hardware/audio/2.0/IStreamOutCallback.h>
+#include <hwbinder/IPCThreadState.h>
#include <mediautils/SchedulingPolicyService.h>
#include <utils/Log.h>
@@ -263,8 +264,10 @@
processReturn("clearCallback", mStream->clearCallback());
}
processReturn("close", mStream->close());
+ mStream.clear();
}
mCallback.clear();
+ hardware::IPCThreadState::self()->flushCommands();
if (mEfGroup) {
EventFlag::deleteEventFlag(&mEfGroup);
}
@@ -538,6 +541,8 @@
StreamInHalHidl::~StreamInHalHidl() {
if (mStream != 0) {
processReturn("close", mStream->close());
+ mStream.clear();
+ hardware::IPCThreadState::self()->flushCommands();
}
if (mEfGroup) {
EventFlag::deleteEventFlag(&mEfGroup);
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 6c6c369..eac532b 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -60,10 +60,10 @@
libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \
libcamera_client libstagefright_foundation \
libgui libdl libaudioutils libaudioclient \
- libmedia_helper \
+ libmedia_helper libmediadrm \
libhidlbase \
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libsonivox
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libsonivox libmediadrm
# for memory heap analysis
LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index bfc43a6..f08fabb 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -21,6 +21,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/media/ICas.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <media/IMediaExtractor.h>
@@ -35,6 +36,7 @@
GETMETADATA,
FLAGS,
GETDRMTRACKINFO,
+ SETMEDIACAS,
SETUID,
NAME,
GETMETRICS
@@ -114,6 +116,21 @@
ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
return NULL;
}
+
+ virtual status_t setMediaCas(const sp<ICas> & cas) {
+ ALOGV("setMediaCas");
+
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(cas));
+
+ status_t err = remote()->transact(SETMEDIACAS, data, &reply);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return reply.readInt32();
+ }
+
virtual void setUID(uid_t uid __unused) {
ALOGV("setUID NOT IMPLEMENTED");
}
@@ -185,6 +202,21 @@
status_t ret = getMetrics(reply);
return ret;
}
+ case SETMEDIACAS: {
+ ALOGV("setMediaCas");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+
+ sp<IBinder> casBinder;
+ status_t err = data.readNullableStrongBinder(&casBinder);
+ if (err != NO_ERROR) {
+ ALOGE("Error reading cas from parcel");
+ return err;
+ }
+ sp<ICas> cas = interface_cast<ICas>(casBinder);
+
+ reply->writeInt32(setMediaCas(cas));
+ return OK;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/MediaDefs.cpp b/media/libmedia/MediaDefs.cpp
index 2ae71f7..544a6ae 100644
--- a/media/libmedia/MediaDefs.cpp
+++ b/media/libmedia/MediaDefs.cpp
@@ -29,6 +29,7 @@
const char *MEDIA_MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw";
const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
+const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
@@ -48,6 +49,7 @@
const char *MEDIA_MIMETYPE_AUDIO_MSGSM = "audio/gsm";
const char *MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3";
const char *MEDIA_MIMETYPE_AUDIO_EAC3 = "audio/eac3";
+const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4";
const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/x-wav";
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index e6d9b71..035cd8a 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -36,6 +36,7 @@
libstagefright_omx \
libstagefright_wfd \
libutils \
+ libnativewindow \
libhidlbase \
android.hardware.media.omx@1.0 \
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index d044754..140ceb1 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -93,6 +93,8 @@
libui \
libutils \
libvorbisidec \
+ libmediadrm \
+ libnativewindow \
LOCAL_STATIC_LIBRARIES := \
libstagefright_color_conversion \
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 03010ab..6674e2c 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -23,6 +23,7 @@
#include "include/SharedMemoryBuffer.h"
#include "include/SoftwareRenderer.h"
+#include <android/media/IDescrambler.h>
#include <binder/IMemory.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -680,8 +681,17 @@
status_t MediaCodec::configure(
const sp<AMessage> &format,
+ const sp<Surface> &nativeWindow,
+ const sp<ICrypto> &crypto,
+ uint32_t flags) {
+ return configure(format, nativeWindow, crypto, NULL, flags);
+}
+
+status_t MediaCodec::configure(
+ const sp<AMessage> &format,
const sp<Surface> &surface,
const sp<ICrypto> &crypto,
+ const sp<IDescrambler> &descrambler,
uint32_t flags) {
sp<AMessage> msg = new AMessage(kWhatConfigure, this);
@@ -710,8 +720,12 @@
msg->setInt32("flags", flags);
msg->setObject("surface", surface);
- if (crypto != NULL) {
- msg->setPointer("crypto", crypto.get());
+ if (crypto != NULL || descrambler != NULL) {
+ if (crypto != NULL) {
+ msg->setPointer("crypto", crypto.get());
+ } else {
+ msg->setPointer("descrambler", descrambler.get());
+ }
if (mAnalyticsItem != NULL) {
// XXX: save indication that it's crypto in some way...
mAnalyticsItem->setInt32("crypto", 1);
@@ -1992,6 +2006,13 @@
ALOGV("kWhatConfigure: New mCrypto: %p (%d)",
mCrypto.get(), (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
+ void *descrambler;
+ if (!msg->findPointer("descrambler", &descrambler)) {
+ descrambler = NULL;
+ }
+
+ mDescrambler = static_cast<IDescrambler *>(descrambler);
+
uint32_t flags;
CHECK(msg->findInt32("flags", (int32_t *)&flags));
@@ -2592,6 +2613,7 @@
mCrypto.get(), (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
}
mCrypto.clear();
+ mDescrambler.clear();
handleSetSurface(NULL);
mInputFormat.clear();
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 1c1acb0..ea3ed28 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -35,6 +35,7 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <android/media/ICas.h>
namespace android {
@@ -82,6 +83,10 @@
return ERROR_UNSUPPORTED;
}
+ if (mCas != NULL) {
+ mImpl->setMediaCas(mCas);
+ }
+
status_t err = updateDurationAndBitrate();
if (err == OK) {
mDataSource = dataSource;
@@ -114,6 +119,10 @@
return ERROR_UNSUPPORTED;
}
+ if (mCas != NULL) {
+ mImpl->setMediaCas(mCas);
+ }
+
err = updateDurationAndBitrate();
if (err == OK) {
mDataSource = fileSource;
@@ -140,6 +149,10 @@
return ERROR_UNSUPPORTED;
}
+ if (mCas != NULL) {
+ mImpl->setMediaCas(mCas);
+ }
+
err = updateDurationAndBitrate();
if (err == OK) {
mDataSource = source;
@@ -148,6 +161,27 @@
return err;
}
+status_t NuMediaExtractor::setMediaCas(const sp<ICas> &cas) {
+ ALOGV("setMediaCas: cas=%p", cas.get());
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (cas == NULL) {
+ return BAD_VALUE;
+ }
+
+ if (mImpl != NULL) {
+ mImpl->setMediaCas(cas);
+ status_t err = updateDurationAndBitrate();
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ mCas = cas;
+ return OK;
+}
+
status_t NuMediaExtractor::updateDurationAndBitrate() {
if (mImpl->countTracks() > kMaxTrackCount) {
return ERROR_UNSUPPORTED;
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index a974671..81179d1 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -1288,8 +1288,51 @@
continue;
}
- meta->setInt32(kKeyWidth, vtrack->GetWidth());
- meta->setInt32(kKeyHeight, vtrack->GetHeight());
+ const long long width = vtrack->GetWidth();
+ const long long height = vtrack->GetHeight();
+ if (width <= 0 || width > INT32_MAX) {
+ ALOGW("track width exceeds int32_t, %lld", width);
+ continue;
+ }
+ if (height <= 0 || height > INT32_MAX) {
+ ALOGW("track height exceeds int32_t, %lld", height);
+ continue;
+ }
+ meta->setInt32(kKeyWidth, (int32_t)width);
+ meta->setInt32(kKeyHeight, (int32_t)height);
+
+ // setting display width/height is optional
+ const long long displayUnit = vtrack->GetDisplayUnit();
+ const long long displayWidth = vtrack->GetDisplayWidth();
+ const long long displayHeight = vtrack->GetDisplayHeight();
+ if (displayWidth > 0 && displayWidth <= INT32_MAX
+ && displayHeight > 0 && displayHeight <= INT32_MAX) {
+ switch (displayUnit) {
+ case 0: // pixels
+ meta->setInt32(kKeyDisplayWidth, (int32_t)displayWidth);
+ meta->setInt32(kKeyDisplayHeight, (int32_t)displayHeight);
+ break;
+ case 1: // centimeters
+ case 2: // inches
+ case 3: // aspect ratio
+ {
+ // Physical layout size is treated the same as aspect ratio.
+ // Note: displayWidth and displayHeight are never zero as they are
+ // checked in the if above.
+ const long long computedWidth =
+ std::max(width, height * displayWidth / displayHeight);
+ const long long computedHeight =
+ std::max(height, width * displayHeight / displayWidth);
+ if (computedWidth <= INT32_MAX && computedHeight <= INT32_MAX) {
+ meta->setInt32(kKeyDisplayWidth, (int32_t)computedWidth);
+ meta->setInt32(kKeyDisplayHeight, (int32_t)computedHeight);
+ }
+ break;
+ }
+ default: // unknown display units, perhaps future version of spec.
+ break;
+ }
+ }
getColorInformation(vtrack, meta);
diff --git a/media/libstagefright/omx/hal/1.0/impl/Android.mk b/media/libstagefright/omx/hal/1.0/impl/Android.mk
index 49e0ca7..09424b5 100644
--- a/media/libstagefright/omx/hal/1.0/impl/Android.mk
+++ b/media/libstagefright/omx/hal/1.0/impl/Android.mk
@@ -2,7 +2,6 @@
include $(CLEAR_VARS)
LOCAL_MODULE := android.hardware.media.omx@1.0-impl
-LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SRC_FILES := \
WGraphicBufferSource.cpp \
WOmx.cpp \
@@ -12,7 +11,6 @@
WOmxObserver.cpp \
WOmxProducerListener.cpp \
Omx.cpp \
- OmxNode.cpp \
LOCAL_SHARED_LIBRARIES := \
libmedia \
@@ -28,6 +26,7 @@
libcutils \
libbinder \
liblog \
+ libbase \
android.hardware.media.omx@1.0 \
android.hardware.graphics.common@1.0 \
android.hardware.media@1.0 \
@@ -38,12 +37,10 @@
-Werror
LOCAL_C_INCLUDES += \
- $(TOP) \
- $(TOP)/frameworks/av/include/media \
- $(TOP)/frameworks/av/media/libstagefright/include \
- $(TOP)/frameworks/av/media/libstagefright/omx \
- $(TOP)/frameworks/native/include/media/hardware \
- $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/frameworks/av/include \
+ $(TOP)/frameworks/av/media/libstagefright \
$(TOP)/frameworks/native/include \
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/frameworks/native/include/media/hardware \
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/hal/1.0/impl/Conversion.h b/media/libstagefright/omx/hal/1.0/impl/Conversion.h
index d164faa..d5cf029 100644
--- a/media/libstagefright/omx/hal/1.0/impl/Conversion.h
+++ b/media/libstagefright/omx/hal/1.0/impl/Conversion.h
@@ -17,29 +17,26 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
+#include <vector>
+#include <list>
+
+#include <unistd.h>
+
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <hidlmemory/mapping.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-
-#include <unistd.h>
-#include <vector>
-#include <list>
#include <binder/Binder.h>
#include <binder/Status.h>
#include <ui/FenceTime.h>
-
-#include <OMXFenceParcelable.h>
+#include <media/OMXFenceParcelable.h>
#include <cutils/native_handle.h>
#include <gui/IGraphicBufferProducer.h>
-#include <IOMX.h>
+#include <media/OMXBuffer.h>
#include <VideoAPI.h>
-#include <OMXBuffer.h>
-#include <android/IOMXBufferSource.h>
-#include <android/IGraphicBufferSource.h>
+#include <android/hidl/memory/1.0/IMemory.h>
#include <android/hardware/media/omx/1.0/types.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
@@ -49,6 +46,9 @@
#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+#include <android/IGraphicBufferSource.h>
+#include <android/IOMXBufferSource.h>
+
namespace android {
namespace hardware {
namespace media {
@@ -177,25 +177,6 @@
*/
/**
- * \brief Convert `binder::Status` to `Return<void>`.
- *
- * \param[in] l The source `binder::Status`.
- * \return The corresponding `Return<void>`.
- */
-// convert: ::android::binder::Status -> Return<void>
-inline Return<void> toHardwareStatus(
- ::android::binder::Status const& l) {
- if (l.exceptionCode() == ::android::binder::Status::EX_SERVICE_SPECIFIC) {
- return ::android::hardware::Status::fromServiceSpecificError(
- l.serviceSpecificErrorCode(),
- l.exceptionMessage());
- }
- return ::android::hardware::Status::fromExceptionCode(
- l.exceptionCode(),
- l.exceptionMessage());
-}
-
-/**
* \brief Convert `Return<void>` to `binder::Status`.
*
* \param[in] t The source `Return<void>`.
diff --git a/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.cpp b/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.cpp
new file mode 100644
index 0000000..2f457ac
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.cpp
@@ -0,0 +1,1203 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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 <inttypes.h>
+
+#define LOG_TAG "GraphicBufferSource"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#define STRINGIFY_ENUMS // for asString in HardwareAPI.h/VideoAPI.h
+
+#include "GraphicBufferSource.h"
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ColorUtils.h>
+
+#include <media/hardware/MetadataBufferType.h>
+#include <ui/GraphicBuffer.h>
+#include <gui/BufferItem.h>
+#include <HardwareAPI.h>
+#include "omx/OMXUtils.h"
+#include <OMX_Component.h>
+#include <OMX_IndexExt.h>
+#include "OMXBuffer.h"
+
+#include <inttypes.h>
+#include "FrameDropper.h"
+
+namespace android {
+
+static const OMX_U32 kPortIndexInput = 0;
+
+class GraphicBufferSource::OmxBufferSource : public BnOMXBufferSource {
+public:
+ GraphicBufferSource* mSource;
+
+ OmxBufferSource(GraphicBufferSource* source): mSource(source) {
+ }
+
+ Status onOmxExecuting() override {
+ return mSource->onOmxExecuting();
+ }
+
+ Status onOmxIdle() override {
+ return mSource->onOmxIdle();
+ }
+
+ Status onOmxLoaded() override {
+ return mSource->onOmxLoaded();
+ }
+
+ Status onInputBufferAdded(int bufferId) override {
+ return mSource->onInputBufferAdded(bufferId);
+ }
+
+ Status onInputBufferEmptied(
+ int bufferId, const OMXFenceParcelable& fenceParcel) override {
+ return mSource->onInputBufferEmptied(bufferId, fenceParcel);
+ }
+};
+
+GraphicBufferSource::GraphicBufferSource() :
+ mInitCheck(UNKNOWN_ERROR),
+ mExecuting(false),
+ mSuspended(false),
+ mStopTimeUs(-1),
+ mLastDataSpace(HAL_DATASPACE_UNKNOWN),
+ mNumFramesAvailable(0),
+ mNumBufferAcquired(0),
+ mEndOfStream(false),
+ mEndOfStreamSent(false),
+ mLastActionTimeUs(-1ll),
+ mPrevOriginalTimeUs(-1ll),
+ mSkipFramesBeforeNs(-1ll),
+ mRepeatAfterUs(-1ll),
+ mRepeatLastFrameGeneration(0),
+ mRepeatLastFrameTimestamp(-1ll),
+ mRepeatLastFrameCount(0),
+ mLatestBufferId(-1),
+ mLatestBufferFrameNum(0),
+ mLatestBufferFence(Fence::NO_FENCE),
+ mRepeatBufferDeferred(false),
+ mTimePerCaptureUs(-1ll),
+ mTimePerFrameUs(-1ll),
+ mPrevCaptureUs(-1ll),
+ mPrevFrameUs(-1ll),
+ mInputBufferTimeOffsetUs(0ll),
+ mOmxBufferSource(new OmxBufferSource(this)) {
+ ALOGV("GraphicBufferSource");
+
+ String8 name("GraphicBufferSource");
+
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ mConsumer->setConsumerName(name);
+
+ // Note that we can't create an sp<...>(this) in a ctor that will not keep a
+ // reference once the ctor ends, as that would cause the refcount of 'this'
+ // dropping to 0 at the end of the ctor. Since all we need is a wp<...>
+ // that's what we create.
+ wp<BufferQueue::ConsumerListener> listener =
+ static_cast<BufferQueue::ConsumerListener*>(this);
+ sp<IConsumerListener> proxy =
+ new BufferQueue::ProxyConsumerListener(listener);
+
+ mInitCheck = mConsumer->consumerConnect(proxy, false);
+ if (mInitCheck != NO_ERROR) {
+ ALOGE("Error connecting to BufferQueue: %s (%d)",
+ strerror(-mInitCheck), mInitCheck);
+ return;
+ }
+
+ memset(&mColorAspects, 0, sizeof(mColorAspects));
+
+ CHECK(mInitCheck == NO_ERROR);
+}
+
+GraphicBufferSource::~GraphicBufferSource() {
+ ALOGV("~GraphicBufferSource");
+ if (mLatestBufferId >= 0) {
+ releaseBuffer(mLatestBufferId, mLatestBufferFrameNum, mLatestBufferFence);
+ }
+ if (mNumBufferAcquired != 0) {
+ ALOGW("potential buffer leak (acquired %d)", mNumBufferAcquired);
+ }
+ if (mConsumer != NULL) {
+ status_t err = mConsumer->consumerDisconnect();
+ if (err != NO_ERROR) {
+ ALOGW("consumerDisconnect failed: %d", err);
+ }
+ }
+}
+
+Status GraphicBufferSource::onOmxExecuting() {
+ Mutex::Autolock autoLock(mMutex);
+ ALOGV("--> executing; avail=%zu, codec vec size=%zd",
+ mNumFramesAvailable, mCodecBuffers.size());
+ CHECK(!mExecuting);
+ mExecuting = true;
+ mLastDataSpace = HAL_DATASPACE_UNKNOWN;
+ ALOGV("clearing last dataSpace");
+
+ // Start by loading up as many buffers as possible. We want to do this,
+ // rather than just submit the first buffer, to avoid a degenerate case:
+ // if all BQ buffers arrive before we start executing, and we only submit
+ // one here, the other BQ buffers will just sit until we get notified
+ // that the codec buffer has been released. We'd then acquire and
+ // submit a single additional buffer, repeatedly, never using more than
+ // one codec buffer simultaneously. (We could instead try to submit
+ // all BQ buffers whenever any codec buffer is freed, but if we get the
+ // initial conditions right that will never be useful.)
+ while (mNumFramesAvailable) {
+ if (!fillCodecBuffer_l()) {
+ ALOGV("stop load with frames available (codecAvail=%d)",
+ isCodecBufferAvailable_l());
+ break;
+ }
+ }
+
+ ALOGV("done loading initial frames, avail=%zu", mNumFramesAvailable);
+
+ // If EOS has already been signaled, and there are no more frames to
+ // submit, try to send EOS now as well.
+ if (mStopTimeUs == -1 && mEndOfStream && mNumFramesAvailable == 0) {
+ submitEndOfInputStream_l();
+ }
+
+ if (mRepeatAfterUs > 0ll && mLooper == NULL) {
+ mReflector = new AHandlerReflector<GraphicBufferSource>(this);
+
+ mLooper = new ALooper;
+ mLooper->registerHandler(mReflector);
+ mLooper->start();
+
+ if (mLatestBufferId >= 0) {
+ sp<AMessage> msg =
+ new AMessage(kWhatRepeatLastFrame, mReflector);
+
+ msg->setInt32("generation", ++mRepeatLastFrameGeneration);
+ msg->post(mRepeatAfterUs);
+ }
+ }
+
+ return Status::ok();
+}
+
+Status GraphicBufferSource::onOmxIdle() {
+ ALOGV("omxIdle");
+
+ Mutex::Autolock autoLock(mMutex);
+
+ if (mExecuting) {
+ // We are only interested in the transition from executing->idle,
+ // not loaded->idle.
+ mExecuting = false;
+ }
+ return Status::ok();
+}
+
+Status GraphicBufferSource::onOmxLoaded(){
+ Mutex::Autolock autoLock(mMutex);
+ if (!mExecuting) {
+ // This can happen if something failed very early.
+ ALOGW("Dropped back down to Loaded without Executing");
+ }
+
+ if (mLooper != NULL) {
+ mLooper->unregisterHandler(mReflector->id());
+ mReflector.clear();
+
+ mLooper->stop();
+ mLooper.clear();
+ }
+
+ ALOGV("--> loaded; avail=%zu eos=%d eosSent=%d acquired=%d",
+ mNumFramesAvailable, mEndOfStream, mEndOfStreamSent, mNumBufferAcquired);
+
+ // Codec is no longer executing. Releasing all buffers to bq.
+ for (int i = (int)mCodecBuffers.size() - 1; i >= 0; --i) {
+ if (mCodecBuffers[i].mGraphicBuffer != NULL) {
+ int id = mCodecBuffers[i].mSlot;
+ if (id != mLatestBufferId) {
+ ALOGV("releasing buffer for codec: slot=%d, useCount=%d, latest=%d",
+ id, mBufferUseCount[id], mLatestBufferId);
+ sp<Fence> fence = new Fence(-1);
+ releaseBuffer(id, mCodecBuffers[i].mFrameNumber, fence);
+ mBufferUseCount[id] = 0;
+ }
+ }
+ }
+ // Also release the latest buffer
+ if (mLatestBufferId >= 0) {
+ releaseBuffer(mLatestBufferId, mLatestBufferFrameNum, mLatestBufferFence);
+ mBufferUseCount[mLatestBufferId] = 0;
+ mLatestBufferId = -1;
+ }
+
+ mCodecBuffers.clear();
+ mOMXNode.clear();
+ mExecuting = false;
+
+ return Status::ok();
+}
+
+Status GraphicBufferSource::onInputBufferAdded(int32_t bufferID) {
+ Mutex::Autolock autoLock(mMutex);
+
+ if (mExecuting) {
+ // This should never happen -- buffers can only be allocated when
+ // transitioning from "loaded" to "idle".
+ ALOGE("addCodecBuffer: buffer added while executing");
+ return Status::fromServiceSpecificError(INVALID_OPERATION);
+ }
+
+ ALOGV("addCodecBuffer: bufferID=%u", bufferID);
+
+ CodecBuffer codecBuffer;
+ codecBuffer.mBufferID = bufferID;
+ mCodecBuffers.add(codecBuffer);
+ return Status::ok();
+}
+
+Status GraphicBufferSource::onInputBufferEmptied(
+ int32_t bufferID, const OMXFenceParcelable &fenceParcel) {
+ int fenceFd = fenceParcel.get();
+
+ Mutex::Autolock autoLock(mMutex);
+ if (!mExecuting) {
+ if (fenceFd >= 0) {
+ ::close(fenceFd);
+ }
+ return Status::fromServiceSpecificError(INVALID_OPERATION);
+ }
+
+ int cbi = findMatchingCodecBuffer_l(bufferID);
+ if (cbi < 0) {
+ // This should never happen.
+ ALOGE("codecBufferEmptied: buffer not recognized (bufferID=%u)", bufferID);
+ if (fenceFd >= 0) {
+ ::close(fenceFd);
+ }
+ return Status::fromServiceSpecificError(BAD_VALUE);
+ }
+
+ ALOGV("codecBufferEmptied: bufferID=%u, cbi=%d", bufferID, cbi);
+ CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
+
+ // header->nFilledLen may not be the original value, so we can't compare
+ // that to zero to see of this was the EOS buffer. Instead we just
+ // see if the GraphicBuffer reference was null, which should only ever
+ // happen for EOS.
+ if (codecBuffer.mGraphicBuffer == NULL) {
+ if (!(mEndOfStream && mEndOfStreamSent)) {
+ // This can happen when broken code sends us the same buffer
+ // twice in a row.
+ ALOGE("ERROR: codecBufferEmptied on non-EOS null buffer "
+ "(buffer emptied twice?)");
+ }
+ // No GraphicBuffer to deal with, no additional input or output is
+ // expected, so just return.
+ if (fenceFd >= 0) {
+ ::close(fenceFd);
+ }
+ return Status::fromServiceSpecificError(BAD_VALUE);
+ }
+
+ // Find matching entry in our cached copy of the BufferQueue slots.
+ // If we find a match, release that slot. If we don't, the BufferQueue
+ // has dropped that GraphicBuffer, and there's nothing for us to release.
+ int id = codecBuffer.mSlot;
+ sp<Fence> fence = new Fence(fenceFd);
+ if (mBufferSlot[id] != NULL &&
+ mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
+ mBufferUseCount[id]--;
+
+ if (mBufferUseCount[id] < 0) {
+ ALOGW("mBufferUseCount for bq slot %d < 0 (=%d)", id, mBufferUseCount[id]);
+ mBufferUseCount[id] = 0;
+ }
+ if (id != mLatestBufferId && mBufferUseCount[id] == 0) {
+ releaseBuffer(id, codecBuffer.mFrameNumber, fence);
+ }
+ ALOGV("codecBufferEmptied: slot=%d, cbi=%d, useCount=%d, acquired=%d, handle=%p",
+ id, cbi, mBufferUseCount[id], mNumBufferAcquired, mBufferSlot[id]->handle);
+ } else {
+ ALOGV("codecBufferEmptied: no match for emptied buffer, "
+ "slot=%d, cbi=%d, useCount=%d, acquired=%d",
+ id, cbi, mBufferUseCount[id], mNumBufferAcquired);
+ // we will not reuse codec buffer, so there is no need to wait for fence
+ }
+
+ // Mark the codec buffer as available by clearing the GraphicBuffer ref.
+ codecBuffer.mGraphicBuffer = NULL;
+
+ if (mNumFramesAvailable) {
+ // Fill this codec buffer.
+ CHECK(!mEndOfStreamSent);
+ ALOGV("buffer freed, %zu frames avail (eos=%d)",
+ mNumFramesAvailable, mEndOfStream);
+ fillCodecBuffer_l();
+ } else if (mEndOfStream && mStopTimeUs == -1) {
+ // No frames available, but EOS is pending and no stop time, so use this buffer to
+ // send that.
+ ALOGV("buffer freed, EOS pending");
+ submitEndOfInputStream_l();
+ } else if (mRepeatBufferDeferred) {
+ bool success = repeatLatestBuffer_l();
+ if (success) {
+ ALOGV("deferred repeatLatestBuffer_l SUCCESS");
+ } else {
+ ALOGV("deferred repeatLatestBuffer_l FAILURE");
+ }
+ mRepeatBufferDeferred = false;
+ }
+
+ return Status::ok();
+}
+
+void GraphicBufferSource::onDataSpaceChanged_l(
+ android_dataspace dataSpace, android_pixel_format pixelFormat) {
+ ALOGD("got buffer with new dataSpace #%x", dataSpace);
+ mLastDataSpace = dataSpace;
+
+ if (ColorUtils::convertDataSpaceToV0(dataSpace)) {
+ omx_message msg;
+ msg.type = omx_message::EVENT;
+ msg.fenceFd = -1;
+ msg.u.event_data.event = OMX_EventDataSpaceChanged;
+ msg.u.event_data.data1 = mLastDataSpace;
+ msg.u.event_data.data2 = ColorUtils::packToU32(mColorAspects);
+ msg.u.event_data.data3 = pixelFormat;
+
+ mOMXNode->dispatchMessage(msg);
+ }
+}
+
+bool GraphicBufferSource::fillCodecBuffer_l() {
+ CHECK(mExecuting && mNumFramesAvailable > 0);
+
+ if (mSuspended && mActionQueue.empty()) {
+ return false;
+ }
+
+ int cbi = findAvailableCodecBuffer_l();
+ if (cbi < 0) {
+ // No buffers available, bail.
+ ALOGV("fillCodecBuffer_l: no codec buffers, avail now %zu",
+ mNumFramesAvailable);
+ return false;
+ }
+
+ ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%zu",
+ mNumFramesAvailable);
+ BufferItem item;
+ status_t err = acquireBuffer(&item);
+ if (err != OK) {
+ ALOGE("fillCodecBuffer_l: acquireBuffer returned err=%d", err);
+ return false;
+ }
+
+ int64_t itemTimeUs = item.mTimestamp / 1000;
+
+ mNumFramesAvailable--;
+
+ // Process ActionItem in the Queue if there is any. If a buffer's timestamp
+ // is smaller than the first action's timestamp, no action need to be performed.
+ // If buffer's timestamp is larger or equal than the last action's timestamp,
+ // only the last action needs to be performed as all the acitions before the
+ // the action are overridden by the last action. For the other cases, traverse
+ // the Queue to find the newest action that with timestamp smaller or equal to
+ // the buffer's timestamp. For example, an action queue like
+ // [pause, 1s], [resume 2us], [pause 3us], [resume 4us], [pause 5us].... Upon
+ // receiving a buffer with timestamp 3.5us, only the action [pause, 3us] needs
+ // to be handled and [pause, 1us], [resume 2us] will be discarded.
+ bool dropped = false;
+ bool done = false;
+ if (!mActionQueue.empty()) {
+ // First scan to check if bufferTimestamp is smaller than first action's timestamp.
+ ActionItem nextAction = *(mActionQueue.begin());
+ if (itemTimeUs < nextAction.mActionTimeUs) {
+ ALOGV("No action. buffer timestamp %lld us < action timestamp: %lld us",
+ (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
+ // All the actions are ahead. No action need to perform now.
+ // Release the buffer if is in suspended state, or process the buffer
+ // if not in suspended state.
+ dropped = mSuspended;
+ done = true;
+ }
+
+ if (!done) {
+ List<ActionItem>::iterator it = mActionQueue.begin();
+ while(it != mActionQueue.end()) {
+ nextAction = *it;
+ mActionQueue.erase(it);
+ if (nextAction.mActionTimeUs > itemTimeUs) {
+ break;
+ }
+ ++it;
+ }
+
+ CHECK(itemTimeUs >= nextAction.mActionTimeUs);
+ switch (nextAction.mAction) {
+ case ActionItem::PAUSE:
+ {
+ mSuspended = true;
+ dropped = true;
+ ALOGV("RUNNING/PAUSE -> PAUSE at buffer %lld us PAUSE Time: %lld us",
+ (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
+ break;
+ }
+ case ActionItem::RESUME:
+ {
+ mSuspended = false;
+ ALOGV("PAUSE/RUNNING -> RUNNING at buffer %lld us RESUME Time: %lld us",
+ (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
+ break;
+ }
+ case ActionItem::STOP:
+ {
+ ALOGV("RUNNING/PAUSE -> STOP at buffer %lld us STOP Time: %lld us",
+ (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
+ dropped = true;
+ // Clear the whole ActionQueue as recording is done
+ mActionQueue.clear();
+ submitEndOfInputStream_l();
+ break;
+ }
+ default:
+ ALOGE("Unknown action type");
+ return false;
+ }
+ }
+ }
+
+ if (dropped) {
+ releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
+ return true;
+ }
+
+ if (item.mDataSpace != mLastDataSpace) {
+ onDataSpaceChanged_l(
+ item.mDataSpace, (android_pixel_format)mBufferSlot[item.mSlot]->getPixelFormat());
+ }
+
+ err = UNKNOWN_ERROR;
+
+ // only submit sample if start time is unspecified, or sample
+ // is queued after the specified start time
+ if (mSkipFramesBeforeNs < 0ll || item.mTimestamp >= mSkipFramesBeforeNs) {
+ // if start time is set, offset time stamp by start time
+ if (mSkipFramesBeforeNs > 0) {
+ item.mTimestamp -= mSkipFramesBeforeNs;
+ }
+
+ int64_t timeUs = item.mTimestamp / 1000;
+ if (mFrameDropper != NULL && mFrameDropper->shouldDrop(timeUs)) {
+ ALOGV("skipping frame (%lld) to meet max framerate", static_cast<long long>(timeUs));
+ // set err to OK so that the skipped frame can still be saved as the lastest frame
+ err = OK;
+ dropped = true;
+ } else {
+ err = submitBuffer_l(item, cbi);
+ }
+ }
+
+ if (err != OK) {
+ ALOGV("submitBuffer_l failed, releasing bq slot %d", item.mSlot);
+ releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
+ } else {
+ // Don't set the last buffer id if we're not repeating,
+ // we'll be holding on to the last buffer for nothing.
+ if (mRepeatAfterUs > 0ll) {
+ setLatestBuffer_l(item);
+ }
+ if (!dropped) {
+ ++mBufferUseCount[item.mSlot];
+ }
+ ALOGV("buffer submitted: slot=%d, cbi=%d, useCount=%d, acquired=%d",
+ item.mSlot, cbi, mBufferUseCount[item.mSlot], mNumBufferAcquired);
+ }
+
+ return true;
+}
+
+bool GraphicBufferSource::repeatLatestBuffer_l() {
+ CHECK(mExecuting && mNumFramesAvailable == 0);
+
+ if (mLatestBufferId < 0 || mSuspended) {
+ return false;
+ }
+ if (mBufferSlot[mLatestBufferId] == NULL) {
+ // This can happen if the remote side disconnects, causing
+ // onBuffersReleased() to NULL out our copy of the slots. The
+ // buffer is gone, so we have nothing to show.
+ //
+ // To be on the safe side we try to release the buffer.
+ ALOGD("repeatLatestBuffer_l: slot was NULL");
+ mConsumer->releaseBuffer(
+ mLatestBufferId,
+ mLatestBufferFrameNum,
+ EGL_NO_DISPLAY,
+ EGL_NO_SYNC_KHR,
+ mLatestBufferFence);
+ mLatestBufferId = -1;
+ mLatestBufferFrameNum = 0;
+ mLatestBufferFence = Fence::NO_FENCE;
+ return false;
+ }
+
+ int cbi = findAvailableCodecBuffer_l();
+ if (cbi < 0) {
+ // No buffers available, bail.
+ ALOGV("repeatLatestBuffer_l: no codec buffers.");
+ return false;
+ }
+
+ BufferItem item;
+ item.mSlot = mLatestBufferId;
+ item.mFrameNumber = mLatestBufferFrameNum;
+ item.mTimestamp = mRepeatLastFrameTimestamp;
+ item.mFence = mLatestBufferFence;
+
+ status_t err = submitBuffer_l(item, cbi);
+
+ if (err != OK) {
+ return false;
+ }
+
+ ++mBufferUseCount[item.mSlot];
+
+ /* repeat last frame up to kRepeatLastFrameCount times.
+ * in case of static scene, a single repeat might not get rid of encoder
+ * ghosting completely, refresh a couple more times to get better quality
+ */
+ if (--mRepeatLastFrameCount > 0) {
+ mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
+
+ if (mReflector != NULL) {
+ sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector);
+ msg->setInt32("generation", ++mRepeatLastFrameGeneration);
+ msg->post(mRepeatAfterUs);
+ }
+ }
+
+ return true;
+}
+
+void GraphicBufferSource::setLatestBuffer_l(const BufferItem &item) {
+ if (mLatestBufferId >= 0 && mBufferUseCount[mLatestBufferId] == 0) {
+ releaseBuffer(mLatestBufferId, mLatestBufferFrameNum, mLatestBufferFence);
+ // mLatestBufferFence will be set to new fence just below
+ }
+
+ mLatestBufferId = item.mSlot;
+ mLatestBufferFrameNum = item.mFrameNumber;
+ mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
+
+ ALOGV("setLatestBuffer_l: slot=%d, useCount=%d",
+ item.mSlot, mBufferUseCount[item.mSlot]);
+
+ mRepeatBufferDeferred = false;
+ mRepeatLastFrameCount = kRepeatLastFrameCount;
+ mLatestBufferFence = item.mFence;
+
+ if (mReflector != NULL) {
+ sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector);
+ msg->setInt32("generation", ++mRepeatLastFrameGeneration);
+ msg->post(mRepeatAfterUs);
+ }
+}
+
+bool GraphicBufferSource::getTimestamp(
+ const BufferItem &item, int64_t *codecTimeUs) {
+ int64_t timeUs = item.mTimestamp / 1000;
+ timeUs += mInputBufferTimeOffsetUs;
+
+ if (mTimePerCaptureUs > 0ll
+ && (mTimePerCaptureUs > 2 * mTimePerFrameUs
+ || mTimePerFrameUs > 2 * mTimePerCaptureUs)) {
+ // Time lapse or slow motion mode
+ if (mPrevCaptureUs < 0ll) {
+ // first capture
+ mPrevCaptureUs = timeUs;
+ // adjust the first sample timestamp.
+ mPrevFrameUs = (timeUs * mTimePerFrameUs) / mTimePerCaptureUs;
+ } else {
+ // snap to nearest capture point
+ int64_t nFrames = (timeUs + mTimePerCaptureUs / 2 - mPrevCaptureUs)
+ / mTimePerCaptureUs;
+ if (nFrames <= 0) {
+ // skip this frame as it's too close to previous capture
+ ALOGV("skipping frame, timeUs %lld", static_cast<long long>(timeUs));
+ return false;
+ }
+ mPrevCaptureUs = mPrevCaptureUs + nFrames * mTimePerCaptureUs;
+ mPrevFrameUs += mTimePerFrameUs * nFrames;
+ }
+
+ ALOGV("timeUs %lld, captureUs %lld, frameUs %lld",
+ static_cast<long long>(timeUs),
+ static_cast<long long>(mPrevCaptureUs),
+ static_cast<long long>(mPrevFrameUs));
+
+ *codecTimeUs = mPrevFrameUs;
+ return true;
+ } else {
+ int64_t originalTimeUs = timeUs;
+ if (originalTimeUs <= mPrevOriginalTimeUs) {
+ // Drop the frame if it's going backward in time. Bad timestamp
+ // could disrupt encoder's rate control completely.
+ ALOGW("Dropping frame that's going backward in time");
+ return false;
+ }
+
+ mPrevOriginalTimeUs = originalTimeUs;
+ }
+
+ *codecTimeUs = timeUs;
+ return true;
+}
+
+status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {
+ ALOGV("submitBuffer_l: slot=%d, cbi=%d", item.mSlot, cbi);
+
+ int64_t codecTimeUs;
+ if (!getTimestamp(item, &codecTimeUs)) {
+ return UNKNOWN_ERROR;
+ }
+
+ CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
+ codecBuffer.mGraphicBuffer = mBufferSlot[item.mSlot];
+ codecBuffer.mSlot = item.mSlot;
+ codecBuffer.mFrameNumber = item.mFrameNumber;
+
+ IOMX::buffer_id bufferID = codecBuffer.mBufferID;
+ const sp<GraphicBuffer> &buffer = codecBuffer.mGraphicBuffer;
+ int fenceID = item.mFence->isValid() ? item.mFence->dup() : -1;
+
+ status_t err = mOMXNode->emptyBuffer(
+ bufferID, buffer, OMX_BUFFERFLAG_ENDOFFRAME, codecTimeUs, fenceID);
+
+ if (err != OK) {
+ ALOGW("WARNING: emptyGraphicBuffer failed: 0x%x", err);
+ codecBuffer.mGraphicBuffer = NULL;
+ return err;
+ }
+
+ ALOGV("emptyGraphicBuffer succeeded, bufferID=%u buf=%p bufhandle=%p",
+ bufferID, buffer->getNativeBuffer(), buffer->handle);
+ return OK;
+}
+
+void GraphicBufferSource::submitEndOfInputStream_l() {
+ CHECK(mEndOfStream);
+ if (mEndOfStreamSent) {
+ ALOGV("EOS already sent");
+ return;
+ }
+
+ int cbi = findAvailableCodecBuffer_l();
+ if (cbi < 0) {
+ ALOGV("submitEndOfInputStream_l: no codec buffers available");
+ return;
+ }
+
+ // We reject any additional incoming graphic buffers, so there's no need
+ // to stick a placeholder into codecBuffer.mGraphicBuffer to mark it as
+ // in-use.
+ CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
+ IOMX::buffer_id bufferID = codecBuffer.mBufferID;
+
+ status_t err = mOMXNode->emptyBuffer(
+ bufferID, (sp<GraphicBuffer>)NULL,
+ OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS,
+ 0 /* timestamp */, -1 /* fenceFd */);
+ if (err != OK) {
+ ALOGW("emptyDirectBuffer EOS failed: 0x%x", err);
+ } else {
+ ALOGV("submitEndOfInputStream_l: buffer submitted, bufferID=%u cbi=%d",
+ bufferID, cbi);
+ mEndOfStreamSent = true;
+ }
+}
+
+int GraphicBufferSource::findAvailableCodecBuffer_l() {
+ CHECK(mCodecBuffers.size() > 0);
+
+ for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) {
+ if (mCodecBuffers[i].mGraphicBuffer == NULL) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int GraphicBufferSource::findMatchingCodecBuffer_l(IOMX::buffer_id bufferID) {
+ for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) {
+ if (mCodecBuffers[i].mBufferID == bufferID) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+status_t GraphicBufferSource::acquireBuffer(BufferItem *bi) {
+ status_t err = mConsumer->acquireBuffer(bi, 0);
+ if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+ // shouldn't happen
+ ALOGW("acquireBuffer: frame was not available");
+ return err;
+ } else if (err != OK) {
+ ALOGW("acquireBuffer: failed with err=%d", err);
+ return err;
+ }
+ // If this is the first time we're seeing this buffer, add it to our
+ // slot table.
+ if (bi->mGraphicBuffer != NULL) {
+ ALOGV("acquireBuffer: setting mBufferSlot %d", bi->mSlot);
+ mBufferSlot[bi->mSlot] = bi->mGraphicBuffer;
+ mBufferUseCount[bi->mSlot] = 0;
+ }
+ mNumBufferAcquired++;
+ return OK;
+}
+
+/*
+ * Releases an acquired buffer back to the consumer.
+ *
+ * id: buffer slot to release
+ * frameNum: frame number of the frame being released
+ * fence: fence of the frame being released
+ */
+void GraphicBufferSource::releaseBuffer(
+ int id, uint64_t frameNum, const sp<Fence> &fence) {
+ ALOGV("releaseBuffer: slot=%d", id);
+ mConsumer->releaseBuffer(
+ id, frameNum, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, fence);
+ mNumBufferAcquired--;
+}
+
+// BufferQueue::ConsumerListener callback
+void GraphicBufferSource::onFrameAvailable(const BufferItem& /*item*/) {
+ Mutex::Autolock autoLock(mMutex);
+
+ ALOGV("onFrameAvailable exec=%d avail=%zu",
+ mExecuting, mNumFramesAvailable);
+
+ if (mOMXNode == NULL || mEndOfStreamSent || (mSuspended && mActionQueue.empty())) {
+ if (mEndOfStreamSent) {
+ // This should only be possible if a new buffer was queued after
+ // EOS was signaled, i.e. the app is misbehaving.
+
+ ALOGW("onFrameAvailable: EOS is sent, ignoring frame");
+ } else {
+ ALOGV("onFrameAvailable: suspended, ignoring frame");
+ }
+
+ BufferItem item;
+ status_t err = acquireBuffer(&item);
+ if (err == OK) {
+ releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
+ } else {
+ ALOGE("onFrameAvailable: acquireBuffer returned err=%d", err);
+ }
+ return;
+ }
+
+ mNumFramesAvailable++;
+
+ mRepeatBufferDeferred = false;
+ ++mRepeatLastFrameGeneration;
+
+ if (mExecuting) {
+ fillCodecBuffer_l();
+ }
+}
+
+// BufferQueue::ConsumerListener callback
+void GraphicBufferSource::onBuffersReleased() {
+ Mutex::Autolock lock(mMutex);
+
+ uint64_t slotMask;
+ if (mConsumer->getReleasedBuffers(&slotMask) != NO_ERROR) {
+ ALOGW("onBuffersReleased: unable to get released buffer set");
+ slotMask = 0xffffffffffffffffULL;
+ }
+
+ ALOGV("onBuffersReleased: 0x%016" PRIx64, slotMask);
+
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ if ((slotMask & 0x01) != 0) {
+ // Last buffer (if set) is always acquired even if its use count
+ // is 0, because we could have skipped that frame but kept it for
+ // repeating. Otherwise a buffer is only acquired if use count>0.
+ if (mBufferSlot[i] != NULL &&
+ (mBufferUseCount[i] > 0 || mLatestBufferId == i)) {
+ ALOGV("releasing acquired buffer: slot=%d, useCount=%d, latest=%d",
+ i, mBufferUseCount[i], mLatestBufferId);
+ mNumBufferAcquired--;
+ }
+ if (mLatestBufferId == i) {
+ mLatestBufferId = -1;
+ }
+ mBufferSlot[i] = NULL;
+ mBufferUseCount[i] = 0;
+ }
+ slotMask >>= 1;
+ }
+}
+
+// BufferQueue::ConsumerListener callback
+void GraphicBufferSource::onSidebandStreamChanged() {
+ ALOG_ASSERT(false, "GraphicBufferSource can't consume sideband streams");
+}
+
+Status GraphicBufferSource::configure(
+ const sp<IOMXNode>& omxNode, int32_t dataSpace) {
+ if (omxNode == NULL) {
+ return Status::fromServiceSpecificError(BAD_VALUE);
+ }
+
+ // Do setInputSurface() first, the node will try to enable metadata
+ // mode on input, and does necessary error checking. If this fails,
+ // we can't use this input surface on the node.
+ status_t err = omxNode->setInputSurface(mOmxBufferSource);
+ if (err != NO_ERROR) {
+ ALOGE("Unable to set input surface: %d", err);
+ return Status::fromServiceSpecificError(err);
+ }
+
+ // use consumer usage bits queried from encoder, but always add
+ // HW_VIDEO_ENCODER for backward compatibility.
+ uint32_t consumerUsage;
+ if (omxNode->getParameter(
+ (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
+ &consumerUsage, sizeof(consumerUsage)) != OK) {
+ consumerUsage = 0;
+ }
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = kPortIndexInput;
+
+ err = omxNode->getParameter(
+ OMX_IndexParamPortDefinition, &def, sizeof(def));
+ if (err != NO_ERROR) {
+ ALOGE("Failed to get port definition: %d", err);
+ return Status::fromServiceSpecificError(UNKNOWN_ERROR);
+ }
+
+ // Call setMaxAcquiredBufferCount without lock.
+ // setMaxAcquiredBufferCount could call back to onBuffersReleased
+ // if the buffer count change results in releasing of existing buffers,
+ // which would lead to deadlock.
+ err = mConsumer->setMaxAcquiredBufferCount(def.nBufferCountActual);
+ if (err != NO_ERROR) {
+ ALOGE("Unable to set BQ max acquired buffer count to %u: %d",
+ def.nBufferCountActual, err);
+ return Status::fromServiceSpecificError(err);
+ }
+
+ {
+ Mutex::Autolock autoLock(mMutex);
+ mOMXNode = omxNode;
+
+ err = mConsumer->setDefaultBufferSize(
+ def.format.video.nFrameWidth,
+ def.format.video.nFrameHeight);
+ if (err != NO_ERROR) {
+ ALOGE("Unable to set BQ default buffer size to %ux%u: %d",
+ def.format.video.nFrameWidth,
+ def.format.video.nFrameHeight,
+ err);
+ return Status::fromServiceSpecificError(err);
+ }
+
+ consumerUsage |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
+ mConsumer->setConsumerUsageBits(consumerUsage);
+
+ // Sets the default buffer data space
+ ALOGD("setting dataspace: %#x, acquired=%d", dataSpace, mNumBufferAcquired);
+ mConsumer->setDefaultBufferDataSpace((android_dataspace)dataSpace);
+ mLastDataSpace = (android_dataspace)dataSpace;
+
+ mExecuting = false;
+ mSuspended = false;
+ mEndOfStream = false;
+ mEndOfStreamSent = false;
+ mPrevOriginalTimeUs = -1ll;
+ mSkipFramesBeforeNs = -1ll;
+ mRepeatAfterUs = -1ll;
+ mRepeatLastFrameGeneration = 0;
+ mRepeatLastFrameTimestamp = -1ll;
+ mRepeatLastFrameCount = 0;
+ mLatestBufferId = -1;
+ mLatestBufferFrameNum = 0;
+ mLatestBufferFence = Fence::NO_FENCE;
+ mRepeatBufferDeferred = false;
+ mTimePerCaptureUs = -1ll;
+ mTimePerFrameUs = -1ll;
+ mPrevCaptureUs = -1ll;
+ mPrevFrameUs = -1ll;
+ mInputBufferTimeOffsetUs = 0;
+ mStopTimeUs = -1;
+ mActionQueue.clear();
+ }
+
+ return Status::ok();
+}
+
+Status GraphicBufferSource::setSuspend(bool suspend, int64_t suspendStartTimeUs) {
+ ALOGV("setSuspend=%d at time %lld us", suspend, (long long)suspendStartTimeUs);
+
+ Mutex::Autolock autoLock(mMutex);
+
+ if (mStopTimeUs != -1) {
+ ALOGE("setSuspend failed as STOP action is pending");
+ return Status::fromServiceSpecificError(INVALID_OPERATION);
+ }
+
+ // Push the action to the queue.
+ if (suspendStartTimeUs != -1) {
+ // suspendStartTimeUs must be smaller or equal to current systemTime.
+ int64_t currentSystemTimeUs = systemTime() / 1000;
+ if (suspendStartTimeUs > currentSystemTimeUs) {
+ ALOGE("setSuspend failed. %lld is larger than current system time %lld us",
+ (long long)suspendStartTimeUs, (long long)currentSystemTimeUs);
+ return Status::fromServiceSpecificError(INVALID_OPERATION);
+ }
+ if (mLastActionTimeUs != -1 && suspendStartTimeUs < mLastActionTimeUs) {
+ ALOGE("setSuspend failed. %lld is smaller than last action time %lld us",
+ (long long)suspendStartTimeUs, (long long)mLastActionTimeUs);
+ return Status::fromServiceSpecificError(INVALID_OPERATION);
+ }
+ mLastActionTimeUs = suspendStartTimeUs;
+ ActionItem action;
+ action.mAction = suspend ? ActionItem::PAUSE : ActionItem::RESUME;
+ action.mActionTimeUs = suspendStartTimeUs;
+ ALOGV("Push %s action into actionQueue", suspend ? "PAUSE" : "RESUME");
+ mActionQueue.push_back(action);
+ } else {
+ if (suspend) {
+ mSuspended = true;
+
+ while (mNumFramesAvailable > 0) {
+ BufferItem item;
+ status_t err = acquireBuffer(&item);
+
+ if (err != OK) {
+ ALOGE("setSuspend: acquireBuffer returned err=%d", err);
+ break;
+ }
+
+ --mNumFramesAvailable;
+
+ releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
+ }
+ return Status::ok();
+ } else {
+
+ mSuspended = false;
+
+ if (mExecuting && mNumFramesAvailable == 0 && mRepeatBufferDeferred) {
+ if (repeatLatestBuffer_l()) {
+ ALOGV("suspend/deferred repeatLatestBuffer_l SUCCESS");
+
+ mRepeatBufferDeferred = false;
+ } else {
+ ALOGV("suspend/deferred repeatLatestBuffer_l FAILURE");
+ }
+ }
+ }
+ }
+ return Status::ok();
+}
+
+Status GraphicBufferSource::setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) {
+ ALOGV("setRepeatPreviousFrameDelayUs: delayUs=%lld", (long long)repeatAfterUs);
+
+ Mutex::Autolock autoLock(mMutex);
+
+ if (mExecuting || repeatAfterUs <= 0ll) {
+ return Status::fromServiceSpecificError(INVALID_OPERATION);
+ }
+
+ mRepeatAfterUs = repeatAfterUs;
+ return Status::ok();
+}
+
+Status GraphicBufferSource::setTimeOffsetUs(int64_t timeOffsetUs) {
+ Mutex::Autolock autoLock(mMutex);
+
+ // timeOffsetUs must be negative for adjustment.
+ if (timeOffsetUs >= 0ll) {
+ return Status::fromServiceSpecificError(INVALID_OPERATION);
+ }
+
+ mInputBufferTimeOffsetUs = timeOffsetUs;
+ return Status::ok();
+}
+
+Status GraphicBufferSource::setMaxFps(float maxFps) {
+ ALOGV("setMaxFps: maxFps=%lld", (long long)maxFps);
+
+ Mutex::Autolock autoLock(mMutex);
+
+ if (mExecuting) {
+ return Status::fromServiceSpecificError(INVALID_OPERATION);
+ }
+
+ mFrameDropper = new FrameDropper();
+ status_t err = mFrameDropper->setMaxFrameRate(maxFps);
+ if (err != OK) {
+ mFrameDropper.clear();
+ return Status::fromServiceSpecificError(err);
+ }
+
+ return Status::ok();
+}
+
+Status GraphicBufferSource::setStartTimeUs(int64_t skipFramesBeforeUs) {
+ ALOGV("setStartTimeUs: skipFramesBeforeUs=%lld", (long long)skipFramesBeforeUs);
+
+ Mutex::Autolock autoLock(mMutex);
+
+ mSkipFramesBeforeNs =
+ (skipFramesBeforeUs > 0) ? (skipFramesBeforeUs * 1000) : -1ll;
+
+ return Status::ok();
+}
+
+Status GraphicBufferSource::setStopTimeUs(int64_t stopTimeUs) {
+ ALOGV("setStopTimeUs: %lld us", (long long)stopTimeUs);
+ Mutex::Autolock autoLock(mMutex);
+
+ if (mStopTimeUs != -1) {
+ // Ignore if stop time has already been set
+ return Status::ok();
+ }
+
+ // stopTimeUs must be smaller or equal to current systemTime.
+ int64_t currentSystemTimeUs = systemTime() / 1000;
+ if (stopTimeUs > currentSystemTimeUs) {
+ ALOGE("setStopTimeUs failed. %lld is larger than current system time %lld us",
+ (long long)stopTimeUs, (long long)currentSystemTimeUs);
+ return Status::fromServiceSpecificError(INVALID_OPERATION);
+ }
+ if (mLastActionTimeUs != -1 && stopTimeUs < mLastActionTimeUs) {
+ ALOGE("setSuspend failed. %lld is smaller than last action time %lld us",
+ (long long)stopTimeUs, (long long)mLastActionTimeUs);
+ return Status::fromServiceSpecificError(INVALID_OPERATION);
+ }
+ mLastActionTimeUs = stopTimeUs;
+ ActionItem action;
+ action.mAction = ActionItem::STOP;
+ action.mActionTimeUs = stopTimeUs;
+ mActionQueue.push_back(action);
+ mStopTimeUs = stopTimeUs;
+ return Status::ok();
+}
+
+Status GraphicBufferSource::setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) {
+ ALOGV("setTimeLapseConfig: timePerFrameUs=%lld, timePerCaptureUs=%lld",
+ (long long)timePerFrameUs, (long long)timePerCaptureUs);
+
+ Mutex::Autolock autoLock(mMutex);
+
+ if (mExecuting || timePerFrameUs <= 0ll || timePerCaptureUs <= 0ll) {
+ return Status::fromServiceSpecificError(INVALID_OPERATION);
+ }
+
+ mTimePerFrameUs = timePerFrameUs;
+ mTimePerCaptureUs = timePerCaptureUs;
+
+ return Status::ok();
+}
+
+Status GraphicBufferSource::setColorAspects(int32_t aspectsPacked) {
+ Mutex::Autolock autoLock(mMutex);
+ mColorAspects = ColorUtils::unpackToColorAspects(aspectsPacked);
+ ALOGD("requesting color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s))",
+ mColorAspects.mRange, asString(mColorAspects.mRange),
+ mColorAspects.mPrimaries, asString(mColorAspects.mPrimaries),
+ mColorAspects.mMatrixCoeffs, asString(mColorAspects.mMatrixCoeffs),
+ mColorAspects.mTransfer, asString(mColorAspects.mTransfer));
+
+ return Status::ok();
+}
+
+Status GraphicBufferSource::signalEndOfInputStream() {
+ Mutex::Autolock autoLock(mMutex);
+ ALOGV("signalEndOfInputStream: exec=%d avail=%zu eos=%d",
+ mExecuting, mNumFramesAvailable, mEndOfStream);
+
+ if (mEndOfStream) {
+ ALOGE("EOS was already signaled");
+ return Status::fromStatusT(INVALID_OPERATION);
+ }
+
+ // Set the end-of-stream flag. If no frames are pending from the
+ // BufferQueue, and a codec buffer is available, and we're executing,
+ // and there is no stop timestamp, we initiate the EOS from here.
+ // Otherwise, we'll let codecBufferEmptied() (or omxExecuting) do it.
+ //
+ // Note: if there are no pending frames and all codec buffers are
+ // available, we *must* submit the EOS from here or we'll just
+ // stall since no future events are expected.
+ mEndOfStream = true;
+
+ if (mStopTimeUs == -1 && mExecuting && mNumFramesAvailable == 0) {
+ submitEndOfInputStream_l();
+ }
+
+ return Status::ok();
+}
+
+void GraphicBufferSource::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatRepeatLastFrame:
+ {
+ Mutex::Autolock autoLock(mMutex);
+
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+
+ if (generation != mRepeatLastFrameGeneration) {
+ // stale
+ break;
+ }
+
+ if (!mExecuting || mNumFramesAvailable > 0) {
+ break;
+ }
+
+ bool success = repeatLatestBuffer_l();
+
+ if (success) {
+ ALOGV("repeatLatestBuffer_l SUCCESS");
+ } else {
+ ALOGV("repeatLatestBuffer_l FAILURE");
+ mRepeatBufferDeferred = true;
+ }
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+}
+
+} // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.h b/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.h
new file mode 100644
index 0000000..475548e
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.h
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef GRAPHIC_BUFFER_SOURCE_H_
+
+#define GRAPHIC_BUFFER_SOURCE_H_
+
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/BufferQueue.h>
+#include <utils/RefBase.h>
+
+#include <VideoAPI.h>
+#include <media/IOMX.h>
+#include <media/OMXFenceParcelable.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
+#include <media/stagefright/foundation/ALooper.h>
+
+#include <android/BnGraphicBufferSource.h>
+#include <android/BnOMXBufferSource.h>
+
+namespace android {
+
+using ::android::binder::Status;
+
+struct FrameDropper;
+
+/*
+ * This class is used to feed OMX codecs from a Surface via BufferQueue.
+ *
+ * Instances of the class don't run on a dedicated thread. Instead,
+ * various events trigger data movement:
+ *
+ * - Availability of a new frame of data from the BufferQueue (notified
+ * via the onFrameAvailable callback).
+ * - The return of a codec buffer (via OnEmptyBufferDone).
+ * - Application signaling end-of-stream.
+ * - Transition to or from "executing" state.
+ *
+ * Frames of data (and, perhaps, the end-of-stream indication) can arrive
+ * before the codec is in the "executing" state, so we need to queue
+ * things up until we're ready to go.
+ */
+class GraphicBufferSource : public BnGraphicBufferSource,
+ public BufferQueue::ConsumerListener {
+public:
+ GraphicBufferSource();
+
+ virtual ~GraphicBufferSource();
+
+ // We can't throw an exception if the constructor fails, so we just set
+ // this and require that the caller test the value.
+ status_t initCheck() const {
+ return mInitCheck;
+ }
+
+ // Returns the handle to the producer side of the BufferQueue. Buffers
+ // queued on this will be received by GraphicBufferSource.
+ sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
+ return mProducer;
+ }
+
+ // This is called when OMX transitions to OMX_StateExecuting, which means
+ // we can start handing it buffers. If we already have buffers of data
+ // sitting in the BufferQueue, this will send them to the codec.
+ Status onOmxExecuting();
+
+ // This is called when OMX transitions to OMX_StateIdle, indicating that
+ // the codec is meant to return all buffers back to the client for them
+ // to be freed. Do NOT submit any more buffers to the component.
+ Status onOmxIdle();
+
+ // This is called when OMX transitions to OMX_StateLoaded, indicating that
+ // we are shutting down.
+ Status onOmxLoaded();
+
+ // A "codec buffer", i.e. a buffer that can be used to pass data into
+ // the encoder, has been allocated. (This call does not call back into
+ // OMXNodeInstance.)
+ Status onInputBufferAdded(int32_t bufferID);
+
+ // Called from OnEmptyBufferDone. If we have a BQ buffer available,
+ // fill it with a new frame of data; otherwise, just mark it as available.
+ Status onInputBufferEmptied(
+ int32_t bufferID, const OMXFenceParcelable& fenceParcel);
+
+ // Configure the buffer source to be used with an OMX node with the default
+ // data space.
+ Status configure(const sp<IOMXNode>& omxNode, int32_t dataSpace) override;
+
+ // This is called after the last input frame has been submitted or buffer
+ // timestamp is greater or equal than stopTimeUs. We need to submit an empty
+ // buffer with the EOS flag set. If we don't have a codec buffer ready,
+ // we just set the mEndOfStream flag.
+ Status signalEndOfInputStream() override;
+
+ // If suspend is true, all incoming buffers (including those currently
+ // in the BufferQueue) with timestamp larger than timeUs will be discarded
+ // until the suspension is lifted. If suspend is false, all incoming buffers
+ // including those currently in the BufferQueue) with timestamp larger than
+ // timeUs will be processed. timeUs uses SYSTEM_TIME_MONOTONIC time base.
+ Status setSuspend(bool suspend, int64_t timeUs) override;
+
+ // Specifies the interval after which we requeue the buffer previously
+ // queued to the encoder. This is useful in the case of surface flinger
+ // providing the input surface if the resulting encoded stream is to
+ // be displayed "live". If we were not to push through the extra frame
+ // the decoder on the remote end would be unable to decode the latest frame.
+ // This API must be called before transitioning the encoder to "executing"
+ // state and once this behaviour is specified it cannot be reset.
+ Status setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override;
+
+ // Sets the input buffer timestamp offset.
+ // When set, the sample's timestamp will be adjusted with the timeOffsetUs.
+ Status setTimeOffsetUs(int64_t timeOffsetUs) override;
+
+ // When set, the max frame rate fed to the encoder will be capped at maxFps.
+ Status setMaxFps(float maxFps) override;
+
+ // Sets the time lapse (or slow motion) parameters.
+ // When set, the sample's timestamp will be modified to playback framerate,
+ // and capture timestamp will be modified to capture rate.
+ Status setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) override;
+
+ // Sets the start time us (in system time), samples before which should
+ // be dropped and not submitted to encoder
+ Status setStartTimeUs(int64_t startTimeUs) override;
+
+ // Sets the stop time us (in system time), samples after which should be dropped
+ // and not submitted to encoder. timeUs uses SYSTEM_TIME_MONOTONIC time base.
+ Status setStopTimeUs(int64_t stopTimeUs) override;
+
+ // Sets the desired color aspects, e.g. to be used when producer does not specify a dataspace.
+ Status setColorAspects(int32_t aspectsPacked) override;
+
+protected:
+ // BufferQueue::ConsumerListener interface, called when a new frame of
+ // data is available. If we're executing and a codec buffer is
+ // available, we acquire the buffer, copy the GraphicBuffer reference
+ // into the codec buffer, and call Empty[This]Buffer. If we're not yet
+ // executing or there's no codec buffer available, we just increment
+ // mNumFramesAvailable and return.
+ void onFrameAvailable(const BufferItem& item) override;
+
+ // BufferQueue::ConsumerListener interface, called when the client has
+ // released one or more GraphicBuffers. We clear out the appropriate
+ // set of mBufferSlot entries.
+ void onBuffersReleased() override;
+
+ // BufferQueue::ConsumerListener interface, called when the client has
+ // changed the sideband stream. GraphicBufferSource doesn't handle sideband
+ // streams so this is a no-op (and should never be called).
+ void onSidebandStreamChanged() override;
+
+private:
+
+ // Keep track of codec input buffers. They may either be available
+ // (mGraphicBuffer == NULL) or in use by the codec.
+ struct CodecBuffer {
+ IOMX::buffer_id mBufferID;
+
+ // buffer producer's frame-number for buffer
+ uint64_t mFrameNumber;
+
+ // buffer producer's buffer slot for buffer
+ int mSlot;
+
+ sp<GraphicBuffer> mGraphicBuffer;
+ };
+
+ // Returns the index of an available codec buffer. If none are
+ // available, returns -1. Mutex must be held by caller.
+ int findAvailableCodecBuffer_l();
+
+ // Returns true if a codec buffer is available.
+ bool isCodecBufferAvailable_l() {
+ return findAvailableCodecBuffer_l() >= 0;
+ }
+
+ // Finds the mCodecBuffers entry that matches. Returns -1 if not found.
+ int findMatchingCodecBuffer_l(IOMX::buffer_id bufferID);
+
+ // Fills a codec buffer with a frame from the BufferQueue. This must
+ // only be called when we know that a frame of data is ready (i.e. we're
+ // in the onFrameAvailable callback, or if we're in codecBufferEmptied
+ // and mNumFramesAvailable is nonzero). Returns without doing anything if
+ // we don't have a codec buffer available.
+ //
+ // Returns true if we successfully filled a codec buffer with a BQ buffer.
+ bool fillCodecBuffer_l();
+
+ // Marks the mCodecBuffers entry as in-use, copies the GraphicBuffer
+ // reference into the codec buffer, and submits the data to the codec.
+ status_t submitBuffer_l(const BufferItem &item, int cbi);
+
+ // Submits an empty buffer, with the EOS flag set. Returns without
+ // doing anything if we don't have a codec buffer available.
+ void submitEndOfInputStream_l();
+
+ // Acquire buffer from the consumer
+ status_t acquireBuffer(BufferItem *bi);
+
+ // Release buffer to the consumer
+ void releaseBuffer(int id, uint64_t frameNum, const sp<Fence> &fence);
+
+ void setLatestBuffer_l(const BufferItem &item);
+ bool repeatLatestBuffer_l();
+ bool getTimestamp(const BufferItem &item, int64_t *codecTimeUs);
+
+ // called when the data space of the input buffer changes
+ void onDataSpaceChanged_l(android_dataspace dataSpace, android_pixel_format pixelFormat);
+
+ // Lock, covers all member variables.
+ mutable Mutex mMutex;
+
+ // Used to report constructor failure.
+ status_t mInitCheck;
+
+ // Pointer back to the IOMXNode that created us. We send buffers here.
+ sp<IOMXNode> mOMXNode;
+
+ // Set by omxExecuting() / omxIdling().
+ bool mExecuting;
+
+ bool mSuspended;
+
+ // The time to stop sending buffers.
+ int64_t mStopTimeUs;
+
+ // Last dataspace seen
+ android_dataspace mLastDataSpace;
+
+ // Our BufferQueue interfaces. mProducer is passed to the producer through
+ // getIGraphicBufferProducer, and mConsumer is used internally to retrieve
+ // the buffers queued by the producer.
+ sp<IGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferConsumer> mConsumer;
+
+ // Number of frames pending in BufferQueue that haven't yet been
+ // forwarded to the codec.
+ size_t mNumFramesAvailable;
+
+ // Number of frames acquired from consumer (debug only)
+ int32_t mNumBufferAcquired;
+
+ // Set to true if we want to send end-of-stream after we run out of
+ // frames in BufferQueue.
+ bool mEndOfStream;
+ bool mEndOfStreamSent;
+
+ // Cache of GraphicBuffers from the buffer queue. When the codec
+ // is done processing a GraphicBuffer, we can use this to map back
+ // to a slot number.
+ sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
+ int32_t mBufferUseCount[BufferQueue::NUM_BUFFER_SLOTS];
+
+ // Tracks codec buffers.
+ Vector<CodecBuffer> mCodecBuffers;
+
+ struct ActionItem {
+ typedef enum {
+ PAUSE,
+ RESUME,
+ STOP
+ } ActionType;
+ ActionType mAction;
+ int64_t mActionTimeUs;
+ };
+
+ // Maintain last action timestamp to ensure all the action timestamps are
+ // monotonically increasing.
+ int64_t mLastActionTimeUs;
+
+ // An action queue that queue up all the actions sent to GraphicBufferSource.
+ // STOP action should only show up at the end of the list as all the actions
+ // after a STOP action will be discarded. mActionQueue is protected by mMutex.
+ List<ActionItem> mActionQueue;
+
+ ////
+ friend struct AHandlerReflector<GraphicBufferSource>;
+
+ enum {
+ kWhatRepeatLastFrame,
+ };
+ enum {
+ kRepeatLastFrameCount = 10,
+ };
+
+ int64_t mPrevOriginalTimeUs;
+ int64_t mSkipFramesBeforeNs;
+
+ sp<FrameDropper> mFrameDropper;
+
+ sp<ALooper> mLooper;
+ sp<AHandlerReflector<GraphicBufferSource> > mReflector;
+
+ int64_t mRepeatAfterUs;
+ int32_t mRepeatLastFrameGeneration;
+ int64_t mRepeatLastFrameTimestamp;
+ int32_t mRepeatLastFrameCount;
+
+ int mLatestBufferId;
+ uint64_t mLatestBufferFrameNum;
+ sp<Fence> mLatestBufferFence;
+
+ // The previous buffer should've been repeated but
+ // no codec buffer was available at the time.
+ bool mRepeatBufferDeferred;
+
+ // Time lapse / slow motion configuration
+ int64_t mTimePerCaptureUs;
+ int64_t mTimePerFrameUs;
+ int64_t mPrevCaptureUs;
+ int64_t mPrevFrameUs;
+
+ int64_t mInputBufferTimeOffsetUs;
+
+ ColorAspects mColorAspects;
+
+ class OmxBufferSource;
+ sp<OmxBufferSource> mOmxBufferSource;
+
+ void onMessageReceived(const sp<AMessage> &msg);
+
+ DISALLOW_EVIL_CONSTRUCTORS(GraphicBufferSource);
+};
+
+} // namespace android
+
+#endif // GRAPHIC_BUFFER_SOURCE_H_
diff --git a/media/libstagefright/omx/hal/1.0/impl/Omx.cpp b/media/libstagefright/omx/hal/1.0/impl/Omx.cpp
index eddcc77..a9f29e9 100644
--- a/media/libstagefright/omx/hal/1.0/impl/Omx.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/Omx.cpp
@@ -14,17 +14,17 @@
* limitations under the License.
*/
+#include <ios>
#include <list>
-#include "Omx.h"
-#include <IOMX.h>
-#include <OMXMaster.h>
-#include <OMXNodeInstance.h>
-#include <GraphicBufferSource.h>
+#include <android-base/logging.h>
#include <gui/IGraphicBufferProducer.h>
-
+#include <OMX_Core.h>
#include <OMX_AsString.h>
-#include <OMXUtils.h>
+
+#include "../../../OMXUtils.h"
+#include "../../../OMXMaster.h"
+#include "../../../GraphicBufferSource.h"
#include "WOmxNode.h"
#include "WOmxObserver.h"
@@ -32,6 +32,8 @@
#include "WGraphicBufferSource.h"
#include "Conversion.h"
+#include "Omx.h"
+
namespace android {
namespace hardware {
namespace media {
@@ -102,9 +104,10 @@
instance.get(), &handle);
if (err != OMX_ErrorNone) {
- ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)",
- name.c_str(), asString(err), err);
-
+ LOG(ERROR) << "Failed to allocate omx component "
+ "'" << name.c_str() << "' "
+ " err=" << asString(err) <<
+ "(0x" << std::hex << unsigned(err) << ")";
_hidl_cb(toStatus(StatusFromOMXError(err)), nullptr);
return Void();
}
@@ -125,8 +128,9 @@
sp<GraphicBufferSource> graphicBufferSource = new GraphicBufferSource();
status_t err = graphicBufferSource->initCheck();
if (err != OK) {
- ALOGE("Failed to create persistent input surface: %s (%d)",
- strerror(-err), err);
+ LOG(ERROR) << "Failed to create persistent input surface: "
+ << strerror(-err) << " "
+ "(" << int(err) << ")";
_hidl_cb(toStatus(err), nullptr, nullptr);
return Void();
}
@@ -147,7 +151,7 @@
ssize_t index = mLiveNodes.indexOfKey(who);
if (index < 0) {
- ALOGE("b/27597103, nonexistent observer on serviceDied");
+ LOG(ERROR) << "b/27597103, nonexistent observer on serviceDied";
android_errorWriteLog(0x534e4554, "27597103");
return;
}
diff --git a/media/libstagefright/omx/hal/1.0/impl/Omx.h b/media/libstagefright/omx/hal/1.0/impl/Omx.h
index 7633820..3e9ea73 100644
--- a/media/libstagefright/omx/hal/1.0/impl/Omx.h
+++ b/media/libstagefright/omx/hal/1.0/impl/Omx.h
@@ -17,13 +17,12 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMX_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMX_H
-#include <android/hardware/media/omx/1.0/IOmx.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
-#include <OmxNodeOwner.h>
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
namespace android {
diff --git a/media/libstagefright/omx/hal/1.0/impl/OmxNode.cpp b/media/libstagefright/omx/hal/1.0/impl/OmxNode.cpp
deleted file mode 100644
index f62269f..0000000
--- a/media/libstagefright/omx/hal/1.0/impl/OmxNode.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2016, The Android Open Source Project
- *
- * 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 <IOMX.h>
-#include <OMXNodeInstance.h>
-#include "OmxNode.h"
-#include "WOmxNode.h"
-#include "WOmxObserver.h"
-#include "Conversion.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace omx {
-namespace V1_0 {
-namespace implementation {
-
-// Methods from ::android::hardware::media::omx::V1_0::IOmxNode follow.
-Return<Status> OmxNode::freeNode() {
- // TODO implement
- return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> OmxNode::sendCommand(uint32_t cmd, int32_t param) {
- // TODO implement
- return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<void> OmxNode::getParameter(uint32_t index, const hidl_vec<uint8_t>& inParams, getParameter_cb _hidl_cb) {
- // TODO implement
- return Void();
-}
-
-Return<Status> OmxNode::setParameter(uint32_t index, const hidl_vec<uint8_t>& params) {
- // TODO implement
- return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<void> OmxNode::getConfig(uint32_t index, const hidl_vec<uint8_t>& inConfig, getConfig_cb _hidl_cb) {
- // TODO implement
- return Void();
-}
-
-Return<Status> OmxNode::setConfig(uint32_t index, const hidl_vec<uint8_t>& config) {
- // TODO implement
- return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> OmxNode::setPortMode(uint32_t portIndex, PortMode mode) {
- // TODO implement
- return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> OmxNode::prepareForAdaptivePlayback(uint32_t portIndex, bool enable, uint32_t maxFrameWidth, uint32_t maxFrameHeight) {
- // TODO implement
- return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<void> OmxNode::configureVideoTunnelMode(uint32_t portIndex, bool tunneled, uint32_t audioHwSync, configureVideoTunnelMode_cb _hidl_cb) {
- // TODO implement
- return Void();
-}
-
-Return<void> OmxNode::getGraphicBufferUsage(uint32_t portIndex, getGraphicBufferUsage_cb _hidl_cb) {
- // TODO implement
- return Void();
-}
-
-Return<Status> OmxNode::setInputSurface(const sp<IOmxBufferSource>& bufferSource) {
- // TODO implement
- return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<void> OmxNode::allocateSecureBuffer(uint32_t portIndex, uint64_t size, allocateSecureBuffer_cb _hidl_cb) {
- // TODO implement
- return Void();
-}
-
-Return<void> OmxNode::useBuffer(uint32_t portIndex, const CodecBuffer& omxBuffer, useBuffer_cb _hidl_cb) {
- // TODO implement
- return Void();
-}
-
-Return<Status> OmxNode::freeBuffer(uint32_t portIndex, uint32_t buffer) {
- // TODO implement
- return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> OmxNode::fillBuffer(uint32_t buffer, const CodecBuffer& omxBuffer, const hidl_handle& fence) {
- // TODO implement
- return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> OmxNode::emptyBuffer(uint32_t buffer, const CodecBuffer& omxBuffer, uint32_t flags, uint64_t timestampUs, const hidl_handle& fence) {
- // TODO implement
- return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<void> OmxNode::getExtensionIndex(const hidl_string& parameterName, getExtensionIndex_cb _hidl_cb) {
- // TODO implement
- return Void();
-}
-
-Return<Status> OmxNode::dispatchMessage(const Message& msg) {
- // TODO implement
- return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-OmxNode::OmxNode(OmxNodeOwner* owner, sp<IOmxObserver> const& observer, char const* name) {
- mLNode = new OMXNodeInstance(owner, new LWOmxObserver(observer), name);
-}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace omx
-} // namespace media
-} // namespace hardware
-} // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/impl/OmxNode.h b/media/libstagefright/omx/hal/1.0/impl/OmxNode.h
deleted file mode 100644
index fc19306..0000000
--- a/media/libstagefright/omx/hal/1.0/impl/OmxNode.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2016, The Android Open Source Project
- *
- * 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.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXNODE_H
-#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXNODE_H
-
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-#include <OMXNodeInstance.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace omx {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::media::omx::V1_0::CodecBuffer;
-using ::android::hardware::media::omx::V1_0::IOmxBufferSource;
-using ::android::hardware::media::omx::V1_0::IOmxNode;
-using ::android::hardware::media::omx::V1_0::IOmxObserver;
-using ::android::hardware::media::omx::V1_0::Message;
-using ::android::hardware::media::omx::V1_0::PortMode;
-using ::android::hardware::media::omx::V1_0::Status;
-using ::android::hidl::base::V1_0::IBase;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-using ::android::OMXNodeInstance;
-using ::android::OmxNodeOwner;
-
-/**
- * Wrapper classes for conversion
- * ==============================
- *
- * Naming convention:
- * - LW = Legacy Wrapper --- It wraps a Treble object inside a legacy object.
- * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
- */
-
-struct OmxNode : public IOmxNode {
- Return<Status> freeNode() override;
- Return<Status> sendCommand(uint32_t cmd, int32_t param) override;
- Return<void> getParameter(uint32_t index, const hidl_vec<uint8_t>& inParams, getParameter_cb _hidl_cb) override;
- Return<Status> setParameter(uint32_t index, const hidl_vec<uint8_t>& params) override;
- Return<void> getConfig(uint32_t index, const hidl_vec<uint8_t>& inConfig, getConfig_cb _hidl_cb) override;
- Return<Status> setConfig(uint32_t index, const hidl_vec<uint8_t>& config) override;
- Return<Status> setPortMode(uint32_t portIndex, PortMode mode) override;
- Return<Status> prepareForAdaptivePlayback(uint32_t portIndex, bool enable, uint32_t maxFrameWidth, uint32_t maxFrameHeight) override;
- Return<void> configureVideoTunnelMode(uint32_t portIndex, bool tunneled, uint32_t audioHwSync, configureVideoTunnelMode_cb _hidl_cb) override;
- Return<void> getGraphicBufferUsage(uint32_t portIndex, getGraphicBufferUsage_cb _hidl_cb) override;
- Return<Status> setInputSurface(const sp<IOmxBufferSource>& bufferSource) override;
- Return<void> allocateSecureBuffer(uint32_t portIndex, uint64_t size, allocateSecureBuffer_cb _hidl_cb) override;
- Return<void> useBuffer(uint32_t portIndex, const CodecBuffer& omxBuffer, useBuffer_cb _hidl_cb) override;
- Return<Status> freeBuffer(uint32_t portIndex, uint32_t buffer) override;
- Return<Status> fillBuffer(uint32_t buffer, const CodecBuffer& omxBuffer, const hidl_handle& fence) override;
- Return<Status> emptyBuffer(uint32_t buffer, const CodecBuffer& omxBuffer, uint32_t flags, uint64_t timestampUs, const hidl_handle& fence) override;
- Return<void> getExtensionIndex(const hidl_string& parameterName, getExtensionIndex_cb _hidl_cb) override;
- Return<Status> dispatchMessage(const Message& msg) override;
-
- OmxNode(OmxNodeOwner* owner, sp<IOmxObserver> const& observer, char const* name);
-protected:
- sp<OMXNodeInstance> mLNode;
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace omx
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXNODE_H
diff --git a/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp
index af9cf03..884e87b 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-#include "WGraphicBufferSource.h"
-#include "Conversion.h"
-#include "WOmxNode.h"
#include <stagefright/foundation/ColorUtils.h>
+#include "WGraphicBufferSource.h"
+#include "WOmxNode.h"
+#include "Conversion.h"
+
namespace android {
namespace hardware {
namespace media {
@@ -124,7 +125,8 @@
}
Return<void> TWGraphicBufferSource::setStopTimeUs(int64_t stopTimeUs) {
- return toHardwareStatus(mBase->setStopTimeUs(stopTimeUs));
+ mBase->setStopTimeUs(stopTimeUs);
+ return Void();
}
Return<void> TWGraphicBufferSource::setColorAspects(
diff --git a/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.h b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.h
index dd6168e..bd60c46 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.h
@@ -17,16 +17,17 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
-#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <frameworks/native/include/binder/Binder.h>
-#include <IOMX.h>
-#include <android/BnGraphicBufferSource.h>
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <media/IOMX.h>
+#include <binder/Binder.h>
#include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+
+#include <android/BnGraphicBufferSource.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmx.h b/media/libstagefright/omx/hal/1.0/impl/WOmx.h
index ab11c6a..3cb002e 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmx.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmx.h
@@ -17,11 +17,12 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
-#include <android/hardware/media/omx/1.0/IOmx.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <IOMX.h>
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.cpp
index 3bd6c6e..b6b9a3b 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.cpp
@@ -14,8 +14,13 @@
* limitations under the License.
*/
+#define LOG_TAG "WOmxBufferProducer-impl"
+
+#include <android-base/logging.h>
+
#include "WOmxBufferProducer.h"
#include "WOmxProducerListener.h"
+#include "Conversion.h"
namespace android {
namespace hardware {
@@ -62,23 +67,29 @@
width, height,
static_cast<::android::PixelFormat>(format), usage,
getFrameTimestamps ? &outTimestamps : nullptr);
-
hidl_handle tFence;
- native_handle_t* nh;
- if (!wrapAs(&tFence, &nh, *fence)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::dequeueBuffer(): "
- "Cannot wrap Fence in hidl_handle"));
- }
FrameEventHistoryDelta tOutTimestamps;
+
+ native_handle_t* nh = nullptr;
+ if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+ LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
+ "Invalid output fence";
+ _hidl_cb(toStatus(status),
+ static_cast<int32_t>(slot),
+ tFence,
+ tOutTimestamps);
+ return Void();
+ }
std::vector<std::vector<native_handle_t*> > nhAA;
if (getFrameTimestamps && !wrapAs(&tOutTimestamps, &nhAA, outTimestamps)) {
+ LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
+ "Invalid output timestamps";
+ _hidl_cb(toStatus(status),
+ static_cast<int32_t>(slot),
+ tFence,
+ tOutTimestamps);
native_handle_delete(nh);
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::dequeueBuffer(): "
- "Cannot wrap Fence in hidl_handle"));
+ return Void();
}
_hidl_cb(toStatus(status),
@@ -89,9 +100,7 @@
if (getFrameTimestamps) {
for (auto& nhA : nhAA) {
for (auto& handle : nhA) {
- if (handle != nullptr) {
- native_handle_delete(handle);
- }
+ native_handle_delete(handle);
}
}
}
@@ -107,16 +116,22 @@
sp<GraphicBuffer> outBuffer;
sp<Fence> outFence;
status_t status = mBase->detachNextBuffer(&outBuffer, &outFence);
-
AnwBuffer tBuffer;
- wrapAs(&tBuffer, *outBuffer);
hidl_handle tFence;
- native_handle_t* nh;
- if (!wrapAs(&tFence, &nh, *outFence)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::detachNextBuffer(): "
- "Cannot wrap Fence in hidl_handle"));
+
+ if (outBuffer == nullptr) {
+ LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
+ "Invalid output buffer";
+ _hidl_cb(toStatus(status), tBuffer, tFence);
+ return Void();
+ }
+ wrapAs(&tBuffer, *outBuffer);
+ native_handle_t* nh = nullptr;
+ if ((outFence != nullptr) && !wrapAs(&tFence, &nh, *outFence)) {
+ LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
+ "Invalid output fence";
+ _hidl_cb(toStatus(status), tBuffer, tFence);
+ return Void();
}
_hidl_cb(toStatus(status), tBuffer, tFence);
@@ -130,10 +145,10 @@
int outSlot;
sp<GraphicBuffer> lBuffer = new GraphicBuffer();
if (!convertTo(lBuffer.get(), buffer)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::attachBuffer(): "
- "Cannot convert AnwBuffer to GraphicBuffer"));
+ LOG(ERROR) << "TWOmxBufferProducer::attachBuffer - "
+ "Invalid input native window buffer";
+ _hidl_cb(toStatus(BAD_VALUE), -1);
+ return Void();
}
status_t status = mBase->attachBuffer(&outSlot, lBuffer);
@@ -144,38 +159,34 @@
Return<void> TWOmxBufferProducer::queueBuffer(
int32_t slot, const QueueBufferInput& input,
queueBuffer_cb _hidl_cb) {
+ QueueBufferOutput tOutput;
IGraphicBufferProducer::QueueBufferInput lInput(
0, false, HAL_DATASPACE_UNKNOWN,
::android::Rect(0, 0, 1, 1),
NATIVE_WINDOW_SCALING_MODE_FREEZE,
0, ::android::Fence::NO_FENCE);
if (!convertTo(&lInput, input)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::queueBuffer(): "
- "Cannot convert IOmxBufferProducer::QueueBufferInput "
- "to IGraphicBufferProducer::QueueBufferInput"));
+ LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
+ "Invalid input";
+ _hidl_cb(toStatus(BAD_VALUE), tOutput);
+ return Void();
}
IGraphicBufferProducer::QueueBufferOutput lOutput;
status_t status = mBase->queueBuffer(
static_cast<int>(slot), lInput, &lOutput);
- QueueBufferOutput tOutput;
std::vector<std::vector<native_handle_t*> > nhAA;
if (!wrapAs(&tOutput, &nhAA, lOutput)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::queueBuffer(): "
- "Cannot wrap IGraphicBufferProducer::QueueBufferOutput "
- "in IOmxBufferProducer::QueueBufferOutput"));
+ LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
+ "Invalid output";
+ _hidl_cb(toStatus(BAD_VALUE), tOutput);
+ return Void();
}
_hidl_cb(toStatus(status), tOutput);
for (auto& nhA : nhAA) {
for (auto& nh : nhA) {
- if (nh != nullptr) {
- native_handle_delete(nh);
- }
+ native_handle_delete(nh);
}
}
return Void();
@@ -185,10 +196,9 @@
int32_t slot, const hidl_handle& fence) {
sp<Fence> lFence = new Fence();
if (!convertTo(lFence.get(), fence)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::cancelBuffer(): "
- "Cannot convert hidl_handle to Fence"));
+ LOG(ERROR) << "TWOmxBufferProducer::cancelBuffer - "
+ "Invalid input fence";
+ return toStatus(BAD_VALUE);
}
return toStatus(mBase->cancelBuffer(static_cast<int>(slot), lFence));
}
@@ -214,19 +224,16 @@
QueueBufferOutput tOutput;
std::vector<std::vector<native_handle_t*> > nhAA;
if (!wrapAs(&tOutput, &nhAA, lOutput)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::connect(): "
- "Cannot wrap IGraphicBufferProducer::QueueBufferOutput "
- "in IOmxBufferProducer::QueueBufferOutput"));
+ LOG(ERROR) << "TWOmxBufferProducer::connect - "
+ "Invalid output";
+ _hidl_cb(toStatus(status), tOutput);
+ return Void();
}
_hidl_cb(toStatus(status), tOutput);
for (auto& nhA : nhAA) {
for (auto& nh : nhA) {
- if (nh != nullptr) {
- native_handle_delete(nh);
- }
+ native_handle_delete(nh);
}
}
return Void();
@@ -287,14 +294,19 @@
&lOutBuffer, &lOutFence, lOutTransformMatrix);
AnwBuffer tOutBuffer;
- wrapAs(&tOutBuffer, *lOutBuffer);
+ if (lOutBuffer != nullptr) {
+ wrapAs(&tOutBuffer, *lOutBuffer);
+ }
hidl_handle tOutFence;
- native_handle_t* nh;
- if (!wrapAs(&tOutFence, &nh, *lOutFence)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::getLastQueuedBuffer(): "
- "Cannot wrap Fence in hidl_handle"));
+ native_handle_t* nh = nullptr;
+ if ((lOutFence == nullptr) || !wrapAs(&tOutFence, &nh, *lOutFence)) {
+ LOG(ERROR) << "TWOmxBufferProducer::getLastQueuedBuffer - "
+ "Invalid output fence";
+ _hidl_cb(toStatus(status),
+ tOutBuffer,
+ tOutFence,
+ hidl_array<float, 16>());
+ return Void();
}
hidl_array<float, 16> tOutTransformMatrix(lOutTransformMatrix);
@@ -311,19 +323,16 @@
FrameEventHistoryDelta tDelta;
std::vector<std::vector<native_handle_t*> > nhAA;
if (!wrapAs(&tDelta, &nhAA, lDelta)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::getFrameTimestamps(): "
- "Cannot wrap ::android::FrameEventHistoryDelta "
- "in FrameEventHistoryDelta"));
+ LOG(ERROR) << "TWOmxBufferProducer::getFrameTimestamps - "
+ "Invalid output frame timestamps";
+ _hidl_cb(tDelta);
+ return Void();
}
_hidl_cb(tDelta);
for (auto& nhA : nhAA) {
for (auto& nh : nhA) {
- if (nh != nullptr) {
- native_handle_delete(nh);
- }
+ native_handle_delete(nh);
}
}
return Void();
@@ -383,9 +392,13 @@
fnStatus = toStatusT(status);
*slot = tSlot;
if (!convertTo(fence->get(), tFence)) {
+ LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
+ "Invalid output fence";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
if (outTimestamps && !convertTo(outTimestamps, tTs)) {
+ LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
+ "Invalid output timestamps";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
}));
@@ -408,9 +421,13 @@
hidl_handle const& tFence) {
fnStatus = toStatusT(status);
if (!convertTo(outFence->get(), tFence)) {
+ LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
+ "Invalid output fence";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
if (!convertTo(outBuffer->get(), tBuffer)) {
+ LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
+ "Invalid output buffer";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
}));
@@ -437,6 +454,8 @@
IOmxBufferProducer::QueueBufferInput tInput;
native_handle_t* nh;
if (!wrapAs(&tInput, &nh, input)) {
+ LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
+ "Invalid input";
return BAD_VALUE;
}
status_t fnStatus;
@@ -446,6 +465,8 @@
IOmxBufferProducer::QueueBufferOutput const& tOutput) {
fnStatus = toStatusT(status);
if (!convertTo(output, tOutput)) {
+ LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
+ "Invalid output";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
}));
@@ -455,8 +476,10 @@
status_t LWOmxBufferProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
hidl_handle tFence;
- native_handle_t* nh;
- if (!wrapAs(&tFence, &nh, *fence)) {
+ native_handle_t* nh = nullptr;
+ if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+ LOG(ERROR) << "LWOmxBufferProducer::cancelBuffer - "
+ "Invalid input fence";
return BAD_VALUE;
}
@@ -490,6 +513,8 @@
IOmxBufferProducer::QueueBufferOutput const& tOutput) {
fnStatus = toStatusT(status);
if (!convertTo(output, tOutput)) {
+ LOG(ERROR) << "LWOmxBufferProducer::connect - "
+ "Invalid output";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
}));
@@ -554,10 +579,14 @@
fnStatus = toStatusT(status);
*outBuffer = new GraphicBuffer();
if (!convertTo(outBuffer->get(), buffer)) {
+ LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
+ "Invalid output buffer";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
*outFence = new Fence();
if (!convertTo(outFence->get(), fence)) {
+ LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
+ "Invalid output fence";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
std::copy(transformMatrix.data(),
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.h b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.h
index 65b093c..8520160 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.h
@@ -17,13 +17,14 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERPRODUCER_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERPRODUCER_H
-#include <android/hardware/media/omx/1.0/IOmxBufferProducer.h>
-#include <binder/Binder.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
+
+#include <binder/Binder.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
-#include "Conversion.h"
+
+#include <android/hardware/media/omx/1.0/IOmxBufferProducer.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.cpp
index 97bcee0..803283a 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.cpp
@@ -14,10 +14,10 @@
* limitations under the License.
*/
+#include <utils/String8.h>
+
#include "WOmxBufferSource.h"
#include "Conversion.h"
-#include <utils/String8.h>
-#include <cutils/native_handle.h>
namespace android {
namespace hardware {
@@ -95,8 +95,7 @@
uint32_t buffer, hidl_handle const& fence) {
OMXFenceParcelable fenceParcelable;
if (!convertTo(&fenceParcelable, fence)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE);
+ return Void();
}
mBase->onInputBufferEmptied(int32_t(buffer), fenceParcelable);
return Void();
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.h b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.h
index 83bf46f..9b27796 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.h
@@ -17,13 +17,14 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
-#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <frameworks/native/include/binder/Binder.h>
+#include <binder/Binder.h>
+#include <media/OMXFenceParcelable.h>
+
+#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
#include <android/BnOMXBufferSource.h>
-#include <OMXFenceParcelable.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxNode.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmxNode.cpp
index 26617aa..dc5c8e1 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxNode.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxNode.cpp
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-#include <IOMX.h>
-#include <OMXNodeInstance.h>
+#include <algorithm>
+
#include "WOmxNode.h"
#include "WOmxBufferSource.h"
#include "Conversion.h"
-#include <algorithm>
-
namespace android {
namespace hardware {
namespace media {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxNode.h b/media/libstagefright/omx/hal/1.0/impl/WOmxNode.h
index 12c2f04..75816ba 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxNode.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxNode.h
@@ -17,13 +17,16 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <utils/Errors.h>
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+
namespace android {
namespace hardware {
namespace media {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.cpp
index 433a8b8..354db29 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.cpp
@@ -15,13 +15,14 @@
*/
#define LOG_TAG "WOmxObserver-impl"
-#include "WOmxObserver.h"
#include <vector>
+#include <android-base/logging.h>
#include <cutils/native_handle.h>
-#include <frameworks/native/include/binder/Binder.h>
+#include <binder/Binder.h>
+#include "WOmxObserver.h"
#include "Conversion.h"
namespace android {
@@ -46,7 +47,7 @@
}
auto transResult = mBase->onMessages(tMessages);
if (!transResult.isOk()) {
- ALOGE("LWOmxObserver::onMessages transaction failed");
+ LOG(ERROR) << "LWOmxObserver::onMessages - Transaction failed";
}
for (auto& handle : handles) {
native_handle_close(handle);
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.h b/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.h
index cfe4281..7075513 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.h
@@ -17,12 +17,14 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <list>
+
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <IOMX.h>
-#include <list>
+#include <media/IOMX.h>
+
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.h b/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.h
index 86656ca..e60032e 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.h
@@ -17,13 +17,14 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
-#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <binder/IBinder.h>
#include <gui/IProducerListener.h>
+#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
+
namespace android {
namespace hardware {
namespace media {
diff --git a/media/libstagefright/omx/hal/1.0/utils/Android.mk b/media/libstagefright/omx/hal/1.0/utils/Android.mk
index 6930c87..c44ce25 100644
--- a/media/libstagefright/omx/hal/1.0/utils/Android.mk
+++ b/media/libstagefright/omx/hal/1.0/utils/Android.mk
@@ -25,18 +25,17 @@
libcutils \
libbinder \
liblog \
+ libbase \
android.hardware.media.omx@1.0 \
android.hardware.graphics.common@1.0 \
android.hardware.media@1.0 \
android.hidl.base@1.0 \
LOCAL_C_INCLUDES += \
- $(TOP) \
- $(TOP)/frameworks/av/include/media \
- $(TOP)/frameworks/av/media/libstagefright/include \
- $(TOP)/frameworks/av/media/libstagefright/omx \
- $(TOP)/frameworks/native/include/media/hardware \
- $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/frameworks/av/include \
+ $(TOP)/frameworks/av/media/libstagefright \
$(TOP)/frameworks/native/include \
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/frameworks/native/include/media/hardware \
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/hal/1.0/utils/Conversion.h b/media/libstagefright/omx/hal/1.0/utils/Conversion.h
index 5050687..375c7f9 100644
--- a/media/libstagefright/omx/hal/1.0/utils/Conversion.h
+++ b/media/libstagefright/omx/hal/1.0/utils/Conversion.h
@@ -17,29 +17,26 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
+#include <vector>
+#include <list>
+
+#include <unistd.h>
+
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <hidlmemory/mapping.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-
-#include <unistd.h>
-#include <vector>
-#include <list>
#include <binder/Binder.h>
#include <binder/Status.h>
#include <ui/FenceTime.h>
-
-#include <OMXFenceParcelable.h>
+#include <media/OMXFenceParcelable.h>
#include <cutils/native_handle.h>
#include <gui/IGraphicBufferProducer.h>
-#include <IOMX.h>
+#include <media/OMXBuffer.h>
#include <VideoAPI.h>
-#include <OMXBuffer.h>
-#include <android/IOMXBufferSource.h>
-#include <android/IGraphicBufferSource.h>
+#include <android/hidl/memory/1.0/IMemory.h>
#include <android/hardware/media/omx/1.0/types.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
@@ -49,6 +46,9 @@
#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+#include <android/IGraphicBufferSource.h>
+#include <android/IOMXBufferSource.h>
+
namespace android {
namespace hardware {
namespace media {
@@ -177,25 +177,6 @@
*/
/**
- * \brief Convert `binder::Status` to `Return<void>`.
- *
- * \param[in] l The source `binder::Status`.
- * \return The corresponding `Return<void>`.
- */
-// convert: ::android::binder::Status -> Return<void>
-inline Return<void> toHardwareStatus(
- ::android::binder::Status const& l) {
- if (l.exceptionCode() == ::android::binder::Status::EX_SERVICE_SPECIFIC) {
- return ::android::hardware::Status::fromServiceSpecificError(
- l.serviceSpecificErrorCode(),
- l.exceptionMessage());
- }
- return ::android::hardware::Status::fromExceptionCode(
- l.exceptionCode(),
- l.exceptionMessage());
-}
-
-/**
* \brief Convert `Return<void>` to `binder::Status`.
*
* \param[in] t The source `Return<void>`.
diff --git a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp b/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp
index afe8bc5..0ba6060 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-#include "WGraphicBufferSource.h"
-#include "Conversion.h"
-#include "WOmxNode.h"
#include <stagefright/foundation/ColorUtils.h>
+#include "WGraphicBufferSource.h"
+#include "WOmxNode.h"
+#include "Conversion.h"
+
namespace android {
namespace hardware {
namespace media {
@@ -95,7 +96,8 @@
return Void();
}
-Return<void> TWGraphicBufferSource::setSuspend(bool suspend, int64_t timeUs) {
+Return<void> TWGraphicBufferSource::setSuspend(
+ bool suspend, int64_t timeUs) {
mBase->setSuspend(suspend, timeUs);
return Void();
}
@@ -123,7 +125,8 @@
}
Return<void> TWGraphicBufferSource::setStopTimeUs(int64_t stopTimeUs) {
- return toHardwareStatus(mBase->setStopTimeUs(stopTimeUs));
+ mBase->setStopTimeUs(stopTimeUs);
+ return Void();
}
Return<void> TWGraphicBufferSource::setColorAspects(
diff --git a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h b/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h
index 1b09cbd..1090d52 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h
@@ -17,16 +17,17 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
-#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <frameworks/native/include/binder/Binder.h>
-#include <IOMX.h>
-#include <android/BnGraphicBufferSource.h>
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <media/IOMX.h>
+#include <binder/Binder.h>
#include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+
+#include <android/BnGraphicBufferSource.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmx.h b/media/libstagefright/omx/hal/1.0/utils/WOmx.h
index 73adc55..7860f46 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmx.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmx.h
@@ -17,11 +17,12 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
-#include <android/hardware/media/omx/1.0/IOmx.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <IOMX.h>
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp
index cfb0cce..e9a93b9 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp
@@ -14,8 +14,13 @@
* limitations under the License.
*/
+#define LOG_TAG "WOmxBufferProducer-utils"
+
+#include <android-base/logging.h>
+
#include "WOmxBufferProducer.h"
#include "WOmxProducerListener.h"
+#include "Conversion.h"
namespace android {
namespace hardware {
@@ -62,23 +67,29 @@
width, height,
static_cast<::android::PixelFormat>(format), usage,
getFrameTimestamps ? &outTimestamps : nullptr);
-
hidl_handle tFence;
- native_handle_t* nh;
- if (!wrapAs(&tFence, &nh, *fence)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::dequeueBuffer(): "
- "Cannot wrap Fence in hidl_handle"));
- }
FrameEventHistoryDelta tOutTimestamps;
+
+ native_handle_t* nh = nullptr;
+ if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+ LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
+ "Invalid output fence";
+ _hidl_cb(toStatus(status),
+ static_cast<int32_t>(slot),
+ tFence,
+ tOutTimestamps);
+ return Void();
+ }
std::vector<std::vector<native_handle_t*> > nhAA;
if (getFrameTimestamps && !wrapAs(&tOutTimestamps, &nhAA, outTimestamps)) {
+ LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
+ "Invalid output timestamps";
+ _hidl_cb(toStatus(status),
+ static_cast<int32_t>(slot),
+ tFence,
+ tOutTimestamps);
native_handle_delete(nh);
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::dequeueBuffer(): "
- "Cannot wrap Fence in hidl_handle"));
+ return Void();
}
_hidl_cb(toStatus(status),
@@ -89,9 +100,7 @@
if (getFrameTimestamps) {
for (auto& nhA : nhAA) {
for (auto& handle : nhA) {
- if (handle != nullptr) {
- native_handle_delete(handle);
- }
+ native_handle_delete(handle);
}
}
}
@@ -107,16 +116,22 @@
sp<GraphicBuffer> outBuffer;
sp<Fence> outFence;
status_t status = mBase->detachNextBuffer(&outBuffer, &outFence);
-
AnwBuffer tBuffer;
- wrapAs(&tBuffer, *outBuffer);
hidl_handle tFence;
- native_handle_t* nh;
- if (!wrapAs(&tFence, &nh, *outFence)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::detachNextBuffer(): "
- "Cannot wrap Fence in hidl_handle"));
+
+ if (outBuffer == nullptr) {
+ LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
+ "Invalid output buffer";
+ _hidl_cb(toStatus(status), tBuffer, tFence);
+ return Void();
+ }
+ wrapAs(&tBuffer, *outBuffer);
+ native_handle_t* nh = nullptr;
+ if ((outFence != nullptr) && !wrapAs(&tFence, &nh, *outFence)) {
+ LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
+ "Invalid output fence";
+ _hidl_cb(toStatus(status), tBuffer, tFence);
+ return Void();
}
_hidl_cb(toStatus(status), tBuffer, tFence);
@@ -130,10 +145,10 @@
int outSlot;
sp<GraphicBuffer> lBuffer = new GraphicBuffer();
if (!convertTo(lBuffer.get(), buffer)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::attachBuffer(): "
- "Cannot convert AnwBuffer to GraphicBuffer"));
+ LOG(ERROR) << "TWOmxBufferProducer::attachBuffer - "
+ "Invalid input native window buffer";
+ _hidl_cb(toStatus(BAD_VALUE), -1);
+ return Void();
}
status_t status = mBase->attachBuffer(&outSlot, lBuffer);
@@ -144,38 +159,34 @@
Return<void> TWOmxBufferProducer::queueBuffer(
int32_t slot, const QueueBufferInput& input,
queueBuffer_cb _hidl_cb) {
+ QueueBufferOutput tOutput;
IGraphicBufferProducer::QueueBufferInput lInput(
0, false, HAL_DATASPACE_UNKNOWN,
::android::Rect(0, 0, 1, 1),
NATIVE_WINDOW_SCALING_MODE_FREEZE,
0, ::android::Fence::NO_FENCE);
if (!convertTo(&lInput, input)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::queueBuffer(): "
- "Cannot convert IOmxBufferProducer::QueueBufferInput "
- "to IGraphicBufferProducer::QueueBufferInput"));
+ LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
+ "Invalid input";
+ _hidl_cb(toStatus(BAD_VALUE), tOutput);
+ return Void();
}
IGraphicBufferProducer::QueueBufferOutput lOutput;
status_t status = mBase->queueBuffer(
static_cast<int>(slot), lInput, &lOutput);
- QueueBufferOutput tOutput;
std::vector<std::vector<native_handle_t*> > nhAA;
if (!wrapAs(&tOutput, &nhAA, lOutput)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::queueBuffer(): "
- "Cannot wrap IGraphicBufferProducer::QueueBufferOutput "
- "in IOmxBufferProducer::QueueBufferOutput"));
+ LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
+ "Invalid output";
+ _hidl_cb(toStatus(BAD_VALUE), tOutput);
+ return Void();
}
_hidl_cb(toStatus(status), tOutput);
for (auto& nhA : nhAA) {
for (auto& nh : nhA) {
- if (nh != nullptr) {
- native_handle_delete(nh);
- }
+ native_handle_delete(nh);
}
}
return Void();
@@ -185,10 +196,9 @@
int32_t slot, const hidl_handle& fence) {
sp<Fence> lFence = new Fence();
if (!convertTo(lFence.get(), fence)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::cancelBuffer(): "
- "Cannot convert hidl_handle to Fence"));
+ LOG(ERROR) << "TWOmxBufferProducer::cancelBuffer - "
+ "Invalid input fence";
+ return toStatus(BAD_VALUE);
}
return toStatus(mBase->cancelBuffer(static_cast<int>(slot), lFence));
}
@@ -214,19 +224,16 @@
QueueBufferOutput tOutput;
std::vector<std::vector<native_handle_t*> > nhAA;
if (!wrapAs(&tOutput, &nhAA, lOutput)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::connect(): "
- "Cannot wrap IGraphicBufferProducer::QueueBufferOutput "
- "in IOmxBufferProducer::QueueBufferOutput"));
+ LOG(ERROR) << "TWOmxBufferProducer::connect - "
+ "Invalid output";
+ _hidl_cb(toStatus(status), tOutput);
+ return Void();
}
_hidl_cb(toStatus(status), tOutput);
for (auto& nhA : nhAA) {
for (auto& nh : nhA) {
- if (nh != nullptr) {
- native_handle_delete(nh);
- }
+ native_handle_delete(nh);
}
}
return Void();
@@ -287,14 +294,19 @@
&lOutBuffer, &lOutFence, lOutTransformMatrix);
AnwBuffer tOutBuffer;
- wrapAs(&tOutBuffer, *lOutBuffer);
+ if (lOutBuffer != nullptr) {
+ wrapAs(&tOutBuffer, *lOutBuffer);
+ }
hidl_handle tOutFence;
- native_handle_t* nh;
- if (!wrapAs(&tOutFence, &nh, *lOutFence)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::getLastQueuedBuffer(): "
- "Cannot wrap Fence in hidl_handle"));
+ native_handle_t* nh = nullptr;
+ if ((lOutFence == nullptr) || !wrapAs(&tOutFence, &nh, *lOutFence)) {
+ LOG(ERROR) << "TWOmxBufferProducer::getLastQueuedBuffer - "
+ "Invalid output fence";
+ _hidl_cb(toStatus(status),
+ tOutBuffer,
+ tOutFence,
+ hidl_array<float, 16>());
+ return Void();
}
hidl_array<float, 16> tOutTransformMatrix(lOutTransformMatrix);
@@ -311,19 +323,16 @@
FrameEventHistoryDelta tDelta;
std::vector<std::vector<native_handle_t*> > nhAA;
if (!wrapAs(&tDelta, &nhAA, lDelta)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE,
- String8("TWOmxBufferProducer::getFrameTimestamps(): "
- "Cannot wrap ::android::FrameEventHistoryDelta "
- "in FrameEventHistoryDelta"));
+ LOG(ERROR) << "TWOmxBufferProducer::getFrameTimestamps - "
+ "Invalid output frame timestamps";
+ _hidl_cb(tDelta);
+ return Void();
}
_hidl_cb(tDelta);
for (auto& nhA : nhAA) {
for (auto& nh : nhA) {
- if (nh != nullptr) {
- native_handle_delete(nh);
- }
+ native_handle_delete(nh);
}
}
return Void();
@@ -383,9 +392,13 @@
fnStatus = toStatusT(status);
*slot = tSlot;
if (!convertTo(fence->get(), tFence)) {
+ LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
+ "Invalid output fence";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
if (outTimestamps && !convertTo(outTimestamps, tTs)) {
+ LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
+ "Invalid output timestamps";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
}));
@@ -408,9 +421,13 @@
hidl_handle const& tFence) {
fnStatus = toStatusT(status);
if (!convertTo(outFence->get(), tFence)) {
+ LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
+ "Invalid output fence";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
if (!convertTo(outBuffer->get(), tBuffer)) {
+ LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
+ "Invalid output buffer";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
}));
@@ -437,6 +454,8 @@
IOmxBufferProducer::QueueBufferInput tInput;
native_handle_t* nh;
if (!wrapAs(&tInput, &nh, input)) {
+ LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
+ "Invalid input";
return BAD_VALUE;
}
status_t fnStatus;
@@ -446,6 +465,8 @@
IOmxBufferProducer::QueueBufferOutput const& tOutput) {
fnStatus = toStatusT(status);
if (!convertTo(output, tOutput)) {
+ LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
+ "Invalid output";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
}));
@@ -455,8 +476,10 @@
status_t LWOmxBufferProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
hidl_handle tFence;
- native_handle_t* nh;
- if (!wrapAs(&tFence, &nh, *fence)) {
+ native_handle_t* nh = nullptr;
+ if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+ LOG(ERROR) << "LWOmxBufferProducer::cancelBuffer - "
+ "Invalid input fence";
return BAD_VALUE;
}
@@ -490,6 +513,8 @@
IOmxBufferProducer::QueueBufferOutput const& tOutput) {
fnStatus = toStatusT(status);
if (!convertTo(output, tOutput)) {
+ LOG(ERROR) << "LWOmxBufferProducer::connect - "
+ "Invalid output";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
}));
@@ -554,10 +579,14 @@
fnStatus = toStatusT(status);
*outBuffer = new GraphicBuffer();
if (!convertTo(outBuffer->get(), buffer)) {
+ LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
+ "Invalid output buffer";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
*outFence = new Fence();
if (!convertTo(outFence->get(), fence)) {
+ LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
+ "Invalid output fence";
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
std::copy(transformMatrix.data(),
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h
index a5d2961..54b9078 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h
@@ -17,13 +17,14 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERPRODUCER_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERPRODUCER_H
-#include <android/hardware/media/omx/1.0/IOmxBufferProducer.h>
-#include <binder/Binder.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
+
+#include <binder/Binder.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
-#include "Conversion.h"
+
+#include <android/hardware/media/omx/1.0/IOmxBufferProducer.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp
index f3f5b9d..fe565e6 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp
@@ -14,10 +14,10 @@
* limitations under the License.
*/
+#include <utils/String8.h>
+
#include "WOmxBufferSource.h"
#include "Conversion.h"
-#include <utils/String8.h>
-#include <cutils/native_handle.h>
namespace android {
namespace hardware {
@@ -95,8 +95,7 @@
uint32_t buffer, hidl_handle const& fence) {
OMXFenceParcelable fenceParcelable;
if (!convertTo(&fenceParcelable, fence)) {
- return ::android::hardware::Status::fromExceptionCode(
- ::android::hardware::Status::EX_BAD_PARCELABLE);
+ return Void();
}
mBase->onInputBufferEmptied(int32_t(buffer), fenceParcelable);
return Void();
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h
index 1214300..086f648 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h
@@ -17,13 +17,14 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
-#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <frameworks/native/include/binder/Binder.h>
+#include <binder/Binder.h>
+#include <media/OMXFenceParcelable.h>
+
+#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
#include <android/BnOMXBufferSource.h>
-#include <OMXFenceParcelable.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp
index 3bb7a99..df191c7 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-#include <IOMX.h>
-#include <OMXNodeInstance.h>
+#include <algorithm>
+
#include "WOmxNode.h"
#include "WOmxBufferSource.h"
#include "Conversion.h"
-#include <algorithm>
-
namespace android {
namespace hardware {
namespace media {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h b/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h
index 9c4bb4a..46dfb49 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h
@@ -17,13 +17,16 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <utils/Errors.h>
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+
namespace android {
namespace hardware {
namespace media {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp
index bab6a09..05ec37e 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp
@@ -15,13 +15,14 @@
*/
#define LOG_TAG "WOmxObserver-utils"
-#include "WOmxObserver.h"
#include <vector>
+#include <android-base/logging.h>
#include <cutils/native_handle.h>
-#include <frameworks/native/include/binder/Binder.h>
+#include <binder/Binder.h>
+#include "WOmxObserver.h"
#include "Conversion.h"
namespace android {
@@ -46,7 +47,7 @@
}
auto transResult = mBase->onMessages(tMessages);
if (!transResult.isOk()) {
- ALOGE("LWOmxObserver::onMessages transaction failed");
+ LOG(ERROR) << "LWOmxObserver::onMessages - Transaction failed";
}
for (auto& handle : handles) {
native_handle_close(handle);
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h b/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h
index b9eb412..d442218 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h
@@ -17,12 +17,14 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <list>
+
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <IOMX.h>
-#include <list>
+#include <media/IOMX.h>
+
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h b/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h
index 2be077b..7d20887 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h
@@ -17,13 +17,14 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
-#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <binder/IBinder.h>
#include <gui/IProducerListener.h>
+#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
+
namespace android {
namespace hardware {
namespace media {
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 08deaab..6d0f189 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -14,6 +14,7 @@
libcutils \
libhidlbase \
libhidlmemory \
+ android.hidl.allocator@1.0 \
android.hidl.memory@1.0 \
android.hardware.media.omx@1.0 \
android.hardware.media.omx@1.0-utils
diff --git a/media/libstagefright/omx/tests/OMXHarness.h b/media/libstagefright/omx/tests/OMXHarness.h
index 94a37da..4fc0f79 100644
--- a/media/libstagefright/omx/tests/OMXHarness.h
+++ b/media/libstagefright/omx/tests/OMXHarness.h
@@ -79,7 +79,7 @@
virtual ~Harness();
private:
- typedef hidl::memory::V1_0::IAllocator IAllocator;
+ typedef hidl::allocator::V1_0::IAllocator IAllocator;
friend struct NodeReaper;
struct CodecObserver;
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 58d2bb8..35dd10f 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -205,13 +205,13 @@
const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
.bLength = sizeof(ss_sink_comp),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bMaxBurst = 2,
+ .bMaxBurst = 6,
};
const struct usb_ss_ep_comp_descriptor ss_source_comp = {
.bLength = sizeof(ss_source_comp),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bMaxBurst = 2,
+ .bMaxBurst = 6,
};
const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index a87c71c..a428c75 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -34,9 +34,12 @@
libcutils \
libhwbinder \
libhidltransport \
- android.hardware.media.omx@1.0
+ android.hardware.media.omx@1.0 \
+ android.hardware.media.omx@1.0-impl \
+ android.hidl.memory@1.0
LOCAL_C_INCLUDES := \
$(TOP)/frameworks/av/media/libstagefright \
+ $(TOP)/frameworks/av/media/libstagefright/include \
$(TOP)/frameworks/native/include/media/openmax
LOCAL_MODULE := mediacodec
LOCAL_32_BIT_ONLY := true
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index 983bbba..688c651 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -33,6 +33,7 @@
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <hidl/HidlTransportSupport.h>
+#include <omx/hal/1.0/impl/Omx.h>
using namespace android;
@@ -54,10 +55,10 @@
if ((trebleOmx == 1) || ((trebleOmx == -1) &&
property_get_bool("persist.hal.binderization", 0))) {
using namespace ::android::hardware::media::omx::V1_0;
- sp<IOmx> omx = IOmx::getService(true);
+ sp<IOmx> omx = new implementation::Omx();
if (omx == nullptr) {
LOG(ERROR) << "Cannot create a Treble IOmx service.";
- } else if (omx->registerAsService("default") != OK) {
+ } else if (omx->registerAsService() != OK) {
LOG(ERROR) << "Cannot register a Treble IOmx service.";
} else {
LOG(INFO) << "Treble IOmx service created.";
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
index e72236d..87fddd4 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ MediaCasService.cpp \
MediaDrmService.cpp \
main_mediadrmserver.cpp
diff --git a/services/mediadrm/FactoryLoader.h b/services/mediadrm/FactoryLoader.h
new file mode 100644
index 0000000..1e03e9b
--- /dev/null
+++ b/services/mediadrm/FactoryLoader.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef MEDIA_CAS_LOADER_H_
+#define MEDIA_CAS_LOADER_H_
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/SharedLibrary.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+
+namespace android {
+using namespace std;
+using namespace media;
+using namespace MediaCas;
+
+template <class T>
+class FactoryLoader {
+public:
+ FactoryLoader(const char *name) :
+ mFactory(NULL), mCreateFactoryFuncName(name) {}
+
+ virtual ~FactoryLoader() { closeFactory(); }
+
+ bool findFactoryForScheme(
+ int32_t CA_system_id,
+ sp<SharedLibrary> *library = NULL,
+ T** factory = NULL);
+
+ bool enumeratePlugins(vector<ParcelableCasPluginDescriptor>* results);
+
+private:
+ typedef T*(*CreateFactoryFunc)();
+
+ Mutex mMapLock;
+ T* mFactory;
+ const char *mCreateFactoryFuncName;
+ sp<SharedLibrary> mLibrary;
+ KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
+ KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
+
+ bool loadFactoryForSchemeFromPath(
+ const String8 &path,
+ int32_t CA_system_id,
+ sp<SharedLibrary> *library,
+ T** factory);
+
+ bool queryPluginsFromPath(
+ const String8 &path,
+ vector<ParcelableCasPluginDescriptor>* results);
+
+ bool openFactory(const String8 &path);
+ void closeFactory();
+};
+
+template <class T>
+bool FactoryLoader<T>::findFactoryForScheme(
+ int32_t CA_system_id, sp<SharedLibrary> *library, T** factory) {
+ if (library != NULL) {
+ library->clear();
+ }
+ if (factory != NULL) {
+ *factory = NULL;
+ }
+
+ Mutex::Autolock autoLock(mMapLock);
+
+ // first check cache
+ ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
+ if (index >= 0) {
+ return loadFactoryForSchemeFromPath(
+ mCASystemIdToLibraryPathMap[index],
+ CA_system_id, library, factory);
+ }
+
+ // no luck, have to search
+ String8 dirPath("/vendor/lib/mediacas");
+ DIR* pDir = opendir(dirPath.string());
+
+ if (pDir == NULL) {
+ ALOGE("Failed to open plugin directory %s", dirPath.string());
+ return false;
+ }
+
+ struct dirent* pEntry;
+ while ((pEntry = readdir(pDir))) {
+ String8 pluginPath = dirPath + "/" + pEntry->d_name;
+ if (pluginPath.getPathExtension() == ".so") {
+ if (loadFactoryForSchemeFromPath(
+ pluginPath, CA_system_id, library, factory)) {
+ mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
+ closedir(pDir);
+
+ return true;
+ }
+ }
+ }
+
+ closedir(pDir);
+
+ ALOGE("Failed to find plugin");
+ return false;
+}
+
+template <class T>
+bool FactoryLoader<T>::enumeratePlugins(
+ vector<ParcelableCasPluginDescriptor>* results) {
+ ALOGI("enumeratePlugins");
+
+ results->clear();
+
+ String8 dirPath("/vendor/lib/mediacas");
+ DIR* pDir = opendir(dirPath.string());
+
+ if (pDir == NULL) {
+ ALOGE("Failed to open plugin directory %s", dirPath.string());
+ return false;
+ }
+
+ Mutex::Autolock autoLock(mMapLock);
+
+ struct dirent* pEntry;
+ while ((pEntry = readdir(pDir))) {
+ String8 pluginPath = dirPath + "/" + pEntry->d_name;
+ if (pluginPath.getPathExtension() == ".so") {
+ queryPluginsFromPath(pluginPath, results);
+ }
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::loadFactoryForSchemeFromPath(
+ const String8 &path, int32_t CA_system_id,
+ sp<SharedLibrary> *library, T** factory) {
+ closeFactory();
+
+ if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
+ closeFactory();
+ return false;
+ }
+
+ if (library != NULL) {
+ *library = mLibrary;
+ }
+ if (factory != NULL) {
+ *factory = mFactory;
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::queryPluginsFromPath(
+ const String8 &path, vector<ParcelableCasPluginDescriptor>* results) {
+ closeFactory();
+
+ vector<CasPluginDescriptor> descriptors;
+ if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
+ closeFactory();
+ return false;
+ }
+
+ for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
+ results->push_back(ParcelableCasPluginDescriptor(
+ it->CA_system_id, it->name));
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::openFactory(const String8 &path) {
+ // get strong pointer to open shared library
+ ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+ if (index >= 0) {
+ mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
+ } else {
+ index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+ }
+
+ if (!mLibrary.get()) {
+ mLibrary = new SharedLibrary(path);
+ if (!*mLibrary) {
+ return false;
+ }
+
+ mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
+ }
+
+ CreateFactoryFunc createFactory =
+ (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
+ if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
+ return false;
+ }
+ return true;
+}
+
+template <class T>
+void FactoryLoader<T>::closeFactory() {
+ delete mFactory;
+ mFactory = NULL;
+ mLibrary.clear();
+}
+
+} // namespace android
+
+#endif // MEDIA_CAS_LOADER_H_
diff --git a/services/mediadrm/MediaCasService.cpp b/services/mediadrm/MediaCasService.cpp
new file mode 100644
index 0000000..c111283
--- /dev/null
+++ b/services/mediadrm/MediaCasService.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaCasService"
+
+#include <binder/IServiceManager.h>
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/CasImpl.h>
+#include <media/DescramblerImpl.h>
+#include <utils/Log.h>
+#include <utils/List.h>
+#include "MediaCasService.h"
+#include <android/media/ICasListener.h>
+
+namespace android {
+
+//static
+void MediaCasService::instantiate() {
+ defaultServiceManager()->addService(
+ String16("media.cas"), new MediaCasService());
+}
+
+MediaCasService::MediaCasService() :
+ mCasLoader(new FactoryLoader<CasFactory>("createCasFactory")),
+ mDescramblerLoader(new FactoryLoader<DescramblerFactory>(
+ "createDescramblerFactory")) {
+}
+
+MediaCasService::~MediaCasService() {
+ delete mCasLoader;
+ delete mDescramblerLoader;
+}
+
+Status MediaCasService::enumeratePlugins(
+ vector<ParcelableCasPluginDescriptor>* results) {
+ ALOGV("enumeratePlugins");
+
+ mCasLoader->enumeratePlugins(results);
+
+ return Status::ok();
+}
+
+Status MediaCasService::isSystemIdSupported(
+ int32_t CA_system_id, bool* result) {
+ ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
+
+ *result = mCasLoader->findFactoryForScheme(CA_system_id);
+
+ return Status::ok();
+}
+
+Status MediaCasService::createPlugin(
+ int32_t CA_system_id,
+ const sp<ICasListener> &listener,
+ sp<ICas>* result) {
+ ALOGV("createPlugin: CA_system_id=%d", CA_system_id);
+
+ result->clear();
+
+ CasFactory *factory;
+ sp<SharedLibrary> library;
+ if (mCasLoader->findFactoryForScheme(CA_system_id, &library, &factory)) {
+ CasPlugin *plugin = NULL;
+ sp<CasImpl> casImpl = new CasImpl(listener);
+ if (factory->createPlugin(CA_system_id, (uint64_t)casImpl.get(),
+ &CasImpl::OnEvent, &plugin) == OK && plugin != NULL) {
+ casImpl->init(library, plugin);
+ *result = casImpl;
+ }
+ }
+
+ return Status::ok();
+}
+
+Status MediaCasService::isDescramblerSupported(
+ int32_t CA_system_id, bool* result) {
+ ALOGV("isDescramblerSupported: CA_system_id=%d", CA_system_id);
+
+ *result = mDescramblerLoader->findFactoryForScheme(CA_system_id);
+
+ return Status::ok();
+}
+
+Status MediaCasService::createDescrambler(
+ int32_t CA_system_id, sp<IDescrambler>* result) {
+ ALOGV("createDescrambler: CA_system_id=%d", CA_system_id);
+
+ result->clear();
+
+ DescramblerFactory *factory;
+ sp<SharedLibrary> library;
+ if (mDescramblerLoader->findFactoryForScheme(
+ CA_system_id, &library, &factory)) {
+ DescramblerPlugin *plugin = NULL;
+ if (factory->createPlugin(CA_system_id, &plugin) == OK
+ && plugin != NULL) {
+ *result = new DescramblerImpl(library, plugin);
+ }
+ }
+
+ return Status::ok();
+}
+
+} // namespace android
diff --git a/services/mediadrm/MediaCasService.h b/services/mediadrm/MediaCasService.h
new file mode 100644
index 0000000..cb828f2
--- /dev/null
+++ b/services/mediadrm/MediaCasService.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef MEDIA_CAS_SERVICE_H_
+#define MEDIA_CAS_SERVICE_H_
+
+#include <android/media/BnMediaCasService.h>
+
+#include "FactoryLoader.h"
+
+namespace android {
+using binder::Status;
+struct CasFactory;
+struct DescramblerFactory;
+
+class MediaCasService : public BnMediaCasService {
+public:
+ static void instantiate();
+
+ virtual Status enumeratePlugins(
+ vector<ParcelableCasPluginDescriptor>* results) override;
+
+ virtual Status isSystemIdSupported(
+ int32_t CA_system_id, bool* result) override;
+
+ virtual Status createPlugin(
+ int32_t CA_system_id,
+ const sp<ICasListener> &listener,
+ sp<ICas>* result) override;
+
+ virtual Status isDescramblerSupported(
+ int32_t CA_system_id, bool* result) override;
+
+ virtual Status createDescrambler(
+ int32_t CA_system_id, sp<IDescrambler>* result) override;
+
+private:
+ FactoryLoader<CasFactory> *mCasLoader;
+ FactoryLoader<DescramblerFactory> *mDescramblerLoader;
+
+ MediaCasService();
+ virtual ~MediaCasService();
+};
+
+} // namespace android
+
+#endif // MEDIA_CAS_SERVICE_H_
diff --git a/services/mediadrm/main_mediadrmserver.cpp b/services/mediadrm/main_mediadrmserver.cpp
index b767b8c..b685ae0 100644
--- a/services/mediadrm/main_mediadrmserver.cpp
+++ b/services/mediadrm/main_mediadrmserver.cpp
@@ -27,6 +27,7 @@
#include <cutils/properties.h>
#include <utils/Log.h>
#include "MediaDrmService.h"
+#include "MediaCasService.h"
using namespace android;
@@ -38,6 +39,7 @@
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
MediaDrmService::instantiate();
+ MediaCasService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
diff --git a/services/radio/RadioHalHidl.cpp b/services/radio/RadioHalHidl.cpp
index 3dcf2f3..bfc5500 100644
--- a/services/radio/RadioHalHidl.cpp
+++ b/services/radio/RadioHalHidl.cpp
@@ -116,7 +116,7 @@
sp<IBroadcastRadio> RadioHalHidl::getService()
{
if (mHalModule == 0) {
- sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService("broadcastradio");
+ sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService();
if (factory != 0) {
factory->connectModule(static_cast<Class>(mClassId),
[&](Result retval, const ::android::sp<IBroadcastRadio>& result) {