Loading automotive/evs/1.0/IEvsCamera.hal +3 −3 Original line number Diff line number Diff line Loading @@ -28,10 +28,10 @@ interface IEvsCamera { /** * Returns the ID of this camera. * * Returns the string id of this camera. This must be the same value as reported in * the camera_id field of the CameraDesc structure by EvsEnumerator::getCamerList(). * Returns the description of this camera. This must be the same value as reported * by EvsEnumerator::getCamerList(). */ getId() generates (string cameraId); getCameraInfo() generates (CameraDesc info); /** * Specifies the depth of the buffer chain the camera is asked to support. Loading automotive/evs/1.0/IEvsDisplay.hal +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ interface IEvsDisplay { /** * Returns basic information about the EVS display provided by the system. * * See the description of the DisplayDesc structure below for details. * See the description of the DisplayDesc structure for details. */ getDisplayInfo() generates (DisplayDesc info); Loading automotive/evs/1.0/IEvsEnumerator.hal +8 −5 Original line number Diff line number Diff line Loading @@ -31,14 +31,14 @@ interface IEvsEnumerator { */ getCameraList() generates (vec<CameraDesc> cameras); /** * Get the IEvsCamera associated with a cameraId from a CameraDesc * * Given a camera's unique cameraId from ca CameraDesc, returns * the ICamera interface assocaited with the specified camera. * When done using the camera, it must be returned by calling * closeCamera on the ICamera interface. * the ICamera interface associated with the specified camera. * When done using the camera, the caller may release it by calling closeCamera(). * TODO(b/36122635) Reliance on the sp<> going out of scope is not recommended because the * resources may not be released right away due to asynchronos behavior in the hardware binder. */ openCamera(string cameraId) generates (IEvsCamera carCamera); Loading @@ -57,6 +57,9 @@ interface IEvsEnumerator { * There can be at most one EVS display object for the system and this function * requests access to it. If the EVS display is not available or is already in use, * a null pointer is returned. * When done using the display, the caller may release it by calling closeDisplay(). * TODO(b/36122635) Reliance on the sp<> going out of scope is not recommended because the * resources may not be released right away due to asynchronos behavior in the hardware binder. */ openDisplay() generates (IEvsDisplay display); Loading @@ -64,7 +67,7 @@ interface IEvsEnumerator { * Return the specified IEvsDisplay interface as no longer in use * * When the IEvsDisplay object is no longer required, it must be released. * NOTE: All buffer must have been returned to the display before making this call. * NOTE: All buffers must have been returned to the display before making this call. */ closeDisplay(IEvsDisplay display); Loading automotive/evs/1.0/default/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -23,4 +23,9 @@ cc_binary { "liblog", "libutils", ], cflags: [ "-O0", "-g", ], } automotive/evs/1.0/default/EvsCamera.cpp +67 −33 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #define LOG_TAG "android.hardware.automotive.evs@1.0-service" #include "EvsCamera.h" #include "EvsEnumerator.h" #include <ui/GraphicBufferAllocator.h> #include <ui/GraphicBufferMapper.h> Loading @@ -30,18 +31,15 @@ namespace V1_0 { namespace implementation { // These are the special camera names for which we'll initialize custom test data // Special camera names for which we'll initialize alternate test data const char EvsCamera::kCameraName_Backup[] = "backup"; const char EvsCamera::kCameraName_RightTurn[] = "Right Turn"; // Arbitrary limit on number of graphics buffers allowed to be allocated // Safeguards against unreasonable resource consumption and provides a testable limit const unsigned MAX_BUFFERS_IN_FLIGHT = 100; // TODO(b/31632518): Need to get notification when our client dies so we can close the camera. // As it stands, if the client dies suddenly, the buffer may be stranded. EvsCamera::EvsCamera(const char *id) : mFramesAllowed(0), mFramesInUse(0), Loading @@ -53,22 +51,14 @@ EvsCamera::EvsCamera(const char *id) : // Set up dummy data for testing if (mDescription.cameraId == kCameraName_Backup) { mDescription.hints = static_cast<uint32_t>(UsageHint::USAGE_HINT_REVERSE); mWidth = 640; // full NTSC/VGA mHeight = 480; // full NTSC/VGA mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value mDescription.defaultHorResolution = 320; // 1/2 NTSC/VGA mDescription.defaultVerResolution = 240; // 1/2 NTSC/VGA } else if (mDescription.cameraId == kCameraName_RightTurn) { // Nothing but the name and the usage hint mDescription.hints = static_cast<uint32_t>(UsageHint::USAGE_HINT_RIGHT_TURN); } else { // Leave empty for a minimalist camera description without even a hint mWidth = 320; // 1/2 NTSC/VGA mHeight = 240; // 1/2 NTSC/VGA } // Set our buffer properties mWidth = (mDescription.defaultHorResolution) ? mDescription.defaultHorResolution : 640; mHeight = (mDescription.defaultVerResolution) ? mDescription.defaultVerResolution : 480; mFormat = HAL_PIXEL_FORMAT_RGBA_8888; mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; Loading @@ -77,13 +67,26 @@ EvsCamera::EvsCamera(const char *id) : EvsCamera::~EvsCamera() { ALOGD("EvsCamera being destroyed"); std::lock_guard<std::mutex> lock(mAccessLock); forceShutdown(); } // // This gets called if another caller "steals" ownership of the camera // void EvsCamera::forceShutdown() { ALOGD("EvsCamera forceShutdown"); // Make sure our output stream is cleaned up // (It really should be already) stopVideoStream(); // Claim the lock while we work on internal state std::lock_guard <std::mutex> lock(mAccessLock); // Drop all the graphics buffers we've been using if (mBuffers.size() > 0) { GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); for (auto&& rec : mBuffers) { if (rec.inUse) { Loading @@ -92,17 +95,21 @@ EvsCamera::~EvsCamera() { alloc.free(rec.handle); rec.handle = nullptr; } mBuffers.clear(); } ALOGD("EvsCamera destroyed"); // Put this object into an unrecoverable error state since somebody else // is going to own the underlying camera now mStreamState = DEAD; } // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow. Return<void> EvsCamera::getId(getId_cb id_cb) { ALOGD("getId"); id_cb(mDescription.cameraId); Return<void> EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) { ALOGD("getCameraInfo"); // Send back our self description _hidl_cb(mDescription); return Void(); } Loading @@ -111,6 +118,12 @@ Return<EvsResult> EvsCamera::setMaxFramesInFlight(uint32_t bufferCount) { ALOGD("setMaxFramesInFlight"); std::lock_guard<std::mutex> lock(mAccessLock); // If we've been displaced by another owner of the camera, then we can't do anything else if (mStreamState == DEAD) { ALOGE("ignoring setMaxFramesInFlight call when camera has been lost."); return EvsResult::OWNERSHIP_LOST; } // We cannot function without at least one video buffer to send data if (bufferCount < 1) { ALOGE("Ignoring setMaxFramesInFlight with less than one buffer requested"); Loading @@ -130,6 +143,11 @@ Return<EvsResult> EvsCamera::startVideoStream(const ::android::sp<IEvsCameraStre ALOGD("startVideoStream"); std::lock_guard<std::mutex> lock(mAccessLock); // If we've been displaced by another owner of the camera, then we can't do anything else if (mStreamState == DEAD) { ALOGE("ignoring startVideoStream call when camera has been lost."); return EvsResult::OWNERSHIP_LOST; } if (mStreamState != STOPPED) { ALOGE("ignoring startVideoStream call when a stream is already running."); return EvsResult::STREAM_ALREADY_RUNNING; Loading Loading @@ -207,6 +225,7 @@ Return<void> EvsCamera::stopVideoStream() { lock.lock(); mStreamState = STOPPED; mStream = nullptr; ALOGD("Stream marked STOPPED."); } Loading @@ -232,6 +251,12 @@ Return<EvsResult> EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int3 ALOGD("setExtendedInfo"); std::lock_guard<std::mutex> lock(mAccessLock); // If we've been displaced by another owner of the camera, then we can't do anything else if (mStreamState == DEAD) { ALOGE("ignoring setExtendedInfo call when camera has been lost."); return EvsResult::OWNERSHIP_LOST; } // We don't store any device specific information in this implementation return EvsResult::INVALID_ARG; } Loading Loading @@ -358,7 +383,9 @@ void EvsCamera::generateFrames() { while (true) { bool timeForFrame = false; // Lock scope nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); // Lock scope for updating shared state { std::lock_guard<std::mutex> lock(mAccessLock); Loading Loading @@ -427,8 +454,15 @@ void EvsCamera::generateFrames() { } } // We arbitrarily choose to generate frames at 10 fps (1/10 * uSecPerSec) usleep(100000); // We arbitrarily choose to generate frames at 12 fps to ensure we pass the 10fps test requirement static const int kTargetFrameRate = 12; static const nsecs_t kTargetFrameTimeUs = 1000*1000 / kTargetFrameRate; const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); const nsecs_t workTimeUs = (now - startTime) / 1000; const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs; if (sleepDurationUs > 0) { usleep(sleepDurationUs); } } // If we've been asked to stop, send one last NULL frame to signal the actual end of stream Loading Loading
automotive/evs/1.0/IEvsCamera.hal +3 −3 Original line number Diff line number Diff line Loading @@ -28,10 +28,10 @@ interface IEvsCamera { /** * Returns the ID of this camera. * * Returns the string id of this camera. This must be the same value as reported in * the camera_id field of the CameraDesc structure by EvsEnumerator::getCamerList(). * Returns the description of this camera. This must be the same value as reported * by EvsEnumerator::getCamerList(). */ getId() generates (string cameraId); getCameraInfo() generates (CameraDesc info); /** * Specifies the depth of the buffer chain the camera is asked to support. Loading
automotive/evs/1.0/IEvsDisplay.hal +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ interface IEvsDisplay { /** * Returns basic information about the EVS display provided by the system. * * See the description of the DisplayDesc structure below for details. * See the description of the DisplayDesc structure for details. */ getDisplayInfo() generates (DisplayDesc info); Loading
automotive/evs/1.0/IEvsEnumerator.hal +8 −5 Original line number Diff line number Diff line Loading @@ -31,14 +31,14 @@ interface IEvsEnumerator { */ getCameraList() generates (vec<CameraDesc> cameras); /** * Get the IEvsCamera associated with a cameraId from a CameraDesc * * Given a camera's unique cameraId from ca CameraDesc, returns * the ICamera interface assocaited with the specified camera. * When done using the camera, it must be returned by calling * closeCamera on the ICamera interface. * the ICamera interface associated with the specified camera. * When done using the camera, the caller may release it by calling closeCamera(). * TODO(b/36122635) Reliance on the sp<> going out of scope is not recommended because the * resources may not be released right away due to asynchronos behavior in the hardware binder. */ openCamera(string cameraId) generates (IEvsCamera carCamera); Loading @@ -57,6 +57,9 @@ interface IEvsEnumerator { * There can be at most one EVS display object for the system and this function * requests access to it. If the EVS display is not available or is already in use, * a null pointer is returned. * When done using the display, the caller may release it by calling closeDisplay(). * TODO(b/36122635) Reliance on the sp<> going out of scope is not recommended because the * resources may not be released right away due to asynchronos behavior in the hardware binder. */ openDisplay() generates (IEvsDisplay display); Loading @@ -64,7 +67,7 @@ interface IEvsEnumerator { * Return the specified IEvsDisplay interface as no longer in use * * When the IEvsDisplay object is no longer required, it must be released. * NOTE: All buffer must have been returned to the display before making this call. * NOTE: All buffers must have been returned to the display before making this call. */ closeDisplay(IEvsDisplay display); Loading
automotive/evs/1.0/default/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -23,4 +23,9 @@ cc_binary { "liblog", "libutils", ], cflags: [ "-O0", "-g", ], }
automotive/evs/1.0/default/EvsCamera.cpp +67 −33 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #define LOG_TAG "android.hardware.automotive.evs@1.0-service" #include "EvsCamera.h" #include "EvsEnumerator.h" #include <ui/GraphicBufferAllocator.h> #include <ui/GraphicBufferMapper.h> Loading @@ -30,18 +31,15 @@ namespace V1_0 { namespace implementation { // These are the special camera names for which we'll initialize custom test data // Special camera names for which we'll initialize alternate test data const char EvsCamera::kCameraName_Backup[] = "backup"; const char EvsCamera::kCameraName_RightTurn[] = "Right Turn"; // Arbitrary limit on number of graphics buffers allowed to be allocated // Safeguards against unreasonable resource consumption and provides a testable limit const unsigned MAX_BUFFERS_IN_FLIGHT = 100; // TODO(b/31632518): Need to get notification when our client dies so we can close the camera. // As it stands, if the client dies suddenly, the buffer may be stranded. EvsCamera::EvsCamera(const char *id) : mFramesAllowed(0), mFramesInUse(0), Loading @@ -53,22 +51,14 @@ EvsCamera::EvsCamera(const char *id) : // Set up dummy data for testing if (mDescription.cameraId == kCameraName_Backup) { mDescription.hints = static_cast<uint32_t>(UsageHint::USAGE_HINT_REVERSE); mWidth = 640; // full NTSC/VGA mHeight = 480; // full NTSC/VGA mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value mDescription.defaultHorResolution = 320; // 1/2 NTSC/VGA mDescription.defaultVerResolution = 240; // 1/2 NTSC/VGA } else if (mDescription.cameraId == kCameraName_RightTurn) { // Nothing but the name and the usage hint mDescription.hints = static_cast<uint32_t>(UsageHint::USAGE_HINT_RIGHT_TURN); } else { // Leave empty for a minimalist camera description without even a hint mWidth = 320; // 1/2 NTSC/VGA mHeight = 240; // 1/2 NTSC/VGA } // Set our buffer properties mWidth = (mDescription.defaultHorResolution) ? mDescription.defaultHorResolution : 640; mHeight = (mDescription.defaultVerResolution) ? mDescription.defaultVerResolution : 480; mFormat = HAL_PIXEL_FORMAT_RGBA_8888; mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; Loading @@ -77,13 +67,26 @@ EvsCamera::EvsCamera(const char *id) : EvsCamera::~EvsCamera() { ALOGD("EvsCamera being destroyed"); std::lock_guard<std::mutex> lock(mAccessLock); forceShutdown(); } // // This gets called if another caller "steals" ownership of the camera // void EvsCamera::forceShutdown() { ALOGD("EvsCamera forceShutdown"); // Make sure our output stream is cleaned up // (It really should be already) stopVideoStream(); // Claim the lock while we work on internal state std::lock_guard <std::mutex> lock(mAccessLock); // Drop all the graphics buffers we've been using if (mBuffers.size() > 0) { GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); for (auto&& rec : mBuffers) { if (rec.inUse) { Loading @@ -92,17 +95,21 @@ EvsCamera::~EvsCamera() { alloc.free(rec.handle); rec.handle = nullptr; } mBuffers.clear(); } ALOGD("EvsCamera destroyed"); // Put this object into an unrecoverable error state since somebody else // is going to own the underlying camera now mStreamState = DEAD; } // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow. Return<void> EvsCamera::getId(getId_cb id_cb) { ALOGD("getId"); id_cb(mDescription.cameraId); Return<void> EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) { ALOGD("getCameraInfo"); // Send back our self description _hidl_cb(mDescription); return Void(); } Loading @@ -111,6 +118,12 @@ Return<EvsResult> EvsCamera::setMaxFramesInFlight(uint32_t bufferCount) { ALOGD("setMaxFramesInFlight"); std::lock_guard<std::mutex> lock(mAccessLock); // If we've been displaced by another owner of the camera, then we can't do anything else if (mStreamState == DEAD) { ALOGE("ignoring setMaxFramesInFlight call when camera has been lost."); return EvsResult::OWNERSHIP_LOST; } // We cannot function without at least one video buffer to send data if (bufferCount < 1) { ALOGE("Ignoring setMaxFramesInFlight with less than one buffer requested"); Loading @@ -130,6 +143,11 @@ Return<EvsResult> EvsCamera::startVideoStream(const ::android::sp<IEvsCameraStre ALOGD("startVideoStream"); std::lock_guard<std::mutex> lock(mAccessLock); // If we've been displaced by another owner of the camera, then we can't do anything else if (mStreamState == DEAD) { ALOGE("ignoring startVideoStream call when camera has been lost."); return EvsResult::OWNERSHIP_LOST; } if (mStreamState != STOPPED) { ALOGE("ignoring startVideoStream call when a stream is already running."); return EvsResult::STREAM_ALREADY_RUNNING; Loading Loading @@ -207,6 +225,7 @@ Return<void> EvsCamera::stopVideoStream() { lock.lock(); mStreamState = STOPPED; mStream = nullptr; ALOGD("Stream marked STOPPED."); } Loading @@ -232,6 +251,12 @@ Return<EvsResult> EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int3 ALOGD("setExtendedInfo"); std::lock_guard<std::mutex> lock(mAccessLock); // If we've been displaced by another owner of the camera, then we can't do anything else if (mStreamState == DEAD) { ALOGE("ignoring setExtendedInfo call when camera has been lost."); return EvsResult::OWNERSHIP_LOST; } // We don't store any device specific information in this implementation return EvsResult::INVALID_ARG; } Loading Loading @@ -358,7 +383,9 @@ void EvsCamera::generateFrames() { while (true) { bool timeForFrame = false; // Lock scope nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); // Lock scope for updating shared state { std::lock_guard<std::mutex> lock(mAccessLock); Loading Loading @@ -427,8 +454,15 @@ void EvsCamera::generateFrames() { } } // We arbitrarily choose to generate frames at 10 fps (1/10 * uSecPerSec) usleep(100000); // We arbitrarily choose to generate frames at 12 fps to ensure we pass the 10fps test requirement static const int kTargetFrameRate = 12; static const nsecs_t kTargetFrameTimeUs = 1000*1000 / kTargetFrameRate; const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); const nsecs_t workTimeUs = (now - startTime) / 1000; const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs; if (sleepDurationUs > 0) { usleep(sleepDurationUs); } } // If we've been asked to stop, send one last NULL frame to signal the actual end of stream Loading