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