goldfish-codecs: add avcdec
This is used to pass h264 decoding to host h264 decoders.
BUG: 124388359
This CL is based on the following cl:
joshuaduong@
ag/9406402 and ag/9406404
Change-Id: I52a17a917e7bee24ab8e46317d1715ead11e469c
diff --git a/Android.mk b/Android.mk
index 467dbcd..2c0a5c2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -163,6 +163,7 @@
# hardware codecs enabled after P
include $(GOLDFISH_OPENGL_PATH)/system/codecs/omx/common/Android.mk
include $(GOLDFISH_OPENGL_PATH)/system/codecs/omx/plugin/Android.mk
+ include $(GOLDFISH_OPENGL_PATH)/system/codecs/omx/avcdec/Android.mk
include $(GOLDFISH_OPENGL_PATH)/system/codecs/omx/vpxdec/Android.mk
endif
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b7615d0..eba847a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@
# instead run make from .../device/generic/goldfish-opengl
# which will re-generate this file.
set(GOLDFISH_DEVICE_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/./Android.mk" "e4989c6c970b11f3d6baf80ac7115cc18f90031d0df26db2002c984a4b39229b")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/./Android.mk" "2c3250b596a2b161e479dd3624a74ae6e485d6238d59d9a5dc55064c46482943")
add_subdirectory(shared/OpenglCodecCommon)
add_subdirectory(system/GLESv1_enc)
add_subdirectory(system/GLESv2_enc)
@@ -14,4 +14,4 @@
add_subdirectory(system/GLESv2)
add_subdirectory(system/gralloc)
add_subdirectory(system/egl)
-add_subdirectory(system/vulkan)
\ No newline at end of file
+add_subdirectory(system/vulkan)
diff --git a/system/codecs/omx/avcdec/Android.mk b/system/codecs/omx/avcdec/Android.mk
new file mode 100644
index 0000000..ea107db
--- /dev/null
+++ b/system/codecs/omx/avcdec/Android.mk
@@ -0,0 +1,48 @@
+#
+# Copyright 2019 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.
+#
+LOCAL_PATH := $(call my-dir)
+
+commonSources := \
+ GoldfishAVCDec.cpp \
+ MediaH264Decoder.cpp
+
+$(call emugl-begin-shared-library,libstagefright_goldfish_avcdec$(GOLDFISH_OPENGL_LIB_SUFFIX))
+
+LOCAL_SRC_FILES := $(commonSources)
+
+LOCAL_CFLAGS += -DLOG_TAG=\"goldfish_avcdec\"
+LOCAL_CFLAGS += -Wno-unused-private-field
+
+$(call emugl-export,SHARED_LIBRARIES,libcutils libutils liblog)
+
+LOCAL_HEADER_LIBRARIES := media_plugin_headers \
+ libmedia_headers \
+ libbinder_headers \
+ libhidlbase_impl_internal \
+ libbase
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libutils \
+ liblog \
+ libcutils \
+ android.hardware.media.omx@1.0 \
+ libstagefright_foundation
+
+$(call emugl-export,C_INCLUDES,$(LOCAL_PATH))
+$(call emugl-import,libgoldfish_codecs_common)
+$(call emugl-import,libstagefrighthw)
+$(call emugl-end-module)
diff --git a/system/codecs/omx/avcdec/GoldfishAVCDec.cpp b/system/codecs/omx/avcdec/GoldfishAVCDec.cpp
new file mode 100644
index 0000000..cc57f4c
--- /dev/null
+++ b/system/codecs/omx/avcdec/GoldfishAVCDec.cpp
@@ -0,0 +1,479 @@
+/*
+ * Copyright 2015 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
+#include <utils/Log.h>
+
+#include "GoldfishAVCDec.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <OMX_VideoExt.h>
+#include <inttypes.h>
+
+namespace android {
+
+#define componentName "video_decoder.avc"
+#define codingType OMX_VIDEO_CodingAVC
+#define CODEC_MIME_TYPE MEDIA_MIMETYPE_VIDEO_AVC
+
+/** Function and structure definitions to keep code similar for each codec */
+#define ivdec_api_function ih264d_api_function
+#define ivdext_create_ip_t ih264d_create_ip_t
+#define ivdext_create_op_t ih264d_create_op_t
+#define ivdext_delete_ip_t ih264d_delete_ip_t
+#define ivdext_delete_op_t ih264d_delete_op_t
+#define ivdext_ctl_set_num_cores_ip_t ih264d_ctl_set_num_cores_ip_t
+#define ivdext_ctl_set_num_cores_op_t ih264d_ctl_set_num_cores_op_t
+
+#define IVDEXT_CMD_CTL_SET_NUM_CORES \
+ (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
+
+static const CodecProfileLevel kProfileLevels[] = {
+ { OMX_VIDEO_AVCProfileConstrainedBaseline, OMX_VIDEO_AVCLevel52 },
+
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel52 },
+
+ { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel52 },
+
+ { OMX_VIDEO_AVCProfileConstrainedHigh, OMX_VIDEO_AVCLevel52 },
+
+ { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel52 },
+};
+
+GoldfishAVCDec::GoldfishAVCDec(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : GoldfishVideoDecoderOMXComponent(
+ name, componentName, codingType,
+ kProfileLevels, ARRAY_SIZE(kProfileLevels),
+ 320 /* width */, 240 /* height */, callbacks,
+ appData, component),
+ mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
+ mChangingResolution(false),
+ mSignalledError(false),
+ mInputOffset(0){
+ initPorts(
+ 1 /* numMinInputBuffers */, kNumBuffers, INPUT_BUF_SIZE,
+ 1 /* numMinOutputBuffers */, kNumBuffers, CODEC_MIME_TYPE);
+
+ mTimeStart = mTimeEnd = systemTime();
+
+ // If input dump is enabled, then open create an empty file
+ GENERATE_FILE_NAMES();
+ CREATE_DUMP_FILE(mInFile);
+}
+
+GoldfishAVCDec::~GoldfishAVCDec() {
+ CHECK_EQ(deInitDecoder(), (status_t)OK);
+}
+
+void GoldfishAVCDec::logVersion() {
+ // TODO: get emulation decoder implementation version from the host.
+ ALOGV("GoldfishAVC decoder version 1.0");
+}
+
+status_t GoldfishAVCDec::resetPlugin() {
+ mIsInFlush = false;
+ mReceivedEOS = false;
+
+ memset(mTimeStamps, 0, sizeof(mTimeStamps));
+ memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
+
+ /* Initialize both start and end times */
+ mTimeStart = mTimeEnd = systemTime();
+
+ return OK;
+}
+
+status_t GoldfishAVCDec::resetDecoder() {
+ // The resolution may have changed, so our safest bet is to just destroy the
+ // current context and recreate another one, with the new width and height.
+ mContext->destroyH264Context();
+ mContext->initH264Context(mWidth,
+ mHeight,
+ outputBufferWidth(),
+ outputBufferHeight(),
+ MediaH264Decoder::PixelFormat::YUV420P);
+
+ return OK;
+}
+
+status_t GoldfishAVCDec::setFlushMode() {
+ /* Set the decoder in Flush mode, subsequent decode() calls will flush */
+ mContext->flush();
+
+ mIsInFlush = true;
+ return OK;
+}
+
+status_t GoldfishAVCDec::initDecoder() {
+ /* Initialize the decoder */
+ mContext.reset(new MediaH264Decoder());
+ mContext->initH264Context(mWidth,
+ mHeight,
+ outputBufferWidth(),
+ outputBufferHeight(),
+ MediaH264Decoder::PixelFormat::YUV420P);
+
+ /* Reset the plugin state */
+ resetPlugin();
+
+ /* Get codec version */
+ logVersion();
+
+ return OK;
+}
+
+status_t GoldfishAVCDec::deInitDecoder() {
+ if (mContext) {
+ mContext->destroyH264Context();
+ mContext.reset();
+ }
+
+ mChangingResolution = false;
+
+ return OK;
+}
+
+void GoldfishAVCDec::onReset() {
+ GoldfishVideoDecoderOMXComponent::onReset();
+
+ mSignalledError = false;
+ mInputOffset = 0;
+ resetDecoder();
+ resetPlugin();
+}
+
+bool GoldfishAVCDec::getVUIParams() {
+ ALOGE("%s: NOT IMPLEMENTED", __func__);
+ /*
+ IV_API_CALL_STATUS_T status;
+ ih264d_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip;
+ ih264d_ctl_get_vui_params_op_t s_ctl_get_vui_params_op;
+
+ s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+ s_ctl_get_vui_params_ip.e_sub_cmd =
+ (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_GET_VUI_PARAMS;
+
+ s_ctl_get_vui_params_ip.u4_size =
+ sizeof(ih264d_ctl_get_vui_params_ip_t);
+
+ s_ctl_get_vui_params_op.u4_size = sizeof(ih264d_ctl_get_vui_params_op_t);
+
+ status = ivdec_api_function(
+ (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_vui_params_ip,
+ (void *)&s_ctl_get_vui_params_op);
+
+ if (status != IV_SUCCESS) {
+ ALOGW("Error in getting VUI params: 0x%x",
+ s_ctl_get_vui_params_op.u4_error_code);
+ return false;
+ }
+
+ int32_t primaries = s_ctl_get_vui_params_op.u1_colour_primaries;
+ int32_t transfer = s_ctl_get_vui_params_op.u1_tfr_chars;
+ int32_t coeffs = s_ctl_get_vui_params_op.u1_matrix_coeffs;
+ bool fullRange = s_ctl_get_vui_params_op.u1_video_full_range_flag;
+
+ ColorAspects colorAspects;
+ ColorUtils::convertIsoColorAspectsToCodecAspects(
+ primaries, transfer, coeffs, fullRange, colorAspects);
+
+ // Update color aspects if necessary.
+ if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
+ mBitstreamColorAspects = colorAspects;
+ status_t err = handleColorAspectsChange();
+ CHECK(err == OK);
+ }
+ return true;
+ */
+ return false;
+}
+
+bool GoldfishAVCDec::setDecodeArgs(
+ OMX_BUFFERHEADERTYPE *inHeader,
+ OMX_BUFFERHEADERTYPE *outHeader,
+ size_t timeStampIx) {
+ size_t sizeY = outputBufferWidth() * outputBufferHeight();
+ size_t sizeUV = sizeY / 4;
+
+ /* When in flush and after EOS with zero byte input,
+ * inHeader is set to zero. Hence check for non-null */
+ if (inHeader) {
+ mCurrentTs = timeStampIx;
+ mConsumedBytes = inHeader->nFilledLen - mInputOffset;
+ mInPBuffer = inHeader->pBuffer + inHeader->nOffset + mInputOffset;
+ } else {
+ mCurrentTs = 0;
+ mConsumedBytes = 0;
+ mInPBuffer = nullptr;
+ }
+
+ if (outHeader) {
+ if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
+ android_errorWriteLog(0x534e4554, "27833616");
+ return false;
+ }
+ mOutHeaderBuf = outHeader->pBuffer;
+ } else {
+ // We flush out on the host side
+ mOutHeaderBuf = nullptr;
+ }
+
+ return true;
+}
+
+void GoldfishAVCDec::onPortFlushCompleted(OMX_U32 portIndex) {
+ /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
+ if (kOutputPortIndex == portIndex) {
+ setFlushMode();
+ resetPlugin();
+ } else {
+ mInputOffset = 0;
+ }
+}
+
+void GoldfishAVCDec::onQueueFilled(OMX_U32 portIndex) {
+ UNUSED(portIndex);
+ OMX_BUFFERHEADERTYPE *inHeader = NULL;
+ BufferInfo *inInfo = NULL;
+
+ if (mSignalledError) {
+ return;
+ }
+ if (mOutputPortSettingsChange != NONE) {
+ return;
+ }
+
+ if (mContext == nullptr) {
+ if (OK != initDecoder()) {
+ ALOGE("Failed to initialize decoder");
+ notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
+ }
+
+ List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+ List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+
+ while (!outQueue.empty()) {
+ BufferInfo *outInfo;
+ OMX_BUFFERHEADERTYPE *outHeader;
+ size_t timeStampIx = 0;
+
+ if (!mIsInFlush && (NULL == inHeader)) {
+ if (!inQueue.empty()) {
+ inInfo = *inQueue.begin();
+ inHeader = inInfo->mHeader;
+ if (inHeader == NULL) {
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ continue;
+ }
+ } else {
+ break;
+ }
+ }
+
+ outInfo = *outQueue.begin();
+ outHeader = outInfo->mHeader;
+ outHeader->nFlags = 0;
+ outHeader->nTimeStamp = 0;
+ outHeader->nOffset = 0;
+
+ if (inHeader != NULL) {
+ if (inHeader->nFilledLen == 0) {
+ // An empty buffer can be end of stream (EOS) buffer, so
+ // we'll set the decoder in flush mode if so. If it's not EOS,
+ // then just release the buffer.
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ if (!(inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
+ return;
+ }
+
+ mReceivedEOS = true;
+ inHeader = NULL;
+ setFlushMode();
+ } else if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ mReceivedEOS = true;
+ }
+ }
+
+ /* Get a free slot in timestamp array to hold input timestamp */
+ {
+ size_t i;
+ timeStampIx = 0;
+ for (i = 0; i < MAX_TIME_STAMPS; i++) {
+ if (!mTimeStampsValid[i]) {
+ timeStampIx = i;
+ break;
+ }
+ }
+ if (inHeader != NULL) {
+ mTimeStampsValid[timeStampIx] = true;
+ mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
+ }
+ }
+
+ {
+ nsecs_t timeDelay, timeTaken;
+
+ if (!setDecodeArgs(inHeader, outHeader, timeStampIx)) {
+ ALOGE("Decoder arg setup failed");
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
+
+ mTimeStart = systemTime();
+ /* Compute time elapsed between end of previous decode()
+ * to start of current decode() */
+ timeDelay = mTimeStart - mTimeEnd;
+
+ // TODO: We also need to send the timestamp
+ h264_result_t h264Res = {(int)MediaH264Decoder::Err::NoErr, 0};
+ if (inHeader != nullptr) {
+ ALOGE("Decoding frame(sz=%lu)", (unsigned long)(inHeader->nFilledLen - mInputOffset));
+ h264Res = mContext->decodeFrame(mInPBuffer,
+ inHeader->nFilledLen - mInputOffset);
+ mConsumedBytes = h264Res.bytesProcessed;
+ if (h264Res.ret == (int)MediaH264Decoder::Err::DecoderRestarted) {
+ // The host will always restart when given a new set of SPS
+ // and PPS frames.
+ mChangingResolution = true;
+ }
+ } else {
+ ALOGE("No more input data. Attempting to get a decoded frame, if any.");
+ }
+ h264_image_t img = mContext->getImage();
+
+
+ // TODO: support getVUIParams()
+// getVUIParams();
+
+ mTimeEnd = systemTime();
+ /* Compute time taken for decode() */
+ timeTaken = mTimeEnd - mTimeStart;
+
+ ALOGV("timeTaken=%6lldus delay=%6lldus numBytes=Nan",
+ (long long) (timeTaken / 1000LL), (long long) (timeDelay / 1000LL));
+
+ if ((inHeader != NULL) && (img.data == nullptr)) {
+ /* If the input did not contain picture data, then ignore
+ * the associated timestamp */
+ mTimeStampsValid[timeStampIx] = false;
+ }
+
+ // If the decoder is in the changing resolution mode and there is no output present,
+ // that means the switching is done and it's ready to reset the decoder and the plugin.
+ if (mChangingResolution && img.data == nullptr) {
+ mChangingResolution = false;
+ resetPlugin();
+ // The decoder on the host has actually already restarted given
+ // the new information, so we don't have to refeed the same
+ // information again.
+ mInputOffset += mConsumedBytes;
+ continue;
+ }
+
+ // Combine the resolution change and coloraspects change in one
+ // PortSettingChange event if necessary.
+ if (img.data != nullptr) {
+ bool portWillReset = false;
+ handlePortSettingsChange(&portWillReset, img.width, img.height);
+ if (portWillReset) {
+ ALOGE("port resetting (img.width=%u, img.height=%u, mWidth=%u, mHeight=%u)",
+ img.width, img.height, mWidth, mHeight);
+ resetDecoder();
+ resetPlugin();
+ return;
+ }
+ }
+
+ if (img.data != nullptr) {
+ outHeader->nFilledLen = img.ret;
+ memcpy(outHeader->pBuffer, img.data, img.ret);
+ outHeader->nTimeStamp = mTimeStamps[mCurrentTs];
+ mTimeStampsValid[mCurrentTs] = false;
+
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(outQueue.begin());
+ outInfo = NULL;
+ notifyFillBufferDone(outHeader);
+ outHeader = NULL;
+ } else if (mIsInFlush) {
+ /* If in flush mode and no output is returned by the codec,
+ * then come out of flush mode */
+ mIsInFlush = false;
+
+ /* If EOS was recieved on input port and there is no output
+ * from the codec, then signal EOS on output port */
+ if (mReceivedEOS) {
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
+
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(outQueue.begin());
+ outInfo = NULL;
+ notifyFillBufferDone(outHeader);
+ outHeader = NULL;
+ resetPlugin();
+ }
+ }
+ mInputOffset += mConsumedBytes;
+ }
+
+ // If more than 4 bytes are remaining in input, then do not release it
+ if (inHeader != NULL && ((inHeader->nFilledLen - mInputOffset) <= 4)) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ mInputOffset = 0;
+
+ /* If input EOS is seen and decoder is not in flush mode,
+ * set the decoder in flush mode.
+ * There can be a case where EOS is sent along with last picture data
+ * In that case, only after decoding that input data, decoder has to be
+ * put in flush. This case is handled here */
+
+ if (mReceivedEOS && !mIsInFlush) {
+ setFlushMode();
+ }
+ }
+ }
+}
+
+int GoldfishAVCDec::getColorAspectPreference() {
+ return kPreferBitstream;
+}
+
+} // namespace android
+
+android::GoldfishOMXComponent *createGoldfishOMXComponent(
+ const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
+ OMX_COMPONENTTYPE **component) {
+ return new android::GoldfishAVCDec(name, callbacks, appData, component);
+}
+
diff --git a/system/codecs/omx/avcdec/GoldfishAVCDec.h b/system/codecs/omx/avcdec/GoldfishAVCDec.h
new file mode 100644
index 0000000..f0e338c
--- /dev/null
+++ b/system/codecs/omx/avcdec/GoldfishAVCDec.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2015 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 GOLDFISH_H264_DEC_H_
+
+#define GOLDFISH_H264_DEC_H_
+
+#include "GoldfishVideoDecoderOMXComponent.h"
+#include "MediaH264Decoder.h"
+#include <sys/time.h>
+
+namespace android {
+
+/** Number of entries in the time-stamp array */
+#define MAX_TIME_STAMPS 64
+
+/** Maximum number of cores supported by the codec */
+#define CODEC_MAX_NUM_CORES 4
+
+#define CODEC_MAX_WIDTH 1920
+
+#define CODEC_MAX_HEIGHT 1088
+
+/** Input buffer size */
+#define INPUT_BUF_SIZE (1024 * 1024)
+
+#define MIN(a, b) ((a) < (b)) ? (a) : (b)
+
+/** Used to remove warnings about unused parameters */
+#define UNUSED(x) ((void)(x))
+
+struct GoldfishAVCDec : public GoldfishVideoDecoderOMXComponent {
+ GoldfishAVCDec(const char *name, const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData, OMX_COMPONENTTYPE **component);
+
+protected:
+ virtual ~GoldfishAVCDec();
+
+ virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onPortFlushCompleted(OMX_U32 portIndex);
+ virtual void onReset();
+ virtual int getColorAspectPreference();
+private:
+ // Number of input and output buffers
+ enum {
+ kNumBuffers = 8
+ };
+
+ size_t mNumCores; // Number of cores to be uesd by the codec
+
+ nsecs_t mTimeStart; // Time at the start of decode()
+ nsecs_t mTimeEnd; // Time at the end of decode()
+
+ // Status of entries in the timestamp array
+ bool mTimeStampsValid[MAX_TIME_STAMPS];
+
+ // Timestamp array - Since codec does not take 64 bit timestamps,
+ // they are maintained in the plugin
+ OMX_S64 mTimeStamps[MAX_TIME_STAMPS];
+
+#ifdef FILE_DUMP_ENABLE
+ char mInFile[200];
+#endif /* FILE_DUMP_ENABLE */
+
+ OMX_COLOR_FORMATTYPE mOmxColorFormat; // OMX Color format
+
+ bool mIsInFlush; // codec is flush mode
+ bool mReceivedEOS; // EOS is receieved on input port
+
+ // The input stream has changed to a different resolution, which is still supported by the
+ // codec. So the codec is switching to decode the new resolution.
+ bool mChangingResolution;
+ bool mSignalledError;
+ size_t mInputOffset;
+
+ status_t initDecoder();
+ status_t deInitDecoder();
+ status_t setFlushMode();
+ status_t setParams(size_t stride);
+ void logVersion();
+ status_t setNumCores();
+ status_t resetDecoder();
+ status_t resetPlugin();
+
+
+ bool setDecodeArgs(
+ OMX_BUFFERHEADERTYPE *inHeader,
+ OMX_BUFFERHEADERTYPE *outHeader,
+ size_t timeStampIx);
+
+ bool getVUIParams();
+
+ std::unique_ptr<MediaH264Decoder> mContext;
+ uint64_t mCurrentTs = 0;
+ uint64_t mConsumedBytes = 0;
+ uint8_t* mInPBuffer = nullptr;
+ uint8_t* mOutHeaderBuf = nullptr;
+ DISALLOW_EVIL_CONSTRUCTORS(GoldfishAVCDec);
+};
+#ifdef FILE_DUMP_ENABLE
+
+#define INPUT_DUMP_PATH "/sdcard/media/avcd_input"
+#define INPUT_DUMP_EXT "h264"
+
+#define GENERATE_FILE_NAMES() { \
+ strcpy(mInFile, ""); \
+ sprintf(mInFile, "%s_%lld.%s", INPUT_DUMP_PATH, \
+ (long long) mTimeStart, \
+ INPUT_DUMP_EXT); \
+}
+
+#define CREATE_DUMP_FILE(m_filename) { \
+ FILE *fp = fopen(m_filename, "wb"); \
+ if (fp != NULL) { \
+ fclose(fp); \
+ } else { \
+ ALOGD("Could not open file %s", m_filename); \
+ } \
+}
+#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset)\
+{ \
+ FILE *fp = fopen(m_filename, "ab"); \
+ if (fp != NULL && m_buf != NULL && m_offset == 0) { \
+ int i; \
+ i = fwrite(m_buf, 1, m_size, fp); \
+ ALOGD("fwrite ret %d to write %d", i, m_size); \
+ if (i != (int) m_size) { \
+ ALOGD("Error in fwrite, returned %d", i); \
+ perror("Error in write to file"); \
+ } \
+ } else if (fp == NULL) { \
+ ALOGD("Could not write to file %s", m_filename);\
+ } \
+ if (fp) { \
+ fclose(fp); \
+ } \
+}
+#else /* FILE_DUMP_ENABLE */
+#define INPUT_DUMP_PATH
+#define INPUT_DUMP_EXT
+#define OUTPUT_DUMP_PATH
+#define OUTPUT_DUMP_EXT
+#define GENERATE_FILE_NAMES()
+#define CREATE_DUMP_FILE(m_filename)
+#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset)
+#endif /* FILE_DUMP_ENABLE */
+
+} // namespace android
+
+#endif // GOLDFISH_H264_DEC_H_
diff --git a/system/codecs/omx/avcdec/MediaH264Decoder.cpp b/system/codecs/omx/avcdec/MediaH264Decoder.cpp
new file mode 100644
index 0000000..aa97c2d
--- /dev/null
+++ b/system/codecs/omx/avcdec/MediaH264Decoder.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2015 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 <utils/Log.h>
+
+#include "MediaH264Decoder.h"
+#include "goldfish_media_utils.h"
+#include <string.h>
+
+void MediaH264Decoder::initH264Context(unsigned int width,
+ unsigned int height,
+ unsigned int outWidth,
+ unsigned int outHeight,
+ PixelFormat pixFmt) {
+ auto transport = GoldfishMediaTransport::getInstance();
+ transport->writeParam(width, 0);
+ transport->writeParam(height, 1);
+ transport->writeParam(outWidth, 2);
+ transport->writeParam(outHeight, 3);
+ transport->writeParam(static_cast<uint64_t>(pixFmt), 4);
+ transport->sendOperation(MediaCodecType::H264Codec,
+ MediaOperation::InitContext);
+}
+
+void MediaH264Decoder::destroyH264Context() {
+ auto transport = GoldfishMediaTransport::getInstance();
+ transport->sendOperation(MediaCodecType::H264Codec,
+ MediaOperation::DestroyContext);
+}
+
+h264_result_t MediaH264Decoder::decodeFrame(uint8_t* img, size_t szBytes) {
+ auto transport = GoldfishMediaTransport::getInstance();
+ uint8_t* hostSrc = transport->getInputAddr();
+ if (img != nullptr && szBytes > 0) {
+ memcpy(hostSrc, img, szBytes);
+ }
+ transport->writeParam(transport->offsetOf((uint64_t)(hostSrc)), 0);
+ transport->writeParam((uint64_t)szBytes, 1);
+ transport->sendOperation(MediaCodecType::H264Codec,
+ MediaOperation::DecodeImage);
+
+ h264_result_t res = {0, 0};
+
+ auto* retptr = transport->getReturnAddr();
+ res.bytesProcessed = *(uint64_t*)(retptr);
+ res.ret = *(int*)(retptr + 8);
+
+ return res;
+}
+
+void MediaH264Decoder::flush() {
+ auto transport = GoldfishMediaTransport::getInstance();
+ transport->sendOperation(MediaCodecType::H264Codec,
+ MediaOperation::Flush);
+}
+
+h264_image_t MediaH264Decoder::getImage() {
+ h264_image_t res = { nullptr, 0, 0, 0 };
+ auto transport = GoldfishMediaTransport::getInstance();
+ uint8_t* dst = transport->getOutputAddr();
+ transport->writeParam(transport->offsetOf((uint64_t)(dst)), 0);
+ transport->sendOperation(MediaCodecType::H264Codec,
+ MediaOperation::GetImage);
+ auto* retptr = transport->getReturnAddr();
+ res.ret = *(int*)(retptr);
+ if (res.ret >= 0) {
+ res.data = dst;
+ res.width = *(uint32_t*)(retptr + 8);
+ res.height = *(uint32_t*)(retptr + 16);
+ }
+
+ return res;
+}
diff --git a/system/codecs/omx/avcdec/MediaH264Decoder.h b/system/codecs/omx/avcdec/MediaH264Decoder.h
new file mode 100644
index 0000000..510da28
--- /dev/null
+++ b/system/codecs/omx/avcdec/MediaH264Decoder.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2015 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 GOLDFISH_MEDIA_H264_DEC_H_
+#define GOLDFISH_MEDIA_H264_DEC_H_
+
+struct h264_result_t {
+ int ret;
+ uint64_t bytesProcessed;
+};
+
+struct h264_image_t {
+ const uint8_t* data;
+ uint32_t width;
+ uint32_t height;
+ // on success, |ret| will indicate the size of |data|.
+ // If failed, |ret| will contain some negative error code.
+ int ret;
+};
+
+class MediaH264Decoder {
+public:
+ MediaH264Decoder() = default;
+ virtual ~MediaH264Decoder() = default;
+
+ enum class PixelFormat : uint8_t {
+ YUV420P = 0,
+ UYVY422 = 1,
+ BGRA8888 = 2,
+ };
+
+ enum class Err : int {
+ NoErr = 0,
+ NoDecodedFrame = -1,
+ InitContextFailed = -2,
+ DecoderRestarted = -3,
+ NALUIgnored = -4,
+ };
+
+ void initH264Context(unsigned int width,
+ unsigned int height,
+ unsigned int outWidth,
+ unsigned int outHeight,
+ PixelFormat pixFmt);
+ void destroyH264Context();
+ h264_result_t decodeFrame(uint8_t* img, size_t szBytes);
+ void flush();
+ h264_image_t getImage();
+};
+#endif
diff --git a/system/codecs/omx/avcdec/exports.lds b/system/codecs/omx/avcdec/exports.lds
new file mode 100644
index 0000000..e6674f2
--- /dev/null
+++ b/system/codecs/omx/avcdec/exports.lds
@@ -0,0 +1,5 @@
+{
+ global:
+ _Z26createGoldfishOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE;
+ local: *;
+};