blob: bb7dd810f5370203afdd34b42d2aff501ee1b9d7 [file] [log] [blame]
Emilian Peev434248e2022-10-06 14:58:54 -07001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "hardware/gralloc.h"
18#include "system/graphics-base-v1.0.h"
19#include "system/graphics-base-v1.1.h"
20#define LOG_TAG "Camera3-JpegRCompositeStream"
21#define ATRACE_TAG ATRACE_TAG_CAMERA
22//#define LOG_NDEBUG 0
23
24#include <aidl/android/hardware/camera/device/CameraBlob.h>
25#include <aidl/android/hardware/camera/device/CameraBlobId.h>
26
27#include "common/CameraProviderManager.h"
28#include <gui/Surface.h>
Dichen Zhang809ed082023-02-10 22:42:30 +000029#include <jpegrecoverymap/jpegr.h>
Emilian Peev434248e2022-10-06 14:58:54 -070030#include <utils/ExifUtils.h>
31#include <utils/Log.h>
32#include "utils/SessionConfigurationUtils.h"
33#include <utils/Trace.h>
34
35#include "JpegRCompositeStream.h"
36
37namespace android {
38namespace camera3 {
39
40using aidl::android::hardware::camera::device::CameraBlob;
41using aidl::android::hardware::camera::device::CameraBlobId;
42
43JpegRCompositeStream::JpegRCompositeStream(sp<CameraDeviceBase> device,
44 wp<hardware::camera2::ICameraDeviceCallbacks> cb) :
45 CompositeStream(device, cb),
46 mBlobStreamId(-1),
47 mBlobSurfaceId(-1),
48 mP010StreamId(-1),
49 mP010SurfaceId(-1),
50 mBlobWidth(0),
51 mBlobHeight(0),
52 mP010BufferAcquired(false),
53 mBlobBufferAcquired(false),
54 mOutputColorSpace(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED),
55 mProducerListener(new ProducerListener()),
56 mMaxJpegBufferSize(-1),
57 mUHRMaxJpegBufferSize(-1),
58 mStaticInfo(device->info()) {
59 auto entry = mStaticInfo.find(ANDROID_JPEG_MAX_SIZE);
60 if (entry.count > 0) {
61 mMaxJpegBufferSize = entry.data.i32[0];
62 } else {
63 ALOGW("%s: Maximum jpeg size absent from camera characteristics", __FUNCTION__);
64 }
65
66 mUHRMaxJpegSize =
67 SessionConfigurationUtils::getMaxJpegResolution(mStaticInfo,
68 /*ultraHighResolution*/true);
69 mDefaultMaxJpegSize =
70 SessionConfigurationUtils::getMaxJpegResolution(mStaticInfo,
71 /*isUltraHighResolution*/false);
72
73 mUHRMaxJpegBufferSize =
74 SessionConfigurationUtils::getUHRMaxJpegBufferSize(mUHRMaxJpegSize, mDefaultMaxJpegSize,
75 mMaxJpegBufferSize);
76}
77
78JpegRCompositeStream::~JpegRCompositeStream() {
79 mBlobConsumer.clear(),
80 mBlobSurface.clear(),
81 mBlobStreamId = -1;
82 mBlobSurfaceId = -1;
83 mP010Consumer.clear();
84 mP010Surface.clear();
85 mP010Consumer = nullptr;
86 mP010Surface = nullptr;
87}
88
89void JpegRCompositeStream::compilePendingInputLocked() {
90 CpuConsumer::LockedBuffer imgBuffer;
91
92 while (mSupportInternalJpeg && !mInputJpegBuffers.empty() && !mBlobBufferAcquired) {
93 auto it = mInputJpegBuffers.begin();
94 auto res = mBlobConsumer->lockNextBuffer(&imgBuffer);
95 if (res == NOT_ENOUGH_DATA) {
96 // Can not lock any more buffers.
97 break;
98 } else if (res != OK) {
99 ALOGE("%s: Error locking blob image buffer: %s (%d)", __FUNCTION__,
100 strerror(-res), res);
101 mPendingInputFrames[*it].error = true;
102 mInputJpegBuffers.erase(it);
103 continue;
104 }
105
106 if (*it != imgBuffer.timestamp) {
107 ALOGW("%s: Expecting jpeg buffer with time stamp: %" PRId64 " received buffer with "
108 "time stamp: %" PRId64, __FUNCTION__, *it, imgBuffer.timestamp);
109 }
110
111 if ((mPendingInputFrames.find(imgBuffer.timestamp) != mPendingInputFrames.end()) &&
112 (mPendingInputFrames[imgBuffer.timestamp].error)) {
113 mBlobConsumer->unlockBuffer(imgBuffer);
114 } else {
115 mPendingInputFrames[imgBuffer.timestamp].jpegBuffer = imgBuffer;
116 mBlobBufferAcquired = true;
117 }
118 mInputJpegBuffers.erase(it);
119 }
120
121 while (!mInputP010Buffers.empty() && !mP010BufferAcquired) {
122 auto it = mInputP010Buffers.begin();
123 auto res = mP010Consumer->lockNextBuffer(&imgBuffer);
124 if (res == NOT_ENOUGH_DATA) {
125 // Can not lock any more buffers.
126 break;
127 } else if (res != OK) {
128 ALOGE("%s: Error receiving P010 image buffer: %s (%d)", __FUNCTION__,
129 strerror(-res), res);
130 mPendingInputFrames[*it].error = true;
131 mInputP010Buffers.erase(it);
132 continue;
133 }
134
135 if (*it != imgBuffer.timestamp) {
136 ALOGW("%s: Expecting P010 buffer with time stamp: %" PRId64 " received buffer with "
137 "time stamp: %" PRId64, __FUNCTION__, *it, imgBuffer.timestamp);
138 }
139
140 if ((mPendingInputFrames.find(imgBuffer.timestamp) != mPendingInputFrames.end()) &&
141 (mPendingInputFrames[imgBuffer.timestamp].error)) {
142 mP010Consumer->unlockBuffer(imgBuffer);
143 } else {
144 mPendingInputFrames[imgBuffer.timestamp].p010Buffer = imgBuffer;
145 mP010BufferAcquired = true;
146 }
147 mInputP010Buffers.erase(it);
148 }
149
150 while (!mCaptureResults.empty()) {
151 auto it = mCaptureResults.begin();
152 // Negative timestamp indicates that something went wrong during the capture result
153 // collection process.
154 if (it->first >= 0) {
155 mPendingInputFrames[it->first].frameNumber = std::get<0>(it->second);
156 mPendingInputFrames[it->first].result = std::get<1>(it->second);
157 }
158 mCaptureResults.erase(it);
159 }
160
161 while (!mFrameNumberMap.empty()) {
162 auto it = mFrameNumberMap.begin();
163 mPendingInputFrames[it->second].frameNumber = it->first;
164 mFrameNumberMap.erase(it);
165 }
166
167 auto it = mErrorFrameNumbers.begin();
168 while (it != mErrorFrameNumbers.end()) {
169 bool frameFound = false;
170 for (auto &inputFrame : mPendingInputFrames) {
171 if (inputFrame.second.frameNumber == *it) {
172 inputFrame.second.error = true;
173 frameFound = true;
174 break;
175 }
176 }
177
178 if (frameFound) {
179 it = mErrorFrameNumbers.erase(it);
180 } else {
181 ALOGW("%s: Not able to find failing input with frame number: %" PRId64, __FUNCTION__,
182 *it);
183 it++;
184 }
185 }
186}
187
188bool JpegRCompositeStream::getNextReadyInputLocked(int64_t *currentTs /*inout*/) {
189 if (currentTs == nullptr) {
190 return false;
191 }
192
193 bool newInputAvailable = false;
194 for (const auto& it : mPendingInputFrames) {
195 if ((!it.second.error) && (it.second.p010Buffer.data != nullptr) &&
196 ((it.second.jpegBuffer.data != nullptr) || !mSupportInternalJpeg) &&
197 (it.first < *currentTs)) {
198 *currentTs = it.first;
199 newInputAvailable = true;
200 }
201 }
202
203 return newInputAvailable;
204}
205
206int64_t JpegRCompositeStream::getNextFailingInputLocked(int64_t *currentTs /*inout*/) {
207 int64_t ret = -1;
208 if (currentTs == nullptr) {
209 return ret;
210 }
211
212 for (const auto& it : mPendingInputFrames) {
213 if (it.second.error && !it.second.errorNotified && (it.first < *currentTs)) {
214 *currentTs = it.first;
215 ret = it.second.frameNumber;
216 }
217 }
218
219 return ret;
220}
221
222status_t JpegRCompositeStream::processInputFrame(nsecs_t ts, const InputFrame &inputFrame) {
223 status_t res;
224 sp<ANativeWindow> outputANW = mOutputSurface;
225 ANativeWindowBuffer *anb;
226 int fenceFd;
227 void *dstBuffer;
228
Dichen Zhang8a533b72022-11-15 23:03:02 +0000229 size_t maxJpegRBufferSize = 0;
Emilian Peev434248e2022-10-06 14:58:54 -0700230 if (mMaxJpegBufferSize > 0) {
231 // If this is an ultra high resolution sensor and the input frames size
232 // is > default res jpeg.
233 if (mUHRMaxJpegSize.width != 0 &&
234 inputFrame.jpegBuffer.width * inputFrame.jpegBuffer.height >
235 mDefaultMaxJpegSize.width * mDefaultMaxJpegSize.height) {
Dichen Zhang8a533b72022-11-15 23:03:02 +0000236 maxJpegRBufferSize = mUHRMaxJpegBufferSize;
Emilian Peev434248e2022-10-06 14:58:54 -0700237 } else {
Dichen Zhang8a533b72022-11-15 23:03:02 +0000238 maxJpegRBufferSize = mMaxJpegBufferSize;
Emilian Peev434248e2022-10-06 14:58:54 -0700239 }
240 } else {
Dichen Zhang8a533b72022-11-15 23:03:02 +0000241 maxJpegRBufferSize = inputFrame.p010Buffer.width * inputFrame.p010Buffer.height;
Emilian Peev434248e2022-10-06 14:58:54 -0700242 }
243
244 uint8_t jpegQuality = 100;
245 auto entry = inputFrame.result.find(ANDROID_JPEG_QUALITY);
246 if (entry.count > 0) {
247 jpegQuality = entry.data.u8[0];
248 }
249
Dichen Zhang8a533b72022-11-15 23:03:02 +0000250 if ((res = native_window_set_buffers_dimensions(mOutputSurface.get(), maxJpegRBufferSize, 1))
Emilian Peev434248e2022-10-06 14:58:54 -0700251 != OK) {
252 ALOGE("%s: Unable to configure stream buffer dimensions"
Dichen Zhang8a533b72022-11-15 23:03:02 +0000253 " %zux%u for stream %d", __FUNCTION__, maxJpegRBufferSize, 1U, mP010StreamId);
Emilian Peev434248e2022-10-06 14:58:54 -0700254 return res;
255 }
256
257 res = outputANW->dequeueBuffer(mOutputSurface.get(), &anb, &fenceFd);
258 if (res != OK) {
259 ALOGE("%s: Error retrieving output buffer: %s (%d)", __FUNCTION__, strerror(-res),
260 res);
261 return res;
262 }
263
264 sp<GraphicBuffer> gb = GraphicBuffer::from(anb);
265 GraphicBufferLocker gbLocker(gb);
266 res = gbLocker.lockAsync(&dstBuffer, fenceFd);
267 if (res != OK) {
268 ALOGE("%s: Error trying to lock output buffer fence: %s (%d)", __FUNCTION__,
269 strerror(-res), res);
270 outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
271 return res;
272 }
273
Dichen Zhang8a533b72022-11-15 23:03:02 +0000274 if ((gb->getWidth() < maxJpegRBufferSize) || (gb->getHeight() != 1)) {
Emilian Peev434248e2022-10-06 14:58:54 -0700275 ALOGE("%s: Blob buffer size mismatch, expected %zux%u received %dx%d", __FUNCTION__,
Dichen Zhang8a533b72022-11-15 23:03:02 +0000276 maxJpegRBufferSize, 1, gb->getWidth(), gb->getHeight());
Emilian Peev434248e2022-10-06 14:58:54 -0700277 outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
278 return BAD_VALUE;
279 }
280
Dichen Zhang8a533b72022-11-15 23:03:02 +0000281 size_t actualJpegRSize = 0;
Dichen Zhang06edce02023-02-10 23:07:15 +0000282 jpegrecoverymap::jpegr_uncompressed_struct p010;
283 jpegrecoverymap::jpegr_compressed_struct jpegR;
284 jpegrecoverymap::JpegR jpegREncoder;
Dichen Zhang8a533b72022-11-15 23:03:02 +0000285
Dichen Zhangd3176472023-01-05 19:39:23 +0000286 p010.height = inputFrame.p010Buffer.height;
287 p010.width = inputFrame.p010Buffer.width;
Dichen Zhang06edce02023-02-10 23:07:15 +0000288 p010.colorGamut = jpegrecoverymap::jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
Dichen Zhangd3176472023-01-05 19:39:23 +0000289 size_t yChannelSizeInByte = p010.width * p010.height * 2;
290 size_t uvChannelSizeInByte = p010.width * p010.height;
291 p010.data = new uint8_t[yChannelSizeInByte + uvChannelSizeInByte];
292 std::unique_ptr<uint8_t[]> p010_data;
293 p010_data.reset(reinterpret_cast<uint8_t*>(p010.data));
294 memcpy((uint8_t*)p010.data, inputFrame.p010Buffer.data, yChannelSizeInByte);
295 memcpy((uint8_t*)p010.data + yChannelSizeInByte, inputFrame.p010Buffer.dataCb,
296 uvChannelSizeInByte);
297
298 jpegR.data = dstBuffer;
299 jpegR.maxLength = maxJpegRBufferSize;
300
Dichen Zhang06edce02023-02-10 23:07:15 +0000301 jpegrecoverymap::jpegr_transfer_function transferFunction;
Dichen Zhangd3176472023-01-05 19:39:23 +0000302 switch (mP010DynamicRange) {
303 case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
304 case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
Dichen Zhang06edce02023-02-10 23:07:15 +0000305 transferFunction = jpegrecoverymap::jpegr_transfer_function::JPEGR_TF_PQ;
Dichen Zhangd3176472023-01-05 19:39:23 +0000306 break;
307 default:
Dichen Zhang06edce02023-02-10 23:07:15 +0000308 transferFunction = jpegrecoverymap::jpegr_transfer_function::JPEGR_TF_HLG;
Dichen Zhangd3176472023-01-05 19:39:23 +0000309 }
310
311 if (mSupportInternalJpeg) {
Dichen Zhang06edce02023-02-10 23:07:15 +0000312 jpegrecoverymap::jpegr_compressed_struct jpeg;
Dichen Zhang8a533b72022-11-15 23:03:02 +0000313
314 jpeg.data = inputFrame.jpegBuffer.data;
315 jpeg.length = android::camera2::JpegProcessor::findJpegSize(inputFrame.jpegBuffer.data,
Emilian Peev434248e2022-10-06 14:58:54 -0700316 inputFrame.jpegBuffer.width);
Dichen Zhang8a533b72022-11-15 23:03:02 +0000317 if (jpeg.length == 0) {
Emilian Peev434248e2022-10-06 14:58:54 -0700318 ALOGW("%s: Failed to find input jpeg size, default to using entire buffer!",
319 __FUNCTION__);
Dichen Zhang8a533b72022-11-15 23:03:02 +0000320 jpeg.length = inputFrame.jpegBuffer.width;
Emilian Peev434248e2022-10-06 14:58:54 -0700321 }
Dichen Zhang8a533b72022-11-15 23:03:02 +0000322
323 if (mOutputColorSpace == ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3) {
Dichen Zhang06edce02023-02-10 23:07:15 +0000324 jpeg.colorGamut = jpegrecoverymap::jpegr_color_gamut::JPEGR_COLORGAMUT_P3;
Dichen Zhang8a533b72022-11-15 23:03:02 +0000325 } else {
Dichen Zhang06edce02023-02-10 23:07:15 +0000326 jpeg.colorGamut = jpegrecoverymap::jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
Emilian Peev434248e2022-10-06 14:58:54 -0700327 }
Dichen Zhang8a533b72022-11-15 23:03:02 +0000328
Dichen Zhang809ed082023-02-10 22:42:30 +0000329 res = jpegREncoder.encodeJPEGR(&p010, &jpeg, transferFunction, &jpegR);
Emilian Peev434248e2022-10-06 14:58:54 -0700330 } else {
331 const uint8_t* exifBuffer = nullptr;
332 size_t exifBufferSize = 0;
333 std::unique_ptr<ExifUtils> utils(ExifUtils::create());
334 utils->initializeEmpty();
335 utils->setFromMetadata(inputFrame.result, mStaticInfo, inputFrame.p010Buffer.width,
336 inputFrame.p010Buffer.height);
337 if (utils->generateApp1()) {
338 exifBuffer = utils->getApp1Buffer();
339 exifBufferSize = utils->getApp1Length();
340 } else {
341 ALOGE("%s: Unable to generate App1 buffer", __FUNCTION__);
342 }
Dichen Zhangd3176472023-01-05 19:39:23 +0000343
Dichen Zhang06edce02023-02-10 23:07:15 +0000344 jpegrecoverymap::jpegr_exif_struct exif;
Dichen Zhangd3176472023-01-05 19:39:23 +0000345 exif.data = reinterpret_cast<void*>(const_cast<uint8_t*>(exifBuffer));
346 exif.length = exifBufferSize;
347
Dichen Zhang809ed082023-02-10 22:42:30 +0000348 res = jpegREncoder.encodeJPEGR(&p010, transferFunction, &jpegR, jpegQuality, &exif);
Emilian Peev434248e2022-10-06 14:58:54 -0700349 }
350
Dichen Zhangd3176472023-01-05 19:39:23 +0000351 if (res != OK) {
352 ALOGE("%s: Error trying to encode JPEG/R: %s (%d)", __FUNCTION__, strerror(-res), res);
353 return res;
354 }
355
356 actualJpegRSize = jpegR.length;
357 p010_data.release();
358
Dichen Zhang8a533b72022-11-15 23:03:02 +0000359 size_t finalJpegRSize = actualJpegRSize + sizeof(CameraBlob);
360 if (finalJpegRSize > maxJpegRBufferSize) {
Emilian Peev434248e2022-10-06 14:58:54 -0700361 ALOGE("%s: Final jpeg buffer not large enough for the jpeg blob header", __FUNCTION__);
362 outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
363 return NO_MEMORY;
364 }
365
366 res = native_window_set_buffers_timestamp(mOutputSurface.get(), ts);
367 if (res != OK) {
368 ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)", __FUNCTION__,
369 getStreamId(), strerror(-res), res);
370 return res;
371 }
372
Dichen Zhang8a533b72022-11-15 23:03:02 +0000373 ALOGV("%s: Final jpeg size: %zu", __func__, finalJpegRSize);
Emilian Peev434248e2022-10-06 14:58:54 -0700374 uint8_t* header = static_cast<uint8_t *> (dstBuffer) +
375 (gb->getWidth() - sizeof(CameraBlob));
376 CameraBlob blobHeader = {
377 .blobId = CameraBlobId::JPEG,
Dichen Zhang8a533b72022-11-15 23:03:02 +0000378 .blobSizeBytes = static_cast<int32_t>(actualJpegRSize)
Emilian Peev434248e2022-10-06 14:58:54 -0700379 };
380 memcpy(header, &blobHeader, sizeof(CameraBlob));
381 outputANW->queueBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
382
383 return res;
384}
385
386void JpegRCompositeStream::releaseInputFrameLocked(InputFrame *inputFrame /*out*/) {
387 if (inputFrame == nullptr) {
388 return;
389 }
390
391 if (inputFrame->p010Buffer.data != nullptr) {
392 mP010Consumer->unlockBuffer(inputFrame->p010Buffer);
393 inputFrame->p010Buffer.data = nullptr;
394 mP010BufferAcquired = false;
395 }
396
397 if (inputFrame->jpegBuffer.data != nullptr) {
398 mBlobConsumer->unlockBuffer(inputFrame->jpegBuffer);
399 inputFrame->jpegBuffer.data = nullptr;
400 mBlobBufferAcquired = false;
401 }
402
403 if ((inputFrame->error || mErrorState) && !inputFrame->errorNotified) {
404 //TODO: Figure out correct requestId
405 notifyError(inputFrame->frameNumber, -1 /*requestId*/);
406 inputFrame->errorNotified = true;
407 }
408}
409
410void JpegRCompositeStream::releaseInputFramesLocked(int64_t currentTs) {
411 auto it = mPendingInputFrames.begin();
412 while (it != mPendingInputFrames.end()) {
413 if (it->first <= currentTs) {
414 releaseInputFrameLocked(&it->second);
415 it = mPendingInputFrames.erase(it);
416 } else {
417 it++;
418 }
419 }
420}
421
422bool JpegRCompositeStream::threadLoop() {
423 int64_t currentTs = INT64_MAX;
424 bool newInputAvailable = false;
425
426 {
427 Mutex::Autolock l(mMutex);
428
429 if (mErrorState) {
430 // In case we landed in error state, return any pending buffers and
431 // halt all further processing.
432 compilePendingInputLocked();
433 releaseInputFramesLocked(currentTs);
434 return false;
435 }
436
437 while (!newInputAvailable) {
438 compilePendingInputLocked();
439 newInputAvailable = getNextReadyInputLocked(&currentTs);
440 if (!newInputAvailable) {
441 auto failingFrameNumber = getNextFailingInputLocked(&currentTs);
442 if (failingFrameNumber >= 0) {
443 // We cannot erase 'mPendingInputFrames[currentTs]' at this point because it is
444 // possible for two internal stream buffers to fail. In such scenario the
445 // composite stream should notify the client about a stream buffer error only
446 // once and this information is kept within 'errorNotified'.
447 // Any present failed input frames will be removed on a subsequent call to
448 // 'releaseInputFramesLocked()'.
449 releaseInputFrameLocked(&mPendingInputFrames[currentTs]);
450 currentTs = INT64_MAX;
451 }
452
453 auto ret = mInputReadyCondition.waitRelative(mMutex, kWaitDuration);
454 if (ret == TIMED_OUT) {
455 return true;
456 } else if (ret != OK) {
457 ALOGE("%s: Timed wait on condition failed: %s (%d)", __FUNCTION__,
458 strerror(-ret), ret);
459 return false;
460 }
461 }
462 }
463 }
464
465 auto res = processInputFrame(currentTs, mPendingInputFrames[currentTs]);
466 Mutex::Autolock l(mMutex);
467 if (res != OK) {
468 ALOGE("%s: Failed processing frame with timestamp: %" PRIu64 ": %s (%d)", __FUNCTION__,
469 currentTs, strerror(-res), res);
470 mPendingInputFrames[currentTs].error = true;
471 }
472
473 releaseInputFramesLocked(currentTs);
474
475 return true;
476}
477
478bool JpegRCompositeStream::isJpegRCompositeStream(const sp<Surface> &surface) {
479 if (CameraProviderManager::kFrameworkJpegRDisabled) {
480 return false;
481 }
482 ANativeWindow *anw = surface.get();
483 status_t err;
484 int format;
485 if ((err = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) {
486 ALOGE("%s: Failed to query Surface format: %s (%d)", __FUNCTION__, strerror(-err),
487 err);
488 return false;
489 }
490
491 int dataspace;
492 if ((err = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE, &dataspace)) != OK) {
493 ALOGE("%s: Failed to query Surface dataspace: %s (%d)", __FUNCTION__, strerror(-err),
494 err);
495 return false;
496 }
497
498 if ((format == HAL_PIXEL_FORMAT_BLOB) && (dataspace == static_cast<int>(kJpegRDataSpace))) {
499 return true;
500 }
501
502 return false;
503}
504
505void JpegRCompositeStream::deriveDynamicRangeAndDataspace(int64_t dynamicProfile,
506 int64_t* /*out*/dynamicRange, int64_t* /*out*/dataSpace) {
507 if ((dynamicRange == nullptr) || (dataSpace == nullptr)) {
508 return;
509 }
510
511 switch (dynamicProfile) {
512 case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
513 case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
514 *dynamicRange = dynamicProfile;
515 *dataSpace = HAL_DATASPACE_BT2020_ITU_PQ;
516 break;
517 case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF:
518 case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO:
519 case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM:
520 case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO:
521 *dynamicRange = dynamicProfile;
522 *dataSpace = HAL_DATASPACE_BT2020_ITU_HLG;
523 break;
524 default:
525 *dynamicRange = kP010DefaultDynamicRange;
526 *dataSpace = kP010DefaultDataSpace;
527 }
528
529}
530
531status_t JpegRCompositeStream::createInternalStreams(const std::vector<sp<Surface>>& consumers,
532 bool /*hasDeferredConsumer*/, uint32_t width, uint32_t height, int format,
533 camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
534 const std::unordered_set<int32_t> &sensorPixelModesUsed,
535 std::vector<int> *surfaceIds,
536 int /*streamSetId*/, bool /*isShared*/, int32_t colorSpace,
Shuzhen Wangbce53db2022-12-03 00:38:20 +0000537 int64_t dynamicProfile, int64_t streamUseCase, bool useReadoutTimestamp) {
Emilian Peev434248e2022-10-06 14:58:54 -0700538 sp<CameraDeviceBase> device = mDevice.promote();
539 if (!device.get()) {
540 ALOGE("%s: Invalid camera device!", __FUNCTION__);
541 return NO_INIT;
542 }
543
544 deriveDynamicRangeAndDataspace(dynamicProfile, &mP010DynamicRange, &mP010DataSpace);
545 mSupportInternalJpeg = CameraProviderManager::isConcurrentDynamicRangeCaptureSupported(
546 mStaticInfo, mP010DynamicRange,
547 ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
548
549 sp<IGraphicBufferProducer> producer;
550 sp<IGraphicBufferConsumer> consumer;
551 BufferQueue::createBufferQueue(&producer, &consumer);
552 mP010Consumer = new CpuConsumer(consumer, /*maxLockedBuffers*/1, /*controlledByApp*/ true);
553 mP010Consumer->setFrameAvailableListener(this);
554 mP010Consumer->setName(String8("Camera3-P010CompositeStream"));
555 mP010Surface = new Surface(producer);
556
557 auto ret = device->createStream(mP010Surface, width, height, kP010PixelFormat,
558 static_cast<android_dataspace>(mP010DataSpace), rotation,
559 id, physicalCameraId, sensorPixelModesUsed, surfaceIds,
560 camera3::CAMERA3_STREAM_SET_ID_INVALID, false /*isShared*/, false /*isMultiResolution*/,
Shuzhen Wangbce53db2022-12-03 00:38:20 +0000561 GRALLOC_USAGE_SW_READ_OFTEN, mP010DynamicRange, streamUseCase,
562 OutputConfiguration::TIMESTAMP_BASE_DEFAULT, OutputConfiguration::MIRROR_MODE_AUTO,
563 ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED, useReadoutTimestamp);
Emilian Peev434248e2022-10-06 14:58:54 -0700564 if (ret == OK) {
565 mP010StreamId = *id;
566 mP010SurfaceId = (*surfaceIds)[0];
567 mOutputSurface = consumers[0];
568 } else {
569 return ret;
570 }
571
572 if (mSupportInternalJpeg) {
573 BufferQueue::createBufferQueue(&producer, &consumer);
574 mBlobConsumer = new CpuConsumer(consumer, /*maxLockedBuffers*/ 1, /*controlledByApp*/ true);
575 mBlobConsumer->setFrameAvailableListener(this);
576 mBlobConsumer->setName(String8("Camera3-JpegRCompositeStream"));
577 mBlobSurface = new Surface(producer);
578 std::vector<int> blobSurfaceId;
579 ret = device->createStream(mBlobSurface, width, height, format,
580 kJpegDataSpace, rotation, &mBlobStreamId, physicalCameraId, sensorPixelModesUsed,
581 &blobSurfaceId,
582 /*streamSetI*/ camera3::CAMERA3_STREAM_SET_ID_INVALID,
583 /*isShared*/ false,
584 /*isMultiResolution*/ false,
585 /*consumerUsage*/ GRALLOC_USAGE_SW_READ_OFTEN,
586 /*dynamicProfile*/ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
587 streamUseCase,
588 /*timestampBase*/ OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
589 /*mirrorMode*/ OutputConfiguration::MIRROR_MODE_AUTO,
Shuzhen Wangbce53db2022-12-03 00:38:20 +0000590 /*colorSpace*/ colorSpace, useReadoutTimestamp);
Emilian Peev434248e2022-10-06 14:58:54 -0700591 if (ret == OK) {
592 mBlobSurfaceId = blobSurfaceId[0];
593 } else {
594 return ret;
595 }
596
597 ret = registerCompositeStreamListener(mBlobStreamId);
598 if (ret != OK) {
599 ALOGE("%s: Failed to register jpeg stream listener!", __FUNCTION__);
600 return ret;
601 }
602 }
603
604 ret = registerCompositeStreamListener(getStreamId());
605 if (ret != OK) {
606 ALOGE("%s: Failed to register P010 stream listener!", __FUNCTION__);
607 return ret;
608 }
609
610 mOutputColorSpace = colorSpace;
611 mBlobWidth = width;
612 mBlobHeight = height;
613
614 return ret;
615}
616
617status_t JpegRCompositeStream::configureStream() {
618 if (isRunning()) {
619 // Processing thread is already running, nothing more to do.
620 return NO_ERROR;
621 }
622
623 if (mOutputSurface.get() == nullptr) {
624 ALOGE("%s: No valid output surface set!", __FUNCTION__);
625 return NO_INIT;
626 }
627
628 auto res = mOutputSurface->connect(NATIVE_WINDOW_API_CAMERA, mProducerListener);
629 if (res != OK) {
630 ALOGE("%s: Unable to connect to native window for stream %d",
631 __FUNCTION__, mP010StreamId);
632 return res;
633 }
634
635 if ((res = native_window_set_buffers_format(mOutputSurface.get(), HAL_PIXEL_FORMAT_BLOB))
636 != OK) {
637 ALOGE("%s: Unable to configure stream buffer format for stream %d", __FUNCTION__,
638 mP010StreamId);
639 return res;
640 }
641
642 int maxProducerBuffers;
643 ANativeWindow *anw = mP010Surface.get();
644 if ((res = anw->query(anw, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxProducerBuffers)) != OK) {
645 ALOGE("%s: Unable to query consumer undequeued"
646 " buffer count for stream %d", __FUNCTION__, mP010StreamId);
647 return res;
648 }
649
650 ANativeWindow *anwConsumer = mOutputSurface.get();
651 int maxConsumerBuffers;
652 if ((res = anwConsumer->query(anwConsumer, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
653 &maxConsumerBuffers)) != OK) {
654 ALOGE("%s: Unable to query consumer undequeued"
655 " buffer count for stream %d", __FUNCTION__, mP010StreamId);
656 return res;
657 }
658
659 if ((res = native_window_set_buffer_count(
660 anwConsumer, maxProducerBuffers + maxConsumerBuffers)) != OK) {
661 ALOGE("%s: Unable to set buffer count for stream %d", __FUNCTION__, mP010StreamId);
662 return res;
663 }
664
665 run("JpegRCompositeStreamProc");
666
667 return NO_ERROR;
668}
669
670status_t JpegRCompositeStream::deleteInternalStreams() {
671 // The 'CameraDeviceClient' parent will delete the P010 stream
672 requestExit();
673
674 auto ret = join();
675 if (ret != OK) {
676 ALOGE("%s: Failed to join with the main processing thread: %s (%d)", __FUNCTION__,
677 strerror(-ret), ret);
678 }
679
680 if (mBlobStreamId >= 0) {
681 // Camera devices may not be valid after switching to offline mode.
682 // In this case, all offline streams including internal composite streams
683 // are managed and released by the offline session.
684 sp<CameraDeviceBase> device = mDevice.promote();
685 if (device.get() != nullptr) {
686 ret = device->deleteStream(mBlobStreamId);
687 }
688
689 mBlobStreamId = -1;
690 }
691
692 if (mOutputSurface != nullptr) {
693 mOutputSurface->disconnect(NATIVE_WINDOW_API_CAMERA);
694 mOutputSurface.clear();
695 }
696
697 return ret;
698}
699
700void JpegRCompositeStream::onFrameAvailable(const BufferItem& item) {
701 if (item.mDataSpace == kJpegDataSpace) {
702 ALOGV("%s: Jpeg buffer with ts: %" PRIu64 " ms. arrived!",
703 __func__, ns2ms(item.mTimestamp));
704
705 Mutex::Autolock l(mMutex);
706 if (!mErrorState) {
707 mInputJpegBuffers.push_back(item.mTimestamp);
708 mInputReadyCondition.signal();
709 }
710 } else if (item.mDataSpace == static_cast<android_dataspace_t>(mP010DataSpace)) {
711 ALOGV("%s: P010 buffer with ts: %" PRIu64 " ms. arrived!", __func__,
712 ns2ms(item.mTimestamp));
713
714 Mutex::Autolock l(mMutex);
715 if (!mErrorState) {
716 mInputP010Buffers.push_back(item.mTimestamp);
717 mInputReadyCondition.signal();
718 }
719 } else {
720 ALOGE("%s: Unexpected data space: 0x%x", __FUNCTION__, item.mDataSpace);
721 }
722}
723
724status_t JpegRCompositeStream::insertGbp(SurfaceMap* /*out*/outSurfaceMap,
725 Vector<int32_t> * /*out*/outputStreamIds, int32_t* /*out*/currentStreamId) {
726 if (outputStreamIds == nullptr) {
727 return BAD_VALUE;
728 }
729
730 if (outSurfaceMap->find(mP010StreamId) == outSurfaceMap->end()) {
731 outputStreamIds->push_back(mP010StreamId);
732 }
733 (*outSurfaceMap)[mP010StreamId].push_back(mP010SurfaceId);
734
735 if (mSupportInternalJpeg) {
736 if (outSurfaceMap->find(mBlobStreamId) == outSurfaceMap->end()) {
737 outputStreamIds->push_back(mBlobStreamId);
738 }
739 (*outSurfaceMap)[mBlobStreamId].push_back(mBlobSurfaceId);
740 }
741
742 if (currentStreamId != nullptr) {
743 *currentStreamId = mP010StreamId;
744 }
745
746 return NO_ERROR;
747}
748
749status_t JpegRCompositeStream::insertCompositeStreamIds(
750 std::vector<int32_t>* compositeStreamIds /*out*/) {
751 if (compositeStreamIds == nullptr) {
752 return BAD_VALUE;
753 }
754
755 compositeStreamIds->push_back(mP010StreamId);
756 if (mSupportInternalJpeg) {
757 compositeStreamIds->push_back(mBlobStreamId);
758 }
759
760 return OK;
761}
762
763void JpegRCompositeStream::onResultError(const CaptureResultExtras& resultExtras) {
764 // Processing can continue even in case of result errors.
765 // At the moment Jpeg/R composite stream processing relies mainly on static camera
766 // characteristics data. The actual result data can be used for the jpeg quality but
767 // in case it is absent we can default to maximum.
768 eraseResult(resultExtras.frameNumber);
769}
770
771bool JpegRCompositeStream::onStreamBufferError(const CaptureResultExtras& resultExtras) {
772 bool ret = false;
773 // Buffer errors concerning internal composite streams should not be directly visible to
774 // camera clients. They must only receive a single buffer error with the public composite
775 // stream id.
776 if ((resultExtras.errorStreamId == mP010StreamId) ||
777 (resultExtras.errorStreamId == mBlobStreamId)) {
778 flagAnErrorFrameNumber(resultExtras.frameNumber);
779 ret = true;
780 }
781
782 return ret;
783}
784
785status_t JpegRCompositeStream::getCompositeStreamInfo(const OutputStreamInfo &streamInfo,
786 const CameraMetadata& staticInfo,
787 std::vector<OutputStreamInfo>* compositeOutput /*out*/) {
788 if (compositeOutput == nullptr) {
789 return BAD_VALUE;
790 }
791
792 int64_t dynamicRange, dataSpace;
793 deriveDynamicRangeAndDataspace(streamInfo.dynamicRangeProfile, &dynamicRange, &dataSpace);
794
795 compositeOutput->clear();
796 compositeOutput->push_back({});
797 (*compositeOutput)[0].width = streamInfo.width;
798 (*compositeOutput)[0].height = streamInfo.height;
799 (*compositeOutput)[0].format = kP010PixelFormat;
800 (*compositeOutput)[0].dataSpace = static_cast<android_dataspace_t>(dataSpace);
801 (*compositeOutput)[0].consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
802 (*compositeOutput)[0].dynamicRangeProfile = dynamicRange;
803 (*compositeOutput)[0].colorSpace =
804 ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED;
805
806 if (CameraProviderManager::isConcurrentDynamicRangeCaptureSupported(staticInfo,
807 streamInfo.dynamicRangeProfile,
808 ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD)) {
809 compositeOutput->push_back({});
810 (*compositeOutput)[1].width = streamInfo.width;
811 (*compositeOutput)[1].height = streamInfo.height;
812 (*compositeOutput)[1].format = HAL_PIXEL_FORMAT_BLOB;
813 (*compositeOutput)[1].dataSpace = kJpegDataSpace;
814 (*compositeOutput)[1].consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
815 (*compositeOutput)[1].dynamicRangeProfile =
816 ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
817 (*compositeOutput)[1].colorSpace = streamInfo.colorSpace;
818 }
819
820 return NO_ERROR;
821}
822
823}; // namespace camera3
824}; // namespace android