From ac4d519f43bd6587b3eafb68dab0861ba4fe4b5b Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Tue, 17 Jul 2012 16:13:52 -0700 Subject: [PATCH 1/4] gralloc: Add automatic format selection Have gralloc_alloc be able to select the appropriate pixel format given the endpoints, triggered by new GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO format. Currently supports camera->screen, and camera->video encoder. Bug: 6243944 Change-Id: Ib1bf8da8d9184ac99e7f50aad09212c146c32809 --- .../system/OpenglSystemCommon/gralloc_cb.h | 18 ++++- tools/emulator/opengl/system/egl/egl.cpp | 4 +- .../opengl/system/gralloc/gralloc.cpp | 73 +++++++++++++++---- 3 files changed, 76 insertions(+), 19 deletions(-) diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/gralloc_cb.h b/tools/emulator/opengl/system/OpenglSystemCommon/gralloc_cb.h index e879409cb..a3fb8dd00 100644 --- a/tools/emulator/opengl/system/OpenglSystemCommon/gralloc_cb.h +++ b/tools/emulator/opengl/system/OpenglSystemCommon/gralloc_cb.h @@ -24,23 +24,36 @@ #define BUFFER_HANDLE_MAGIC ((int)0xabfabfab) #define CB_HANDLE_NUM_INTS(nfds) (int)((sizeof(cb_handle_t) - (nfds)*sizeof(int)) / sizeof(int)) +// +// Emulator-specific gralloc formats +// +enum { + // Request that gralloc select the proper format given the usage + // flags. Pass this as the format to gralloc_alloc, and then the concrete + // format can be found in cb_handle_t.format. It is invalid for + // cb_handle_t.format to be AUTO; it must be a concrete format in either the + // standard HAL_PIXEL_FORMAT enum or other values in this enum. + GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO = 0x100 +}; + // // Our buffer handle structure // struct cb_handle_t : public native_handle { cb_handle_t(int p_fd, int p_ashmemSize, int p_usage, - int p_width, int p_height, + int p_width, int p_height, int p_format, int p_glFormat, int p_glType) : fd(p_fd), magic(BUFFER_HANDLE_MAGIC), usage(p_usage), width(p_width), height(p_height), + format(p_format), glFormat(p_glFormat), glType(p_glType), ashmemSize(p_ashmemSize), - ashmemBase(NULL), + ashmemBase(0), ashmemBasePid(0), mappedPid(0), lockedLeft(0), @@ -88,6 +101,7 @@ struct cb_handle_t : public native_handle { int usage; // usage bits the buffer was created with int width; // buffer width int height; // buffer height + int format; // real internal pixel format format int glFormat; // OpenGL format enum used for host h/w color buffer int glType; // OpenGL type enum used when uploading to host int ashmemSize; // ashmem region size for the buffer (0 unless is HW_FB buffer or diff --git a/tools/emulator/opengl/system/egl/egl.cpp b/tools/emulator/opengl/system/egl/egl.cpp index b1be38dfb..da89c4dee 100644 --- a/tools/emulator/opengl/system/egl/egl.cpp +++ b/tools/emulator/opengl/system/egl/egl.cpp @@ -1146,7 +1146,9 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EG if (native_buffer->common.version != sizeof(android_native_buffer_t)) setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); - switch (native_buffer->format) { + cb_handle_t *cb = (cb_handle_t *)(native_buffer->handle); + + switch (cb->format) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_RGB_888: diff --git a/tools/emulator/opengl/system/gralloc/gralloc.cpp b/tools/emulator/opengl/system/gralloc/gralloc.cpp index 3953f9c33..dd5e5156d 100644 --- a/tools/emulator/opengl/system/gralloc/gralloc.cpp +++ b/tools/emulator/opengl/system/gralloc/gralloc.cpp @@ -133,8 +133,11 @@ static int gralloc_alloc(alloc_device_t* dev, D("gralloc_alloc w=%d h=%d usage=0x%x\n", w, h, usage); gralloc_device_t *grdev = (gralloc_device_t *)dev; - if (!grdev || !pHandle || !pStride) + if (!grdev || !pHandle || !pStride) { + ALOGE("gralloc_alloc: Bad inputs (grdev: %p, pHandle: %p, pStride: %p", + grdev, pHandle, pStride); return -EINVAL; + } // // Validate usage: buffer cannot be written both by s/w and h/w access. @@ -142,9 +145,37 @@ static int gralloc_alloc(alloc_device_t* dev, bool sw_write = (0 != (usage & GRALLOC_USAGE_SW_WRITE_MASK)); bool hw_write = (usage & GRALLOC_USAGE_HW_RENDER); if (hw_write && sw_write) { + ALOGE("gralloc_alloc: Mismatched usage flags: %d x %d, usage %x", + w, h, usage); return -EINVAL; } bool sw_read = (0 != (usage & GRALLOC_USAGE_SW_READ_MASK)); + bool hw_cam_write = usage & GRALLOC_USAGE_HW_CAMERA_WRITE; + bool hw_cam_read = usage & GRALLOC_USAGE_HW_CAMERA_READ; + bool hw_vid_enc_read = usage & GRALLOC_USAGE_HW_VIDEO_ENCODER; + + // Pick the right concrete pixel format given the endpoints as encoded in + // the usage bits. Every end-point pair needs explicit listing here. + if (format == GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO) { + // Camera as producer + if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) { + if (usage & GRALLOC_USAGE_HW_TEXTURE) { + // Camera-to-display is RGBA + format = HAL_PIXEL_FORMAT_RGBA_8888; + } else if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) { + // Camera-to-encoder is NV21 + format = HAL_PIXEL_FORMAT_YCrCb_420_SP; + } + } + + if (format == GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO) { + ALOGE("gralloc_alloc: Requested auto format selection, " + "but no known format for this usage: %d x %d, usage %x", + w, h, usage); + return -EINVAL; + } + } + bool yuv_format = false; int ashmem_size = 0; @@ -186,8 +217,8 @@ static int gralloc_alloc(alloc_device_t* dev, case HAL_PIXEL_FORMAT_RAW_SENSOR: bpp = 2; align = 16*bpp; - if (! (sw_read && sw_write) ) { - // Raw sensor data cannot be used by HW + if (! ((sw_read && hw_cam_write) || (sw_write && hw_cam_read) ) ) { + // Raw sensor data only goes to/from camera to CPU return -EINVAL; } // Not expecting to actually create any GL surfaces for this @@ -196,8 +227,8 @@ static int gralloc_alloc(alloc_device_t* dev, break; case HAL_PIXEL_FORMAT_BLOB: bpp = 1; - if (! (sw_read && sw_write) ) { - // Blob data cannot be used by HW + if (! (sw_read && hw_cam_write) ) { + // Blob data cannot be used by HW other than camera emulator return -EINVAL; } // Not expecting to actually create any GL surfaces for this @@ -210,6 +241,7 @@ static int gralloc_alloc(alloc_device_t* dev, // Not expecting to actually create any GL surfaces for this break; default: + ALOGE("gralloc_alloc: Unknown format %d", format); return -EINVAL; } @@ -218,9 +250,9 @@ static int gralloc_alloc(alloc_device_t* dev, ashmem_size += sizeof(uint32_t); } - if (sw_read || sw_write) { + if (sw_read || sw_write || hw_cam_write || hw_vid_enc_read) { // keep space for image on guest memory if SW access is needed - + // or if the camera is doing writing if (yuv_format) { // For NV21 ashmem_size += w * h * 3 / 2; @@ -232,8 +264,8 @@ static int gralloc_alloc(alloc_device_t* dev, } } - D("gralloc_alloc ashmem_size=%d, stride=%d, tid %d\n", ashmem_size, stride, - gettid()); + D("gralloc_alloc format=%d, ashmem_size=%d, stride=%d, tid %d\n", format, + ashmem_size, stride, gettid()); // // Allocate space in ashmem if needed @@ -252,7 +284,7 @@ static int gralloc_alloc(alloc_device_t* dev, } cb_handle_t *cb = new cb_handle_t(fd, ashmem_size, usage, - w, h, glFormat, glType); + w, h, format, glFormat, glType); if (ashmem_size > 0) { // @@ -271,8 +303,11 @@ static int gralloc_alloc(alloc_device_t* dev, // // Allocate ColorBuffer handle on the host (only if h/w access is allowed) + // Only do this for some h/w usages, not all. // - if (usage & GRALLOC_USAGE_HW_MASK) { + if (usage & (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_2D | GRALLOC_USAGE_HW_COMPOSER | + GRALLOC_USAGE_HW_FB) ) { DEFINE_HOST_CONNECTION; if (hostCon && rcEnc) { cb->hostHandle = rcEnc->rcCreateColorBuffer(rcEnc, w, h, glFormat); @@ -565,14 +600,17 @@ static int gralloc_lock(gralloc_module_t const* module, bool sw_write = (0 != (usage & GRALLOC_USAGE_SW_WRITE_MASK)); bool hw_read = (usage & GRALLOC_USAGE_HW_TEXTURE); bool hw_write = (usage & GRALLOC_USAGE_HW_RENDER); + bool hw_vid_enc_read = (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER); + bool hw_cam_write = (usage & GRALLOC_USAGE_HW_CAMERA_WRITE); bool sw_read_allowed = (0 != (cb->usage & GRALLOC_USAGE_SW_READ_MASK)); bool sw_write_allowed = (0 != (cb->usage & GRALLOC_USAGE_SW_WRITE_MASK)); if ( (hw_read || hw_write) || - (!sw_read && !sw_write) || + (!sw_read && !sw_write && !hw_cam_write && !hw_vid_enc_read) || (sw_read && !sw_read_allowed) || (sw_write && !sw_write_allowed) ) { - ALOGE("gralloc_lock usage mismatch usage=0x%x cb->usage=0x%x\n", usage, cb->usage); + ALOGE("gralloc_lock usage mismatch usage=0x%x cb->usage=0x%x\n", usage, + cb->usage); return -EINVAL; } @@ -582,7 +620,7 @@ static int gralloc_lock(gralloc_module_t const* module, // // make sure ashmem area is mapped if needed // - if (cb->canBePosted() || sw_read || sw_write) { + if (cb->canBePosted() || sw_read || sw_write || hw_cam_write || hw_vid_enc_read) { if (cb->ashmemBasePid != getpid() || !cb->ashmemBase) { return -EACCES; } @@ -619,11 +657,11 @@ static int gralloc_lock(gralloc_module_t const* module, // // is virtual address required ? // - if (sw_read || sw_write) { + if (sw_read || sw_write || hw_cam_write || hw_vid_enc_read) { *vaddr = cpu_addr; } - if (sw_write) { + if (sw_write || hw_cam_write) { // // Keep locked region if locked for s/w write access. // @@ -633,6 +671,9 @@ static int gralloc_lock(gralloc_module_t const* module, cb->lockedHeight = h; } + DD("gralloc_lock success. vaddr: %p, *vaddr: %p, usage: %x, cpu_addr: %p", + vaddr, vaddr ? *vaddr : 0, usage, cpu_addr); + return 0; } From ef0d02006a58231f475cde30b62e855fdb41484e Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Mon, 18 Jun 2012 17:06:41 -0700 Subject: [PATCH 2/4] EmulatedFakeCamera2: Add features needed for recording support for 320x240, NV21 - Support 320x240 in addition to 640x480 - Support NV21 (monochrome only right now) - Base simulated time on system time, since stagefright cares about timestamp base - Use emulator magic gralloc format to enable gralloc to pick format based on destination. Bug: 6243944 Change-Id: I3ea56bca726c69b51e03233ce86d4881401a3ffd --- tools/emulator/system/camera/Android.mk | 1 + .../system/camera/EmulatedFakeCamera2.cpp | 61 +++++++++++++++--- .../system/camera/fake-pipeline2/Base.h | 2 +- .../system/camera/fake-pipeline2/Sensor.cpp | 63 ++++++++++++++++--- .../system/camera/fake-pipeline2/Sensor.h | 2 +- 5 files changed, 108 insertions(+), 21 deletions(-) diff --git a/tools/emulator/system/camera/Android.mk b/tools/emulator/system/camera/Android.mk index ee08f9403..3843c1dfc 100755 --- a/tools/emulator/system/camera/Android.mk +++ b/tools/emulator/system/camera/Android.mk @@ -39,6 +39,7 @@ LOCAL_C_INCLUDES += external/jpeg \ external/skia/include/core/ \ frameworks/native/include/media/hardware \ frameworks/base/core/jni/android/graphics \ + $(LOCAL_PATH)/../../opengl/system/OpenglSystemCommon \ $(call include-path-for, camera) LOCAL_SRC_FILES := \ diff --git a/tools/emulator/system/camera/EmulatedFakeCamera2.cpp b/tools/emulator/system/camera/EmulatedFakeCamera2.cpp index 2e46d1e95..711c2d2b6 100644 --- a/tools/emulator/system/camera/EmulatedFakeCamera2.cpp +++ b/tools/emulator/system/camera/EmulatedFakeCamera2.cpp @@ -27,6 +27,7 @@ #include "EmulatedCameraFactory.h" #include #include +#include "gralloc_cb.h" namespace android { @@ -47,8 +48,8 @@ const uint64_t EmulatedFakeCamera2::kAvailableRawMinDurations[1] = { Sensor::kFrameDurationRange[0] }; -const uint32_t EmulatedFakeCamera2::kAvailableProcessedSizes[2] = { - 640, 480 +const uint32_t EmulatedFakeCamera2::kAvailableProcessedSizes[4] = { + 640, 480, 320, 240 // Sensor::kResolution[0], Sensor::kResolution[1] }; @@ -251,8 +252,9 @@ int EmulatedFakeCamera2::allocateStream( return BAD_VALUE; } } else { - // Emulator's opaque format is RGBA - format = HAL_PIXEL_FORMAT_RGBA_8888; + // Translate to emulator's magic format. + // Note: It is assumed that this is a processed format (not raw or JPEG). + format = GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO; } const uint32_t *availableSizes; @@ -266,6 +268,7 @@ int EmulatedFakeCamera2::allocateStream( availableSizes = kAvailableJpegSizes; availableSizeCount = sizeof(kAvailableJpegSizes)/sizeof(uint32_t); break; + case GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO: case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_YV12: case HAL_PIXEL_FORMAT_YCrCb_420_SP: @@ -326,7 +329,7 @@ int EmulatedFakeCamera2::allocateStream( *stream_id = mNextStreamId; if (format_actual) *format_actual = format; - *usage = GRALLOC_USAGE_SW_WRITE_OFTEN; + *usage = GRALLOC_USAGE_HW_CAMERA_WRITE; *max_buffers = 4; ALOGV("Stream allocated: %d, %d x %d, 0x%x. U: %x, B: %d", @@ -340,9 +343,42 @@ int EmulatedFakeCamera2::registerStreamBuffers( uint32_t stream_id, int num_buffers, buffer_handle_t *buffers) { - // Emulator doesn't need to register these with V4L2, etc. + Mutex::Autolock l(mMutex); + ALOGV("%s: Stream %d registering %d buffers", __FUNCTION__, stream_id, num_buffers); + // Need to find out what the final concrete pixel format for our stream is + // Assumes that all buffers have the same format. + if (num_buffers < 1) { + ALOGE("%s: Stream %d only has %d buffers!", + __FUNCTION__, stream_id, num_buffers); + return BAD_VALUE; + } + const cb_handle_t *streamBuffer = + reinterpret_cast(buffers[0]); + + int finalFormat = streamBuffer->format; + + if (finalFormat == GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO) { + ALOGE("%s: Stream %d: Bad final pixel format " + "GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO; " + "concrete pixel format required!", __FUNCTION__, stream_id); + return BAD_VALUE; + } + + ssize_t streamIndex = mStreams.indexOfKey(stream_id); + if (streamIndex < 0) { + ALOGE("%s: Unknown stream id %d!", __FUNCTION__, stream_id); + return BAD_VALUE; + } + + Stream &stream = mStreams.editValueAt(streamIndex); + + ALOGV("%s: Stream %d format set to %x, previously %x", + __FUNCTION__, stream_id, finalFormat, stream.format); + + stream.format = finalFormat; + return NO_ERROR; } @@ -593,7 +629,14 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() { mNextNeedsJpeg = false; ALOGV("Setting up buffers for capture"); for (size_t i = 0; i < streams.count; i++) { - const Stream &s = mParent->getStreamInfo(streams.data.u8[i]); + int streamId = streams.data.u8[i]; + const Stream &s = mParent->getStreamInfo(streamId); + if (s.format == GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO) { + ALOGE("%s: Stream %d does not have a concrete pixel format, but " + "is included in a request!", __FUNCTION__, streamId); + mParent->signalError(); + return false; + } StreamBuffer b; b.streamId = streams.data.u8[i]; b.width = s.width; @@ -708,7 +751,7 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() { const Rect rect(s.width, s.height); res = GraphicBufferMapper::get().lock(*(b.buffer), - GRALLOC_USAGE_SW_WRITE_OFTEN, + GRALLOC_USAGE_HW_CAMERA_WRITE, rect, (void**)&(b.img) ); if (res != NO_ERROR) { @@ -1220,7 +1263,7 @@ status_t EmulatedFakeCamera2::constructStaticInfo( sizeof(exposureCompensationRange)/sizeof(int32_t)); static const int32_t availableTargetFpsRanges[] = { - 5, 30 + 5, 30, 15, 30 }; ADD_OR_SIZE(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, availableTargetFpsRanges, diff --git a/tools/emulator/system/camera/fake-pipeline2/Base.h b/tools/emulator/system/camera/fake-pipeline2/Base.h index 7f6be16c7..f7ef9b1d6 100644 --- a/tools/emulator/system/camera/fake-pipeline2/Base.h +++ b/tools/emulator/system/camera/fake-pipeline2/Base.h @@ -43,7 +43,7 @@ typedef Vector Buffers; struct Stream { const camera2_stream_ops_t *ops; uint32_t width, height; - uint32_t format; + int32_t format; uint32_t stride; }; diff --git a/tools/emulator/system/camera/fake-pipeline2/Sensor.cpp b/tools/emulator/system/camera/fake-pipeline2/Sensor.cpp index 29898b840..ca6908d89 100644 --- a/tools/emulator/system/camera/fake-pipeline2/Sensor.cpp +++ b/tools/emulator/system/camera/fake-pipeline2/Sensor.cpp @@ -247,7 +247,9 @@ bool Sensor::threadLoop() { nsecs_t captureTime = 0; nsecs_t startRealTime = systemTime(); - nsecs_t simulatedTime = startRealTime - mStartupTime; + // Stagefright cares about system time for timestamps, so base simulated + // time on that. + nsecs_t simulatedTime = startRealTime; nsecs_t frameEndRealTime = startRealTime + frameDuration; nsecs_t frameReadoutEndRealTime = startRealTime + kRowReadoutTime * kResolution[1]; @@ -312,8 +314,10 @@ bool Sensor::threadLoop() { captureRGB(bAux.img, gain, b.stride); mNextCapturedBuffers->push_back(bAux); break; - case HAL_PIXEL_FORMAT_YV12: case HAL_PIXEL_FORMAT_YCrCb_420_SP: + captureNV21(b.img, gain, b.stride); + break; + case HAL_PIXEL_FORMAT_YV12: // TODO: ALOGE("%s: Format %x is TODO", __FUNCTION__, b.format); break; @@ -390,11 +394,12 @@ void Sensor::captureRGBA(uint8_t *img, uint32_t gain, uint32_t stride) { float totalGain = gain/100.0 * kBaseGainFactor; // In fixed-point math, calculate total scaling from electrons to 8bpp int scale64x = 64 * totalGain * 255 / kMaxRawValue; - mScene.setReadoutPixel(0,0); + uint32_t inc = (stride == 320) ? 2 : 1; - for (unsigned int y = 0; y < kResolution[1]; y++ ) { - uint8_t *px = img + y * stride * 4; - for (unsigned int x = 0; x < kResolution[0]; x++) { + for (unsigned int y = 0, outY = 0; y < kResolution[1]; y+=inc, outY++ ) { + uint8_t *px = img + outY * stride * 4; + mScene.setReadoutPixel(0, y); + for (unsigned int x = 0; x < kResolution[0]; x+=inc) { uint32_t rCount, gCount, bCount; // TODO: Perfect demosaicing is a cheat const uint32_t *pixel = mScene.getPixelElectrons(); @@ -406,6 +411,7 @@ void Sensor::captureRGBA(uint8_t *img, uint32_t gain, uint32_t stride) { *px++ = gCount < 255*64 ? gCount / 64 : 255; *px++ = bCount < 255*64 ? bCount / 64 : 255; *px++ = 255; + if (inc == 2) mScene.getPixelElectrons(); } // TODO: Handle this better //simulatedTime += kRowReadoutTime; @@ -417,11 +423,12 @@ void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t stride) { float totalGain = gain/100.0 * kBaseGainFactor; // In fixed-point math, calculate total scaling from electrons to 8bpp int scale64x = 64 * totalGain * 255 / kMaxRawValue; - mScene.setReadoutPixel(0,0); + uint32_t inc = (stride == 320) ? 2 : 1; - for (unsigned int y = 0; y < kResolution[1]; y++ ) { - uint8_t *px = img + y * stride * 3; - for (unsigned int x = 0; x < kResolution[0]; x++) { + for (unsigned int y = 0, outY = 0; y < kResolution[1]; y += inc, outY++ ) { + mScene.setReadoutPixel(0, y); + uint8_t *px = img + outY * stride * 3; + for (unsigned int x = 0; x < kResolution[0]; x += inc) { uint32_t rCount, gCount, bCount; // TODO: Perfect demosaicing is a cheat const uint32_t *pixel = mScene.getPixelElectrons(); @@ -432,6 +439,7 @@ void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t stride) { *px++ = rCount < 255*64 ? rCount / 64 : 255; *px++ = gCount < 255*64 ? gCount / 64 : 255; *px++ = bCount < 255*64 ? bCount / 64 : 255; + if (inc == 2) mScene.getPixelElectrons(); } // TODO: Handle this better //simulatedTime += kRowReadoutTime; @@ -439,4 +447,39 @@ void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t stride) { ALOGVV("RGB sensor image captured"); } +void Sensor::captureNV21(uint8_t *img, uint32_t gain, uint32_t stride) { + float totalGain = gain/100.0 * kBaseGainFactor; + // In fixed-point math, calculate total scaling from electrons to 8bpp + int scale64x = 64 * totalGain * 255 / kMaxRawValue; + + // TODO: Make full-color + uint32_t inc = (stride == 320) ? 2 : 1; + uint32_t outH = kResolution[1] / inc; + for (unsigned int y = 0, outY = 0, outUV = outH; + y < kResolution[1]; y+=inc, outY++, outUV ) { + uint8_t *pxY = img + outY * stride; + mScene.setReadoutPixel(0,y); + for (unsigned int x = 0; x < kResolution[0]; x+=inc) { + uint32_t rCount, gCount, bCount; + // TODO: Perfect demosaicing is a cheat + const uint32_t *pixel = mScene.getPixelElectrons(); + rCount = pixel[Scene::R] * scale64x; + gCount = pixel[Scene::Gr] * scale64x; + bCount = pixel[Scene::B] * scale64x; + uint32_t avg = (rCount + gCount + bCount) / 3; + *pxY++ = avg < 255*64 ? avg / 64 : 255; + if (inc == 2) mScene.getPixelElectrons(); + } + } + for (unsigned int y = 0, outY = outH; y < kResolution[1]/2; y+=inc, outY++) { + uint8_t *px = img + outY * stride; + for (unsigned int x = 0; x < kResolution[0]; x+=inc) { + // UV to neutral + *px++ = 128; + *px++ = 128; + } + } + ALOGVV("NV21 sensor image captured"); +} + } // namespace android diff --git a/tools/emulator/system/camera/fake-pipeline2/Sensor.h b/tools/emulator/system/camera/fake-pipeline2/Sensor.h index a666cc387..2919be452 100644 --- a/tools/emulator/system/camera/fake-pipeline2/Sensor.h +++ b/tools/emulator/system/camera/fake-pipeline2/Sensor.h @@ -212,7 +212,7 @@ class Sensor: private Thread, public virtual RefBase { void captureRaw(uint8_t *img, uint32_t gain, uint32_t stride); void captureRGBA(uint8_t *img, uint32_t gain, uint32_t stride); void captureRGB(uint8_t *img, uint32_t gain, uint32_t stride); - + void captureNV21(uint8_t *img, uint32_t gain, uint32_t stride); }; } From 2318ff33c56c2a3956c7f9307613815f9270b920 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Wed, 25 Jul 2012 13:07:30 -0700 Subject: [PATCH 3/4] Camera2: Fix deadlock issues with getInProgressCount Bug: 6243944 Change-Id: Icb32e4b8c4a916eb7c97ac18767cadfc5122ec88 --- .../system/camera/EmulatedFakeCamera2.cpp | 36 +++++++++++-------- .../system/camera/EmulatedFakeCamera2.h | 7 ++-- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/tools/emulator/system/camera/EmulatedFakeCamera2.cpp b/tools/emulator/system/camera/EmulatedFakeCamera2.cpp index 711c2d2b6..9fcab91ba 100644 --- a/tools/emulator/system/camera/EmulatedFakeCamera2.cpp +++ b/tools/emulator/system/camera/EmulatedFakeCamera2.cpp @@ -517,7 +517,9 @@ void EmulatedFakeCamera2::signalError() { EmulatedFakeCamera2::ConfigureThread::ConfigureThread(EmulatedFakeCamera2 *parent): Thread(false), - mParent(parent) { + mParent(parent), + mNextBuffers(NULL), + mRequestCount(0) { mRunning = false; } @@ -567,8 +569,8 @@ bool EmulatedFakeCamera2::ConfigureThread::isStreamInUse(uint32_t id) { } int EmulatedFakeCamera2::ConfigureThread::getInProgressCount() { - Mutex::Autolock lock(mInternalsMutex); - return mNextBuffers == NULL ? 0 : 1; + Mutex::Autolock lock(mInputMutex); + return mRequestCount; } bool EmulatedFakeCamera2::ConfigureThread::threadLoop() { @@ -610,6 +612,9 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() { Mutex::Autolock lock(mInputMutex); mActive = false; return true; + } else { + Mutex::Autolock lock(mInputMutex); + mRequestCount++; } // Get necessary parameters for sensor config @@ -770,6 +775,10 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() { mRequest = NULL; mNextBuffers = NULL; + Mutex::Autolock lock(mInputMutex); + mRequestCount--; + + return true; } @@ -778,7 +787,9 @@ EmulatedFakeCamera2::ReadoutThread::ReadoutThread(EmulatedFakeCamera2 *parent): mParent(parent), mRunning(false), mActive(false), - mRequest(NULL) + mRequest(NULL), + mBuffers(NULL), + mRequestCount(0) { mInFlightQueue = new InFlightQueue[kInFlightQueueSize]; mInFlightHead = 0; @@ -818,6 +829,7 @@ void EmulatedFakeCamera2::ReadoutThread::setNextCapture( mInFlightQueue[mInFlightTail].request = request; mInFlightQueue[mInFlightTail].buffers = buffers; mInFlightTail = (mInFlightTail + 1) % kInFlightQueueSize; + mRequestCount++; if (!mActive) { mActive = true; @@ -850,14 +862,8 @@ bool EmulatedFakeCamera2::ReadoutThread::isStreamInUse(uint32_t id) { int EmulatedFakeCamera2::ReadoutThread::getInProgressCount() { Mutex::Autolock lock(mInputMutex); - Mutex::Autolock iLock(mInternalsMutex); - int requestCount = - ((mInFlightTail + kInFlightQueueSize) - mInFlightHead) - % kInFlightQueueSize; - requestCount += (mBuffers == NULL) ? 0 : 1; - - return requestCount; + return mRequestCount; } bool EmulatedFakeCamera2::ReadoutThread::threadLoop() { @@ -996,9 +1002,8 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() { ALOGV("Sending image buffer %d to output stream %d", i, b.streamId); GraphicBufferMapper::get().unlock(*(b.buffer)); - res = mParent->getStreamInfo(b.streamId).ops->enqueue_buffer( - mParent->getStreamInfo(b.streamId).ops, - captureTime, b.buffer); + const Stream &s = mParent->getStreamInfo(b.streamId); + res = s.ops->enqueue_buffer(s.ops, captureTime, b.buffer); if (res != OK) { ALOGE("Error enqueuing image buffer %p: %s (%d)", b.buffer, strerror(-res), res); @@ -1018,6 +1023,9 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() { mBuffers = NULL; } + Mutex::Autolock l(mInputMutex); + mRequestCount--; + return true; } diff --git a/tools/emulator/system/camera/EmulatedFakeCamera2.h b/tools/emulator/system/camera/EmulatedFakeCamera2.h index 9a0b67623..8af700b70 100644 --- a/tools/emulator/system/camera/EmulatedFakeCamera2.h +++ b/tools/emulator/system/camera/EmulatedFakeCamera2.h @@ -185,10 +185,11 @@ private: bool mRunning; bool threadLoop(); - Mutex mInputMutex; // Protects mActive + Mutex mInputMutex; // Protects mActive, mRequestCount Condition mInputSignal; bool mActive; // Whether we're waiting for input requests or actively // working on them + size_t mRequestCount; camera_metadata_t *mRequest; @@ -222,7 +223,7 @@ private: bool threadLoop(); // Inputs - Mutex mInputMutex; // Protects mActive, mInFlightQueue + Mutex mInputMutex; // Protects mActive, mInFlightQueue, mRequestCount Condition mInputSignal; bool mActive; @@ -235,6 +236,8 @@ private: size_t mInFlightHead; size_t mInFlightTail; + size_t mRequestCount; + // Internals Mutex mInternalsMutex; camera_metadata_t *mRequest; From 9b467d63802f0b96d6ab59227e4696de45c1d14d Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Wed, 25 Jul 2012 13:13:09 -0700 Subject: [PATCH 4/4] Camera2: Use lower resolutions for front fake camera To differentiate front/back fake camera, support a lower set of resolutions for the front camera processed and jpeg streams. Bug: 6243944 Change-Id: I4a8746500944f7b445e0e5f0a3f441885733a7a4 --- .../system/camera/EmulatedFakeCamera2.cpp | 60 ++++++++++++++----- .../system/camera/EmulatedFakeCamera2.h | 6 +- .../system/camera/fake-pipeline2/Sensor.cpp | 15 +++-- 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/tools/emulator/system/camera/EmulatedFakeCamera2.cpp b/tools/emulator/system/camera/EmulatedFakeCamera2.cpp index 9fcab91ba..f614f1d8b 100644 --- a/tools/emulator/system/camera/EmulatedFakeCamera2.cpp +++ b/tools/emulator/system/camera/EmulatedFakeCamera2.cpp @@ -48,20 +48,31 @@ const uint64_t EmulatedFakeCamera2::kAvailableRawMinDurations[1] = { Sensor::kFrameDurationRange[0] }; -const uint32_t EmulatedFakeCamera2::kAvailableProcessedSizes[4] = { +const uint32_t EmulatedFakeCamera2::kAvailableProcessedSizesBack[4] = { 640, 480, 320, 240 // Sensor::kResolution[0], Sensor::kResolution[1] }; +const uint32_t EmulatedFakeCamera2::kAvailableProcessedSizesFront[4] = { + 320, 240, 160, 120 + // Sensor::kResolution[0], Sensor::kResolution[1] +}; + const uint64_t EmulatedFakeCamera2::kAvailableProcessedMinDurations[1] = { Sensor::kFrameDurationRange[0] }; -const uint32_t EmulatedFakeCamera2::kAvailableJpegSizes[2] = { +const uint32_t EmulatedFakeCamera2::kAvailableJpegSizesBack[2] = { 640, 480 // Sensor::kResolution[0], Sensor::kResolution[1] }; +const uint32_t EmulatedFakeCamera2::kAvailableJpegSizesFront[2] = { + 320, 240 + // Sensor::kResolution[0], Sensor::kResolution[1] +}; + + const uint64_t EmulatedFakeCamera2::kAvailableJpegMinDurations[1] = { Sensor::kFrameDurationRange[0] }; @@ -265,15 +276,21 @@ int EmulatedFakeCamera2::allocateStream( availableSizeCount = sizeof(kAvailableRawSizes)/sizeof(uint32_t); break; case HAL_PIXEL_FORMAT_BLOB: - availableSizes = kAvailableJpegSizes; - availableSizeCount = sizeof(kAvailableJpegSizes)/sizeof(uint32_t); + availableSizes = mFacingBack ? + kAvailableJpegSizesBack : kAvailableJpegSizesFront; + availableSizeCount = mFacingBack ? + sizeof(kAvailableJpegSizesBack)/sizeof(uint32_t) : + sizeof(kAvailableJpegSizesFront)/sizeof(uint32_t); break; case GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO: case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_YV12: case HAL_PIXEL_FORMAT_YCrCb_420_SP: - availableSizes = kAvailableProcessedSizes; - availableSizeCount = sizeof(kAvailableProcessedSizes)/sizeof(uint32_t); + availableSizes = mFacingBack ? + kAvailableProcessedSizesBack : kAvailableProcessedSizesFront; + availableSizeCount = mFacingBack ? + sizeof(kAvailableProcessedSizesBack)/sizeof(uint32_t) : + sizeof(kAvailableProcessedSizesFront)/sizeof(uint32_t); break; default: ALOGE("%s: Unknown format 0x%x", __FUNCTION__, format); @@ -778,7 +795,6 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() { Mutex::Autolock lock(mInputMutex); mRequestCount--; - return true; } @@ -1012,6 +1028,7 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() { } } } + if (compressedBufferIndex == -1) { delete mBuffers; mBuffers = NULL; @@ -1172,17 +1189,29 @@ status_t EmulatedFakeCamera2::constructStaticInfo( kAvailableRawMinDurations, sizeof(kAvailableRawMinDurations)/sizeof(uint64_t)); - ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, - kAvailableProcessedSizes, - sizeof(kAvailableProcessedSizes)/sizeof(uint32_t)); + if (mFacingBack) { + ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, + kAvailableProcessedSizesBack, + sizeof(kAvailableProcessedSizesBack)/sizeof(uint32_t)); + } else { + ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, + kAvailableProcessedSizesFront, + sizeof(kAvailableProcessedSizesFront)/sizeof(uint32_t)); + } ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS, kAvailableProcessedMinDurations, sizeof(kAvailableProcessedMinDurations)/sizeof(uint64_t)); - ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_JPEG_SIZES, - kAvailableJpegSizes, - sizeof(kAvailableJpegSizes)/sizeof(uint32_t)); + if (mFacingBack) { + ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_JPEG_SIZES, + kAvailableJpegSizesBack, + sizeof(kAvailableJpegSizesBack)/sizeof(uint32_t)); + } else { + ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_JPEG_SIZES, + kAvailableJpegSizesFront, + sizeof(kAvailableJpegSizesFront)/sizeof(uint32_t)); + } ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS, kAvailableJpegMinDurations, @@ -1196,9 +1225,8 @@ status_t EmulatedFakeCamera2::constructStaticInfo( static const int32_t jpegThumbnailSizes[] = { 160, 120, - 320, 240, - 640, 480 - }; + 320, 240 + }; ADD_OR_SIZE(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, jpegThumbnailSizes, sizeof(jpegThumbnailSizes)/sizeof(int32_t)); diff --git a/tools/emulator/system/camera/EmulatedFakeCamera2.h b/tools/emulator/system/camera/EmulatedFakeCamera2.h index 8af700b70..5563c1d7a 100644 --- a/tools/emulator/system/camera/EmulatedFakeCamera2.h +++ b/tools/emulator/system/camera/EmulatedFakeCamera2.h @@ -255,9 +255,11 @@ private: static const uint32_t kAvailableFormats[]; static const uint32_t kAvailableRawSizes[]; static const uint64_t kAvailableRawMinDurations[]; - static const uint32_t kAvailableProcessedSizes[]; + static const uint32_t kAvailableProcessedSizesBack[]; + static const uint32_t kAvailableProcessedSizesFront[]; static const uint64_t kAvailableProcessedMinDurations[]; - static const uint32_t kAvailableJpegSizes[]; + static const uint32_t kAvailableJpegSizesBack[]; + static const uint32_t kAvailableJpegSizesFront[]; static const uint64_t kAvailableJpegMinDurations[]; /**************************************************************************** diff --git a/tools/emulator/system/camera/fake-pipeline2/Sensor.cpp b/tools/emulator/system/camera/fake-pipeline2/Sensor.cpp index ca6908d89..5eff98d4b 100644 --- a/tools/emulator/system/camera/fake-pipeline2/Sensor.cpp +++ b/tools/emulator/system/camera/fake-pipeline2/Sensor.cpp @@ -394,7 +394,7 @@ void Sensor::captureRGBA(uint8_t *img, uint32_t gain, uint32_t stride) { float totalGain = gain/100.0 * kBaseGainFactor; // In fixed-point math, calculate total scaling from electrons to 8bpp int scale64x = 64 * totalGain * 255 / kMaxRawValue; - uint32_t inc = (stride == 320) ? 2 : 1; + uint32_t inc = kResolution[0] / stride; for (unsigned int y = 0, outY = 0; y < kResolution[1]; y+=inc, outY++ ) { uint8_t *px = img + outY * stride * 4; @@ -411,7 +411,8 @@ void Sensor::captureRGBA(uint8_t *img, uint32_t gain, uint32_t stride) { *px++ = gCount < 255*64 ? gCount / 64 : 255; *px++ = bCount < 255*64 ? bCount / 64 : 255; *px++ = 255; - if (inc == 2) mScene.getPixelElectrons(); + for (unsigned int j = 1; j < inc; j++) + mScene.getPixelElectrons(); } // TODO: Handle this better //simulatedTime += kRowReadoutTime; @@ -423,7 +424,7 @@ void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t stride) { float totalGain = gain/100.0 * kBaseGainFactor; // In fixed-point math, calculate total scaling from electrons to 8bpp int scale64x = 64 * totalGain * 255 / kMaxRawValue; - uint32_t inc = (stride == 320) ? 2 : 1; + uint32_t inc = kResolution[0] / stride; for (unsigned int y = 0, outY = 0; y < kResolution[1]; y += inc, outY++ ) { mScene.setReadoutPixel(0, y); @@ -439,7 +440,8 @@ void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t stride) { *px++ = rCount < 255*64 ? rCount / 64 : 255; *px++ = gCount < 255*64 ? gCount / 64 : 255; *px++ = bCount < 255*64 ? bCount / 64 : 255; - if (inc == 2) mScene.getPixelElectrons(); + for (unsigned int j = 1; j < inc; j++) + mScene.getPixelElectrons(); } // TODO: Handle this better //simulatedTime += kRowReadoutTime; @@ -453,7 +455,7 @@ void Sensor::captureNV21(uint8_t *img, uint32_t gain, uint32_t stride) { int scale64x = 64 * totalGain * 255 / kMaxRawValue; // TODO: Make full-color - uint32_t inc = (stride == 320) ? 2 : 1; + uint32_t inc = kResolution[0] / stride; uint32_t outH = kResolution[1] / inc; for (unsigned int y = 0, outY = 0, outUV = outH; y < kResolution[1]; y+=inc, outY++, outUV ) { @@ -468,7 +470,8 @@ void Sensor::captureNV21(uint8_t *img, uint32_t gain, uint32_t stride) { bCount = pixel[Scene::B] * scale64x; uint32_t avg = (rCount + gCount + bCount) / 3; *pxY++ = avg < 255*64 ? avg / 64 : 255; - if (inc == 2) mScene.getPixelElectrons(); + for (unsigned int j = 1; j < inc; j++) + mScene.getPixelElectrons(); } } for (unsigned int y = 0, outY = outH; y < kResolution[1]/2; y+=inc, outY++) {