diff options
Diffstat (limited to 'test/CameraHal/camera_test_surfacetexture.cpp')
-rw-r--r-- | test/CameraHal/camera_test_surfacetexture.cpp | 909 |
1 files changed, 909 insertions, 0 deletions
diff --git a/test/CameraHal/camera_test_surfacetexture.cpp b/test/CameraHal/camera_test_surfacetexture.cpp new file mode 100644 index 0000000..5c52094 --- /dev/null +++ b/test/CameraHal/camera_test_surfacetexture.cpp @@ -0,0 +1,909 @@ +#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/SurfaceTexture.h> +#include <gui/SurfaceTextureClient.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; +} + +// SurfaceTexture specific +sp<SurfaceTexture> SurfaceTextureBase::getST() { + return mST; +} + +void SurfaceTextureBase::initialize(int tex_id, EGLenum tex_target) { + mTexId = tex_id; + mST = new SurfaceTexture(tex_id, true, tex_target); + mSTC = new SurfaceTextureClient(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(); +} + +// SurfaceTexture 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 SurfaceTexture 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; +} |