1 /*
2  * Copyright (C) 2017 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 "RenderPixelCopy.h"
18 #include "FormatConvert.h"
19 
20 #include <android-base/logging.h>
21 
22 
RenderPixelCopy(sp<IEvsEnumerator> enumerator,const ConfigManager::CameraInfo & cam)23 RenderPixelCopy::RenderPixelCopy(sp<IEvsEnumerator> enumerator,
24                                    const ConfigManager::CameraInfo& cam) {
25     mEnumerator = enumerator;
26     mCameraInfo = cam;
27 }
28 
29 
activate()30 bool RenderPixelCopy::activate() {
31     // Set up the camera to feed this texture
32     sp<IEvsCamera> pCamera =
33         IEvsCamera::castFrom(mEnumerator->openCamera(mCameraInfo.cameraId.c_str()))
34         .withDefault(nullptr);
35 
36     if (pCamera.get() == nullptr) {
37         LOG(ERROR) << "Failed to allocate new EVS Camera interface";
38         return false;
39     }
40 
41     // Initialize the stream that will help us update this texture's contents
42     sp<StreamHandler> pStreamHandler = new StreamHandler(pCamera);
43     if (pStreamHandler.get() == nullptr) {
44         LOG(ERROR) << "Failed to allocate FrameHandler";
45         return false;
46     }
47 
48     // Start the video stream
49     if (!pStreamHandler->startStream()) {
50         LOG(ERROR) << "Start stream failed";
51         return false;
52     }
53 
54     mStreamHandler = pStreamHandler;
55 
56     return true;
57 }
58 
59 
deactivate()60 void RenderPixelCopy::deactivate() {
61     mStreamHandler = nullptr;
62 }
63 
64 
drawFrame(const BufferDesc & tgtBuffer)65 bool RenderPixelCopy::drawFrame(const BufferDesc& tgtBuffer) {
66     bool success = true;
67     const AHardwareBuffer_Desc* pTgtDesc =
68         reinterpret_cast<const AHardwareBuffer_Desc *>(&tgtBuffer.buffer.description);
69 
70     sp<android::GraphicBuffer> tgt = new android::GraphicBuffer(tgtBuffer.buffer.nativeHandle,
71                                                                 android::GraphicBuffer::CLONE_HANDLE,
72                                                                 pTgtDesc->width,
73                                                                 pTgtDesc->height,
74                                                                 pTgtDesc->format,
75                                                                 pTgtDesc->layers,
76                                                                 pTgtDesc->usage,
77                                                                 pTgtDesc->stride);
78 
79     // Lock our target buffer for writing (should be RGBA8888 format)
80     uint32_t* tgtPixels = nullptr;
81     tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
82 
83     if (tgtPixels) {
84         if (pTgtDesc->format != HAL_PIXEL_FORMAT_RGBA_8888) {
85             // We always expect 32 bit RGB for the display output for now.  Is there a need for 565?
86             LOG(ERROR) << "Diplay buffer is always expected to be 32bit RGBA";
87             success = false;
88         } else {
89             // Make sure we have the latest frame data
90             if (mStreamHandler->newFrameAvailable()) {
91                 const BufferDesc& srcBuffer = mStreamHandler->getNewFrame();
92                 const AHardwareBuffer_Desc* pSrcDesc =
93                     reinterpret_cast<const AHardwareBuffer_Desc *>(&srcBuffer.buffer.description);
94 
95                 // Lock our source buffer for reading (current expectation are for this to be NV21 format)
96                 sp<android::GraphicBuffer> src = new android::GraphicBuffer(srcBuffer.buffer.nativeHandle,
97                                                                             android::GraphicBuffer::CLONE_HANDLE,
98                                                                             pSrcDesc->width,
99                                                                             pSrcDesc->height,
100                                                                             pSrcDesc->format,
101                                                                             pSrcDesc->layers,
102                                                                             pSrcDesc->usage,
103                                                                             pSrcDesc->stride);
104 
105                 unsigned char* srcPixels = nullptr;
106                 src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels);
107                 if (srcPixels != nullptr) {
108                     // Make sure we don't run off the end of either buffer
109                     const unsigned width  = std::min(pTgtDesc->width,
110                                                      pSrcDesc->width);
111                     const unsigned height = std::min(pTgtDesc->height,
112                                                      pSrcDesc->height);
113 
114                     if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCRCB_420_SP) {   // 420SP == NV21
115                         copyNV21toRGB32(width, height,
116                                         srcPixels,
117                                         tgtPixels, pTgtDesc->stride);
118                     } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
119                         copyYV12toRGB32(width, height,
120                                         srcPixels,
121                                         tgtPixels, pTgtDesc->stride);
122                     } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
123                         copyYUYVtoRGB32(width, height,
124                                         srcPixels, pSrcDesc->stride,
125                                         tgtPixels, pTgtDesc->stride);
126                     } else if (pSrcDesc->format == pTgtDesc->format) {  // 32bit RGBA
127                         copyMatchedInterleavedFormats(width, height,
128                                                       srcPixels, pSrcDesc->stride,
129                                                       tgtPixels, pTgtDesc->stride,
130                                                       tgtBuffer.pixelSize);
131                     }
132                 } else {
133                     LOG(ERROR) << "Failed to get pointer into src image data";
134                     success = false;
135                 }
136 
137                 mStreamHandler->doneWithFrame(srcBuffer);
138             }
139         }
140     } else {
141         LOG(ERROR) << "Failed to lock buffer contents for contents transfer";
142         success = false;
143     }
144 
145     if (tgtPixels) {
146         tgt->unlock();
147     }
148 
149     return success;
150 }
151