summaryrefslogtreecommitdiffstats
path: root/test/VTC
diff options
context:
space:
mode:
authorPrasanna Kumar M.R <prasanna.kumarmr@ti.com>2012-04-03 16:25:11 -0500
committerDaniel Levin <dendy@ti.com>2012-07-25 08:56:29 -0500
commit5d732514084b76d6d047b89066ad679a098c89d6 (patch)
tree343076ca3f219e4b16edeffefef47efaf28962e9 /test/VTC
parent286e1a5ed9bb6113b754921229f94cf18d2b31d5 (diff)
downloadhardware_ti_omap4-5d732514084b76d6d047b89066ad679a098c89d6.zip
hardware_ti_omap4-5d732514084b76d6d047b89066ad679a098c89d6.tar.gz
hardware_ti_omap4-5d732514084b76d6d047b89066ad679a098c89d6.tar.bz2
New VTC loopback application
In this application: - Camera Preview is started. - Preview Frames are sent to encoder for encoding. - The encoded frames are then sent to the decoder for decoding. - The decoded frames are then rendered along side the preview window. The application can be run in frame mode or slice mode Slice mode support is included at: - Camera->encoder level (OMX tunneling) - Encoder output data Run "VTCLoopbackTest -h" to see all the supported features. Change-Id: I4462adad8dde32d70d6c8ba13197296b96f96827 Signed-off-by: Prasanna Kumar M.R. <prasanna.kumarmr@ti.com> Signed-off-by: Jorge E. Solano <jsolano@ti.com> Signed-off-by: Anu Sundararajan <sanuradha@ti.com>
Diffstat (limited to 'test/VTC')
-rw-r--r--test/VTC/Android.mk71
-rw-r--r--test/VTC/CameraHardwareInterfaceTest.cpp304
-rw-r--r--test/VTC/IOMXDecoder.cpp1077
-rw-r--r--test/VTC/IOMXDecoder.h252
-rw-r--r--test/VTC/IOMXEncoder.cpp1158
-rw-r--r--test/VTC/IOMXEncoder.h193
-rw-r--r--test/VTC/VTCLoopback.cpp883
-rw-r--r--test/VTC/VTCLoopback.h145
-rw-r--r--test/VTC/VTCTestApp.cpp80
9 files changed, 4112 insertions, 51 deletions
diff --git a/test/VTC/Android.mk b/test/VTC/Android.mk
index 337b13c..ef344f3 100644
--- a/test/VTC/Android.mk
+++ b/test/VTC/Android.mk
@@ -29,3 +29,74 @@ LOCAL_MODULE_TAGS:= optional
LOCAL_MODULE := VTCTestApp
include $(BUILD_EXECUTABLE)
+###############################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := VTCLoopback.cpp IOMXEncoder.cpp IOMXDecoder.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcamera_client \
+ libstagefright \
+ libmedia \
+ libbinder \
+ libtiutils \
+ libcutils \
+ libutils \
+ liblog \
+ libgui \
+ libui \
+
+LOCAL_C_INCLUDES += \
+ $(TOP)/frameworks/base/include/ui \
+ $(TOP)/frameworks/base/include/surfaceflinger \
+ $(TOP)/frameworks/base/include/camera \
+ $(TOP)/frameworks/base/include/media \
+ $(TOP)/frameworks/base/include/media/stagefright \
+ $(TOP)/hardware/ti/domx/omx_core/inc \
+ $(TOP)/hardware/ti/omap4xxx/libtiutils
+
+LOCAL_CFLAGS +=-Wall -fno-short-enums -O0 -g
+
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_TAGS:= optional
+LOCAL_MODULE := VTCLoopbackTest
+include $(BUILD_EXECUTABLE)
+
+###############################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= CameraHardwareInterfaceTest.cpp
+
+LOCAL_SHARED_LIBRARIES:= \
+ libdl \
+ libui \
+ libutils \
+ libcutils \
+ libbinder \
+ libmedia \
+ libui \
+ libgui \
+ libcamera_client \
+ libhardware
+
+LOCAL_C_INCLUDES += \
+ frameworks/base/include/ui \
+ frameworks/base/include/surfaceflinger \
+ frameworks/base/include/camera \
+ frameworks/base/include/media \
+ frameworks/base/services/camera/libcameraservice \
+ $(PV_INCLUDES)
+
+LOCAL_MODULE:= CameraHardwareInterfaceTest
+LOCAL_MODULE_TAGS:= tests
+
+LOCAL_CFLAGS += -Wall -fno-short-enums -O0 -g -D___ANDROID___
+
+ifeq ($(TARGET_BOARD_PLATFORM),omap4)
+ LOCAL_CFLAGS += -DTARGET_OMAP4
+endif
+
+include $(BUILD_HEAPTRACKED_EXECUTABLE)
+
diff --git a/test/VTC/CameraHardwareInterfaceTest.cpp b/test/VTC/CameraHardwareInterfaceTest.cpp
new file mode 100644
index 0000000..70d94dc
--- /dev/null
+++ b/test/VTC/CameraHardwareInterfaceTest.cpp
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "CamHalTest"
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <semaphore.h>
+#include <pthread.h>
+
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+
+#include <camera/Camera.h>
+#include <camera/ICamera.h>
+
+#include <cutils/log.h>
+#include <media/stagefright/CameraSource.h>
+#include <media/stagefright/MetaData.h>
+
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/ISurface.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include <cutils/properties.h>
+
+#include <hardware/camera.h>
+#include <hardware/hardware.h>
+#include "CameraHardwareInterface.h"
+
+using namespace android;
+
+int startPreviewNow = 1;
+int mWidth = 640;
+int mHeight = 480;
+
+static int cameraId = 0;
+static int mPriority = 0;
+camera_module_t *mModule;
+sp<CameraHardwareInterface> mHardware = NULL;
+
+static int surface_setup_complete = 0;
+sp<Surface> mSurface;
+sp<SurfaceComposerClient> mComposerClient;
+sp<SurfaceControl> mSurfaceControl;
+sp<ANativeWindow> mWindow;
+
+static pthread_cond_t mCond;
+static pthread_mutex_t mMutex;
+
+
+void my_notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user) {
+ LOGD("\n\nnotifyCallback(%d)\n\n", msgType);
+}
+
+void my_dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata, void* user) {
+ LOGD("\n\ndataCallback(%d)\n\n", msgType);
+}
+
+void my_dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr, void* user) {
+ LOGD("\n\ndataCallbackTimestamp(%d)\n\n", msgType);
+}
+
+void surfaceInit() {
+ status_t retval;
+
+ mComposerClient = new SurfaceComposerClient;
+
+ retval = mComposerClient->initCheck();
+ if (retval != NO_ERROR) {
+ LOGE("mCOmposerClient->initCheck failed");
+ return;
+ }
+
+ mSurfaceControl = mComposerClient->createSurface(String8("NativeSurface"),
+ 0, mWidth, mHeight,
+ PIXEL_FORMAT_OPAQUE, ISurfaceComposer::eFXSurfaceNormal);
+
+ if (mSurfaceControl == NULL) {
+ LOGE("mComposerClient->createSurface failed");
+ return;
+ }
+
+ if (mSurfaceControl->isValid()) {
+ LOGE("mSurfaceControl is valid");
+ } else {
+ LOGE("mSurfaceControl is not valid");
+ return;
+ }
+
+ SurfaceComposerClient::openGlobalTransaction();
+
+ retval = mSurfaceControl->setPosition(100,100);
+ if (retval != NO_ERROR) {
+ LOGE("mCOmposerClient->setPosition failed");
+ return;
+ }
+
+ retval = mSurfaceControl->setSize(400,400);
+ if (retval != NO_ERROR) {
+ LOGE("mCOmposerClient->setPosition failed");
+ return;
+ }
+
+ retval = mSurfaceControl->setLayer(999990);
+ if (retval != NO_ERROR) {
+ LOGE("mCOmposerClient->setLayer 999990 failed");
+ return;
+ }
+
+ retval = mSurfaceControl->show();
+ if (retval != NO_ERROR) {
+ LOGE("mCOmposerClient->show failed");
+ return;
+ }
+ SurfaceComposerClient::closeGlobalTransaction();
+
+ mSurface = mSurfaceControl->getSurface();
+ if (mSurface == NULL) {
+ LOGE("mSurfaceControl->getSurface failed");
+ return;
+ }
+
+ surface_setup_complete = 1;
+}
+
+int main (int argc, char* argv[]) {
+ status_t result;
+ char cmd[160],*cmdptr;
+ struct camera_info info;
+ char camera_device_name[10];
+
+ sp<ProcessState> proc(ProcessState::self());
+ ProcessState::self()->startThreadPool();
+
+ if (argc >= 2) {
+ mPriority = atoi(argv[1]);
+ }
+
+ if (argc == 3) {
+ startPreviewNow = atoi(argv[2]);
+ }
+
+ if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
+ (const hw_module_t **)&mModule) < 0) {
+ LOGE("Could not load camera HAL module");
+ return -1;
+ }
+ LOGD("\nLoaded the camera module\n");
+
+
+ if (mModule->get_camera_info(cameraId, &info) != OK) {
+ LOGE("Invalid camera id %d", cameraId);
+ return -1;
+ }
+ LOGD("\nLoaded the camera properties\n");
+
+ if (startPreviewNow == 0) return -1;
+
+ snprintf(camera_device_name, sizeof(camera_device_name), "%d", cameraId);
+ mHardware = new CameraHardwareInterface(camera_device_name);
+ if (mHardware->initialize(&mModule->common) != OK) {
+ mHardware.clear();
+ LOGE("mHardware->initialize FAILED");
+ return -1;
+ }
+ LOGD("\nInitialized the camera hardware\n");
+
+ mHardware->setCallbacks(my_notifyCallback,
+ my_dataCallback,
+ my_dataCallbackTimestamp,
+ (void *)cameraId);
+
+ mHardware->enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_PREVIEW_METADATA);
+
+ String8 param_str(mHardware->getParameters().flatten());
+ CameraParameters params(param_str);
+ params.setPreviewSize(mWidth, mHeight);
+ params.set("priority", mPriority);
+ //params.dump();
+ mHardware->setParameters(params);
+
+ surfaceInit();
+ if (surface_setup_complete == 0) {
+ LOGE("\n\nsurfaceInit failed! \n\n");
+ goto EXIT;
+ }
+
+ mWindow = mSurface;
+ if (mWindow == 0) {
+ LOGE("\n\nWhy is mWindow == 0?? \n\n");
+ goto EXIT;
+ }
+
+ result = native_window_api_connect(mWindow.get(), NATIVE_WINDOW_API_CAMERA);
+ if (result != NO_ERROR) {
+ LOGE("native_window_api_connect failed: %s (%d)", strerror(-result),
+ result);
+ goto EXIT;
+ }
+
+ native_window_set_scaling_mode(mWindow.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ native_window_set_buffers_transform(mWindow.get(), 0);
+
+ result = mHardware->setPreviewWindow(mWindow);
+ if (result != NO_ERROR) {
+ LOGE("mHardware->setPreviewWindow");
+ goto EXIT;
+ }
+
+ mHardware->startPreview();
+
+#if USE_TIMED_WAIT
+ pthread_mutex_init(&mMutex, NULL);
+ pthread_cond_init(&mCond, NULL);
+
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += 30;
+ pthread_mutex_lock(&mMutex);
+ pthread_cond_timedwait(&mCond, &mMutex, &ts);
+ pthread_mutex_unlock(&mMutex);
+#else
+
+ while (1) {
+ cmdptr = fgets(cmd, sizeof(cmd), stdin);
+ if (!strncmp(cmdptr,"quit",4)) {
+ break;
+ }
+ }
+#endif
+ LOGD("\n\n STOPPING PREVIEW \n\n");
+ mHardware->stopPreview();
+
+
+EXIT:
+ if (mHardware != 0){
+ mHardware->release();
+
+ if (mWindow != 0) {
+ result = native_window_api_disconnect(mWindow.get(), NATIVE_WINDOW_API_CAMERA);
+ if (result != NO_ERROR) {
+ LOGW("native_window_api_disconnect failed: %s (%d)", strerror(-result), result);
+ }
+ mWindow = 0;
+ }
+ mHardware.clear();
+ }
+
+ if ( NULL != mSurface.get() ) {
+ mSurface.clear();
+ }
+
+ if ( NULL != mSurfaceControl.get() ) {
+ mSurfaceControl->clear();
+ mSurfaceControl.clear();
+ }
+
+ if ( NULL != mComposerClient.get() ) {
+ mComposerClient->dispose();
+ mComposerClient.clear();
+ }
+
+#if USE_TIMED_WAIT
+ pthread_mutex_destroy(&mMutex);
+ pthread_cond_destroy(&mCond);
+#endif
+
+ LOGD("\n\n SUCCESS \n\n");
+
+ return 0;
+}
+
diff --git a/test/VTC/IOMXDecoder.cpp b/test/VTC/IOMXDecoder.cpp
new file mode 100644
index 0000000..d8f34ab
--- /dev/null
+++ b/test/VTC/IOMXDecoder.cpp
@@ -0,0 +1,1077 @@
+/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "VTCLoopback.h"
+#include "IOMXDecoder.h"
+#define LOG_TAG "VTC_DEC"
+#define LOG_NDEBUG 0
+
+#define NO_PORT_RECONFIG 1
+
+//Can have '7' in all cases except 1080p slice mode when VNF is enabled and
+//1080p frame mode with Vstab as we will reach Tiler 2-D boundary and alloc fails
+#define MAX_OUTPUT_BUF_NUM 5
+
+#define MAX_FRAME_WIDTH 2048 //For 1080p
+#define MAX_FRAME_HEIGHT 1184 //For 1080p
+
+#define MAX_FRAME_WIDTH_720P 1408 //For 720p
+#define MAX_FRAME_HEIGHT_720P 832 //For 720p
+
+#define MY_LOGV(x, ...) LOGV(x, ##__VA_ARGS__)
+
+using namespace android;
+
+
+static void PrintDecoderFPS() {
+ static int mFrameCount = 0;
+ static int mLastFrameCount = 0;
+ static nsecs_t mLastFpsTime = 0;
+ static float mFps = 0;
+ mFrameCount++;
+ if (!(mFrameCount & 0x1F)) {
+ nsecs_t now = systemTime();
+ nsecs_t diff = now - mLastFpsTime;
+ mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
+ mLastFpsTime = now;
+ mLastFrameCount = mFrameCount;
+ LOGD("Decoder: %d Frames, %f FPS", mFrameCount, mFps);
+ }
+ // XXX: mFPS has the value we want
+}
+
+static void PrintVTCLatency(nsecs_t ts) {
+ static int mFrameCount = 0;
+ static int64_t sum_latency_ms = 0;
+ int64_t now, diff_ms, avg_latency;
+
+ now = systemTime()/1000;
+ diff_ms = (now - ts) / 1000;
+ sum_latency_ms += diff_ms;
+ mFrameCount++;
+ if (!(mFrameCount & 0x1F)) {
+ avg_latency = sum_latency_ms / 32;
+ sum_latency_ms = 0;
+ LOGD("Avg Latency: %d Frames, %llu ms", mFrameCount, avg_latency);
+ }
+}
+
+bool OMXDecoder::SourceHandler::Handler() {
+ MY_LOGV("\n SourceHandler::Handler \n");
+ TIUTILS::Message msg;
+ volatile int forever = 1;
+
+ while(forever) {
+ TIUTILS::MessageQueue::waitForMsg(&mCommandMsgQ, NULL, NULL, -1);
+ {
+ Mutex::Autolock lock(mLock);
+ mCommandMsgQ.get(&msg);
+ }
+
+ switch ( msg.command ) {
+ case SourceHandler::COMMAND_PROCESS_MSG: {
+ InPortBufferInfo *info = (InPortBufferInfo *)(msg.arg1);
+ mOMXDecoder->drainInputBuffer(info);
+ break;
+ }
+ case SourceHandler::COMMAND_EXIT: {
+ LOGD("Exiting OMX callback handler");
+ forever = 0;
+ break;
+ }
+ }
+ }
+ return false;
+}
+
+
+bool OMXDecoder::OMXCallbackHandler::Handler() {
+ MY_LOGV("\n OMXCallbackHandler::Handler \n");
+ TIUTILS::Message msg;
+ volatile int forever = 1;
+
+ while(forever) {
+ TIUTILS::MessageQueue::waitForMsg(&mCommandMsgQ, NULL, NULL, -1);
+ {
+ Mutex::Autolock lock(mLock);
+ mCommandMsgQ.get(&msg);
+ }
+
+ switch ( msg.command ) {
+ case OMXCallbackHandler::COMMAND_PROCESS_MSG: {
+ omx_message *om = (omx_message*)(msg.arg1);
+ omx_message omsg = *om;
+ mOMXDecoder->on_message(omsg);
+ break;
+ }
+ case OMXCallbackHandler::COMMAND_EXIT: {
+ LOGD("Exiting OMX callback handler");
+ forever = 0;
+ break;
+ }
+ }
+ }
+ return false;
+}
+
+
+OMXDecoder::OMXDecoder(int width, int height, int framerate):
+ mWidth(width),
+ mHeight(height),
+ mFrameRate(framerate),
+ mAcceptingBuffers(0),
+ mPortReconfigInProgress(false),
+ mSizeOfAllAllocatedOutputBuffers(0) {
+
+}
+
+OMXDecoder::~OMXDecoder() {
+
+}
+
+void OMXDecoder::on_message(const omx_message &msg) {
+ switch (msg.type) {
+ case omx_message::EVENT:
+ EventHandler(msg.u.event_data.event, msg.u.event_data.data1, msg.u.event_data.data2);
+ break;
+ case omx_message::EMPTY_BUFFER_DONE:
+ EmptyBufferDone((OMX_BUFFERHEADERTYPE*)msg.u.extended_buffer_data.buffer);
+ break;
+ case omx_message::FILL_BUFFER_DONE:
+ PrintVTCLatency(msg.u.extended_buffer_data.timestamp);
+ FillBufferDone((OMX_BUFFERHEADERTYPE*)msg.u.extended_buffer_data.buffer);
+ break;
+ default:
+ CHECK(!"############ Corrupted Message !!! #############");
+ break;
+ }
+}
+
+status_t OMXDecoder::configure(OMX_VIDEO_AVCPROFILETYPE profile, OMX_VIDEO_AVCLEVELTYPE level, OMX_U32 refFrames) {
+ status_t err;
+ LOG_FUNCTION_NAME_ENTRY
+
+ createPlaybackSurface();
+
+ CHECK_EQ(mOMXClient.connect(), (status_t)OK);
+ mOMX = mOMXClient.interface();
+ mNode = 0;
+ mObserver = new OMXDecoderObserver();
+ err = mOMX->allocateNode("OMX.TI.DUCATI1.VIDEO.DECODER", mObserver, &mNode);
+ if (err != OK) {
+ LOGD("Failed to allocate OMX node!!");
+ return -1;
+ }
+ mObserver->setCodec(this);
+
+ // initialize omx callback handling thread
+ if(mOMXCallbackHandler.get() == NULL)
+ mOMXCallbackHandler = new OMXCallbackHandler(this);
+
+ if ( NULL == mOMXCallbackHandler.get() ) {
+ LOGE("Couldn't create omx callback handler");
+ return -1;
+ }
+
+ err = mOMXCallbackHandler->run("OMXCallbackThread", PRIORITY_URGENT_DISPLAY);
+ if ( err != NO_ERROR ) {
+ if( err == INVALID_OPERATION) {
+ LOGE("omx callback handler thread already runnning!!");
+ err = NO_ERROR;
+ } else {
+ LOGE("Couldn't run omx callback handler thread");
+ return -1;
+ }
+ }
+
+ // initialize source handling thread
+ if(mSourceHandler.get() == NULL)
+ mSourceHandler = new SourceHandler(this);
+
+ if ( NULL == mSourceHandler.get() ) {
+ LOGE("Couldn't create source handler");
+ return -1;
+ }
+
+ err = mSourceHandler->run("SourceThread", PRIORITY_URGENT_DISPLAY);
+ if ( err != NO_ERROR ) {
+ if( err == INVALID_OPERATION) {
+ LOGE("source handler thread already runnning!!");
+ err = NO_ERROR;
+ } else {
+ LOGE("Couldn't run source handler thread");
+ return -1;
+ }
+ }
+
+ mState = OMX_StateLoaded;
+ waitForStateChange = 0;
+
+ OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+ INIT_OMX_STRUCT(&format, OMX_VIDEO_PARAM_PORTFORMATTYPE);
+ bool found = false;
+ OMX_U32 index = 0;
+ format.nPortIndex = OUTPUT_PORT;
+ format.nIndex = 0;
+ for (;;) {
+ format.nIndex = index;
+ err = mOMX->getParameter(mNode, OMX_IndexParamVideoPortFormat, &format, sizeof(format));
+ if (err != OK) {
+ LOGD( "get OMX_IndexParamVideoPortFormat OutPort Error:%d", err);
+ return -1;
+ }
+
+ if (format.eCompressionFormat == OMX_VIDEO_CodingUnused
+ && format.eColorFormat == (OMX_TI_COLOR_FormatYUV420PackedSemiPlanar)) {
+ found = true;
+ break;
+ }
+ ++index;
+ }
+
+ if (!found) {
+ LOGE("Did not find a match.");
+ return -1;
+ }
+
+ MY_LOGV("found a match.");
+ err = mOMX->setParameter(mNode, OMX_IndexParamVideoPortFormat, &format, sizeof(format));
+ if (err != OK) {
+ LOGD( "set OMX_IndexParamVideoPortFormat OutPort Error:%d", err);
+ return -1;
+ }
+
+ //
+ // Populate Video input Port
+ //
+ INIT_OMX_STRUCT(&tInPortDef, OMX_PARAM_PORTDEFINITIONTYPE);
+
+ tInPortDef.nPortIndex = INPUT_PORT;
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, &tInPortDef, sizeof(tInPortDef));
+ if (err != OK) {
+ LOGD( "get OMX_IndexParamPortDefinition InPort Error:%d", err);
+ return -1;
+ }
+
+ tInPortDef.format.video.nFrameWidth = mWidth;
+ tInPortDef.format.video.nFrameHeight = mHeight;
+ tInPortDef.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
+ tInPortDef.nBufferCountActual = 4; // better to match this with the number of encoder output buffers
+ tInPortDef.nBufferSize = (mWidth * mHeight);
+ err = mOMX->setParameter(mNode, OMX_IndexParamPortDefinition, &tInPortDef, sizeof(tInPortDef));
+ if (err != OK) {
+ LOGD( "set OMX_IndexParamPortDefinition InPort Error:%d", err);
+ return -1;
+ }
+
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, &tInPortDef, sizeof(tInPortDef));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamPortDefinition InPort Error:%d", err);
+ return -1;
+ }
+
+ //
+ // Populate Video output Port
+ //
+ INIT_OMX_STRUCT(&tOutPortDef, OMX_PARAM_PORTDEFINITIONTYPE);
+ tOutPortDef.nPortIndex = OUTPUT_PORT;
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition,&tOutPortDef, sizeof(tOutPortDef));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamPortDefinition OutPort Error:%d", err);
+ return -1;
+ }
+
+ tOutPortDef.format.video.nFrameWidth = mWidth;
+ tOutPortDef.format.video.nFrameHeight = mHeight;
+ tOutPortDef.format.video.nStride = 4096;
+ tOutPortDef.format.video.xFramerate = (mFrameRate << 16);
+ tOutPortDef.format.video.eColorFormat = OMX_COLOR_FormatYUV420PackedSemiPlanar;
+// tOutPortDef.nBufferCountActual += 2; // 2 for surface flinger.
+ //set buffer count such that port reconfig can be avoided..
+ //is that possible? in any case add 2 for surface flinger.
+
+ err = mOMX->setParameter(mNode, OMX_IndexParamPortDefinition, &tOutPortDef, sizeof(tOutPortDef));
+ if (err != OK) {
+ LOGD( "set OMX_IndexParamPortDefinition OutPort Error:%d", err);
+ return -1;
+ }
+
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition,&tOutPortDef, sizeof(tOutPortDef));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamPortDefinition OutPort Error:%d", err);
+ return -1;
+ }
+
+ //
+ // setup (code specific) AVC Decoder paramters
+ //
+ OMX_VIDEO_PARAM_AVCTYPE h264type;
+ INIT_OMX_STRUCT(&h264type,OMX_VIDEO_PARAM_AVCTYPE);
+ h264type.nPortIndex = INPUT_PORT;
+
+ err = mOMX->getParameter(mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamVideoAvc failed : %d", err);
+ return -1;
+ }
+
+ h264type.eProfile = profile;
+ h264type.eLevel = level;
+ h264type.nRefFrames = refFrames;
+
+ err = mOMX->setParameter(mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
+ if (err != OK) {
+ LOGD("set OMX_IndexParamVideoAvc failed : %d", err);
+ return -1;
+ }
+
+ // Native Window related calls
+ err = mOMX->enableGraphicBuffers(mNode, OUTPUT_PORT, OMX_TRUE);
+ if (err != 0) {
+ return err;
+ }
+
+ android_native_rect_t crop;
+ crop.left = 0;
+ crop.top = 0;
+ crop.right = mWidth + 1;
+ crop.bottom = mHeight + 1;
+
+ // We'll ignore any errors here, if the surface is
+ // already invalid, we'll know soon enough.
+ native_window_set_crop(mNativeWindow.get(), &crop);
+
+ LOG_FUNCTION_NAME_EXIT
+
+ return 0;
+
+}
+
+status_t OMXDecoder::prepare() {
+ status_t err;
+
+ LOG_FUNCTION_NAME_ENTRY
+
+ if (setCurrentState(OMX_StateIdle)) {
+ return -1;
+ }
+
+ INIT_OMX_STRUCT(&tInPortDef, OMX_PARAM_PORTDEFINITIONTYPE);
+ tInPortDef.nPortIndex = INPUT_PORT;
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, &tInPortDef, sizeof(tInPortDef));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamPortDefinition InPort Error:%d", err);
+ return -1;
+ }
+ //dump_video_port_values(tInPortDef);
+
+ mDealer = new MemoryDealer((tInPortDef.nBufferCountActual*tInPortDef.nBufferSize), "PLAYBACK_INPUT");
+ for (OMX_U32 i = 0; i < tInPortDef.nBufferCountActual; ++i) {
+ sp<IMemory> mMem = mDealer->allocate(tInPortDef.nBufferSize);
+ CHECK(mMem.get() != NULL);
+ IOMX::buffer_id buffer;
+ err = mOMX->allocateBufferWithBackup(mNode, INPUT_PORT, mMem, &buffer);
+ if (err != OK) {
+ LOGD("OMX_AllocateBuffer for input port index:%d failed:%d",(int)i,err);
+ }
+ InPortBufferInfo *info = new InPortBufferInfo;
+ info->mem = mMem;
+ info->b_id = buffer;
+ mInputBuffers.push(info);
+ mEmptyInputBuffers.push_back(info);
+ }
+ LOGD( "Allocated %d Input port Buffers. ", (int)tInPortDef.nBufferCountActual);
+
+
+ INIT_OMX_STRUCT(&tOutPortDef, OMX_PARAM_PORTDEFINITIONTYPE);
+ tOutPortDef.nPortIndex = OUTPUT_PORT;
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, &tOutPortDef, sizeof(tOutPortDef));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamPortDefinition OutPort Error:%d", err);
+ return -1;
+ }
+ //dump_video_port_values(tOutPortDef);
+
+ err = allocateOutputBuffersFromNativeWindow();
+ if (err != OK) {
+ LOGD("allocateOutputBuffersFromNativeWindow failed. err:%d", err);
+ return -1;
+ }
+
+ // now wait until state becomes idle.
+ if (waitForStateSet(OMX_StateIdle)) {
+ LOGD("state change to IDLE failed");
+ return -1;
+ }
+
+ // now transition to exec
+ if (setCurrentState(OMX_StateExecuting)) {
+ return -1;
+ }
+
+ if (waitForStateSet(OMX_StateExecuting)) {
+ LOGD("state change to EXECUTING failed");
+ return -1;
+ }
+
+ if (restart() != 0) return -1;
+
+ return 0;
+}
+
+status_t OMXDecoder::restart() {
+ status_t err;
+ LOG_FUNCTION_NAME_ENTRY
+
+ // give output buffers to the OMX
+ for (int i=0; i<tOutPortDef.nBufferCountActual; i++) {
+ if (mOutputBuffers[i].mStatus == OWNED_BY_US) {
+ err = mOMX->fillBuffer(mNode, mOutputBuffers[i].b_id);
+ if (err != OK) {
+ LOGD("fillBuffer failed:%d", err);
+ }
+ else LOGD("called fillBuffer(%d)",i);
+ }
+ }
+
+ return 0;
+}
+
+status_t OMXDecoder::start(MetaData *params) {
+ LOG_FUNCTION_NAME_ENTRY
+ mAcceptingBuffers = 1;
+ return 0;
+}
+
+status_t OMXDecoder::stop() {
+ status_t err;
+
+ LOG_FUNCTION_NAME_ENTRY
+
+ mAcceptingBuffers = 0;
+ // flush all the buffers
+ err = mOMX->sendCommand(mNode,OMX_CommandFlush, INPUT_PORT);
+ if (err != OK) {
+ LOGD("OMX_CommandFlush for input port (0) failed:%d", err);
+ }
+
+ err = mOMX->sendCommand(mNode,OMX_CommandFlush, OUTPUT_PORT);
+ if (err != OK) {
+ LOGD("OMX_CommandFlush for output port (1) failed:%d", err);
+ }
+
+ // change state to Idle if not already
+ if (mState != OMX_StateIdle && mState != OMX_StateLoaded) {
+ if (setCurrentState(OMX_StateIdle)) {
+ LOGD("OMX_StateIdle failed");
+ }
+
+ if (waitForStateSet(OMX_StateIdle)) {
+ LOGD("state change to IDLE failed");
+ }
+ }
+
+ // disable ports
+ err = mOMX->sendCommand(mNode, OMX_CommandPortDisable, -1);
+ if (err != OK) {
+ LOGD("Error in SendCommand()-OMX_CommandPortDisable:");
+ } else {
+ LOGD("OMX_CommandPortDisable done");
+ }
+
+ // free input buffers
+ for (int i=0; i<(int)tInPortDef.nBufferCountActual; i++) {
+ err = mOMX->freeBuffer(mNode, INPUT_PORT, mInputBuffers[i]->b_id);
+ if( (err != OK)) {
+ LOGD("Free Buffer for Input Port buffer:%d failed:%d",i,err);
+ }
+ }
+
+ freeOutputBuffers();
+
+ // change state to Loaded
+ if (mState != OMX_StateLoaded) {
+ if (setCurrentState(OMX_StateLoaded)) {
+ LOGD("OMX_StateLoaded failed");
+ }
+ if (waitForStateSet(OMX_StateLoaded)) {
+ LOGD("state change to LOADED failed");
+ }
+ } else {
+ LOGD("It was already OMX_StateLoaded???");
+ }
+
+
+ usleep(5000);
+
+ err = mOMX->freeNode(mNode);
+ CHECK_EQ(err, (status_t)OK);
+
+ LOGD("OMX_FreeHandle completed");
+
+ //Exit and free ref to callback handling thread
+ if ( NULL != mOMXCallbackHandler.get() ) {
+ TIUTILS::Message msg;
+ msg.command = OMXCallbackHandler::COMMAND_EXIT;
+ //Clear all messages pending first
+ mOMXCallbackHandler->clearCommandQ();
+ mOMXCallbackHandler->put(&msg);
+ mOMXCallbackHandler->requestExitAndWait();
+ mOMXCallbackHandler.clear();
+ }
+
+ //Exit and free ref to source handling thread
+ if ( NULL != mSourceHandler.get() ) {
+ TIUTILS::Message msg;
+ msg.command = SourceHandler::COMMAND_EXIT;
+ //Clear all messages pending first
+ mSourceHandler->clearCommandQ();
+ mSourceHandler->put(&msg);
+ mSourceHandler->requestExitAndWait();
+ mSourceHandler.clear();
+ }
+
+ destroyPlaybackSurface();
+
+ //what else needs to be freed..
+
+ return 0;
+}
+
+sp<MetaData> OMXDecoder::getFormat() {
+ return NULL;
+}
+
+status_t OMXDecoder::read(MediaBuffer **buffer, const ReadOptions *options) {
+ return 0;
+}
+
+void OMXDecoder::AcceptEncodedBuffer(void *pBuffer, OMX_U32 nFilledLen, OMX_TICKS nTimeStamp) {
+ //MY_LOGV("AcceptEncodedBuffer - Len = %d", nFilledLen);
+ if (mEmptyInputBuffers.empty()) {
+ LOGE("\n\n\n Ran out of input buffers. Dropping Frames.\n\n\n");
+ return;
+ }
+
+ if (mPortReconfigInProgress) {
+ MY_LOGV( "%s:\t mPortReconfigInProgress.", __FUNCTION__);
+ //return;
+ }
+
+ while(mPortReconfigInProgress) sleep(1);
+
+ List<InPortBufferInfo*>::iterator iter;
+ InPortBufferInfo *info;
+ iter = mEmptyInputBuffers.begin();
+ info = (InPortBufferInfo *)*iter;
+ mEmptyInputBuffers.erase(iter);
+
+ info->nFilledLen = nFilledLen;
+ info->nTimeStamp = nTimeStamp;
+ memcpy((void*)info->mem->pointer(), pBuffer, nFilledLen);
+
+ TIUTILS::Message msg;
+ msg.command = SourceHandler::COMMAND_PROCESS_MSG;
+ msg.arg1 = (void*)info;
+ mSourceHandler->put(&msg);
+
+}
+
+OMX_ERRORTYPE OMXDecoder::EventHandler(OMX_EVENTTYPE eEvent, OMX_U32 nData1,OMX_U32 nData2) {
+ OMX_ERRORTYPE errorType;
+ MY_LOGV("########## EventHandler: eEvent:0x%x, nData1:0x%x, nData2:0x%x, pid=%d", (int)eEvent, (int)nData1, (int)nData2, getpid());
+
+ switch (eEvent) {
+ case OMX_EventCmdComplete:
+ if (nData1 == OMX_CommandPortDisable) {
+ if (nData2 == OMX_DirInput) {
+ LOGD( "Component OMX_EventCmdComplete OMX_CommandPortDisable OMX_DirInput");
+ }
+ if (nData2 == OMX_DirOutput) {
+ LOGD( "Component OMX_EventCmdComplete OMX_CommandPortDisable OMX_DirOutput");
+ if (mPortReconfigInProgress) {
+ status_t err = mOMX->sendCommand(mNode, OMX_CommandPortEnable, OUTPUT_PORT);
+ CHECK_EQ(err, (status_t)OK);
+ allocateOutputBuffersFromNativeWindow();
+ }
+ }
+ } else if (nData1 == OMX_CommandPortEnable) {
+ if (nData2 == OUTPUT_PORT) {
+ LOGD( "Component OMX_EventCmdComplete OMX_CommandPortEnable OMX_DirOutput");
+ restart();
+ mPortReconfigInProgress = false;
+ LOGD("\nPort Reconfiguration completed.. \n");
+
+ }
+ } else if (nData1 == OMX_CommandStateSet) {
+ LOGD( "Component OMX_EventCmdComplete OMX_CommandStateSet new State:%s",OMXStateName((OMX_STATETYPE)nData2));
+ {
+ Mutex::Autolock autoLock(mLock);
+ mState = (OMX_STATETYPE)nData2;
+ waitForStateChange = 0;
+ }
+ mAsyncCompletion.signal();
+
+ } else if (nData1 == OMX_CommandFlush) {
+ LOGD( "Component OMX_EventCmdComplete OMX_CommandFlush port:%d",(int)nData2);
+ } else {
+ LOGD( "Component OMX_EventCmdComplete command:%d",(int)nData1);
+ }
+ break;
+
+ case OMX_EventPortSettingsChanged:
+ if (nData2 == 0 || nData2 == OMX_IndexParamPortDefinition) {
+ LOGD("\nPort Reconfiguration in progress.. \n");
+ mPortReconfigInProgress = true;
+ status_t err = mOMX->sendCommand(mNode, OMX_CommandPortDisable, nData1);
+ CHECK_EQ(err, (status_t)OK);
+
+ freeOutputBuffers();
+ } else if ((nData1 == OUTPUT_PORT)&& (nData2 == OMX_IndexConfigCommonOutputCrop)) {
+
+ OMX_CONFIG_RECTTYPE rect;
+ INIT_OMX_STRUCT(&rect, OMX_CONFIG_RECTTYPE);
+ rect.nPortIndex = OUTPUT_PORT;
+ status_t err = mOMX->getConfig(mNode, OMX_IndexConfigCommonOutputCrop, &rect, sizeof(rect));
+
+ if (err == OK) {
+ LOGI("Crop rect is %ld x %ld @ (%ld, %ld)", rect.nWidth, rect.nHeight, rect.nLeft, rect.nTop);
+
+ android_native_rect_t crop;
+ crop.left = rect.nLeft;
+ crop.top = rect.nTop;
+ crop.right = rect.nLeft + rect.nWidth;
+ crop.bottom = rect.nTop + rect.nHeight;
+
+ native_window_set_crop(mNativeWindow.get(), &crop);
+ }
+ } else {
+ LOGD("\n\nNOT PROCESSING THIS OMX_EventPortSettingsChanged EVENT: nData1 = 0x%x, nData2 = 0x%x\n\n", nData1, nData2);
+ }
+ break;
+
+ case OMX_EventError:
+ errorType = (OMX_ERRORTYPE) nData1;
+ LOGD( "\n\n\nComponent OMX_EventError error:%x\n\n\n",errorType);
+ break;
+
+ default:
+ break;
+ }
+
+ LOG_FUNCTION_NAME_EXIT
+ return OMX_ErrorNone;
+}
+
+status_t OMXDecoder::FillBufferDone(OMX_BUFFERHEADERTYPE* pBufferHdr) {
+ status_t err;
+
+ OMX_U32 i=0;
+
+ //LOG_FUNCTION_NAME_ENTRY
+
+ // not mAcceptingBuffers, just return, eventually, decoder will stop
+ if (mAcceptingBuffers == 0) {
+ MY_LOGV( " in non mAcceptingBuffers mode");
+ return OMX_ErrorNone;
+ }
+
+ if (mPortReconfigInProgress) {
+ MY_LOGV( "%s:\t mPortReconfigInProgress", __FUNCTION__);
+ return OMX_ErrorNone;
+ }
+
+ int sz = tOutPortDef.nBufferCountActual;
+ for (i = 0; i < sz; i++) {
+ if (pBufferHdr == mOutputBuffers[i].b_id) {
+ break;
+ }
+ }
+
+ if (i == sz) {
+ LOGE("FillBufferDone returned unknown buffer header! i=%d",(int)i);
+ return -1;
+ }
+ //LOGD( "----- %d ----- ", (int)i);
+ PortBufferInfo *info = &mOutputBuffers.editItemAt(i);
+ info->mStatus = OWNED_BY_US;
+
+ err = mNativeWindow->queueBuffer(mNativeWindow.get(), mOutputBuffers[i].gb.get());
+ if (err != 0) {
+ LOGE("queueBuffer failed with error %s (%d)", strerror(-err), -err);
+ return -1;
+ }
+ info->mStatus = OWNED_BY_NATIVE_WINDOW;
+
+ if (mDebugFlags & FPS_DECODER) PrintDecoderFPS();
+
+ ANativeWindowBuffer* buf;
+ err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
+ if (err != 0) {
+ LOGE("dequeueBuffer failed w/ error 0x%08x", err);
+ return -1;
+ }
+
+ for (i = 0; i < sz; i++) {
+ if (mOutputBuffers[i].gb->handle == buf->handle) {
+ break;
+ }
+ }
+
+ if (i == sz) {
+ LOGE("FillBufferDone returned unknown buffer header! i=%d",(int)i);
+ return -1;
+ }
+
+ info = &mOutputBuffers.editItemAt(i);
+ info->mStatus = OWNED_BY_US;
+
+ err = mOMX->fillBuffer(mNode, mOutputBuffers[i].b_id);
+ if (err != OK) {
+ LOGE("OMX_FillThisBuffer failed:%d", err);
+ }
+ info->mStatus = OWNED_BY_COMPONENT;
+
+ //mBufferCount++;
+ //MY_LOGV("EXIT FillBufferDone: nFilledLen=%d, mBufferCount=%d", nFilledLen, mBufferCount);
+
+ return OMX_ErrorNone;
+}
+
+status_t OMXDecoder::EmptyBufferDone(OMX_BUFFERHEADERTYPE* pBufferHdr) {
+ status_t err;
+ OMX_U32 i=0;
+ //LOG_FUNCTION_NAME_ENTRY
+
+ // not mAcceptingBuffers, just return, eventually, decoder will stop
+ if (mAcceptingBuffers == 0) {
+ MY_LOGV( " in non mAcceptingBuffers mode");
+ return OMX_ErrorNone;
+ }
+
+ int sz = mInputBuffers.size();
+ for (i = 0; i < sz; i++) {
+ if (pBufferHdr == mInputBuffers[i]->b_id)
+ break;
+ }
+
+ if (i == sz) {
+ LOGE("EmptyBufferDone returned unknown buffer header! i=%d",(int)i);
+ return -1;
+ }
+
+ mEmptyInputBuffers.push_back(mInputBuffers[i]);
+
+ //LOG_FUNCTION_NAME_EXIT
+
+ return err;
+}
+
+status_t OMXDecoder::setCurrentState(OMX_STATETYPE newState) {
+ LOGD("Attempting to set state to %s.", OMXStateName(newState));
+
+ status_t err = mOMX->sendCommand(mNode, OMX_CommandStateSet, newState);
+ if (err != OK) {
+ LOGD("setCurrentState: Error:%d", err);
+ return -1;
+ }
+
+ LOG_FUNCTION_NAME_EXIT
+ return 0;
+}
+
+status_t OMXDecoder::waitForStateSet(OMX_STATETYPE newState) {
+ LOGD("ENTER waitForStateSet: Waiting to move to state %s .....", OMXStateName(newState));
+
+ if (newState == mState) {
+ LOGD("New State [%s] already set!", OMXStateName(newState));
+ return 0;
+ }
+
+ status_t retval = mAsyncCompletion.waitRelative(mLock, TWO_SECOND);
+ if (retval) {
+ LOGD("mAsyncCompletion.waitRelative RETURNED %d", retval);
+ if (errno == ETIMEDOUT) {
+ LOGD("$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Waiting for State change timed out $$$$$$$$$$$$$$$$$$$$$$$$$$$$");
+ waitForStateChange = 0;
+ }
+ }
+
+ if (newState == mState) {
+ LOGD("State [%s] Set !!!!!!!!!!!!!!!!!", OMXStateName(newState));
+ return 0;
+ }
+
+ LOG_FUNCTION_NAME_EXIT
+ return -1;
+}
+
+
+status_t OMXDecoder::createPlaybackSurface() {
+
+ mSurfaceComposerClient = new SurfaceComposerClient();
+ CHECK_EQ(mSurfaceComposerClient->initCheck(), (status_t)OK);
+
+ mSurfaceControl = mSurfaceComposerClient->createSurface(0,
+ 320, 320, HAL_PIXEL_FORMAT_RGB_565);
+
+ mNativeWindow = mSurfaceControl->getSurface();
+
+ mSurfaceComposerClient->openGlobalTransaction();
+ mSurfaceControl->setLayer(0x7fffffff);
+ mSurfaceControl->setPosition(10, 10);
+ mSurfaceControl->setSize(300, 300);
+ mSurfaceControl->show();
+ mSurfaceComposerClient->closeGlobalTransaction();
+
+ return 0;
+}
+
+status_t OMXDecoder::destroyPlaybackSurface() {
+
+ if ( NULL != mNativeWindow.get() ) {
+ mNativeWindow.clear();
+ }
+
+ if ( NULL != mSurfaceControl.get() ) {
+ mSurfaceControl->clear();
+ mSurfaceControl.clear();
+ }
+
+ if ( NULL != mSurfaceComposerClient.get() ) {
+ mSurfaceComposerClient->dispose();
+ mSurfaceComposerClient.clear();
+ }
+
+ return 0;
+}
+
+status_t OMXDecoder::allocateOutputBuffersFromNativeWindow() {
+
+ status_t err;
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, &tOutPortDef, sizeof(tOutPortDef));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamPortDefinition OutPort Error:%d", err);
+ return -1;
+ }
+
+ err = native_window_set_scaling_mode(mNativeWindow.get(),
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+
+ if (err != OK) {
+ return err;
+ }
+
+ OMX_U32 nBufferCnt = tOutPortDef.nBufferCountActual;
+#ifdef NO_PORT_RECONFIG
+
+ LOGD("\nO/P Buffer Reqmt: %d buffers of size %d x %d\n", tOutPortDef.nBufferCountActual, tOutPortDef.format.video.nFrameWidth, tOutPortDef.format.video.nFrameHeight);
+
+ int newBufferRqmt = tOutPortDef.nBufferCountActual *
+ tOutPortDef.format.video.nFrameWidth *
+ tOutPortDef.format.video.nFrameHeight *
+ 3 / 2;
+ bool bufferRqmtsChanged = (mSizeOfAllAllocatedOutputBuffers < newBufferRqmt) ? true : false;
+ nBufferCnt = (MAX_OUTPUT_BUF_NUM > tOutPortDef.nBufferCountActual) ? MAX_OUTPUT_BUF_NUM : tOutPortDef.nBufferCountActual;
+
+ if ((mPortReconfigInProgress == false)|| bufferRqmtsChanged ) {
+ int framewidth = 0;
+ int frameheight = 0;
+
+ if (tOutPortDef.format.video.nFrameWidth > MAX_FRAME_WIDTH_720P) {
+ framewidth = (tOutPortDef.format.video.nFrameWidth > MAX_FRAME_WIDTH)? tOutPortDef.format.video.nFrameWidth : MAX_FRAME_WIDTH;
+ } else {
+ framewidth = MAX_FRAME_WIDTH_720P;
+ }
+
+ if (tOutPortDef.format.video.nFrameHeight > MAX_FRAME_HEIGHT_720P) {
+ frameheight = (tOutPortDef.format.video.nFrameHeight > MAX_FRAME_HEIGHT)? tOutPortDef.format.video.nFrameHeight : MAX_FRAME_HEIGHT;
+ } else {
+ frameheight = MAX_FRAME_HEIGHT_720P;
+ }
+
+ err = native_window_set_buffers_geometry(
+ mNativeWindow.get(),
+ framewidth,
+ frameheight,
+ tOutPortDef.format.video.eColorFormat);
+
+ if (err != 0) {
+ LOGE("native_window_set_buffers_geometry failed: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+ mSizeOfAllAllocatedOutputBuffers = nBufferCnt * framewidth * frameheight * 3 / 2;
+ LOGD("\nO/P Buffers actually allocated: %d buffers of size %d x %d\n\n", nBufferCnt, framewidth, frameheight);
+ }
+ else LOGI("\n---RECONFIGURING: skip native_window_set_buffers_geometry()\n");
+
+#else
+ err = native_window_set_buffers_geometry(
+ mNativeWindow.get(),
+ tOutPortDef.format.video.nFrameWidth,
+ tOutPortDef.format.video.nFrameHeight,
+ tOutPortDef.format.video.eColorFormat);
+
+ if (err != 0) {
+ LOGE("native_window_set_buffers_geometry failed: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+
+#endif
+
+ // Set up the native window.
+ OMX_U32 usage = 0;
+ err = mOMX->getGraphicBufferUsage(mNode, OUTPUT_PORT, &usage);
+ if (err != 0) {
+ LOGW("querying usage flags from OMX IL component failed: %d", err);
+ // XXX: Currently this error is logged, but not fatal.
+ usage = 0;
+ }
+
+ MY_LOGV("native_window_set_usage usage=0x%lx", usage);
+ err = native_window_set_usage(
+ mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
+ if (err != 0) {
+ LOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+#ifdef NO_PORT_RECONFIG
+
+ if ((mPortReconfigInProgress == false)|| bufferRqmtsChanged ) {
+ err = native_window_set_buffer_count(mNativeWindow.get(), nBufferCnt);
+ if (err != 0) {
+ LOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err),
+ -err);
+ return err;
+ }
+ LOGI("allocating %lu buffers from a native window", nBufferCnt);
+ }
+ else LOGI("---RECONFIGURING: skip native_window_set_buffer_count()\n\n");
+#else
+
+ err = native_window_set_buffer_count(mNativeWindow.get(), nBufferCnt);
+ if (err != 0) {
+ LOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err),
+ -err);
+ return err;
+ }
+
+ LOGI("allocating %lu buffers from a native window of size %lu on "
+ "output port", tOutPortDef.nBufferCountActual, tOutPortDef.nBufferSize);
+
+#endif
+
+ OMX_U32 i = 0;
+ // Dequeue buffers and send them to OMX
+ for (i = 0; i < nBufferCnt; i++) {
+ ANativeWindowBuffer* buf;
+ err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
+ if (err != 0) {
+ LOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
+ break;
+ }
+
+ sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(buf, false));
+ IOMX::buffer_id bufferId = 0;
+
+ if (i < tOutPortDef.nBufferCountActual) {
+ err = mOMX->useGraphicBuffer(mNode, OUTPUT_PORT, graphicBuffer,
+ &bufferId);
+ if (err != 0) {
+ LOGE("registering GraphicBuffer with OMX IL component "
+ "failed: %d", err);
+ break;
+ }
+ }
+
+ PortBufferInfo pbi;
+ pbi.gb = graphicBuffer;
+ pbi.b_id = bufferId;
+ pbi.mStatus = OWNED_BY_US;
+ mOutputBuffers.push(pbi);
+
+ LOGI("registered graphic buffer with ID %p (pointer = %p)",
+ bufferId, graphicBuffer.get());
+ }
+
+ OMX_U32 cancelStart;
+ OMX_U32 cancelEnd;
+ if (err != 0) {
+ // If an error occurred while dequeuing we need to cancel any buffers
+ // that were dequeued.
+ cancelStart = 0;
+ cancelEnd = i;
+ } else {
+ // Return the last two buffers to the native window.
+ cancelStart = tOutPortDef.nBufferCountActual - 2;
+ cancelEnd = tOutPortDef.nBufferCountActual;
+ }
+
+ for (OMX_U32 i = cancelStart; i < cancelEnd; i++) {
+ PortBufferInfo *info = &mOutputBuffers.editItemAt(i);
+ err = mNativeWindow->cancelBuffer(
+ mNativeWindow.get(), info->gb.get());
+ if (err != 0) {
+ LOGE("cancelBuffer failed w/ error 0x%08x", err);
+ return err;
+ }
+ info->mStatus = OWNED_BY_NATIVE_WINDOW;
+ }
+
+ return err;
+}
+
+status_t OMXDecoder::drainInputBuffer(InPortBufferInfo *info) {
+ OMX_TICKS ts;
+ ts = info->nTimeStamp;
+ if (mDebugFlags & DECODER_LATENCY) ts = systemTime() / 1000;
+ status_t err = mOMX->emptyBuffer(mNode, info->b_id, 0, info->nFilledLen, OMX_BUFFERFLAG_ENDOFFRAME, ts);
+ if (err != OK) {
+ LOGD("OMX_EmptyThisBuffer failed:%d", err);
+ return err;
+ }
+ return 0;
+}
+
+status_t OMXDecoder::freeOutputBuffers() {
+ status_t err = 0;
+
+ for (size_t i = mOutputBuffers.size(); i-- > 0;) {
+
+ if (i < tOutPortDef.nBufferCountActual) {
+ err = mOMX->freeBuffer(mNode, OUTPUT_PORT, mOutputBuffers[i].b_id);
+ if (err != OK) LOGE("\n\n\n Free Buffer for Output Port buffer:%d failed:%d\n\n\n",i,err);
+ }
+
+ // Cancel the buffer if it belongs to an ANativeWindow.
+ if (mOutputBuffers[i].mStatus == OWNED_BY_US && mOutputBuffers[i].gb != 0) {
+ err = mNativeWindow->cancelBuffer(mNativeWindow.get(), mOutputBuffers[i].gb.get());
+ if (err != 0)LOGE("\n\n\nCancel Buffer for Output Port buffer:%d failed:%d\n\n\n",i,err);
+ }
+
+ mOutputBuffers.removeAt(i);
+ }
+
+ return 0;
+}
+
diff --git a/test/VTC/IOMXDecoder.h b/test/VTC/IOMXDecoder.h
new file mode 100644
index 0000000..e73e336
--- /dev/null
+++ b/test/VTC/IOMXDecoder.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef IOMX_DECODER_H
+#define IOMX_DECODER_H
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <semaphore.h>
+#include <pthread.h>
+
+#include <binder/MemoryDealer.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <system/audio.h>
+#include <utils/List.h>
+#include <cutils/log.h>
+#include <OMX_Component.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaDebug.h>
+
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/ISurface.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+#include <android/native_window.h>
+#include <ui/GraphicBuffer.h>
+
+#include "MessageQueue.h"
+
+
+using namespace android;
+
+struct OMXDecoderObserver;
+
+struct OMXDecoder : public MediaSource
+{
+ enum BufferStatus {
+ OWNED_BY_US,
+ OWNED_BY_COMPONENT,
+ OWNED_BY_NATIVE_WINDOW,
+ OWNED_BY_CLIENT,
+ };
+
+ struct BufferInfo {
+ void* pBuffer;
+ OMX_U32 nFilledLen;
+ OMX_TICKS nTimeStamp;
+ };
+
+ struct PortBufferInfo{
+ sp<GraphicBuffer> gb;
+ IOMX::buffer_id b_id;
+ BufferStatus mStatus;
+ };
+
+ struct InPortBufferInfo{
+ sp<IMemory> mem;
+ IOMX::buffer_id b_id;
+ OMX_U32 nFilledLen;
+ OMX_TICKS nTimeStamp;
+ };
+
+ friend class OMXDecoderObserver;
+
+ status_t configure(OMX_VIDEO_AVCPROFILETYPE profile, OMX_VIDEO_AVCLEVELTYPE level, OMX_U32 refFrames);
+ status_t prepare();
+ status_t start(MetaData *params = NULL);
+ status_t stop();
+ sp<MetaData> getFormat();
+ status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL);
+ void on_message(const omx_message &msg);
+ void AcceptEncodedBuffer(void *pBuffer, OMX_U32 nFilledLen, OMX_TICKS nTimeStamp);
+ OMXDecoder(int width, int height, int framerate);
+ OMXDecoder(const OMXDecoder &);
+ OMXDecoder &operator=(const OMXDecoder &);
+ ~OMXDecoder();
+ uint32_t mDebugFlags;
+
+private:
+
+ class SourceHandler : public Thread {
+ public:
+ SourceHandler(OMXDecoder* dec)
+ : Thread(false), mOMXDecoder(dec) { }
+
+ virtual bool threadLoop() {
+ bool ret;
+ ret = Handler();
+ return ret;
+ }
+
+ status_t put(TIUTILS::Message* msg) {
+ Mutex::Autolock lock(mLock);
+ return mCommandMsgQ.put(msg);
+ }
+
+ void clearCommandQ() {
+ Mutex::Autolock lock(mLock);
+ mCommandMsgQ.clear();
+ }
+
+ enum {
+ COMMAND_EXIT = -1,
+ COMMAND_PROCESS_MSG,
+ };
+
+ private:
+ bool Handler();
+ TIUTILS::MessageQueue mCommandMsgQ;
+ OMXDecoder* mOMXDecoder;
+ Mutex mLock;
+ };
+
+ sp<SourceHandler> mSourceHandler;
+
+ class OMXCallbackHandler : public Thread {
+ public:
+ OMXCallbackHandler(OMXDecoder* dec)
+ : Thread(false), mOMXDecoder(dec) { }
+
+ virtual bool threadLoop() {
+ bool ret;
+ ret = Handler();
+ return ret;
+ }
+
+ status_t put(TIUTILS::Message* msg) {
+ Mutex::Autolock lock(mLock);
+ return mCommandMsgQ.put(msg);
+ }
+
+ void clearCommandQ() {
+ Mutex::Autolock lock(mLock);
+ mCommandMsgQ.clear();
+ }
+
+ enum {
+ COMMAND_EXIT = -1,
+ COMMAND_PROCESS_MSG,
+ };
+
+ private:
+ bool Handler();
+ TIUTILS::MessageQueue mCommandMsgQ;
+ OMXDecoder* mOMXDecoder;
+ Mutex mLock;
+ };
+
+ sp<OMXCallbackHandler> mOMXCallbackHandler;
+
+ OMX_ERRORTYPE EventHandler(OMX_EVENTTYPE eEvent, OMX_U32 nData1,OMX_U32 nData2);
+ status_t FillBufferDone(OMX_BUFFERHEADERTYPE* pBufferHdr);
+ status_t EmptyBufferDone(OMX_BUFFERHEADERTYPE* pBufferHdr);
+ status_t setCurrentState(OMX_STATETYPE newState);
+ status_t waitForStateSet(OMX_STATETYPE newState);
+ status_t createPlaybackSurface();
+ status_t destroyPlaybackSurface();
+ status_t allocateOutputBuffersFromNativeWindow();
+ status_t drainInputBuffer(InPortBufferInfo *info);
+ status_t freeOutputBuffers();
+ status_t restart();
+
+ int mWidth;
+ int mHeight;
+ int mSizeOfAllAllocatedOutputBuffers;
+ uint32_t mFrameRate;
+ OMX_PARAM_PORTDEFINITIONTYPE tInPortDef;
+ OMX_PARAM_PORTDEFINITIONTYPE tOutPortDef;
+ sp<IOMX> mOMX;
+ IOMX::node_id mNode;
+ sp<OMXDecoderObserver> mObserver;
+ OMXClient mOMXClient;
+ Vector<PortBufferInfo> mOutputBuffers;
+ Vector<InPortBufferInfo*> mInputBuffers;
+ List<InPortBufferInfo*> mEmptyInputBuffers;
+ Condition mAsyncCompletion;
+ Mutex mLock;
+ int waitForStateChange;
+ OMX_STATETYPE mState;
+ int mAcceptingBuffers;
+ sp<MemoryDealer> mDealer;
+ sp<SurfaceComposerClient> mSurfaceComposerClient;
+ sp<SurfaceControl> mSurfaceControl;
+ sp<ANativeWindow> mNativeWindow;
+ bool mPortReconfigInProgress;
+};
+
+struct OMXDecoderObserver : public BnOMXObserver {
+ OMXDecoderObserver() {
+ }
+
+ void setCodec(const sp<OMXDecoder> &target) {
+ mTarget = target;
+ }
+
+ // from IOMXObserver
+ virtual void onMessage(const omx_message &omx_msg) {
+ TIUTILS::Message msg;
+ omx_message *ptemp_omx_msg;
+ // HACK HACK HACK LEAK LEAK LEAK FIXIT
+ ptemp_omx_msg = (omx_message *)malloc(sizeof(omx_message));
+ memcpy(ptemp_omx_msg, &omx_msg, sizeof(omx_message));
+ //LOGD("=================omx_msg.type = %x, temp_omx_msg.type = %x",omx_msg.type, ptemp_omx_msg->type);
+ sp<OMXDecoder> codec = mTarget.promote();
+ if (codec.get() != NULL) {
+ msg.command = OMXDecoder::OMXCallbackHandler::COMMAND_PROCESS_MSG;
+ msg.arg1 = (void *)ptemp_omx_msg;
+ codec->mOMXCallbackHandler->put(&msg);
+ codec.clear();
+ }
+ }
+
+protected:
+ virtual ~OMXDecoderObserver() {}
+
+private:
+ wp<OMXDecoder> mTarget;
+ OMXDecoderObserver(const OMXDecoderObserver &);
+ OMXDecoderObserver &operator=(const OMXDecoderObserver &);
+};
+
+#endif
+
diff --git a/test/VTC/IOMXEncoder.cpp b/test/VTC/IOMXEncoder.cpp
new file mode 100644
index 0000000..88ce9af
--- /dev/null
+++ b/test/VTC/IOMXEncoder.cpp
@@ -0,0 +1,1158 @@
+/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "VTCLoopback.h"
+#include "IOMXEncoder.h"
+#define LOG_TAG "VTC_ENC"
+#define LOG_NDEBUG 0
+//#define NO_MEMCOPY 1
+#define MY_LOGV(x, ...) LOGV(x, ##__VA_ARGS__)
+
+using namespace android;
+
+static void PrintEncoderFPS() {
+ static int mFrameCount = 0;
+ static int mLastFrameCount = 0;
+ static nsecs_t mLastFpsTime = 0;
+ static float mFps = 0;
+ mFrameCount++;
+ if (!(mFrameCount & 0x1F)) {
+ nsecs_t now = systemTime();
+ nsecs_t diff = now - mLastFpsTime;
+ mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
+ mLastFpsTime = now;
+ mLastFrameCount = mFrameCount;
+ LOGD("Encoder: %d Frames, %f FPS", mFrameCount, mFps);
+ }
+ // XXX: mFPS has the value we want
+}
+
+static void PrintEncoderLatency(nsecs_t ts) {
+ static int mFrameCount = 0;
+ static int64_t sum_latency_ms = 0;
+ int64_t now, diff_ms, avg_latency;
+
+ now = systemTime()/1000;
+ diff_ms = (now - ts) / 1000;
+ sum_latency_ms += diff_ms;
+ mFrameCount++;
+ if (!(mFrameCount & 0x1F)) {
+ avg_latency = sum_latency_ms / 32;
+ sum_latency_ms = 0;
+ LOGD("Avg Encoder Latency: %d Frames, %llu ms", mFrameCount, avg_latency);
+ }
+}
+
+static uint64_t get_time_of_day_ms() {
+ struct timeval t0;
+ gettimeofday(&t0,0);
+ return t0.tv_sec*1000 + t0.tv_usec/1000;
+}
+
+static void PrintEffectiveBitrate(OMX_U32 filledLen) {
+ static int framecount = 0;
+ static uint64_t bytecount = 0;
+ static uint64_t starttime = get_time_of_day_ms();
+ const uint64_t wallclock = get_time_of_day_ms();
+ framecount++;
+ bytecount+=filledLen;
+ int delta=wallclock-starttime;
+ if (delta>2000) {
+ int fps=framecount*10000/delta;
+ const uint64_t br=bytecount*8*1000/delta;
+ //LOGI("ENCODER FPS: %d.%d",fps/10,fps-(fps/10)*10);
+ LOGI("ENCODER EFFECTIVE BITRATE: %llu",br);
+ framecount=0;
+ bytecount=0;
+ starttime = wallclock;
+ }
+}
+
+
+bool OMXEncoder::OMXCallbackHandler::Handler() {
+ MY_LOGV("\n OMXCallbackHandler::Handler \n");
+ TIUTILS::Message msg;
+ volatile int forever = 1;
+
+ while(forever) {
+ TIUTILS::MessageQueue::waitForMsg(&mCommandMsgQ, NULL, NULL, -1);
+ {
+ Mutex::Autolock lock(mLock);
+ mCommandMsgQ.get(&msg);
+ }
+
+ switch ( msg.command ) {
+ case OMXCallbackHandler::COMMAND_PROCESS_MSG: {
+ omx_message *om = (omx_message*)(msg.arg1);
+ omx_message omsg = *om;
+ mOMXEncoder->on_message(omsg);
+ break;
+ }
+ case OMXCallbackHandler::COMMAND_EXIT: {
+ LOGD("Exiting OMX callback handler");
+ forever = 0;
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+OMXEncoder::OMXEncoder(const sp<IOMX> &omx, IOMX::node_id node, sp<MyCameraClient> camera, int width, int height, int framerate, int bitrate, char *fname, int sliceHeight):
+ mOMX(omx),
+ mNode(node),
+ mCameraSource(camera) {
+ resetParameters(width, height, framerate, bitrate, fname, sliceHeight);
+}
+
+
+OMXEncoder::~OMXEncoder() {
+ status_t err = mOMX->freeNode(mNode);
+ CHECK_EQ(err, (status_t)OK);
+ LOGD("OMX_FreeHandle completed");
+}
+
+status_t OMXEncoder::resetParameters(int width, int height, int framerate, int bitrate, char *fname, int sliceHeight) {
+ mWidth = width;
+ mHeight = height;
+ mFrameRate= framerate;
+ mBitRate = bitrate;
+ mSliceHeight = sliceHeight;
+ mAcceptingBuffers = 0;
+ mOutputFD = NULL;
+ mBufferCount = 0;
+ mOutputBufferCount = 4;
+ mCallbackSet = false;
+ mState = OMX_StateLoaded;
+ return OK;
+}
+
+void OMXEncoder::on_message(const omx_message &msg) {
+ switch (msg.type) {
+ case omx_message::EVENT:
+ EventHandler(msg.u.event_data.event, msg.u.event_data.data1, msg.u.event_data.data2);
+ break;
+ case omx_message::EMPTY_BUFFER_DONE:
+ EmptyBufferDone((OMX_BUFFERHEADERTYPE*)msg.u.extended_buffer_data.buffer);
+ break;
+ case omx_message::FILL_BUFFER_DONE:
+ FillBufferDone((OMX_BUFFERHEADERTYPE*)msg.u.extended_buffer_data.buffer,
+ msg.u.extended_buffer_data.range_offset,
+ msg.u.extended_buffer_data.range_length,
+ msg.u.extended_buffer_data.timestamp);
+ break;
+ default:
+ CHECK(!"############ Corrupted Message !!! #############");
+ break;
+ }
+}
+
+status_t OMXEncoder::configure(OMX_VIDEO_AVCPROFILETYPE profile, OMX_VIDEO_AVCLEVELTYPE level, OMX_U32 refFrames) {
+ status_t err;
+ LOG_FUNCTION_NAME_ENTRY
+
+ MY_LOGV("\n\nPROFILE=%d\nLEVEL=%d\nRefFrames=%d\nWidth=%d\nHeight=%d\nFramerate=%d\nBitrate=%d\nSliceHeight=%d\n\n",
+ profile, level, refFrames, mWidth, mHeight, mFrameRate, mBitRate, mSliceHeight);
+
+ if ((mCallbackSet == false) && ((mDebugFlags & ENCODER_NO_FILE_WRTIE) == 0)) {
+ mOutputFD = fopen("/mnt/sdcard/video_0.264","w");
+ if (mOutputFD == NULL) {
+ LOGE("\n fopen failed\n");
+ }
+ LOGD("\nCallback was NULL. Opened file for writing\n");
+ }
+
+ // initialize omx callback handling thread
+ if(mOMXCallbackHandler.get() == NULL) {
+ mOMXCallbackHandler = new OMXCallbackHandler(this);
+ }
+
+ if ( NULL == mOMXCallbackHandler.get() ) {
+ LOGE("Couldn't create omx callback handler");
+ return -1;
+ }
+
+ err = mOMXCallbackHandler->run("OMXCallbackThread", PRIORITY_URGENT_DISPLAY);
+ if ( err != NO_ERROR ) {
+ if( err == INVALID_OPERATION) {
+ LOGE("omx callback handler thread already runnning!!");
+ err = NO_ERROR;
+ } else {
+ LOGE("Couldn't run omx callback handler thread");
+ return -1;
+ }
+ }
+
+ mState = OMX_StateLoaded;
+
+ OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+ INIT_OMX_STRUCT(&format, OMX_VIDEO_PARAM_PORTFORMATTYPE);
+ format.nPortIndex = INPUT_PORT;
+ format.nIndex = 0;
+ bool found = false;
+ OMX_U32 index = 0;
+ for (;;) {
+ format.nIndex = index;
+ err = mOMX->getParameter(mNode, OMX_IndexParamVideoPortFormat, &format, sizeof(format));
+ if (err != OK) {
+ LOGD( "get OMX_IndexParamVideoPortFormat InPort Error:0x%x. OMX_ErrorUnsupportedIndex=0x%x", err, OMX_ErrorUnsupportedIndex);
+ return -1;
+ }
+
+ if (format.eCompressionFormat == OMX_VIDEO_CodingUnused
+ && format.eColorFormat == (OMX_COLOR_FORMATTYPE)OMX_TI_COLOR_FormatYUV420PackedSemiPlanar) {
+ found = true;
+ break;
+ }
+ ++index;
+ }
+
+ if (!found) {
+ LOGE("Did not find a match.");
+ return -1;
+ }
+
+ MY_LOGV("found a match.");
+ err = mOMX->setParameter(mNode, OMX_IndexParamVideoPortFormat, &format, sizeof(format));
+ if (err != OK) {
+ LOGD( "set OMX_IndexParamVideoPortFormat InPort Error:%d", err);
+ return -1;
+ }
+
+ format.nPortIndex = OUTPUT_PORT;
+ format.nIndex = 0;
+ found = false;
+ index = 0;
+ for (;;) {
+ format.nIndex = index;
+ err = mOMX->getParameter(mNode, OMX_IndexParamVideoPortFormat, &format, sizeof(format));
+ if (err != OK) {
+ LOGD( "get OMX_IndexParamVideoPortFormat OutPort Error:%d", err);
+ return -1;
+ }
+
+ if (format.eCompressionFormat == OMX_VIDEO_CodingAVC
+ && format.eColorFormat == (OMX_COLOR_FormatUnused)) {
+ found = true;
+ break;
+ }
+ ++index;
+ }
+
+ if (!found) {
+ LOGE("Did not find a match.");
+ return -1;
+ }
+
+ MY_LOGV("found a match.");
+ err = mOMX->setParameter(mNode, OMX_IndexParamVideoPortFormat, &format, sizeof(format));
+ if (err != OK) {
+ LOGD( "set OMX_IndexParamVideoPortFormat OutPort Error:%d", err);
+ return -1;
+ }
+
+ //
+ // Populate Video input Port
+ //
+ INIT_OMX_STRUCT(&tInPortDef, OMX_PARAM_PORTDEFINITIONTYPE);
+
+ tInPortDef.nPortIndex = INPUT_PORT;
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, &tInPortDef, sizeof(tInPortDef));
+ if (err != OK) {
+ LOGD( "get OMX_IndexParamPortDefinition InPort Error:%d", err);
+ return -1;
+ }
+
+ tInPortDef.format.video.nFrameWidth = mWidth;
+ tInPortDef.format.video.nFrameHeight = mHeight;
+ tInPortDef.format.video.nStride = 4096;
+ tInPortDef.format.video.nSliceHeight = mHeight;
+ tInPortDef.format.video.xFramerate = (mFrameRate << 16);
+ tInPortDef.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
+ tInPortDef.format.video.eColorFormat = (OMX_COLOR_FORMATTYPE)OMX_TI_COLOR_FormatYUV420PackedSemiPlanar;
+ tInPortDef.nBufferSize = (mWidth * mHeight *3)/2;
+ err = mOMX->setParameter(mNode, OMX_IndexParamPortDefinition, &tInPortDef, sizeof(tInPortDef));
+ if (err != OK) {
+ LOGD( "set OMX_IndexParamPortDefinition InPort Error:%d", err);
+ return -1;
+ }
+
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, &tInPortDef, sizeof(tInPortDef));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamPortDefinition InPort Error:%d", err);
+ return -1;
+ }
+
+ //
+ // Populate Video output Port
+ //
+ INIT_OMX_STRUCT(&tOutPortDef, OMX_PARAM_PORTDEFINITIONTYPE);
+ tOutPortDef.nPortIndex = OUTPUT_PORT;
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition,&tOutPortDef, sizeof(tOutPortDef));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamPortDefinition OutPort Error:%d", err);
+ return -1;
+ }
+
+ tOutPortDef.format.video.nFrameWidth = mWidth;
+ tOutPortDef.format.video.nFrameHeight = mHeight;
+ tOutPortDef.format.video.xFramerate = 0;
+ tOutPortDef.format.video.nBitrate = mBitRate;
+ tOutPortDef.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
+ tOutPortDef.format.video.eColorFormat = OMX_COLOR_FormatUnused;
+ tOutPortDef.nBufferCountActual = mOutputBufferCount;
+
+ err = mOMX->setParameter(mNode, OMX_IndexParamPortDefinition, &tOutPortDef, sizeof(tOutPortDef));
+ if (err != OK) {
+ LOGD( "set OMX_IndexParamPortDefinition OutPort Error:%d", err);
+ return -1;
+ }
+
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition,&tOutPortDef, sizeof(tOutPortDef));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamPortDefinition OutPort Error:%d", err);
+ return -1;
+ }
+
+ //
+ // setup (code specific) AVC Encoder paramters for OUTPUT port
+ //
+ OMX_VIDEO_PARAM_AVCTYPE h264type;
+ INIT_OMX_STRUCT(&h264type,OMX_VIDEO_PARAM_AVCTYPE);
+
+ h264type.nPortIndex = OUTPUT_PORT;
+
+ err = mOMX->getParameter(mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamVideoAvc failed : %d", err);
+ return -1;
+ }
+
+ h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
+ h264type.eProfile = profile;
+ h264type.eLevel = level;
+ h264type.nSliceHeaderSpacing = 0;
+ h264type.bUseHadamard = OMX_TRUE;
+ h264type.nRefFrames = refFrames;
+ h264type.nBFrames = 0;
+ //h264type.nPFrames = 30; // assume iFrameInterval 1, frameRate
+ h264type.nPFrames = 0; // Let only the first frame be an I Frame. The rest will be P Frames. For VTC type of applications, you want to insert the IDR only when necessary.
+ h264type.nRefIdx10ActiveMinus1 = 0;
+ h264type.nRefIdx11ActiveMinus1 = 0;
+ h264type.bEntropyCodingCABAC = OMX_FALSE;
+ h264type.bWeightedPPrediction = OMX_FALSE;
+ h264type.bconstIpred = OMX_FALSE;
+ h264type.bDirect8x8Inference = OMX_FALSE;
+ h264type.bDirectSpatialTemporal = OMX_FALSE;
+ h264type.nCabacInitIdc = 0;
+ h264type.bEnableUEP = OMX_FALSE;
+ h264type.bEnableFMO = OMX_FALSE;
+ h264type.bEnableASO = OMX_FALSE;
+ h264type.bEnableRS = OMX_FALSE;
+ h264type.bFrameMBsOnly = OMX_TRUE;
+ h264type.bMBAFF = OMX_FALSE;
+ h264type.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable;
+
+ err = mOMX->setParameter(mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
+ if (err != OK) {
+ LOGD("set OMX_IndexParamVideoAvc failed : %d", err);
+ return -1;
+ }
+
+ //
+ // Set Profile and Level for OUTPUT
+ //
+ OMX_VIDEO_PARAM_PROFILELEVELTYPE profileLevel;
+ INIT_OMX_STRUCT(&profileLevel, OMX_VIDEO_PARAM_PROFILELEVELTYPE);
+ profileLevel.nPortIndex = OUTPUT_PORT;
+ err = mOMX->getParameter(mNode, OMX_IndexParamVideoProfileLevelCurrent, &profileLevel, sizeof(profileLevel));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamVideoProfileLevelCurrent failed : %d", err);
+ return -1;
+ }
+
+ profileLevel.eProfile = profile;
+ profileLevel.eLevel = level;
+ err = mOMX->setParameter(mNode, OMX_IndexParamVideoProfileLevelCurrent, &profileLevel, sizeof(profileLevel));
+ if (err != OK) {
+ LOGD("set OMX_IndexParamVideoProfileLevelCurrent failed : %d", err);
+ return -1;
+ }
+
+ //
+ // Set data content type for input port
+ //
+ OMX_TI_VIDEO_PARAM_FRAMEDATACONTENTTYPE dataContent;
+ INIT_OMX_STRUCT(&dataContent, OMX_TI_VIDEO_PARAM_FRAMEDATACONTENTTYPE);
+ dataContent.nPortIndex = INPUT_PORT;
+ err = mOMX->getParameter(mNode, (OMX_INDEXTYPE)OMX_TI_IndexParamVideoFrameDataContentSettings, &dataContent, sizeof(dataContent));
+ if (err != OK) {
+ LOGD("get OMX_TI_IndexParamVideoFrameDataContentSettings failed : %d", err);
+ return -1;
+ }
+
+ dataContent.eContentType = OMX_TI_Video_Progressive; //appears to be the default value
+ err = mOMX->setParameter(mNode, (OMX_INDEXTYPE)OMX_TI_IndexParamVideoFrameDataContentSettings, &dataContent, sizeof(dataContent));
+ if (err != OK) {
+ LOGD("set OMX_TI_IndexParamVideoFrameDataContentSettings failed : %d", err);
+ return -1;
+ }
+
+ //
+ // setupBitRate for OUTPUT
+ //
+ OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
+ INIT_OMX_STRUCT(&bitrateType,OMX_VIDEO_PARAM_BITRATETYPE);
+ bitrateType.nPortIndex = OUTPUT_PORT;
+ err = mOMX->getParameter(mNode, OMX_IndexParamVideoBitrate, &bitrateType, sizeof(bitrateType));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamVideoBitrate failed : %d", err);
+ return -1;
+ }
+
+ bitrateType.eControlRate = OMX_Video_ControlRateVariable;
+ bitrateType.nTargetBitrate = mBitRate;
+ err = mOMX->setParameter(mNode, OMX_IndexParamVideoBitrate, &bitrateType, sizeof(bitrateType));
+ if (err != OK) {
+ LOGD("set OMX_IndexParamVideoBitrate failed : %d", err);
+ return -1;
+ }
+
+ err = mOMX->storeMetaDataInBuffers(mNode, INPUT_PORT, OMX_TRUE);
+ if (err != OK) {
+ LOGE("Storing meta data in video buffers is not supported");
+ return -1;
+ }
+
+ if (mSliceHeight == 0) {
+ LOG_FUNCTION_NAME_EXIT
+ return 0;
+ }
+
+ /**************** Configuration specific to Slice based processing ******************/
+
+ //
+ // setup data sync mode for INPUT
+ //
+ OMX_VIDEO_PARAM_DATASYNCMODETYPE syncMode;
+ INIT_OMX_STRUCT(&syncMode, OMX_VIDEO_PARAM_DATASYNCMODETYPE);
+ syncMode.nPortIndex = INPUT_PORT;
+ err = mOMX->getParameter(mNode, (OMX_INDEXTYPE)OMX_TI_IndexParamVideoDataSyncMode, &syncMode, sizeof(syncMode));
+ if (err != OK) {
+ LOGD("get OMX_TI_IndexParamVideoDataSyncMode failed : %d", err);
+ return -1;
+ }
+
+ syncMode.eDataMode = OMX_Video_NumMBRows;
+ err = mOMX->setParameter(mNode, (OMX_INDEXTYPE)OMX_TI_IndexParamVideoDataSyncMode, &syncMode, sizeof(syncMode));
+ if (err != OK) {
+ LOGD("set OMX_TI_IndexParamVideoDataSyncMode failed: %d", err);
+ return -1;
+ }
+
+ //
+ // setup data sync mode for OUTPUT
+ //
+ INIT_OMX_STRUCT(&syncMode, OMX_VIDEO_PARAM_DATASYNCMODETYPE);
+ syncMode.nPortIndex = OUTPUT_PORT;
+ err = mOMX->getParameter(mNode, (OMX_INDEXTYPE)OMX_TI_IndexParamVideoDataSyncMode, &syncMode, sizeof(syncMode));
+ if (err != OK) {
+ LOGD("get OMX_TI_IndexParamVideoDataSyncMode failed : %d", err);
+ return -1;
+ }
+
+ syncMode.eDataMode = OMX_Video_EntireFrame;
+ syncMode.nNumDataUnits = 1;
+ err = mOMX->setParameter(mNode, (OMX_INDEXTYPE)OMX_TI_IndexParamVideoDataSyncMode, &syncMode, sizeof(syncMode));
+ if (err != OK) {
+ LOGD("set OMX_TI_IndexParamVideoDataSyncMode failed: %d", err);
+ return -1;
+ }
+
+ LOG_FUNCTION_NAME_EXIT
+ return 0;
+}
+
+status_t OMXEncoder::prepare() {
+ status_t err;
+
+ LOG_FUNCTION_NAME_ENTRY
+
+ if (setCurrentState(OMX_StateIdle)) {
+ return -1;
+ }
+
+ INIT_OMX_STRUCT(&tInPortDef, OMX_PARAM_PORTDEFINITIONTYPE);
+ tInPortDef.nPortIndex = INPUT_PORT;
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, &tInPortDef, sizeof(tInPortDef));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamPortDefinition InPort Error:%d", err);
+ return -1;
+ }
+
+ if (mSliceHeight == 0) { // non tunnel mode
+
+ mDealer[INPUT_PORT] = new MemoryDealer((tInPortDef.nBufferCountActual*tInPortDef.nBufferSize), "RECORD_INPUT");
+ for (OMX_U32 i = 0; i < tInPortDef.nBufferCountActual; ++i) {
+ mBufferInfo[INPUT_PORT][i].mEncMem= mDealer[INPUT_PORT]->allocate(tInPortDef.nBufferSize);
+ CHECK(mBufferInfo[INPUT_PORT][i].mEncMem.get() != NULL);
+ err = mOMX->allocateBufferWithBackup(mNode, INPUT_PORT, mBufferInfo[INPUT_PORT][i].mEncMem, (void**)(&(mBufferInfo[INPUT_PORT][i].mBufferHdr)));
+ if (err != OK) {
+ LOGE("OMX_AllocateBuffer for input port index:%d failed:%d",(int)i,err);
+ mBufferInfo[INPUT_PORT][i].mBufferHdr = NULL;
+ }
+ }
+ LOGD( "Allocated %d Input port Buffers. ", (int)tInPortDef.nBufferCountActual);
+ }
+
+ INIT_OMX_STRUCT(&tOutPortDef, OMX_PARAM_PORTDEFINITIONTYPE);
+ tOutPortDef.nPortIndex = OUTPUT_PORT;
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, &tOutPortDef, sizeof(tOutPortDef));
+ if (err != OK) {
+ LOGE("get OMX_IndexParamPortDefinition OutPort Error:%d", err);
+ return -1;
+ }
+
+#ifdef NO_MEMCOPY
+ err = allocateOutputBuffers();
+ if (err != OK) return -1;
+#else
+
+ mDealer[OUTPUT_PORT] = new MemoryDealer((tOutPortDef.nBufferCountActual*tOutPortDef.nBufferSize), "RECORD_OUTPUT");
+ for (OMX_U32 i = 0; i < tOutPortDef.nBufferCountActual; ++i) {
+ mBufferInfo[OUTPUT_PORT][i].mEncMem = mDealer[OUTPUT_PORT]->allocate(tOutPortDef.nBufferSize);
+ err = mOMX->allocateBufferWithBackup(mNode, OUTPUT_PORT, mBufferInfo[OUTPUT_PORT][i].mEncMem, (void**)(&(mBufferInfo[OUTPUT_PORT][i].mBufferHdr)));
+ if (err != OK) {
+ LOGD("OMX_UseBuffer for output port index:%d failed:%d",(int)i,err);
+ mBufferInfo[OUTPUT_PORT][i].mBufferHdr = NULL;
+ return -1;
+ }
+ }
+#endif
+
+ LOGD( "Allocated %d Output port Buffers. ", (int)tOutPortDef.nBufferCountActual);
+
+ LOG_FUNCTION_NAME_EXIT
+ return 0;
+}
+
+status_t OMXEncoder::start(MetaData *params) {
+ status_t err;
+
+ LOG_FUNCTION_NAME_ENTRY
+
+ // now wait until state becomes idle.
+ if (waitForStateSet(OMX_StateIdle)) {
+ LOGD("state change to IDLE failed");
+ return -1;
+ }
+
+ // If we are going to reuse the node, then port enable is a MUST
+ // since we are disabling the port during stop
+
+ // now transition to exec
+ if (setCurrentState(OMX_StateExecuting)) {
+ return -1;
+ }
+
+ if (waitForStateSet(OMX_StateExecuting)) {
+ LOGD("state change to EXECUTING failed");
+ return -1;
+ }
+
+ mAcceptingBuffers = 1; // let OMX callbacks to handle buffers
+
+ INIT_OMX_STRUCT(&tInPortDef, OMX_PARAM_PORTDEFINITIONTYPE);
+ tInPortDef.nPortIndex = INPUT_PORT;
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, &tInPortDef, sizeof(tInPortDef));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamPortDefinition InPort Error:%d", err);
+ return -1;
+ }
+
+ INIT_OMX_STRUCT(&tOutPortDef, OMX_PARAM_PORTDEFINITIONTYPE);
+ tOutPortDef.nPortIndex = OUTPUT_PORT;
+ err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, &tOutPortDef, sizeof(tOutPortDef));
+ if (err != OK) {
+ LOGD("get OMX_IndexParamPortDefinition OutPort Error:%d", err);
+ return -1;
+ }
+
+ // give output buffers to the OMX
+ for (int i=0; i<(int)tOutPortDef.nBufferCountActual; i++) {
+ err = mOMX->fillBuffer(mNode, mBufferInfo[OUTPUT_PORT][i].mBufferHdr);
+ if (err != OK) {
+ LOGD("OMX_FillThisBuffer failed:%d", err);
+ } else {
+ LOGD("called fillBuffer(%d)",i);
+ }
+ }
+
+ // call camera encoder_is_ready
+ mCameraSource->encoderReady();
+
+ if (mSliceHeight) {
+ LOG_FUNCTION_NAME_EXIT
+ return 0;
+ }
+
+ /************** non tunnel / frame mode ***************/
+
+ // now wait for payload to be available. when it does, call OMX_EmptyThisBuffer
+ int64_t time[3];
+ sp<IMemory> payload[3];
+
+ // wait until camera returns a frame
+ for (int i=0; i<3; i++) {
+ payload[i] = mCameraSource->getCameraPayload(time[i]);
+ }
+
+ for (int i=0; i<3; i++) {
+ mBufferInfo[INPUT_PORT][i].mCamMem = payload[i];
+ memcpy((uint8_t *)mBufferInfo[INPUT_PORT][i].mEncMem->pointer(), payload[i]->pointer(), payload[i]->size());
+ err = mOMX->emptyBuffer(mNode, mBufferInfo[INPUT_PORT][i].mBufferHdr, 0, payload[i]->size(), OMX_BUFFERFLAG_ENDOFFRAME, (OMX_TICKS)time);
+ if (err != OK) {
+ LOGD("OMX_EmptyThisBuffer failed:%d", err);
+ } else {
+ LOGD("Called EmptyThisBuffer[%d] ",i);
+ }
+ }
+
+ LOG_FUNCTION_NAME_EXIT
+ return 0;
+}
+
+status_t OMXEncoder::stop() {
+ status_t err;
+
+ LOG_FUNCTION_NAME_ENTRY
+
+ // stop mAcceptingBuffers any callbacks
+ mAcceptingBuffers = 0;
+ mCameraSource->encoderNotReady();
+
+ if (mOutputFD) {
+ fclose(mOutputFD);
+ mOutputFD = NULL;
+ }
+
+ if (mSliceHeight == 0) { // non tunnel mode
+ // flush all the buffers since mAcceptingBuffers off they won't be returned.
+ err = mOMX->sendCommand(mNode,OMX_CommandFlush, INPUT_PORT);
+ if (err != OK) {
+ LOGD("OMX_CommandFlush for input port (0) failed:%d", err);
+ }
+ }
+
+ err = mOMX->sendCommand(mNode,OMX_CommandFlush, OUTPUT_PORT);
+ if (err != OK) {
+ LOGD("OMX_CommandFlush for output port (1) failed:%d", err);
+ }
+
+ // change state to Idle if not already
+ if (mState != OMX_StateIdle && mState != OMX_StateLoaded) {
+ if (setCurrentState(OMX_StateIdle)) {
+ LOGD("OMX_StateIdle failed");
+ }
+
+ if (waitForStateSet(OMX_StateIdle)) {
+ LOGD("state change to IDLE failed");
+ }
+ }
+
+ // disable ports
+ err = mOMX->sendCommand(mNode, OMX_CommandPortDisable, -1);
+ if (err != OK) {
+ LOGD("Error in SendCommand()-OMX_CommandPortDisable:");
+ } else {
+ LOGD("OMX_CommandPortDisable done");
+ }
+
+ return 0;
+}
+
+status_t OMXEncoder::deinit() {
+ status_t err;
+
+ LOG_FUNCTION_NAME_ENTRY
+
+ if (mSliceHeight == 0) { // non tunnel mode
+ // free input buffers
+ for (int i=0; i<(int)tInPortDef.nBufferCountActual; i++) {
+ if (mBufferInfo[INPUT_PORT][i].mBufferHdr) {
+ err = mOMX->freeBuffer(mNode, INPUT_PORT, mBufferInfo[INPUT_PORT][i].mBufferHdr);
+ if( (err != OK)) {
+ LOGD("Free Buffer for Input Port buffer:%d failed:%d",i,err);
+ }
+ }
+ }
+ }
+
+ // free output buffers
+ for (int i=0; i <(int)tOutPortDef.nBufferCountActual; i++) {
+ if (mBufferInfo[OUTPUT_PORT][i].mBufferHdr) {
+ err = mOMX->freeBuffer(mNode,OUTPUT_PORT,mBufferInfo[OUTPUT_PORT][i].mBufferHdr);
+ if( (err != OK)) {
+ LOGD("Free Buffer for Output Port buffer:%d failed:%d",i,err);
+ }
+ }
+ }
+
+ // change state to Loaded
+ if (mState != OMX_StateLoaded) {
+ if (setCurrentState(OMX_StateLoaded)) {
+ LOGD("OMX_StateLoaded failed");
+ }
+ if (waitForStateSet(OMX_StateLoaded)) {
+ LOGD("state change to LOADED failed");
+ }
+ } else {
+ LOGD("It was already OMX_StateLoaded???");
+ }
+
+ usleep(5000);
+
+
+ //Exit and free ref to callback handling thread
+ if ( NULL != mOMXCallbackHandler.get() ) {
+ TIUTILS::Message msg;
+ msg.command = OMXCallbackHandler::COMMAND_EXIT;
+ //Clear all messages pending first
+ mOMXCallbackHandler->clearCommandQ();
+ mOMXCallbackHandler->put(&msg);
+ mOMXCallbackHandler->requestExitAndWait();
+ mOMXCallbackHandler.clear();
+ }
+
+ LOG_FUNCTION_NAME_EXIT
+ return 0;
+}
+
+sp<MetaData> OMXEncoder::getFormat() {
+ return NULL;
+}
+
+status_t OMXEncoder::read(MediaBuffer **buffer, const ReadOptions *options) {
+ return 0;
+}
+
+
+OMX_ERRORTYPE OMXEncoder::EventHandler(OMX_EVENTTYPE eEvent, OMX_U32 nData1,OMX_U32 nData2) {
+ OMX_ERRORTYPE errorType;
+ MY_LOGV("########## EventHandler: eEvent:0x%x, nData1:%d, nData2:%d, pid=%d", (int)eEvent, (int)nData1, (int)nData2, getpid());
+
+ switch (eEvent) {
+ case OMX_EventCmdComplete:
+ if (nData1 == OMX_CommandPortDisable) {
+ if (nData2 == OMX_DirInput) {
+ LOGD( "Component OMX_EventCmdComplete OMX_CommandPortDisable OMX_DirInput");
+ }
+ if (nData2 == OMX_DirOutput) {
+ LOGD( "Component OMX_EventCmdComplete OMX_CommandPortDisable OMX_DirOutput");
+ }
+ } else if (nData1 == OMX_CommandStateSet) {
+ LOGD( "Component OMX_EventCmdComplete OMX_CommandStateSet new State:%s",OMXStateName((OMX_STATETYPE)nData2));
+ {
+ Mutex::Autolock autoLock(mLock);
+ mState = (OMX_STATETYPE)nData2;
+ }
+ mAsyncCompletion.signal();
+
+ } else if (nData1 == OMX_CommandFlush) {
+ LOGD( "Component OMX_EventCmdComplete OMX_CommandFlush port:%d",(int)nData2);
+ } else {
+ LOGD( "Component OMX_EventCmdComplete command:%d",(int)nData1);
+ }
+ break;
+
+ case OMX_EventError:
+ errorType = (OMX_ERRORTYPE) nData1;
+ LOGD( "\n\n\nComponent OMX_EventError error:%x\n\n\n",errorType);
+ break;
+ default:
+ break;
+ }
+ MY_LOGV("EXIT EventHandler");
+ return errorType;
+}
+
+status_t OMXEncoder::FillBufferDone(OMX_BUFFERHEADERTYPE* pBufferHdr, OMX_U32 nOffset, OMX_U32 nFilledLen, OMX_TICKS nTimeStamp) {
+ status_t err;
+ OMX_U32 i=0;
+
+ // not mAcceptingBuffers, just return, eventually, decoder will stop
+ if (mAcceptingBuffers == 0) {
+ MY_LOGV( " in non mAcceptingBuffers mode");
+ return OMX_ErrorNone;
+ }
+
+ for (i = 0; i < tOutPortDef.nBufferCountActual; i++) {
+ if (pBufferHdr == mBufferInfo[OUTPUT_PORT][i].mBufferHdr) {
+ break;
+ }
+ }
+ if (i == tOutPortDef.nBufferCountActual) {
+ LOGE("FillBufferDone returned unknown buffer header! i=%d",(int)i);
+ return -1;
+ }
+ //LOGD( "----- %d ----- ", (int)i);
+
+ if (mDebugFlags & DEBUG_DUMP_ENCODER_TIMESTAMP) LOGD("FBD TS: %lld", nTimeStamp);
+
+ if (mDebugFlags & FPS_ENCODER) PrintEncoderFPS();
+
+ if (mDebugFlags & ENCODER_LATENCY) PrintEncoderLatency(nTimeStamp);
+
+ if (mDebugFlags & ENCODER_EFFECTIVE_BITRATE) PrintEffectiveBitrate(nFilledLen);
+
+ if (mCallbackSet) {
+ mEncodedBufferCallback((mBufferInfo[OUTPUT_PORT][i].mEncMem->pointer() + nOffset), nFilledLen, nTimeStamp);
+ } else {
+ if (mOutputFD != NULL) {
+ i = fwrite((unsigned char *)(mBufferInfo[OUTPUT_PORT][i].mEncMem->pointer() + nOffset), 1, nFilledLen, mOutputFD);
+ if (i != nFilledLen) {
+ LOGD("fwrite failed:%d should have been:%d\n", i, nFilledLen);
+ return -1;
+ }
+ fflush(mOutputFD);
+ }
+ }
+
+ err = mOMX->fillBuffer(mNode, pBufferHdr);
+ if (err != OK) {
+ LOGE("OMX_FillThisBuffer failed:%d", err);
+ }
+
+ mBufferCount++;
+ MY_LOGV("EXIT FillBufferDone: nOffset: %d, nFilledLen=%d, mBufferCount=%d", nOffset, nFilledLen, mBufferCount);
+ return OMX_ErrorNone;
+}
+
+status_t OMXEncoder::EmptyBufferDone(OMX_BUFFERHEADERTYPE* pBufferHdr)
+{
+ status_t err;
+ OMX_U32 i=0;
+ //MY_LOGV("ENTER EmptyBufferDone");
+
+ // not mAcceptingBuffers, just return, eventually, decoder will stop
+ if (mAcceptingBuffers == 0) {
+ MY_LOGV( " in non mAcceptingBuffers mode");
+ return OMX_ErrorNone;
+ }
+
+ for (i = 0; i < tInPortDef.nBufferCountActual; i++) {
+ if (pBufferHdr == mBufferInfo[INPUT_PORT][i].mBufferHdr) break;
+ }
+
+ if (i == tInPortDef.nBufferCountActual) {
+ LOGE("EmptyBufferDone returned unknown buffer header! i=%d",(int)i);
+ return -1;
+ }
+
+ mCameraSource->releaseBuffer(mBufferInfo[INPUT_PORT][i].mCamMem);
+
+ if (mSliceHeight == 0) { // non tunnel mode
+
+ // now get the next buffer and feed the encoder
+ sp<IMemory> payload;
+ int64_t time;
+
+ // wait til buffer in the camera
+ payload = mCameraSource->getCameraPayload(time);
+ if (payload != NULL) {
+ mBufferInfo[INPUT_PORT][i].mCamMem = payload;
+ memcpy((uint8_t *)mBufferInfo[INPUT_PORT][i].mEncMem->pointer(), payload->pointer(), payload->size());
+ err = mOMX->emptyBuffer(mNode, mBufferInfo[INPUT_PORT][i].mBufferHdr, 0, payload->size(), OMX_BUFFERFLAG_ENDOFFRAME, time);
+ if (err != OK) {
+ LOGE("OMX_EmptyThisBuffer failed:%d", err);
+ }
+ }
+ }
+
+ //MY_LOGV("EXIT EmptyBufferDone");
+ return err;
+}
+
+status_t OMXEncoder::setCurrentState(OMX_STATETYPE newState) {
+ MY_LOGV("Attempting to set state to %s.", OMXStateName(newState));
+
+ status_t err = mOMX->sendCommand(mNode, OMX_CommandStateSet, newState);
+ if (err != OK) {
+ LOGD("setCurrentState: Error:%d", err);
+ return -1;
+ }
+
+ LOG_FUNCTION_NAME_EXIT
+ return 0;
+}
+
+status_t OMXEncoder::waitForStateSet(OMX_STATETYPE newState) {
+ MY_LOGV("waitForStateSet: Waiting to move to state %s .....", OMXStateName(newState));
+
+ if (newState == mState) {
+ LOGD("New State [%s] already set!", OMXStateName(newState));
+ return 0;
+ }
+
+ status_t retval = mAsyncCompletion.waitRelative(mLock, TWO_SECOND);
+ if (retval) {
+ if (errno == ETIMEDOUT) {
+ LOGD("$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Waiting for State change timed out $$$$$$$$$$$$$$$$$$$$$$$$$$$$");
+ } else {
+ LOGD("$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Waiting for State errno :%d, retval:%d \n", errno, retval);
+ }
+ }
+
+ if (newState == mState) {
+ LOGD("State [%s] Set !!!!!!!!!!!!!!!!!", OMXStateName(newState));
+ return 0;
+ }
+
+ LOG_FUNCTION_NAME_EXIT
+ return -1;
+}
+
+//Function to set the slice mode for video encoder output port
+status_t OMXEncoder::setEncoderOutputSlice(OMX_U32 nHeight, OMX_U32 nWidth, OMX_U32 sizeBytes, OMX_U32 sizeMB) {
+ status_t err = 0;
+
+ MY_LOGV("Setting Video Output Slice Mode Size in Bytes:%d, Size in MB:%d\n",sizeBytes, sizeMB);
+
+ if ((!sizeBytes) && (!sizeMB)) {
+ //Enc o/p slice not set
+ return err;
+ }
+
+ if (sizeBytes) {
+
+ if (nWidth <= 320) {
+ LOGD ("Setting the Video Encoder output slice mode NOT supported for given Resolution(width should be > 320)\n");
+ return err;
+ }
+
+ if (sizeBytes < 256) {
+ LOGD ("Slice size provided for Video Encoder output port too small, should be atleast 256 bytes\n");
+ return err;
+ }
+
+ OMX_VIDEO_CONFIG_SLICECODINGTYPE slicetype;
+ INIT_OMX_STRUCT(&slicetype, OMX_VIDEO_CONFIG_SLICECODINGTYPE);
+ slicetype.nPortIndex = OUTPUT_PORT;
+
+ err = mOMX->getConfig(
+ mNode, (OMX_INDEXTYPE)OMX_TI_IndexConfigSliceSettings, &slicetype, sizeof(slicetype));
+ if (err != OK) {
+ LOGD("get OMX_TI_IndexConfigSliceSettings failed : 0x%x", err);
+ return -1;
+ }
+
+ slicetype.eSliceMode = OMX_VIDEO_SLICEMODE_AVCByteSlice;
+ slicetype.nSlicesize = sizeBytes;
+
+ err = mOMX->setConfig(
+ mNode, (OMX_INDEXTYPE)OMX_TI_IndexConfigSliceSettings, &slicetype, sizeof(slicetype));
+ if (err != OK) {
+ LOGD("set OMX_TI_IndexConfigSliceSettings OMX_VIDEO_SLICEMODE_AVCByteSlice failed : 0x%x", err);
+ return -1;
+ }
+
+ } else if (sizeMB) {
+
+ if (sizeMB <= 6) {
+ LOGD ("Macro Block set for the Video Encoder output slice mode NOT supported (very low should be > 6) \n");
+ return err;
+ }
+
+ /* Max # of MB
+ 1080p=8160
+ 720p=3600
+ VGA=1200
+ */
+ if (sizeMB > (((nWidth+15)>> 4) * ((nHeight+15)>> 4))) {
+ LOGD ("Macro Block set for the Video Encoder output slice mode is too large, should be less then \
+ (((PreviewWidth+15)>> 4) * ((PreviewHeight+15)>> 4)) \n");
+ return err;
+ }
+
+ OMX_VIDEO_CONFIG_SLICECODINGTYPE slicetype;
+ INIT_OMX_STRUCT(&slicetype, OMX_VIDEO_CONFIG_SLICECODINGTYPE);
+ slicetype.nPortIndex = OUTPUT_PORT;
+
+ err = mOMX->getConfig(
+ mNode, (OMX_INDEXTYPE)OMX_TI_IndexConfigSliceSettings, &slicetype, sizeof(slicetype));
+ if (err != OK) {
+ LOGD("get OMX_TI_IndexConfigSliceSettings failed : 0x%x", err);
+ return -1;
+ }
+
+ slicetype.eSliceMode = OMX_VIDEO_SLICEMODE_AVCMBSlice;
+ slicetype.nSlicesize = sizeMB;
+
+ err = mOMX->setConfig(
+ mNode, (OMX_INDEXTYPE)OMX_TI_IndexConfigSliceSettings, &slicetype, sizeof(slicetype));
+ if (err != OK) {
+ LOGD("set OMX_TI_IndexConfigSliceSettings OMX_VIDEO_SLICEMODE_AVCMBSlice failed : 0x%x", err);
+ return -1;
+ }
+
+ }
+
+ /* Other limitations:
+ - Input content type should be progressive (currently nPFrames = 0 by default)
+ - Changing parameters at run time will not have effect until next I-frame (hence setting IDR frame forcefully below)
+ - Incase of doing the initial setting of nPFrames = 0 (only initial frame is I-frame and all others P-frames),
+ you must request an I-frame to the codec after you have set nSlicesize to see your changes take place.
+ */
+
+ MY_LOGV ("Insert IDR frame for the Encoder o/p slice mode setting to get effective \n");
+ //Insert IDR frame for the setting to get effective
+ OMX_CONFIG_INTRAREFRESHVOPTYPE voptype;
+ INIT_OMX_STRUCT(&voptype, OMX_CONFIG_INTRAREFRESHVOPTYPE);
+ voptype.nPortIndex = OUTPUT_PORT;
+
+ err = mOMX->getConfig(
+ mNode, OMX_IndexConfigVideoIntraVOPRefresh, &voptype, sizeof(voptype));
+ if (err != OK) {
+ LOGD("get OMX_IndexConfigVideoIntraVOPRefresh failed : %d", err);
+ return -1;
+ }
+
+ voptype.IntraRefreshVOP = OMX_TRUE;
+ err = mOMX->setConfig(
+ mNode, OMX_IndexConfigVideoIntraVOPRefresh, &voptype, sizeof(voptype));
+ if (err != OK) {
+ LOGD("set OMX_IndexConfigVideoIntraVOPRefresh failed : %d", err);
+ return -1;
+ }
+
+ MY_LOGV("Insert IDR Frame DONE!!!, Setting Video Output Slice Mode\n");
+ return err;
+}
+
+
+
+void OMXEncoder::setCallback(EncodedBufferCallback fp) {
+ mEncodedBufferCallback = fp;
+ mCallbackSet = true;
+}
+
+status_t OMXEncoder::changeFrameRate(int framerate) {
+ LOGV("setConfigVideoFrameRate: %d", frameRate);
+ OMX_CONFIG_FRAMERATETYPE framerateType;
+ INIT_OMX_STRUCT(&framerateType, OMX_CONFIG_FRAMERATETYPE);
+ framerateType.nPortIndex = INPUT_PORT;
+
+ status_t err = mOMX->getConfig(
+ mNode, OMX_IndexConfigVideoFramerate,
+ &framerateType, sizeof(framerateType));
+ if (err != OK) {
+ return BAD_VALUE;
+ }
+
+ framerateType.xEncodeFramerate = framerate << 16;
+ err = mOMX->setConfig(mNode, OMX_IndexConfigVideoFramerate, &framerateType, sizeof(framerateType));
+ if (err != OK) {
+ return BAD_VALUE;
+ }
+ return OK;
+}
+
+status_t OMXEncoder::changeBitRate(int bitrate) {
+ OMX_VIDEO_CONFIG_BITRATETYPE bitrateType;
+ INIT_OMX_STRUCT(&bitrateType,OMX_VIDEO_CONFIG_BITRATETYPE);
+ bitrateType.nPortIndex = OUTPUT_PORT;
+ status_t err = mOMX->getConfig(mNode, OMX_IndexConfigVideoBitrate, &bitrateType, sizeof(bitrateType));
+ if (err != OMX_ErrorNone) {
+ LOGE("get OMX_IndexConfigVideoBitrate failed err:%X", err);
+ return err;
+ }
+
+ LOGD("\nSet encoder bitrate to %d.\n\n", bitrate);
+ bitrateType.nEncodeBitrate = bitrate;
+ err = mOMX->setConfig(mNode, OMX_IndexConfigVideoBitrate, &bitrateType, sizeof(bitrateType));
+ if (err != OMX_ErrorNone) {
+ LOGE("set OMX_IndexConfigVideoBitrate failed error:%x", err);
+ return err;
+ }
+
+ return OK;
+}
+
+#ifdef NO_MEMCOPY
+status_t OMXEncoder::allocateOutputBuffer() {
+ //USE_ION_BUFFERS_ALLOCATED_BY_DOMX
+
+ int ion_fd = ion_open();
+ if(ion_fd == 0) {
+ LOGE("ion_open failed!!!");
+ return -1;
+ }
+
+ struct ion_handle *importedHandle = NULL;
+
+ for (OMX_U32 i = 0; i < tOutPortDef.nBufferCountActual; ++i) {
+
+ IOMX::buffer_id buffer;
+ void *pBuffer;
+ err = mOMX->allocateBuffer(mNode, OUTPUT_PORT, tOutPortDef.nBufferSize, &buffer, &pBuffer);
+ if (err != OK) {
+ LOGD("OMX_UseBuffer for output port index:%d failed:%d",(int)i,err);
+ mBufferInfo[OUTPUT_PORT][i].mBufferHdr = NULL;
+ }
+
+ OMX_TI_ION_SHARE_FD shareFDParam;
+ INIT_OMX_STRUCT(&shareFDParam, OMX_TI_ION_SHARE_FD);
+ shareFDParam.nPortIndex = OUTPUT_PORT;
+ shareFDParam.nBufferIndex = i;
+ err = mOMX->getParameter(mNode, (OMX_INDEXTYPE)OMX_TI_IndexIONBufferShareHandle, (void*)&shareFDParam, sizeof(shareFDParam));
+ if (err != OK) {
+ LOGD("get OMX_TI_IndexIONBufferShareHandle Error:%d", err);
+ return -1;
+ }
+ LOGD("ENC SHARE FD = %d", shareFDParam.nShareFD);
+
+ OMX_U32 nSize = (tOutPortDef.nBufferSize + LINUX_PAGE_SIZE - 1) & ~(LINUX_PAGE_SIZE - 1);
+
+ err = ion_import(ion_fd, shareFDParam.nShareFD, &importedHandle);
+ if (err != OK) {
+ LOGD("ion_import failed. ret = %d", err);
+ return -1;
+ }
+ LOGD("IMPORT SUCCEEDED");
+
+ int mmap_fd;
+ void *pIONBuffer;
+ err = ion_map(ion_fd, importedHandle, nSize, PROT_READ | PROT_WRITE, MAP_SHARED, 0, (unsigned char**)&pIONBuffer, &mmap_fd);
+ if (err) {
+ LOGE("\n\n$$$$$$$$$$$$$$$$ Userspace mapping of ION buffers returned error %d\n\n", err);
+ err = ion_free(ion_fd, h);
+ if (err) LOGE("\n ion_free failed err=%d.\n\n%s\n\n", err, strerror(errno));
+ return -1;
+ }
+ // TODO: More work needs to be done here.. This is just a skeleton for the moment.
+ }
+
+ return OK;
+}
+
+#endif
+
+
diff --git a/test/VTC/IOMXEncoder.h b/test/VTC/IOMXEncoder.h
new file mode 100644
index 0000000..367e56b
--- /dev/null
+++ b/test/VTC/IOMXEncoder.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef IOMX_ENCODER_H
+#define IOMX_ENCODER_H
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <semaphore.h>
+#include <pthread.h>
+
+#include <binder/MemoryDealer.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <system/audio.h>
+#include <utils/List.h>
+#include <cutils/log.h>
+#include <OMX_Component.h>
+#include <camera/Camera.h>
+#include <camera/ICamera.h>
+#include <camera/ICameraClient.h>
+#include <camera/ICameraService.h>
+#include <media/mediaplayer.h>
+#include <media/mediarecorder.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/CameraSource.h>
+#include <media/stagefright/MetaData.h>
+
+
+using namespace android;
+
+typedef void (*EncodedBufferCallback)(void* pBuffer, OMX_U32 nFilledLen, OMX_TICKS nTimeStamp);
+
+struct OMXEncoderObserver;
+
+struct OMXEncoder : public MediaSource {
+ struct BufferInfo {
+ OMX_BUFFERHEADERTYPE* mBufferHdr;
+ sp<IMemory> mEncMem;
+ sp<IMemory> mCamMem;
+ };
+
+ friend class OMXEncoderObserver;
+
+ status_t resetParameters(int width, int height, int framerate, int bitrate, char *fname, int sliceHeight);
+ status_t configure(OMX_VIDEO_AVCPROFILETYPE profile, OMX_VIDEO_AVCLEVELTYPE level, OMX_U32 refFrames);
+ status_t prepare();
+ status_t start(MetaData *params = NULL);
+ status_t stop();
+ status_t deinit();
+ status_t changeFrameRate(int framerate);
+ status_t changeBitRate(int bitrate);
+ status_t setEncoderOutputSlice(OMX_U32 nHeight, OMX_U32 nWidth, OMX_U32 sizeBytes, OMX_U32 sizeMB);
+ sp<MetaData> getFormat();
+ status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL);
+ void on_message(const omx_message &msg);
+ void setCallback(EncodedBufferCallback fp);
+ OMXEncoder(const sp<IOMX> &omx, IOMX::node_id node, sp<MyCameraClient> camera, int width, int height, int framerate, int bitrate, char *fname, int sliceHeight);
+ OMXEncoder(const OMXEncoder &);
+ OMXEncoder &operator=(const OMXEncoder &);
+ ~OMXEncoder();
+ uint32_t mDebugFlags;
+ uint32_t mOutputBufferCount;
+
+private:
+
+ class OMXCallbackHandler : public Thread {
+ public:
+ OMXCallbackHandler(OMXEncoder* enc)
+ : Thread(false), mOMXEncoder(enc) { }
+
+ virtual bool threadLoop() {
+ bool ret;
+ ret = Handler();
+ return ret;
+ }
+
+ status_t put(TIUTILS::Message* msg) {
+ Mutex::Autolock lock(mLock);
+ return mCommandMsgQ.put(msg);
+ }
+
+ void clearCommandQ() {
+ Mutex::Autolock lock(mLock);
+ mCommandMsgQ.clear();
+ }
+
+ enum {
+ COMMAND_EXIT = -1,
+ COMMAND_PROCESS_MSG,
+ };
+
+ private:
+ bool Handler();
+ TIUTILS::MessageQueue mCommandMsgQ;
+ OMXEncoder* mOMXEncoder;
+ Mutex mLock;
+ };
+
+ sp<OMXCallbackHandler> mOMXCallbackHandler;
+
+ OMX_ERRORTYPE EventHandler(OMX_EVENTTYPE eEvent, OMX_U32 nData1,OMX_U32 nData2);
+ status_t FillBufferDone(OMX_BUFFERHEADERTYPE* pBufferHdr, OMX_U32 nOffset, OMX_U32 nFilledLen, OMX_TICKS nTimeStamp);
+ status_t EmptyBufferDone(OMX_BUFFERHEADERTYPE* pBufferHdr);
+ status_t setCurrentState(OMX_STATETYPE newState);
+ status_t waitForStateSet(OMX_STATETYPE newState);
+
+ int mWidth;
+ int mHeight;
+ uint32_t mBitRate;
+ uint32_t mFrameRate;
+ sp<MyCameraClient> mCameraSource;
+ OMX_PARAM_PORTDEFINITIONTYPE tInPortDef;
+ OMX_PARAM_PORTDEFINITIONTYPE tOutPortDef;
+ sp<IOMX> mOMX;
+ IOMX::node_id mNode;
+ BufferInfo mBufferInfo[NUM_PORTS][ENCODER_MAX_BUFFER_COUNT];
+ Condition mAsyncCompletion;
+ Mutex mLock;
+ OMX_STATETYPE mState;
+ int mAcceptingBuffers;
+ sp<MemoryDealer> mDealer[NUM_PORTS];
+ FILE* mOutputFD;
+ int mSliceHeight;
+ int mBufferCount;
+ EncodedBufferCallback mEncodedBufferCallback;
+ bool mCallbackSet;
+};
+
+struct OMXEncoderObserver : public BnOMXObserver {
+ OMXEncoderObserver() {
+ }
+
+ void setCodec(const sp<OMXEncoder> &target) {
+ mTarget = target;
+ }
+
+ // from IOMXObserver
+ virtual void onMessage(const omx_message &omx_msg) {
+ TIUTILS::Message msg;
+ omx_message *ptemp_omx_msg;
+ // TODO: Check on the memory scope of below allocation
+ ptemp_omx_msg = (omx_message *)malloc(sizeof(omx_message));
+ memcpy(ptemp_omx_msg, &omx_msg, sizeof(omx_message));
+ //LOGD("=================omx_msg.type = %x, temp_omx_msg.type = %x",omx_msg.type, ptemp_omx_msg->type);
+ sp<OMXEncoder> codec = mTarget.promote();
+ if (codec.get() != NULL) {
+ msg.command = OMXEncoder::OMXCallbackHandler::COMMAND_PROCESS_MSG;
+ msg.arg1 = (void *)ptemp_omx_msg;
+ codec->mOMXCallbackHandler->put(&msg);
+ codec.clear();
+ }
+ }
+
+protected:
+ virtual ~OMXEncoderObserver() {}
+
+private:
+ wp<OMXEncoder> mTarget;
+ OMXEncoderObserver(const OMXEncoderObserver &);
+ OMXEncoderObserver &operator=(const OMXEncoderObserver &);
+};
+
+#endif
diff --git a/test/VTC/VTCLoopback.cpp b/test/VTC/VTCLoopback.cpp
new file mode 100644
index 0000000..9c7c06b
--- /dev/null
+++ b/test/VTC/VTCLoopback.cpp
@@ -0,0 +1,883 @@
+/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "VTCLoopback.h"
+#include "IOMXEncoder.h"
+#include "IOMXDecoder.h"
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "VTC"
+
+#define MY_LOGV(x, ...) LOGV(x, ##__VA_ARGS__)
+
+using namespace android;
+
+
+int gFilename = 0;
+int gDuration = 10;
+int gTestcaseID = 1;
+int gPreviewWidth = WIDTH;
+int gPreviewHeight = HEIGHT;
+int gCameraIndex = 0;
+int gCameraFrameRate = 30;
+int gNewCameraFrameRate = 0;
+int gEnableAlgo = 0;
+uint32_t gSliceHeight = 0;
+uint32_t gCameraWinX = 50;
+uint32_t gCameraWinY = 50;
+uint32_t gCameraSurfaceWidth = 400;
+uint32_t gCameraSurfaceHeight = 400;
+uint32_t gEncoderBitRate = BITRATE;
+uint32_t gMinEncoderBitRate = BITRATE;
+uint32_t gMaxEncoderBitRate = BITRATE;
+uint32_t gDebugFlags = FPS_DECODER; // | ENCODER_ONLY ;
+uint32_t gEncoderOutputBufferCount = 4;
+uint32_t gEncoderOutputSliceSizeBytes = 0;
+uint32_t gEncoderOutputSliceSizeMB = 0;
+bool gEnableLoopback = false;
+bool gVaryFrameRate = false;
+bool gVaryOrientation = false;
+char mParamValue[100];
+char gRecordFileName[256];
+sp<SurfaceComposerClient> gSurfaceComposerClient;
+sp<SurfaceControl> gSurfaceControl;
+sp<Surface> gPreviewSurface;
+sp<ICameraService> gCameraService;
+sp<ICamera> gICamera;
+sp<MyCameraClient> gCameraClient;
+sp<OMXDecoder> mOMXDecoder;
+OMX_VIDEO_AVCPROFILETYPE gProfile = OMX_VIDEO_AVCProfileBaseline;
+OMX_VIDEO_AVCLEVELTYPE gLevel = OMX_VIDEO_AVCLevel4;
+OMX_U32 gRefFrames = 1;
+
+// Add more parameters as needed.
+struct Configuration {
+ size_t width, height;
+};
+
+int test_DEFAULT_Slice();
+int test_DEFAULT_Frame();
+int test_Robustness();
+int test_Frame_Robustness();
+int test_Slice_Robustness();
+
+typedef int (*pt2TestFunction)();
+pt2TestFunction TestFunctions[10] = {0, test_DEFAULT_Frame, test_DEFAULT_Slice, test_Frame_Robustness, test_Slice_Robustness, 0, 0, 0, 0, 0};
+
+
+static void PrintCameraFPS() {
+ static int mFrameCount = 0;
+ static int mLastFrameCount = 0;
+ static nsecs_t mLastFpsTime = 0;
+ static float mFps = 0;
+ mFrameCount++;
+ if (!(mFrameCount & 0x1F)) {
+ nsecs_t now = systemTime();
+ nsecs_t diff = now - mLastFpsTime;
+ mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
+ mLastFpsTime = now;
+ mLastFrameCount = mFrameCount;
+ LOGD("Camera: %d Frames, %f FPS", mFrameCount, mFps);
+ }
+ // XXX: mFPS has the value we want
+}
+
+void dump_video_port_values(OMX_PARAM_PORTDEFINITIONTYPE& def) {
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
+ LOGD("--------------------------------------------------------------------------------");
+ LOGD("nPortIndex:%d eDir:%s\n",(int)def.nPortIndex,(def.eDir == OMX_DirInput)?"OMX_DirInput":"OMX_DirOutput");
+ LOGD("BufferCountActual:%d BufferCountMin:%d nBufferSize:%d\n", (int)def.nBufferCountActual, (int)def.nBufferCountMin, (int)def.nBufferSize);
+ LOGD("bEnabled:%s bPopulated:%s eDomain:%s BuffersContiguous:%s BufferAlignment:%d",
+ (def.bEnabled)?"TRUE":"FALSE",(def.bPopulated)?"TRUE":"FALSE",
+ (def.eDomain == OMX_PortDomainVideo)?"Video":"Not Video",
+ (def.bBuffersContiguous)?"TRUE":"FALSE",(int)def.nBufferAlignment);
+
+ LOGD("cMIMEType:%s pNativeRender:%p\n",(def.format.video.cMIMEType)?(def.format.video.cMIMEType):"NULL",def.format.video.pNativeRender);
+ LOGD("nFrameWidth:%d nFrameHeight:%d nStride:%d nSliceHeight:%d",
+ (int)def.format.video.nFrameWidth, (int)def.format.video.nFrameHeight, (int)def.format.video.nStride, (int)def.format.video.nSliceHeight);
+ LOGD("nBitrate:%d xFramerate:%d bFlagErrorConcealment:%s",
+ (int)def.format.video.nBitrate, (int)def.format.video.xFramerate, (def.format.video.bFlagErrorConcealment)?"TRUE":"FALSE");
+ LOGD("eCompressionFormat:0x%x eColorFormat:0x%x pNativeWindow:%p",
+ (def.format.video.eCompressionFormat),
+ (def.format.video.eColorFormat), def.format.video.pNativeWindow);
+ LOGD("--------------------------------------------------------------------------------");
+}
+
+#define NAME(n) case n: return #n
+const char *OMXStateName(OMX_STATETYPE state) {
+ switch (state) {
+ NAME(OMX_StateInvalid);
+ NAME(OMX_StateLoaded);
+ NAME(OMX_StateIdle);
+ NAME(OMX_StateExecuting);
+ NAME(OMX_StatePause);
+ NAME(OMX_StateWaitForResources);
+ NAME(OMX_StateKhronosExtensions);
+ NAME(OMX_StateVendorStartUnused);
+ default: return "???";
+ }
+}
+
+
+MyCameraClient::MyCameraClient() {
+ encoder_is_ready = 0;
+ cameraPayloadWaitFlag = 0;
+}
+
+void MyCameraClient::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& data) {
+ //MY_LOGV("=============================================dataCallbackTimestamp");
+ CHECK(data != NULL && data->size() > 0);
+ if (msgType == CAMERA_MSG_VIDEO_FRAME) {
+ if ((gSliceHeight == 0) && (encoder_is_ready)) { // non tunnel mode
+ putCameraPayload(data,(int64_t)timestamp/1000);
+ } else {
+ if (mReleaser != NULL) {
+ mReleaser->releaseRecordingFrame(data);
+ //MY_LOGV("CAMERA_MSG_VIDEO_FRAME %p released",data->pointer());
+ }
+ }
+ }
+}
+
+void MyCameraClient::putCameraPayload(sp<IMemory> payload, int64_t frameTime) {
+ if (gDebugFlags & FPS_CAMERA) PrintCameraFPS();
+ if (gDebugFlags & DEBUG_DUMP_CAMERA_TIMESTAMP) LOGD("CAM TS: %lld", frameTime);
+
+ Mutex::Autolock autoLock(cameraPayloadQueueMutex);
+ cameraPayloadQueue.push_back(payload);
+ frameTimeQueue.push_back(frameTime);
+ if (cameraPayloadQueue.size() >= 1) {
+ if ( cameraPayloadWaitFlag ) cameraPayloadWait.signal();
+ }
+ return;
+}
+
+sp<IMemory> MyCameraClient::getCameraPayload(int64_t& frameTime) {
+ if (!encoder_is_ready) {
+ frameTime = 0;
+ LOGE("getCameraPayload --- returning null");
+ return NULL;
+ }
+
+ {
+ status_t retval;
+ Mutex::Autolock autoLock(cameraPayloadQueueMutex);
+ if (cameraPayloadQueue.empty()) {
+ cameraPayloadWaitFlag = 1;
+ retval = cameraPayloadWait.waitRelative(cameraPayloadQueueMutex, TWO_SECOND);
+ if (retval || !encoder_is_ready) {
+ LOGD("$$$$$$$$$$$$$$$$$$$$$$$$$$$$ getCameraPayload timed out or we are stopping $$$$$$$$$$$$$$$$$$$$$$$$$$$$");
+ frameTime = 0;
+ return NULL;
+ }
+ cameraPayloadWaitFlag = 0;
+ }
+ }
+
+ List< sp<IMemory> >::iterator iterPayload;
+ sp<IMemory> payload;
+
+ List<int64_t>::iterator iterTime;
+ int64_t time;
+
+ {
+ Mutex::Autolock autoLock(cameraPayloadQueueMutex);
+
+ iterPayload = cameraPayloadQueue.begin();
+ payload = (sp<IMemory>)*iterPayload;
+ cameraPayloadQueue.erase(iterPayload);
+
+ iterTime = frameTimeQueue.begin();
+ time = (int64_t)*iterTime;
+ frameTimeQueue.erase(iterTime);
+ }
+
+ frameTime = time;
+ //MY_LOGV("%s: pointer[%p], size[%d]", __FUNCTION__, payload->pointer(), payload->size());
+ return payload;
+}
+
+
+
+int createPreviewSurface() {
+
+ gSurfaceComposerClient = new SurfaceComposerClient();
+ CHECK_EQ(gSurfaceComposerClient->initCheck(), (status_t)OK);
+
+ gCameraSurfaceWidth = gSurfaceComposerClient->getDisplayWidth(0);
+ gCameraSurfaceHeight = gSurfaceComposerClient->getDisplayHeight(0);
+
+ gSurfaceControl = gSurfaceComposerClient->createSurface(0,
+ gCameraSurfaceWidth,
+ gCameraSurfaceHeight,
+ HAL_PIXEL_FORMAT_RGB_565);
+
+ gPreviewSurface = gSurfaceControl->getSurface();
+
+ gSurfaceComposerClient->openGlobalTransaction();
+ gSurfaceControl->setLayer(0x7ffffff0);
+ gSurfaceControl->setPosition(gCameraWinX, gCameraWinY);
+ gSurfaceControl->setSize(gCameraSurfaceWidth, gCameraSurfaceHeight);
+ gSurfaceControl->show();
+ gSurfaceComposerClient->closeGlobalTransaction();
+
+ return 0;
+}
+
+int destroyPreviewSurface() {
+
+ if ( NULL != gPreviewSurface.get() ) {
+ gPreviewSurface.clear();
+ }
+
+ if ( NULL != gSurfaceControl.get() ) {
+ gSurfaceControl->clear();
+ gSurfaceControl.clear();
+ }
+
+ if ( NULL != gSurfaceComposerClient.get() ) {
+ gSurfaceComposerClient->dispose();
+ gSurfaceComposerClient.clear();
+ }
+
+ return 0;
+}
+
+
+int configureCamera() {
+
+ createPreviewSurface();
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ CHECK(sm.get() != NULL);
+
+ sp<IBinder> binder = sm->getService(String16("media.camera"));
+ CHECK(binder.get() != NULL);
+
+ gCameraService = interface_cast<ICameraService>(binder);
+ CHECK(gCameraService.get() != NULL);
+
+ gCameraClient = new MyCameraClient();
+ int i = 0;
+ do {
+ gICamera = gCameraService->connect(gCameraClient, gCameraIndex);
+ if (gICamera.get() != NULL) break;
+ LOGD("\n\n\n========= Camera Busy. So relax and retry. ===========\n\n\n");
+ sleep(1);
+ i++;
+ } while (i < 10);
+
+ if (gICamera == NULL) return -1;
+
+ LOGD("Acquired Camera");
+ gICamera->setPreviewDisplay(gPreviewSurface);
+ gCameraClient->setReleaser(gICamera.get());
+
+ String8 param_str = gICamera->getParameters();
+ CameraParameters params(param_str);
+ params.setPreviewSize(gPreviewWidth, gPreviewHeight);
+ params.setPreviewFrameRate(gCameraFrameRate);
+ params.set(CameraParameters::KEY_RECORDING_HINT, CameraParameters::TRUE);// Set recording hint, otherwise it defaults to high-quality and there is not enough memory available to do playback and camera preview simultaneously!
+ params.set("internal-vtc-hint", CameraParameters::TRUE);
+
+ if (gEnableAlgo & 1) { //VNF Enabled based on cmd line
+ LOGD("VNF is enabled!!! \n");
+ params.set("vnf", CameraParameters::TRUE);
+ } else {
+ LOGD("VNF is disabled!!! \n");
+ params.set("vnf", CameraParameters::FALSE);
+ }
+
+ sprintf(mParamValue,"%u,%u", gCameraFrameRate*1000, gCameraFrameRate*1000);
+ params.set("preview-fps-range", mParamValue);
+ params.set("mode","video-mode");
+
+ if ((!gSliceHeight) && (gEnableAlgo & 2)) { // VSTAB not supported for Slice Mode
+ LOGD("VSTAB is enabled!!! \n");
+ params.set("vstab",CameraParameters::TRUE);
+ params.set("video-stabilization",CameraParameters::TRUE);
+ } else {
+ LOGD("VSTAB is disabled!!! \n");
+ params.set("vstab",CameraParameters::FALSE);
+ params.set("video-stabilization",CameraParameters::FALSE);
+ }
+
+ //params.dump();
+ gICamera->setParameters(params.flatten());
+ return 0;
+}
+
+void stopPreview() {
+ gICamera->stopPreview();
+ gCameraClient->setReleaser(NULL);
+ gICamera->disconnect();
+ gICamera.clear();
+ gCameraClient.clear();
+ gCameraService.clear();
+ destroyPreviewSurface();
+}
+
+void encodedBufferCallback(void* pBuffer, OMX_U32 nFilledLen, OMX_TICKS nTimeStamp) {
+ if (mOMXDecoder.get()) {
+ mOMXDecoder->AcceptEncodedBuffer(pBuffer, nFilledLen, nTimeStamp);
+ } else {
+ LOGE("\n\nDECODER IS NULL !!!!!!! \n\n");
+ }
+}
+
+void setFrameRate(sp<OMXEncoder> pOMXEncoder) {
+ sleep(8);
+ pOMXEncoder->mDebugFlags |= FPS_ENCODER;
+
+ // Changing the framerate in camera.
+ String8 param_str = gICamera->getParameters();
+ CameraParameters params(param_str);
+ LOGD("Setting new framerate: %d", gNewCameraFrameRate);
+ params.setPreviewFrameRate(gNewCameraFrameRate);
+ sprintf(mParamValue,"%u,%u", gNewCameraFrameRate*1000, gNewCameraFrameRate*1000);
+ params.set("preview-fps-range", mParamValue);
+ gICamera->setParameters(params.flatten());
+
+ // Changing the framerate in encoder.
+ pOMXEncoder->changeFrameRate(gNewCameraFrameRate);
+}
+
+void varyBitRate1(sp<OMXEncoder> pOMXEncoder) {
+ uint32_t currentBitRate = gMinEncoderBitRate;
+ uint32_t step = (gMaxEncoderBitRate - gMinEncoderBitRate) / 10;
+ while (currentBitRate <= gMaxEncoderBitRate) {
+ sleep(10);
+ pOMXEncoder->changeBitRate(currentBitRate);
+ currentBitRate += step;
+ }
+}
+
+
+void varyBitRate2(sp<OMXEncoder> pOMXEncoder) {
+ int32_t step = gMaxEncoderBitRate - gMinEncoderBitRate;
+ uint32_t currentBitRate = gMinEncoderBitRate;
+
+ int i = 1;
+ while (i <= 10) {
+ sleep(10);
+ pOMXEncoder->changeBitRate(currentBitRate);
+ currentBitRate += step;
+ step *= -1;
+ i++;
+ }
+}
+
+
+void varyBitRate(sp<OMXEncoder> pOMXEncoder) {
+ if ((gMinEncoderBitRate == 0) || (gMaxEncoderBitRate == 0)) return;
+
+ pOMXEncoder->mDebugFlags |= ENCODER_EFFECTIVE_BITRATE;
+
+ varyBitRate1(pOMXEncoder);
+ varyBitRate2(pOMXEncoder);
+}
+
+void varyFrameRate(sp<OMXEncoder> pOMXEncoder) {
+ for (int i = 7; i <= 30; i+=2) {
+ gNewCameraFrameRate = i;
+ setFrameRate(pOMXEncoder);
+ }
+ for (int i = 30; i >= 7; i-=2) {
+ gNewCameraFrameRate = i;
+ setFrameRate(pOMXEncoder);
+ }
+}
+
+void varyOrientation(sp<OMXEncoder> pOMXEncoder) {
+ //TODO : Check on the requirement and enhance to support this functionality
+}
+
+
+int test_DEFAULT_Frame() {
+ status_t err = 0;
+
+ if (gEnableLoopback) {
+ mOMXDecoder = new OMXDecoder(gPreviewWidth, gPreviewHeight, gCameraFrameRate);
+ mOMXDecoder->mDebugFlags = gDebugFlags;
+ err = mOMXDecoder->configure(gProfile, gLevel, gRefFrames);
+ if (err != 0) return -1;
+ err = mOMXDecoder->prepare();
+ if (err != 0) return -1;
+ }
+
+ configureCamera();
+
+ OMXClient omxclient;
+ CHECK_EQ(omxclient.connect(), (status_t)OK);
+ sp<IOMX> omx = omxclient.interface();
+ IOMX::node_id node = 0;
+ sp<OMXEncoderObserver> observer = new OMXEncoderObserver();
+ err = omx->allocateNode("OMX.TI.DUCATI1.VIDEO.H264E", observer, &node);
+ if (err != OK) {
+ LOGD("Failed to allocate OMX node!!");
+ return -1;
+ }
+
+ sp<OMXEncoder> pOMXEncoder = new OMXEncoder(omx, node, gCameraClient,
+ gPreviewWidth, gPreviewHeight, gCameraFrameRate, gEncoderBitRate, gRecordFileName, 0 /*SliceHeight*/);
+ observer->setCodec(pOMXEncoder);
+ pOMXEncoder->mDebugFlags = gDebugFlags;
+ pOMXEncoder->mOutputBufferCount = gEncoderOutputBufferCount;
+
+ if (gEnableLoopback) pOMXEncoder->setCallback(&encodedBufferCallback);
+
+ err = pOMXEncoder->configure(gProfile, gLevel, gRefFrames);
+ if (err != 0) return -1;
+ err = pOMXEncoder->prepare();
+ if (err != 0) return -1;
+
+ gICamera->startPreview();
+ sleep(SLEEP_AFTER_STARTING_PREVIEW);
+
+ gICamera->startRecording();
+ err = pOMXEncoder->start();
+ if (err != 0) return -1;
+
+ if (gEnableLoopback) {
+ err = mOMXDecoder->start();
+ if (err != 0) return -1;
+ }
+
+
+ if (gNewCameraFrameRate) setFrameRate(pOMXEncoder);
+ if (gMinEncoderBitRate != gMaxEncoderBitRate) varyBitRate(pOMXEncoder);
+ if (gVaryFrameRate) varyFrameRate(pOMXEncoder);
+ if (gVaryOrientation) varyOrientation(pOMXEncoder);
+
+ sleep(gDuration);
+
+ gICamera->stopRecording();
+ pOMXEncoder->stop();
+ pOMXEncoder->deinit();
+ stopPreview();
+
+ if (gEnableLoopback) {
+ mOMXDecoder->stop();
+ mOMXDecoder.clear();
+ }
+ pOMXEncoder.clear();
+ observer.clear();
+
+ return 0;
+}
+
+int test_DEFAULT_Slice() {
+ status_t err = 0;
+ if (gSliceHeight == 0) gSliceHeight = gPreviewHeight / 2;
+ if (gSliceHeight < 128) gSliceHeight = gPreviewHeight;
+
+ if (gEnableLoopback) {
+ mOMXDecoder = new OMXDecoder(gPreviewWidth, gPreviewHeight, gCameraFrameRate);
+ if (gEncoderOutputSliceSizeBytes || gEncoderOutputSliceSizeMB) {
+ mOMXDecoder->mDebugFlags = gDebugFlags | INPUT_OUTPUT_SLICE_MODE;
+ } else {
+ mOMXDecoder->mDebugFlags = gDebugFlags | INPUT_SLICE_MODE;
+ }
+ err = mOMXDecoder->configure(gProfile, gLevel, gRefFrames);
+ if (err != 0) return -1;
+ err = mOMXDecoder->prepare();
+ if (err != 0) return -1;
+ }
+
+ configureCamera();
+
+ OMXClient omxclient;
+ CHECK_EQ(omxclient.connect(), (status_t)OK);
+ sp<IOMX> omx = omxclient.interface();
+ IOMX::node_id node = 0;
+ sp<OMXEncoderObserver> observer = new OMXEncoderObserver();
+ err = omx->allocateNode("OMX.TI.DUCATI1.VIDEO.H264E", observer, &node);
+ if (err != OK) {
+ LOGD("Failed to allocate OMX node!!");
+ return -1;
+ }
+
+ sp<OMXEncoder> pOMXEncoder = new OMXEncoder(omx, node, gCameraClient, gPreviewWidth, gPreviewHeight, gCameraFrameRate, gEncoderBitRate, gRecordFileName, gSliceHeight);
+ observer->setCodec(pOMXEncoder);
+ pOMXEncoder->mDebugFlags = gDebugFlags;
+ if (gEnableLoopback) pOMXEncoder->setCallback(&encodedBufferCallback);
+ err = pOMXEncoder->configure(gProfile, gLevel, gRefFrames);
+ if (err != 0) return -1;
+
+ OMX_TI_COMPONENT_HANDLE compHandle;
+ INIT_OMX_STRUCT(&compHandle, OMX_TI_COMPONENT_HANDLE);
+ err = omx->getParameter(node, (OMX_INDEXTYPE)OMX_TI_IndexComponentHandle, &compHandle, sizeof(compHandle));
+ if (err != OK) {
+ LOGD("get OMX_TI_IndexComponentHandle failed : %d", err);
+ return -1;
+ }
+
+ // Set up the Tunnel
+ String8 param_str = gICamera->getParameters();
+ CameraParameters params(param_str);
+ sprintf(mParamValue,"%u", gSliceHeight);
+ params.set("encoder_slice_height", mParamValue);
+ sprintf(mParamValue,"%u", (int)compHandle.pHandle);
+ params.set("encoder_handle", mParamValue);
+ gICamera->setParameters(params.flatten());
+
+ err = pOMXEncoder->prepare();
+ if (err != 0) return -1;
+
+ gICamera->sendCommand(CAMERA_CMD_PREVIEW_INITIALIZATION, 0, 0);
+
+ if (gEncoderOutputSliceSizeBytes || gEncoderOutputSliceSizeMB) {
+ sleep(SLEEP_AFTER_STARTING_PREVIEW);
+ //Setting the Encoder output slice mode
+ err = pOMXEncoder->setEncoderOutputSlice(gPreviewHeight, gPreviewWidth, gEncoderOutputSliceSizeBytes, gEncoderOutputSliceSizeMB);
+ if (err != 0) {
+ LOGD("pOMXEncoder->setEncoderOutputSlice error \n");
+ return -1;
+ }
+ }
+
+ //Moving to Executing State
+ err = pOMXEncoder->start();
+ if (err != 0) return -1;
+
+ err = gICamera->startPreview();
+ if (err != 0) return -1;
+
+ if (gEnableLoopback) err = mOMXDecoder->start();
+ if (err != 0) return -1;
+
+
+ if (gNewCameraFrameRate) setFrameRate(pOMXEncoder);
+ if (gMinEncoderBitRate != gMaxEncoderBitRate) varyBitRate(pOMXEncoder);
+ if (gVaryFrameRate) varyFrameRate(pOMXEncoder);
+
+
+ sleep(gDuration);
+ //camera goes to idle
+ gICamera->sendCommand(CAMERA_CMD_PREVIEW_DEINITIALIZATION, 0, 0);
+ //encoder goes to idle
+ pOMXEncoder->stop();
+ //delay for state changes
+ usleep (100000);
+ //camera goes to loaded
+ stopPreview();
+ //encoder goes to loaded
+ pOMXEncoder->deinit();
+
+ if (gEnableLoopback) {
+ mOMXDecoder->stop();
+ mOMXDecoder.clear();
+ }
+ pOMXEncoder.clear();
+ //observer.clear();
+
+ return 0;
+}
+
+// TODO: One should not be required to release the camera and destroy the node
+// everytime we start and stop or change resolution or some other parameter.
+// Presently, this code does not work as is...
+int test_Robustness() {
+ status_t err = 0;
+ int loopCnt = 0;
+ gDuration = 5;
+
+ configureCamera();
+ gICamera->startPreview();
+ sleep(SLEEP_AFTER_STARTING_PREVIEW);
+
+ OMXClient omxclient;
+ CHECK_EQ(omxclient.connect(), (status_t)OK);
+ sp<IOMX> omx = omxclient.interface();
+ IOMX::node_id node = 0;
+ sp<OMXEncoderObserver> observer = new OMXEncoderObserver();
+ err = omx->allocateNode("OMX.TI.DUCATI1.VIDEO.H264E", observer, &node);
+ if (err != OK) {
+ LOGD("Failed to allocate OMX node!!");
+ return -1;
+ }
+
+ sp<OMXEncoder> pOMXEncoder = new OMXEncoder(omx, node, gCameraClient, gPreviewWidth, gPreviewHeight, gCameraFrameRate, gEncoderBitRate, gRecordFileName, 0 /*SliceHeight*/);
+ observer->setCodec(pOMXEncoder);
+
+
+ while(loopCnt < 3) {
+ sleep(SLEEP_AFTER_STARTING_PREVIEW);
+
+ pOMXEncoder->resetParameters(gPreviewWidth, gPreviewHeight, gCameraFrameRate, gEncoderBitRate, gRecordFileName, 0 /*SliceHeight*/);
+ pOMXEncoder->mDebugFlags = gDebugFlags;
+ pOMXEncoder->mOutputBufferCount = gEncoderOutputBufferCount;
+
+ if (gEnableLoopback) pOMXEncoder->setCallback(&encodedBufferCallback);
+
+ err = pOMXEncoder->configure(gProfile, gLevel, gRefFrames);
+ if (err != 0) return -1;
+ err = pOMXEncoder->prepare();
+ if (err != 0) return -1;
+
+
+ gICamera->startRecording();
+ err = pOMXEncoder->start();
+ if (err != 0) return -1;
+
+
+ sleep(gDuration);
+
+ gICamera->stopRecording();
+ pOMXEncoder->stop();
+ pOMXEncoder->deinit();
+
+ loopCnt++;
+ LOGD("#######################################################################");
+ LOGD("#######################################################################");
+ }
+
+ stopPreview();
+
+ return 0;
+}
+
+// TODO: Combine these 2 tests into one. Reuse.
+int test_Frame_Robustness() {
+ const Configuration configdata[] = {
+ { 160, 120 },
+ { 320, 240 },
+ { 640, 480 },
+ { 1280, 720 },
+ };
+
+ for (int i = 0, j = 0; i < 4000; i++) {
+ gPreviewWidth = configdata[j].width;
+ gPreviewHeight = configdata[j].height;
+ LOGD("##################################################################");
+ LOGD("##################### ITERATION %d : %d x %d ###################", i, gPreviewWidth, gPreviewHeight);
+ LOGD("##################################################################");
+ sleep(1);
+
+ test_DEFAULT_Frame();
+ j++;
+ j = j % (sizeof(configdata)/sizeof(Configuration));
+ }
+ return 0;
+
+}
+
+int test_Slice_Robustness() {
+ const Configuration configdata[] = {
+// { 160, 120 }, // If this resolution is included, it results in random errors being thrown. Recall that the min slice height is 128 which is more than 120.
+ { 320, 240 },
+ { 640, 480 },
+ { 1280, 720 },
+ };
+
+ for (int i = 0, j = 0; i < 4000; i++) {
+ gPreviewWidth = configdata[j].width;
+ gPreviewHeight = configdata[j].height;
+ LOGD("##################################################################");
+ LOGD("##################### ITERATION %d : %d x %d ###################", i, gPreviewWidth, gPreviewHeight);
+ LOGD("##################################################################");
+ sleep(1);
+
+ test_DEFAULT_Slice();
+ j++;
+ j = j % (sizeof(configdata)/sizeof(Configuration));
+ }
+ return 0;
+
+}
+
+
+void printUsage() {
+ printf("\n\nApplication for testing VTC using IOMX");
+ printf("\n\nIn this application:");
+ printf("\n\t- Camera Preview is started.");
+ printf("\n\t- Preview Frames are sent to encoder for encoding.");
+ printf("\n\t- The encoded frames are then sent to the decoder for decoding.");
+ printf("\n\t- The decoded frames are then rendered along side the preview window.");
+ printf("\n\nThe application can be run in frame mode or slice mode.");
+
+ printf("\n\n\nUsage: /system/bin/VTCLoopbackTest <Testcase_ID> <options>\n");
+
+ printf("\n\n\nTest Case ID can be any of the following");
+ printf("\n1 - Default test case. Frame Mode. No Loopback. Does not require any parameters to be set.");
+ printf("\n2 - Slice Mode. No Loopback. Does not require any parameters to be set.");
+ printf("\n3 - Test Robustness. Frame Mode.");
+ printf("\n4 - Test Robustness. Slice Mode.");
+
+ printf("\n\n\nAvailable Options:");
+ printf("\n-t: Test case ID. Default = %d", gTestcaseID);
+ printf("\n-n: Record Filename(/mnt/sdcard/video_0.264) is appended with this number. Default = %d", gFilename);
+ printf("\n-w: Preview/Record Width. Default = %d", gPreviewWidth);
+ printf("\n-e: Preview/Record Height. Default = %d", gPreviewHeight);
+ printf("\n-d: Recording time in secs. Default = %d seconds", gDuration);
+ printf("\n-f: Framerate. Default = %d", gCameraFrameRate);
+ printf("\n-b: Bitrate. Default = %d", gEncoderBitRate);
+ printf("\n-s: Slice Height in # of lines. Default = %d", gSliceHeight);
+ printf("\n-g: Debug Options. Refer to source for usage.");
+ printf("\n-c: Camera Index. Default = %d", gCameraIndex);
+ printf("\n-p: Print FPS. 4 = dont write to file. Print Encoder FPS");
+ printf("\n-o: Encoder Output Buffer Count. Default = %d", gEncoderOutputBufferCount);
+ printf("\n-l: Enable loopback. Default = %d", gEnableLoopback);
+ printf("\n-j: Change to this framerate at runtime after 8 seconds. Default = %d", gNewCameraFrameRate);
+ printf("\n-v: VNF/VSTAB Option. 1-Enable VNF, 2-Enable VSTAB, 3-Enable Both, Default = %d", gEnableAlgo);
+ printf("\n-i: Min bitrate. Vary the bitrate at run time between min and max values");
+ printf("\n-a: Max bitrate. Vary the bitrate at run time between min and max values");
+ printf("\n-x: Vary framerate between 7 and 30 at run time");
+ printf("\n-r: Test Rotation. Not supported yet.");
+ printf("\n-h: Print help menu");
+
+ printf("\n\n\nSample Commands:");
+ printf("\n\nTesting Frame mode. Loopback. 720p");
+ printf("\nVTCLoopbackTest -t 1 -d 10 -w 1280 -e 720 -b 2000000 -l 1");
+ printf("\n\nTesting Slice mode. Loopback. 720p");
+ printf("\nVTCLoopbackTest -t 2 -d 10 -w 1280 -e 720 -b 2000000 -l 1");
+ printf("\n\nTesting Robustness. Frame mode.");
+ printf("\nVTCLoopbackTest -t 3 -l 1");
+ printf("\n\nTesting Robustness. Slice mode.");
+ printf("\nVTCLoopbackTest -t 4 -l 1");
+ printf("\n\nVary Framerate at runtime between 7 and 30");
+ printf("\nVTCLoopbackTest -t 1 -x 1 -g 2");
+ printf("\n\nTesting Bitrate");
+ printf("\nVTCLoopbackTest -t 1 -w 1280 -e 720 -b 2000000 -i 1000000 -a 3000000 -g 64");
+ printf("\n\n\n");
+
+}
+
+int main (int argc, char* argv[]) {
+ sp<ProcessState> proc(ProcessState::self());
+ ProcessState::self()->startThreadPool();
+
+ int opt;
+ const char* const short_options = "a:g:n:w:e:d:b:f:s:c:p:t:o:y:m:l:j:i:v:x:r:h";
+ const struct option long_options[] = {
+ {"debug_flags", 1, NULL, 'g'},
+ {"record_filename", 1, NULL, 'n'},
+ {"width", 1, NULL, 'w'},
+ {"height", 1, NULL, 'e'},
+ {"gDuration", 1, NULL, 'd'},
+ {"bitrate", 1, NULL, 'b'},
+ {"min_bitrate", 1, NULL, 'i'},
+ {"max_bitrate", 1, NULL, 'a'},
+ {"framerate", 1, NULL, 'f'},
+ {"sliceheight", 1, NULL, 's'},
+ {"camera_index", 1, NULL, 'c'},
+ {"print_fps", 1, NULL, 'p'},
+ {"testcase_id", 1, NULL, 't'},
+ {"out_buff_cnt", 1, NULL, 'o'},
+ {"encoder_slicesize_bytes", 1, NULL, 'y'},
+ {"encoder_slicesize_mb", 1, NULL, 'm'},
+ {"enable_loopback", 1, NULL, 'l'},
+ {"new_framerate", 1, NULL, 'j'},
+ {"vary_framerate", 1, NULL, 'x'},
+ {"vary_rotation", 1, NULL, 'r'},
+ {"algo", 1, NULL, 'v'},
+ {"help", 1, NULL, 'h'},
+ {NULL, 0, NULL, 0}
+ };
+
+ while((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
+ switch(opt) {
+ case 'h':
+ printUsage();
+ return 0;
+ case 'g':
+ gDebugFlags = atoi(optarg);
+ break;
+ case 'l':
+ gEnableLoopback = atoi(optarg);
+ break;
+ case 'x':
+ gVaryFrameRate = atoi(optarg);
+ break;
+ case 'r':
+ gVaryOrientation = atoi(optarg);
+ break;
+ case 'o':
+ gEncoderOutputBufferCount = atoi(optarg);
+ if (gEncoderOutputBufferCount > ENCODER_MAX_BUFFER_COUNT)
+ gEncoderOutputBufferCount = ENCODER_MAX_BUFFER_COUNT;
+ break;
+ case 'y':
+ gEncoderOutputSliceSizeBytes = atoi(optarg);
+ break;
+ case 'm':
+ gEncoderOutputSliceSizeMB = atoi(optarg);
+ break;
+ case 't':
+ gTestcaseID = atoi(optarg);
+ break;
+ case 'n':
+ gFilename = atoi(optarg);
+ break;
+ case 'w':
+ gPreviewWidth = atoi(optarg);
+ break;
+ case 'e':
+ gPreviewHeight = atoi(optarg);
+ break;
+ case 'd':
+ gDuration = atoi(optarg);
+ break;
+ case 'b':
+ gEncoderBitRate = atoi(optarg);
+ break;
+ case 'i':
+ gMinEncoderBitRate = atoi(optarg);
+ break;
+ case 'a':
+ gMaxEncoderBitRate = atoi(optarg);
+ break;
+ case 'f':
+ gCameraFrameRate = atoi(optarg);
+ break;
+ case 'j':
+ gNewCameraFrameRate = atoi(optarg);
+ break;
+ case 's':
+ gSliceHeight = atoi(optarg);
+ break;
+ case 'c':
+ gCameraIndex = atoi(optarg);
+ break;
+ case 'v':
+ gEnableAlgo = atoi(optarg);
+ break;
+ case ':':
+ LOGE("\nError - Option `%c' needs a value\n\n", optopt);
+ return -1;
+ case '?':
+ LOGE("\nError - No such option: `%c'\n\n", optopt);
+ return -1;
+ }
+ }
+
+ if (argc == 1) printUsage();
+ if (gVaryFrameRate) gCameraFrameRate = 30; // Framerate must be initialized to 30.
+
+ sprintf(gRecordFileName, "/mnt/sdcard/video_%d.264", gFilename);
+ LOGI("\n\nRecorded Output is stored in %s\n\n", gRecordFileName);
+
+ system("setprop debug.vfr.enable 0");
+
+ TestFunctions[gTestcaseID]();
+ return 0;
+}
+
diff --git a/test/VTC/VTCLoopback.h b/test/VTC/VTCLoopback.h
new file mode 100644
index 0000000..ff3fe23
--- /dev/null
+++ b/test/VTC/VTCLoopback.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef VTC_LOOPBACK_H
+#define VTC_LOOPBACK_H
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <semaphore.h>
+#include <pthread.h>
+
+#include <binder/MemoryDealer.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <system/audio.h>
+#include <utils/List.h>
+#include <cutils/log.h>
+#include <OMX_Component.h>
+#include <camera/Camera.h>
+#include <camera/ICamera.h>
+#include <camera/ICameraClient.h>
+#include <camera/ICameraService.h>
+#include <media/mediaplayer.h>
+#include <media/mediarecorder.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/CameraSource.h>
+#include <media/stagefright/MetaData.h>
+
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/ISurface.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include "../../../domx/omx_core/inc/OMX_TI_Index.h" // for OMX_TI_VIDEO_PARAM_FRAMEDATACONTENTTYPE
+#include "../../../domx/omx_core/inc/OMX_TI_Video.h" // for OMX_VIDEO_PARAM_DATASYNCMODETYPE
+#include "../../../domx/omx_core/inc/OMX_TI_Common.h" // for OMX_TI_COMPONENT_HANDLE
+#include "../../../domx/omx_core/inc/OMX_TI_IVCommon.h"// for OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
+#include "MessageQueue.h"
+
+
+#define SLEEP_AFTER_STARTING_PREVIEW 2
+#define WIDTH 640
+#define HEIGHT 480
+#define BITRATE 5000000 // 5 mbps
+#define INPUT_PORT 0
+#define OUTPUT_PORT 1
+#define TWO_SECOND 1000000000ll // 1000,000,000 nsec = 1sec
+
+#define FPS_CAMERA 0x1
+#define FPS_ENCODER 0X2
+#define FPS_DECODER 0x4
+#define DEBUG_DUMP_CAMERA_TIMESTAMP 0x8
+#define DEBUG_DUMP_ENCODER_TIMESTAMP 0x10
+#define ENCODER_EFFECTIVE_BITRATE 0x20
+#define ENCODER_NO_FILE_WRTIE 0x40
+#define INPUT_SLICE_MODE 0x80
+#define INPUT_OUTPUT_SLICE_MODE 0x100
+#define ENCODER_LATENCY 0x200
+#define DECODER_LATENCY 0x400
+
+#define ENCODER_MAX_BUFFER_COUNT 10
+#define NUM_PORTS 2
+
+#define LOG_FUNCTION_NAME_ENTRY LOGV("\n ENTER %s \n", __FUNCTION__);
+#define LOG_FUNCTION_NAME_EXIT LOGV("\n EXIT %s \n", __FUNCTION__);
+
+#define INIT_OMX_STRUCT(_s_, _name_) \
+ memset((_s_), 0x0, sizeof(_name_)); \
+ (_s_)->nSize = sizeof(_name_); \
+ (_s_)->nVersion.s.nVersionMajor = 0x1; \
+ (_s_)->nVersion.s.nVersionMinor = 0x1; \
+ (_s_)->nVersion.s.nRevision = 0x0; \
+ (_s_)->nVersion.s.nStep = 0x0
+
+using namespace android;
+
+
+
+class MyCameraClient : public BnCameraClient {
+public:
+ virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {}
+ virtual void dataCallback(int32_t msgType, const sp<IMemory>& data,
+ camera_frame_metadata_t *metadata){}
+ virtual void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& data);
+
+ MyCameraClient();
+ ~MyCameraClient() {}
+ sp<IMemory> getCameraPayload(int64_t& frameTime);
+ void encoderReady() { encoder_is_ready = 1; }
+ void encoderNotReady() { encoder_is_ready = 0; }
+ void releaseBuffer(sp<IMemory> data)
+ { if (mReleaser != NULL) { mReleaser->releaseRecordingFrame(data); } }
+ void setReleaser(ICamera *releaser) {
+ mReleaser = releaser;
+ }
+
+private:
+
+ void putCameraPayload(sp<IMemory> payload, int64_t frameTime);
+ int encoder_is_ready;
+ ICamera *mReleaser;
+ List<sp<IMemory> > cameraPayloadQueue;
+ List<int64_t> frameTimeQueue;
+ Mutex cameraPayloadQueueMutex;
+ Condition cameraPayloadWait;
+ int cameraPayloadWaitFlag;
+
+};
+
+void dump_video_port_values(OMX_PARAM_PORTDEFINITIONTYPE& def);
+const char *OMXStateName(OMX_STATETYPE state);
+
+
+#endif
+
diff --git a/test/VTC/VTCTestApp.cpp b/test/VTC/VTCTestApp.cpp
index b64db55..b7cb7ff 100644
--- a/test/VTC/VTCTestApp.cpp
+++ b/test/VTC/VTCTestApp.cpp
@@ -235,8 +235,7 @@ int getMediaserverInfo(int *PID, int *VSIZE){
return 0;
}
-int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t * mutex, int waitTimeInMilliSecs)
-{
+int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t * mutex, int waitTimeInMilliSecs) {
if (waitTimeInMilliSecs == 0)
{
return pthread_cond_wait(cond, mutex);
@@ -245,9 +244,11 @@ int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t * mutex, int
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
- if (waitTimeInMilliSecs >= 1000) // > 1 sec
+ if (waitTimeInMilliSecs >= 1000) { // > 1 sec
ts.tv_sec += (waitTimeInMilliSecs/1000);
- else ts.tv_nsec += waitTimeInMilliSecs * 1000000;
+ } else {
+ ts.tv_nsec += waitTimeInMilliSecs * 1000000;
+ }
return pthread_cond_timedwait(cond, mutex, &ts);
}
@@ -335,9 +336,9 @@ int createPreviewSurface() {
}
surfaceControl = client->createSurface(0,
- cameraSurfaceWidth,
- cameraSurfaceHeight,
- HAL_PIXEL_FORMAT_RGB_565);
+ cameraSurfaceWidth,
+ cameraSurfaceHeight,
+ HAL_PIXEL_FORMAT_RGB_565);
previewSurface = surfaceControl->getSurface();
@@ -552,8 +553,7 @@ void stopPreview() {
destroyPreviewSurface();
}
-int test_DEFAULT()
-{
+int test_DEFAULT() {
startPreview();
startRecording();
sleep(mDuration);
@@ -562,9 +562,7 @@ int test_DEFAULT()
return 0;
}
-
-int test_InsertIDRFrames()
-{
+int test_InsertIDRFrames() {
status_t err = 0;
mIFramesIntervalSec = 0;
startPreview();
@@ -589,16 +587,14 @@ int test_InsertIDRFrames()
}
-int test_MaxNALSize()
-{
+int test_MaxNALSize() {
status_t err = 0;
- if (mIsSizeInBytes){
+ if (mIsSizeInBytes) {
//Testing size base on bytes
CHECK(mPreviewWidth > 320);
CHECK(mSliceSizeBytes >= 256);
- }
- else{
+ } else {
//Testing size base on MB
CHECK(mSliceSizeMB > 6);
CHECK(mSliceSizeMB < (((mPreviewWidth+15)>> 4) * ((mPreviewHeight+15)>> 4)));
@@ -620,14 +616,13 @@ int test_MaxNALSize()
startPreview();
startRecording();
- if (mIsSizeInBytes){
+ if (mIsSizeInBytes) {
sprintf(mParamValue,"video-param-nalsize-bytes=%u", mSliceSizeBytes);
String8 param(mParamValue);
err = recorder->setParameters(param);
if (err != OK) return -1;
LOGI("\n Set the Slice Size in bytes.\n");
- }
- else{
+ } else {
sprintf(mParamValue,"video-param-nalsize-macroblocks=%u", mSliceSizeMB);
String8 param(mParamValue);
err = recorder->setParameters(param);
@@ -651,8 +646,7 @@ int test_MaxNALSize()
}
-int test_ChangeBitRate()
-{
+int test_ChangeBitRate() {
startPreview();
startRecording();
sleep(mDuration/2);
@@ -670,8 +664,7 @@ int test_ChangeBitRate()
}
-int test_ChangeFrameRate()
-{
+int test_ChangeFrameRate() {
startPreview();
startRecording();
sleep(mDuration/2);
@@ -697,16 +690,14 @@ int test_ChangeFrameRate()
return 0;
}
-int test_PlaybackAndRecord_sidebyside()
-{
+int test_PlaybackAndRecord_sidebyside() {
playbackComposerClient = new SurfaceComposerClient();
CHECK_EQ(playbackComposerClient->initCheck(), (status_t)OK);
int panelwidth = playbackComposerClient->getDisplayWidth(0);
int panelheight = playbackComposerClient->getDisplayHeight(0);
LOGD("Panel WxH = %d x %d", panelwidth, panelheight);
- if (panelwidth < panelheight) //Portrait Phone
- {
+ if (panelwidth < panelheight) {//Portrait Phone
LOGD("\nPortrait Device\n");
playbackSurfaceWidth = panelwidth;
playbackSurfaceHeight = panelheight/2;
@@ -717,9 +708,7 @@ int test_PlaybackAndRecord_sidebyside()
cameraWinY = playbackSurfaceHeight;
cameraSurfaceWidth = panelwidth;
cameraSurfaceHeight = panelheight/2;
- }
- else // Landscape
- {
+ } else {// Landscape
LOGD("\n Landscape Device\n");
playbackSurfaceWidth = panelwidth/2;
playbackSurfaceHeight = panelheight;
@@ -755,16 +744,14 @@ int test_PlaybackAndRecord_sidebyside()
}
-int test_PlaybackAndRecord_PIP()
-{
+int test_PlaybackAndRecord_PIP() {
playbackComposerClient = new SurfaceComposerClient();
CHECK_EQ(playbackComposerClient->initCheck(), (status_t)OK);
uint32_t panelwidth = playbackComposerClient->getDisplayWidth(0);
uint32_t panelheight = playbackComposerClient->getDisplayHeight(0);
LOGD("Panel WxH = %d x %d", panelwidth, panelheight);
- if (panelwidth < panelheight) //Portrait Phone
- {
+ if (panelwidth < panelheight) {//Portrait Phone
LOGD("\nPortrait Device\n");
playbackSurfaceWidth = panelwidth;
playbackSurfaceHeight = panelheight;
@@ -775,9 +762,7 @@ int test_PlaybackAndRecord_PIP()
cameraSurfaceHeight = panelheight/4;
cameraWinX = (panelwidth - cameraSurfaceWidth) / 2;
cameraWinY = 0;
- }
- else // Landscape
- {
+ } else { // Landscape
LOGD("\n Landscape Device\n");
playbackSurfaceWidth = panelwidth;
playbackSurfaceHeight = panelheight;
@@ -816,8 +801,7 @@ int test_PlaybackAndRecord_PIP()
client->openGlobalTransaction();
surfaceControl->hide();
client->closeGlobalTransaction();
- }
- else{
+ } else {
client->openGlobalTransaction();
surfaceControl->show();
client->closeGlobalTransaction();
@@ -843,8 +827,7 @@ int test_PlaybackOnly()
int panelwidth = playbackComposerClient->getDisplayWidth(0);
int panelheight = playbackComposerClient->getDisplayHeight(0);
LOGD("Panel WxH = %d x %d", panelwidth, panelheight);
- if (panelwidth < panelheight) //Portrait Phone
- {
+ if (panelwidth < panelheight) {//Portrait Phone
LOGD("\nPortrait Device\n");
playbackSurfaceWidth = panelwidth;
playbackSurfaceHeight = panelheight/2;
@@ -855,9 +838,7 @@ int test_PlaybackOnly()
cameraWinY = playbackSurfaceHeight;
cameraSurfaceWidth = panelwidth;
cameraSurfaceHeight = panelheight/2;
- }
- else // Landscape
- {
+ } else {// Landscape
LOGD("\n Landscape Device\n");
playbackSurfaceWidth = panelwidth;
playbackSurfaceHeight = panelheight;
@@ -924,8 +905,7 @@ void updatePassRate(int test_status, bool verifyRecordedClip) {
mStartMemory = endMemory; //I shouldn't be doing this right??
}
-int test_Robust()
-{
+int test_Robust() {
int status = 0;
uint32_t cyclesCompleted = 0;
getMediaserverInfo(&mMediaServerPID, &mStartMemory);
@@ -1375,8 +1355,7 @@ int test_ALL()
}
-void printUsage()
-{
+void printUsage() {
printf("\n\nApplication for testing VTC requirements");
printf("\nUsage: /system/bin/VTCTestApp test_case_id");
printf("\n\n\nTest Case ID can be any of the following");
@@ -1412,8 +1391,7 @@ void printUsage()
}
-int main (int argc, char* argv[])
-{
+int main (int argc, char* argv[]) {
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
pthread_mutex_init(&mMutex, NULL);