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