895 lines
30 KiB
C++
895 lines
30 KiB
C++
/*
|
|
* 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"
|
|
|
|
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;
|
|
VTC_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;
|
|
|
|
VTC_LOGD("--------------------------------------------------------------------------------");
|
|
VTC_LOGD("nPortIndex:%d eDir:%s\n",(int)def.nPortIndex,(def.eDir == OMX_DirInput)?"OMX_DirInput":"OMX_DirOutput");
|
|
VTC_LOGD("BufferCountActual:%d BufferCountMin:%d nBufferSize:%d\n", (int)def.nBufferCountActual, (int)def.nBufferCountMin, (int)def.nBufferSize);
|
|
VTC_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);
|
|
|
|
VTC_LOGD("cMIMEType:%s pNativeRender:%p\n",(def.format.video.cMIMEType)?(def.format.video.cMIMEType):"NULL",def.format.video.pNativeRender);
|
|
VTC_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);
|
|
VTC_LOGD("nBitrate:%d xFramerate:%d bFlagErrorConcealment:%s",
|
|
(int)def.format.video.nBitrate, (int)def.format.video.xFramerate, (def.format.video.bFlagErrorConcealment)?"TRUE":"FALSE");
|
|
VTC_LOGD("eCompressionFormat:0x%x eColorFormat:0x%x pNativeWindow:%p",
|
|
(def.format.video.eCompressionFormat),
|
|
(def.format.video.eColorFormat), def.format.video.pNativeWindow);
|
|
VTC_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) {
|
|
//VTC_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);
|
|
//VTC_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) VTC_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;
|
|
VTC_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) {
|
|
VTC_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;
|
|
//VTC_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);
|
|
|
|
#ifdef ANDROID_API_JB_MR1_OR_LATER
|
|
DisplayInfo displayInfo;
|
|
gSurfaceComposerClient->getDisplayInfo(0, &displayInfo);
|
|
int gCameraSurfaceWidth = displayInfo.w;
|
|
int gCameraSurfaceHeight = displayInfo.h;
|
|
#else
|
|
gCameraSurfaceWidth = gSurfaceComposerClient->getDisplayWidth(0);
|
|
gCameraSurfaceHeight = gSurfaceComposerClient->getDisplayHeight(0);
|
|
#endif
|
|
|
|
#ifdef ANDROID_API_JB_MR1_OR_LATER
|
|
gSurfaceControl = gSurfaceComposerClient->createSurface(String8(),
|
|
gCameraSurfaceWidth,
|
|
gCameraSurfaceHeight,
|
|
HAL_PIXEL_FORMAT_RGB_565);
|
|
#else
|
|
gSurfaceControl = gSurfaceComposerClient->createSurface(0,
|
|
gCameraSurfaceWidth,
|
|
gCameraSurfaceHeight,
|
|
HAL_PIXEL_FORMAT_RGB_565);
|
|
#endif
|
|
|
|
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;
|
|
VTC_LOGD("\n\n\n========= Camera Busy. So relax and retry. ===========\n\n\n");
|
|
sleep(1);
|
|
i++;
|
|
} while (i < 10);
|
|
|
|
if (gICamera == NULL) return -1;
|
|
|
|
VTC_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
|
|
VTC_LOGD("VNF is enabled!!! \n");
|
|
params.set("vnf", CameraParameters::TRUE);
|
|
} else {
|
|
VTC_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
|
|
VTC_LOGD("VSTAB is enabled!!! \n");
|
|
params.set("vstab",CameraParameters::TRUE);
|
|
params.set("video-stabilization",CameraParameters::TRUE);
|
|
} else {
|
|
VTC_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 {
|
|
VTC_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);
|
|
VTC_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) {
|
|
VTC_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) {
|
|
VTC_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) {
|
|
VTC_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) {
|
|
VTC_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) {
|
|
VTC_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++;
|
|
VTC_LOGD("#######################################################################");
|
|
VTC_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;
|
|
VTC_LOGD("##################################################################");
|
|
VTC_LOGD("##################### ITERATION %d : %d x %d ###################", i, gPreviewWidth, gPreviewHeight);
|
|
VTC_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;
|
|
VTC_LOGD("##################################################################");
|
|
VTC_LOGD("##################### ITERATION %d : %d x %d ###################", i, gPreviewWidth, gPreviewHeight);
|
|
VTC_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 ':':
|
|
VTC_LOGE("\nError - Option `%c' needs a value\n\n", optopt);
|
|
return -1;
|
|
case '?':
|
|
VTC_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);
|
|
VTC_LOGI("\n\nRecorded Output is stored in %s\n\n", gRecordFileName);
|
|
|
|
system("setprop debug.vfr.enable 0");
|
|
|
|
TestFunctions[gTestcaseID]();
|
|
return 0;
|
|
}
|
|
|