@@ -1221,6 +1221,10 @@ void CameraDevice::requestComplete(Request *request)
CameraStream *stream = iter->first;
StreamBuffer *buffer = iter->second;
+ if (stream->isJpegStream()) {
+ generateJpegExifMetadata(descriptor, buffer);
+ }
+
FrameBuffer *src = request->findBuffer(stream->stream());
if (!src) {
LOG(HAL, Error) << "Failed to find a source stream buffer";
@@ -1410,6 +1414,29 @@ void CameraDevice::notifyError(uint32_t frameNumber, camera3_stream_t *stream,
callbacks_->notify(callbacks_, ¬ify);
}
+/*
+ * Set jpeg metadata used to generate EXIF in the JPEG post processing.
+ */
+void CameraDevice::generateJpegExifMetadata(Camera3RequestDescriptor *request,
+ StreamBuffer *buffer) const
+{
+ const ControlList &metadata = request->request_->metadata();
+ auto &jpegExifMetadata = buffer->jpegExifMetadata;
+ jpegExifMetadata.emplace(StreamBuffer::JpegExifMetadata());
+
+ jpegExifMetadata->sensorExposureTime = 0;
+ if (metadata.contains(controls::ExposureTime)) {
+ jpegExifMetadata->sensorExposureTime = metadata.get(controls::ExposureTime) * 1000ULL;
+ }
+
+ /*
+ * todo: Android Sensitivity = analog gain X digital gain only on sensor.
+ * Digital gain on ISP shouldn't be included. Calculate sensitivity
+ * accordingingly when we can differentiate the source of digital gains.
+ */
+ jpegExifMetadata->sensorSensitivityISO = 100;
+}
+
/*
* Produce a set of fixed result metadata.
*/
@@ -97,6 +97,8 @@ private:
LIBCAMERA_TSA_EXCLUDES(descriptorsMutex_);
void sendCaptureResults() LIBCAMERA_TSA_REQUIRES(descriptorsMutex_);
void setBufferStatus(StreamBuffer &buffer, StreamBuffer::Status status);
+ void generateJpegExifMetadata(Camera3RequestDescriptor *request,
+ StreamBuffer *buffer) const;
std::unique_ptr<CameraMetadata> getResultMetadata(
const Camera3RequestDescriptor &descriptor) const;
@@ -42,6 +42,11 @@ public:
StreamBuffer(StreamBuffer &&);
StreamBuffer &operator=(StreamBuffer &&);
+ struct JpegExifMetadata {
+ int64_t sensorExposureTime;
+ int32_t sensorSensitivityISO;
+ };
+
CameraStream *stream;
buffer_handle_t *camera3Buffer;
std::unique_ptr<libcamera::FrameBuffer> frameBuffer;
@@ -50,6 +55,7 @@ public:
libcamera::FrameBuffer *internalBuffer = nullptr;
const libcamera::FrameBuffer *srcBuffer = nullptr;
std::unique_ptr<CameraBuffer> dstBuffer;
+ std::optional<JpegExifMetadata> jpegExifMetadata;
Camera3RequestDescriptor *request;
private:
@@ -125,6 +125,10 @@ public:
const libcamera::StreamConfiguration &configuration() const;
libcamera::Stream *stream() const;
CameraStream *sourceStream() const { return sourceStream_; }
+ bool isJpegStream() const
+ {
+ return camera3Stream_->format == HAL_PIXEL_FORMAT_BLOB;
+ }
int configure();
int process(StreamBuffer *streamBuffer);
@@ -104,8 +104,11 @@ void PostProcessorJpeg::process(StreamBuffer *streamBuffer)
const FrameBuffer &source = *streamBuffer->srcBuffer;
CameraBuffer *destination = streamBuffer->dstBuffer.get();
+ const std::optional<StreamBuffer::JpegExifMetadata> &jpegExifMetadata =
+ streamBuffer->jpegExifMetadata;
ASSERT(destination->numPlanes() == 1);
+ ASSERT(jpegExifMetadata.has_value());
const CameraMetadata &requestMetadata = streamBuffer->request->settings_;
CameraMetadata *resultMetadata = streamBuffer->request->resultMetadata_.get();
@@ -131,15 +134,13 @@ void PostProcessorJpeg::process(StreamBuffer *streamBuffer)
*/
exif.setTimestamp(std::time(nullptr), 0ms);
- ret = resultMetadata->getEntry(ANDROID_SENSOR_EXPOSURE_TIME, &entry);
- exif.setExposureTime(ret ? *entry.data.i64 : 0);
+ exif.setExposureTime(jpegExifMetadata->sensorExposureTime * 1000);
+ exif.setISO(jpegExifMetadata->sensorSensitivityISO);
+
ret = requestMetadata.getEntry(ANDROID_LENS_APERTURE, &entry);
if (ret)
exif.setAperture(*entry.data.f);
- ret = resultMetadata->getEntry(ANDROID_SENSOR_SENSITIVITY, &entry);
- exif.setISO(ret ? *entry.data.i32 : 100);
-
exif.setFlash(Exif::Flash::FlashNotPresent);
exif.setWhiteBalance(Exif::WhiteBalance::Auto);
@@ -152,6 +153,7 @@ void PostProcessorJpeg::process(StreamBuffer *streamBuffer)
*entry.data.i64);
}
+ std::vector<unsigned char> thumbnail;
ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_SIZE, &entry);
if (ret) {
const int32_t *data = entry.data.i32;
@@ -163,7 +165,6 @@ void PostProcessorJpeg::process(StreamBuffer *streamBuffer)
resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, quality);
if (thumbnailSize != Size(0, 0)) {
- std::vector<unsigned char> thumbnail;
generateThumbnail(source, thumbnailSize, quality, &thumbnail);
if (!thumbnail.empty())
exif.setThumbnail(thumbnail, Exif::Compression::JPEG);
With partial result, some metadata needed to adding into Exif may be sent back to framework earlier before Jpeg post-processing. Add a type JpegExifMetadata associated with StreamBuffer to store the values, so Jpeg post-processing doesn't need to reference to current metadata for the them. Signed-off-by: Han-Lin Chen <hanlinchen@chromium.org> --- src/android/camera_device.cpp | 27 ++++++++++++++++++++++++ src/android/camera_device.h | 2 ++ src/android/camera_request.h | 6 ++++++ src/android/camera_stream.h | 4 ++++ src/android/jpeg/post_processor_jpeg.cpp | 13 ++++++------ 5 files changed, 46 insertions(+), 6 deletions(-)