blob: 68e9ad427f93ea25291bcad94d63d88eb7d71536 [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);
Shuzhen Wang1403d952023-07-31 20:42:19 +0000455 }
456
457 if (mUseGrid || mUseHeic) {
458 int32_t gridRows, gridCols, tileWidth, tileHeight;
459 if (newFormat->findInt32(KEY_GRID_ROWS, &gridRows) &&
460 newFormat->findInt32(KEY_GRID_COLUMNS, &gridCols) &&
461 newFormat->findInt32(KEY_TILE_WIDTH, &tileWidth) &&
462 newFormat->findInt32(KEY_TILE_HEIGHT, &tileHeight)) {
463 mGridWidth = tileWidth;
464 mGridHeight = tileHeight;
465 mGridRows = gridRows;
466 mGridCols = gridCols;
467 } else {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800468 newFormat->setInt32(KEY_TILE_WIDTH, mGridWidth);
469 newFormat->setInt32(KEY_TILE_HEIGHT, mGridHeight);
470 newFormat->setInt32(KEY_GRID_ROWS, mGridRows);
471 newFormat->setInt32(KEY_GRID_COLUMNS, mGridCols);
Shuzhen Wang1403d952023-07-31 20:42:19 +0000472 }
473 int32_t left, top, right, bottom;
474 if (newFormat->findRect("crop", &left, &top, &right, &bottom)) {
475 newFormat->setRect("crop", 0, 0, mOutputWidth - 1, mOutputHeight - 1);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800476 }
477 }
478 newFormat->setInt32(KEY_IS_DEFAULT, 1 /*isPrimary*/);
479
480 int32_t gridRows, gridCols;
481 if (newFormat->findInt32(KEY_GRID_ROWS, &gridRows) &&
482 newFormat->findInt32(KEY_GRID_COLUMNS, &gridCols)) {
483 mNumOutputTiles = gridRows * gridCols;
484 } else {
485 mNumOutputTiles = 1;
486 }
487
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800488 mFormat = newFormat;
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700489
490 ALOGV("%s: mNumOutputTiles is %zu", __FUNCTION__, mNumOutputTiles);
491 mInputReadyCondition.signal();
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800492}
493
494void HeicCompositeStream::onHeicCodecError() {
495 Mutex::Autolock l(mMutex);
496 mErrorState = true;
497}
498
499status_t HeicCompositeStream::configureStream() {
500 if (isRunning()) {
501 // Processing thread is already running, nothing more to do.
502 return NO_ERROR;
503 }
504
505 if (mOutputSurface.get() == nullptr) {
506 ALOGE("%s: No valid output surface set!", __FUNCTION__);
507 return NO_INIT;
508 }
509
510 auto res = mOutputSurface->connect(NATIVE_WINDOW_API_CAMERA, mProducerListener);
511 if (res != OK) {
512 ALOGE("%s: Unable to connect to native window for stream %d",
513 __FUNCTION__, mMainImageStreamId);
514 return res;
515 }
516
517 if ((res = native_window_set_buffers_format(mOutputSurface.get(), HAL_PIXEL_FORMAT_BLOB))
518 != OK) {
519 ALOGE("%s: Unable to configure stream buffer format for stream %d", __FUNCTION__,
520 mMainImageStreamId);
521 return res;
522 }
523
524 ANativeWindow *anwConsumer = mOutputSurface.get();
525 int maxConsumerBuffers;
526 if ((res = anwConsumer->query(anwConsumer, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
527 &maxConsumerBuffers)) != OK) {
528 ALOGE("%s: Unable to query consumer undequeued"
529 " buffer count for stream %d", __FUNCTION__, mMainImageStreamId);
530 return res;
531 }
532
533 // Cannot use SourceSurface buffer count since it could be codec's 512*512 tile
534 // buffer count.
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800535 if ((res = native_window_set_buffer_count(
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700536 anwConsumer, kMaxOutputSurfaceProducerCount + maxConsumerBuffers)) != OK) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800537 ALOGE("%s: Unable to set buffer count for stream %d", __FUNCTION__, mMainImageStreamId);
538 return res;
539 }
540
541 if ((res = native_window_set_buffers_dimensions(anwConsumer, mMaxHeicBufferSize, 1)) != OK) {
542 ALOGE("%s: Unable to set buffer dimension %zu x 1 for stream %d: %s (%d)",
543 __FUNCTION__, mMaxHeicBufferSize, mMainImageStreamId, strerror(-res), res);
544 return res;
545 }
546
Shuzhen Wange8675782019-12-05 09:12:14 -0800547 sp<camera3::StatusTracker> statusTracker = mStatusTracker.promote();
548 if (statusTracker != nullptr) {
Yin-Chia Yeh87b3ec02019-06-03 10:44:39 -0700549 std::string name = std::string("HeicStream ") + std::to_string(getStreamId());
550 mStatusId = statusTracker->addComponent(name);
Shuzhen Wange8675782019-12-05 09:12:14 -0800551 }
552
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800553 run("HeicCompositeStreamProc");
554
555 return NO_ERROR;
556}
557
558status_t HeicCompositeStream::insertGbp(SurfaceMap* /*out*/outSurfaceMap,
559 Vector<int32_t>* /*out*/outputStreamIds, int32_t* /*out*/currentStreamId) {
560 if (outSurfaceMap->find(mAppSegmentStreamId) == outSurfaceMap->end()) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800561 outputStreamIds->push_back(mAppSegmentStreamId);
562 }
563 (*outSurfaceMap)[mAppSegmentStreamId].push_back(mAppSegmentSurfaceId);
564
565 if (outSurfaceMap->find(mMainImageStreamId) == outSurfaceMap->end()) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800566 outputStreamIds->push_back(mMainImageStreamId);
567 }
568 (*outSurfaceMap)[mMainImageStreamId].push_back(mMainImageSurfaceId);
569
570 if (currentStreamId != nullptr) {
571 *currentStreamId = mMainImageStreamId;
572 }
573
574 return NO_ERROR;
575}
576
Emilian Peev4697b642019-11-19 17:11:14 -0800577status_t HeicCompositeStream::insertCompositeStreamIds(
578 std::vector<int32_t>* compositeStreamIds /*out*/) {
579 if (compositeStreamIds == nullptr) {
580 return BAD_VALUE;
581 }
582
583 compositeStreamIds->push_back(mAppSegmentStreamId);
584 compositeStreamIds->push_back(mMainImageStreamId);
585
586 return OK;
587}
588
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800589void HeicCompositeStream::onShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) {
590 Mutex::Autolock l(mMutex);
591 if (mErrorState) {
592 return;
593 }
594
595 if (mSettingsByFrameNumber.find(resultExtras.frameNumber) != mSettingsByFrameNumber.end()) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800596 ALOGV("%s: [%" PRId64 "]: timestamp %" PRId64 ", requestId %d", __FUNCTION__,
597 resultExtras.frameNumber, timestamp, resultExtras.requestId);
598 mSettingsByFrameNumber[resultExtras.frameNumber].shutterNotified = true;
599 mSettingsByFrameNumber[resultExtras.frameNumber].timestamp = timestamp;
600 mSettingsByFrameNumber[resultExtras.frameNumber].requestId = resultExtras.requestId;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800601 mInputReadyCondition.signal();
602 }
603}
604
605void HeicCompositeStream::compilePendingInputLocked() {
Shuzhen Wange8675782019-12-05 09:12:14 -0800606 auto i = mSettingsByFrameNumber.begin();
607 while (i != mSettingsByFrameNumber.end()) {
608 if (i->second.shutterNotified) {
609 mPendingInputFrames[i->first].orientation = i->second.orientation;
610 mPendingInputFrames[i->first].quality = i->second.quality;
611 mPendingInputFrames[i->first].timestamp = i->second.timestamp;
612 mPendingInputFrames[i->first].requestId = i->second.requestId;
613 ALOGV("%s: [%" PRId64 "]: timestamp is %" PRId64, __FUNCTION__,
614 i->first, i->second.timestamp);
615 i = mSettingsByFrameNumber.erase(i);
Shuzhen Wang62f49ed2019-09-04 14:07:53 -0700616
Shuzhen Wange8675782019-12-05 09:12:14 -0800617 // Set encoder quality if no inflight encoding
618 if (mPendingInputFrames.size() == 1) {
619 sp<StatusTracker> statusTracker = mStatusTracker.promote();
620 if (statusTracker != nullptr) {
621 statusTracker->markComponentActive(mStatusId);
622 ALOGV("%s: Mark component as active", __FUNCTION__);
623 }
624
625 int32_t newQuality = mPendingInputFrames.begin()->second.quality;
626 updateCodecQualityLocked(newQuality);
627 }
628 } else {
629 i++;
Shuzhen Wang62f49ed2019-09-04 14:07:53 -0700630 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800631 }
632
Shuzhen Wange8675782019-12-05 09:12:14 -0800633 while (!mInputAppSegmentBuffers.empty() && mAppSegmentFrameNumbers.size() > 0) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800634 CpuConsumer::LockedBuffer imgBuffer;
635 auto it = mInputAppSegmentBuffers.begin();
636 auto res = mAppSegmentConsumer->lockNextBuffer(&imgBuffer);
637 if (res == NOT_ENOUGH_DATA) {
Michael Gonzalezb5986a32019-10-09 15:38:17 -0700638 // Can not lock any more buffers.
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800639 break;
640 } else if ((res != OK) || (*it != imgBuffer.timestamp)) {
641 if (res != OK) {
642 ALOGE("%s: Error locking JPEG_APP_SEGMENTS image buffer: %s (%d)", __FUNCTION__,
643 strerror(-res), res);
644 } else {
645 ALOGE("%s: Expecting JPEG_APP_SEGMENTS buffer with time stamp: %" PRId64
646 " received buffer with time stamp: %" PRId64, __FUNCTION__,
647 *it, imgBuffer.timestamp);
Michael Gonzalezb5986a32019-10-09 15:38:17 -0700648 mAppSegmentConsumer->unlockBuffer(imgBuffer);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800649 }
650 mPendingInputFrames[*it].error = true;
651 mInputAppSegmentBuffers.erase(it);
652 continue;
653 }
654
Shuzhen Wange8675782019-12-05 09:12:14 -0800655 if (mPendingInputFrames.find(mAppSegmentFrameNumbers.front()) == mPendingInputFrames.end()) {
656 ALOGE("%s: mPendingInputFrames doesn't contain frameNumber %" PRId64, __FUNCTION__,
657 mAppSegmentFrameNumbers.front());
Shuzhen Wang991b7b62020-06-17 11:39:11 -0700658 mInputAppSegmentBuffers.erase(it);
659 mAppSegmentFrameNumbers.pop();
Shuzhen Wange8675782019-12-05 09:12:14 -0800660 continue;
661 }
662
663 int64_t frameNumber = mAppSegmentFrameNumbers.front();
664 // If mPendingInputFrames doesn't contain the expected frame number, the captured
665 // input app segment frame must have been dropped via a buffer error. Simply
666 // return the buffer to the buffer queue.
667 if ((mPendingInputFrames.find(frameNumber) == mPendingInputFrames.end()) ||
668 (mPendingInputFrames[frameNumber].error)) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800669 mAppSegmentConsumer->unlockBuffer(imgBuffer);
670 } else {
Shuzhen Wange8675782019-12-05 09:12:14 -0800671 mPendingInputFrames[frameNumber].appSegmentBuffer = imgBuffer;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800672 }
673 mInputAppSegmentBuffers.erase(it);
Shuzhen Wange8675782019-12-05 09:12:14 -0800674 mAppSegmentFrameNumbers.pop();
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800675 }
676
Shuzhen Wange8675782019-12-05 09:12:14 -0800677 while (!mInputYuvBuffers.empty() && !mYuvBufferAcquired && mMainImageFrameNumbers.size() > 0) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800678 CpuConsumer::LockedBuffer imgBuffer;
679 auto it = mInputYuvBuffers.begin();
680 auto res = mMainImageConsumer->lockNextBuffer(&imgBuffer);
681 if (res == NOT_ENOUGH_DATA) {
Michael Gonzalezb5986a32019-10-09 15:38:17 -0700682 // Can not lock any more buffers.
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800683 break;
684 } else if (res != OK) {
685 ALOGE("%s: Error locking YUV_888 image buffer: %s (%d)", __FUNCTION__,
686 strerror(-res), res);
687 mPendingInputFrames[*it].error = true;
688 mInputYuvBuffers.erase(it);
689 continue;
690 } else if (*it != imgBuffer.timestamp) {
691 ALOGW("%s: Expecting YUV_888 buffer with time stamp: %" PRId64 " received buffer with "
692 "time stamp: %" PRId64, __FUNCTION__, *it, imgBuffer.timestamp);
693 mPendingInputFrames[*it].error = true;
694 mInputYuvBuffers.erase(it);
695 continue;
696 }
697
Shuzhen Wange8675782019-12-05 09:12:14 -0800698 if (mPendingInputFrames.find(mMainImageFrameNumbers.front()) == mPendingInputFrames.end()) {
699 ALOGE("%s: mPendingInputFrames doesn't contain frameNumber %" PRId64, __FUNCTION__,
700 mMainImageFrameNumbers.front());
701 mInputYuvBuffers.erase(it);
Shuzhen Wang991b7b62020-06-17 11:39:11 -0700702 mMainImageFrameNumbers.pop();
Shuzhen Wange8675782019-12-05 09:12:14 -0800703 continue;
704 }
705
706 int64_t frameNumber = mMainImageFrameNumbers.front();
707 // If mPendingInputFrames doesn't contain the expected frame number, the captured
708 // input main image must have been dropped via a buffer error. Simply
709 // return the buffer to the buffer queue.
710 if ((mPendingInputFrames.find(frameNumber) == mPendingInputFrames.end()) ||
711 (mPendingInputFrames[frameNumber].error)) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800712 mMainImageConsumer->unlockBuffer(imgBuffer);
713 } else {
Shuzhen Wange8675782019-12-05 09:12:14 -0800714 mPendingInputFrames[frameNumber].yuvBuffer = imgBuffer;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800715 mYuvBufferAcquired = true;
716 }
717 mInputYuvBuffers.erase(it);
Shuzhen Wange8675782019-12-05 09:12:14 -0800718 mMainImageFrameNumbers.pop();
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800719 }
720
721 while (!mCodecOutputBuffers.empty()) {
722 auto it = mCodecOutputBuffers.begin();
Shuzhen Wange8675782019-12-05 09:12:14 -0800723 // Assume encoder input to output is FIFO, use a queue to look up
724 // frameNumber when handling codec outputs.
725 int64_t bufferFrameNumber = -1;
726 if (mCodecOutputBufferFrameNumbers.empty()) {
727 ALOGV("%s: Failed to find buffer frameNumber for codec output buffer!", __FUNCTION__);
Michael Gonzalez5c103f22019-10-08 14:30:32 -0700728 break;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800729 } else {
Shuzhen Wange8675782019-12-05 09:12:14 -0800730 // Direct mapping between camera frame number and codec timestamp (in us).
731 bufferFrameNumber = mCodecOutputBufferFrameNumbers.front();
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700732 mCodecOutputCounter++;
733 if (mCodecOutputCounter == mNumOutputTiles) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800734 mCodecOutputBufferFrameNumbers.pop();
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700735 mCodecOutputCounter = 0;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800736 }
737
Shuzhen Wange8675782019-12-05 09:12:14 -0800738 mPendingInputFrames[bufferFrameNumber].codecOutputBuffers.push_back(*it);
739 ALOGV("%s: [%" PRId64 "]: Pushing codecOutputBuffers (frameNumber %" PRId64 ")",
740 __FUNCTION__, bufferFrameNumber, it->timeUs);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800741 }
742 mCodecOutputBuffers.erase(it);
743 }
744
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800745 while (!mCaptureResults.empty()) {
746 auto it = mCaptureResults.begin();
Shuzhen Wange8675782019-12-05 09:12:14 -0800747 // Negative frame number indicates that something went wrong during the capture result
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800748 // collection process.
Shuzhen Wange8675782019-12-05 09:12:14 -0800749 int64_t frameNumber = std::get<0>(it->second);
750 if (it->first >= 0 &&
751 mPendingInputFrames.find(frameNumber) != mPendingInputFrames.end()) {
752 if (mPendingInputFrames[frameNumber].timestamp == it->first) {
753 mPendingInputFrames[frameNumber].result =
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800754 std::make_unique<CameraMetadata>(std::get<1>(it->second));
755 } else {
756 ALOGE("%s: Capture result frameNumber/timestamp mapping changed between "
Shuzhen Wange8675782019-12-05 09:12:14 -0800757 "shutter and capture result! before: %" PRId64 ", after: %" PRId64,
758 __FUNCTION__, mPendingInputFrames[frameNumber].timestamp,
759 it->first);
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800760 }
761 }
762 mCaptureResults.erase(it);
763 }
764
765 // mErrorFrameNumbers stores frame number of dropped buffers.
766 auto it = mErrorFrameNumbers.begin();
767 while (it != mErrorFrameNumbers.end()) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800768 if (mPendingInputFrames.find(*it) != mPendingInputFrames.end()) {
769 mPendingInputFrames[*it].error = true;
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800770 } else {
Shuzhen Wange8675782019-12-05 09:12:14 -0800771 //Error callback is guaranteed to arrive after shutter notify, which
772 //results in mPendingInputFrames being populated.
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800773 ALOGW("%s: Not able to find failing input with frame number: %" PRId64, __FUNCTION__,
774 *it);
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800775 }
Shuzhen Wange8675782019-12-05 09:12:14 -0800776 it = mErrorFrameNumbers.erase(it);
777 }
778
779 // mExifErrorFrameNumbers stores the frame number of dropped APP_SEGMENT buffers
780 it = mExifErrorFrameNumbers.begin();
781 while (it != mExifErrorFrameNumbers.end()) {
782 if (mPendingInputFrames.find(*it) != mPendingInputFrames.end()) {
783 mPendingInputFrames[*it].exifError = true;
784 }
785 it = mExifErrorFrameNumbers.erase(it);
Shuzhen Wange7f4b462019-02-12 08:43:07 -0800786 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800787
788 // Distribute codec input buffers to be filled out from YUV output
789 for (auto it = mPendingInputFrames.begin();
790 it != mPendingInputFrames.end() && mCodecInputBuffers.size() > 0; it++) {
791 InputFrame& inputFrame(it->second);
792 if (inputFrame.codecInputCounter < mGridRows * mGridCols) {
793 // Available input tiles that are required for the current input
794 // image.
795 size_t newInputTiles = std::min(mCodecInputBuffers.size(),
796 mGridRows * mGridCols - inputFrame.codecInputCounter);
797 for (size_t i = 0; i < newInputTiles; i++) {
798 CodecInputBufferInfo inputInfo =
799 { mCodecInputBuffers[0], mGridTimestampUs++, inputFrame.codecInputCounter };
800 inputFrame.codecInputBuffers.push_back(inputInfo);
801
802 mCodecInputBuffers.erase(mCodecInputBuffers.begin());
803 inputFrame.codecInputCounter++;
804 }
805 break;
806 }
807 }
808}
809
Shuzhen Wange8675782019-12-05 09:12:14 -0800810bool HeicCompositeStream::getNextReadyInputLocked(int64_t *frameNumber /*out*/) {
811 if (frameNumber == nullptr) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800812 return false;
813 }
814
815 bool newInputAvailable = false;
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700816 for (auto& it : mPendingInputFrames) {
817 // New input is considered to be available only if:
818 // 1. input buffers are ready, or
819 // 2. App segment and muxer is created, or
820 // 3. A codec output tile is ready, and an output buffer is available.
821 // This makes sure that muxer gets created only when an output tile is
822 // generated, because right now we only handle 1 HEIC output buffer at a
823 // time (max dequeued buffer count is 1).
Shuzhen Wange8675782019-12-05 09:12:14 -0800824 bool appSegmentReady =
825 (it.second.appSegmentBuffer.data != nullptr || it.second.exifError) &&
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700826 !it.second.appSegmentWritten && it.second.result != nullptr &&
827 it.second.muxer != nullptr;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800828 bool codecOutputReady = !it.second.codecOutputBuffers.empty();
829 bool codecInputReady = (it.second.yuvBuffer.data != nullptr) &&
830 (!it.second.codecInputBuffers.empty());
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700831 bool hasOutputBuffer = it.second.muxer != nullptr ||
832 (mDequeuedOutputBufferCnt < kMaxOutputSurfaceProducerCount);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800833 if ((!it.second.error) &&
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700834 (appSegmentReady || (codecOutputReady && hasOutputBuffer) || codecInputReady)) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800835 *frameNumber = it.first;
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700836 if (it.second.format == nullptr && mFormat != nullptr) {
837 it.second.format = mFormat->dup();
838 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800839 newInputAvailable = true;
840 break;
841 }
842 }
843
844 return newInputAvailable;
845}
846
Shuzhen Wange8675782019-12-05 09:12:14 -0800847int64_t HeicCompositeStream::getNextFailingInputLocked() {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800848 int64_t res = -1;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800849
850 for (const auto& it : mPendingInputFrames) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800851 if (it.second.error) {
852 res = it.first;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800853 break;
854 }
855 }
856
857 return res;
858}
859
Shuzhen Wange8675782019-12-05 09:12:14 -0800860status_t HeicCompositeStream::processInputFrame(int64_t frameNumber,
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800861 InputFrame &inputFrame) {
862 ATRACE_CALL();
863 status_t res = OK;
864
Shuzhen Wange8675782019-12-05 09:12:14 -0800865 bool appSegmentReady =
866 (inputFrame.appSegmentBuffer.data != nullptr || inputFrame.exifError) &&
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700867 !inputFrame.appSegmentWritten && inputFrame.result != nullptr &&
868 inputFrame.muxer != nullptr;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800869 bool codecOutputReady = inputFrame.codecOutputBuffers.size() > 0;
870 bool codecInputReady = inputFrame.yuvBuffer.data != nullptr &&
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700871 !inputFrame.codecInputBuffers.empty();
872 bool hasOutputBuffer = inputFrame.muxer != nullptr ||
873 (mDequeuedOutputBufferCnt < kMaxOutputSurfaceProducerCount);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800874
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700875 ALOGV("%s: [%" PRId64 "]: appSegmentReady %d, codecOutputReady %d, codecInputReady %d,"
Shuzhen Wange8675782019-12-05 09:12:14 -0800876 " dequeuedOutputBuffer %d, timestamp %" PRId64, __FUNCTION__, frameNumber,
877 appSegmentReady, codecOutputReady, codecInputReady, mDequeuedOutputBufferCnt,
878 inputFrame.timestamp);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800879
880 // Handle inputs for Hevc tiling
881 if (codecInputReady) {
882 res = processCodecInputFrame(inputFrame);
883 if (res != OK) {
884 ALOGE("%s: Failed to process codec input frame: %s (%d)", __FUNCTION__,
885 strerror(-res), res);
886 return res;
887 }
888 }
889
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700890 if (!(codecOutputReady && hasOutputBuffer) && !appSegmentReady) {
891 return OK;
892 }
893
894 // Initialize and start muxer if not yet done so. In this case,
895 // codecOutputReady must be true. Otherwise, appSegmentReady is guaranteed
896 // to be false, and the function must have returned early.
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800897 if (inputFrame.muxer == nullptr) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800898 res = startMuxerForInputFrame(frameNumber, inputFrame);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800899 if (res != OK) {
900 ALOGE("%s: Failed to create and start muxer: %s (%d)", __FUNCTION__,
901 strerror(-res), res);
902 return res;
903 }
904 }
905
906 // Write JPEG APP segments data to the muxer.
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700907 if (appSegmentReady) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800908 res = processAppSegment(frameNumber, inputFrame);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800909 if (res != OK) {
910 ALOGE("%s: Failed to process JPEG APP segments: %s (%d)", __FUNCTION__,
911 strerror(-res), res);
912 return res;
913 }
914 }
915
916 // Write media codec bitstream buffers to muxer.
917 while (!inputFrame.codecOutputBuffers.empty()) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800918 res = processOneCodecOutputFrame(frameNumber, inputFrame);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800919 if (res != OK) {
920 ALOGE("%s: Failed to process codec output frame: %s (%d)", __FUNCTION__,
921 strerror(-res), res);
922 return res;
923 }
924 }
925
Michael Gonzalezb5986a32019-10-09 15:38:17 -0700926 if (inputFrame.pendingOutputTiles == 0) {
927 if (inputFrame.appSegmentWritten) {
Shuzhen Wange8675782019-12-05 09:12:14 -0800928 res = processCompletedInputFrame(frameNumber, inputFrame);
Michael Gonzalezb5986a32019-10-09 15:38:17 -0700929 if (res != OK) {
930 ALOGE("%s: Failed to process completed input frame: %s (%d)", __FUNCTION__,
931 strerror(-res), res);
932 return res;
933 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800934 }
935 }
936
937 return res;
938}
939
Shuzhen Wange8675782019-12-05 09:12:14 -0800940status_t HeicCompositeStream::startMuxerForInputFrame(int64_t frameNumber, InputFrame &inputFrame) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800941 sp<ANativeWindow> outputANW = mOutputSurface;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800942
943 auto res = outputANW->dequeueBuffer(mOutputSurface.get(), &inputFrame.anb, &inputFrame.fenceFd);
944 if (res != OK) {
945 ALOGE("%s: Error retrieving output buffer: %s (%d)", __FUNCTION__, strerror(-res),
946 res);
947 return res;
948 }
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700949 mDequeuedOutputBufferCnt++;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800950
951 // Combine current thread id, stream id and timestamp to uniquely identify image.
952 std::ostringstream tempOutputFile;
953 tempOutputFile << "HEIF-" << pthread_self() << "-"
Shuzhen Wange8675782019-12-05 09:12:14 -0800954 << getStreamId() << "-" << frameNumber;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800955 inputFrame.fileFd = syscall(__NR_memfd_create, tempOutputFile.str().c_str(), MFD_CLOEXEC);
956 if (inputFrame.fileFd < 0) {
957 ALOGE("%s: Failed to create file %s. Error no is %d", __FUNCTION__,
958 tempOutputFile.str().c_str(), errno);
959 return NO_INIT;
960 }
Manisha Jajoo022b52f2021-10-09 00:51:42 +0530961 inputFrame.muxer = MediaMuxer::create(inputFrame.fileFd, MediaMuxer::OUTPUT_FORMAT_HEIF);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800962 if (inputFrame.muxer == nullptr) {
963 ALOGE("%s: Failed to create MediaMuxer for file fd %d",
964 __FUNCTION__, inputFrame.fileFd);
965 return NO_INIT;
966 }
967
968 res = inputFrame.muxer->setOrientationHint(inputFrame.orientation);
969 if (res != OK) {
970 ALOGE("%s: Failed to setOrientationHint: %s (%d)", __FUNCTION__,
971 strerror(-res), res);
972 return res;
973 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800974
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700975 ssize_t trackId = inputFrame.muxer->addTrack(inputFrame.format);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800976 if (trackId < 0) {
977 ALOGE("%s: Failed to addTrack to the muxer: %zd", __FUNCTION__, trackId);
978 return NO_INIT;
979 }
980
981 inputFrame.trackIndex = trackId;
982 inputFrame.pendingOutputTiles = mNumOutputTiles;
983
984 res = inputFrame.muxer->start();
985 if (res != OK) {
986 ALOGE("%s: Failed to start MediaMuxer: %s (%d)",
987 __FUNCTION__, strerror(-res), res);
988 return res;
989 }
990
Shuzhen Wang3d00ee52019-09-25 14:19:28 -0700991 ALOGV("%s: [%" PRId64 "]: Muxer started for inputFrame", __FUNCTION__,
Shuzhen Wange8675782019-12-05 09:12:14 -0800992 frameNumber);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800993 return OK;
994}
995
Shuzhen Wange8675782019-12-05 09:12:14 -0800996status_t HeicCompositeStream::processAppSegment(int64_t frameNumber, InputFrame &inputFrame) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800997 size_t app1Size = 0;
Shuzhen Wange8675782019-12-05 09:12:14 -0800998 size_t appSegmentSize = 0;
999 if (!inputFrame.exifError) {
1000 appSegmentSize = findAppSegmentsSize(inputFrame.appSegmentBuffer.data,
1001 inputFrame.appSegmentBuffer.width * inputFrame.appSegmentBuffer.height,
1002 &app1Size);
1003 if (appSegmentSize == 0) {
1004 ALOGE("%s: Failed to find JPEG APP segment size", __FUNCTION__);
1005 return NO_INIT;
1006 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001007 }
1008
1009 std::unique_ptr<ExifUtils> exifUtils(ExifUtils::create());
Shuzhen Wange8675782019-12-05 09:12:14 -08001010 auto exifRes = inputFrame.exifError ?
1011 exifUtils->initializeEmpty() :
1012 exifUtils->initialize(inputFrame.appSegmentBuffer.data, app1Size);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001013 if (!exifRes) {
1014 ALOGE("%s: Failed to initialize ExifUtils object!", __FUNCTION__);
1015 return BAD_VALUE;
1016 }
Shuzhen Wange7f4b462019-02-12 08:43:07 -08001017 exifRes = exifUtils->setFromMetadata(*inputFrame.result, mStaticInfo,
1018 mOutputWidth, mOutputHeight);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001019 if (!exifRes) {
1020 ALOGE("%s: Failed to set Exif tags using metadata and main image sizes", __FUNCTION__);
1021 return BAD_VALUE;
1022 }
1023 exifRes = exifUtils->setOrientation(inputFrame.orientation);
1024 if (!exifRes) {
1025 ALOGE("%s: ExifUtils failed to set orientation", __FUNCTION__);
1026 return BAD_VALUE;
1027 }
1028 exifRes = exifUtils->generateApp1();
1029 if (!exifRes) {
1030 ALOGE("%s: ExifUtils failed to generate APP1 segment", __FUNCTION__);
1031 return BAD_VALUE;
1032 }
1033
1034 unsigned int newApp1Length = exifUtils->getApp1Length();
1035 const uint8_t *newApp1Segment = exifUtils->getApp1Buffer();
1036
1037 //Assemble the APP1 marker buffer required by MediaCodec
1038 uint8_t kExifApp1Marker[] = {'E', 'x', 'i', 'f', 0xFF, 0xE1, 0x00, 0x00};
1039 kExifApp1Marker[6] = static_cast<uint8_t>(newApp1Length >> 8);
1040 kExifApp1Marker[7] = static_cast<uint8_t>(newApp1Length & 0xFF);
1041 size_t appSegmentBufferSize = sizeof(kExifApp1Marker) +
1042 appSegmentSize - app1Size + newApp1Length;
1043 uint8_t* appSegmentBuffer = new uint8_t[appSegmentBufferSize];
1044 memcpy(appSegmentBuffer, kExifApp1Marker, sizeof(kExifApp1Marker));
1045 memcpy(appSegmentBuffer + sizeof(kExifApp1Marker), newApp1Segment, newApp1Length);
1046 if (appSegmentSize - app1Size > 0) {
1047 memcpy(appSegmentBuffer + sizeof(kExifApp1Marker) + newApp1Length,
1048 inputFrame.appSegmentBuffer.data + app1Size, appSegmentSize - app1Size);
1049 }
1050
1051 sp<ABuffer> aBuffer = new ABuffer(appSegmentBuffer, appSegmentBufferSize);
1052 auto res = inputFrame.muxer->writeSampleData(aBuffer, inputFrame.trackIndex,
Shuzhen Wange8675782019-12-05 09:12:14 -08001053 inputFrame.timestamp, MediaCodec::BUFFER_FLAG_MUXER_DATA);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001054 delete[] appSegmentBuffer;
1055
1056 if (res != OK) {
1057 ALOGE("%s: Failed to write JPEG APP segments to muxer: %s (%d)",
1058 __FUNCTION__, strerror(-res), res);
1059 return res;
1060 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001061
Shuzhen Wang3d00ee52019-09-25 14:19:28 -07001062 ALOGV("%s: [%" PRId64 "]: appSegmentSize is %zu, width %d, height %d, app1Size %zu",
Shuzhen Wange8675782019-12-05 09:12:14 -08001063 __FUNCTION__, frameNumber, appSegmentSize, inputFrame.appSegmentBuffer.width,
Shuzhen Wang3d00ee52019-09-25 14:19:28 -07001064 inputFrame.appSegmentBuffer.height, app1Size);
Michael Gonzalezb5986a32019-10-09 15:38:17 -07001065
1066 inputFrame.appSegmentWritten = true;
1067 // Release the buffer now so any pending input app segments can be processed
1068 mAppSegmentConsumer->unlockBuffer(inputFrame.appSegmentBuffer);
1069 inputFrame.appSegmentBuffer.data = nullptr;
Shuzhen Wange8675782019-12-05 09:12:14 -08001070 inputFrame.exifError = false;
Michael Gonzalezb5986a32019-10-09 15:38:17 -07001071
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001072 return OK;
1073}
1074
1075status_t HeicCompositeStream::processCodecInputFrame(InputFrame &inputFrame) {
1076 for (auto& inputBuffer : inputFrame.codecInputBuffers) {
1077 sp<MediaCodecBuffer> buffer;
1078 auto res = mCodec->getInputBuffer(inputBuffer.index, &buffer);
1079 if (res != OK) {
1080 ALOGE("%s: Error getting codec input buffer: %s (%d)", __FUNCTION__,
1081 strerror(-res), res);
1082 return res;
1083 }
1084
1085 // Copy one tile from source to destination.
1086 size_t tileX = inputBuffer.tileIndex % mGridCols;
1087 size_t tileY = inputBuffer.tileIndex / mGridCols;
1088 size_t top = mGridHeight * tileY;
1089 size_t left = mGridWidth * tileX;
1090 size_t width = (tileX == static_cast<size_t>(mGridCols) - 1) ?
1091 mOutputWidth - tileX * mGridWidth : mGridWidth;
1092 size_t height = (tileY == static_cast<size_t>(mGridRows) - 1) ?
1093 mOutputHeight - tileY * mGridHeight : mGridHeight;
Shuzhen Wang3d00ee52019-09-25 14:19:28 -07001094 ALOGV("%s: inputBuffer tileIndex [%zu, %zu], top %zu, left %zu, width %zu, height %zu,"
1095 " timeUs %" PRId64, __FUNCTION__, tileX, tileY, top, left, width, height,
1096 inputBuffer.timeUs);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001097
1098 res = copyOneYuvTile(buffer, inputFrame.yuvBuffer, top, left, width, height);
1099 if (res != OK) {
1100 ALOGE("%s: Failed to copy YUV tile %s (%d)", __FUNCTION__,
1101 strerror(-res), res);
1102 return res;
1103 }
1104
1105 res = mCodec->queueInputBuffer(inputBuffer.index, 0, buffer->capacity(),
1106 inputBuffer.timeUs, 0, nullptr /*errorDetailMsg*/);
1107 if (res != OK) {
1108 ALOGE("%s: Failed to queueInputBuffer to Codec: %s (%d)",
1109 __FUNCTION__, strerror(-res), res);
1110 return res;
1111 }
1112 }
1113
1114 inputFrame.codecInputBuffers.clear();
1115 return OK;
1116}
1117
Shuzhen Wange8675782019-12-05 09:12:14 -08001118status_t HeicCompositeStream::processOneCodecOutputFrame(int64_t frameNumber,
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001119 InputFrame &inputFrame) {
1120 auto it = inputFrame.codecOutputBuffers.begin();
1121 sp<MediaCodecBuffer> buffer;
1122 status_t res = mCodec->getOutputBuffer(it->index, &buffer);
1123 if (res != OK) {
1124 ALOGE("%s: Error getting Heic codec output buffer at index %d: %s (%d)",
1125 __FUNCTION__, it->index, strerror(-res), res);
1126 return res;
1127 }
1128 if (buffer == nullptr) {
1129 ALOGE("%s: Invalid Heic codec output buffer at index %d",
1130 __FUNCTION__, it->index);
1131 return BAD_VALUE;
1132 }
1133
1134 sp<ABuffer> aBuffer = new ABuffer(buffer->data(), buffer->size());
1135 res = inputFrame.muxer->writeSampleData(
Shuzhen Wange8675782019-12-05 09:12:14 -08001136 aBuffer, inputFrame.trackIndex, inputFrame.timestamp, 0 /*flags*/);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001137 if (res != OK) {
1138 ALOGE("%s: Failed to write buffer index %d to muxer: %s (%d)",
1139 __FUNCTION__, it->index, strerror(-res), res);
1140 return res;
1141 }
1142
1143 mCodec->releaseOutputBuffer(it->index);
1144 if (inputFrame.pendingOutputTiles == 0) {
1145 ALOGW("%s: Codec generated more tiles than expected!", __FUNCTION__);
1146 } else {
1147 inputFrame.pendingOutputTiles--;
1148 }
1149
1150 inputFrame.codecOutputBuffers.erase(inputFrame.codecOutputBuffers.begin());
Shuzhen Wang3d00ee52019-09-25 14:19:28 -07001151
1152 ALOGV("%s: [%" PRId64 "]: Output buffer index %d",
Shuzhen Wange8675782019-12-05 09:12:14 -08001153 __FUNCTION__, frameNumber, it->index);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001154 return OK;
1155}
1156
Shuzhen Wange8675782019-12-05 09:12:14 -08001157status_t HeicCompositeStream::processCompletedInputFrame(int64_t frameNumber,
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001158 InputFrame &inputFrame) {
1159 sp<ANativeWindow> outputANW = mOutputSurface;
1160 inputFrame.muxer->stop();
1161
1162 // Copy the content of the file to memory.
1163 sp<GraphicBuffer> gb = GraphicBuffer::from(inputFrame.anb);
1164 void* dstBuffer;
Shuzhen Wangc87315d2022-03-17 00:11:20 +00001165 GraphicBufferLocker gbLocker(gb);
1166 auto res = gbLocker.lockAsync(&dstBuffer, inputFrame.fenceFd);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001167 if (res != OK) {
1168 ALOGE("%s: Error trying to lock output buffer fence: %s (%d)", __FUNCTION__,
1169 strerror(-res), res);
1170 return res;
1171 }
1172
1173 off_t fSize = lseek(inputFrame.fileFd, 0, SEEK_END);
1174 if (static_cast<size_t>(fSize) > mMaxHeicBufferSize - sizeof(CameraBlob)) {
1175 ALOGE("%s: Error: MediaMuxer output size %ld is larger than buffer sizer %zu",
1176 __FUNCTION__, fSize, mMaxHeicBufferSize - sizeof(CameraBlob));
1177 return BAD_VALUE;
1178 }
1179
1180 lseek(inputFrame.fileFd, 0, SEEK_SET);
1181 ssize_t bytesRead = read(inputFrame.fileFd, dstBuffer, fSize);
1182 if (bytesRead < fSize) {
1183 ALOGE("%s: Only %zd of %ld bytes read", __FUNCTION__, bytesRead, fSize);
1184 return BAD_VALUE;
1185 }
1186
1187 close(inputFrame.fileFd);
1188 inputFrame.fileFd = -1;
1189
1190 // Fill in HEIC header
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001191 // Must be in sync with CAMERA3_HEIC_BLOB_ID in android_media_Utils.cpp
Shuzhen Wangdc519092022-12-02 12:29:04 -08001192 uint8_t *header = static_cast<uint8_t*>(dstBuffer) + mMaxHeicBufferSize - sizeof(CameraBlob);
1193 CameraBlob blobHeader = {
1194 .blobId = static_cast<CameraBlobId>(0x00FE),
1195 .blobSizeBytes = static_cast<int32_t>(fSize)
1196 };
1197 memcpy(header, &blobHeader, sizeof(CameraBlob));
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001198
Shuzhen Wange8675782019-12-05 09:12:14 -08001199 res = native_window_set_buffers_timestamp(mOutputSurface.get(), inputFrame.timestamp);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001200 if (res != OK) {
1201 ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
1202 __FUNCTION__, getStreamId(), strerror(-res), res);
1203 return res;
1204 }
1205
1206 res = outputANW->queueBuffer(mOutputSurface.get(), inputFrame.anb, /*fence*/ -1);
1207 if (res != OK) {
1208 ALOGE("%s: Failed to queueBuffer to Heic stream: %s (%d)", __FUNCTION__,
1209 strerror(-res), res);
1210 return res;
1211 }
1212 inputFrame.anb = nullptr;
Shuzhen Wang3d00ee52019-09-25 14:19:28 -07001213 mDequeuedOutputBufferCnt--;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001214
Shuzhen Wange8675782019-12-05 09:12:14 -08001215 ALOGV("%s: [%" PRId64 "]", __FUNCTION__, frameNumber);
1216 ATRACE_ASYNC_END("HEIC capture", frameNumber);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001217 return OK;
1218}
1219
1220
Shuzhen Wange8675782019-12-05 09:12:14 -08001221void HeicCompositeStream::releaseInputFrameLocked(int64_t frameNumber,
1222 InputFrame *inputFrame /*out*/) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001223 if (inputFrame == nullptr) {
1224 return;
1225 }
1226
1227 if (inputFrame->appSegmentBuffer.data != nullptr) {
1228 mAppSegmentConsumer->unlockBuffer(inputFrame->appSegmentBuffer);
1229 inputFrame->appSegmentBuffer.data = nullptr;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001230 }
1231
1232 while (!inputFrame->codecOutputBuffers.empty()) {
1233 auto it = inputFrame->codecOutputBuffers.begin();
1234 ALOGV("%s: releaseOutputBuffer index %d", __FUNCTION__, it->index);
1235 mCodec->releaseOutputBuffer(it->index);
1236 inputFrame->codecOutputBuffers.erase(it);
1237 }
1238
1239 if (inputFrame->yuvBuffer.data != nullptr) {
1240 mMainImageConsumer->unlockBuffer(inputFrame->yuvBuffer);
1241 inputFrame->yuvBuffer.data = nullptr;
1242 mYuvBufferAcquired = false;
1243 }
1244
1245 while (!inputFrame->codecInputBuffers.empty()) {
1246 auto it = inputFrame->codecInputBuffers.begin();
1247 inputFrame->codecInputBuffers.erase(it);
1248 }
1249
Shuzhen Wange8675782019-12-05 09:12:14 -08001250 if (inputFrame->error || mErrorState) {
1251 ALOGV("%s: notifyError called for frameNumber %" PRId64, __FUNCTION__, frameNumber);
1252 notifyError(frameNumber, inputFrame->requestId);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001253 }
1254
1255 if (inputFrame->fileFd >= 0) {
1256 close(inputFrame->fileFd);
1257 inputFrame->fileFd = -1;
1258 }
1259
1260 if (inputFrame->anb != nullptr) {
1261 sp<ANativeWindow> outputANW = mOutputSurface;
1262 outputANW->cancelBuffer(mOutputSurface.get(), inputFrame->anb, /*fence*/ -1);
1263 inputFrame->anb = nullptr;
Shuzhen Wange8675782019-12-05 09:12:14 -08001264
1265 mDequeuedOutputBufferCnt--;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001266 }
1267}
1268
Michael Gonzalezb5986a32019-10-09 15:38:17 -07001269void HeicCompositeStream::releaseInputFramesLocked() {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001270 auto it = mPendingInputFrames.begin();
Shuzhen Wang62f49ed2019-09-04 14:07:53 -07001271 bool inputFrameDone = false;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001272 while (it != mPendingInputFrames.end()) {
Michael Gonzalezb5986a32019-10-09 15:38:17 -07001273 auto& inputFrame = it->second;
1274 if (inputFrame.error ||
Shuzhen Wange8675782019-12-05 09:12:14 -08001275 (inputFrame.appSegmentWritten && inputFrame.pendingOutputTiles == 0)) {
1276 releaseInputFrameLocked(it->first, &inputFrame);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001277 it = mPendingInputFrames.erase(it);
Shuzhen Wang62f49ed2019-09-04 14:07:53 -07001278 inputFrameDone = true;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001279 } else {
1280 it++;
1281 }
1282 }
Shuzhen Wang62f49ed2019-09-04 14:07:53 -07001283
1284 // Update codec quality based on first upcoming input frame.
1285 // Note that when encoding is in surface mode, currently there is no
1286 // way for camera service to synchronize quality setting on a per-frame
1287 // basis: we don't get notification when codec is ready to consume a new
1288 // input frame. So we update codec quality on a best-effort basis.
1289 if (inputFrameDone) {
1290 auto firstPendingFrame = mPendingInputFrames.begin();
1291 if (firstPendingFrame != mPendingInputFrames.end()) {
1292 updateCodecQualityLocked(firstPendingFrame->second.quality);
Shuzhen Wange8675782019-12-05 09:12:14 -08001293 } else {
1294 markTrackerIdle();
Shuzhen Wang62f49ed2019-09-04 14:07:53 -07001295 }
1296 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001297}
1298
1299status_t HeicCompositeStream::initializeCodec(uint32_t width, uint32_t height,
1300 const sp<CameraDeviceBase>& cameraDevice) {
1301 ALOGV("%s", __FUNCTION__);
1302
1303 bool useGrid = false;
Chong Zhang688abaa2019-05-17 16:32:23 -07001304 AString hevcName;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001305 bool isSizeSupported = isSizeSupportedByHeifEncoder(width, height,
Chong Zhang688abaa2019-05-17 16:32:23 -07001306 &mUseHeic, &useGrid, nullptr, &hevcName);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001307 if (!isSizeSupported) {
1308 ALOGE("%s: Encoder doesnt' support size %u x %u!",
1309 __FUNCTION__, width, height);
1310 return BAD_VALUE;
1311 }
1312
1313 // Create Looper for MediaCodec.
1314 auto desiredMime = mUseHeic ? MIMETYPE_IMAGE_ANDROID_HEIC : MIMETYPE_VIDEO_HEVC;
1315 mCodecLooper = new ALooper;
1316 mCodecLooper->setName("Camera3-HeicComposite-MediaCodecLooper");
1317 status_t res = mCodecLooper->start(
1318 false, // runOnCallingThread
1319 false, // canCallJava
1320 PRIORITY_AUDIO);
1321 if (res != OK) {
1322 ALOGE("%s: Failed to start codec looper: %s (%d)",
1323 __FUNCTION__, strerror(-res), res);
1324 return NO_INIT;
1325 }
1326
1327 // Create HEIC/HEVC codec.
Chong Zhang688abaa2019-05-17 16:32:23 -07001328 if (mUseHeic) {
1329 mCodec = MediaCodec::CreateByType(mCodecLooper, desiredMime, true /*encoder*/);
1330 } else {
1331 mCodec = MediaCodec::CreateByComponentName(mCodecLooper, hevcName);
1332 }
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001333 if (mCodec == nullptr) {
1334 ALOGE("%s: Failed to create codec for %s", __FUNCTION__, desiredMime);
1335 return NO_INIT;
1336 }
1337
1338 // Create Looper and handler for Codec callback.
1339 mCodecCallbackHandler = new CodecCallbackHandler(this);
1340 if (mCodecCallbackHandler == nullptr) {
1341 ALOGE("%s: Failed to create codec callback handler", __FUNCTION__);
1342 return NO_MEMORY;
1343 }
1344 mCallbackLooper = new ALooper;
1345 mCallbackLooper->setName("Camera3-HeicComposite-MediaCodecCallbackLooper");
1346 res = mCallbackLooper->start(
1347 false, // runOnCallingThread
1348 false, // canCallJava
1349 PRIORITY_AUDIO);
1350 if (res != OK) {
1351 ALOGE("%s: Failed to start media callback looper: %s (%d)",
1352 __FUNCTION__, strerror(-res), res);
1353 return NO_INIT;
1354 }
1355 mCallbackLooper->registerHandler(mCodecCallbackHandler);
1356
1357 mAsyncNotify = new AMessage(kWhatCallbackNotify, mCodecCallbackHandler);
1358 res = mCodec->setCallback(mAsyncNotify);
1359 if (res != OK) {
1360 ALOGE("%s: Failed to set MediaCodec callback: %s (%d)", __FUNCTION__,
1361 strerror(-res), res);
1362 return res;
1363 }
1364
1365 // Create output format and configure the Codec.
1366 sp<AMessage> outputFormat = new AMessage();
1367 outputFormat->setString(KEY_MIME, desiredMime);
1368 outputFormat->setInt32(KEY_BITRATE_MODE, BITRATE_MODE_CQ);
1369 outputFormat->setInt32(KEY_QUALITY, kDefaultJpegQuality);
1370 // Ask codec to skip timestamp check and encode all frames.
Chong Zhang70bfcec2019-03-18 12:52:28 -07001371 outputFormat->setInt64(KEY_MAX_PTS_GAP_TO_ENCODER, kNoFrameDropMaxPtsGap);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001372
1373 int32_t gridWidth, gridHeight, gridRows, gridCols;
1374 if (useGrid || mUseHeic) {
1375 gridWidth = HeicEncoderInfoManager::kGridWidth;
1376 gridHeight = HeicEncoderInfoManager::kGridHeight;
1377 gridRows = (height + gridHeight - 1)/gridHeight;
1378 gridCols = (width + gridWidth - 1)/gridWidth;
1379
1380 if (mUseHeic) {
1381 outputFormat->setInt32(KEY_TILE_WIDTH, gridWidth);
1382 outputFormat->setInt32(KEY_TILE_HEIGHT, gridHeight);
1383 outputFormat->setInt32(KEY_GRID_COLUMNS, gridCols);
1384 outputFormat->setInt32(KEY_GRID_ROWS, gridRows);
1385 }
1386
1387 } else {
1388 gridWidth = width;
1389 gridHeight = height;
1390 gridRows = 1;
1391 gridCols = 1;
1392 }
1393
1394 outputFormat->setInt32(KEY_WIDTH, !useGrid ? width : gridWidth);
1395 outputFormat->setInt32(KEY_HEIGHT, !useGrid ? height : gridHeight);
1396 outputFormat->setInt32(KEY_I_FRAME_INTERVAL, 0);
1397 outputFormat->setInt32(KEY_COLOR_FORMAT,
1398 useGrid ? COLOR_FormatYUV420Flexible : COLOR_FormatSurface);
Shuzhen Wang0ca81522019-08-30 14:15:16 -07001399 outputFormat->setInt32(KEY_FRAME_RATE, useGrid ? gridRows * gridCols : kNoGridOpRate);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001400 // This only serves as a hint to encoder when encoding is not real-time.
1401 outputFormat->setInt32(KEY_OPERATING_RATE, useGrid ? kGridOpRate : kNoGridOpRate);
1402
1403 res = mCodec->configure(outputFormat, nullptr /*nativeWindow*/,
1404 nullptr /*crypto*/, CONFIGURE_FLAG_ENCODE);
1405 if (res != OK) {
1406 ALOGE("%s: Failed to configure codec: %s (%d)", __FUNCTION__,
1407 strerror(-res), res);
1408 return res;
1409 }
1410
1411 mGridWidth = gridWidth;
1412 mGridHeight = gridHeight;
1413 mGridRows = gridRows;
1414 mGridCols = gridCols;
1415 mUseGrid = useGrid;
1416 mOutputWidth = width;
1417 mOutputHeight = height;
1418 mAppSegmentMaxSize = calcAppSegmentMaxSize(cameraDevice->info());
Susmitha Gummallae911f2e2020-11-23 09:57:03 -08001419 mMaxHeicBufferSize =
1420 ALIGN(mOutputWidth, HeicEncoderInfoManager::kGridWidth) *
1421 ALIGN(mOutputHeight, HeicEncoderInfoManager::kGridHeight) * 3 / 2 + mAppSegmentMaxSize;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001422
1423 return OK;
1424}
1425
1426void HeicCompositeStream::deinitCodec() {
1427 ALOGV("%s", __FUNCTION__);
1428 if (mCodec != nullptr) {
1429 mCodec->stop();
1430 mCodec->release();
1431 mCodec.clear();
1432 }
1433
1434 if (mCodecLooper != nullptr) {
1435 mCodecLooper->stop();
1436 mCodecLooper.clear();
1437 }
1438
1439 if (mCallbackLooper != nullptr) {
1440 mCallbackLooper->stop();
1441 mCallbackLooper.clear();
1442 }
1443
1444 mAsyncNotify.clear();
1445 mFormat.clear();
1446}
1447
1448// Return the size of the complete list of app segment, 0 indicates failure
1449size_t HeicCompositeStream::findAppSegmentsSize(const uint8_t* appSegmentBuffer,
1450 size_t maxSize, size_t *app1SegmentSize) {
1451 if (appSegmentBuffer == nullptr || app1SegmentSize == nullptr) {
1452 ALOGE("%s: Invalid input appSegmentBuffer %p, app1SegmentSize %p",
1453 __FUNCTION__, appSegmentBuffer, app1SegmentSize);
1454 return 0;
1455 }
1456
1457 size_t expectedSize = 0;
1458 // First check for EXIF transport header at the end of the buffer
Jayant Chowdharyc67af1b2022-04-07 18:05:04 +00001459 const uint8_t *header = appSegmentBuffer + (maxSize - sizeof(CameraBlob));
1460 const CameraBlob *blob = (const CameraBlob*)(header);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001461 if (blob->blobId != CameraBlobId::JPEG_APP_SEGMENTS) {
Jayant Chowdharyc67af1b2022-04-07 18:05:04 +00001462 ALOGE("%s: Invalid EXIF blobId %d", __FUNCTION__, blob->blobId);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001463 return 0;
1464 }
1465
Jayant Chowdharyc67af1b2022-04-07 18:05:04 +00001466 expectedSize = blob->blobSizeBytes;
1467 if (expectedSize == 0 || expectedSize > maxSize - sizeof(CameraBlob)) {
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001468 ALOGE("%s: Invalid blobSize %zu.", __FUNCTION__, expectedSize);
1469 return 0;
1470 }
1471
1472 uint32_t totalSize = 0;
1473
1474 // Verify APP1 marker (mandatory)
1475 uint8_t app1Marker[] = {0xFF, 0xE1};
1476 if (memcmp(appSegmentBuffer, app1Marker, sizeof(app1Marker))) {
1477 ALOGE("%s: Invalid APP1 marker: %x, %x", __FUNCTION__,
1478 appSegmentBuffer[0], appSegmentBuffer[1]);
1479 return 0;
1480 }
1481 totalSize += sizeof(app1Marker);
1482
1483 uint16_t app1Size = (static_cast<uint16_t>(appSegmentBuffer[totalSize]) << 8) +
1484 appSegmentBuffer[totalSize+1];
1485 totalSize += app1Size;
1486
1487 ALOGV("%s: Expected APP segments size %zu, APP1 segment size %u",
1488 __FUNCTION__, expectedSize, app1Size);
1489 while (totalSize < expectedSize) {
1490 if (appSegmentBuffer[totalSize] != 0xFF ||
1491 appSegmentBuffer[totalSize+1] <= 0xE1 ||
1492 appSegmentBuffer[totalSize+1] > 0xEF) {
1493 // Invalid APPn marker
1494 ALOGE("%s: Invalid APPn marker: %x, %x", __FUNCTION__,
1495 appSegmentBuffer[totalSize], appSegmentBuffer[totalSize+1]);
1496 return 0;
1497 }
1498 totalSize += 2;
1499
1500 uint16_t appnSize = (static_cast<uint16_t>(appSegmentBuffer[totalSize]) << 8) +
1501 appSegmentBuffer[totalSize+1];
1502 totalSize += appnSize;
1503 }
1504
1505 if (totalSize != expectedSize) {
1506 ALOGE("%s: Invalid JPEG APP segments: totalSize %u vs expected size %zu",
1507 __FUNCTION__, totalSize, expectedSize);
1508 return 0;
1509 }
1510
1511 *app1SegmentSize = app1Size + sizeof(app1Marker);
1512 return expectedSize;
1513}
1514
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001515status_t HeicCompositeStream::copyOneYuvTile(sp<MediaCodecBuffer>& codecBuffer,
1516 const CpuConsumer::LockedBuffer& yuvBuffer,
1517 size_t top, size_t left, size_t width, size_t height) {
1518 ATRACE_CALL();
1519
1520 // Get stride information for codecBuffer
1521 sp<ABuffer> imageData;
1522 if (!codecBuffer->meta()->findBuffer("image-data", &imageData)) {
1523 ALOGE("%s: Codec input buffer is not for image data!", __FUNCTION__);
1524 return BAD_VALUE;
1525 }
1526 if (imageData->size() != sizeof(MediaImage2)) {
1527 ALOGE("%s: Invalid codec input image size %zu, expected %zu",
1528 __FUNCTION__, imageData->size(), sizeof(MediaImage2));
1529 return BAD_VALUE;
1530 }
1531 MediaImage2* imageInfo = reinterpret_cast<MediaImage2*>(imageData->data());
1532 if (imageInfo->mType != MediaImage2::MEDIA_IMAGE_TYPE_YUV ||
1533 imageInfo->mBitDepth != 8 ||
1534 imageInfo->mBitDepthAllocated != 8 ||
1535 imageInfo->mNumPlanes != 3) {
1536 ALOGE("%s: Invalid codec input image info: mType %d, mBitDepth %d, "
1537 "mBitDepthAllocated %d, mNumPlanes %d!", __FUNCTION__,
1538 imageInfo->mType, imageInfo->mBitDepth,
1539 imageInfo->mBitDepthAllocated, imageInfo->mNumPlanes);
1540 return BAD_VALUE;
1541 }
1542
1543 ALOGV("%s: yuvBuffer chromaStep %d, chromaStride %d",
1544 __FUNCTION__, yuvBuffer.chromaStep, yuvBuffer.chromaStride);
1545 ALOGV("%s: U offset %u, V offset %u, U rowInc %d, V rowInc %d, U colInc %d, V colInc %d",
1546 __FUNCTION__, imageInfo->mPlane[MediaImage2::U].mOffset,
1547 imageInfo->mPlane[MediaImage2::V].mOffset,
1548 imageInfo->mPlane[MediaImage2::U].mRowInc,
1549 imageInfo->mPlane[MediaImage2::V].mRowInc,
1550 imageInfo->mPlane[MediaImage2::U].mColInc,
1551 imageInfo->mPlane[MediaImage2::V].mColInc);
1552
1553 // Y
1554 for (auto row = top; row < top+height; row++) {
1555 uint8_t *dst = codecBuffer->data() + imageInfo->mPlane[MediaImage2::Y].mOffset +
1556 imageInfo->mPlane[MediaImage2::Y].mRowInc * (row - top);
Shuzhen Wang219c2992019-02-15 17:24:28 -08001557 mFnCopyRow(yuvBuffer.data+row*yuvBuffer.stride+left, dst, width);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001558 }
1559
1560 // U is Cb, V is Cr
1561 bool codecUPlaneFirst = imageInfo->mPlane[MediaImage2::V].mOffset >
1562 imageInfo->mPlane[MediaImage2::U].mOffset;
1563 uint32_t codecUvOffsetDiff = codecUPlaneFirst ?
1564 imageInfo->mPlane[MediaImage2::V].mOffset - imageInfo->mPlane[MediaImage2::U].mOffset :
1565 imageInfo->mPlane[MediaImage2::U].mOffset - imageInfo->mPlane[MediaImage2::V].mOffset;
1566 bool isCodecUvSemiplannar = (codecUvOffsetDiff == 1) &&
1567 (imageInfo->mPlane[MediaImage2::U].mRowInc ==
1568 imageInfo->mPlane[MediaImage2::V].mRowInc) &&
1569 (imageInfo->mPlane[MediaImage2::U].mColInc == 2) &&
1570 (imageInfo->mPlane[MediaImage2::V].mColInc == 2);
1571 bool isCodecUvPlannar =
1572 ((codecUPlaneFirst && codecUvOffsetDiff >=
1573 imageInfo->mPlane[MediaImage2::U].mRowInc * imageInfo->mHeight/2) ||
1574 ((!codecUPlaneFirst && codecUvOffsetDiff >=
1575 imageInfo->mPlane[MediaImage2::V].mRowInc * imageInfo->mHeight/2))) &&
1576 imageInfo->mPlane[MediaImage2::U].mColInc == 1 &&
1577 imageInfo->mPlane[MediaImage2::V].mColInc == 1;
1578 bool cameraUPlaneFirst = yuvBuffer.dataCr > yuvBuffer.dataCb;
1579
1580 if (isCodecUvSemiplannar && yuvBuffer.chromaStep == 2 &&
1581 (codecUPlaneFirst == cameraUPlaneFirst)) {
1582 // UV semiplannar
1583 // The chrome plane could be either Cb first, or Cr first. Take the
1584 // smaller address.
1585 uint8_t *src = std::min(yuvBuffer.dataCb, yuvBuffer.dataCr);
1586 MediaImage2::PlaneIndex dstPlane = codecUvOffsetDiff > 0 ? MediaImage2::U : MediaImage2::V;
1587 for (auto row = top/2; row < (top+height)/2; row++) {
1588 uint8_t *dst = codecBuffer->data() + imageInfo->mPlane[dstPlane].mOffset +
1589 imageInfo->mPlane[dstPlane].mRowInc * (row - top/2);
Shuzhen Wang219c2992019-02-15 17:24:28 -08001590 mFnCopyRow(src+row*yuvBuffer.chromaStride+left, dst, width);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001591 }
1592 } else if (isCodecUvPlannar && yuvBuffer.chromaStep == 1) {
1593 // U plane
1594 for (auto row = top/2; row < (top+height)/2; row++) {
1595 uint8_t *dst = codecBuffer->data() + imageInfo->mPlane[MediaImage2::U].mOffset +
1596 imageInfo->mPlane[MediaImage2::U].mRowInc * (row - top/2);
Shuzhen Wang219c2992019-02-15 17:24:28 -08001597 mFnCopyRow(yuvBuffer.dataCb+row*yuvBuffer.chromaStride+left/2, dst, width/2);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001598 }
1599
1600 // V plane
1601 for (auto row = top/2; row < (top+height)/2; row++) {
1602 uint8_t *dst = codecBuffer->data() + imageInfo->mPlane[MediaImage2::V].mOffset +
1603 imageInfo->mPlane[MediaImage2::V].mRowInc * (row - top/2);
Shuzhen Wang219c2992019-02-15 17:24:28 -08001604 mFnCopyRow(yuvBuffer.dataCr+row*yuvBuffer.chromaStride+left/2, dst, width/2);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001605 }
1606 } else {
Shuzhen Wang219c2992019-02-15 17:24:28 -08001607 // Convert between semiplannar and plannar, or when UV orders are
1608 // different.
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001609 uint8_t *dst = codecBuffer->data();
1610 for (auto row = top/2; row < (top+height)/2; row++) {
1611 for (auto col = left/2; col < (left+width)/2; col++) {
1612 // U/Cb
1613 int32_t dstIndex = imageInfo->mPlane[MediaImage2::U].mOffset +
1614 imageInfo->mPlane[MediaImage2::U].mRowInc * (row - top/2) +
1615 imageInfo->mPlane[MediaImage2::U].mColInc * (col - left/2);
1616 int32_t srcIndex = row * yuvBuffer.chromaStride + yuvBuffer.chromaStep * col;
1617 dst[dstIndex] = yuvBuffer.dataCb[srcIndex];
1618
1619 // V/Cr
1620 dstIndex = imageInfo->mPlane[MediaImage2::V].mOffset +
1621 imageInfo->mPlane[MediaImage2::V].mRowInc * (row - top/2) +
1622 imageInfo->mPlane[MediaImage2::V].mColInc * (col - left/2);
1623 srcIndex = row * yuvBuffer.chromaStride + yuvBuffer.chromaStep * col;
1624 dst[dstIndex] = yuvBuffer.dataCr[srcIndex];
1625 }
1626 }
1627 }
1628 return OK;
1629}
1630
Colin Cross14900c92023-01-13 14:50:17 -08001631void HeicCompositeStream::initCopyRowFunction([[maybe_unused]] int32_t width)
Shuzhen Wang219c2992019-02-15 17:24:28 -08001632{
1633 using namespace libyuv;
1634
1635 mFnCopyRow = CopyRow_C;
1636#if defined(HAS_COPYROW_SSE2)
1637 if (TestCpuFlag(kCpuHasSSE2)) {
1638 mFnCopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
1639 }
1640#endif
1641#if defined(HAS_COPYROW_AVX)
1642 if (TestCpuFlag(kCpuHasAVX)) {
1643 mFnCopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
1644 }
1645#endif
1646#if defined(HAS_COPYROW_ERMS)
1647 if (TestCpuFlag(kCpuHasERMS)) {
1648 mFnCopyRow = CopyRow_ERMS;
1649 }
1650#endif
1651#if defined(HAS_COPYROW_NEON)
1652 if (TestCpuFlag(kCpuHasNEON)) {
1653 mFnCopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
1654 }
1655#endif
1656#if defined(HAS_COPYROW_MIPS)
1657 if (TestCpuFlag(kCpuHasMIPS)) {
1658 mFnCopyRow = CopyRow_MIPS;
1659 }
1660#endif
1661}
1662
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001663size_t HeicCompositeStream::calcAppSegmentMaxSize(const CameraMetadata& info) {
1664 camera_metadata_ro_entry_t entry = info.find(ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT);
1665 size_t maxAppsSegment = 1;
1666 if (entry.count > 0) {
1667 maxAppsSegment = entry.data.u8[0] < 1 ? 1 :
1668 entry.data.u8[0] > 16 ? 16 : entry.data.u8[0];
1669 }
Jayant Chowdharyc67af1b2022-04-07 18:05:04 +00001670 return maxAppsSegment * (2 + 0xFFFF) + sizeof(CameraBlob);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001671}
1672
Shuzhen Wang62f49ed2019-09-04 14:07:53 -07001673void HeicCompositeStream::updateCodecQualityLocked(int32_t quality) {
1674 if (quality != mQuality) {
1675 sp<AMessage> qualityParams = new AMessage;
1676 qualityParams->setInt32(PARAMETER_KEY_VIDEO_BITRATE, quality);
1677 status_t res = mCodec->setParameters(qualityParams);
1678 if (res != OK) {
1679 ALOGE("%s: Failed to set codec quality: %s (%d)",
1680 __FUNCTION__, strerror(-res), res);
1681 } else {
1682 mQuality = quality;
1683 }
1684 }
1685}
1686
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001687bool HeicCompositeStream::threadLoop() {
Shuzhen Wange8675782019-12-05 09:12:14 -08001688 int64_t frameNumber = -1;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001689 bool newInputAvailable = false;
1690
1691 {
1692 Mutex::Autolock l(mMutex);
1693 if (mErrorState) {
1694 // In case we landed in error state, return any pending buffers and
1695 // halt all further processing.
1696 compilePendingInputLocked();
Michael Gonzalezb5986a32019-10-09 15:38:17 -07001697 releaseInputFramesLocked();
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001698 return false;
1699 }
1700
1701
1702 while (!newInputAvailable) {
1703 compilePendingInputLocked();
Shuzhen Wange8675782019-12-05 09:12:14 -08001704 newInputAvailable = getNextReadyInputLocked(&frameNumber);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001705
1706 if (!newInputAvailable) {
Shuzhen Wange8675782019-12-05 09:12:14 -08001707 auto failingFrameNumber = getNextFailingInputLocked();
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001708 if (failingFrameNumber >= 0) {
Shuzhen Wange8675782019-12-05 09:12:14 -08001709 releaseInputFrameLocked(failingFrameNumber,
1710 &mPendingInputFrames[failingFrameNumber]);
1711
1712 // It's okay to remove the entry from mPendingInputFrames
1713 // because:
1714 // 1. Only one internal stream (main input) is critical in
1715 // backing the output stream.
1716 // 2. If captureResult/appSegment arrives after the entry is
1717 // removed, they are simply skipped.
1718 mPendingInputFrames.erase(failingFrameNumber);
1719 if (mPendingInputFrames.size() == 0) {
1720 markTrackerIdle();
1721 }
1722 return true;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001723 }
1724
1725 auto ret = mInputReadyCondition.waitRelative(mMutex, kWaitDuration);
1726 if (ret == TIMED_OUT) {
1727 return true;
1728 } else if (ret != OK) {
1729 ALOGE("%s: Timed wait on condition failed: %s (%d)", __FUNCTION__,
1730 strerror(-ret), ret);
1731 return false;
1732 }
1733 }
1734 }
1735 }
1736
Shuzhen Wange8675782019-12-05 09:12:14 -08001737 auto res = processInputFrame(frameNumber, mPendingInputFrames[frameNumber]);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001738 Mutex::Autolock l(mMutex);
1739 if (res != OK) {
Shuzhen Wange8675782019-12-05 09:12:14 -08001740 ALOGE("%s: Failed processing frame with timestamp: %" PRIu64 ", frameNumber: %"
1741 PRId64 ": %s (%d)", __FUNCTION__, mPendingInputFrames[frameNumber].timestamp,
1742 frameNumber, strerror(-res), res);
1743 mPendingInputFrames[frameNumber].error = true;
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001744 }
1745
Michael Gonzalezb5986a32019-10-09 15:38:17 -07001746 releaseInputFramesLocked();
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001747
1748 return true;
1749}
1750
Shuzhen Wange8675782019-12-05 09:12:14 -08001751void HeicCompositeStream::flagAnExifErrorFrameNumber(int64_t frameNumber) {
1752 Mutex::Autolock l(mMutex);
1753 mExifErrorFrameNumbers.emplace(frameNumber);
1754 mInputReadyCondition.signal();
1755}
1756
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001757bool HeicCompositeStream::onStreamBufferError(const CaptureResultExtras& resultExtras) {
1758 bool res = false;
Shuzhen Wange8675782019-12-05 09:12:14 -08001759 int64_t frameNumber = resultExtras.frameNumber;
1760
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001761 // Buffer errors concerning internal composite streams should not be directly visible to
1762 // camera clients. They must only receive a single buffer error with the public composite
1763 // stream id.
Shuzhen Wange8675782019-12-05 09:12:14 -08001764 if (resultExtras.errorStreamId == mAppSegmentStreamId) {
1765 ALOGV("%s: APP_SEGMENT frameNumber: %" PRId64, __FUNCTION__, frameNumber);
1766 flagAnExifErrorFrameNumber(frameNumber);
1767 res = true;
1768 } else if (resultExtras.errorStreamId == mMainImageStreamId) {
1769 ALOGV("%s: YUV frameNumber: %" PRId64, __FUNCTION__, frameNumber);
1770 flagAnErrorFrameNumber(frameNumber);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001771 res = true;
1772 }
1773
1774 return res;
1775}
1776
Shuzhen Wange7f4b462019-02-12 08:43:07 -08001777void HeicCompositeStream::onResultError(const CaptureResultExtras& resultExtras) {
1778 // For result error, since the APPS_SEGMENT buffer already contains EXIF,
1779 // simply skip using the capture result metadata to override EXIF.
1780 Mutex::Autolock l(mMutex);
1781
1782 int64_t timestamp = -1;
Shuzhen Wange8675782019-12-05 09:12:14 -08001783 for (const auto& fn : mSettingsByFrameNumber) {
Shuzhen Wange7f4b462019-02-12 08:43:07 -08001784 if (fn.first == resultExtras.frameNumber) {
Shuzhen Wange8675782019-12-05 09:12:14 -08001785 timestamp = fn.second.timestamp;
Shuzhen Wange7f4b462019-02-12 08:43:07 -08001786 break;
1787 }
1788 }
1789 if (timestamp == -1) {
1790 for (const auto& inputFrame : mPendingInputFrames) {
Shuzhen Wange8675782019-12-05 09:12:14 -08001791 if (inputFrame.first == resultExtras.frameNumber) {
1792 timestamp = inputFrame.second.timestamp;
Shuzhen Wange7f4b462019-02-12 08:43:07 -08001793 break;
1794 }
1795 }
1796 }
1797
1798 if (timestamp == -1) {
1799 ALOGE("%s: Failed to find shutter timestamp for result error!", __FUNCTION__);
1800 return;
1801 }
1802
1803 mCaptureResults.emplace(timestamp, std::make_tuple(resultExtras.frameNumber, CameraMetadata()));
Shuzhen Wange8675782019-12-05 09:12:14 -08001804 ALOGV("%s: timestamp %" PRId64 ", frameNumber %" PRId64, __FUNCTION__,
1805 timestamp, resultExtras.frameNumber);
Shuzhen Wange7f4b462019-02-12 08:43:07 -08001806 mInputReadyCondition.signal();
1807}
1808
Shuzhen Wange8675782019-12-05 09:12:14 -08001809void HeicCompositeStream::onRequestError(const CaptureResultExtras& resultExtras) {
1810 auto frameNumber = resultExtras.frameNumber;
1811 ALOGV("%s: frameNumber: %" PRId64, __FUNCTION__, frameNumber);
1812 Mutex::Autolock l(mMutex);
1813 auto numRequests = mSettingsByFrameNumber.erase(frameNumber);
1814 if (numRequests == 0) {
1815 // Pending request has been populated into mPendingInputFrames
1816 mErrorFrameNumbers.emplace(frameNumber);
1817 mInputReadyCondition.signal();
1818 } else {
1819 // REQUEST_ERROR was received without onShutter.
1820 }
1821}
1822
1823void HeicCompositeStream::markTrackerIdle() {
1824 sp<StatusTracker> statusTracker = mStatusTracker.promote();
1825 if (statusTracker != nullptr) {
1826 statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE);
1827 ALOGV("%s: Mark component as idle", __FUNCTION__);
1828 }
1829}
1830
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001831void HeicCompositeStream::CodecCallbackHandler::onMessageReceived(const sp<AMessage> &msg) {
1832 sp<HeicCompositeStream> parent = mParent.promote();
1833 if (parent == nullptr) return;
1834
1835 switch (msg->what()) {
1836 case kWhatCallbackNotify: {
1837 int32_t cbID;
1838 if (!msg->findInt32("callbackID", &cbID)) {
1839 ALOGE("kWhatCallbackNotify: callbackID is expected.");
1840 break;
1841 }
1842
1843 ALOGV("kWhatCallbackNotify: cbID = %d", cbID);
1844
1845 switch (cbID) {
1846 case MediaCodec::CB_INPUT_AVAILABLE: {
1847 int32_t index;
1848 if (!msg->findInt32("index", &index)) {
1849 ALOGE("CB_INPUT_AVAILABLE: index is expected.");
1850 break;
1851 }
1852 parent->onHeicInputFrameAvailable(index);
1853 break;
1854 }
1855
1856 case MediaCodec::CB_OUTPUT_AVAILABLE: {
1857 int32_t index;
1858 size_t offset;
1859 size_t size;
1860 int64_t timeUs;
1861 int32_t flags;
1862
1863 if (!msg->findInt32("index", &index)) {
1864 ALOGE("CB_OUTPUT_AVAILABLE: index is expected.");
1865 break;
1866 }
1867 if (!msg->findSize("offset", &offset)) {
1868 ALOGE("CB_OUTPUT_AVAILABLE: offset is expected.");
1869 break;
1870 }
1871 if (!msg->findSize("size", &size)) {
1872 ALOGE("CB_OUTPUT_AVAILABLE: size is expected.");
1873 break;
1874 }
1875 if (!msg->findInt64("timeUs", &timeUs)) {
1876 ALOGE("CB_OUTPUT_AVAILABLE: timeUs is expected.");
1877 break;
1878 }
1879 if (!msg->findInt32("flags", &flags)) {
1880 ALOGE("CB_OUTPUT_AVAILABLE: flags is expected.");
1881 break;
1882 }
1883
1884 CodecOutputBufferInfo bufferInfo = {
1885 index,
1886 (int32_t)offset,
1887 (int32_t)size,
1888 timeUs,
1889 (uint32_t)flags};
1890
1891 parent->onHeicOutputFrameAvailable(bufferInfo);
1892 break;
1893 }
1894
1895 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED: {
1896 sp<AMessage> format;
1897 if (!msg->findMessage("format", &format)) {
1898 ALOGE("CB_OUTPUT_FORMAT_CHANGED: format is expected.");
1899 break;
1900 }
Chong Zhang860eff12019-09-16 16:15:00 -07001901 // Here format is MediaCodec's internal copy of output format.
1902 // Make a copy since onHeicFormatChanged() might modify it.
1903 sp<AMessage> formatCopy;
1904 if (format != nullptr) {
1905 formatCopy = format->dup();
1906 }
1907 parent->onHeicFormatChanged(formatCopy);
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -08001908 break;
1909 }
1910
1911 case MediaCodec::CB_ERROR: {
1912 status_t err;
1913 int32_t actionCode;
1914 AString detail;
1915 if (!msg->findInt32("err", &err)) {
1916 ALOGE("CB_ERROR: err is expected.");
1917 break;
1918 }
1919 if (!msg->findInt32("action", &actionCode)) {
1920 ALOGE("CB_ERROR: action is expected.");
1921 break;
1922 }
1923 msg->findString("detail", &detail);
1924 ALOGE("Codec reported error(0x%x), actionCode(%d), detail(%s)",
1925 err, actionCode, detail.c_str());
1926
1927 parent->onHeicCodecError();
1928 break;
1929 }
1930
1931 default: {
1932 ALOGE("kWhatCallbackNotify: callbackID(%d) is unexpected.", cbID);
1933 break;
1934 }
1935 }
1936 break;
1937 }
1938
1939 default:
1940 ALOGE("shouldn't be here");
1941 break;
1942 }
1943}
1944
1945}; // namespace camera3
1946}; // namespace android