Home | History | Annotate | Download | only in camera
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * Contains implementation of a class EmulatedFakeRotatingCameraDevice that encapsulates
     19  * fake camera device.
     20  */
     21 
     22 #define GL_GLEXT_PROTOTYPES
     23 #define LOG_NDEBUG 0
     24 #define LOG_TAG "EmulatedCamera_FakeDevice"
     25 #define FAKE_CAMERA_SENSOR "FakeRotatingCameraSensor"
     26 #include <cutils/log.h>
     27 #include "EmulatedFakeCamera.h"
     28 #include "EmulatedFakeRotatingCameraDevice.h"
     29 #include "qemud.h"
     30 
     31 #include <EGL/egl.h>
     32 #include <GLES/gl.h>
     33 #include <GLES/glext.h>
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <math.h>
     37 #include <ui/DisplayInfo.h>
     38 #include <fcntl.h>
     39 
     40 #undef min
     41 #undef max
     42 #include <algorithm>
     43 
     44 namespace android {
     45 
     46 // include the dots pattern directly, it is NV21 format
     47 #include "acircles_pattern_1280_720.c"
     48 
     49 // ----------------------------------------------------------------------------
     50 
     51 static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
     52     if (returnVal != EGL_TRUE) {
     53         ALOGE("%s() returned %d\n", op, returnVal);
     54     }
     55 
     56     for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
     57             = eglGetError()) {
     58         ALOGE("after %s() eglError (0x%x)\n", op, error);
     59     }
     60 }
     61 
     62 static signed clamp_rgb(signed value) {
     63     if (value > 255) {
     64         value = 255;
     65     } else if (value < 0) {
     66         value = 0;
     67     }
     68     return value;
     69 }
     70 
     71 static void rgba8888_to_nv21(uint8_t* input, uint8_t* output, int width, int height) {
     72     int align = 16;
     73     int yStride = (width + (align -1)) & ~(align-1);
     74     uint8_t* outputVU = output + height*yStride;
     75     for (int j = 0; j < height; ++j) {
     76         uint8_t* outputY = output + j*yStride;
     77         for (int i = 0; i < width; ++i) {
     78             uint8_t R = input[j*width*4 + i*4];
     79             uint8_t G = input[j*width*4 + i*4 + 1];
     80             uint8_t B = input[j*width*4 + i*4 + 2];
     81             uint8_t Y = clamp_rgb((77 * R + 150 * G +  29 * B) >> 8);
     82             *outputY++ = Y;
     83             bool jeven = (j & 1) == 0;
     84             bool ieven = (i & 1) == 0;
     85             if (jeven && ieven) {
     86                 uint8_t V = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128);
     87                 uint8_t U = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128);
     88                 *outputVU++ = V;
     89                 *outputVU++ = U;
     90             }
     91         }
     92     }
     93 }
     94 
     95 static void nv21_to_rgba8888(uint8_t* input, uint32_t * output, int width, int height) {
     96     int align = 16;
     97     uint32_t* output0 = output;
     98     int yStride = (width + (align -1)) & ~(align-1);
     99     uint8_t* inputVU = input + height*yStride;
    100     uint8_t Y, U, V;
    101     for (int j = 0; j < height; ++j) {
    102         uint8_t* inputY = input + j*yStride;
    103         for (int i = 0; i < width; ++i) {
    104             Y = *inputY++;
    105             bool jeven = (j & 1) == 0;
    106             bool ieven = (i & 1) == 0;
    107             if (jeven && ieven) {
    108                 V = *inputVU++;
    109                 U = *inputVU++;
    110             }
    111             *output++ = YUVToRGB32(Y,U,V);
    112         }
    113     }
    114 }
    115 
    116 void EmulatedFakeRotatingCameraDevice::render(int width, int height)
    117 {
    118     update_scene((float)width, (float)height);
    119     create_texture_dotx(1280, 720);
    120     int i, j;
    121     int quads = 1;
    122 
    123     int w= 992/2;
    124     int h = 1280/2;
    125     const GLfloat verticesfloat[] = {
    126              -w,  -h,  0,
    127               w,  -h,  0,
    128               w,   h,  0,
    129              -w,   h,  0
    130     };
    131 
    132     const GLfloat texCoordsfloat[] = {
    133             0,       0,
    134             1.0f,    0,
    135             1.0f,    1.0f,
    136             0,       1.0f
    137     };
    138 
    139     const GLushort indices[] = { 0, 1, 2,  0, 2, 3 };
    140 
    141     glVertexPointer(3, GL_FLOAT, 0, verticesfloat);
    142     glTexCoordPointer(2, GL_FLOAT, 0, texCoordsfloat);
    143     glClearColor(0.5, 0.5, 0.5, 1.0);
    144     int nelem = sizeof(indices)/sizeof(indices[0]);
    145     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    146     glDrawElements(GL_TRIANGLES, nelem, GL_UNSIGNED_SHORT, indices);
    147     glFinish();
    148     glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, mPixelBuf);
    149 }
    150 
    151 static void get_color(uint32_t* img, int i, int j, int w, int h, int dw, uint32_t * color) {
    152     int mini = dw/2 - w/2;
    153     int minj = dw/2 - h/2;
    154     int maxi = mini + w -1;
    155     int maxj = minj + h -1;
    156 
    157     if ( i >= mini && i <= maxi && j >= minj && j <= maxj) {
    158         *color = img[i-mini + dw*(j-minj)];
    159     }
    160 }
    161 
    162 static void convert_to_square(uint32_t* src, uint32_t* dest, int sw, int sh, int dw) {
    163     for (int i=0; i < dw; ++i) {
    164         for (int j=0; j < dw; ++j) {
    165             uint32_t color=0;
    166             get_color(src, i, j, sw, sh, dw, &color);
    167             dest[i+j*dw] = color;
    168         }
    169     }
    170 }
    171 
    172 void EmulatedFakeRotatingCameraDevice::create_texture_dotx(int width, int height) {
    173     uint32_t* myrgba = new uint32_t[width * height];
    174     nv21_to_rgba8888(rawData, myrgba, width, height);
    175     uint32_t* myrgba2 = new uint32_t[width * width];
    176     convert_to_square(myrgba, myrgba2, width, height, width);
    177 
    178     glGenTextures(1, &mTexture);
    179     glBindTexture(GL_TEXTURE_2D, mTexture);
    180     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, width, 0, GL_RGBA, GL_UNSIGNED_BYTE, myrgba2);
    181     //glGenerateMipmapOES does not work on mac, dont use it.
    182     //glGenerateMipmapOES(GL_TEXTURE_2D);
    183     // need to use linear, otherwise the dots will have sharp edges
    184     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    185     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    186     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    187     delete[] myrgba;
    188     delete[] myrgba2;
    189 }
    190 
    191 
    192 static void gluLookAt(float eyeX, float eyeY, float eyeZ,
    193         float centerX, float centerY, float centerZ, float upX, float upY,
    194         float upZ)
    195 {
    196     // See the OpenGL GLUT documentation for gluLookAt for a description
    197     // of the algorithm. We implement it in a straightforward way:
    198 
    199     float fx = centerX - eyeX;
    200     float fy = centerY - eyeY;
    201     float fz = centerZ - eyeZ;
    202     float flf = 1.0f / sqrt(fx * fx + fy * fy + fz * fz);
    203     fx *= flf;
    204     fy *= flf;
    205     fz *= flf;
    206 
    207     // compute s = f x up (x means "cross product")
    208 
    209     float sx = fy * upZ - fz * upY;
    210     float sy = fz * upX - fx * upZ;
    211     float sz = fx * upY - fy * upX;
    212     float slf = 1.0f / sqrt(sx * sx + sy * sy + sz * sz);
    213     sx *= slf;
    214     sy *= slf;
    215     sz *= slf;
    216 
    217     // compute u = s x f
    218     float ux = sy * fz - sz * fy;
    219     float uy = sz * fx - sx * fz;
    220     float uz = sx * fy - sy * fx;
    221     float ulf = 1.0f / sqrt(ux * ux + uy * uy + uz * uz);
    222     ux *= ulf;
    223     uy *= ulf;
    224     uz *= ulf;
    225 
    226     float m[16] ;
    227     m[0] = sx;
    228     m[1] = ux;
    229     m[2] = -fx;
    230     m[3] = 0.0f;
    231 
    232     m[4] = sy;
    233     m[5] = uy;
    234     m[6] = -fy;
    235     m[7] = 0.0f;
    236 
    237     m[8] = sz;
    238     m[9] = uz;
    239     m[10] = -fz;
    240     m[11] = 0.0f;
    241 
    242     m[12] = 0.0f;
    243     m[13] = 0.0f;
    244     m[14] = 0.0f;
    245     m[15] = 1.0f;
    246 
    247     glMultMatrixf(m);
    248     glTranslatef(-eyeX, -eyeY, -eyeZ);
    249 }
    250 
    251 void EmulatedFakeRotatingCameraDevice::update_scene(float width, float height)
    252 {
    253     float ratio = width / height;
    254     glViewport(0, 0, width, height);
    255     glMatrixMode(GL_PROJECTION);
    256     glLoadIdentity();
    257     glFrustumf(-ratio/2.0, ratio/2.0, -1/2.0, 1/2.0, 1, 40000);
    258     glMatrixMode(GL_MODELVIEW);
    259     glLoadIdentity();
    260     float up_x=-1;
    261     float up_y=0;
    262     float up_z=0;
    263     get_yawing(&up_x, &up_y, &up_z);
    264     float eye_x=0;
    265     float eye_y=0;
    266     float eye_z=2000;
    267     get_eye_x_y_z(&eye_x, &eye_y, &eye_z);
    268     gluLookAt( eye_x, eye_y, eye_z, 0, 0, 0, up_x, up_y, up_z);
    269     glEnable(GL_TEXTURE_2D);
    270     glEnableClientState(GL_VERTEX_ARRAY);
    271     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    272 }
    273 
    274 void EmulatedFakeRotatingCameraDevice::free_gl_surface(void)
    275 {
    276     if (mEglDisplay != EGL_NO_DISPLAY)
    277     {
    278         eglMakeCurrent( EGL_NO_DISPLAY, EGL_NO_SURFACE,
    279                 EGL_NO_SURFACE, EGL_NO_CONTEXT );
    280         eglDestroyContext( mEglDisplay, mEglContext );
    281         eglDestroySurface( mEglDisplay, mEglSurface );
    282         eglTerminate( mEglDisplay );
    283         mEglDisplay = EGL_NO_DISPLAY;
    284     }
    285 }
    286 
    287 void EmulatedFakeRotatingCameraDevice::init_sensor() {
    288     if (mSensorPipe >=0) return;
    289     // create a sensor pipe
    290     mSensorPipe = qemu_pipe_open(FAKE_CAMERA_SENSOR);
    291     if (mSensorPipe < 0) {
    292         ALOGE("cannot open %s", FAKE_CAMERA_SENSOR);
    293     } else {
    294         ALOGD("successfully opened %s", FAKE_CAMERA_SENSOR);
    295     }
    296 }
    297 
    298 void EmulatedFakeRotatingCameraDevice::read_sensor() {
    299     if (mSensorPipe < 0) return;
    300     char get[] = "get";
    301     int pipe_command_length = sizeof(get);
    302     WriteFully(mSensorPipe, &pipe_command_length, sizeof(pipe_command_length));
    303     WriteFully(mSensorPipe, get, pipe_command_length);
    304     ReadFully(mSensorPipe, &pipe_command_length, sizeof(pipe_command_length));
    305     ReadFully(mSensorPipe, &mSensorValues, pipe_command_length);
    306     assert(pipe_command_length == 9*sizeof(float));
    307     ALOGD("accel: %g %g %g; magnetic %g %g %g orientation %g %g %g",
    308             mSensorValues[SENSOR_VALUE_ACCEL_X], mSensorValues[SENSOR_VALUE_ACCEL_Y],
    309             mSensorValues[SENSOR_VALUE_ACCEL_Z],
    310             mSensorValues[SENSOR_VALUE_MAGNETIC_X], mSensorValues[SENSOR_VALUE_MAGNETIC_Y],
    311             mSensorValues[SENSOR_VALUE_MAGNETIC_Y],
    312             mSensorValues[SENSOR_VALUE_ROTATION_X], mSensorValues[SENSOR_VALUE_ROTATION_Y],
    313             mSensorValues[SENSOR_VALUE_ROTATION_Z]);
    314 }
    315 
    316 void EmulatedFakeRotatingCameraDevice::read_rotation_vector(double *yaw, double* pitch, double* roll) {
    317     read_sensor();
    318     *yaw = mSensorValues[SENSOR_VALUE_ROTATION_Z];
    319     *pitch = mSensorValues[SENSOR_VALUE_ROTATION_X];
    320     *roll = mSensorValues[SENSOR_VALUE_ROTATION_Y];
    321     return;
    322 }
    323 
    324 void EmulatedFakeRotatingCameraDevice::get_yawing(float* x, float* y, float*z) {
    325     double yaw, pitch, roll;
    326     read_rotation_vector(&yaw, &pitch, &roll);
    327     *x = sin((180+yaw)*3.14/180);
    328     *y = cos((180+yaw)*3.14/180);
    329     *z = 0;
    330     ALOGD("%s: yaw is %g, x %g y %g z %g", __func__, yaw, *x, *y, *z);
    331 }
    332 
    333 void EmulatedFakeRotatingCameraDevice::get_eye_x_y_z(float* x, float* y, float*z) {
    334     const float R=3500;
    335     //the coordinate of real camera is rotated (x-y swap)
    336     //and reverted (+/- swap)
    337     //
    338     //so rotation y is clockwise around x axis;
    339     //and rotation x is clockwise around y axis.
    340     const float theta_around_x = -mSensorValues[SENSOR_VALUE_ROTATION_Y];
    341     const float theta_around_y = -mSensorValues[SENSOR_VALUE_ROTATION_X];
    342     //apply x rotation first
    343     float y1 = -R*sin(theta_around_x*3.14/180);
    344     float z1 = R*cos(theta_around_x*3.14/180);
    345     //apply y rotation second
    346     float xz2 = z1 * sin(theta_around_y*3.14/180);
    347     float zz2 = z1 * cos(theta_around_y*3.14/180);
    348     *x = xz2;
    349     *y = y1;
    350     *z = zz2;
    351 
    352 }
    353 
    354 int EmulatedFakeRotatingCameraDevice::init_gl_surface(int width, int height)
    355 {
    356     EGLint numConfigs = 1;
    357     EGLConfig myConfig = {0};
    358 
    359     if ( (mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY )
    360     {
    361         ALOGE("eglGetDisplay failed\n");
    362         return 0;
    363     }
    364 
    365     if ( eglInitialize(mEglDisplay, NULL, NULL) != EGL_TRUE )
    366     {
    367         ALOGE("eglInitialize failed\n");
    368         return 0;
    369     }
    370 
    371     {
    372         EGLint s_configAttribs[] = {
    373          EGL_SURFACE_TYPE, EGL_PBUFFER_BIT|EGL_WINDOW_BIT,
    374          EGL_RED_SIZE,       5,
    375          EGL_GREEN_SIZE,     6,
    376          EGL_BLUE_SIZE,      5,
    377          EGL_NONE
    378         };
    379         eglChooseConfig(mEglDisplay, s_configAttribs, &myConfig, 1, &numConfigs);
    380         EGLint attribs[] = { EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE };
    381         mEglSurface = eglCreatePbufferSurface(mEglDisplay, myConfig, attribs);
    382         if (mEglSurface == EGL_NO_SURFACE) {
    383             ALOGE("eglCreatePbufferSurface error %x\n", eglGetError());
    384         }
    385     }
    386 
    387     if ( (mEglContext = eglCreateContext(mEglDisplay, myConfig, 0, 0)) == EGL_NO_CONTEXT )
    388     {
    389         ALOGE("eglCreateContext failed\n");
    390         return 0;
    391     }
    392 
    393     if ( eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext) != EGL_TRUE )
    394     {
    395         ALOGE("eglMakeCurrent failed\n");
    396         return 0;
    397     }
    398 
    399     int w, h;
    400 
    401     eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &w);
    402     checkEglError("eglQuerySurface");
    403     eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &h);
    404     checkEglError("eglQuerySurface");
    405     GLint dim = w < h ? w : h;
    406 
    407     ALOGD("Window dimensions: %d x %d\n", w, h);
    408 
    409     glDisable(GL_DITHER);
    410     glEnable(GL_CULL_FACE);
    411 
    412     return 1;
    413 }
    414 
    415 EmulatedFakeRotatingCameraDevice::EmulatedFakeRotatingCameraDevice(EmulatedFakeCamera* camera_hal)
    416     : EmulatedCameraDevice(camera_hal), mOpenglReady(false)
    417 {
    418 }
    419 
    420 EmulatedFakeRotatingCameraDevice::~EmulatedFakeRotatingCameraDevice()
    421 {
    422 }
    423 
    424 /****************************************************************************
    425  * Emulated camera device abstract interface implementation.
    426  ***************************************************************************/
    427 
    428 status_t EmulatedFakeRotatingCameraDevice::connectDevice()
    429 {
    430     ALOGV("%s", __FUNCTION__);
    431 
    432     Mutex::Autolock locker(&mObjectLock);
    433     if (!isInitialized()) {
    434         ALOGE("%s: Fake camera device is not initialized.", __FUNCTION__);
    435         return EINVAL;
    436     }
    437     if (isConnected()) {
    438         ALOGW("%s: Fake camera device is already connected.", __FUNCTION__);
    439         return NO_ERROR;
    440     }
    441 
    442     /* There is no device to connect to. */
    443     mState = ECDS_CONNECTED;
    444 
    445     return NO_ERROR;
    446 }
    447 
    448 status_t EmulatedFakeRotatingCameraDevice::disconnectDevice()
    449 {
    450     ALOGV("%s", __FUNCTION__);
    451 
    452     Mutex::Autolock locker(&mObjectLock);
    453     if (!isConnected()) {
    454         ALOGW("%s: Fake camera device is already disconnected.", __FUNCTION__);
    455         return NO_ERROR;
    456     }
    457     if (isStarted()) {
    458         ALOGE("%s: Cannot disconnect from the started device.", __FUNCTION__);
    459         return EINVAL;
    460     }
    461 
    462     /* There is no device to disconnect from. */
    463     mState = ECDS_INITIALIZED;
    464 
    465     return NO_ERROR;
    466 }
    467 
    468 status_t EmulatedFakeRotatingCameraDevice::startDevice(int width,
    469                                                int height,
    470                                                uint32_t pix_fmt)
    471 {
    472     ALOGE("%s width %d height %d", __FUNCTION__, width, height);
    473 
    474     Mutex::Autolock locker(&mObjectLock);
    475     if (!isConnected()) {
    476         ALOGE("%s: Fake camera device is not connected.", __FUNCTION__);
    477         return EINVAL;
    478     }
    479     if (isStarted()) {
    480         ALOGE("%s: Fake camera device is already started.", __FUNCTION__);
    481         return EINVAL;
    482     }
    483 
    484     /* Initialize the base class. */
    485     const status_t res =
    486         EmulatedCameraDevice::commonStartDevice(width, height, pix_fmt);
    487 
    488     mState = ECDS_STARTED;
    489 
    490     return res;
    491 }
    492 
    493 status_t EmulatedFakeRotatingCameraDevice::stopDevice()
    494 {
    495     ALOGV("%s", __FUNCTION__);
    496 
    497     Mutex::Autolock locker(&mObjectLock);
    498     if (!isStarted()) {
    499         ALOGW("%s: Fake camera device is not started.", __FUNCTION__);
    500         return NO_ERROR;
    501     }
    502 
    503     EmulatedCameraDevice::commonStopDevice();
    504     mState = ECDS_CONNECTED;
    505 
    506     if (mOpenglReady) {
    507         free_gl_surface();
    508         delete mPixelBuf;
    509         mOpenglReady=false;
    510     }
    511     if (mSensorPipe >= 0) {
    512         close(mSensorPipe);
    513         mSensorPipe = -1;
    514     }
    515 
    516     return NO_ERROR;
    517 }
    518 
    519 /****************************************************************************
    520  * Worker thread management overrides.
    521  ***************************************************************************/
    522 
    523 bool EmulatedFakeRotatingCameraDevice::produceFrame(void* buffer,
    524                                                     int64_t* timestamp)
    525 {
    526     if (mOpenglReady == false) {
    527         init_gl_surface(mFrameWidth, mFrameHeight);
    528         mOpenglReady = true;
    529         int width=mFrameWidth;
    530         int height = mFrameHeight;
    531         int kGlBytesPerPixel = 4;
    532         mPixelBuf = new uint8_t[width * height * kGlBytesPerPixel];
    533         init_sensor();
    534     }
    535     render(mFrameWidth, mFrameHeight);
    536     fillBuffer(buffer);
    537     return true;
    538 }
    539 
    540 /****************************************************************************
    541  * Fake camera device private API
    542  ***************************************************************************/
    543 
    544 void EmulatedFakeRotatingCameraDevice::fillBuffer(void* buffer)
    545 {
    546     uint8_t* currentFrame = reinterpret_cast<uint8_t*>(buffer);
    547     rgba8888_to_nv21(mPixelBuf, currentFrame, mFrameWidth, mFrameHeight);
    548     return;
    549 }
    550 
    551 }; /* namespace android */
    552