#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 <string.h>
#include <climits>
#include <math.h>
#include <gui/GLConsumer.h>
#include <gui/Surface.h>
#include <ui/GraphicBuffer.h>
#include <ui/GraphicBufferMapper.h>
#include <camera/Camera.h>
#include <camera/ICamera.h>
#include <media/mediarecorder.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <camera/CameraParameters.h>
#include <camera/ShotParameters.h>
#include <camera/CameraMetadata.h>
#include <system/audio.h>
#include <system/camera.h>
#include <cutils/memory.h>
#include <utils/Log.h>
#include <sys/wait.h>
#include "camera_test.h"
#include "camera_test_surfacetexture.h"
#define ASSERT(X) \
do { \
if(!(X)) { \
printf("error: %s():%d", __FUNCTION__, __LINE__); \
return; \
} \
} while(0);
#define ALIGN_DOWN(x, n) ((x) & (~((n) - 1)))
#define ALIGN_UP(x, n) ((((x) + (n) - 1)) & (~((n) - 1)))
#define ALIGN_WIDTH 32 // Should be 32...but the calculated dimension causes an ion crash
#define ALIGN_HEIGHT 2 // Should be 2...but the calculated dimension causes an ion crash
//temporarily define format here
#define HAL_PIXEL_FORMAT_TI_NV12 0x100
#define HAL_PIXEL_FORMAT_TI_Y8 0x103
#define HAL_PIXEL_FORMAT_TI_Y16 0x104
#define HAL_PIXEL_FORMAT_TI_UYVY 0x105
using namespace android;
static EGLint getSurfaceWidth() {
return 512;
}
static EGLint getSurfaceHeight() {
return 512;
}
static size_t calcBufSize(int format, int width, int height)
{
int buf_size;
switch (format) {
case HAL_PIXEL_FORMAT_TI_NV12:
buf_size = width * height * 3 /2;
break;
case HAL_PIXEL_FORMAT_TI_Y16:
case HAL_PIXEL_FORMAT_TI_UYVY:
buf_size = width * height * 2;
break;
// add more formats later
default:
buf_size = width * height * 3 /2;
break;
}
return buf_size;
}
static unsigned int calcOffset(int format, unsigned int width, unsigned int top, unsigned int left)
{
unsigned int bpp;
switch (format) {
case HAL_PIXEL_FORMAT_TI_NV12:
bpp = 1;
break;
case HAL_PIXEL_FORMAT_TI_UYVY:
case HAL_PIXEL_FORMAT_TI_Y16:
bpp = 2;
break;
// add more formats later
default:
bpp = 1;
break;
}
return top * width + left * bpp;
}
static int getHalPixFormat(const char *format)
{
int pixformat = HAL_PIXEL_FORMAT_TI_NV12;
if ( NULL != format ) {
if ( strcmp(format, CameraParameters::PIXEL_FORMAT_BAYER_RGGB) == 0 ) {
pixformat = HAL_PIXEL_FORMAT_TI_Y16;
} else if ( strcmp(format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0 ) {
pixformat = HAL_PIXEL_FORMAT_TI_NV12;
} else if ( strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422I) == 0 ) {
pixformat = HAL_PIXEL_FORMAT_TI_UYVY;
} else {
pixformat = HAL_PIXEL_FORMAT_TI_NV12;
}
}
return pixformat;
}
static int getUsageFromANW(int format)
{
int usage = GRALLOC_USAGE_SW_READ_RARELY |
GRALLOC_USAGE_SW_WRITE_NEVER;
switch (format) {
case HAL_PIXEL_FORMAT_TI_NV12:
case HAL_PIXEL_FORMAT_TI_Y16:
// This usage flag indicates to gralloc we want the
// buffers to come from system heap
usage |= GRALLOC_USAGE_PRIVATE_0;
break;
default:
// No special flags needed
break;
}
return usage;
}
static status_t writeCroppedNV12(unsigned int offset,
unsigned int stride,
unsigned int bufWidth,
unsigned int bufHeight,
const Rect &crop,
int fd,
unsigned char *buffer)
{
unsigned char *luma = NULL, *chroma = NULL, *src = NULL;
unsigned int uvoffset;
int write_size;
if (!buffer || !crop.isValid()) {
return BAD_VALUE;
}
src = buffer;
// offset to beginning of uv plane
uvoffset = stride * bufHeight;
// offset to beginning of valid region of uv plane
uvoffset += (offset - (offset % stride)) / 2 + (offset % stride);
// start of valid luma region
luma = src + offset;
// start of valid chroma region
chroma = src + uvoffset;
// write luma line x line
unsigned int height = crop.height();
unsigned int width = crop.width();
write_size = width;
for (unsigned int i = 0; i < height; i++) {
if (write_size != write(fd, luma, width)) {
printf("Bad Write error (%d)%s\n",
errno, strerror(errno));
return UNKNOWN_ERROR;
}
luma += stride;
}
// write chroma line x line
height /= 2;
write_size = width;
for (unsigned int i = 0; i < height; i++) {
if (write_size != write(fd, chroma, width)) {
printf("Bad Write error (%d)%s\n",
errno, strerror(errno));
return UNKNOWN_ERROR;
}
chroma += stride;
}
return NO_ERROR;
}
static status_t writeCroppedUYVY(unsigned int offset,
unsigned int stride,
unsigned int bufWidth,
unsigned int bufHeight,
const Rect &crop,
int fd,
unsigned char *buffer)
{
unsigned char *src = NULL;
int write_size;
if (!buffer) {
return BAD_VALUE;
}
src = buffer + offset;
int height = crop.height();
int width = crop.width();
write_size = width*2;
for (unsigned int i = 0; i < height; i++) {
if (write_size != write(fd, src, width*2)) {
printf("Bad Write error (%d)%s\n",
errno, strerror(errno));
return UNKNOWN_ERROR;
}
src += stride*2;
}
return NO_ERROR;
}
static status_t copyCroppedNV12(unsigned int offset,
unsigned int strideSrc,
unsigned int strideDst,
unsigned int bufWidth,
unsigned int bufHeight,
const Rect &crop,
void *bufferSrc,
void *bufferDst)
{
unsigned char *lumaSrc = NULL, *chromaSrc = NULL;
unsigned char *lumaDst = NULL, *chromaDst = NULL;
unsigned int uvoffset;
int write_size;
if (!bufferSrc || !bufferDst) {
return BAD_VALUE;
}
uvoffset = strideSrc * crop.height();
uvoffset += (offset - (offset % strideSrc)) / 2 + (offset % strideSrc);
lumaSrc = static_cast<unsigned char *>(bufferSrc) + offset;
chromaSrc = static_cast<unsigned char *>(bufferSrc) + uvoffset;
int height = crop.height();
int width = crop.width();
uvoffset = strideDst * height;
lumaDst = static_cast<unsigned char *>(bufferDst);
chromaDst = static_cast<unsigned char *>(bufferDst) + uvoffset;
write_size = width;
for (unsigned int i = 0; i < height; i++) {
memcpy(lumaDst, lumaSrc, width);
lumaSrc += strideSrc;
lumaDst += strideDst;
}
height /= 2;
write_size = width;
for (unsigned int i = 0; i < height; i++) {
memcpy(chromaDst, chromaSrc, width);
chromaSrc += strideSrc;
chromaDst += strideDst;
}
return NO_ERROR;
}
static status_t copyCroppedPacked16(unsigned int offset,
unsigned int stride,
unsigned int bufWidth,
unsigned int bufHeight,
const Rect &crop,
void *bufferSrc,
void *bufferDst)
{
unsigned char *src = NULL, *dst = NULL;
if (!bufferSrc || !bufferDst) {
return BAD_VALUE;
}
src = static_cast<unsigned char *>(bufferSrc) + offset;
dst = static_cast<unsigned char *>(bufferDst);
int height = crop.height();
int width = crop.width();
for (unsigned int i = 0; i < height; i++) {
memcpy(dst, src, width*2);
src += stride*2;
dst += width*2;
}
return NO_ERROR;
}
void GLSurface::initialize(int display) {
mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
ASSERT(EGL_SUCCESS == eglGetError());
ASSERT(EGL_NO_DISPLAY != mEglDisplay);
EGLint majorVersion;
EGLint minorVersion;
ASSERT(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
ASSERT(EGL_SUCCESS == eglGetError());
EGLint numConfigs = 0;
ASSERT(eglChooseConfig(mEglDisplay, getConfigAttribs(), &mGlConfig,
1, &numConfigs));
ASSERT(EGL_SUCCESS == eglGetError());
if (display) {
mComposerClient = new SurfaceComposerClient;
ASSERT(NO_ERROR == mComposerClient->initCheck());
mSurfaceControl = mComposerClient->createSurface(
String8("Test Surface"), 0,
800, 480, HAL_PIXEL_FORMAT_YCrCb_420_SP, 0);
ASSERT(mSurfaceControl != NULL);
ASSERT(mSurfaceControl->isValid());
SurfaceComposerClient::openGlobalTransaction();
ASSERT(NO_ERROR == mSurfaceControl->setLayer(0x7FFFFFFF));
ASSERT(NO_ERROR == mSurfaceControl->show());
SurfaceComposerClient::closeGlobalTransaction();
sp<ANativeWindow> window = mSurfaceControl->getSurface();
mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
window.get(), NULL);
} else {
EGLint pbufferAttribs[] = {
EGL_WIDTH, getSurfaceWidth(),
EGL_HEIGHT, getSurfaceHeight(),
EGL_NONE };
mEglSurface = eglCreatePbufferSurface(mEglDisplay, mGlConfig,
pbufferAttribs);
}
ASSERT(EGL_SUCCESS == eglGetError());
ASSERT(EGL_NO_SURFACE != mEglSurface);
mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT,
getContextAttribs());
ASSERT(EGL_SUCCESS == eglGetError());
ASSERT(EGL_NO_CONTEXT != mEglContext);
ASSERT(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
ASSERT(EGL_SUCCESS == eglGetError());
EGLint w, h;
ASSERT(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &w));
ASSERT(EGL_SUCCESS == eglGetError());
ASSERT(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &h));
ASSERT(EGL_SUCCESS == eglGetError());
glViewport(0, 0, w, h);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
}
void GLSurface::deinit() {
if (mComposerClient != NULL) {
mComposerClient->dispose();
}
if (mEglContext != EGL_NO_CONTEXT) {
eglDestroyContext(mEglDisplay, mEglContext);
}
if (mEglSurface != EGL_NO_SURFACE) {
eglDestroySurface(mEglDisplay, mEglSurface);
}
if (mEglDisplay != EGL_NO_DISPLAY) {
eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
eglTerminate(mEglDisplay);
}
ASSERT(EGL_SUCCESS == eglGetError());
}
EGLint const* GLSurface::getConfigAttribs() {
static EGLint sDefaultConfigAttribs[] = {
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 16,
EGL_STENCIL_SIZE, 8,
EGL_NONE };
return sDefaultConfigAttribs;
}
EGLint const* GLSurface::getContextAttribs() {
static EGLint sDefaultContextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE };
return sDefaultContextAttribs;
}
void GLSurface::loadShader(GLenum shaderType, const char* pSource, GLuint* outShader) {
GLuint shader = glCreateShader(shaderType);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
if (shader) {
glShaderSource(shader, 1, &pSource, NULL);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
glCompileShader(shader);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
GLint compiled = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
if (!compiled) {
GLint infoLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
if (infoLen) {
char* buf = (char*) malloc(infoLen);
if (buf) {
glGetShaderInfoLog(shader, infoLen, NULL, buf);
printf("Shader compile log:\n%s\n", buf);
free(buf);
}
} else {
char* buf = (char*) malloc(0x1000);
if (buf) {
glGetShaderInfoLog(shader, 0x1000, NULL, buf);
printf("Shader compile log:\n%s\n", buf);
free(buf);
}
}
glDeleteShader(shader);
shader = 0;
}
}
ASSERT(shader != 0);
*outShader = shader;
}
void GLSurface::createProgram(const char* pVertexSource, const char* pFragmentSource,
GLuint* outPgm) {
GLuint vertexShader, fragmentShader;
{
loadShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader);
}
{
loadShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader);
}
GLuint program = glCreateProgram();
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
if (program) {
glAttachShader(program, vertexShader);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
glAttachShader(program, fragmentShader);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
glLinkProgram(program);
GLint linkStatus = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus != GL_TRUE) {
GLint bufLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
if (bufLength) {
char* buf = (char*) malloc(bufLength);
if (buf) {
glGetProgramInfoLog(program, bufLength, NULL, buf);
printf("Program link log:\n%s\n", buf);
free(buf);
}
}
glDeleteProgram(program);
program = 0;
}
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
ASSERT(program != 0);
*outPgm = program;
}
// GLConsumer specific
sp<GLConsumer> SurfaceTextureBase::getST() {
return mST;
}
void SurfaceTextureBase::initialize(int tex_id, EGLenum tex_target) {
mTexId = tex_id;
sp<BufferQueue> bq = new BufferQueue();
mST = new GLConsumer(bq, tex_id, tex_target);
mSTC = new Surface(mST);
mANW = mSTC;
}
void SurfaceTextureBase::deinit() {
mANW.clear();
mSTC.clear();
mST->abandon();
mST.clear();
}
void SurfaceTextureBase::getId(const char **name) {
sp<ANativeWindow> windowTapOut = mSTC;
*name = NULL;
if (windowTapOut.get()) {
windowTapOut->perform(windowTapOut.get(), NATIVE_WINDOW_GET_ID, name);
}
windowTapOut.clear();
}
// GLConsumer with GL specific
void SurfaceTextureGL::initialize(int display, int tex_id) {
GLSurface::initialize(display);
SurfaceTextureBase::initialize(tex_id, GL_TEXTURE_EXTERNAL_OES);
const char vsrc[] =
"attribute vec4 vPosition;\n"
"varying vec2 texCoords;\n"
"uniform mat4 texMatrix;\n"
"void main() {\n"
" vec2 vTexCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n"
" texCoords = (texMatrix * vec4(vTexCoords, 0.0, 1.0)).xy;\n"
" gl_Position = vPosition;\n"
"}\n";
const char fsrc[] =
"#extension GL_OES_EGL_image_external : require\n"
"precision mediump float;\n"
"uniform samplerExternalOES texSampler;\n"
"varying vec2 texCoords;\n"
"void main() {\n"
" gl_FragColor = texture2D(texSampler, texCoords);\n"
"}\n";
{
createProgram(vsrc, fsrc, &mPgm);
}
mPositionHandle = glGetAttribLocation(mPgm, "vPosition");
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
ASSERT(-1 != mPositionHandle);
mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler");
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
ASSERT(-1 != mTexSamplerHandle);
mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix");
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
ASSERT(-1 != mTexMatrixHandle);
}
void SurfaceTextureGL::deinit() {
SurfaceTextureBase::deinit();
GLSurface::deinit();
}
// drawTexture draws the GLConsumer over the entire GL viewport.
void SurfaceTextureGL::drawTexture() {
const GLfloat triangleVertices[] = {
-1.0f, 1.0f,
-1.0f, -1.0f,
1.0f, -1.0f,
1.0f, 1.0f,
};
glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0,
triangleVertices);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
glEnableVertexAttribArray(mPositionHandle);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
glUseProgram(mPgm);
glUniform1i(mTexSamplerHandle, 0);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexId);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
// XXX: These calls are not needed for GL_TEXTURE_EXTERNAL_OES as
// they're setting the defautls for that target, but when hacking things
// to use GL_TEXTURE_2D they are needed to achieve the same behavior.
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER,
GL_LINEAR);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER,
GL_LINEAR);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
GLfloat texMatrix[16];
mST->getTransformMatrix(texMatrix);
glUniformMatrix4fv(mTexMatrixHandle, 1, GL_FALSE, texMatrix);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
ASSERT(GLenum(GL_NO_ERROR) == glGetError());
eglSwapBuffers(mEglDisplay, mEglSurface);
}
// buffer source stuff
void BufferSourceThread::handleBuffer(sp<GraphicBuffer> &graphic_buffer, uint8_t *buffer,
unsigned int count, const Rect &crop) {
int size;
buffer_info_t info;
unsigned int offset = 0;
int fd = -1;
char fn[256];
if (!graphic_buffer.get()) {
printf("Invalid graphic_buffer!\n");
return;
}
size = calcBufSize((int)graphic_buffer->getPixelFormat(),
graphic_buffer->getWidth(),
graphic_buffer->getHeight());
if (size <= 0) {
printf("Can't get size!\n");
return;
}
if (!buffer) {
printf("Invalid mapped buffer!\n");
return;
}
info.size = size;
info.width = graphic_buffer->getWidth();
info.height = graphic_buffer->getHeight();
info.format = graphic_buffer->getPixelFormat();
info.buf = graphic_buffer;
info.crop = crop;
{
Mutex::Autolock lock(mReturnedBuffersMutex);
if (mReturnedBuffers.size() >= kReturnedBuffersMaxCapacity) mReturnedBuffers.removeAt(0);
}
// re-calculate size and offset
size = calcBufSize((int) graphic_buffer->getPixelFormat(), crop.width(), crop.height());
offset = calcOffset((int) graphic_buffer->getPixelFormat(), info.width, crop.top, crop.left);
// Do not write buffer to file if we are streaming capture
// It adds too much latency
if (!mRestartCapture) {
fn[0] = 0;
sprintf(fn, "/sdcard/img%03d.raw", count);
fd = open(fn, O_CREAT | O_WRONLY | O_TRUNC, 0777);
if (fd >= 0) {
if (HAL_PIXEL_FORMAT_TI_NV12 == info.format) {
writeCroppedNV12(offset, info.width, info.width, info.height,
crop, fd, buffer);
} else if (HAL_PIXEL_FORMAT_TI_UYVY == info.format) {
writeCroppedUYVY(offset, info.width, info.width, info.height,
crop, fd, buffer);
} else if (size != write(fd, buffer + offset, size)) {
printf("Bad Write int a %s error (%d)%s\n", fn, errno, strerror(errno));
}
printf("%s: buffer=%08X, size=%d stored at %s\n"
"\tRect: top[%d] left[%d] right[%d] bottom[%d] width[%d] height[%d] offset[%d] stride[%d]\n",
__FUNCTION__, (int)buffer, size, fn,
crop.top, crop.left, crop.right, crop.bottom,
crop.width(), crop.height(),
offset, info.width);
close(fd);
} else {
printf("error opening or creating %s\n", fn);
}
}
}
Rect BufferSourceThread::getCrop(sp<GraphicBuffer> &graphic_buffer, const float *mtx) {
Rect crop(graphic_buffer->getWidth(), graphic_buffer->getHeight());
// calculate crop rectangle from tranformation matrix
float sx, sy, tx, ty, h, w;
unsigned int rect_x, rect_y;
/* sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, 1, 0,
tx, ty, 0, 1 */
sx = mtx[0];
sy = mtx[5];
tx = mtx[12];
ty = mtx[13];
w = float(graphic_buffer->getWidth());
h = float(graphic_buffer->getHeight());
unsigned int bottom = (unsigned int)(h - (ty * h + 1));
unsigned int left = (unsigned int)(tx * w -1);
rect_y = (unsigned int)(fabsf(sy) * h);
rect_x = (unsigned int)(fabsf(sx) * w);
// handle v-flip
if (sy < 0.0f) {
bottom = h - bottom;
}
// handle h-flip
if (sx < 0.0f) {
left = w - left;
}
unsigned int top = bottom - rect_y;
unsigned int right = left + rect_x;
Rect updatedCrop(left, top, right, bottom);
if (updatedCrop.isValid()) {
crop = updatedCrop;
} else {
printf("Crop for buffer %d is not valid: "
"left=%u, top=%u, right=%u, bottom=%u. "
"Will use default.\n",
mCounter,
left, top, right, bottom);
}
return crop;
}
void BufferSourceInput::setInput(buffer_info_t bufinfo, const char *format, ShotParameters ¶ms) {
ANativeWindowBuffer* anb;
GraphicBufferMapper &mapper = GraphicBufferMapper::get();
int pixformat = HAL_PIXEL_FORMAT_TI_NV12;
size_t tapInMinUndequeued = 0;
int aligned_width, aligned_height;
pixformat = bufinfo.format;
// Aligning is not needed for Bayer
if ( ( pixformat == HAL_PIXEL_FORMAT_TI_Y16 ) ||
( pixformat == HAL_PIXEL_FORMAT_TI_UYVY ) ) {
aligned_width = bufinfo.crop.right - bufinfo.crop.left;
} else {
aligned_width = ALIGN_UP(bufinfo.crop.right - bufinfo.crop.left, ALIGN_WIDTH);
}
aligned_height = bufinfo.crop.bottom - bufinfo.crop.top;
printf("aligned width: %d height: %d \n", aligned_width, aligned_height);
if (mWindowTapIn.get() == 0) {
return;
}
native_window_set_usage(mWindowTapIn.get(),
getUsageFromANW(pixformat));
mWindowTapIn->perform(mWindowTapIn.get(),
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
&tapInMinUndequeued);;
native_window_set_buffer_count(mWindowTapIn.get(), tapInMinUndequeued);
native_window_set_buffers_geometry(mWindowTapIn.get(),
aligned_width, aligned_height, bufinfo.format);
// if buffer dimensions are the same as the aligned dimensions, then we can
// queue the buffer directly to tapin surface. if the dimensions are different
// then the aligned ones, then we have to copy the buffer into our own buffer
// to make sure the stride of the buffer is correct
if ((aligned_width != bufinfo.width) || (aligned_height != bufinfo.height) ||
( pixformat == HAL_PIXEL_FORMAT_TI_Y16 ) ||
( pixformat == HAL_PIXEL_FORMAT_TI_UYVY) ) {
void *dest[3] = { 0 };
void *src[3] = { 0 };
Rect bounds(aligned_width, aligned_height);
mWindowTapIn->dequeueBuffer(mWindowTapIn.get(), &anb);
mapper.lock(anb->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, dest);
// copy buffer to input buffer if available
if (bufinfo.buf.get()) {
bufinfo.buf->lock(GRALLOC_USAGE_SW_READ_OFTEN, src);
}
if (src[0]) {
switch (pixformat) {
case HAL_PIXEL_FORMAT_TI_Y16:
case HAL_PIXEL_FORMAT_TI_UYVY:
copyCroppedPacked16(bufinfo.offset,
bufinfo.width,
bufinfo.width,
bufinfo.height,
bufinfo.crop,
src[0],
dest[0]);
break;
case HAL_PIXEL_FORMAT_TI_NV12:
copyCroppedNV12(bufinfo.offset,
bufinfo.width,
aligned_width,
bufinfo.width,
bufinfo.height,
bufinfo.crop,
src[0],
dest[0]);
break;
default:
printf("Pixel format 0x%x not supported\n", pixformat);
exit(1);
break;
}
}
if (bufinfo.buf.get()) {
bufinfo.buf->unlock();
}
mapper.unlock(anb->handle);
} else {
mWindowTapIn->perform(mWindowTapIn.get(), NATIVE_WINDOW_ADD_BUFFER_SLOT, &bufinfo.buf);
anb = bufinfo.buf->getNativeBuffer();
}
mWindowTapIn->queueBuffer(mWindowTapIn.get(), anb);
{
sp<ANativeWindow> windowTapIn = mWindowTapIn;
const char* id = NULL;
if (windowTapIn.get()) {
windowTapIn->perform(windowTapIn.get(), NATIVE_WINDOW_GET_ID, &id);
}
if (id) {
params.set(KEY_TAP_IN_SURFACE, id);
} else {
params.remove(KEY_TAP_IN_SURFACE);
}
windowTapIn.clear();
}
}
void BufferSourceThread::showMetadata(sp<IMemory> data) {
static nsecs_t prevTime = 0;
nsecs_t currTime = 0;
ssize_t offset;
size_t size;
if ( NULL == data.get() ) {
printf("No Metadata!");
return;
}
sp<IMemoryHeap> heap = data->getMemory(&offset, &size);
camera_metadata_t * meta = static_cast<camera_metadata_t *> (heap->base());
printf(" frame nmber: %d\n", meta->frame_number);
printf(" shot number: %d\n", meta->shot_number);
printf(" analog gain: %d req: %d range: %d~%d dev: %d err: %d\n",
meta->analog_gain,
meta->analog_gain_req,
meta->analog_gain_min,
meta->analog_gain_max,
meta->analog_gain_dev,
meta->analog_gain_error);
printf(" exposure time: %d req: %d range: %d~%d dev: %d err: %d\n",
meta->exposure_time,
meta->exposure_time_req,
meta->exposure_time_min,
meta->exposure_time_max,
meta->exposure_time_dev,
meta->exposure_time_error);
printf(" EV compensation: req: %d dev: %d\n",
meta->exposure_compensation_req,
meta->exposure_dev);
printf(" awb gain: %d\n", meta->analog_gain);
printf(" awb offsets: %d\n", meta->offset_b);
printf(" awb temperature: %d\n", meta->awb_temp);
printf(" LSC table applied: %d\n", meta->lsc_table_applied);
if ( meta->lsc_table_applied ) {
uint8_t *lscTable = (uint8_t *)meta + meta->lsc_table_offset;
printf("LSC Table Size:%d Data[0:7]: %d:%d:%d:%d:%d:%d:%d:%d\n",
meta->lsc_table_size,
lscTable[0],
lscTable[1],
lscTable[2],
lscTable[3],
lscTable[4],
lscTable[5],
lscTable[6],
lscTable[7]);
}
printf(" Faces detected: %d\n", meta->number_of_faces);
currTime = meta->timestamp;
printf(" timestamp (ns): %llu\n", currTime);
if (prevTime) printf("inter-shot time (ms): %llu\n", (currTime - prevTime) / 1000000l);
prevTime = currTime;
}