• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <vector>
17 #include <stdio.h>
18 #include <fcntl.h>
19 #include <alloca.h>
20 #include <unistd.h>
21 #include <sys/ioctl.h>
22 #include <malloc.h>
23 #include <png.h>
24 
25 #include "VideoTex.h"
26 #include "glError.h"
27 
28 #include <ui/GraphicBuffer.h>
29 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
30 #include <android-base/logging.h>
31 
32 // Eventually we shouldn't need this dependency, but for now the
33 // graphics allocator interface isn't fully supported on all platforms
34 // and this is our work around.
35 using ::android::GraphicBuffer;
36 
37 
VideoTex(sp<IEvsEnumerator> pEnum,sp<IEvsCamera> pCamera,sp<StreamHandler> pStreamHandler,EGLDisplay glDisplay)38 VideoTex::VideoTex(sp<IEvsEnumerator> pEnum,
39                    sp<IEvsCamera> pCamera,
40                    sp<StreamHandler> pStreamHandler,
41                    EGLDisplay glDisplay)
42     : TexWrapper()
43     , mEnumerator(pEnum)
44     , mCamera(pCamera)
45     , mStreamHandler(pStreamHandler)
46     , mDisplay(glDisplay) {
47     // Nothing but initialization here...
48 }
49 
~VideoTex()50 VideoTex::~VideoTex() {
51     // Tell the stream to stop flowing
52     mStreamHandler->asyncStopStream();
53 
54     // Close the camera
55     mEnumerator->closeCamera(mCamera);
56 
57     // Drop our device texture image
58     if (mKHRimage != EGL_NO_IMAGE_KHR) {
59         eglDestroyImageKHR(mDisplay, mKHRimage);
60         mKHRimage = EGL_NO_IMAGE_KHR;
61     }
62 }
63 
64 
65 // Return true if the texture contents are changed
refresh()66 bool VideoTex::refresh() {
67     if (!mStreamHandler->newFrameAvailable()) {
68         // No new image has been delivered, so there's nothing to do here
69         return false;
70     }
71 
72     // If we already have an image backing us, then it's time to return it
73     if (mImageBuffer.buffer.nativeHandle.getNativeHandle() != nullptr) {
74         // Drop our device texture image
75         if (mKHRimage != EGL_NO_IMAGE_KHR) {
76             eglDestroyImageKHR(mDisplay, mKHRimage);
77             mKHRimage = EGL_NO_IMAGE_KHR;
78         }
79 
80         // Return it since we're done with it
81         mStreamHandler->doneWithFrame(mImageBuffer);
82     }
83 
84     // Get the new image we want to use as our contents
85     mImageBuffer = mStreamHandler->getNewFrame();
86 
87 
88     // create a GraphicBuffer from the existing handle
89     const AHardwareBuffer_Desc* pDesc =
90         reinterpret_cast<const AHardwareBuffer_Desc *>(&mImageBuffer.buffer.description);
91     sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(mImageBuffer.buffer.nativeHandle,
92                                                      GraphicBuffer::CLONE_HANDLE,
93                                                      pDesc->width,
94                                                      pDesc->height,
95                                                      pDesc->format,
96                                                      1,//pDesc->layers,
97                                                      GRALLOC_USAGE_HW_TEXTURE,
98                                                      pDesc->stride);
99     if (pGfxBuffer.get() == nullptr) {
100         LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap image handle";
101         // Returning "true" in this error condition because we already released the
102         // previous image (if any) and so the texture may change in unpredictable ways now!
103         return true;
104     }
105 
106     // Get a GL compatible reference to the graphics buffer we've been given
107     EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
108     EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
109     mKHRimage = eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT,
110                                   EGL_NATIVE_BUFFER_ANDROID, clientBuf,
111                                   eglImageAttributes);
112     if (mKHRimage == EGL_NO_IMAGE_KHR) {
113         const char *msg = getEGLError();
114         LOG(ERROR) << "Error creating EGLImage: " << msg;
115     } else {
116         // Update the texture handle we already created to refer to this gralloc buffer
117         glActiveTexture(GL_TEXTURE0);
118         glBindTexture(GL_TEXTURE_2D, glId());
119         glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(mKHRimage));
120 
121         // Initialize the sampling properties (it seems the sample may not work if this isn't done)
122         // The user of this texture may very well want to set their own filtering, but we're going
123         // to pay the (minor) price of setting this up for them to avoid the dreaded "black image"
124         // if they forget.
125         // TODO:  Can we do this once for the texture ID rather than ever refresh?
126         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
127         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
128         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
129         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
130     }
131 
132     return true;
133 }
134 
135 
createVideoTexture(sp<IEvsEnumerator> pEnum,const char * evsCameraId,std::unique_ptr<Stream> streamCfg,EGLDisplay glDisplay,bool useExternalMemory,android_pixel_format_t format)136 VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
137                              const char* evsCameraId,
138                              std::unique_ptr<Stream> streamCfg,
139                              EGLDisplay glDisplay,
140                              bool useExternalMemory,
141                              android_pixel_format_t format) {
142     // Set up the camera to feed this texture
143     sp<IEvsCamera> pCamera = nullptr;
144     sp<StreamHandler> pStreamHandler = nullptr;
145     if (streamCfg != nullptr) {
146         pCamera = pEnum->openCamera_1_1(evsCameraId, *streamCfg);
147 
148         // Initialize the stream that will help us update this texture's contents
149         pStreamHandler = new StreamHandler(pCamera,
150                                            2,     // number of buffers
151                                            useExternalMemory,
152                                            format,
153                                            streamCfg->width,
154                                            streamCfg->height);
155     } else {
156         pCamera =
157             IEvsCamera::castFrom(pEnum->openCamera(evsCameraId))
158             .withDefault(nullptr);
159 
160         // Initialize the stream with the default resolution
161         pStreamHandler = new StreamHandler(pCamera,
162                                            2,     // number of buffers
163                                            useExternalMemory,
164                                            format);
165     }
166 
167     if (pCamera == nullptr) {
168         LOG(ERROR) << "Failed to allocate new EVS Camera interface for " << evsCameraId;
169         return nullptr;
170     }
171 
172     if (pStreamHandler == nullptr) {
173         LOG(ERROR) << "Failed to allocate FrameHandler";
174         return nullptr;
175     }
176 
177     // Start the video stream
178     if (!pStreamHandler->startStream()) {
179         printf("Couldn't start the camera stream (%s)\n", evsCameraId);
180         LOG(ERROR) << "Start stream failed for " << evsCameraId;
181         return nullptr;
182     }
183 
184     return new VideoTex(pEnum, pCamera, pStreamHandler, glDisplay);
185 }
186