Merge "camera3: Add flush"
diff --git a/include/hardware/audio.h b/include/hardware/audio.h
index 3a0962e..b0c0c0e 100644
--- a/include/hardware/audio.h
+++ b/include/hardware/audio.h
@@ -67,6 +67,7 @@
#define AUDIO_HARDWARE_MODULE_ID_A2DP "a2dp"
#define AUDIO_HARDWARE_MODULE_ID_USB "usb"
#define AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX "r_submix"
+#define AUDIO_HARDWARE_MODULE_ID_CODEC_OFFLOAD "codec_offload"
/**************************************/
@@ -117,16 +118,35 @@
* "sup_sampling_rates=44100|48000" */
#define AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES "sup_sampling_rates"
+/**
+ * audio codec parameters
+ */
+
+#define AUDIO_OFFLOAD_CODEC_PARAMS "music_offload_codec_param"
+#define AUDIO_OFFLOAD_CODEC_BIT_PER_SAMPLE "music_offload_bit_per_sample"
+#define AUDIO_OFFLOAD_CODEC_BIT_RATE "music_offload_bit_rate"
+#define AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE "music_offload_avg_bit_rate"
+#define AUDIO_OFFLOAD_CODEC_ID "music_offload_codec_id"
+#define AUDIO_OFFLOAD_CODEC_BLOCK_ALIGN "music_offload_block_align"
+#define AUDIO_OFFLOAD_CODEC_SAMPLE_RATE "music_offload_sample_rate"
+#define AUDIO_OFFLOAD_CODEC_ENCODE_OPTION "music_offload_encode_option"
+#define AUDIO_OFFLOAD_CODEC_NUM_CHANNEL "music_offload_num_channels"
+#define AUDIO_OFFLOAD_CODEC_DOWN_SAMPLING "music_offload_down_sampling"
+#define AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES "delay_samples"
+#define AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES "padding_samples"
/**************************************/
-/* common audio stream configuration parameters */
+/* common audio stream configuration parameters
+ * You should memset() the entire structure to zero before use to
+ * ensure forward compatibility
+ */
struct audio_config {
uint32_t sample_rate;
audio_channel_mask_t channel_mask;
audio_format_t format;
+ audio_offload_info_t offload_info;
};
-
typedef struct audio_config audio_config_t;
/* common audio stream parameters and operations */
@@ -213,6 +233,22 @@
};
typedef struct audio_stream audio_stream_t;
+/* type of asynchronous write callback events. Mutually exclusive */
+typedef enum {
+ STREAM_CBK_EVENT_WRITE_READY, /* non blocking write completed */
+ STREAM_CBK_EVENT_DRAIN_READY /* drain completed */
+} stream_callback_event_t;
+
+typedef int (*stream_callback_t)(stream_callback_event_t event, void *param, void *cookie);
+
+/* type of drain requested to audio_stream_out->drain(). Mutually exclusive */
+typedef enum {
+ AUDIO_DRAIN_ALL, /* drain() returns when all data has been played */
+ AUDIO_DRAIN_EARLY_NOTIFY /* drain() returns a short time before all data
+ from the current track has been played to
+ give time for gapless track switch */
+} audio_drain_type_t;
+
/**
* audio_stream_out is the abstraction interface for the audio output hardware.
*
@@ -242,6 +278,13 @@
* negative status_t. If at least one frame was written successfully prior to the error,
* it is suggested that the driver return that successful (short) byte count
* and then return an error in the subsequent call.
+ *
+ * If set_callback() has previously been called to enable non-blocking mode
+ * the write() is not allowed to block. It must write only the number of
+ * bytes that currently fit in the driver/hardware buffer and then return
+ * this byte count. If this is less than the requested write size the
+ * callback function must be called when more space is available in the
+ * driver/hardware buffer.
*/
ssize_t (*write)(struct audio_stream_out *stream, const void* buffer,
size_t bytes);
@@ -259,6 +302,60 @@
int (*get_next_write_timestamp)(const struct audio_stream_out *stream,
int64_t *timestamp);
+ /**
+ * set the callback function for notifying completion of non-blocking
+ * write and drain.
+ * Calling this function implies that all future write() and drain()
+ * must be non-blocking and use the callback to signal completion.
+ */
+ int (*set_callback)(struct audio_stream_out *stream,
+ stream_callback_t callback, void *cookie);
+
+ /**
+ * Notifies to the audio driver to stop playback however the queued buffers are
+ * retained by the hardware. Useful for implementing pause/resume. Empty implementation
+ * if not supported however should be implemented for hardware with non-trivial
+ * latency. In the pause state audio hardware could still be using power. User may
+ * consider calling suspend after a timeout.
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ */
+ int (*pause)(struct audio_stream_out* stream);
+
+ /**
+ * Notifies to the audio driver to resume playback following a pause.
+ * Returns error if called without matching pause.
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ */
+ int (*resume)(struct audio_stream_out* stream);
+
+ /**
+ * Requests notification when data buffered by the driver/hardware has
+ * been played. If set_callback() has previously been called to enable
+ * non-blocking mode, the drain() must not block, instead it should return
+ * quickly and completion of the drain is notified through the callback.
+ * If set_callback() has not been called, the drain() must block until
+ * completion.
+ * If type==AUDIO_DRAIN_ALL, the drain completes when all previously written
+ * data has been played.
+ * If type==AUDIO_DRAIN_EARLY_NOTIFY, the drain completes shortly before all
+ * data for the current track has played to allow time for the framework
+ * to perform a gapless track switch.
+ *
+ * Drain must return immediately on stop() and flush() call
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ */
+ int (*drain)(struct audio_stream_out* stream, audio_drain_type_t type );
+
+ /**
+ * Notifies to the audio driver to flush the queued data. Stream must already
+ * be paused before calling flush().
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ */
+ int (*flush)(struct audio_stream_out* stream);
};
typedef struct audio_stream_out audio_stream_out_t;
@@ -296,18 +393,14 @@
static inline size_t audio_stream_frame_size(const struct audio_stream *s)
{
size_t chan_samp_sz;
+ audio_format_t format = s->get_format(s);
- switch (s->get_format(s)) {
- case AUDIO_FORMAT_PCM_16_BIT:
- chan_samp_sz = sizeof(int16_t);
- break;
- case AUDIO_FORMAT_PCM_8_BIT:
- default:
- chan_samp_sz = sizeof(int8_t);
- break;
+ if (audio_is_linear_pcm(format)) {
+ chan_samp_sz = audio_bytes_per_sample(format);
+ return popcount(s->get_channels(s)) * chan_samp_sz;
}
- return popcount(s->get_channels(s)) * chan_samp_sz;
+ return sizeof(int8_t);
}
diff --git a/include/hardware/audio_policy.h b/include/hardware/audio_policy.h
index c635ebf..4e75e02 100644
--- a/include/hardware/audio_policy.h
+++ b/include/hardware/audio_policy.h
@@ -133,7 +133,8 @@
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- audio_output_flags_t flags);
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo);
/* indicates to the audio policy manager that the output starts being used
* by corresponding stream. */
@@ -241,6 +242,10 @@
/* dump state */
int (*dump)(const struct audio_policy *pol, int fd);
+
+ /* check if offload is possible for given sample rate, bitrate, duration, ... */
+ bool (*is_offload_supported)(const struct audio_policy *pol,
+ const audio_offload_info_t *info);
};
/* audio hw module handle used by load_hw_module(), open_output_on_module()
@@ -390,7 +395,8 @@
audio_format_t *pFormat,
audio_channel_mask_t *pChannelMask,
uint32_t *pLatencyMs,
- audio_output_flags_t flags);
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo);
/* Opens an audio input on a particular HW module.
*
diff --git a/include/hardware/bluetooth.h b/include/hardware/bluetooth.h
index 2741332..c00a8f7 100755
--- a/include/hardware/bluetooth.h
+++ b/include/hardware/bluetooth.h
@@ -451,6 +451,8 @@
/* opcode MUST be one of: LE_Receiver_Test, LE_Transmitter_Test, LE_Test_End */
int (*le_test_mode)(uint16_t opcode, uint8_t *buf, uint8_t len);
+ /* enable or disable bluetooth HCI snoop log */
+ int (*config_hci_snoop_log)(uint8_t enable);
} bt_interface_t;
/** TODO: Need to add APIs for Service Discovery, Service authorization and
diff --git a/include/hardware/fused_location.h b/include/hardware/fused_location.h
index f61575d..fecf822 100644
--- a/include/hardware/fused_location.h
+++ b/include/hardware/fused_location.h
@@ -49,7 +49,7 @@
/**
* Name for the FLP location interface
*/
-#define FLP_DEBUG_INTERFACE "flp_debug"
+#define FLP_DIAGNOSTIC_INTERFACE "flp_diagnostic"
/**
* Name for the FLP_Geofencing interface.
@@ -57,6 +57,11 @@
#define FLP_GEOFENCING_INTERFACE "flp_geofencing"
/**
+ * Name for the FLP_device context interface.
+ */
+#define FLP_DEVICE_CONTEXT_INTERFACE "flp_device_context"
+
+/**
* Constants to indicate the various subsystems
* that will be used.
*/
@@ -84,6 +89,8 @@
* fix has been obtained. This flag controls that option.
* Its the responsibility of the upper layers (caller) to switch
* it off, if it knows that the AP might go to sleep.
+ * When this bit is on amidst a batching session, batching should
+ * continue while location fixes are reported in real time.
*/
#define FLP_BATCH_CALLBACK_ON_LOCATION_FIX 0x0000002
@@ -149,7 +156,7 @@
/**
* Callback with location information.
- * Can only be called from a thread created by create_thread_cb.
+ * Can only be called from a thread associated to JVM using set_thread_event_cb.
* Parameters:
* num_locations is the number of batched locations available.
* location is the pointer to an array of pointers to location objects.
@@ -168,10 +175,13 @@
typedef void (*flp_release_wakelock)();
/**
- * Callback for creating a thread that can call into the Java framework code.
- * This must be used to create any threads that report events up to the framework.
+ * Callback for associating a thread that can call into the Java framework code.
+ * This must be used to initialize any threads that report events up to the framework.
+ * Return value:
+ * FLP_RESULT_SUCCESS on success.
+ * FLP_RESULT_ERROR if the association failed in the current thread.
*/
-typedef pthread_t (*flp_create_thread)(ThreadEvent event);
+typedef int (*flp_set_thread_event)(ThreadEvent event);
/** FLP callback structure. */
typedef struct {
@@ -180,7 +190,7 @@
flp_location_callback location_cb;
flp_acquire_wakelock acquire_wakelock_cb;
flp_release_wakelock release_wakelock_cb;
- flp_create_thread create_thread_cb;
+ flp_set_thread_event set_thread_event_cb;
} FlpCallbacks;
@@ -189,6 +199,8 @@
/**
* Maximum power in mW that the underlying implementation
* can use for this batching call.
+ * If max_power_allocation_mW is 0, only fixes that are generated
+ * at no additional cost of power shall be reported.
*/
double max_power_allocation_mW;
@@ -203,7 +215,9 @@
* FLP_BATCH_CALLBACK_ON_LOCATION_FIX - If set the location
* callback will be called every time there is a location fix.
* Its the responsibility of the upper layers (caller) to switch
- * it off, if it knows that the AP might go to sleep.
+ * it off, if it knows that the AP might go to sleep. When this
+ * bit is on amidst a batching session, batching should continue
+ * while location fixes are reported in real time.
*
* Other flags to be bitwised ORed in the future.
*/
@@ -240,7 +254,10 @@
int (*init)(FlpCallbacks* callbacks );
/**
- * Return the batch size (in bytes) available in the hardware.
+ * Return the batch size (in number of FlpLocation objects)
+ * available in the hardware. Note, different HW implementations
+ * may have different sample sizes. This shall return number
+ * of samples defined in the format of FlpLocation.
* This will be used by the upper layer, to decide on the batching
* interval and whether the AP should be woken up or not.
*/
@@ -341,32 +358,74 @@
};
/**
- * FLP debug callback structure.
+ * Callback for reports diagnostic data into the Java framework code.
+*/
+typedef void (*report_data)(char* data, int length);
+
+/**
+ * FLP diagnostic callback structure.
* Currently, not used - but this for future extension.
*/
typedef struct {
- /** set to sizeof(FlpDebugCallbacks) */
+ /** set to sizeof(FlpDiagnosticCallbacks) */
size_t size;
- flp_create_thread create_thread_cb;
-} FlpDebugCallbacks;
-/** Extended interface for debug support. */
+ flp_set_thread_event set_thread_event_cb;
+
+ /** reports diagnostic data into the Java framework code */
+ report_data data_cb;
+} FlpDiagnosticCallbacks;
+
+/** Extended interface for diagnostic support. */
typedef struct {
- /** set to sizeof(FlpDebugInterface) */
+ /** set to sizeof(FlpDiagnosticInterface) */
size_t size;
/**
- * Opens the debug interface and provides the callback routines
+ * Opens the diagnostic interface and provides the callback routines
* to the implemenation of this interface.
*/
- void (*init)(FlpDebugCallbacks* callbacks);
+ void (*init)(FlpDiagnosticCallbacks* callbacks);
+
+ /**
+ * Injects diagnostic data into the FLP subsystem.
+ * Return 0 on success, -1 on error.
+ **/
+ int (*inject_data)(char* data, int length );
+} FlpDiagnosticInterface;
+
+/**
+ * Context setting information.
+ * All these settings shall be injected to FLP HAL at FLP init time.
+ * Following that, only the changed setting need to be re-injected
+ * upon changes.
+ */
+
+#define FLP_DEVICE_CONTEXT_GPS_ENABLED (1U<<0)
+#define FLP_DEVICE_CONTEXT_AGPS_ENABLED (1U<<1)
+#define FLP_DEVICE_CONTEXT_NETWORK_POSITIONING_ENABLED (1U<<2)
+#define FLP_DEVICE_CONTEXT_WIFI_CONNECTIVITY_ENABLED (1U<<3)
+#define FLP_DEVICE_CONTEXT_WIFI_POSITIONING_ENABLED (1U<<4)
+#define FIP_DEVICE_CONTEXT_HW_NETWORK_POSITIONING ENABLED (1U<<5)
+#define FLP_DEVICE_CONTEXT_AIRPLANE_MODE_ON (1U<<6)
+#define FLP_DEVICE_CONTEXT_DATA_ENABLED (1U<<7)
+#define FLP_DEVICE_CONTEXT_ROAMING_ENABLED (1U<<8)
+#define FLP_DEVICE_CONTEXT_CURRENTLY_ROAMING (1U<<9)
+#define FLP_DEVICE_CONTEXT_SENSOR_ENABLED (1U<<10)
+#define FLP_DEVICE_CONTEXT_BLUETOOTH_ENABLED (1U<<11)
+#define FLP_DEVICE_CONTEXT_CHARGER_ON (1U<<12)
+
+/** Extended interface for device context support. */
+typedef struct {
+ /** set to sizeof(FlpDeviceContextInterface) */
+ size_t size;
/**
* Injects debug data into the FLP subsystem.
* Return 0 on success, -1 on error.
**/
- int (*inject_debug_data)(char* data, int length );
-} FlpDebugInterface;
+ int (*inject_device_context)(uint32_t enabledMask);
+} FlpDeviceContextInterface;
/**
@@ -449,7 +508,7 @@
* location - The current location as determined by the FLP subsystem.
* transition - Can be one of FLP_GEOFENCE_TRANSITION_ENTERED, FLP_GEOFENCE_TRANSITION_EXITED,
* FLP_GEOFENCE_TRANSITION_UNCERTAIN.
- * timestamp - Timestamp when the transition was detected.
+ * timestamp - Timestamp when the transition was detected; -1 if not available.
* sources_used - Bitwise OR of FLP_TECH_MASK flags indicating which
* subsystems were used.
*
@@ -530,13 +589,15 @@
typedef void (*flp_geofence_resume_callback) (int32_t geofence_id, int32_t result);
typedef struct {
+ /** set to sizeof(FlpGeofenceCallbacks) */
+ size_t size;
flp_geofence_transition_callback geofence_transition_callback;
flp_geofence_monitor_status_callback geofence_status_callback;
flp_geofence_add_callback geofence_add_callback;
flp_geofence_remove_callback geofence_remove_callback;
flp_geofence_pause_callback geofence_pause_callback;
flp_geofence_resume_callback geofence_resume_callback;
- flp_create_thread create_thread_cb;
+ flp_set_thread_event set_thread_event_cb;
} FlpGeofenceCallbacks;
@@ -649,6 +710,15 @@
void (*resume_geofence) (int32_t geofence_id, int monitor_transitions);
/**
+ * Modify a particular geofence option.
+ * Parameters:
+ * geofence_id - The id for the geofence.
+ * options - Various options associated with the geofence. See
+ * GeofenceOptions structure for details.
+ */
+ void (*modify_geofence_option) (int32_t geofence_id, GeofenceOptions* options);
+
+ /**
* Remove a list of geofences. After the function returns, no notifications
* should be sent.
* Parameter:
diff --git a/include/hardware/gralloc.h b/include/hardware/gralloc.h
index 9c62242..0dbebcf 100644
--- a/include/hardware/gralloc.h
+++ b/include/hardware/gralloc.h
@@ -104,6 +104,9 @@
/* mask for the software usage bit-mask */
GRALLOC_USAGE_HW_MASK = 0x00071F00,
+ /* buffer will be used as a RenderScript Allocation */
+ GRALLOC_USAGE_RENDERSCRIPT = 0x00100000,
+
/* buffer should be displayed full-screen on an external display when
* possible
*/
diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h
index d75a047..9492d3a 100644
--- a/include/hardware/hwcomposer.h
+++ b/include/hardware/hwcomposer.h
@@ -54,6 +54,13 @@
int bottom;
} hwc_rect_t;
+typedef struct hwc_frect {
+ float left;
+ float top;
+ float right;
+ float bottom;
+} hwc_frect_t;
+
typedef struct hwc_region {
size_t numRects;
hwc_rect_t const* rects;
@@ -149,8 +156,17 @@
int32_t blending;
/* area of the source to consider, the origin is the top-left corner of
- * the buffer */
- hwc_rect_t sourceCrop;
+ * the buffer. As of HWC_DEVICE_API_VERSION_1_3, sourceRect uses floats.
+ * If the h/w can't support a non-integer source crop rectangle, it should
+ * punt to OpenGL ES composition.
+ */
+ union {
+ // crop rectangle in integer (pre HWC_DEVICE_API_VERSION_1_3)
+ hwc_rect_t sourceCropi;
+ hwc_rect_t sourceCrop; // just for source compatibility
+ // crop rectangle in floats (as of HWC_DEVICE_API_VERSION_1_3)
+ hwc_frect_t sourceCropf;
+ };
/* where to composite the sourceCrop onto the display. The sourceCrop
* is scaled using linear filtering to the displayFrame. The origin is the
diff --git a/include/hardware/hwcomposer_defs.h b/include/hardware/hwcomposer_defs.h
index 1edfd3d..ce4723c 100644
--- a/include/hardware/hwcomposer_defs.h
+++ b/include/hardware/hwcomposer_defs.h
@@ -35,6 +35,7 @@
#define HWC_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION_2(1, 0, HWC_HEADER_VERSION)
#define HWC_DEVICE_API_VERSION_1_1 HARDWARE_DEVICE_API_VERSION_2(1, 1, HWC_HEADER_VERSION)
#define HWC_DEVICE_API_VERSION_1_2 HARDWARE_DEVICE_API_VERSION_2(1, 2, HWC_HEADER_VERSION)
+#define HWC_DEVICE_API_VERSION_1_3 HARDWARE_DEVICE_API_VERSION_2(1, 3, HWC_HEADER_VERSION)
enum {
/* hwc_composer_device_t::set failed in EGL */
diff --git a/include/hardware/power.h b/include/hardware/power.h
index 6c55061..89d57ed 100644
--- a/include/hardware/power.h
+++ b/include/hardware/power.h
@@ -28,7 +28,6 @@
#define POWER_MODULE_API_VERSION_0_1 HARDWARE_MODULE_API_VERSION(0, 1)
#define POWER_MODULE_API_VERSION_0_2 HARDWARE_MODULE_API_VERSION(0, 2)
-
/**
* The id of this module
*/
@@ -41,6 +40,11 @@
typedef enum {
POWER_HINT_VSYNC = 0x00000001,
POWER_HINT_INTERACTION = 0x00000002,
+ /* DO NOT USE POWER_HINT_VIDEO_ENCODE/_DECODE! They will be removed in
+ * KLP.
+ */
+ POWER_HINT_VIDEO_ENCODE = 0x00000003,
+ POWER_HINT_VIDEO_DECODE = 0x00000004
} power_hint_t;
/**
diff --git a/include/hardware/sensors.h b/include/hardware/sensors.h
index 7778e8f..b377051 100644
--- a/include/hardware/sensors.h
+++ b/include/hardware/sensors.h
@@ -451,6 +451,9 @@
* SENSOR_TYPE_MAGNETIC_FIELD must be present and both must return the
* same sensor_t::name and sensor_t::vendor.
*
+ * Minimum filtering should be applied to this sensor. In particular, low pass
+ * filters should be avoided.
+ *
* See SENSOR_TYPE_MAGNETIC_FIELD for more information
*/
#define SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED (14)
@@ -608,7 +611,7 @@
*
* A sensor of this type returns the number of steps taken by the user since
* the last reboot while activated. The value is returned as a uint64_t and is
- * reset to zero only on a system reboot.
+ * reset to zero only on a system / android reboot.
*
* The timestamp of the event is set to the time when the first step
* for that event was taken.
@@ -662,7 +665,9 @@
* of using a gyroscope.
*
* This sensor must be based on a magnetometer. It cannot be implemented using
- * a gyroscope, and gyroscope input cannot be used by this sensor.
+ * a gyroscope, and gyroscope input cannot be used by this sensor, as the
+ * goal of this sensor is to be low power.
+ * The accelerometer can be (and usually is) used.
*
* Just like SENSOR_TYPE_ROTATION_VECTOR, this sensor reports an estimated
* heading accuracy:
@@ -761,45 +766,51 @@
int64_t timestamp;
union {
- float data[16];
+ union {
+ float data[16];
- /* acceleration values are in meter per second per second (m/s^2) */
- sensors_vec_t acceleration;
+ /* acceleration values are in meter per second per second (m/s^2) */
+ sensors_vec_t acceleration;
- /* magnetic vector values are in micro-Tesla (uT) */
- sensors_vec_t magnetic;
+ /* magnetic vector values are in micro-Tesla (uT) */
+ sensors_vec_t magnetic;
- /* orientation values are in degrees */
- sensors_vec_t orientation;
+ /* orientation values are in degrees */
+ sensors_vec_t orientation;
- /* gyroscope values are in rad/s */
- sensors_vec_t gyro;
+ /* gyroscope values are in rad/s */
+ sensors_vec_t gyro;
- /* temperature is in degrees centigrade (Celsius) */
- float temperature;
+ /* temperature is in degrees centigrade (Celsius) */
+ float temperature;
- /* distance in centimeters */
- float distance;
+ /* distance in centimeters */
+ float distance;
- /* light in SI lux units */
- float light;
+ /* light in SI lux units */
+ float light;
- /* pressure in hectopascal (hPa) */
- float pressure;
+ /* pressure in hectopascal (hPa) */
+ float pressure;
- /* relative humidity in percent */
- float relative_humidity;
+ /* relative humidity in percent */
+ float relative_humidity;
- /* step-counter */
- uint64_t step_counter;
+ /* uncalibrated gyroscope values are in rad/s */
+ uncalibrated_event_t uncalibrated_gyro;
- /* uncalibrated gyroscope values are in rad/s */
- uncalibrated_event_t uncalibrated_gyro;
+ /* uncalibrated magnetometer values are in micro-Teslas */
+ uncalibrated_event_t uncalibrated_magnetic;
+ };
- /* uncalibrated magnetometer values are in micro-Teslas */
- uncalibrated_event_t uncalibrated_magnetic;
+ union {
+ uint64_t data[8];
+
+ /* step-counter */
+ uint64_t step_counter;
+ } u64;
};
- uint32_t reserved1[4];
+ uint32_t reserved1[4];
} sensors_event_t;
@@ -903,6 +914,10 @@
* handle is the handle of the sensor to change.
* enabled set to 1 to enable, or 0 to disable the sensor.
*
+ * if enabled is set to 1, the sensor is activated even if
+ * setDelay() wasn't called before. In this case, a default rate
+ * should be used.
+ *
* unless otherwise noted in the sensor types definitions, an
* activated sensor never prevents the SoC to go into suspend
* mode; that is, the HAL shall not hold a partial wake-lock on
@@ -912,10 +927,10 @@
* receiving an event and they must still accept to be deactivated
* through a call to activate(..., ..., 0).
*
- * if "enabled" is true and the sensor is already activated, this
+ * if "enabled" is 1 and the sensor is already activated, this
* function is a no-op and succeeds.
*
- * if "enabled" is false and the sensor is already de-activated,
+ * if "enabled" is 0 and the sensor is already de-activated,
* this function is a no-op and succeeds.
*
* return 0 on success, negative errno code otherwise
@@ -939,6 +954,9 @@
* sensor_t::minDelay unless sensor_t::minDelay is 0, in which
* case it is clamped to >= 1ms.
*
+ * setDelay will not be called when the sensor is in batching mode.
+ * In this case, batch() will be called with the new period.
+ *
* @return 0 if successful, < 0 on error
*/
int (*setDelay)(struct sensors_poll_device_t *dev,
@@ -1068,19 +1086,30 @@
* if a batch call with SENSORS_BATCH_DRY_RUN is successful,
* the same call without SENSORS_BATCH_DRY_RUN must succeed as well).
*
- * If successful, 0 is returned.
- * If the specified sensor doesn't support batch mode, -EINVAL is returned.
- * If the specified sensor's trigger-mode is one-shot, -EINVAL is returned.
- * If WAKE_UPON_FIFO_FULL is specified and the specified sensor's internal
- * FIFO is too small to store at least 10 seconds worth of data at the
- * given rate, -EINVAL is returned. Note that as stated above, this has to
- * be determined at compile time, and not based on the state of the system.
- * If some other constraints above cannot be satisfied, -EINVAL is returned.
+ * When timeout is not 0:
+ * If successful, 0 is returned.
+ * If the specified sensor doesn't support batch mode, return -EINVAL.
+ * If the specified sensor's trigger-mode is one-shot, return -EINVAL.
+ * If WAKE_UPON_FIFO_FULL is specified and the specified sensor's internal
+ * FIFO is too small to store at least 10 seconds worth of data at the
+ * given rate, -EINVAL is returned. Note that as stated above, this has to
+ * be determined at compile time, and not based on the state of the
+ * system.
+ * If some other constraints above cannot be satisfied, return -EINVAL.
*
* Note: the timeout parameter, when > 0, has no impact on whether this
* function succeeds or fails.
*
- * If timeout is set to 0, this function must succeed.
+ * When timeout is 0:
+ * The caller will never set the wake_upon_fifo_full flag.
+ * The function must succeed, and batch mode must be deactivated.
+ *
+ * Independently of whether DRY_RUN is specified, When the call to batch()
+ * fails, no state should be changed. In particular, a failed call to
+ * batch() should not change the rate of the sensor. Example:
+ * setDelay(..., 10ms)
+ * batch(..., 20ms, ...) fails
+ * rate should stay 10ms.
*
*
* IMPLEMENTATION NOTES:
diff --git a/modules/audio/audio_policy.c b/modules/audio/audio_policy.c
index 2dd3dbe..9335654 100644
--- a/modules/audio/audio_policy.c
+++ b/modules/audio/audio_policy.c
@@ -99,7 +99,8 @@
uint32_t sampling_rate,
audio_format_t format,
audio_channel_mask_t channelMask,
- audio_output_flags_t flags)
+ audio_output_flags_t flags,
+ const audio_offload_info_t *info)
{
return 0;
}
@@ -229,6 +230,12 @@
return -ENOSYS;
}
+static bool ap_is_offload_supported(const struct audio_policy *pol,
+ const audio_offload_info_t *info)
+{
+ return false;
+}
+
static int create_default_ap(const struct audio_policy_device *device,
struct audio_policy_service_ops *aps_ops,
void *service,
@@ -278,6 +285,8 @@
dap->policy.is_stream_active = ap_is_stream_active;
dap->policy.dump = ap_dump;
+ dap->policy.is_offload_supported = ap_is_offload_supported;
+
dap->service = service;
dap->aps_ops = aps_ops;
diff --git a/modules/camera/Android.mk b/modules/camera/Android.mk
index 5d26934..e02a143 100644
--- a/modules/camera/Android.mk
+++ b/modules/camera/Android.mk
@@ -26,6 +26,7 @@
LOCAL_SRC_FILES := \
CameraHAL.cpp \
Camera.cpp \
+ Metadata.cpp \
Stream.cpp \
LOCAL_SHARED_LIBRARIES := \
diff --git a/modules/camera/Camera.cpp b/modules/camera/Camera.cpp
index 718d42b..2fe7395 100644
--- a/modules/camera/Camera.cpp
+++ b/modules/camera/Camera.cpp
@@ -19,7 +19,9 @@
#include <hardware/camera3.h>
#include <sync/sync.h>
#include <system/camera_metadata.h>
+#include <system/graphics.h>
#include "CameraHAL.h"
+#include "Metadata.h"
#include "Stream.h"
//#define LOG_NDEBUG 0
@@ -34,6 +36,8 @@
#define CAMERA_SYNC_TIMEOUT 5000 // in msecs
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
namespace default_camera_hal {
extern "C" {
@@ -48,6 +52,7 @@
Camera::Camera(int id)
: mId(id),
+ mStaticInfo(NULL),
mBusy(false),
mCallbackOps(NULL),
mStreams(NULL),
@@ -59,6 +64,7 @@
memset(&mDevice, 0, sizeof(mDevice));
mDevice.common.tag = HARDWARE_DEVICE_TAG;
+ mDevice.common.version = CAMERA_DEVICE_API_VERSION_3_0;
mDevice.common.close = close_device;
mDevice.ops = const_cast<camera3_device_ops_t*>(&sOps);
mDevice.priv = this;
@@ -88,6 +94,25 @@
return 0;
}
+int Camera::getInfo(struct camera_info *info)
+{
+ int ret = 0;
+
+ info->facing = CAMERA_FACING_FRONT;
+ info->orientation = 0;
+ info->device_version = mDevice.common.version;
+
+ pthread_mutex_lock(&mMutex);
+ if (mStaticInfo == NULL) {
+ ret = initStaticInfo();
+ }
+ pthread_mutex_unlock(&mMutex);
+
+ info->static_camera_characteristics = mStaticInfo;
+
+ return ret;
+}
+
int Camera::close()
{
ALOGI("%s:%d: Closing camera device", __func__, mId);
@@ -110,6 +135,164 @@
{
ALOGV("%s:%d: callback_ops=%p", __func__, mId, callback_ops);
mCallbackOps = callback_ops;
+ // Create standard settings templates
+ // 0 is invalid as template
+ mTemplates[0] = NULL;
+ // CAMERA3_TEMPLATE_PREVIEW = 1
+ mTemplates[1] = new Metadata(ANDROID_CONTROL_MODE_OFF,
+ ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW);
+ // CAMERA3_TEMPLATE_STILL_CAPTURE = 2
+ mTemplates[2] = new Metadata(ANDROID_CONTROL_MODE_OFF,
+ ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
+ // CAMERA3_TEMPLATE_VIDEO_RECORD = 3
+ mTemplates[3] = new Metadata(ANDROID_CONTROL_MODE_OFF,
+ ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
+ // CAMERA3_TEMPLATE_VIDEO_SNAPSHOT = 4
+ mTemplates[4] = new Metadata(ANDROID_CONTROL_MODE_OFF,
+ ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT);
+ // CAMERA3_TEMPLATE_STILL_ZERO_SHUTTER_LAG = 5
+ mTemplates[5] = new Metadata(ANDROID_CONTROL_MODE_OFF,
+ ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG);
+ // Pre-generate metadata structures
+ for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; i++) {
+ mTemplates[i]->generate();
+ }
+ // TODO: create vendor templates
+ return 0;
+}
+
+int Camera::initStaticInfo()
+{
+ /*
+ * Setup static camera info. This will have to customized per camera
+ * device.
+ */
+
+ /* android.control */
+ int32_t android_control_ae_available_target_fps_ranges[] = {30, 30};
+ mMetadata.addInt32(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
+ ARRAY_SIZE(android_control_ae_available_target_fps_ranges),
+ android_control_ae_available_target_fps_ranges);
+
+ int32_t android_control_ae_compensation_range[] = {-4, 4};
+ mMetadata.addInt32(ANDROID_CONTROL_AE_COMPENSATION_RANGE,
+ ARRAY_SIZE(android_control_ae_compensation_range),
+ android_control_ae_compensation_range);
+
+ camera_metadata_rational_t android_control_ae_compensation_step[] = {{2,1}};
+ mMetadata.addRational(ANDROID_CONTROL_AE_COMPENSATION_STEP,
+ ARRAY_SIZE(android_control_ae_compensation_step),
+ android_control_ae_compensation_step);
+
+ int32_t android_control_max_regions[] = {1};
+ mMetadata.addInt32(ANDROID_CONTROL_MAX_REGIONS,
+ ARRAY_SIZE(android_control_max_regions),
+ android_control_max_regions);
+
+ /* android.jpeg */
+ int32_t android_jpeg_available_thumbnail_sizes[] = {0, 0, 128, 96};
+ mMetadata.addInt32(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+ ARRAY_SIZE(android_jpeg_available_thumbnail_sizes),
+ android_jpeg_available_thumbnail_sizes);
+
+ /* android.lens */
+ float android_lens_info_available_focal_lengths[] = {1.0};
+ mMetadata.addFloat(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
+ ARRAY_SIZE(android_lens_info_available_focal_lengths),
+ android_lens_info_available_focal_lengths);
+
+ /* android.request */
+ int32_t android_request_max_num_output_streams[] = {0, 3, 1};
+ mMetadata.addInt32(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
+ ARRAY_SIZE(android_request_max_num_output_streams),
+ android_request_max_num_output_streams);
+
+ /* android.scaler */
+ int32_t android_scaler_available_formats[] = {
+ HAL_PIXEL_FORMAT_RAW_SENSOR,
+ HAL_PIXEL_FORMAT_BLOB,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+ // These are handled by YCbCr_420_888
+ // HAL_PIXEL_FORMAT_YV12,
+ // HAL_PIXEL_FORMAT_YCrCb_420_SP,
+ HAL_PIXEL_FORMAT_YCbCr_420_888};
+ mMetadata.addInt32(ANDROID_SCALER_AVAILABLE_FORMATS,
+ ARRAY_SIZE(android_scaler_available_formats),
+ android_scaler_available_formats);
+
+ int64_t android_scaler_available_jpeg_min_durations[] = {1};
+ mMetadata.addInt64(ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS,
+ ARRAY_SIZE(android_scaler_available_jpeg_min_durations),
+ android_scaler_available_jpeg_min_durations);
+
+ int32_t android_scaler_available_jpeg_sizes[] = {640, 480};
+ mMetadata.addInt32(ANDROID_SCALER_AVAILABLE_JPEG_SIZES,
+ ARRAY_SIZE(android_scaler_available_jpeg_sizes),
+ android_scaler_available_jpeg_sizes);
+
+ float android_scaler_available_max_digital_zoom[] = {1};
+ mMetadata.addFloat(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+ ARRAY_SIZE(android_scaler_available_max_digital_zoom),
+ android_scaler_available_max_digital_zoom);
+
+ int64_t android_scaler_available_processed_min_durations[] = {1};
+ mMetadata.addInt64(ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS,
+ ARRAY_SIZE(android_scaler_available_processed_min_durations),
+ android_scaler_available_processed_min_durations);
+
+ int32_t android_scaler_available_processed_sizes[] = {640, 480};
+ mMetadata.addInt32(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES,
+ ARRAY_SIZE(android_scaler_available_processed_sizes),
+ android_scaler_available_processed_sizes);
+
+ int64_t android_scaler_available_raw_min_durations[] = {1};
+ mMetadata.addInt64(ANDROID_SCALER_AVAILABLE_RAW_MIN_DURATIONS,
+ ARRAY_SIZE(android_scaler_available_raw_min_durations),
+ android_scaler_available_raw_min_durations);
+
+ int32_t android_scaler_available_raw_sizes[] = {640, 480};
+ mMetadata.addInt32(ANDROID_SCALER_AVAILABLE_RAW_SIZES,
+ ARRAY_SIZE(android_scaler_available_raw_sizes),
+ android_scaler_available_raw_sizes);
+
+ /* android.sensor */
+
+ int32_t android_sensor_info_active_array_size[] = {0, 0, 640, 480};
+ mMetadata.addInt32(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
+ ARRAY_SIZE(android_sensor_info_active_array_size),
+ android_sensor_info_active_array_size);
+
+ int32_t android_sensor_info_sensitivity_range[] =
+ {100, 1600};
+ mMetadata.addInt32(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
+ ARRAY_SIZE(android_sensor_info_sensitivity_range),
+ android_sensor_info_sensitivity_range);
+
+ int64_t android_sensor_info_max_frame_duration[] = {30000000000};
+ mMetadata.addInt64(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
+ ARRAY_SIZE(android_sensor_info_max_frame_duration),
+ android_sensor_info_max_frame_duration);
+
+ float android_sensor_info_physical_size[] = {3.2, 2.4};
+ mMetadata.addFloat(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
+ ARRAY_SIZE(android_sensor_info_physical_size),
+ android_sensor_info_physical_size);
+
+ int32_t android_sensor_info_pixel_array_size[] = {640, 480};
+ mMetadata.addInt32(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
+ ARRAY_SIZE(android_sensor_info_pixel_array_size),
+ android_sensor_info_pixel_array_size);
+
+ int32_t android_sensor_orientation[] = {0};
+ mMetadata.addInt32(ANDROID_SENSOR_ORIENTATION,
+ ARRAY_SIZE(android_sensor_orientation),
+ android_sensor_orientation);
+
+ /* End of static camera characteristics */
+
+ mStaticInfo = mMetadata.generate();
+
return 0;
}
@@ -141,12 +324,15 @@
for (int i = 0; i < mNumStreams; i++)
mStreams[i]->mReuse = false;
// Fill new stream array with reused streams and new streams
- for (int i = 0; i < stream_config->num_streams; i++) {
+ for (unsigned int i = 0; i < stream_config->num_streams; i++) {
astream = stream_config->streams[i];
- if (astream->max_buffers > 0)
+ if (astream->max_buffers > 0) {
+ ALOGV("%s:%d: Reusing stream %d", __func__, mId, i);
newStreams[i] = reuseStream(astream);
- else
+ } else {
+ ALOGV("%s:%d: Creating new stream %d", __func__, mId, i);
newStreams[i] = new Stream(mId, astream);
+ }
if (newStreams[i] == NULL) {
ALOGE("%s:%d: Error processing stream %d", __func__, mId, i);
@@ -228,6 +414,8 @@
if (streams[i]->isOutputType())
outputs++;
}
+ ALOGV("%s:%d: Configuring %d output streams and %d input streams",
+ __func__, mId, outputs, inputs);
if (outputs < 1) {
ALOGE("%s:%d: Stream config must have >= 1 output", __func__, mId);
return false;
@@ -285,8 +473,12 @@
const camera_metadata_t* Camera::constructDefaultRequestSettings(int type)
{
ALOGV("%s:%d: type=%d", __func__, mId, type);
- // TODO: return statically built default request
- return NULL;
+
+ if (type < 1 || type >= CAMERA3_TEMPLATE_COUNT) {
+ ALOGE("%s:%d: Invalid template request type: %d", __func__, mId, type);
+ return NULL;
+ }
+ return mTemplates[type]->generate();
}
int Camera::processCaptureRequest(camera3_capture_request_t *request)
@@ -352,6 +544,7 @@
// TODO: return actual captured/reprocessed settings
result.result = request->settings;
// TODO: asynchronously return results
+ notifyShutter(request->frame_number, 0);
mCallbackOps->process_capture_result(mCallbackOps, &result);
return 0;
@@ -373,13 +566,13 @@
mSettings = clone_camera_metadata(new_settings);
}
-bool Camera::isValidCaptureSettings(const camera_metadata_t *settings)
+bool Camera::isValidCaptureSettings(const camera_metadata_t* /*settings*/)
{
// TODO: reject settings that cannot be captured
return true;
}
-bool Camera::isValidReprocessSettings(const camera_metadata_t *settings)
+bool Camera::isValidReprocessSettings(const camera_metadata_t* /*settings*/)
{
// TODO: reject settings that cannot be reprocessed
// input buffers unimplemented, use this to reject reprocessing requests
@@ -390,14 +583,17 @@
int Camera::processCaptureBuffer(const camera3_stream_buffer_t *in,
camera3_stream_buffer_t *out)
{
- int res = sync_wait(in->acquire_fence, CAMERA_SYNC_TIMEOUT);
- if (res == -ETIME) {
- ALOGE("%s:%d: Timeout waiting on buffer acquire fence", __func__, mId);
- return res;
- } else if (res) {
- ALOGE("%s:%d: Error waiting on buffer acquire fence: %s(%d)",
- __func__, mId, strerror(-res), res);
- return res;
+ if (in->acquire_fence != -1) {
+ int res = sync_wait(in->acquire_fence, CAMERA_SYNC_TIMEOUT);
+ if (res == -ETIME) {
+ ALOGE("%s:%d: Timeout waiting on buffer acquire fence",
+ __func__, mId);
+ return res;
+ } else if (res) {
+ ALOGE("%s:%d: Error waiting on buffer acquire fence: %s(%d)",
+ __func__, mId, strerror(-res), res);
+ return res;
+ }
}
out->stream = in->stream;
@@ -411,6 +607,31 @@
return 0;
}
+void Camera::notifyShutter(uint32_t frame_number, uint64_t timestamp)
+{
+ int res;
+ struct timespec ts;
+
+ // If timestamp is 0, get timestamp from right now instead
+ if (timestamp == 0) {
+ ALOGW("%s:%d: No timestamp provided, using CLOCK_BOOTTIME",
+ __func__, mId);
+ res = clock_gettime(CLOCK_BOOTTIME, &ts);
+ if (res == 0) {
+ timestamp = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+ } else {
+ ALOGE("%s:%d: No timestamp and failed to get CLOCK_BOOTTIME %s(%d)",
+ __func__, mId, strerror(errno), errno);
+ }
+ }
+ camera3_notify_msg_t m;
+ memset(&m, 0, sizeof(m));
+ m.type = CAMERA3_MSG_SHUTTER;
+ m.message.shutter.frame_number = frame_number;
+ m.message.shutter.timestamp = timestamp;
+ mCallbackOps->notify(mCallbackOps, &m);
+}
+
void Camera::getMetadataVendorTagOps(vendor_tag_query_ops_t *ops)
{
ALOGV("%s:%d: ops=%p", __func__, mId, ops);
diff --git a/modules/camera/Camera.h b/modules/camera/Camera.h
index 4001453..16e1439 100644
--- a/modules/camera/Camera.h
+++ b/modules/camera/Camera.h
@@ -20,6 +20,7 @@
#include <pthread.h>
#include <hardware/hardware.h>
#include <hardware/camera3.h>
+#include "Metadata.h"
#include "Stream.h"
namespace default_camera_hal {
@@ -36,6 +37,7 @@
// Common Camera Device Operations (see <hardware/camera_common.h>)
int open(const hw_module_t *module, hw_device_t **device);
+ int getInfo(struct camera_info *info);
int close();
// Camera v3 Device Operations (see <hardware/camera3.h>)
@@ -51,6 +53,8 @@
camera3_device_t mDevice;
private:
+ // Separate initialization method for static metadata
+ int initStaticInfo();
// Reuse a stream already created by this device
Stream *reuseStream(camera3_stream_t *astream);
// Destroy all streams in a stream array, and the array itself
@@ -68,9 +72,15 @@
// Process an output buffer
int processCaptureBuffer(const camera3_stream_buffer_t *in,
camera3_stream_buffer_t *out);
+ // Send a shutter notify message with start of exposure time
+ void notifyShutter(uint32_t frame_number, uint64_t timestamp);
// Identifier used by framework to distinguish cameras
const int mId;
+ // Metadata containing persistent camera characteristics
+ Metadata mMetadata;
+ // camera_metadata structure containing static characteristics
+ camera_metadata_t *mStaticInfo;
// Busy flag indicates camera is in use
bool mBusy;
// Camera device operations handle shared by all devices
@@ -83,6 +93,8 @@
Stream **mStreams;
// Number of streams in mStreams
int mNumStreams;
+ // Static array of standard camera settings templates
+ Metadata *mTemplates[CAMERA3_TEMPLATE_COUNT];
// Most recent request settings seen, memoized to be reused
camera_metadata_t *mSettings;
};
diff --git a/modules/camera/CameraHAL.cpp b/modules/camera/CameraHAL.cpp
index 05b1fad..dfbbe4c 100644
--- a/modules/camera/CameraHAL.cpp
+++ b/modules/camera/CameraHAL.cpp
@@ -76,7 +76,7 @@
return -ENODEV;
}
// TODO: return device-specific static metadata
- return 0;
+ return mCameras[id]->getInfo(info);
}
int CameraHAL::setCallbacks(const camera_module_callbacks_t *callbacks)
@@ -92,8 +92,12 @@
char *nameEnd;
ALOGV("%s: module=%p, name=%s, device=%p", __func__, mod, name, dev);
+ if (*name == '\0') {
+ ALOGE("%s: Invalid camera id name is NULL", __func__);
+ return -EINVAL;
+ }
id = strtol(name, &nameEnd, 10);
- if (nameEnd != NULL) {
+ if (*nameEnd != '\0') {
ALOGE("%s: Invalid camera id name %s", __func__, name);
return -EINVAL;
} else if (id < 0 || id >= mNumberOfCameras) {
diff --git a/modules/camera/Metadata.cpp b/modules/camera/Metadata.cpp
new file mode 100644
index 0000000..d5854f9
--- /dev/null
+++ b/modules/camera/Metadata.cpp
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <pthread.h>
+#include <system/camera_metadata.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Metadata"
+#include <cutils/log.h>
+
+#define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL)
+#include <cutils/trace.h>
+#include "ScopedTrace.h"
+
+#include "Metadata.h"
+
+namespace default_camera_hal {
+
+Metadata::Metadata()
+ : mHead(NULL),
+ mTail(NULL),
+ mEntryCount(0),
+ mDataCount(0),
+ mGenerated(NULL),
+ mDirty(true)
+{
+ // NULL (default) pthread mutex attributes
+ pthread_mutex_init(&mMutex, NULL);
+}
+
+Metadata::~Metadata()
+{
+ Entry *current = mHead;
+
+ while (current != NULL) {
+ Entry *tmp = current;
+ current = current->mNext;
+ delete tmp;
+ }
+
+ if (mGenerated != NULL)
+ free_camera_metadata(mGenerated);
+
+ pthread_mutex_destroy(&mMutex);
+}
+
+Metadata::Metadata(uint8_t mode, uint8_t intent)
+ : mHead(NULL),
+ mTail(NULL),
+ mEntryCount(0),
+ mDataCount(0),
+ mGenerated(NULL),
+ mDirty(true)
+{
+ pthread_mutex_init(&mMutex, NULL);
+
+ if (validate(ANDROID_CONTROL_MODE, TYPE_BYTE, 1)) {
+ int res = add(ANDROID_CONTROL_MODE, 1, &mode);
+ if (res != 0) {
+ ALOGE("%s: Unable to add mode to template!", __func__);
+ }
+ } else {
+ ALOGE("%s: Invalid mode constructing template!", __func__);
+ }
+
+ if (validate(ANDROID_CONTROL_CAPTURE_INTENT, TYPE_BYTE, 1)) {
+ int res = add(ANDROID_CONTROL_CAPTURE_INTENT, 1, &intent);
+ if (res != 0) {
+ ALOGE("%s: Unable to add capture intent to template!", __func__);
+ }
+ } else {
+ ALOGE("%s: Invalid capture intent constructing template!", __func__);
+ }
+}
+
+int Metadata::addUInt8(uint32_t tag, int count, uint8_t *data)
+{
+ if (!validate(tag, TYPE_BYTE, count)) return -EINVAL;
+ return add(tag, count, data);
+}
+
+int Metadata::addInt32(uint32_t tag, int count, int32_t *data)
+{
+ if (!validate(tag, TYPE_INT32, count)) return -EINVAL;
+ return add(tag, count, data);
+}
+
+int Metadata::addFloat(uint32_t tag, int count, float *data)
+{
+ if (!validate(tag, TYPE_FLOAT, count)) return -EINVAL;
+ return add(tag, count, data);
+}
+
+int Metadata::addInt64(uint32_t tag, int count, int64_t *data)
+{
+ if (!validate(tag, TYPE_INT64, count)) return -EINVAL;
+ return add(tag, count, data);
+}
+
+int Metadata::addDouble(uint32_t tag, int count, double *data)
+{
+ if (!validate(tag, TYPE_DOUBLE, count)) return -EINVAL;
+ return add(tag, count, data);
+}
+
+int Metadata::addRational(uint32_t tag, int count,
+ camera_metadata_rational_t *data)
+{
+ if (!validate(tag, TYPE_RATIONAL, count)) return -EINVAL;
+ return add(tag, count, data);
+}
+
+bool Metadata::validate(uint32_t tag, int tag_type, int count)
+{
+ if (get_camera_metadata_tag_type(tag) < 0) {
+ ALOGE("%s: Invalid metadata entry tag: %d", __func__, tag);
+ return false;
+ }
+ if (tag_type < 0 || tag_type >= NUM_TYPES) {
+ ALOGE("%s: Invalid metadata entry tag type: %d", __func__, tag_type);
+ return false;
+ }
+ if (tag_type != get_camera_metadata_tag_type(tag)) {
+ ALOGE("%s: Tag %d called with incorrect type: %s(%d)", __func__, tag,
+ camera_metadata_type_names[tag_type], tag_type);
+ return false;
+ }
+ if (count < 1) {
+ ALOGE("%s: Invalid metadata entry count: %d", __func__, count);
+ return false;
+ }
+ return true;
+}
+
+int Metadata::add(uint32_t tag, int count, void *tag_data)
+{
+ int tag_type = get_camera_metadata_tag_type(tag);
+ size_t type_sz = camera_metadata_type_size[tag_type];
+
+ // Allocate array to hold new metadata
+ void *data = malloc(count * type_sz);
+ if (data == NULL)
+ return -ENOMEM;
+ memcpy(data, tag_data, count * type_sz);
+
+ pthread_mutex_lock(&mMutex);
+ mEntryCount++;
+ mDataCount += calculate_camera_metadata_entry_data_size(tag_type, count);
+ push(new Entry(tag, data, count));
+ mDirty = true;
+ pthread_mutex_unlock(&mMutex);
+ return 0;
+}
+
+camera_metadata_t* Metadata::generate()
+{
+ pthread_mutex_lock(&mMutex);
+ // Reuse if old generated metadata still valid
+ if (!mDirty && mGenerated != NULL) {
+ ALOGV("%s: Reusing generated metadata at %p", __func__, mGenerated);
+ goto out;
+ }
+ // Destroy old metadata
+ if (mGenerated != NULL) {
+ ALOGV("%s: Freeing generated metadata at %p", __func__, mGenerated);
+ free_camera_metadata(mGenerated);
+ mGenerated = NULL;
+ }
+ // Generate new metadata structure
+ ALOGV("%s: Generating new camera metadata structure, Entries:%d Data:%d",
+ __func__, mEntryCount, mDataCount);
+ mGenerated = allocate_camera_metadata(mEntryCount, mDataCount);
+ if (mGenerated == NULL) {
+ ALOGE("%s: Failed to allocate metadata (%d entries %d data)",
+ __func__, mEntryCount, mDataCount);
+ goto out;
+ }
+ // Walk list of entries adding each one to newly allocated metadata
+ for (Entry *current = mHead; current != NULL; current = current->mNext) {
+ int res = add_camera_metadata_entry(mGenerated, current->mTag,
+ current->mData, current->mCount);
+ if (res != 0) {
+ ALOGE("%s: Failed to add camera metadata: %d", __func__, res);
+ free_camera_metadata(mGenerated);
+ mGenerated = NULL;
+ goto out;
+ }
+ }
+
+out:
+ pthread_mutex_unlock(&mMutex);
+ return mGenerated;
+}
+
+Metadata::Entry::Entry(uint32_t tag, void *data, int count)
+ : mNext(NULL),
+ mPrev(NULL),
+ mTag(tag),
+ mData(data),
+ mCount(count)
+{
+}
+
+void Metadata::push(Entry *e)
+{
+ if (mHead == NULL) {
+ mHead = mTail = e;
+ } else {
+ mTail->insertAfter(e);
+ mTail = e;
+ }
+}
+
+Metadata::Entry::~Entry()
+{
+ if (mNext != NULL)
+ mNext->mPrev = mPrev;
+ if (mPrev != NULL)
+ mPrev->mNext = mNext;
+}
+
+void Metadata::Entry::insertAfter(Entry *e)
+{
+ if (e == NULL)
+ return;
+ if (mNext != NULL)
+ mNext->mPrev = e;
+ e->mNext = mNext;
+ e->mPrev = this;
+ mNext = e;
+}
+
+} // namespace default_camera_hal
diff --git a/modules/camera/Metadata.h b/modules/camera/Metadata.h
new file mode 100644
index 0000000..22d2f22
--- /dev/null
+++ b/modules/camera/Metadata.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef METADATA_H_
+#define METADATA_H_
+
+#include <hardware/camera3.h>
+#include <hardware/gralloc.h>
+#include <system/camera_metadata.h>
+#include <system/graphics.h>
+
+namespace default_camera_hal {
+// Metadata is a convenience class for dealing with libcamera_metadata
+class Metadata {
+ public:
+ Metadata();
+ ~Metadata();
+ // Constructor used for request metadata templates
+ Metadata(uint8_t mode, uint8_t intent);
+
+ // Parse and add an entry
+ int addUInt8(uint32_t tag, int count, uint8_t *data);
+ int addInt32(uint32_t tag, int count, int32_t *data);
+ int addFloat(uint32_t tag, int count, float *data);
+ int addInt64(uint32_t tag, int count, int64_t *data);
+ int addDouble(uint32_t tag, int count, double *data);
+ int addRational(uint32_t tag, int count,
+ camera_metadata_rational_t *data);
+ // Generate a camera_metadata structure and fill it with internal data
+ camera_metadata_t *generate();
+
+ private:
+ // Validate the tag, type and count for a metadata entry
+ bool validate(uint32_t tag, int tag_type, int count);
+ // Add a verified tag with data to this Metadata structure
+ int add(uint32_t tag, int count, void *tag_data);
+
+ class Entry {
+ public:
+ Entry(uint32_t tag, void *data, int count);
+ ~Entry();
+ Entry *mNext;
+ Entry *mPrev;
+ const uint32_t mTag;
+ const void *mData;
+ const int mCount;
+ void insertAfter(Entry *e);
+ };
+ // List ends
+ Entry *mHead;
+ Entry *mTail;
+ // Append entry to list
+ void push(Entry *e);
+ // Total of entries and entry data size
+ int mEntryCount;
+ int mDataCount;
+ // Save generated metadata, invalidated on update
+ camera_metadata_t *mGenerated;
+ // Flag to force metadata regeneration
+ bool mDirty;
+ // Lock protecting the Metadata object for modifications
+ pthread_mutex_t mMutex;
+};
+} // namespace default_camera_hal
+
+#endif // METADATA_H_
diff --git a/modules/camera/Stream.cpp b/modules/camera/Stream.cpp
index 0834aee..aae7adb 100644
--- a/modules/camera/Stream.cpp
+++ b/modules/camera/Stream.cpp
@@ -61,6 +61,7 @@
pthread_mutex_lock(&mMutex);
if (usage != mUsage) {
mUsage = usage;
+ mStream->usage = usage;
unregisterBuffers_L();
}
pthread_mutex_unlock(&mMutex);
@@ -71,6 +72,7 @@
pthread_mutex_lock(&mMutex);
if (max_buffers != mMaxBuffers) {
mMaxBuffers = max_buffers;
+ mStream->max_buffers = max_buffers;
unregisterBuffers_L();
}
pthread_mutex_unlock(&mMutex);
@@ -83,12 +85,14 @@
bool Stream::isInputType()
{
- return mType & (CAMERA3_STREAM_INPUT | CAMERA3_STREAM_BIDIRECTIONAL);
+ return mType == CAMERA3_STREAM_INPUT ||
+ mType == CAMERA3_STREAM_BIDIRECTIONAL;
}
bool Stream::isOutputType()
{
- return mType & (CAMERA3_STREAM_OUTPUT | CAMERA3_STREAM_BIDIRECTIONAL);
+ return mType == CAMERA3_STREAM_OUTPUT ||
+ mType == CAMERA3_STREAM_BIDIRECTIONAL;
}
bool Stream::isRegistered()
diff --git a/modules/camera/Stream.h b/modules/camera/Stream.h
index 521362e..34abd95 100644
--- a/modules/camera/Stream.h
+++ b/modules/camera/Stream.h
@@ -52,7 +52,7 @@
// The camera device id this stream belongs to
const int mId;
// Handle to framework's stream, used as a cookie for buffers
- const camera3_stream_t *mStream;
+ camera3_stream_t *mStream;
// Stream type: CAMERA3_STREAM_* (see <hardware/camera3.h>)
const int mType;
// Width in pixels of the buffers in this stream
diff --git a/tests/camera2/CameraBurstTests.cpp b/tests/camera2/CameraBurstTests.cpp
index e39970c..cf8f68a 100644
--- a/tests/camera2/CameraBurstTests.cpp
+++ b/tests/camera2/CameraBurstTests.cpp
@@ -19,13 +19,14 @@
#define LOG_TAG "CameraBurstTest"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <utils/Timers.h>
#include <cmath>
#include "CameraStreamFixture.h"
#include "TestExtensions.h"
-#define CAMERA_FRAME_TIMEOUT 1000000000 //nsecs (1 secs)
+#define CAMERA_FRAME_TIMEOUT 1000000000LL //nsecs (1 secs)
#define CAMERA_HEAP_COUNT 2 //HALBUG: 1 means registerBuffers fails
#define CAMERA_BURST_DEBUGGING 0
#define CAMERA_FRAME_BURST_COUNT 10
@@ -34,9 +35,13 @@
#define CAMERA_EXPOSURE_DOUBLE 2
#define CAMERA_EXPOSURE_DOUBLING_THRESHOLD 1.0f
#define CAMERA_EXPOSURE_DOUBLING_COUNT 4
-#define CAMERA_EXPOSURE_FORMAT HAL_PIXEL_FORMAT_YCrCb_420_SP
+#define CAMERA_EXPOSURE_FORMAT CAMERA_STREAM_AUTO_CPU_FORMAT
#define CAMERA_EXPOSURE_STARTING 100000 // 1/10ms, up to 51.2ms with 10 steps
+#define USEC 1000LL // in ns
+#define MSEC 1000000LL // in ns
+#define SEC 1000000000LL // in ns
+
#if CAMERA_BURST_DEBUGGING
#define dout std::cout
#else
@@ -86,7 +91,7 @@
TEST_EXTENSION_FORKING_TEAR_DOWN;
}
- /* this assumes the format is YUV420sp */
+ /* this assumes the format is YUV420sp or flexible YUV */
long long TotalBrightness(const CpuConsumer::LockedBuffer& imgBuffer,
int *underexposed,
int *overexposed) const {
@@ -122,6 +127,23 @@
return acc;
}
+
+ // Parses a comma-separated string list into a Vector
+ template<typename T>
+ void ParseList(const char *src, Vector<T> &list) {
+ std::istringstream s(src);
+ while (!s.eof()) {
+ char c = s.peek();
+ if (c == ',' || c == ' ') {
+ s.ignore(1, EOF);
+ continue;
+ }
+ T val;
+ s >> val;
+ list.push_back(val);
+ }
+ }
+
};
TEST_F(CameraBurstTest, ManualExposureControl) {
@@ -170,6 +192,11 @@
uint8_t cmOff = static_cast<uint8_t>(ANDROID_CONTROL_MODE_OFF);
ASSERT_EQ(OK, previewRequest.update(ANDROID_CONTROL_MODE,
&cmOff, 1));
+
+ int requestId = 1;
+ ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_ID,
+ &requestId, 1));
+
if (CAMERA_BURST_DEBUGGING) {
int frameCount = 0;
ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_FRAME_COUNT,
@@ -252,7 +279,415 @@
<< " times over each consecutive frame as the exposure is doubled";
}
-}
-}
+/**
+ * This test varies exposure time, frame duration, and sensitivity for a
+ * burst of captures. It picks values by default, but the selection can be
+ * overridden with the environment variables
+ * CAMERA2_TEST_VARIABLE_BURST_EXPOSURE_TIMES
+ * CAMERA2_TEST_VARIABLE_BURST_FRAME_DURATIONS
+ * CAMERA2_TEST_VARIABLE_BURST_SENSITIVITIES
+ * which must all be a list of comma-separated values, and each list must be
+ * the same length. In addition, if the environment variable
+ * CAMERA2_TEST_VARIABLE_BURST_DUMP_FRAMES
+ * is set to 1, then the YUV buffers are dumped into files named
+ * "camera2_test_variable_burst_frame_NNN.yuv"
+ *
+ * For example:
+ * $ setenv CAMERA2_TEST_VARIABLE_BURST_EXPOSURE_TIMES 10000000,20000000
+ * $ setenv CAMERA2_TEST_VARIABLE_BURST_FRAME_DURATIONS 40000000,40000000
+ * $ setenv CAMERA2_TEST_VARIABLE_BURST_SENSITIVITIES 200,100
+ * $ setenv CAMERA2_TEST_VARIABLE_BURST_DUMP_FRAMES 1
+ * $ /data/nativetest/camera2_test/camera2_test --gtest_filter="*VariableBurst"
+ */
+TEST_F(CameraBurstTest, VariableBurst) {
+
+ TEST_EXTENSION_FORKING_INIT;
+
+ // Bounds for checking frame duration is within range
+ const nsecs_t DURATION_UPPER_BOUND = 10 * MSEC;
+ const nsecs_t DURATION_LOWER_BOUND = 20 * MSEC;
+
+ // Threshold for considering two captures to have equivalent exposure value,
+ // as a ratio of the smaller EV to the larger EV.
+ const float EV_MATCH_BOUND = 0.95;
+ // Bound for two captures with equivalent exp values to have the same
+ // measured brightness, in 0-255 luminance.
+ const float BRIGHTNESS_MATCH_BOUND = 5;
+
+ // Environment variables to look for to override test settings
+ const char *expEnv = "CAMERA2_TEST_VARIABLE_BURST_EXPOSURE_TIMES";
+ const char *durationEnv = "CAMERA2_TEST_VARIABLE_BURST_FRAME_DURATIONS";
+ const char *sensitivityEnv = "CAMERA2_TEST_VARIABLE_BURST_SENSITIVITIES";
+ const char *dumpFrameEnv = "CAMERA2_TEST_VARIABLE_BURST_DUMP_FRAMES";
+
+ // Range of valid exposure times, in nanoseconds
+ int64_t minExp = 0, maxExp = 0;
+ // List of valid sensor sensitivities
+ Vector<int32_t> sensitivities;
+ // Range of valid frame durations, in nanoseconds
+ int64_t minDuration = 0, maxDuration = 0;
+
+ {
+ camera_metadata_ro_entry exposureTimeRange =
+ GetStaticEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE);
+
+ EXPECT_EQ(2u, exposureTimeRange.count) << "Bad exposure time range tag."
+ "Using default values";
+ if (exposureTimeRange.count == 2) {
+ minExp = exposureTimeRange.data.i64[0];
+ maxExp = exposureTimeRange.data.i64[1];
+ }
+
+ EXPECT_LT(0, minExp) << "Minimum exposure time is 0";
+ EXPECT_LT(0, maxExp) << "Maximum exposure time is 0";
+ EXPECT_LE(minExp, maxExp) << "Minimum exposure is greater than maximum";
+
+ if (minExp == 0) {
+ minExp = 1 * MSEC; // Fallback minimum exposure time
+ }
+
+ if (maxExp == 0) {
+ maxExp = 10 * SEC; // Fallback maximum exposure time
+ }
+ }
+
+ dout << "Stream size is " << mWidth << " x " << mHeight << std::endl;
+ dout << "Valid exposure range is: " <<
+ minExp << " - " << maxExp << " ns " << std::endl;
+
+ {
+ camera_metadata_ro_entry sensivityRange =
+ GetStaticEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE);
+ EXPECT_EQ(2u, sensivityRange.count) << "No sensitivity range listed."
+ "Falling back to default set.";
+ int32_t minSensitivity = 100;
+ int32_t maxSensitivity = 800;
+ if (sensivityRange.count >= 2) {
+ minSensitivity = sensivityRange.data.i32[0];
+ maxSensitivity = sensivityRange.data.i32[1];
+ }
+ int32_t count = (maxSensitivity - minSensitivity + 99) / 100;
+ sensitivities.push_back(minSensitivity);
+ for (int i = 1; i < count; i++) {
+ sensitivities.push_back(minSensitivity + i * 100);
+ }
+ sensitivities.push_back(maxSensitivity);
+ }
+
+ dout << "Available sensitivities: ";
+ for (size_t i = 0; i < sensitivities.size(); i++) {
+ dout << sensitivities[i] << " ";
+ }
+ dout << std::endl;
+
+ {
+ camera_metadata_ro_entry availableProcessedSizes =
+ GetStaticEntry(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
+
+ camera_metadata_ro_entry availableProcessedMinFrameDurations =
+ GetStaticEntry(ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS);
+
+ EXPECT_EQ(availableProcessedSizes.count,
+ availableProcessedMinFrameDurations.count * 2) <<
+ "The number of minimum frame durations doesn't match the number of "
+ "available sizes. Using fallback values";
+
+ if (availableProcessedSizes.count ==
+ availableProcessedMinFrameDurations.count * 2) {
+ bool gotSize = false;
+ for (size_t i = 0; i < availableProcessedSizes.count; i += 2) {
+ if (availableProcessedSizes.data.i32[i] == mWidth &&
+ availableProcessedSizes.data.i32[i+1] == mHeight) {
+ gotSize = true;
+ minDuration = availableProcessedMinFrameDurations.data.i64[i/2];
+ }
+ }
+ EXPECT_TRUE(gotSize) << "Can't find stream size in list of "
+ "available sizes: " << mWidth << ", " << mHeight;
+ }
+ if (minDuration == 0) {
+ minDuration = 1 * SEC / 30; // Fall back to 30 fps as minimum duration
+ }
+
+ ASSERT_LT(0, minDuration);
+
+ camera_metadata_ro_entry maxFrameDuration =
+ GetStaticEntry(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION);
+
+ EXPECT_EQ(1u, maxFrameDuration.count) << "No valid maximum frame duration";
+
+ if (maxFrameDuration.count == 1) {
+ maxDuration = maxFrameDuration.data.i64[0];
+ }
+
+ EXPECT_GT(0, maxDuration) << "Max duration is 0 or not given, using fallback";
+
+ if (maxDuration == 0) {
+ maxDuration = 10 * SEC; // Fall back to 10 seconds as max duration
+ }
+
+ }
+ dout << "Available frame duration range for configured stream size: "
+ << minDuration << " - " << maxDuration << " ns" << std::endl;
+
+ // Get environment variables if set
+ const char *expVal = getenv(expEnv);
+ const char *durationVal = getenv(durationEnv);
+ const char *sensitivityVal = getenv(sensitivityEnv);
+
+ bool gotExp = (expVal != NULL);
+ bool gotDuration = (durationVal != NULL);
+ bool gotSensitivity = (sensitivityVal != NULL);
+
+ // All or none must be provided if using override envs
+ ASSERT_TRUE( (gotDuration && gotExp && gotSensitivity) ||
+ (!gotDuration && !gotExp && !gotSensitivity) ) <<
+ "Incomplete set of environment variable overrides provided";
+
+ Vector<int64_t> expList, durationList;
+ Vector<int32_t> sensitivityList;
+ if (gotExp) {
+ ParseList(expVal, expList);
+ ParseList(durationVal, durationList);
+ ParseList(sensitivityVal, sensitivityList);
+
+ ASSERT_TRUE(
+ (expList.size() == durationList.size()) &&
+ (durationList.size() == sensitivityList.size())) <<
+ "Mismatched sizes in env lists, or parse error";
+
+ dout << "Using burst list from environment with " << expList.size() <<
+ " captures" << std::endl;
+ } else {
+ // Create a default set of controls based on the available ranges
+
+ int64_t e;
+ int64_t d;
+ int32_t s;
+
+ // Exposure ramp
+
+ e = minExp;
+ d = minDuration;
+ s = sensitivities[0];
+ while (e < maxExp) {
+ expList.push_back(e);
+ durationList.push_back(d);
+ sensitivityList.push_back(s);
+ e = e * 2;
+ }
+ e = maxExp;
+ expList.push_back(e);
+ durationList.push_back(d);
+ sensitivityList.push_back(s);
+
+ // Duration ramp
+
+ e = 30 * MSEC;
+ d = minDuration;
+ s = sensitivities[0];
+ while (d < maxDuration) {
+ // make sure exposure <= frame duration
+ expList.push_back(e > d ? d : e);
+ durationList.push_back(d);
+ sensitivityList.push_back(s);
+ d = d * 2;
+ }
+
+ // Sensitivity ramp
+
+ e = 30 * MSEC;
+ d = 30 * MSEC;
+ d = d > minDuration ? d : minDuration;
+ for (size_t i = 0; i < sensitivities.size(); i++) {
+ expList.push_back(e);
+ durationList.push_back(d);
+ sensitivityList.push_back(sensitivities[i]);
+ }
+
+ // Constant-EV ramp, duration == exposure
+
+ e = 30 * MSEC; // at ISO 100
+ for (size_t i = 0; i < sensitivities.size(); i++) {
+ int64_t e_adj = e * 100 / sensitivities[i];
+ expList.push_back(e_adj);
+ durationList.push_back(e_adj > minDuration ? e_adj : minDuration);
+ sensitivityList.push_back(sensitivities[i]);
+ }
+
+ dout << "Default burst sequence created with " << expList.size() <<
+ " entries" << std::endl;
+ }
+
+ // Validate the list, but warn only
+ for (size_t i = 0; i < expList.size(); i++) {
+ EXPECT_GE(maxExp, expList[i])
+ << "Capture " << i << " exposure too long: " << expList[i];
+ EXPECT_LE(minExp, expList[i])
+ << "Capture " << i << " exposure too short: " << expList[i];
+ EXPECT_GE(maxDuration, durationList[i])
+ << "Capture " << i << " duration too long: " << durationList[i];
+ EXPECT_LE(minDuration, durationList[i])
+ << "Capture " << i << " duration too short: " << durationList[i];
+ bool validSensitivity = false;
+ for (size_t j = 0; j < sensitivities.size(); j++) {
+ if (sensitivityList[i] == sensitivities[j]) {
+ validSensitivity = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(validSensitivity)
+ << "Capture " << i << " sensitivity not in list: " << sensitivityList[i];
+ }
+
+ // Check if debug yuv dumps are requested
+
+ bool dumpFrames = false;
+ {
+ const char *frameDumpVal = getenv(dumpFrameEnv);
+ if (frameDumpVal != NULL) {
+ if (frameDumpVal[0] == '1') dumpFrames = true;
+ }
+ }
+
+ dout << "Dumping YUV frames " <<
+ (dumpFrames ? "enabled, not checking timing" : "disabled") << std::endl;
+
+ // Create a base preview request, turning off all 3A
+ CameraMetadata previewRequest;
+ ASSERT_EQ(OK, mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+ &previewRequest));
+ {
+ Vector<uint8_t> outputStreamIds;
+ outputStreamIds.push(mStreamId);
+ ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
+ outputStreamIds));
+
+ // Disable all 3A routines
+ uint8_t cmOff = static_cast<uint8_t>(ANDROID_CONTROL_MODE_OFF);
+ ASSERT_EQ(OK, previewRequest.update(ANDROID_CONTROL_MODE,
+ &cmOff, 1));
+
+ int requestId = 1;
+ ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_ID,
+ &requestId, 1));
+ }
+
+ // Submit capture requests
+
+ for (size_t i = 0; i < expList.size(); ++i) {
+ CameraMetadata tmpRequest = previewRequest;
+ ASSERT_EQ(OK, tmpRequest.update(ANDROID_SENSOR_EXPOSURE_TIME,
+ &expList[i], 1));
+ ASSERT_EQ(OK, tmpRequest.update(ANDROID_SENSOR_FRAME_DURATION,
+ &durationList[i], 1));
+ ASSERT_EQ(OK, tmpRequest.update(ANDROID_SENSOR_SENSITIVITY,
+ &sensitivityList[i], 1));
+ ALOGV("Submitting capture %d with exposure %lld, frame duration %lld, sensitivity %d",
+ i, expList[i], durationList[i], sensitivityList[i]);
+ dout << "Capture request " << i <<
+ ": exposure is " << (expList[i]/1e6f) << " ms" <<
+ ", frame duration is " << (durationList[i]/1e6f) << " ms" <<
+ ", sensitivity is " << sensitivityList[i] <<
+ std::endl;
+ ASSERT_EQ(OK, mDevice->capture(tmpRequest));
+ }
+
+ Vector<float> brightnesses;
+ Vector<nsecs_t> captureTimes;
+ brightnesses.setCapacity(expList.size());
+ captureTimes.setCapacity(expList.size());
+
+ // Get each frame (metadata) and then the buffer. Calculate brightness.
+ for (size_t i = 0; i < expList.size(); ++i) {
+
+ ALOGV("Reading request %d", i);
+ dout << "Waiting for capture " << i << ": " <<
+ " exposure " << (expList[i]/1e6f) << " ms," <<
+ " frame duration " << (durationList[i]/1e6f) << " ms," <<
+ " sensitivity " << sensitivityList[i] <<
+ std::endl;
+
+ // Set wait limit based on expected frame duration, or minimum timeout
+ int64_t waitLimit = CAMERA_FRAME_TIMEOUT;
+ if (expList[i] * 2 > waitLimit) waitLimit = expList[i] * 2;
+ if (durationList[i] * 2 > waitLimit) waitLimit = durationList[i] * 2;
+
+ ASSERT_EQ(OK, mDevice->waitForNextFrame(waitLimit));
+ ALOGV("Reading capture request-1 %d", i);
+ CameraMetadata frameMetadata;
+ ASSERT_EQ(OK, mDevice->getNextFrame(&frameMetadata));
+ ALOGV("Reading capture request-2 %d", i);
+
+ ASSERT_EQ(OK, mFrameListener->waitForFrame(CAMERA_FRAME_TIMEOUT));
+ ALOGV("We got the frame now");
+
+ captureTimes.push_back(systemTime());
+
+ CpuConsumer::LockedBuffer imgBuffer;
+ ASSERT_EQ(OK, mCpuConsumer->lockNextBuffer(&imgBuffer));
+
+ int underexposed, overexposed;
+ float avgBrightness = 0;
+ long long brightness = TotalBrightness(imgBuffer, &underexposed,
+ &overexposed);
+ int numValidPixels = mWidth * mHeight - (underexposed + overexposed);
+ if (numValidPixels != 0) {
+ avgBrightness = brightness * 1.0f / numValidPixels;
+ } else if (underexposed < overexposed) {
+ avgBrightness = 255;
+ }
+
+ ALOGV("Total brightness for frame %d was %lld (underexposed %d, "
+ "overexposed %d), avg %f", i, brightness, underexposed,
+ overexposed, avgBrightness);
+ dout << "Average brightness (frame " << i << ") was " << avgBrightness
+ << " (underexposed " << underexposed << ", overexposed "
+ << overexposed << ")" << std::endl;
+ brightnesses.push_back(avgBrightness);
+
+ if (i != 0) {
+ float prevEv = static_cast<float>(expList[i - 1]) * sensitivityList[i - 1];
+ float currentEv = static_cast<float>(expList[i]) * sensitivityList[i];
+ float evRatio = (prevEv > currentEv) ? (currentEv / prevEv) :
+ (prevEv / currentEv);
+ if ( evRatio > EV_MATCH_BOUND ) {
+ EXPECT_LT( fabs(brightnesses[i] - brightnesses[i - 1]),
+ BRIGHTNESS_MATCH_BOUND) <<
+ "Capture brightness different from previous, even though "
+ "they have the same EV value. Ev now: " << currentEv <<
+ ", previous: " << prevEv << ". Brightness now: " <<
+ brightnesses[i] << ", previous: " << brightnesses[i-1];
+ }
+ // Only check timing if not saving to disk, since that slows things
+ // down substantially
+ if (!dumpFrames) {
+ nsecs_t timeDelta = captureTimes[i] - captureTimes[i-1];
+ nsecs_t expectedDelta = expList[i] > durationList[i] ?
+ expList[i] : durationList[i];
+ EXPECT_LT(timeDelta, expectedDelta + DURATION_UPPER_BOUND) <<
+ "Capture took " << timeDelta << " ns to receive, but expected"
+ " frame duration was " << expectedDelta << " ns.";
+ EXPECT_GT(timeDelta, expectedDelta - DURATION_LOWER_BOUND) <<
+ "Capture took " << timeDelta << " ns to receive, but expected"
+ " frame duration was " << expectedDelta << " ns.";
+ dout << "Time delta from previous frame: " << timeDelta / 1e6 <<
+ " ms. Expected " << expectedDelta / 1e6 << " ms" << std::endl;
+ }
+ }
+
+ if (dumpFrames) {
+ String8 dumpName =
+ String8::format("/data/local/tmp/camera2_test_variable_burst_frame_%03d.yuv", i);
+ dout << " Writing YUV dump to " << dumpName << std::endl;
+ DumpYuvToFile(dumpName, imgBuffer);
+ }
+
+ ASSERT_EQ(OK, mCpuConsumer->unlockBuffer(imgBuffer));
+ }
+
}
+}
+}
+}
diff --git a/tests/camera2/CameraFrameTests.cpp b/tests/camera2/CameraFrameTests.cpp
index 2b5b546..8445098 100644
--- a/tests/camera2/CameraFrameTests.cpp
+++ b/tests/camera2/CameraFrameTests.cpp
@@ -23,7 +23,7 @@
#include "hardware/hardware.h"
#include "hardware/camera2.h"
-#include "Camera2Device.h"
+#include "CameraDeviceBase.h"
#include "utils/StrongPointer.h"
#include <gui/CpuConsumer.h>
@@ -46,7 +46,7 @@
namespace tests {
static CameraStreamParams STREAM_PARAMETERS = {
- /*mFormat*/ HAL_PIXEL_FORMAT_YCrCb_420_SP,
+ /*mFormat*/ CAMERA_STREAM_AUTO_CPU_FORMAT,
/*mHeapCount*/ CAMERA_HEAP_COUNT
};
@@ -139,4 +139,3 @@
}
}
}
-
diff --git a/tests/camera2/CameraMetadataTests.cpp b/tests/camera2/CameraMetadataTests.cpp
index 8cae619..66c4847 100644
--- a/tests/camera2/CameraMetadataTests.cpp
+++ b/tests/camera2/CameraMetadataTests.cpp
@@ -25,7 +25,7 @@
#include "hardware/hardware.h"
#include "hardware/camera2.h"
-#include "Camera2Device.h"
+#include "CameraDeviceBase.h"
#include "utils/StrongPointer.h"
#include <gui/CpuConsumer.h>
@@ -142,13 +142,25 @@
HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
HAL_PIXEL_FORMAT_BLOB)); // JPEG
- EXPECT_TRUE(
- HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
- HAL_PIXEL_FORMAT_YCrCb_420_SP)); // NV21
+ if (getDeviceVersion() < CAMERA_DEVICE_API_VERSION_3_0) {
+ // HAL2 can support either flexible YUV or YV12 + NV21
+ if (!HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
+ HAL_PIXEL_FORMAT_YCbCr_420_888)) {
- EXPECT_TRUE(
- HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
- HAL_PIXEL_FORMAT_YV12));
+ EXPECT_TRUE(
+ HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
+ HAL_PIXEL_FORMAT_YCrCb_420_SP)); // NV21
+
+ EXPECT_TRUE(
+ HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
+ HAL_PIXEL_FORMAT_YV12));
+ }
+ } else {
+ // HAL3 must support flexible YUV
+ EXPECT_TRUE(HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
+ HAL_PIXEL_FORMAT_YCbCr_420_888));
+ }
+
}
TEST_F(CameraMetadataTest, SaneResolutions) {
@@ -156,7 +168,7 @@
// Iff there are listed raw resolutions, the format should be available
int rawResolutionsCount =
- GetEntryCountFromStaticTag(HAL_PIXEL_FORMAT_RAW_SENSOR);
+ GetEntryCountFromStaticTag(ANDROID_SCALER_AVAILABLE_RAW_SIZES);
EXPECT_EQ(rawResolutionsCount > 0,
HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
HAL_PIXEL_FORMAT_RAW_SENSOR));
diff --git a/tests/camera2/CameraModuleFixture.h b/tests/camera2/CameraModuleFixture.h
index 01e1ad0..ef4a9a5 100644
--- a/tests/camera2/CameraModuleFixture.h
+++ b/tests/camera2/CameraModuleFixture.h
@@ -23,6 +23,7 @@
#include "hardware/camera2.h"
#include "Camera2Device.h"
+#include "Camera3Device.h"
#include "camera2_utils.h"
#include "TestExtensions.h"
@@ -82,6 +83,42 @@
}
}
+ void CreateCamera(int cameraID, /*out*/ sp<CameraDeviceBase> *device) {
+ struct camera_info info;
+ ASSERT_EQ(OK, mModule->get_camera_info(cameraID, &info));
+
+ ASSERT_GE((int)info.device_version, CAMERA_DEVICE_API_VERSION_2_0) <<
+ "Device version too old for camera " << cameraID << ". Version: " <<
+ info.device_version;
+ switch(info.device_version) {
+ case CAMERA_DEVICE_API_VERSION_2_0:
+ case CAMERA_DEVICE_API_VERSION_2_1:
+ *device = new Camera2Device(cameraID);
+ break;
+ case CAMERA_DEVICE_API_VERSION_3_0:
+ *device = new Camera3Device(cameraID);
+ break;
+ default:
+ device->clear();
+ FAIL() << "Device version unknown for camera " << cameraID << ". Version: " <<
+ info.device_version;
+ }
+
+ }
+
+ int getDeviceVersion() {
+ return getDeviceVersion(mCameraID);
+ }
+
+ int getDeviceVersion(int cameraId, status_t* status = NULL) {
+ camera_info info;
+ status_t res;
+ res = mModule->get_camera_info(cameraId, &info);
+ if (status != NULL) *status = res;
+
+ return info.device_version;
+ }
+
private:
void SetUpMixin() {
@@ -90,14 +127,12 @@
EXPECT_LE(0, mCameraID);
EXPECT_LT(mCameraID, mNumberOfCameras);
- /* HALBUG (Exynos5); crashes if trying to initialize
- before calling get_camera_info */
- if (InfoQuirk) {
- struct camera_info info;
- ASSERT_EQ(OK, mModule->get_camera_info(mCameraID, &info));
- }
+ /* HALBUG (Exynos5); crashes if we skip calling get_camera_info
+ before initializing. Need info anyway now. */
- mDevice = new Camera2Device(mCameraID);
+ CreateCamera(mCameraID, &mDevice);
+
+ ASSERT_TRUE(mDevice != NULL) << "Failed to open device " << mCameraID;
ASSERT_EQ(OK, mDevice->initialize(mModule))
<< "Failed to initialize device " << mCameraID;
}
@@ -110,7 +145,7 @@
protected:
int mNumberOfCameras;
camera_module_t *mModule;
- sp<Camera2Device> mDevice;
+ sp<CameraDeviceBase> mDevice;
private:
int mCameraID;
diff --git a/tests/camera2/CameraModuleTests.cpp b/tests/camera2/CameraModuleTests.cpp
index fc6fd36..44d3e3b 100644
--- a/tests/camera2/CameraModuleTests.cpp
+++ b/tests/camera2/CameraModuleTests.cpp
@@ -23,7 +23,7 @@
#include "hardware/hardware.h"
#include "hardware/camera2.h"
-#include "Camera2Device.h"
+#include "CameraDeviceBase.h"
#include "utils/StrongPointer.h"
#include "CameraModuleFixture.h"
@@ -54,13 +54,6 @@
return stat;
}
- int getDeviceVersion(int cameraId, status_t* status) {
- camera_info info;
- *status = mModule->get_camera_info(cameraId, &info);
-
- return info.device_version;
- }
-
bool isDeviceVersionHal2(int cameraId, status_t* status) {
return getDeviceVersion(cameraId, status)
>= CAMERA_DEVICE_API_VERSION_2_0;
@@ -72,8 +65,7 @@
TEST_EXTENSION_FORKING_INIT;
for (int i = 0; i < mNumberOfCameras; ++i) {
- mDevice = new Camera2Device(i);
-
+ CreateCamera(i, &mDevice);
ASSERT_EQ(OK, initializeDevice(i))
<< "Failed to initialize device " << i;
mDevice.clear();
@@ -88,6 +80,8 @@
int idx[] = { -1, mNumberOfCameras, mNumberOfCameras + 1 };
for (unsigned i = 0; i < sizeof(idx)/sizeof(idx[0]); ++i) {
+ // Since the initialization should fail at device open(), it doesn't
+ // matter which version of CameraNDevice is used here
mDevice = new Camera2Device(idx[i]);
status_t deviceInitializeCode = initializeDevice(idx[i]);
EXPECT_NE(OK, deviceInitializeCode);
@@ -136,4 +130,3 @@
}
}
}
-
diff --git a/tests/camera2/CameraStreamFixture.h b/tests/camera2/CameraStreamFixture.h
index c5db7ef..195e764 100644
--- a/tests/camera2/CameraStreamFixture.h
+++ b/tests/camera2/CameraStreamFixture.h
@@ -19,27 +19,50 @@
#include <gtest/gtest.h>
#include <iostream>
+#include <fstream>
#include <gui/CpuConsumer.h>
#include <gui/Surface.h>
#include <utils/Condition.h>
#include <utils/Mutex.h>
+#include <system/camera_metadata.h>
#include "CameraModuleFixture.h"
#include "TestExtensions.h"
+#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
+
namespace android {
namespace camera2 {
namespace tests {
+// Format specifier for picking the best format for CPU reading the given device
+// version
+#define CAMERA_STREAM_AUTO_CPU_FORMAT (-1)
+
+struct CameraStreamParams;
+
+void PrintTo(const CameraStreamParams& p, ::std::ostream* os);
+
struct CameraStreamParams {
int mFormat;
int mHeapCount;
+
};
+inline ::std::ostream& operator<<(::std::ostream& os, const CameraStreamParams &p) {
+ PrintTo(p, &os);
+ return os;
+}
+
inline void PrintTo(const CameraStreamParams& p, ::std::ostream* os) {
+ char fmt[100];
+ camera_metadata_enum_snprint(
+ ANDROID_SCALER_AVAILABLE_FORMATS, p.mFormat, fmt, sizeof(fmt));
+
*os << "{ ";
*os << "Format: 0x" << std::hex << p.mFormat << ", ";
+ *os << "Format name: " << fmt << ", ";
*os << "HeapCount: " << p.mHeapCount;
*os << " }";
}
@@ -71,7 +94,7 @@
CameraModuleFixture::SetUp();
CameraStreamParams p = mParam;
- sp<Camera2Device> device = mDevice;
+ sp<CameraDeviceBase> device = mDevice;
/* use an arbitrary w,h */
{
@@ -136,18 +159,21 @@
};
void CreateStream() {
- sp<Camera2Device> device = mDevice;
+ sp<CameraDeviceBase> device = mDevice;
CameraStreamParams p = mParam;
- mCpuConsumer = new CpuConsumer(p.mHeapCount);
+ sp<BufferQueue> bq = new BufferQueue();
+ mCpuConsumer = new CpuConsumer(bq, p.mHeapCount);
mCpuConsumer->setName(String8("CameraStreamTest::mCpuConsumer"));
mNativeWindow = new Surface(
mCpuConsumer->getProducerInterface());
+ int format = MapAutoFormat(p.mFormat);
+
ASSERT_EQ(OK,
device->createStream(mNativeWindow,
- mWidth, mHeight, p.mFormat, /*size (for jpegs)*/0,
+ mWidth, mHeight, format, /*size (for jpegs)*/0,
&mStreamId));
ASSERT_NE(-1, mStreamId);
@@ -161,6 +187,91 @@
ASSERT_EQ(OK, mDevice->deleteStream(mStreamId));
}
+ int MapAutoFormat(int format) {
+ if (format == CAMERA_STREAM_AUTO_CPU_FORMAT) {
+ if (getDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_0) {
+ format = HAL_PIXEL_FORMAT_YCbCr_420_888;
+ } else {
+ format = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+ }
+ }
+ return format;
+ }
+
+ void DumpYuvToFile(const String8 &fileName, const CpuConsumer::LockedBuffer &img) {
+ uint8_t *dataCb, *dataCr;
+ uint32_t stride;
+ uint32_t chromaStride;
+ uint32_t chromaStep;
+
+ switch (img.format) {
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ stride = img.stride;
+ chromaStride = img.chromaStride;
+ chromaStep = img.chromaStep;
+ dataCb = img.dataCb;
+ dataCr = img.dataCr;
+ break;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ stride = img.width;
+ chromaStride = img.width;
+ chromaStep = 2;
+ dataCr = img.data + img.width * img.height;
+ dataCb = dataCr + 1;
+ break;
+ case HAL_PIXEL_FORMAT_YV12:
+ stride = img.stride;
+ chromaStride = ALIGN(img.width / 2, 16);
+ chromaStep = 1;
+ dataCr = img.data + img.stride * img.height;
+ dataCb = dataCr + chromaStride * img.height/2;
+ break;
+ default:
+ ALOGE("Unknown format %d, not dumping", img.format);
+ return;
+ }
+
+ // Write Y
+ FILE *yuvFile = fopen(fileName.string(), "w");
+
+ size_t bytes;
+
+ for (size_t y = 0; y < img.height; ++y) {
+ bytes = fwrite(
+ reinterpret_cast<const char*>(img.data + stride * y),
+ 1, img.width, yuvFile);
+ if (bytes != img.width) {
+ ALOGE("Unable to write to file %s", fileName.string());
+ fclose(yuvFile);
+ return;
+ }
+ }
+
+ // Write Cb/Cr
+ uint8_t *src = dataCb;
+ for (int c = 0; c < 2; ++c) {
+ for (size_t y = 0; y < img.height / 2; ++y) {
+ uint8_t *px = src + y * chromaStride;
+ if (chromaStep != 1) {
+ for (size_t x = 0; x < img.width / 2; ++x) {
+ fputc(*px, yuvFile);
+ px += chromaStep;
+ }
+ } else {
+ bytes = fwrite(reinterpret_cast<const char*>(px),
+ 1, img.width / 2, yuvFile);
+ if (bytes != img.width / 2) {
+ ALOGE("Unable to write to file %s", fileName.string());
+ fclose(yuvFile);
+ return;
+ }
+ }
+ }
+ src = dataCr;
+ }
+ fclose(yuvFile);
+ }
+
int mWidth;
int mHeight;
diff --git a/tests/camera2/CameraStreamTests.cpp b/tests/camera2/CameraStreamTests.cpp
index 5423a30..164e0e5 100644
--- a/tests/camera2/CameraStreamTests.cpp
+++ b/tests/camera2/CameraStreamTests.cpp
@@ -93,8 +93,8 @@
std::cerr << "Skipping test "
<< test_info->test_case_name() << "."
<< test_info->name()
- << " because the format was not available: 0x"
- << std::hex << GetParam().mFormat << std::endl;
+ << " because the format was not available: "
+ << GetParam() << std::endl;
return;
}
}
@@ -186,4 +186,3 @@
}
}
}
-
diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp
index 0f75070..87f51f0 100644
--- a/tests/camera2/camera2.cpp
+++ b/tests/camera2/camera2.cpp
@@ -92,7 +92,8 @@
std::cout << " Version: 0x" << std::hex <<
info.device_version << std::endl;
}
- if (info.device_version >= CAMERA_DEVICE_API_VERSION_2_0) {
+ if (info.device_version >= CAMERA_DEVICE_API_VERSION_2_0 &&
+ info.device_version < CAMERA_DEVICE_API_VERSION_3_0) {
sCameraSupportsHal2[i] = true;
ASSERT_TRUE(NULL != info.static_camera_characteristics);
IF_ALOGV() {
@@ -181,12 +182,15 @@
return OK;
}
- static status_t closeCameraDevice(camera2_device_t *cam_dev) {
+ static status_t closeCameraDevice(camera2_device_t **cam_dev) {
int res;
+ if (*cam_dev == NULL ) return OK;
+
ALOGV("Closing camera %p", cam_dev);
- hw_device_t *dev = reinterpret_cast<hw_device_t *>(cam_dev);
+ hw_device_t *dev = reinterpret_cast<hw_device_t *>(*cam_dev);
res = dev->close(dev);
+ *cam_dev = NULL;
return res;
}
@@ -195,7 +199,7 @@
status_t res;
if (mDevice != NULL) {
- closeCameraDevice(mDevice);
+ closeCameraDevice(&mDevice);
}
mDevice = openCameraDevice(id);
ASSERT_TRUE(NULL != mDevice) << "Failed to open camera device";
@@ -324,7 +328,7 @@
delete mStreams[i];
}
if (mDevice != NULL) {
- closeCameraDevice(mDevice);
+ closeCameraDevice(&mDevice);
}
TearDownModule();
@@ -366,7 +370,7 @@
camera2_device_t *d = openCameraDevice(id);
ASSERT_TRUE(NULL != d) << "Failed to open camera device";
- res = closeCameraDevice(d);
+ res = closeCameraDevice(&d);
ASSERT_EQ(NO_ERROR, res) << "Failed to close camera device";
}
}
@@ -382,7 +386,8 @@
ASSERT_NO_FATAL_FAILURE(setUpCamera(id));
- sp<CpuConsumer> rawConsumer = new CpuConsumer(1);
+ sp<BufferQueue> bq = new BufferQueue();
+ sp<CpuConsumer> rawConsumer = new CpuConsumer(bq, 1);
sp<FrameWaiter> rawWaiter = new FrameWaiter();
rawConsumer->setFrameAvailableListener(rawWaiter);
@@ -499,7 +504,7 @@
ASSERT_EQ(OK, waitUntilDrained());
ASSERT_NO_FATAL_FAILURE(disconnectStream(streamId));
- res = closeCameraDevice(mDevice);
+ res = closeCameraDevice(&mDevice);
ASSERT_EQ(NO_ERROR, res) << "Failed to close camera device";
}
@@ -516,7 +521,8 @@
ASSERT_NO_FATAL_FAILURE(setUpCamera(id));
- sp<CpuConsumer> rawConsumer = new CpuConsumer(1);
+ sp<BufferQueue> bq = new BufferQueue();
+ sp<CpuConsumer> rawConsumer = new CpuConsumer(bq, 1);
sp<FrameWaiter> rawWaiter = new FrameWaiter();
rawConsumer->setFrameAvailableListener(rawWaiter);
@@ -697,7 +703,8 @@
ASSERT_NO_FATAL_FAILURE(setUpCamera(id));
- sp<CpuConsumer> jpegConsumer = new CpuConsumer(1);
+ sp<BufferQueue> bq = new BufferQueue();
+ sp<CpuConsumer> jpegConsumer = new CpuConsumer(bq, 1);
sp<FrameWaiter> jpegWaiter = new FrameWaiter();
jpegConsumer->setFrameAvailableListener(jpegWaiter);
@@ -802,7 +809,7 @@
ASSERT_EQ(OK, waitUntilDrained());
ASSERT_NO_FATAL_FAILURE(disconnectStream(streamId));
- res = closeCameraDevice(mDevice);
+ res = closeCameraDevice(&mDevice);
ASSERT_EQ(NO_ERROR, res) << "Failed to close camera device";
}