1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <DeviceAsWebcamServiceManager.h>
18 #include <linux/videodev2.h>
19 #include <log/log.h>
20 #include <utility>
21 #include <vector>
22
23 #include "Buffer.h"
24 #include "SdkFrameProvider.h"
25 #include "Utils.h"
26
27 namespace android {
28 namespace webcam {
29
SdkFrameProvider(std::shared_ptr<BufferProducer> producer,CameraConfig config)30 SdkFrameProvider::SdkFrameProvider(std::shared_ptr<BufferProducer> producer, CameraConfig config)
31 : FrameProvider(std::move(producer), config) {
32 // Set stream configuration in java service.
33 mEncoder = std::make_shared<Encoder>(config, this);
34 if (!(mEncoder->isInited())) {
35 ALOGE("%s: Encoder initialization failed", __FUNCTION__);
36 return;
37 }
38 mEncoder->startEncoderThread();
39
40 mInited = true;
41 }
42
setStreamConfig()43 void SdkFrameProvider::setStreamConfig() {
44 DeviceAsWebcamServiceManager::kInstance->setStreamConfig(
45 mConfig.fcc == V4L2_PIX_FMT_MJPEG, mConfig.width, mConfig.height, mConfig.fps);
46 }
47
startStreaming()48 Status SdkFrameProvider::startStreaming() {
49 DeviceAsWebcamServiceManager::kInstance->startStreaming();
50 return Status::OK;
51 }
52
stopStreaming()53 Status SdkFrameProvider::stopStreaming() {
54 DeviceAsWebcamServiceManager::kInstance->stopStreaming();
55 return Status::OK;
56 }
57
encodeImage(AHardwareBuffer * hardwareBuffer,long timestamp,int rotation)58 Status SdkFrameProvider::encodeImage(AHardwareBuffer* hardwareBuffer, long timestamp,
59 int rotation) {
60 HardwareBufferDesc desc;
61 if (getHardwareBufferDescFromHardwareBuffer(hardwareBuffer, desc) != Status::OK) {
62 ALOGE("%s Couldn't get hardware buffer descriptor", __FUNCTION__);
63 return Status::ERROR;
64 }
65 return encodeImage(desc, timestamp, rotation);
66 }
67
getHardwareBufferDescFromHardwareBuffer(AHardwareBuffer * hardwareBuffer,HardwareBufferDesc & ret)68 Status SdkFrameProvider::getHardwareBufferDescFromHardwareBuffer(AHardwareBuffer* hardwareBuffer,
69 HardwareBufferDesc& ret) {
70 if (hardwareBuffer == nullptr) {
71 ALOGE("%s: Received null AHardwareBuffer.", __FUNCTION__);
72 return Status::ERROR;
73 }
74
75 // Acquire to prevent Java from accidentally GC'ing the hardware buffer while it is in
76 // use by SdkFrameProvider.
77 AHardwareBuffer_acquire(hardwareBuffer);
78
79 AHardwareBuffer_Planes planes{};
80 if (AHardwareBuffer_lockPlanes(hardwareBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
81 /*fence*/ -1, /*rect*/ nullptr, &planes) != 0) {
82 ALOGE("%s: Couldn't get hardware buffer planes from hardware buffer", __FUNCTION__);
83 AHardwareBuffer_release(hardwareBuffer);
84 return Status::ERROR;
85 }
86 AHardwareBuffer_Desc desc{};
87 AHardwareBuffer_describe(hardwareBuffer, &desc);
88
89 uint32_t height = desc.height;
90 uint32_t width = desc.width;
91 ret.format = desc.format;
92 ret.width = width;
93 ret.height = height;
94
95 if (ret.format == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
96 YuvHardwareBufferDesc yuvDesc;
97 yuvDesc.yData = (uint8_t*) planes.planes[0].data;
98 yuvDesc.yDataLength = planes.planes[0].rowStride * (height - 1) + width;
99 yuvDesc.yRowStride = planes.planes[0].rowStride;
100
101 yuvDesc.uData = (uint8_t*) planes.planes[1].data;
102 yuvDesc.uDataLength = planes.planes[1].rowStride * (height / 2 - 1) +
103 (planes.planes[1].pixelStride * width / 2 - 1) + 1;
104 yuvDesc.uRowStride = planes.planes[1].rowStride;
105
106 yuvDesc.vData = (uint8_t*) planes.planes[2].data;
107 yuvDesc.vDataLength = planes.planes[2].rowStride * (height / 2 - 1) +
108 (planes.planes[2].pixelStride * width / 2 - 1) + 1;
109 yuvDesc.vRowStride = planes.planes[2].rowStride;
110
111 // Pixel stride is the same for u and v planes
112 yuvDesc.uvPixelStride = planes.planes[1].pixelStride;
113 ret.bufferDesc = yuvDesc;
114 } else if(ret.format == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM) {
115 ARGBHardwareBufferDesc argbDesc;
116 argbDesc.buf = (uint8_t*) planes.planes[0].data;
117 argbDesc.rowStride = planes.planes[0].rowStride;
118 ret.bufferDesc = argbDesc;
119 }
120 {
121 std::lock_guard<std::mutex> l(mMapLock);
122 ret.bufferId = mNextBufferId++;
123 mBufferIdToAHardwareBuffer[ret.bufferId] = hardwareBuffer;
124 }
125 return Status::OK;
126 }
127
encodeImage(HardwareBufferDesc desc,jlong timestamp,jint rotation)128 Status SdkFrameProvider::encodeImage(HardwareBufferDesc desc, jlong timestamp, jint rotation) {
129 Buffer* producerBuffer = mBufferProducer->getFreeBufferIfAvailable();
130 if (producerBuffer == nullptr) {
131 // Not available so don't compress
132 ALOGV("%s: Producer buffer not available, returning", __FUNCTION__);
133 releaseHardwareBuffer(desc);
134 return Status::ERROR;
135 }
136
137 producerBuffer->setTimestamp(static_cast<uint64_t>(timestamp));
138 // send to the Encoder.
139 EncodeRequest encodeRequest(desc, producerBuffer, rotation);
140 mEncoder->queueRequest(encodeRequest);
141 return Status::OK;
142 }
143
onEncoded(Buffer * producerBuffer,HardwareBufferDesc & desc,bool success)144 void SdkFrameProvider::onEncoded(Buffer* producerBuffer, HardwareBufferDesc& desc, bool success) {
145 releaseHardwareBuffer(desc);
146 // Let Java know that HardwareBuffer is free to be cleaned up
147 DeviceAsWebcamServiceManager::kInstance->returnImage(
148 static_cast<long>(producerBuffer->getTimestamp()));
149
150 if (!success) {
151 ALOGE("%s Encoding was unsuccessful", __FUNCTION__);
152 mBufferProducer->cancelBuffer(producerBuffer);
153 return;
154 }
155 if (mBufferProducer->queueFilledBuffer(producerBuffer) != Status::OK) {
156 ALOGE("%s Queueing filled buffer failed, something is wrong", __FUNCTION__);
157 return;
158 }
159 }
160
releaseHardwareBuffer(const HardwareBufferDesc & desc)161 void SdkFrameProvider::releaseHardwareBuffer(const HardwareBufferDesc& desc) {
162 // Unlock and release
163 {
164 std::lock_guard<std::mutex> l(mMapLock);
165 auto it = mBufferIdToAHardwareBuffer.find(desc.bufferId);
166 if (it == mBufferIdToAHardwareBuffer.end()) {
167 // Continue anyway to let java call HardwareBuffer.close();
168 ALOGE("Couldn't find AHardwareBuffer for buffer id %u, what ?", desc.bufferId);
169 } else {
170 AHardwareBuffer_unlock(it->second, /*fence*/ nullptr);
171 AHardwareBuffer_release(it->second);
172 mBufferIdToAHardwareBuffer.erase(it->first);
173 }
174 }
175 }
176
~SdkFrameProvider()177 SdkFrameProvider::~SdkFrameProvider() {
178 stopStreaming();
179 mEncoder.reset();
180 }
181
182 } // namespace webcam
183 } // namespace android
184