summaryrefslogtreecommitdiff
path: root/src/android/mm
AgeCommit message (Expand)Author
2021-11-08android: mm: Null check for CameraBufferManagerUmang Jain
2021-09-09android: mm: cros_camera_buffer: Log failure error on cleanupUmang Jain
2021-09-07libcamera: formats: Add planeSize() helpers to PixelFormatInfoLaurent Pinchart
2021-09-06android: Cleanup libcamera namespace usageUmang Jain
2021-08-31android: generic_camera_buffer: Fix bufferLength_ initializationLaurent Pinchart
2021-08-30libcamera: mapped_framebuffer: Return plane begin address by MappedBuffer::ma...Hirokazu Honda
2021-08-27android: camera_buffer: Add stride/offset/size functionHirokazu Honda
2021-08-27android: camera_buffer: Map buffer in the first plane() callHirokazu Honda
2021-08-27android: generic_camera_buffer: Correct buffer mappingHirokazu Honda
2021-08-10libcamera: Give MappedFrameBuffer its own implementationKieran Bingham
2021-08-06android: mm: cros_camera_buffer: Fix unused parameterHirokazu Honda
2021-08-03libcamera: base: class: Don't pass Extensible pointer to Private constructorLaurent Pinchart
2021-07-11libcamera: buffer: Rename buffer.h to framebuffer.hLaurent Pinchart
2021-06-28android: mm: cros_camera_buffer: Drop undefined functionsLaurent Pinchart
2021-06-25libcamera/base: Move extended base functionalityKieran Bingham
2021-06-25android: mm: cros_camera_buffer: Fix wrong indexing in plane()Hirokazu Honda
2021-06-01android: Fix unused parameter warnings on Chrome OSLaurent Pinchart
2021-05-31android: Don't rely on indirect inclusion of unistd.hLaurent Pinchart
2021-05-05src: android: Rectify internal header's #include pathUmang Jain
2021-04-04android: mm: cros: Fix compilationLaurent Pinchart
2021-04-04android: mm: cros: Handle buffer registration failureHirokazu Honda
2021-03-03android: Introduce Chromium OS buffer managerJacopo Mondi
2021-03-03android: mm: Provide helper macro for PIMPLJacopo Mondi
2021-03-03android: camera_buffer: Add method to get the JPEG blob sizeJacopo Mondi
2021-03-03android: post_processor: Use CameraBuffer APIJacopo Mondi
2021-03-03android: camera_buffer: Implement libcamera::ExtensibleJacopo Mondi
2021-03-03android: camera_buffer: Drop 'const' from buffer_handle_tJacopo Mondi
2021-03-03android: Introduce CameraBuffer interfaceJacopo Mondi
quest.h" #include "encoder_libjpeg.h" #include "exif.h" #include <libcamera/base/log.h> #include <libcamera/formats.h> using namespace libcamera; using namespace std::chrono_literals; LOG_DEFINE_CATEGORY(JPEG) PostProcessorJpeg::PostProcessorJpeg(CameraDevice *const device) : cameraDevice_(device) { } int PostProcessorJpeg::configure(const StreamConfiguration &inCfg, const StreamConfiguration &outCfg) { if (inCfg.size != outCfg.size) { LOG(JPEG, Error) << "Mismatch of input and output stream sizes"; return -EINVAL; } if (outCfg.pixelFormat != formats::MJPEG) { LOG(JPEG, Error) << "Output stream pixel format is not JPEG"; return -EINVAL; } streamSize_ = outCfg.size; thumbnailer_.configure(inCfg.size, inCfg.pixelFormat); encoder_ = std::make_unique<EncoderLibJpeg>(); return encoder_->configure(inCfg); } void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, const Size &targetSize, unsigned int quality, std::vector<unsigned char> *thumbnail) { /* Stores the raw scaled-down thumbnail bytes. */ std::vector<unsigned char> rawThumbnail; thumbnailer_.createThumbnail(source, targetSize, &rawThumbnail); StreamConfiguration thCfg; thCfg.size = targetSize; thCfg.pixelFormat = thumbnailer_.pixelFormat(); int ret = thumbnailEncoder_.configure(thCfg); if (!rawThumbnail.empty() && !ret) { /* * \todo Avoid value-initialization of all elements of the * vector. */ thumbnail->resize(rawThumbnail.size()); /* * Split planes manually as the encoder expects a vector of * planes. * * \todo Pass a vector of planes directly to * Thumbnailer::createThumbnailer above and remove the manual * planes split from here. */ std::vector<Span<uint8_t>> thumbnailPlanes; const PixelFormatInfo &formatNV12 = PixelFormatInfo::info(formats::NV12); size_t yPlaneSize = formatNV12.planeSize(targetSize, 0); size_t uvPlaneSize = formatNV12.planeSize(targetSize, 1); thumbnailPlanes.push_back({ rawThumbnail.data(), yPlaneSize }); thumbnailPlanes.push_back({ rawThumbnail.data() + yPlaneSize, uvPlaneSize }); int jpeg_size = thumbnailEncoder_.encode(thumbnailPlanes, *thumbnail, {}, quality); thumbnail->resize(jpeg_size); LOG(JPEG, Debug) << "Thumbnail compress returned " << jpeg_size << " bytes"; } } void PostProcessorJpeg::process(Camera3RequestDescriptor::StreamBuffer *streamBuffer) { ASSERT(encoder_); const FrameBuffer &source = *streamBuffer->srcBuffer; CameraBuffer *destination = streamBuffer->dstBuffer.get(); ASSERT(destination->numPlanes() == 1); const CameraMetadata &requestMetadata = streamBuffer->request->settings_; CameraMetadata *resultMetadata = streamBuffer->request->resultMetadata_.get(); camera_metadata_ro_entry_t entry; int ret; /* Set EXIF metadata for various tags. */ Exif exif; exif.setMake(cameraDevice_->maker()); exif.setModel(cameraDevice_->model()); ret = requestMetadata.getEntry(ANDROID_JPEG_ORIENTATION, &entry); const uint32_t jpegOrientation = ret ? *entry.data.i32 : 0; resultMetadata->addEntry(ANDROID_JPEG_ORIENTATION, jpegOrientation); exif.setOrientation(jpegOrientation); exif.setSize(streamSize_); /* * We set the frame's EXIF timestamp as the time of encode. * Since the precision we need for EXIF timestamp is only one * second, it is good enough. */ exif.setTimestamp(std::time(nullptr), 0ms); ret = resultMetadata->getEntry(ANDROID_SENSOR_EXPOSURE_TIME, &entry); exif.setExposureTime(ret ? *entry.data.i64 : 0); 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); exif.setFocalLength(1.0); ret = requestMetadata.getEntry(ANDROID_JPEG_GPS_TIMESTAMP, &entry); if (ret) { exif.setGPSDateTimestamp(*entry.data.i64); resultMetadata->addEntry(ANDROID_JPEG_GPS_TIMESTAMP, *entry.data.i64); } ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_SIZE, &entry); if (ret) { const int32_t *data = entry.data.i32; Size thumbnailSize = { static_cast<uint32_t>(data[0]), static_cast<uint32_t>(data[1]) }; ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &entry); uint8_t quality = ret ? *entry.data.u8 : 95; 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); } resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE, data, 2); } ret = requestMetadata.getEntry(ANDROID_JPEG_GPS_COORDINATES, &entry); if (ret) { exif.setGPSLocation(entry.data.d); resultMetadata->addEntry(ANDROID_JPEG_GPS_COORDINATES, entry.data.d, 3); } ret = requestMetadata.getEntry(ANDROID_JPEG_GPS_PROCESSING_METHOD, &entry); if (ret) { std::string method(entry.data.u8, entry.data.u8 + entry.count); exif.setGPSMethod(method); resultMetadata->addEntry(ANDROID_JPEG_GPS_PROCESSING_METHOD, entry.data.u8, entry.count); } if (exif.generate() != 0) LOG(JPEG, Error) << "Failed to generate valid EXIF data"; ret = requestMetadata.getEntry(ANDROID_JPEG_QUALITY, &entry); const uint8_t quality = ret ? *entry.data.u8 : 95; resultMetadata->addEntry(ANDROID_JPEG_QUALITY, quality); int jpeg_size = encoder_->encode(source, destination->plane(0), exif.data(), quality); if (jpeg_size < 0) { LOG(JPEG, Error) << "Failed to encode stream image"; processComplete.emit(streamBuffer, PostProcessor::Status::Error); return; } /* Fill in the JPEG blob header. */ uint8_t *resultPtr = destination->plane(0).data() + destination->jpegBufferSize(cameraDevice_->maxJpegBufferSize()) - sizeof(struct camera3_jpeg_blob); auto *blob = reinterpret_cast<struct camera3_jpeg_blob *>(resultPtr); blob->jpeg_blob_id = CAMERA3_JPEG_BLOB_ID; blob->jpeg_size = jpeg_size; /* Update the JPEG result Metadata. */ resultMetadata->addEntry(ANDROID_JPEG_SIZE, jpeg_size); processComplete.emit(streamBuffer, PostProcessor::Status::Success); }