blob: 8144792721c7986d78a0026fca362a2807c5b9b9 [file] [log] [blame]
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001/*
2 * Copyright (C) 2019 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#define LOG_TAG "Camera3-HeicCompositeStream"
18#define ATRACE_TAG ATRACE_TAG_CAMERA
Susmitha Gummallae911f2e2020-11-23 09:57:03 -080019#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -080020//#define LOG_NDEBUG 0
21
22#include <linux/memfd.h>
23#include <pthread.h>
24#include <sys/syscall.h>
25
Jayant Chowdharyc67af1b2022-04-07 18:05:04 +000026#include <aidl/android/hardware/camera/device/CameraBlob.h>
27#include <aidl/android/hardware/camera/device/CameraBlobId.h>
Shuzhen Wang219c2992019-02-15 17:24:28 -080028#include <libyuv.h>
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -080029#include <gui/Surface.h>
30#include <utils/Log.h>
31#include <utils/Trace.h>
Austin Borger1c1bee02023-06-01 16:51:35 -070032#include <camera/StringUtils.h>
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -080033
Marco Nelissen13aa1a42019-09-27 10:21:55 -070034#include <mediadrm/ICrypto.h>
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -080035#include <media/MediaCodecBuffer.h>
36#include <media/stagefright/foundation/ABuffer.h>
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -080037#include <media/stagefright/foundation/MediaDefs.h>
38#include <media/stagefright/MediaCodecConstants.h>
39
40#include "common/CameraDeviceBase.h"
41#include "utils/ExifUtils.h"
Jayant Chowdhary13f9b2f2020-12-02 22:46:15 -080042#include "utils/SessionConfigurationUtils.h"
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -080043#include "HeicEncoderInfoManager.h"
44#include "HeicCompositeStream.h"
45
Jayant Chowdharyc67af1b2022-04-07 18:05:04 +000046using aidl::android::hardware::camera::device::CameraBlob;
47using aidl::android::hardware::camera::device::CameraBlobId;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -080048
49namespace android {
50namespace camera3 {
51
Shuzhen Wange8675782019-12-05 09:12:14 -080052HeicCompositeStream::HeicCompositeStream(sp<CameraDeviceBase> device,
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -080053 wp<hardware::camera2::ICameraDeviceCallbacks> cb) :
54 CompositeStream(device, cb),
55 mUseHeic(false),
56 mNumOutputTiles(1),
57 mOutputWidth(0),
58 mOutputHeight(0),
59 mMaxHeicBufferSize(0),
60 mGridWidth(HeicEncoderInfoManager::kGridWidth),
61 mGridHeight(HeicEncoderInfoManager::kGridHeight),
62 mGridRows(1),
63 mGridCols(1),
64 mUseGrid(false),
65 mAppSegmentStreamId(-1),
66 mAppSegmentSurfaceId(-1),
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -080067 mMainImageStreamId(-1),
68 mMainImageSurfaceId(-1),
69 mYuvBufferAcquired(false),
70 mProducerListener(new ProducerListener()),
Shuzhen Wang3d00ee52019-09-25 14:19:28 -070071 mDequeuedOutputBufferCnt(0),
72 mCodecOutputCounter(0),
Shuzhen Wang62f49ed2019-09-04 14:07:53 -070073 mQuality(-1),
Shuzhen Wange8675782019-12-05 09:12:14 -080074 mGridTimestampUs(0),
75 mStatusId(StatusTracker::NO_STATUS_ID) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -080076}
77
78HeicCompositeStream::~HeicCompositeStream() {
79 // Call deinitCodec in case stream hasn't been deleted yet to avoid any
80 // memory/resource leak.
81 deinitCodec();
82
83 mInputAppSegmentBuffers.clear();
84 mCodecOutputBuffers.clear();
85
86 mAppSegmentStreamId = -1;
87 mAppSegmentSurfaceId = -1;
88 mAppSegmentConsumer.clear();
89 mAppSegmentSurface.clear();
90
91 mMainImageStreamId = -1;
92 mMainImageSurfaceId = -1;
93 mMainImageConsumer.clear();
94 mMainImageSurface.clear();
95}
96
97bool HeicCompositeStream::isHeicCompositeStream(const sp<Surface> &surface) {
98 ANativeWindow *anw = surface.get();
99 status_t err;
100 int format;
101 if ((err = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) {
Austin Borger1c1bee02023-06-01 16:51:35 -0700102 std::string msg = fmt::sprintf("Failed to query Surface format: %s (%d)", strerror(-err),
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800103 err);
Austin Borger1c1bee02023-06-01 16:51:35 -0700104 ALOGE("%s: %s", __FUNCTION__, msg.c_str());
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800105 return false;
106 }
107
108 int dataspace;
109 if ((err = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE, &dataspace)) != OK) {
Austin Borger1c1bee02023-06-01 16:51:35 -0700110 std::string msg = fmt::sprintf("Failed to query Surface dataspace: %s (%d)", strerror(-err),
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800111 err);
Austin Borger1c1bee02023-06-01 16:51:35 -0700112 ALOGE("%s: %s", __FUNCTION__, msg.c_str());
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800113 return false;
114 }
115
116 return ((format == HAL_PIXEL_FORMAT_BLOB) && (dataspace == HAL_DATASPACE_HEIF));
117}
118
119status_t HeicCompositeStream::createInternalStreams(const std::vector<sp<Surface>>& consumers,
120 bool /*hasDeferredConsumer*/, uint32_t width, uint32_t height, int format,
Austin Borger1c1bee02023-06-01 16:51:35 -0700121 camera_stream_rotation_t rotation, int *id, const std::string& physicalCameraId,
Jayant Chowdhary13f9b2f2020-12-02 22:46:15 -0800122 const std::unordered_set<int32_t> &sensorPixelModesUsed,
123 std::vector<int> *surfaceIds,
Syed Haqc8a536d2023-05-09 12:14:52 -0700124 int /*streamSetId*/, bool /*isShared*/, int32_t colorSpace,
Shuzhen Wangbce53db2022-12-03 00:38:20 +0000125 int64_t /*dynamicProfile*/, int64_t /*streamUseCase*/, bool useReadoutTimestamp) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800126 sp<CameraDeviceBase> device = mDevice.promote();
127 if (!device.get()) {
128 ALOGE("%s: Invalid camera device!", __FUNCTION__);
129 return NO_INIT;
130 }
131
132 status_t res = initializeCodec(width, height, device);
133 if (res != OK) {
134 ALOGE("%s: Failed to initialize HEIC/HEVC codec: %s (%d)",
135 __FUNCTION__, strerror(-res), res);
136 return NO_INIT;
137 }
138
139 sp<IGraphicBufferProducer> producer;
140 sp<IGraphicBufferConsumer> consumer;
141 BufferQueue::createBufferQueue(&producer, &consumer);
Michael Gonzalezb5986a32019-10-09 15:38:17 -0700142 mAppSegmentConsumer = new CpuConsumer(consumer, kMaxAcquiredAppSegment);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800143 mAppSegmentConsumer->setFrameAvailableListener(this);
144 mAppSegmentConsumer->setName(String8("Camera3-HeicComposite-AppSegmentStream"));
145 mAppSegmentSurface = new Surface(producer);
146
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800147 mStaticInfo = device->info();
148
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800149 res = device->createStream(mAppSegmentSurface, mAppSegmentMaxSize, 1, format,
Jayant Chowdhary13f9b2f2020-12-02 22:46:15 -0800150 kAppSegmentDataSpace, rotation, &mAppSegmentStreamId, physicalCameraId,
Shuzhen Wangbce53db2022-12-03 00:38:20 +0000151 sensorPixelModesUsed, surfaceIds, camera3::CAMERA3_STREAM_SET_ID_INVALID,
152 /*isShared*/false, /*isMultiResolution*/false,
153 /*consumerUsage*/0, ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
154 ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
155 OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
156 OutputConfiguration::MIRROR_MODE_AUTO,
Syed Haqc8a536d2023-05-09 12:14:52 -0700157 colorSpace,
Shuzhen Wangbce53db2022-12-03 00:38:20 +0000158 useReadoutTimestamp);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800159 if (res == OK) {
160 mAppSegmentSurfaceId = (*surfaceIds)[0];
161 } else {
162 ALOGE("%s: Failed to create JPEG App segment stream: %s (%d)", __FUNCTION__,
163 strerror(-res), res);
164 return res;
165 }
166
167 if (!mUseGrid) {
168 res = mCodec->createInputSurface(&producer);
169 if (res != OK) {
170 ALOGE("%s: Failed to create input surface for Heic codec: %s (%d)",
171 __FUNCTION__, strerror(-res), res);
172 return res;
173 }
174 } else {
175 BufferQueue::createBufferQueue(&producer, &consumer);
176 mMainImageConsumer = new CpuConsumer(consumer, 1);
177 mMainImageConsumer->setFrameAvailableListener(this);
178 mMainImageConsumer->setName(String8("Camera3-HeicComposite-HevcInputYUVStream"));
179 }
180 mMainImageSurface = new Surface(producer);
181
182 res = mCodec->start();
183 if (res != OK) {
184 ALOGE("%s: Failed to start codec: %s (%d)", __FUNCTION__,
185 strerror(-res), res);
186 return res;
187 }
188
189 std::vector<int> sourceSurfaceId;
190 //Use YUV_888 format if framework tiling is needed.
191 int srcStreamFmt = mUseGrid ? HAL_PIXEL_FORMAT_YCbCr_420_888 :
192 HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
193 res = device->createStream(mMainImageSurface, width, height, srcStreamFmt, kHeifDataSpace,
Shuzhen Wangbce53db2022-12-03 00:38:20 +0000194 rotation, id, physicalCameraId, sensorPixelModesUsed, &sourceSurfaceId,
195 camera3::CAMERA3_STREAM_SET_ID_INVALID, /*isShared*/false, /*isMultiResolution*/false,
196 /*consumerUsage*/0, ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
197 ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
198 OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
199 OutputConfiguration::MIRROR_MODE_AUTO,
Syed Haqc8a536d2023-05-09 12:14:52 -0700200 colorSpace,
Shuzhen Wangbce53db2022-12-03 00:38:20 +0000201 useReadoutTimestamp);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800202 if (res == OK) {
203 mMainImageSurfaceId = sourceSurfaceId[0];
204 mMainImageStreamId = *id;
205 } else {
206 ALOGE("%s: Failed to create main image stream: %s (%d)", __FUNCTION__,
207 strerror(-res), res);
208 return res;
209 }
210
211 mOutputSurface = consumers[0];
Shuzhen Wange8675782019-12-05 09:12:14 -0800212 res = registerCompositeStreamListener(mMainImageStreamId);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800213 if (res != OK) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800214 ALOGE("%s: Failed to register HAL main image stream: %s (%d)", __FUNCTION__,
215 strerror(-res), res);
216 return res;
217 }
218
219 res = registerCompositeStreamListener(mAppSegmentStreamId);
220 if (res != OK) {
221 ALOGE("%s: Failed to register HAL app segment stream: %s (%d)", __FUNCTION__,
222 strerror(-res), res);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800223 return res;
224 }
225
Shuzhen Wang219c2992019-02-15 17:24:28 -0800226 initCopyRowFunction(width);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800227 return res;
228}
229
230status_t HeicCompositeStream::deleteInternalStreams() {
231 requestExit();
232 auto res = join();
233 if (res != OK) {
234 ALOGE("%s: Failed to join with the main processing thread: %s (%d)", __FUNCTION__,
235 strerror(-res), res);
236 }
237
238 deinitCodec();
239
240 if (mAppSegmentStreamId >= 0) {
Emilian Peevc0fe54c2020-03-11 14:05:07 -0700241 // Camera devices may not be valid after switching to offline mode.
242 // In this case, all offline streams including internal composite streams
243 // are managed and released by the offline session.
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800244 sp<CameraDeviceBase> device = mDevice.promote();
Emilian Peevc0fe54c2020-03-11 14:05:07 -0700245 if (device.get() != nullptr) {
246 res = device->deleteStream(mAppSegmentStreamId);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800247 }
248
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800249 mAppSegmentStreamId = -1;
250 }
251
Shuzhen Wang2c545042019-02-07 10:27:35 -0800252 if (mOutputSurface != nullptr) {
253 mOutputSurface->disconnect(NATIVE_WINDOW_API_CAMERA);
254 mOutputSurface.clear();
255 }
Shuzhen Wange8675782019-12-05 09:12:14 -0800256
257 sp<StatusTracker> statusTracker = mStatusTracker.promote();
258 if (statusTracker != nullptr && mStatusId != StatusTracker::NO_STATUS_ID) {
259 statusTracker->removeComponent(mStatusId);
260 mStatusId = StatusTracker::NO_STATUS_ID;
261 }
262
263 if (mPendingInputFrames.size() > 0) {
264 ALOGW("%s: mPendingInputFrames has %zu stale entries",
265 __FUNCTION__, mPendingInputFrames.size());
266 mPendingInputFrames.clear();
267 }
268
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800269 return res;
270}
271
272void HeicCompositeStream::onBufferReleased(const BufferInfo& bufferInfo) {
273 Mutex::Autolock l(mMutex);
274
275 if (bufferInfo.mError) return;
276
Shuzhen Wange8675782019-12-05 09:12:14 -0800277 if (bufferInfo.mStreamId == mMainImageStreamId) {
278 mMainImageFrameNumbers.push(bufferInfo.mFrameNumber);
279 mCodecOutputBufferFrameNumbers.push(bufferInfo.mFrameNumber);
280 ALOGV("%s: [%" PRId64 "]: Adding main image frame number (%zu frame numbers in total)",
281 __FUNCTION__, bufferInfo.mFrameNumber, mMainImageFrameNumbers.size());
282 } else if (bufferInfo.mStreamId == mAppSegmentStreamId) {
283 mAppSegmentFrameNumbers.push(bufferInfo.mFrameNumber);
284 ALOGV("%s: [%" PRId64 "]: Adding app segment frame number (%zu frame numbers in total)",
285 __FUNCTION__, bufferInfo.mFrameNumber, mAppSegmentFrameNumbers.size());
286 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800287}
288
289// We need to get the settings early to handle the case where the codec output
290// arrives earlier than result metadata.
291void HeicCompositeStream::onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId,
292 const CameraMetadata& settings) {
293 ATRACE_ASYNC_BEGIN("HEIC capture", frameNumber);
294
295 Mutex::Autolock l(mMutex);
296 if (mErrorState || (streamId != getStreamId())) {
297 return;
298 }
299
300 mPendingCaptureResults.emplace(frameNumber, CameraMetadata());
301
302 camera_metadata_ro_entry entry;
303
304 int32_t orientation = 0;
305 entry = settings.find(ANDROID_JPEG_ORIENTATION);
306 if (entry.count == 1) {
307 orientation = entry.data.i32[0];
308 }
309
310 int32_t quality = kDefaultJpegQuality;
311 entry = settings.find(ANDROID_JPEG_QUALITY);
312 if (entry.count == 1) {
313 quality = entry.data.i32[0];
314 }
315
Shuzhen Wange8675782019-12-05 09:12:14 -0800316 mSettingsByFrameNumber[frameNumber] = {orientation, quality};
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800317}
318
319void HeicCompositeStream::onFrameAvailable(const BufferItem& item) {
320 if (item.mDataSpace == static_cast<android_dataspace>(kAppSegmentDataSpace)) {
321 ALOGV("%s: JPEG APP segments buffer with ts: %" PRIu64 " ms. arrived!",
322 __func__, ns2ms(item.mTimestamp));
323
324 Mutex::Autolock l(mMutex);
325 if (!mErrorState) {
326 mInputAppSegmentBuffers.push_back(item.mTimestamp);
327 mInputReadyCondition.signal();
328 }
329 } else if (item.mDataSpace == kHeifDataSpace) {
330 ALOGV("%s: YUV_888 buffer with ts: %" PRIu64 " ms. arrived!",
331 __func__, ns2ms(item.mTimestamp));
332
333 Mutex::Autolock l(mMutex);
334 if (!mUseGrid) {
335 ALOGE("%s: YUV_888 internal stream is only supported for HEVC tiling",
336 __FUNCTION__);
337 return;
338 }
339 if (!mErrorState) {
340 mInputYuvBuffers.push_back(item.mTimestamp);
341 mInputReadyCondition.signal();
342 }
343 } else {
344 ALOGE("%s: Unexpected data space: 0x%x", __FUNCTION__, item.mDataSpace);
345 }
346}
347
348status_t HeicCompositeStream::getCompositeStreamInfo(const OutputStreamInfo &streamInfo,
349 const CameraMetadata& ch, std::vector<OutputStreamInfo>* compositeOutput /*out*/) {
350 if (compositeOutput == nullptr) {
351 return BAD_VALUE;
352 }
353
354 compositeOutput->clear();
355
356 bool useGrid, useHeic;
357 bool isSizeSupported = isSizeSupportedByHeifEncoder(
358 streamInfo.width, streamInfo.height, &useHeic, &useGrid, nullptr);
359 if (!isSizeSupported) {
360 // Size is not supported by either encoder.
361 return OK;
362 }
363
364 compositeOutput->insert(compositeOutput->end(), 2, streamInfo);
365
366 // JPEG APPS segments Blob stream info
367 (*compositeOutput)[0].width = calcAppSegmentMaxSize(ch);
368 (*compositeOutput)[0].height = 1;
369 (*compositeOutput)[0].format = HAL_PIXEL_FORMAT_BLOB;
370 (*compositeOutput)[0].dataSpace = kAppSegmentDataSpace;
371 (*compositeOutput)[0].consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
372
373 // YUV/IMPLEMENTATION_DEFINED stream info
374 (*compositeOutput)[1].width = streamInfo.width;
375 (*compositeOutput)[1].height = streamInfo.height;
376 (*compositeOutput)[1].format = useGrid ? HAL_PIXEL_FORMAT_YCbCr_420_888 :
377 HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
378 (*compositeOutput)[1].dataSpace = kHeifDataSpace;
379 (*compositeOutput)[1].consumerUsage = useHeic ? GRALLOC_USAGE_HW_IMAGE_ENCODER :
380 useGrid ? GRALLOC_USAGE_SW_READ_OFTEN : GRALLOC_USAGE_HW_VIDEO_ENCODER;
381
382 return NO_ERROR;
383}
384
385bool HeicCompositeStream::isSizeSupportedByHeifEncoder(int32_t width, int32_t height,
Chong Zhang688abaa2019-05-17 16:32:23 -0700386 bool* useHeic, bool* useGrid, int64_t* stall, AString* hevcName) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800387 static HeicEncoderInfoManager& heicManager = HeicEncoderInfoManager::getInstance();
Chong Zhang688abaa2019-05-17 16:32:23 -0700388 return heicManager.isSizeSupported(width, height, useHeic, useGrid, stall, hevcName);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800389}
390
391bool HeicCompositeStream::isInMemoryTempFileSupported() {
392 int memfd = syscall(__NR_memfd_create, "HEIF-try-memfd", MFD_CLOEXEC);
393 if (memfd == -1) {
394 if (errno != ENOSYS) {
395 ALOGE("%s: Failed to create tmpfs file. errno %d", __FUNCTION__, errno);
396 }
397 return false;
398 }
399 close(memfd);
400 return true;
401}
402
403void HeicCompositeStream::onHeicOutputFrameAvailable(
404 const CodecOutputBufferInfo& outputBufferInfo) {
405 Mutex::Autolock l(mMutex);
406
407 ALOGV("%s: index %d, offset %d, size %d, time %" PRId64 ", flags 0x%x",
408 __FUNCTION__, outputBufferInfo.index, outputBufferInfo.offset,
409 outputBufferInfo.size, outputBufferInfo.timeUs, outputBufferInfo.flags);
410
411 if (!mErrorState) {
412 if ((outputBufferInfo.size > 0) &&
413 ((outputBufferInfo.flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) == 0)) {
414 mCodecOutputBuffers.push_back(outputBufferInfo);
415 mInputReadyCondition.signal();
416 } else {
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700417 ALOGV("%s: Releasing output buffer: size %d flags: 0x%x ", __FUNCTION__,
418 outputBufferInfo.size, outputBufferInfo.flags);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800419 mCodec->releaseOutputBuffer(outputBufferInfo.index);
420 }
421 } else {
422 mCodec->releaseOutputBuffer(outputBufferInfo.index);
423 }
424}
425
426void HeicCompositeStream::onHeicInputFrameAvailable(int32_t index) {
427 Mutex::Autolock l(mMutex);
428
429 if (!mUseGrid) {
430 ALOGE("%s: Codec YUV input mode must only be used for Hevc tiling mode", __FUNCTION__);
431 return;
432 }
433
434 mCodecInputBuffers.push_back(index);
435 mInputReadyCondition.signal();
436}
437
438void HeicCompositeStream::onHeicFormatChanged(sp<AMessage>& newFormat) {
439 if (newFormat == nullptr) {
440 ALOGE("%s: newFormat must not be null!", __FUNCTION__);
441 return;
442 }
443
444 Mutex::Autolock l(mMutex);
445
446 AString mime;
447 AString mimeHeic(MIMETYPE_IMAGE_ANDROID_HEIC);
448 newFormat->findString(KEY_MIME, &mime);
449 if (mime != mimeHeic) {
450 // For HEVC codec, below keys need to be filled out or overwritten so that the
451 // muxer can handle them as HEIC output image.
452 newFormat->setString(KEY_MIME, mimeHeic);
453 newFormat->setInt32(KEY_WIDTH, mOutputWidth);
454 newFormat->setInt32(KEY_HEIGHT, mOutputHeight);
455 if (mUseGrid) {
456 newFormat->setInt32(KEY_TILE_WIDTH, mGridWidth);
457 newFormat->setInt32(KEY_TILE_HEIGHT, mGridHeight);
458 newFormat->setInt32(KEY_GRID_ROWS, mGridRows);
459 newFormat->setInt32(KEY_GRID_COLUMNS, mGridCols);
dan.shen60fa4b92022-04-12 18:57:43 +0800460 int32_t left, top, right, bottom;
461 if (newFormat->findRect("crop", &left, &top, &right, &bottom)) {
462 newFormat->setRect("crop", 0, 0, mOutputWidth - 1, mOutputHeight - 1);
463 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800464 }
465 }
466 newFormat->setInt32(KEY_IS_DEFAULT, 1 /*isPrimary*/);
467
468 int32_t gridRows, gridCols;
469 if (newFormat->findInt32(KEY_GRID_ROWS, &gridRows) &&
470 newFormat->findInt32(KEY_GRID_COLUMNS, &gridCols)) {
471 mNumOutputTiles = gridRows * gridCols;
472 } else {
473 mNumOutputTiles = 1;
474 }
475
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800476 mFormat = newFormat;
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700477
478 ALOGV("%s: mNumOutputTiles is %zu", __FUNCTION__, mNumOutputTiles);
479 mInputReadyCondition.signal();
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800480}
481
482void HeicCompositeStream::onHeicCodecError() {
483 Mutex::Autolock l(mMutex);
484 mErrorState = true;
485}
486
487status_t HeicCompositeStream::configureStream() {
488 if (isRunning()) {
489 // Processing thread is already running, nothing more to do.
490 return NO_ERROR;
491 }
492
493 if (mOutputSurface.get() == nullptr) {
494 ALOGE("%s: No valid output surface set!", __FUNCTION__);
495 return NO_INIT;
496 }
497
498 auto res = mOutputSurface->connect(NATIVE_WINDOW_API_CAMERA, mProducerListener);
499 if (res != OK) {
500 ALOGE("%s: Unable to connect to native window for stream %d",
501 __FUNCTION__, mMainImageStreamId);
502 return res;
503 }
504
505 if ((res = native_window_set_buffers_format(mOutputSurface.get(), HAL_PIXEL_FORMAT_BLOB))
506 != OK) {
507 ALOGE("%s: Unable to configure stream buffer format for stream %d", __FUNCTION__,
508 mMainImageStreamId);
509 return res;
510 }
511
512 ANativeWindow *anwConsumer = mOutputSurface.get();
513 int maxConsumerBuffers;
514 if ((res = anwConsumer->query(anwConsumer, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
515 &maxConsumerBuffers)) != OK) {
516 ALOGE("%s: Unable to query consumer undequeued"
517 " buffer count for stream %d", __FUNCTION__, mMainImageStreamId);
518 return res;
519 }
520
521 // Cannot use SourceSurface buffer count since it could be codec's 512*512 tile
522 // buffer count.
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800523 if ((res = native_window_set_buffer_count(
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700524 anwConsumer, kMaxOutputSurfaceProducerCount + maxConsumerBuffers)) != OK) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800525 ALOGE("%s: Unable to set buffer count for stream %d", __FUNCTION__, mMainImageStreamId);
526 return res;
527 }
528
529 if ((res = native_window_set_buffers_dimensions(anwConsumer, mMaxHeicBufferSize, 1)) != OK) {
530 ALOGE("%s: Unable to set buffer dimension %zu x 1 for stream %d: %s (%d)",
531 __FUNCTION__, mMaxHeicBufferSize, mMainImageStreamId, strerror(-res), res);
532 return res;
533 }
534
Shuzhen Wange8675782019-12-05 09:12:14 -0800535 sp<camera3::StatusTracker> statusTracker = mStatusTracker.promote();
536 if (statusTracker != nullptr) {
Yin-Chia Yeh87b3ec02019-06-03 10:44:39 -0700537 std::string name = std::string("HeicStream ") + std::to_string(getStreamId());
538 mStatusId = statusTracker->addComponent(name);
Shuzhen Wange8675782019-12-05 09:12:14 -0800539 }
540
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800541 run("HeicCompositeStreamProc");
542
543 return NO_ERROR;
544}
545
546status_t HeicCompositeStream::insertGbp(SurfaceMap* /*out*/outSurfaceMap,
547 Vector<int32_t>* /*out*/outputStreamIds, int32_t* /*out*/currentStreamId) {
548 if (outSurfaceMap->find(mAppSegmentStreamId) == outSurfaceMap->end()) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800549 outputStreamIds->push_back(mAppSegmentStreamId);
550 }
551 (*outSurfaceMap)[mAppSegmentStreamId].push_back(mAppSegmentSurfaceId);
552
553 if (outSurfaceMap->find(mMainImageStreamId) == outSurfaceMap->end()) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800554 outputStreamIds->push_back(mMainImageStreamId);
555 }
556 (*outSurfaceMap)[mMainImageStreamId].push_back(mMainImageSurfaceId);
557
558 if (currentStreamId != nullptr) {
559 *currentStreamId = mMainImageStreamId;
560 }
561
562 return NO_ERROR;
563}
564
Emilian Peev4697b642019-11-19 17:11:14 -0800565status_t HeicCompositeStream::insertCompositeStreamIds(
566 std::vector<int32_t>* compositeStreamIds /*out*/) {
567 if (compositeStreamIds == nullptr) {
568 return BAD_VALUE;
569 }
570
571 compositeStreamIds->push_back(mAppSegmentStreamId);
572 compositeStreamIds->push_back(mMainImageStreamId);
573
574 return OK;
575}
576
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800577void HeicCompositeStream::onShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) {
578 Mutex::Autolock l(mMutex);
579 if (mErrorState) {
580 return;
581 }
582
583 if (mSettingsByFrameNumber.find(resultExtras.frameNumber) != mSettingsByFrameNumber.end()) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800584 ALOGV("%s: [%" PRId64 "]: timestamp %" PRId64 ", requestId %d", __FUNCTION__,
585 resultExtras.frameNumber, timestamp, resultExtras.requestId);
586 mSettingsByFrameNumber[resultExtras.frameNumber].shutterNotified = true;
587 mSettingsByFrameNumber[resultExtras.frameNumber].timestamp = timestamp;
588 mSettingsByFrameNumber[resultExtras.frameNumber].requestId = resultExtras.requestId;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800589 mInputReadyCondition.signal();
590 }
591}
592
593void HeicCompositeStream::compilePendingInputLocked() {
Shuzhen Wange8675782019-12-05 09:12:14 -0800594 auto i = mSettingsByFrameNumber.begin();
595 while (i != mSettingsByFrameNumber.end()) {
596 if (i->second.shutterNotified) {
597 mPendingInputFrames[i->first].orientation = i->second.orientation;
598 mPendingInputFrames[i->first].quality = i->second.quality;
599 mPendingInputFrames[i->first].timestamp = i->second.timestamp;
600 mPendingInputFrames[i->first].requestId = i->second.requestId;
601 ALOGV("%s: [%" PRId64 "]: timestamp is %" PRId64, __FUNCTION__,
602 i->first, i->second.timestamp);
603 i = mSettingsByFrameNumber.erase(i);
Shuzhen Wang62f49ed2019-09-04 14:07:53 -0700604
Shuzhen Wange8675782019-12-05 09:12:14 -0800605 // Set encoder quality if no inflight encoding
606 if (mPendingInputFrames.size() == 1) {
607 sp<StatusTracker> statusTracker = mStatusTracker.promote();
608 if (statusTracker != nullptr) {
609 statusTracker->markComponentActive(mStatusId);
610 ALOGV("%s: Mark component as active", __FUNCTION__);
611 }
612
613 int32_t newQuality = mPendingInputFrames.begin()->second.quality;
614 updateCodecQualityLocked(newQuality);
615 }
616 } else {
617 i++;
Shuzhen Wang62f49ed2019-09-04 14:07:53 -0700618 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800619 }
620
Shuzhen Wange8675782019-12-05 09:12:14 -0800621 while (!mInputAppSegmentBuffers.empty() && mAppSegmentFrameNumbers.size() > 0) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800622 CpuConsumer::LockedBuffer imgBuffer;
623 auto it = mInputAppSegmentBuffers.begin();
624 auto res = mAppSegmentConsumer->lockNextBuffer(&imgBuffer);
625 if (res == NOT_ENOUGH_DATA) {
Michael Gonzalezb5986a32019-10-09 15:38:17 -0700626 // Can not lock any more buffers.
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800627 break;
628 } else if ((res != OK) || (*it != imgBuffer.timestamp)) {
629 if (res != OK) {
630 ALOGE("%s: Error locking JPEG_APP_SEGMENTS image buffer: %s (%d)", __FUNCTION__,
631 strerror(-res), res);
632 } else {
633 ALOGE("%s: Expecting JPEG_APP_SEGMENTS buffer with time stamp: %" PRId64
634 " received buffer with time stamp: %" PRId64, __FUNCTION__,
635 *it, imgBuffer.timestamp);
Michael Gonzalezb5986a32019-10-09 15:38:17 -0700636 mAppSegmentConsumer->unlockBuffer(imgBuffer);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800637 }
638 mPendingInputFrames[*it].error = true;
639 mInputAppSegmentBuffers.erase(it);
640 continue;
641 }
642
Shuzhen Wange8675782019-12-05 09:12:14 -0800643 if (mPendingInputFrames.find(mAppSegmentFrameNumbers.front()) == mPendingInputFrames.end()) {
644 ALOGE("%s: mPendingInputFrames doesn't contain frameNumber %" PRId64, __FUNCTION__,
645 mAppSegmentFrameNumbers.front());
Shuzhen Wang991b7b62020-06-17 11:39:11 -0700646 mInputAppSegmentBuffers.erase(it);
647 mAppSegmentFrameNumbers.pop();
Shuzhen Wange8675782019-12-05 09:12:14 -0800648 continue;
649 }
650
651 int64_t frameNumber = mAppSegmentFrameNumbers.front();
652 // If mPendingInputFrames doesn't contain the expected frame number, the captured
653 // input app segment frame must have been dropped via a buffer error. Simply
654 // return the buffer to the buffer queue.
655 if ((mPendingInputFrames.find(frameNumber) == mPendingInputFrames.end()) ||
656 (mPendingInputFrames[frameNumber].error)) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800657 mAppSegmentConsumer->unlockBuffer(imgBuffer);
658 } else {
Shuzhen Wange8675782019-12-05 09:12:14 -0800659 mPendingInputFrames[frameNumber].appSegmentBuffer = imgBuffer;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800660 }
661 mInputAppSegmentBuffers.erase(it);
Shuzhen Wange8675782019-12-05 09:12:14 -0800662 mAppSegmentFrameNumbers.pop();
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800663 }
664
Shuzhen Wange8675782019-12-05 09:12:14 -0800665 while (!mInputYuvBuffers.empty() && !mYuvBufferAcquired && mMainImageFrameNumbers.size() > 0) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800666 CpuConsumer::LockedBuffer imgBuffer;
667 auto it = mInputYuvBuffers.begin();
668 auto res = mMainImageConsumer->lockNextBuffer(&imgBuffer);
669 if (res == NOT_ENOUGH_DATA) {
Michael Gonzalezb5986a32019-10-09 15:38:17 -0700670 // Can not lock any more buffers.
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800671 break;
672 } else if (res != OK) {
673 ALOGE("%s: Error locking YUV_888 image buffer: %s (%d)", __FUNCTION__,
674 strerror(-res), res);
675 mPendingInputFrames[*it].error = true;
676 mInputYuvBuffers.erase(it);
677 continue;
678 } else if (*it != imgBuffer.timestamp) {
679 ALOGW("%s: Expecting YUV_888 buffer with time stamp: %" PRId64 " received buffer with "
680 "time stamp: %" PRId64, __FUNCTION__, *it, imgBuffer.timestamp);
681 mPendingInputFrames[*it].error = true;
682 mInputYuvBuffers.erase(it);
683 continue;
684 }
685
Shuzhen Wange8675782019-12-05 09:12:14 -0800686 if (mPendingInputFrames.find(mMainImageFrameNumbers.front()) == mPendingInputFrames.end()) {
687 ALOGE("%s: mPendingInputFrames doesn't contain frameNumber %" PRId64, __FUNCTION__,
688 mMainImageFrameNumbers.front());
689 mInputYuvBuffers.erase(it);
Shuzhen Wang991b7b62020-06-17 11:39:11 -0700690 mMainImageFrameNumbers.pop();
Shuzhen Wange8675782019-12-05 09:12:14 -0800691 continue;
692 }
693
694 int64_t frameNumber = mMainImageFrameNumbers.front();
695 // If mPendingInputFrames doesn't contain the expected frame number, the captured
696 // input main image must have been dropped via a buffer error. Simply
697 // return the buffer to the buffer queue.
698 if ((mPendingInputFrames.find(frameNumber) == mPendingInputFrames.end()) ||
699 (mPendingInputFrames[frameNumber].error)) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800700 mMainImageConsumer->unlockBuffer(imgBuffer);
701 } else {
Shuzhen Wange8675782019-12-05 09:12:14 -0800702 mPendingInputFrames[frameNumber].yuvBuffer = imgBuffer;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800703 mYuvBufferAcquired = true;
704 }
705 mInputYuvBuffers.erase(it);
Shuzhen Wange8675782019-12-05 09:12:14 -0800706 mMainImageFrameNumbers.pop();
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800707 }
708
709 while (!mCodecOutputBuffers.empty()) {
710 auto it = mCodecOutputBuffers.begin();
Shuzhen Wange8675782019-12-05 09:12:14 -0800711 // Assume encoder input to output is FIFO, use a queue to look up
712 // frameNumber when handling codec outputs.
713 int64_t bufferFrameNumber = -1;
714 if (mCodecOutputBufferFrameNumbers.empty()) {
715 ALOGV("%s: Failed to find buffer frameNumber for codec output buffer!", __FUNCTION__);
Michael Gonzalez5c103f22019-10-08 14:30:32 -0700716 break;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800717 } else {
Shuzhen Wange8675782019-12-05 09:12:14 -0800718 // Direct mapping between camera frame number and codec timestamp (in us).
719 bufferFrameNumber = mCodecOutputBufferFrameNumbers.front();
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700720 mCodecOutputCounter++;
721 if (mCodecOutputCounter == mNumOutputTiles) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800722 mCodecOutputBufferFrameNumbers.pop();
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700723 mCodecOutputCounter = 0;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800724 }
725
Shuzhen Wange8675782019-12-05 09:12:14 -0800726 mPendingInputFrames[bufferFrameNumber].codecOutputBuffers.push_back(*it);
727 ALOGV("%s: [%" PRId64 "]: Pushing codecOutputBuffers (frameNumber %" PRId64 ")",
728 __FUNCTION__, bufferFrameNumber, it->timeUs);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800729 }
730 mCodecOutputBuffers.erase(it);
731 }
732
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800733 while (!mCaptureResults.empty()) {
734 auto it = mCaptureResults.begin();
Shuzhen Wange8675782019-12-05 09:12:14 -0800735 // Negative frame number indicates that something went wrong during the capture result
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800736 // collection process.
Shuzhen Wange8675782019-12-05 09:12:14 -0800737 int64_t frameNumber = std::get<0>(it->second);
738 if (it->first >= 0 &&
739 mPendingInputFrames.find(frameNumber) != mPendingInputFrames.end()) {
740 if (mPendingInputFrames[frameNumber].timestamp == it->first) {
741 mPendingInputFrames[frameNumber].result =
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800742 std::make_unique<CameraMetadata>(std::get<1>(it->second));
743 } else {
744 ALOGE("%s: Capture result frameNumber/timestamp mapping changed between "
Shuzhen Wange8675782019-12-05 09:12:14 -0800745 "shutter and capture result! before: %" PRId64 ", after: %" PRId64,
746 __FUNCTION__, mPendingInputFrames[frameNumber].timestamp,
747 it->first);
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800748 }
749 }
750 mCaptureResults.erase(it);
751 }
752
753 // mErrorFrameNumbers stores frame number of dropped buffers.
754 auto it = mErrorFrameNumbers.begin();
755 while (it != mErrorFrameNumbers.end()) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800756 if (mPendingInputFrames.find(*it) != mPendingInputFrames.end()) {
757 mPendingInputFrames[*it].error = true;
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800758 } else {
Shuzhen Wange8675782019-12-05 09:12:14 -0800759 //Error callback is guaranteed to arrive after shutter notify, which
760 //results in mPendingInputFrames being populated.
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800761 ALOGW("%s: Not able to find failing input with frame number: %" PRId64, __FUNCTION__,
762 *it);
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800763 }
Shuzhen Wange8675782019-12-05 09:12:14 -0800764 it = mErrorFrameNumbers.erase(it);
765 }
766
767 // mExifErrorFrameNumbers stores the frame number of dropped APP_SEGMENT buffers
768 it = mExifErrorFrameNumbers.begin();
769 while (it != mExifErrorFrameNumbers.end()) {
770 if (mPendingInputFrames.find(*it) != mPendingInputFrames.end()) {
771 mPendingInputFrames[*it].exifError = true;
772 }
773 it = mExifErrorFrameNumbers.erase(it);
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800774 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800775
776 // Distribute codec input buffers to be filled out from YUV output
777 for (auto it = mPendingInputFrames.begin();
778 it != mPendingInputFrames.end() && mCodecInputBuffers.size() > 0; it++) {
779 InputFrame& inputFrame(it->second);
780 if (inputFrame.codecInputCounter < mGridRows * mGridCols) {
781 // Available input tiles that are required for the current input
782 // image.
783 size_t newInputTiles = std::min(mCodecInputBuffers.size(),
784 mGridRows * mGridCols - inputFrame.codecInputCounter);
785 for (size_t i = 0; i < newInputTiles; i++) {
786 CodecInputBufferInfo inputInfo =
787 { mCodecInputBuffers[0], mGridTimestampUs++, inputFrame.codecInputCounter };
788 inputFrame.codecInputBuffers.push_back(inputInfo);
789
790 mCodecInputBuffers.erase(mCodecInputBuffers.begin());
791 inputFrame.codecInputCounter++;
792 }
793 break;
794 }
795 }
796}
797
Shuzhen Wange8675782019-12-05 09:12:14 -0800798bool HeicCompositeStream::getNextReadyInputLocked(int64_t *frameNumber /*out*/) {
799 if (frameNumber == nullptr) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800800 return false;
801 }
802
803 bool newInputAvailable = false;
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700804 for (auto& it : mPendingInputFrames) {
805 // New input is considered to be available only if:
806 // 1. input buffers are ready, or
807 // 2. App segment and muxer is created, or
808 // 3. A codec output tile is ready, and an output buffer is available.
809 // This makes sure that muxer gets created only when an output tile is
810 // generated, because right now we only handle 1 HEIC output buffer at a
811 // time (max dequeued buffer count is 1).
Shuzhen Wange8675782019-12-05 09:12:14 -0800812 bool appSegmentReady =
813 (it.second.appSegmentBuffer.data != nullptr || it.second.exifError) &&
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700814 !it.second.appSegmentWritten && it.second.result != nullptr &&
815 it.second.muxer != nullptr;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800816 bool codecOutputReady = !it.second.codecOutputBuffers.empty();
817 bool codecInputReady = (it.second.yuvBuffer.data != nullptr) &&
818 (!it.second.codecInputBuffers.empty());
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700819 bool hasOutputBuffer = it.second.muxer != nullptr ||
820 (mDequeuedOutputBufferCnt < kMaxOutputSurfaceProducerCount);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800821 if ((!it.second.error) &&
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700822 (appSegmentReady || (codecOutputReady && hasOutputBuffer) || codecInputReady)) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800823 *frameNumber = it.first;
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700824 if (it.second.format == nullptr && mFormat != nullptr) {
825 it.second.format = mFormat->dup();
826 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800827 newInputAvailable = true;
828 break;
829 }
830 }
831
832 return newInputAvailable;
833}
834
Shuzhen Wange8675782019-12-05 09:12:14 -0800835int64_t HeicCompositeStream::getNextFailingInputLocked() {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800836 int64_t res = -1;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800837
838 for (const auto& it : mPendingInputFrames) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800839 if (it.second.error) {
840 res = it.first;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800841 break;
842 }
843 }
844
845 return res;
846}
847
Shuzhen Wange8675782019-12-05 09:12:14 -0800848status_t HeicCompositeStream::processInputFrame(int64_t frameNumber,
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800849 InputFrame &inputFrame) {
850 ATRACE_CALL();
851 status_t res = OK;
852
Shuzhen Wange8675782019-12-05 09:12:14 -0800853 bool appSegmentReady =
854 (inputFrame.appSegmentBuffer.data != nullptr || inputFrame.exifError) &&
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700855 !inputFrame.appSegmentWritten && inputFrame.result != nullptr &&
856 inputFrame.muxer != nullptr;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800857 bool codecOutputReady = inputFrame.codecOutputBuffers.size() > 0;
858 bool codecInputReady = inputFrame.yuvBuffer.data != nullptr &&
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700859 !inputFrame.codecInputBuffers.empty();
860 bool hasOutputBuffer = inputFrame.muxer != nullptr ||
861 (mDequeuedOutputBufferCnt < kMaxOutputSurfaceProducerCount);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800862
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700863 ALOGV("%s: [%" PRId64 "]: appSegmentReady %d, codecOutputReady %d, codecInputReady %d,"
Shuzhen Wange8675782019-12-05 09:12:14 -0800864 " dequeuedOutputBuffer %d, timestamp %" PRId64, __FUNCTION__, frameNumber,
865 appSegmentReady, codecOutputReady, codecInputReady, mDequeuedOutputBufferCnt,
866 inputFrame.timestamp);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800867
868 // Handle inputs for Hevc tiling
869 if (codecInputReady) {
870 res = processCodecInputFrame(inputFrame);
871 if (res != OK) {
872 ALOGE("%s: Failed to process codec input frame: %s (%d)", __FUNCTION__,
873 strerror(-res), res);
874 return res;
875 }
876 }
877
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700878 if (!(codecOutputReady && hasOutputBuffer) && !appSegmentReady) {
879 return OK;
880 }
881
882 // Initialize and start muxer if not yet done so. In this case,
883 // codecOutputReady must be true. Otherwise, appSegmentReady is guaranteed
884 // to be false, and the function must have returned early.
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800885 if (inputFrame.muxer == nullptr) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800886 res = startMuxerForInputFrame(frameNumber, inputFrame);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800887 if (res != OK) {
888 ALOGE("%s: Failed to create and start muxer: %s (%d)", __FUNCTION__,
889 strerror(-res), res);
890 return res;
891 }
892 }
893
894 // Write JPEG APP segments data to the muxer.
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700895 if (appSegmentReady) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800896 res = processAppSegment(frameNumber, inputFrame);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800897 if (res != OK) {
898 ALOGE("%s: Failed to process JPEG APP segments: %s (%d)", __FUNCTION__,
899 strerror(-res), res);
900 return res;
901 }
902 }
903
904 // Write media codec bitstream buffers to muxer.
905 while (!inputFrame.codecOutputBuffers.empty()) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800906 res = processOneCodecOutputFrame(frameNumber, inputFrame);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800907 if (res != OK) {
908 ALOGE("%s: Failed to process codec output frame: %s (%d)", __FUNCTION__,
909 strerror(-res), res);
910 return res;
911 }
912 }
913
Michael Gonzalezb5986a32019-10-09 15:38:17 -0700914 if (inputFrame.pendingOutputTiles == 0) {
915 if (inputFrame.appSegmentWritten) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800916 res = processCompletedInputFrame(frameNumber, inputFrame);
Michael Gonzalezb5986a32019-10-09 15:38:17 -0700917 if (res != OK) {
918 ALOGE("%s: Failed to process completed input frame: %s (%d)", __FUNCTION__,
919 strerror(-res), res);
920 return res;
921 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800922 }
923 }
924
925 return res;
926}
927
Shuzhen Wange8675782019-12-05 09:12:14 -0800928status_t HeicCompositeStream::startMuxerForInputFrame(int64_t frameNumber, InputFrame &inputFrame) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800929 sp<ANativeWindow> outputANW = mOutputSurface;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800930
931 auto res = outputANW->dequeueBuffer(mOutputSurface.get(), &inputFrame.anb, &inputFrame.fenceFd);
932 if (res != OK) {
933 ALOGE("%s: Error retrieving output buffer: %s (%d)", __FUNCTION__, strerror(-res),
934 res);
935 return res;
936 }
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700937 mDequeuedOutputBufferCnt++;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800938
939 // Combine current thread id, stream id and timestamp to uniquely identify image.
940 std::ostringstream tempOutputFile;
941 tempOutputFile << "HEIF-" << pthread_self() << "-"
Shuzhen Wange8675782019-12-05 09:12:14 -0800942 << getStreamId() << "-" << frameNumber;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800943 inputFrame.fileFd = syscall(__NR_memfd_create, tempOutputFile.str().c_str(), MFD_CLOEXEC);
944 if (inputFrame.fileFd < 0) {
945 ALOGE("%s: Failed to create file %s. Error no is %d", __FUNCTION__,
946 tempOutputFile.str().c_str(), errno);
947 return NO_INIT;
948 }
Manisha Jajoo022b52f2021-10-09 00:51:42 +0530949 inputFrame.muxer = MediaMuxer::create(inputFrame.fileFd, MediaMuxer::OUTPUT_FORMAT_HEIF);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800950 if (inputFrame.muxer == nullptr) {
951 ALOGE("%s: Failed to create MediaMuxer for file fd %d",
952 __FUNCTION__, inputFrame.fileFd);
953 return NO_INIT;
954 }
955
956 res = inputFrame.muxer->setOrientationHint(inputFrame.orientation);
957 if (res != OK) {
958 ALOGE("%s: Failed to setOrientationHint: %s (%d)", __FUNCTION__,
959 strerror(-res), res);
960 return res;
961 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800962
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700963 ssize_t trackId = inputFrame.muxer->addTrack(inputFrame.format);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800964 if (trackId < 0) {
965 ALOGE("%s: Failed to addTrack to the muxer: %zd", __FUNCTION__, trackId);
966 return NO_INIT;
967 }
968
969 inputFrame.trackIndex = trackId;
970 inputFrame.pendingOutputTiles = mNumOutputTiles;
971
972 res = inputFrame.muxer->start();
973 if (res != OK) {
974 ALOGE("%s: Failed to start MediaMuxer: %s (%d)",
975 __FUNCTION__, strerror(-res), res);
976 return res;
977 }
978
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700979 ALOGV("%s: [%" PRId64 "]: Muxer started for inputFrame", __FUNCTION__,
Shuzhen Wange8675782019-12-05 09:12:14 -0800980 frameNumber);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800981 return OK;
982}
983
Shuzhen Wange8675782019-12-05 09:12:14 -0800984status_t HeicCompositeStream::processAppSegment(int64_t frameNumber, InputFrame &inputFrame) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800985 size_t app1Size = 0;
Shuzhen Wange8675782019-12-05 09:12:14 -0800986 size_t appSegmentSize = 0;
987 if (!inputFrame.exifError) {
988 appSegmentSize = findAppSegmentsSize(inputFrame.appSegmentBuffer.data,
989 inputFrame.appSegmentBuffer.width * inputFrame.appSegmentBuffer.height,
990 &app1Size);
991 if (appSegmentSize == 0) {
992 ALOGE("%s: Failed to find JPEG APP segment size", __FUNCTION__);
993 return NO_INIT;
994 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800995 }
996
997 std::unique_ptr<ExifUtils> exifUtils(ExifUtils::create());
Shuzhen Wange8675782019-12-05 09:12:14 -0800998 auto exifRes = inputFrame.exifError ?
999 exifUtils->initializeEmpty() :
1000 exifUtils->initialize(inputFrame.appSegmentBuffer.data, app1Size);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001001 if (!exifRes) {
1002 ALOGE("%s: Failed to initialize ExifUtils object!", __FUNCTION__);
1003 return BAD_VALUE;
1004 }
Shuzhen Wange7f4b462019-02-12 08:43:07 -08001005 exifRes = exifUtils->setFromMetadata(*inputFrame.result, mStaticInfo,
1006 mOutputWidth, mOutputHeight);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001007 if (!exifRes) {
1008 ALOGE("%s: Failed to set Exif tags using metadata and main image sizes", __FUNCTION__);
1009 return BAD_VALUE;
1010 }
1011 exifRes = exifUtils->setOrientation(inputFrame.orientation);
1012 if (!exifRes) {
1013 ALOGE("%s: ExifUtils failed to set orientation", __FUNCTION__);
1014 return BAD_VALUE;
1015 }
1016 exifRes = exifUtils->generateApp1();
1017 if (!exifRes) {
1018 ALOGE("%s: ExifUtils failed to generate APP1 segment", __FUNCTION__);
1019 return BAD_VALUE;
1020 }
1021
1022 unsigned int newApp1Length = exifUtils->getApp1Length();
1023 const uint8_t *newApp1Segment = exifUtils->getApp1Buffer();
1024
1025 //Assemble the APP1 marker buffer required by MediaCodec
1026 uint8_t kExifApp1Marker[] = {'E', 'x', 'i', 'f', 0xFF, 0xE1, 0x00, 0x00};
1027 kExifApp1Marker[6] = static_cast<uint8_t>(newApp1Length >> 8);
1028 kExifApp1Marker[7] = static_cast<uint8_t>(newApp1Length & 0xFF);
1029 size_t appSegmentBufferSize = sizeof(kExifApp1Marker) +
1030 appSegmentSize - app1Size + newApp1Length;
1031 uint8_t* appSegmentBuffer = new uint8_t[appSegmentBufferSize];
1032 memcpy(appSegmentBuffer, kExifApp1Marker, sizeof(kExifApp1Marker));
1033 memcpy(appSegmentBuffer + sizeof(kExifApp1Marker), newApp1Segment, newApp1Length);
1034 if (appSegmentSize - app1Size > 0) {
1035 memcpy(appSegmentBuffer + sizeof(kExifApp1Marker) + newApp1Length,
1036 inputFrame.appSegmentBuffer.data + app1Size, appSegmentSize - app1Size);
1037 }
1038
1039 sp<ABuffer> aBuffer = new ABuffer(appSegmentBuffer, appSegmentBufferSize);
1040 auto res = inputFrame.muxer->writeSampleData(aBuffer, inputFrame.trackIndex,
Shuzhen Wange8675782019-12-05 09:12:14 -08001041 inputFrame.timestamp, MediaCodec::BUFFER_FLAG_MUXER_DATA);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001042 delete[] appSegmentBuffer;
1043
1044 if (res != OK) {
1045 ALOGE("%s: Failed to write JPEG APP segments to muxer: %s (%d)",
1046 __FUNCTION__, strerror(-res), res);
1047 return res;
1048 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001049
Shuzhen Wang3d00ee52019-09-25 14:19:28 -07001050 ALOGV("%s: [%" PRId64 "]: appSegmentSize is %zu, width %d, height %d, app1Size %zu",
Shuzhen Wange8675782019-12-05 09:12:14 -08001051 __FUNCTION__, frameNumber, appSegmentSize, inputFrame.appSegmentBuffer.width,
Shuzhen Wang3d00ee52019-09-25 14:19:28 -07001052 inputFrame.appSegmentBuffer.height, app1Size);
Michael Gonzalezb5986a32019-10-09 15:38:17 -07001053
1054 inputFrame.appSegmentWritten = true;
1055 // Release the buffer now so any pending input app segments can be processed
1056 mAppSegmentConsumer->unlockBuffer(inputFrame.appSegmentBuffer);
1057 inputFrame.appSegmentBuffer.data = nullptr;
Shuzhen Wange8675782019-12-05 09:12:14 -08001058 inputFrame.exifError = false;
Michael Gonzalezb5986a32019-10-09 15:38:17 -07001059
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001060 return OK;
1061}
1062
1063status_t HeicCompositeStream::processCodecInputFrame(InputFrame &inputFrame) {
1064 for (auto& inputBuffer : inputFrame.codecInputBuffers) {
1065 sp<MediaCodecBuffer> buffer;
1066 auto res = mCodec->getInputBuffer(inputBuffer.index, &buffer);
1067 if (res != OK) {
1068 ALOGE("%s: Error getting codec input buffer: %s (%d)", __FUNCTION__,
1069 strerror(-res), res);
1070 return res;
1071 }
1072
1073 // Copy one tile from source to destination.
1074 size_t tileX = inputBuffer.tileIndex % mGridCols;
1075 size_t tileY = inputBuffer.tileIndex / mGridCols;
1076 size_t top = mGridHeight * tileY;
1077 size_t left = mGridWidth * tileX;
1078 size_t width = (tileX == static_cast<size_t>(mGridCols) - 1) ?
1079 mOutputWidth - tileX * mGridWidth : mGridWidth;
1080 size_t height = (tileY == static_cast<size_t>(mGridRows) - 1) ?
1081 mOutputHeight - tileY * mGridHeight : mGridHeight;
Shuzhen Wang3d00ee52019-09-25 14:19:28 -07001082 ALOGV("%s: inputBuffer tileIndex [%zu, %zu], top %zu, left %zu, width %zu, height %zu,"
1083 " timeUs %" PRId64, __FUNCTION__, tileX, tileY, top, left, width, height,
1084 inputBuffer.timeUs);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001085
1086 res = copyOneYuvTile(buffer, inputFrame.yuvBuffer, top, left, width, height);
1087 if (res != OK) {
1088 ALOGE("%s: Failed to copy YUV tile %s (%d)", __FUNCTION__,
1089 strerror(-res), res);
1090 return res;
1091 }
1092
1093 res = mCodec->queueInputBuffer(inputBuffer.index, 0, buffer->capacity(),
1094 inputBuffer.timeUs, 0, nullptr /*errorDetailMsg*/);
1095 if (res != OK) {
1096 ALOGE("%s: Failed to queueInputBuffer to Codec: %s (%d)",
1097 __FUNCTION__, strerror(-res), res);
1098 return res;
1099 }
1100 }
1101
1102 inputFrame.codecInputBuffers.clear();
1103 return OK;
1104}
1105
Shuzhen Wange8675782019-12-05 09:12:14 -08001106status_t HeicCompositeStream::processOneCodecOutputFrame(int64_t frameNumber,
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001107 InputFrame &inputFrame) {
1108 auto it = inputFrame.codecOutputBuffers.begin();
1109 sp<MediaCodecBuffer> buffer;
1110 status_t res = mCodec->getOutputBuffer(it->index, &buffer);
1111 if (res != OK) {
1112 ALOGE("%s: Error getting Heic codec output buffer at index %d: %s (%d)",
1113 __FUNCTION__, it->index, strerror(-res), res);
1114 return res;
1115 }
1116 if (buffer == nullptr) {
1117 ALOGE("%s: Invalid Heic codec output buffer at index %d",
1118 __FUNCTION__, it->index);
1119 return BAD_VALUE;
1120 }
1121
1122 sp<ABuffer> aBuffer = new ABuffer(buffer->data(), buffer->size());
1123 res = inputFrame.muxer->writeSampleData(
Shuzhen Wange8675782019-12-05 09:12:14 -08001124 aBuffer, inputFrame.trackIndex, inputFrame.timestamp, 0 /*flags*/);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001125 if (res != OK) {
1126 ALOGE("%s: Failed to write buffer index %d to muxer: %s (%d)",
1127 __FUNCTION__, it->index, strerror(-res), res);
1128 return res;
1129 }
1130
1131 mCodec->releaseOutputBuffer(it->index);
1132 if (inputFrame.pendingOutputTiles == 0) {
1133 ALOGW("%s: Codec generated more tiles than expected!", __FUNCTION__);
1134 } else {
1135 inputFrame.pendingOutputTiles--;
1136 }
1137
1138 inputFrame.codecOutputBuffers.erase(inputFrame.codecOutputBuffers.begin());
Shuzhen Wang3d00ee52019-09-25 14:19:28 -07001139
1140 ALOGV("%s: [%" PRId64 "]: Output buffer index %d",
Shuzhen Wange8675782019-12-05 09:12:14 -08001141 __FUNCTION__, frameNumber, it->index);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001142 return OK;
1143}
1144
Shuzhen Wange8675782019-12-05 09:12:14 -08001145status_t HeicCompositeStream::processCompletedInputFrame(int64_t frameNumber,
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001146 InputFrame &inputFrame) {
1147 sp<ANativeWindow> outputANW = mOutputSurface;
1148 inputFrame.muxer->stop();
1149
1150 // Copy the content of the file to memory.
1151 sp<GraphicBuffer> gb = GraphicBuffer::from(inputFrame.anb);
1152 void* dstBuffer;
Shuzhen Wangc87315d2022-03-17 00:11:20 +00001153 GraphicBufferLocker gbLocker(gb);
1154 auto res = gbLocker.lockAsync(&dstBuffer, inputFrame.fenceFd);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001155 if (res != OK) {
1156 ALOGE("%s: Error trying to lock output buffer fence: %s (%d)", __FUNCTION__,
1157 strerror(-res), res);
1158 return res;
1159 }
1160
1161 off_t fSize = lseek(inputFrame.fileFd, 0, SEEK_END);
1162 if (static_cast<size_t>(fSize) > mMaxHeicBufferSize - sizeof(CameraBlob)) {
1163 ALOGE("%s: Error: MediaMuxer output size %ld is larger than buffer sizer %zu",
1164 __FUNCTION__, fSize, mMaxHeicBufferSize - sizeof(CameraBlob));
1165 return BAD_VALUE;
1166 }
1167
1168 lseek(inputFrame.fileFd, 0, SEEK_SET);
1169 ssize_t bytesRead = read(inputFrame.fileFd, dstBuffer, fSize);
1170 if (bytesRead < fSize) {
1171 ALOGE("%s: Only %zd of %ld bytes read", __FUNCTION__, bytesRead, fSize);
1172 return BAD_VALUE;
1173 }
1174
1175 close(inputFrame.fileFd);
1176 inputFrame.fileFd = -1;
1177
1178 // Fill in HEIC header
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001179 // Must be in sync with CAMERA3_HEIC_BLOB_ID in android_media_Utils.cpp
Shuzhen Wangdc519092022-12-02 12:29:04 -08001180 uint8_t *header = static_cast<uint8_t*>(dstBuffer) + mMaxHeicBufferSize - sizeof(CameraBlob);
1181 CameraBlob blobHeader = {
1182 .blobId = static_cast<CameraBlobId>(0x00FE),
1183 .blobSizeBytes = static_cast<int32_t>(fSize)
1184 };
1185 memcpy(header, &blobHeader, sizeof(CameraBlob));
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001186
Shuzhen Wange8675782019-12-05 09:12:14 -08001187 res = native_window_set_buffers_timestamp(mOutputSurface.get(), inputFrame.timestamp);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001188 if (res != OK) {
1189 ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
1190 __FUNCTION__, getStreamId(), strerror(-res), res);
1191 return res;
1192 }
1193
1194 res = outputANW->queueBuffer(mOutputSurface.get(), inputFrame.anb, /*fence*/ -1);
1195 if (res != OK) {
1196 ALOGE("%s: Failed to queueBuffer to Heic stream: %s (%d)", __FUNCTION__,
1197 strerror(-res), res);
1198 return res;
1199 }
1200 inputFrame.anb = nullptr;
Shuzhen Wang3d00ee52019-09-25 14:19:28 -07001201 mDequeuedOutputBufferCnt--;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001202
Shuzhen Wange8675782019-12-05 09:12:14 -08001203 ALOGV("%s: [%" PRId64 "]", __FUNCTION__, frameNumber);
1204 ATRACE_ASYNC_END("HEIC capture", frameNumber);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001205 return OK;
1206}
1207
1208
Shuzhen Wange8675782019-12-05 09:12:14 -08001209void HeicCompositeStream::releaseInputFrameLocked(int64_t frameNumber,
1210 InputFrame *inputFrame /*out*/) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001211 if (inputFrame == nullptr) {
1212 return;
1213 }
1214
1215 if (inputFrame->appSegmentBuffer.data != nullptr) {
1216 mAppSegmentConsumer->unlockBuffer(inputFrame->appSegmentBuffer);
1217 inputFrame->appSegmentBuffer.data = nullptr;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001218 }
1219
1220 while (!inputFrame->codecOutputBuffers.empty()) {
1221 auto it = inputFrame->codecOutputBuffers.begin();
1222 ALOGV("%s: releaseOutputBuffer index %d", __FUNCTION__, it->index);
1223 mCodec->releaseOutputBuffer(it->index);
1224 inputFrame->codecOutputBuffers.erase(it);
1225 }
1226
1227 if (inputFrame->yuvBuffer.data != nullptr) {
1228 mMainImageConsumer->unlockBuffer(inputFrame->yuvBuffer);
1229 inputFrame->yuvBuffer.data = nullptr;
1230 mYuvBufferAcquired = false;
1231 }
1232
1233 while (!inputFrame->codecInputBuffers.empty()) {
1234 auto it = inputFrame->codecInputBuffers.begin();
1235 inputFrame->codecInputBuffers.erase(it);
1236 }
1237
Shuzhen Wange8675782019-12-05 09:12:14 -08001238 if (inputFrame->error || mErrorState) {
1239 ALOGV("%s: notifyError called for frameNumber %" PRId64, __FUNCTION__, frameNumber);
1240 notifyError(frameNumber, inputFrame->requestId);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001241 }
1242
1243 if (inputFrame->fileFd >= 0) {
1244 close(inputFrame->fileFd);
1245 inputFrame->fileFd = -1;
1246 }
1247
1248 if (inputFrame->anb != nullptr) {
1249 sp<ANativeWindow> outputANW = mOutputSurface;
1250 outputANW->cancelBuffer(mOutputSurface.get(), inputFrame->anb, /*fence*/ -1);
1251 inputFrame->anb = nullptr;
Shuzhen Wange8675782019-12-05 09:12:14 -08001252
1253 mDequeuedOutputBufferCnt--;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001254 }
1255}
1256
Michael Gonzalezb5986a32019-10-09 15:38:17 -07001257void HeicCompositeStream::releaseInputFramesLocked() {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001258 auto it = mPendingInputFrames.begin();
Shuzhen Wang62f49ed2019-09-04 14:07:53 -07001259 bool inputFrameDone = false;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001260 while (it != mPendingInputFrames.end()) {
Michael Gonzalezb5986a32019-10-09 15:38:17 -07001261 auto& inputFrame = it->second;
1262 if (inputFrame.error ||
Shuzhen Wange8675782019-12-05 09:12:14 -08001263 (inputFrame.appSegmentWritten && inputFrame.pendingOutputTiles == 0)) {
1264 releaseInputFrameLocked(it->first, &inputFrame);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001265 it = mPendingInputFrames.erase(it);
Shuzhen Wang62f49ed2019-09-04 14:07:53 -07001266 inputFrameDone = true;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001267 } else {
1268 it++;
1269 }
1270 }
Shuzhen Wang62f49ed2019-09-04 14:07:53 -07001271
1272 // Update codec quality based on first upcoming input frame.
1273 // Note that when encoding is in surface mode, currently there is no
1274 // way for camera service to synchronize quality setting on a per-frame
1275 // basis: we don't get notification when codec is ready to consume a new
1276 // input frame. So we update codec quality on a best-effort basis.
1277 if (inputFrameDone) {
1278 auto firstPendingFrame = mPendingInputFrames.begin();
1279 if (firstPendingFrame != mPendingInputFrames.end()) {
1280 updateCodecQualityLocked(firstPendingFrame->second.quality);
Shuzhen Wange8675782019-12-05 09:12:14 -08001281 } else {
1282 markTrackerIdle();
Shuzhen Wang62f49ed2019-09-04 14:07:53 -07001283 }
1284 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001285}
1286
1287status_t HeicCompositeStream::initializeCodec(uint32_t width, uint32_t height,
1288 const sp<CameraDeviceBase>& cameraDevice) {
1289 ALOGV("%s", __FUNCTION__);
1290
1291 bool useGrid = false;
Chong Zhang688abaa2019-05-17 16:32:23 -07001292 AString hevcName;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001293 bool isSizeSupported = isSizeSupportedByHeifEncoder(width, height,
Chong Zhang688abaa2019-05-17 16:32:23 -07001294 &mUseHeic, &useGrid, nullptr, &hevcName);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001295 if (!isSizeSupported) {
1296 ALOGE("%s: Encoder doesnt' support size %u x %u!",
1297 __FUNCTION__, width, height);
1298 return BAD_VALUE;
1299 }
1300
1301 // Create Looper for MediaCodec.
1302 auto desiredMime = mUseHeic ? MIMETYPE_IMAGE_ANDROID_HEIC : MIMETYPE_VIDEO_HEVC;
1303 mCodecLooper = new ALooper;
1304 mCodecLooper->setName("Camera3-HeicComposite-MediaCodecLooper");
1305 status_t res = mCodecLooper->start(
1306 false, // runOnCallingThread
1307 false, // canCallJava
1308 PRIORITY_AUDIO);
1309 if (res != OK) {
1310 ALOGE("%s: Failed to start codec looper: %s (%d)",
1311 __FUNCTION__, strerror(-res), res);
1312 return NO_INIT;
1313 }
1314
1315 // Create HEIC/HEVC codec.
Chong Zhang688abaa2019-05-17 16:32:23 -07001316 if (mUseHeic) {
1317 mCodec = MediaCodec::CreateByType(mCodecLooper, desiredMime, true /*encoder*/);
1318 } else {
1319 mCodec = MediaCodec::CreateByComponentName(mCodecLooper, hevcName);
1320 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001321 if (mCodec == nullptr) {
1322 ALOGE("%s: Failed to create codec for %s", __FUNCTION__, desiredMime);
1323 return NO_INIT;
1324 }
1325
1326 // Create Looper and handler for Codec callback.
1327 mCodecCallbackHandler = new CodecCallbackHandler(this);
1328 if (mCodecCallbackHandler == nullptr) {
1329 ALOGE("%s: Failed to create codec callback handler", __FUNCTION__);
1330 return NO_MEMORY;
1331 }
1332 mCallbackLooper = new ALooper;
1333 mCallbackLooper->setName("Camera3-HeicComposite-MediaCodecCallbackLooper");
1334 res = mCallbackLooper->start(
1335 false, // runOnCallingThread
1336 false, // canCallJava
1337 PRIORITY_AUDIO);
1338 if (res != OK) {
1339 ALOGE("%s: Failed to start media callback looper: %s (%d)",
1340 __FUNCTION__, strerror(-res), res);
1341 return NO_INIT;
1342 }
1343 mCallbackLooper->registerHandler(mCodecCallbackHandler);
1344
1345 mAsyncNotify = new AMessage(kWhatCallbackNotify, mCodecCallbackHandler);
1346 res = mCodec->setCallback(mAsyncNotify);
1347 if (res != OK) {
1348 ALOGE("%s: Failed to set MediaCodec callback: %s (%d)", __FUNCTION__,
1349 strerror(-res), res);
1350 return res;
1351 }
1352
1353 // Create output format and configure the Codec.
1354 sp<AMessage> outputFormat = new AMessage();
1355 outputFormat->setString(KEY_MIME, desiredMime);
1356 outputFormat->setInt32(KEY_BITRATE_MODE, BITRATE_MODE_CQ);
1357 outputFormat->setInt32(KEY_QUALITY, kDefaultJpegQuality);
1358 // Ask codec to skip timestamp check and encode all frames.
Chong Zhang70bfcec2019-03-18 12:52:28 -07001359 outputFormat->setInt64(KEY_MAX_PTS_GAP_TO_ENCODER, kNoFrameDropMaxPtsGap);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001360
1361 int32_t gridWidth, gridHeight, gridRows, gridCols;
1362 if (useGrid || mUseHeic) {
1363 gridWidth = HeicEncoderInfoManager::kGridWidth;
1364 gridHeight = HeicEncoderInfoManager::kGridHeight;
1365 gridRows = (height + gridHeight - 1)/gridHeight;
1366 gridCols = (width + gridWidth - 1)/gridWidth;
1367
1368 if (mUseHeic) {
1369 outputFormat->setInt32(KEY_TILE_WIDTH, gridWidth);
1370 outputFormat->setInt32(KEY_TILE_HEIGHT, gridHeight);
1371 outputFormat->setInt32(KEY_GRID_COLUMNS, gridCols);
1372 outputFormat->setInt32(KEY_GRID_ROWS, gridRows);
1373 }
1374
1375 } else {
1376 gridWidth = width;
1377 gridHeight = height;
1378 gridRows = 1;
1379 gridCols = 1;
1380 }
1381
1382 outputFormat->setInt32(KEY_WIDTH, !useGrid ? width : gridWidth);
1383 outputFormat->setInt32(KEY_HEIGHT, !useGrid ? height : gridHeight);
1384 outputFormat->setInt32(KEY_I_FRAME_INTERVAL, 0);
1385 outputFormat->setInt32(KEY_COLOR_FORMAT,
1386 useGrid ? COLOR_FormatYUV420Flexible : COLOR_FormatSurface);
Shuzhen Wang0ca81522019-08-30 14:15:16 -07001387 outputFormat->setInt32(KEY_FRAME_RATE, useGrid ? gridRows * gridCols : kNoGridOpRate);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001388 // This only serves as a hint to encoder when encoding is not real-time.
1389 outputFormat->setInt32(KEY_OPERATING_RATE, useGrid ? kGridOpRate : kNoGridOpRate);
1390
1391 res = mCodec->configure(outputFormat, nullptr /*nativeWindow*/,
1392 nullptr /*crypto*/, CONFIGURE_FLAG_ENCODE);
1393 if (res != OK) {
1394 ALOGE("%s: Failed to configure codec: %s (%d)", __FUNCTION__,
1395 strerror(-res), res);
1396 return res;
1397 }
1398
1399 mGridWidth = gridWidth;
1400 mGridHeight = gridHeight;
1401 mGridRows = gridRows;
1402 mGridCols = gridCols;
1403 mUseGrid = useGrid;
1404 mOutputWidth = width;
1405 mOutputHeight = height;
1406 mAppSegmentMaxSize = calcAppSegmentMaxSize(cameraDevice->info());
Susmitha Gummallae911f2e2020-11-23 09:57:03 -08001407 mMaxHeicBufferSize =
1408 ALIGN(mOutputWidth, HeicEncoderInfoManager::kGridWidth) *
1409 ALIGN(mOutputHeight, HeicEncoderInfoManager::kGridHeight) * 3 / 2 + mAppSegmentMaxSize;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001410
1411 return OK;
1412}
1413
1414void HeicCompositeStream::deinitCodec() {
1415 ALOGV("%s", __FUNCTION__);
1416 if (mCodec != nullptr) {
1417 mCodec->stop();
1418 mCodec->release();
1419 mCodec.clear();
1420 }
1421
1422 if (mCodecLooper != nullptr) {
1423 mCodecLooper->stop();
1424 mCodecLooper.clear();
1425 }
1426
1427 if (mCallbackLooper != nullptr) {
1428 mCallbackLooper->stop();
1429 mCallbackLooper.clear();
1430 }
1431
1432 mAsyncNotify.clear();
1433 mFormat.clear();
1434}
1435
1436// Return the size of the complete list of app segment, 0 indicates failure
1437size_t HeicCompositeStream::findAppSegmentsSize(const uint8_t* appSegmentBuffer,
1438 size_t maxSize, size_t *app1SegmentSize) {
1439 if (appSegmentBuffer == nullptr || app1SegmentSize == nullptr) {
1440 ALOGE("%s: Invalid input appSegmentBuffer %p, app1SegmentSize %p",
1441 __FUNCTION__, appSegmentBuffer, app1SegmentSize);
1442 return 0;
1443 }
1444
1445 size_t expectedSize = 0;
1446 // First check for EXIF transport header at the end of the buffer
Jayant Chowdharyc67af1b2022-04-07 18:05:04 +00001447 const uint8_t *header = appSegmentBuffer + (maxSize - sizeof(CameraBlob));
1448 const CameraBlob *blob = (const CameraBlob*)(header);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001449 if (blob->blobId != CameraBlobId::JPEG_APP_SEGMENTS) {
Jayant Chowdharyc67af1b2022-04-07 18:05:04 +00001450 ALOGE("%s: Invalid EXIF blobId %d", __FUNCTION__, blob->blobId);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001451 return 0;
1452 }
1453
Jayant Chowdharyc67af1b2022-04-07 18:05:04 +00001454 expectedSize = blob->blobSizeBytes;
1455 if (expectedSize == 0 || expectedSize > maxSize - sizeof(CameraBlob)) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001456 ALOGE("%s: Invalid blobSize %zu.", __FUNCTION__, expectedSize);
1457 return 0;
1458 }
1459
1460 uint32_t totalSize = 0;
1461
1462 // Verify APP1 marker (mandatory)
1463 uint8_t app1Marker[] = {0xFF, 0xE1};
1464 if (memcmp(appSegmentBuffer, app1Marker, sizeof(app1Marker))) {
1465 ALOGE("%s: Invalid APP1 marker: %x, %x", __FUNCTION__,
1466 appSegmentBuffer[0], appSegmentBuffer[1]);
1467 return 0;
1468 }
1469 totalSize += sizeof(app1Marker);
1470
1471 uint16_t app1Size = (static_cast<uint16_t>(appSegmentBuffer[totalSize]) << 8) +
1472 appSegmentBuffer[totalSize+1];
1473 totalSize += app1Size;
1474
1475 ALOGV("%s: Expected APP segments size %zu, APP1 segment size %u",
1476 __FUNCTION__, expectedSize, app1Size);
1477 while (totalSize < expectedSize) {
1478 if (appSegmentBuffer[totalSize] != 0xFF ||
1479 appSegmentBuffer[totalSize+1] <= 0xE1 ||
1480 appSegmentBuffer[totalSize+1] > 0xEF) {
1481 // Invalid APPn marker
1482 ALOGE("%s: Invalid APPn marker: %x, %x", __FUNCTION__,
1483 appSegmentBuffer[totalSize], appSegmentBuffer[totalSize+1]);
1484 return 0;
1485 }
1486 totalSize += 2;
1487
1488 uint16_t appnSize = (static_cast<uint16_t>(appSegmentBuffer[totalSize]) << 8) +
1489 appSegmentBuffer[totalSize+1];
1490 totalSize += appnSize;
1491 }
1492
1493 if (totalSize != expectedSize) {
1494 ALOGE("%s: Invalid JPEG APP segments: totalSize %u vs expected size %zu",
1495 __FUNCTION__, totalSize, expectedSize);
1496 return 0;
1497 }
1498
1499 *app1SegmentSize = app1Size + sizeof(app1Marker);
1500 return expectedSize;
1501}
1502
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001503status_t HeicCompositeStream::copyOneYuvTile(sp<MediaCodecBuffer>& codecBuffer,
1504 const CpuConsumer::LockedBuffer& yuvBuffer,
1505 size_t top, size_t left, size_t width, size_t height) {
1506 ATRACE_CALL();
1507
1508 // Get stride information for codecBuffer
1509 sp<ABuffer> imageData;
1510 if (!codecBuffer->meta()->findBuffer("image-data", &imageData)) {
1511 ALOGE("%s: Codec input buffer is not for image data!", __FUNCTION__);
1512 return BAD_VALUE;
1513 }
1514 if (imageData->size() != sizeof(MediaImage2)) {
1515 ALOGE("%s: Invalid codec input image size %zu, expected %zu",
1516 __FUNCTION__, imageData->size(), sizeof(MediaImage2));
1517 return BAD_VALUE;
1518 }
1519 MediaImage2* imageInfo = reinterpret_cast<MediaImage2*>(imageData->data());
1520 if (imageInfo->mType != MediaImage2::MEDIA_IMAGE_TYPE_YUV ||
1521 imageInfo->mBitDepth != 8 ||
1522 imageInfo->mBitDepthAllocated != 8 ||
1523 imageInfo->mNumPlanes != 3) {
1524 ALOGE("%s: Invalid codec input image info: mType %d, mBitDepth %d, "
1525 "mBitDepthAllocated %d, mNumPlanes %d!", __FUNCTION__,
1526 imageInfo->mType, imageInfo->mBitDepth,
1527 imageInfo->mBitDepthAllocated, imageInfo->mNumPlanes);
1528 return BAD_VALUE;
1529 }
1530
1531 ALOGV("%s: yuvBuffer chromaStep %d, chromaStride %d",
1532 __FUNCTION__, yuvBuffer.chromaStep, yuvBuffer.chromaStride);
1533 ALOGV("%s: U offset %u, V offset %u, U rowInc %d, V rowInc %d, U colInc %d, V colInc %d",
1534 __FUNCTION__, imageInfo->mPlane[MediaImage2::U].mOffset,
1535 imageInfo->mPlane[MediaImage2::V].mOffset,
1536 imageInfo->mPlane[MediaImage2::U].mRowInc,
1537 imageInfo->mPlane[MediaImage2::V].mRowInc,
1538 imageInfo->mPlane[MediaImage2::U].mColInc,
1539 imageInfo->mPlane[MediaImage2::V].mColInc);
1540
1541 // Y
1542 for (auto row = top; row < top+height; row++) {
1543 uint8_t *dst = codecBuffer->data() + imageInfo->mPlane[MediaImage2::Y].mOffset +
1544 imageInfo->mPlane[MediaImage2::Y].mRowInc * (row - top);
Shuzhen Wang219c2992019-02-15 17:24:28 -08001545 mFnCopyRow(yuvBuffer.data+row*yuvBuffer.stride+left, dst, width);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001546 }
1547
1548 // U is Cb, V is Cr
1549 bool codecUPlaneFirst = imageInfo->mPlane[MediaImage2::V].mOffset >
1550 imageInfo->mPlane[MediaImage2::U].mOffset;
1551 uint32_t codecUvOffsetDiff = codecUPlaneFirst ?
1552 imageInfo->mPlane[MediaImage2::V].mOffset - imageInfo->mPlane[MediaImage2::U].mOffset :
1553 imageInfo->mPlane[MediaImage2::U].mOffset - imageInfo->mPlane[MediaImage2::V].mOffset;
1554 bool isCodecUvSemiplannar = (codecUvOffsetDiff == 1) &&
1555 (imageInfo->mPlane[MediaImage2::U].mRowInc ==
1556 imageInfo->mPlane[MediaImage2::V].mRowInc) &&
1557 (imageInfo->mPlane[MediaImage2::U].mColInc == 2) &&
1558 (imageInfo->mPlane[MediaImage2::V].mColInc == 2);
1559 bool isCodecUvPlannar =
1560 ((codecUPlaneFirst && codecUvOffsetDiff >=
1561 imageInfo->mPlane[MediaImage2::U].mRowInc * imageInfo->mHeight/2) ||
1562 ((!codecUPlaneFirst && codecUvOffsetDiff >=
1563 imageInfo->mPlane[MediaImage2::V].mRowInc * imageInfo->mHeight/2))) &&
1564 imageInfo->mPlane[MediaImage2::U].mColInc == 1 &&
1565 imageInfo->mPlane[MediaImage2::V].mColInc == 1;
1566 bool cameraUPlaneFirst = yuvBuffer.dataCr > yuvBuffer.dataCb;
1567
1568 if (isCodecUvSemiplannar && yuvBuffer.chromaStep == 2 &&
1569 (codecUPlaneFirst == cameraUPlaneFirst)) {
1570 // UV semiplannar
1571 // The chrome plane could be either Cb first, or Cr first. Take the
1572 // smaller address.
1573 uint8_t *src = std::min(yuvBuffer.dataCb, yuvBuffer.dataCr);
1574 MediaImage2::PlaneIndex dstPlane = codecUvOffsetDiff > 0 ? MediaImage2::U : MediaImage2::V;
1575 for (auto row = top/2; row < (top+height)/2; row++) {
1576 uint8_t *dst = codecBuffer->data() + imageInfo->mPlane[dstPlane].mOffset +
1577 imageInfo->mPlane[dstPlane].mRowInc * (row - top/2);
Shuzhen Wang219c2992019-02-15 17:24:28 -08001578 mFnCopyRow(src+row*yuvBuffer.chromaStride+left, dst, width);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001579 }
1580 } else if (isCodecUvPlannar && yuvBuffer.chromaStep == 1) {
1581 // U plane
1582 for (auto row = top/2; row < (top+height)/2; row++) {
1583 uint8_t *dst = codecBuffer->data() + imageInfo->mPlane[MediaImage2::U].mOffset +
1584 imageInfo->mPlane[MediaImage2::U].mRowInc * (row - top/2);
Shuzhen Wang219c2992019-02-15 17:24:28 -08001585 mFnCopyRow(yuvBuffer.dataCb+row*yuvBuffer.chromaStride+left/2, dst, width/2);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001586 }
1587
1588 // V plane
1589 for (auto row = top/2; row < (top+height)/2; row++) {
1590 uint8_t *dst = codecBuffer->data() + imageInfo->mPlane[MediaImage2::V].mOffset +
1591 imageInfo->mPlane[MediaImage2::V].mRowInc * (row - top/2);
Shuzhen Wang219c2992019-02-15 17:24:28 -08001592 mFnCopyRow(yuvBuffer.dataCr+row*yuvBuffer.chromaStride+left/2, dst, width/2);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001593 }
1594 } else {
Shuzhen Wang219c2992019-02-15 17:24:28 -08001595 // Convert between semiplannar and plannar, or when UV orders are
1596 // different.
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001597 uint8_t *dst = codecBuffer->data();
1598 for (auto row = top/2; row < (top+height)/2; row++) {
1599 for (auto col = left/2; col < (left+width)/2; col++) {
1600 // U/Cb
1601 int32_t dstIndex = imageInfo->mPlane[MediaImage2::U].mOffset +
1602 imageInfo->mPlane[MediaImage2::U].mRowInc * (row - top/2) +
1603 imageInfo->mPlane[MediaImage2::U].mColInc * (col - left/2);
1604 int32_t srcIndex = row * yuvBuffer.chromaStride + yuvBuffer.chromaStep * col;
1605 dst[dstIndex] = yuvBuffer.dataCb[srcIndex];
1606
1607 // V/Cr
1608 dstIndex = imageInfo->mPlane[MediaImage2::V].mOffset +
1609 imageInfo->mPlane[MediaImage2::V].mRowInc * (row - top/2) +
1610 imageInfo->mPlane[MediaImage2::V].mColInc * (col - left/2);
1611 srcIndex = row * yuvBuffer.chromaStride + yuvBuffer.chromaStep * col;
1612 dst[dstIndex] = yuvBuffer.dataCr[srcIndex];
1613 }
1614 }
1615 }
1616 return OK;
1617}
1618
Colin Cross14900c92023-01-13 14:50:17 -08001619void HeicCompositeStream::initCopyRowFunction([[maybe_unused]] int32_t width)
Shuzhen Wang219c2992019-02-15 17:24:28 -08001620{
1621 using namespace libyuv;
1622
1623 mFnCopyRow = CopyRow_C;
1624#if defined(HAS_COPYROW_SSE2)
1625 if (TestCpuFlag(kCpuHasSSE2)) {
1626 mFnCopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
1627 }
1628#endif
1629#if defined(HAS_COPYROW_AVX)
1630 if (TestCpuFlag(kCpuHasAVX)) {
1631 mFnCopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
1632 }
1633#endif
1634#if defined(HAS_COPYROW_ERMS)
1635 if (TestCpuFlag(kCpuHasERMS)) {
1636 mFnCopyRow = CopyRow_ERMS;
1637 }
1638#endif
1639#if defined(HAS_COPYROW_NEON)
1640 if (TestCpuFlag(kCpuHasNEON)) {
1641 mFnCopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
1642 }
1643#endif
1644#if defined(HAS_COPYROW_MIPS)
1645 if (TestCpuFlag(kCpuHasMIPS)) {
1646 mFnCopyRow = CopyRow_MIPS;
1647 }
1648#endif
1649}
1650
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001651size_t HeicCompositeStream::calcAppSegmentMaxSize(const CameraMetadata& info) {
1652 camera_metadata_ro_entry_t entry = info.find(ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT);
1653 size_t maxAppsSegment = 1;
1654 if (entry.count > 0) {
1655 maxAppsSegment = entry.data.u8[0] < 1 ? 1 :
1656 entry.data.u8[0] > 16 ? 16 : entry.data.u8[0];
1657 }
Jayant Chowdharyc67af1b2022-04-07 18:05:04 +00001658 return maxAppsSegment * (2 + 0xFFFF) + sizeof(CameraBlob);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001659}
1660
Shuzhen Wang62f49ed2019-09-04 14:07:53 -07001661void HeicCompositeStream::updateCodecQualityLocked(int32_t quality) {
1662 if (quality != mQuality) {
1663 sp<AMessage> qualityParams = new AMessage;
1664 qualityParams->setInt32(PARAMETER_KEY_VIDEO_BITRATE, quality);
1665 status_t res = mCodec->setParameters(qualityParams);
1666 if (res != OK) {
1667 ALOGE("%s: Failed to set codec quality: %s (%d)",
1668 __FUNCTION__, strerror(-res), res);
1669 } else {
1670 mQuality = quality;
1671 }
1672 }
1673}
1674
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001675bool HeicCompositeStream::threadLoop() {
Shuzhen Wange8675782019-12-05 09:12:14 -08001676 int64_t frameNumber = -1;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001677 bool newInputAvailable = false;
1678
1679 {
1680 Mutex::Autolock l(mMutex);
1681 if (mErrorState) {
1682 // In case we landed in error state, return any pending buffers and
1683 // halt all further processing.
1684 compilePendingInputLocked();
Michael Gonzalezb5986a32019-10-09 15:38:17 -07001685 releaseInputFramesLocked();
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001686 return false;
1687 }
1688
1689
1690 while (!newInputAvailable) {
1691 compilePendingInputLocked();
Shuzhen Wange8675782019-12-05 09:12:14 -08001692 newInputAvailable = getNextReadyInputLocked(&frameNumber);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001693
1694 if (!newInputAvailable) {
Shuzhen Wange8675782019-12-05 09:12:14 -08001695 auto failingFrameNumber = getNextFailingInputLocked();
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001696 if (failingFrameNumber >= 0) {
Shuzhen Wange8675782019-12-05 09:12:14 -08001697 releaseInputFrameLocked(failingFrameNumber,
1698 &mPendingInputFrames[failingFrameNumber]);
1699
1700 // It's okay to remove the entry from mPendingInputFrames
1701 // because:
1702 // 1. Only one internal stream (main input) is critical in
1703 // backing the output stream.
1704 // 2. If captureResult/appSegment arrives after the entry is
1705 // removed, they are simply skipped.
1706 mPendingInputFrames.erase(failingFrameNumber);
1707 if (mPendingInputFrames.size() == 0) {
1708 markTrackerIdle();
1709 }
1710 return true;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001711 }
1712
1713 auto ret = mInputReadyCondition.waitRelative(mMutex, kWaitDuration);
1714 if (ret == TIMED_OUT) {
1715 return true;
1716 } else if (ret != OK) {
1717 ALOGE("%s: Timed wait on condition failed: %s (%d)", __FUNCTION__,
1718 strerror(-ret), ret);
1719 return false;
1720 }
1721 }
1722 }
1723 }
1724
Shuzhen Wange8675782019-12-05 09:12:14 -08001725 auto res = processInputFrame(frameNumber, mPendingInputFrames[frameNumber]);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001726 Mutex::Autolock l(mMutex);
1727 if (res != OK) {
Shuzhen Wange8675782019-12-05 09:12:14 -08001728 ALOGE("%s: Failed processing frame with timestamp: %" PRIu64 ", frameNumber: %"
1729 PRId64 ": %s (%d)", __FUNCTION__, mPendingInputFrames[frameNumber].timestamp,
1730 frameNumber, strerror(-res), res);
1731 mPendingInputFrames[frameNumber].error = true;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001732 }
1733
Michael Gonzalezb5986a32019-10-09 15:38:17 -07001734 releaseInputFramesLocked();
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001735
1736 return true;
1737}
1738
Shuzhen Wange8675782019-12-05 09:12:14 -08001739void HeicCompositeStream::flagAnExifErrorFrameNumber(int64_t frameNumber) {
1740 Mutex::Autolock l(mMutex);
1741 mExifErrorFrameNumbers.emplace(frameNumber);
1742 mInputReadyCondition.signal();
1743}
1744
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001745bool HeicCompositeStream::onStreamBufferError(const CaptureResultExtras& resultExtras) {
1746 bool res = false;
Shuzhen Wange8675782019-12-05 09:12:14 -08001747 int64_t frameNumber = resultExtras.frameNumber;
1748
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001749 // Buffer errors concerning internal composite streams should not be directly visible to
1750 // camera clients. They must only receive a single buffer error with the public composite
1751 // stream id.
Shuzhen Wange8675782019-12-05 09:12:14 -08001752 if (resultExtras.errorStreamId == mAppSegmentStreamId) {
1753 ALOGV("%s: APP_SEGMENT frameNumber: %" PRId64, __FUNCTION__, frameNumber);
1754 flagAnExifErrorFrameNumber(frameNumber);
1755 res = true;
1756 } else if (resultExtras.errorStreamId == mMainImageStreamId) {
1757 ALOGV("%s: YUV frameNumber: %" PRId64, __FUNCTION__, frameNumber);
1758 flagAnErrorFrameNumber(frameNumber);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001759 res = true;
1760 }
1761
1762 return res;
1763}
1764
Shuzhen Wange7f4b462019-02-12 08:43:07 -08001765void HeicCompositeStream::onResultError(const CaptureResultExtras& resultExtras) {
1766 // For result error, since the APPS_SEGMENT buffer already contains EXIF,
1767 // simply skip using the capture result metadata to override EXIF.
1768 Mutex::Autolock l(mMutex);
1769
1770 int64_t timestamp = -1;
Shuzhen Wange8675782019-12-05 09:12:14 -08001771 for (const auto& fn : mSettingsByFrameNumber) {
Shuzhen Wange7f4b462019-02-12 08:43:07 -08001772 if (fn.first == resultExtras.frameNumber) {
Shuzhen Wange8675782019-12-05 09:12:14 -08001773 timestamp = fn.second.timestamp;
Shuzhen Wange7f4b462019-02-12 08:43:07 -08001774 break;
1775 }
1776 }
1777 if (timestamp == -1) {
1778 for (const auto& inputFrame : mPendingInputFrames) {
Shuzhen Wange8675782019-12-05 09:12:14 -08001779 if (inputFrame.first == resultExtras.frameNumber) {
1780 timestamp = inputFrame.second.timestamp;
Shuzhen Wange7f4b462019-02-12 08:43:07 -08001781 break;
1782 }
1783 }
1784 }
1785
1786 if (timestamp == -1) {
1787 ALOGE("%s: Failed to find shutter timestamp for result error!", __FUNCTION__);
1788 return;
1789 }
1790
1791 mCaptureResults.emplace(timestamp, std::make_tuple(resultExtras.frameNumber, CameraMetadata()));
Shuzhen Wange8675782019-12-05 09:12:14 -08001792 ALOGV("%s: timestamp %" PRId64 ", frameNumber %" PRId64, __FUNCTION__,
1793 timestamp, resultExtras.frameNumber);
Shuzhen Wange7f4b462019-02-12 08:43:07 -08001794 mInputReadyCondition.signal();
1795}
1796
Shuzhen Wange8675782019-12-05 09:12:14 -08001797void HeicCompositeStream::onRequestError(const CaptureResultExtras& resultExtras) {
1798 auto frameNumber = resultExtras.frameNumber;
1799 ALOGV("%s: frameNumber: %" PRId64, __FUNCTION__, frameNumber);
1800 Mutex::Autolock l(mMutex);
1801 auto numRequests = mSettingsByFrameNumber.erase(frameNumber);
1802 if (numRequests == 0) {
1803 // Pending request has been populated into mPendingInputFrames
1804 mErrorFrameNumbers.emplace(frameNumber);
1805 mInputReadyCondition.signal();
1806 } else {
1807 // REQUEST_ERROR was received without onShutter.
1808 }
1809}
1810
1811void HeicCompositeStream::markTrackerIdle() {
1812 sp<StatusTracker> statusTracker = mStatusTracker.promote();
1813 if (statusTracker != nullptr) {
1814 statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE);
1815 ALOGV("%s: Mark component as idle", __FUNCTION__);
1816 }
1817}
1818
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001819void HeicCompositeStream::CodecCallbackHandler::onMessageReceived(const sp<AMessage> &msg) {
1820 sp<HeicCompositeStream> parent = mParent.promote();
1821 if (parent == nullptr) return;
1822
1823 switch (msg->what()) {
1824 case kWhatCallbackNotify: {
1825 int32_t cbID;
1826 if (!msg->findInt32("callbackID", &cbID)) {
1827 ALOGE("kWhatCallbackNotify: callbackID is expected.");
1828 break;
1829 }
1830
1831 ALOGV("kWhatCallbackNotify: cbID = %d", cbID);
1832
1833 switch (cbID) {
1834 case MediaCodec::CB_INPUT_AVAILABLE: {
1835 int32_t index;
1836 if (!msg->findInt32("index", &index)) {
1837 ALOGE("CB_INPUT_AVAILABLE: index is expected.");
1838 break;
1839 }
1840 parent->onHeicInputFrameAvailable(index);
1841 break;
1842 }
1843
1844 case MediaCodec::CB_OUTPUT_AVAILABLE: {
1845 int32_t index;
1846 size_t offset;
1847 size_t size;
1848 int64_t timeUs;
1849 int32_t flags;
1850
1851 if (!msg->findInt32("index", &index)) {
1852 ALOGE("CB_OUTPUT_AVAILABLE: index is expected.");
1853 break;
1854 }
1855 if (!msg->findSize("offset", &offset)) {
1856 ALOGE("CB_OUTPUT_AVAILABLE: offset is expected.");
1857 break;
1858 }
1859 if (!msg->findSize("size", &size)) {
1860 ALOGE("CB_OUTPUT_AVAILABLE: size is expected.");
1861 break;
1862 }
1863 if (!msg->findInt64("timeUs", &timeUs)) {
1864 ALOGE("CB_OUTPUT_AVAILABLE: timeUs is expected.");
1865 break;
1866 }
1867 if (!msg->findInt32("flags", &flags)) {
1868 ALOGE("CB_OUTPUT_AVAILABLE: flags is expected.");
1869 break;
1870 }
1871
1872 CodecOutputBufferInfo bufferInfo = {
1873 index,
1874 (int32_t)offset,
1875 (int32_t)size,
1876 timeUs,
1877 (uint32_t)flags};
1878
1879 parent->onHeicOutputFrameAvailable(bufferInfo);
1880 break;
1881 }
1882
1883 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED: {
1884 sp<AMessage> format;
1885 if (!msg->findMessage("format", &format)) {
1886 ALOGE("CB_OUTPUT_FORMAT_CHANGED: format is expected.");
1887 break;
1888 }
Chong Zhang860eff12019-09-16 16:15:00 -07001889 // Here format is MediaCodec's internal copy of output format.
1890 // Make a copy since onHeicFormatChanged() might modify it.
1891 sp<AMessage> formatCopy;
1892 if (format != nullptr) {
1893 formatCopy = format->dup();
1894 }
1895 parent->onHeicFormatChanged(formatCopy);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001896 break;
1897 }
1898
1899 case MediaCodec::CB_ERROR: {
1900 status_t err;
1901 int32_t actionCode;
1902 AString detail;
1903 if (!msg->findInt32("err", &err)) {
1904 ALOGE("CB_ERROR: err is expected.");
1905 break;
1906 }
1907 if (!msg->findInt32("action", &actionCode)) {
1908 ALOGE("CB_ERROR: action is expected.");
1909 break;
1910 }
1911 msg->findString("detail", &detail);
1912 ALOGE("Codec reported error(0x%x), actionCode(%d), detail(%s)",
1913 err, actionCode, detail.c_str());
1914
1915 parent->onHeicCodecError();
1916 break;
1917 }
1918
1919 default: {
1920 ALOGE("kWhatCallbackNotify: callbackID(%d) is unexpected.", cbID);
1921 break;
1922 }
1923 }
1924 break;
1925 }
1926
1927 default:
1928 ALOGE("shouldn't be here");
1929 break;
1930 }
1931}
1932
1933}; // namespace camera3
1934}; // namespace android