1150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph/*
2150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * Copyright (C) 2017 The Android Open Source Project
3150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph *
4150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * Licensed under the Apache License, Version 2.0 (the "License");
5150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * you may not use this file except in compliance with the License.
6150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * You may obtain a copy of the License at
7150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph *
8150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph *      http://www.apache.org/licenses/LICENSE-2.0
9150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph *
10150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * Unless required by applicable law or agreed to in writing, software
11150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * distributed under the License is distributed on an "AS IS" BASIS,
12150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * See the License for the specific language governing permissions and
14150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * limitations under the License.
15150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph */
16150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include <vector>
17150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include <stdio.h>
18150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include <fcntl.h>
19150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include <alloca.h>
20150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include <unistd.h>
21150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include <sys/ioctl.h>
22150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include <malloc.h>
23150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include <png.h>
24150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
25150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include "VideoTex.h"
26150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include "glError.h"
27150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
28150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include <ui/GraphicBuffer.h>
29150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
30150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph// Eventually we shouldn't need this dependency, but for now the
31150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph// graphics allocator interface isn't fully supported on all platforms
32150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph// and this is our work around.
33150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolphusing ::android::GraphicBuffer;
34150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
35150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
36150c580464a7a4d6b0ad3362f23f790ded65e7abScott RandolphVideoTex::VideoTex(sp<IEvsEnumerator> pEnum,
37150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                   sp<IEvsCamera> pCamera,
38150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                   sp<StreamHandler> pStreamHandler,
39150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                   EGLDisplay glDisplay)
40150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    : TexWrapper()
41150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    , mEnumerator(pEnum)
42150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    , mCamera(pCamera)
43150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    , mStreamHandler(pStreamHandler)
44150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    , mDisplay(glDisplay) {
45150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Nothing but initialization here...
46150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph}
47150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
48150c580464a7a4d6b0ad3362f23f790ded65e7abScott RandolphVideoTex::~VideoTex() {
49150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Tell the stream to stop flowing
50150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    mStreamHandler->asyncStopStream();
51150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
52150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Close the camera
53150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    mEnumerator->closeCamera(mCamera);
54150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
55150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Drop our device texture image
56150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (mKHRimage != EGL_NO_IMAGE_KHR) {
57150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        eglDestroyImageKHR(mDisplay, mKHRimage);
58150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        mKHRimage = EGL_NO_IMAGE_KHR;
59150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
60150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph}
61150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
62150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
63150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph// Return true if the texture contents are changed
64150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolphbool VideoTex::refresh() {
65150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (!mStreamHandler->newFrameAvailable()) {
66150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        // No new image has been delivered, so there's nothing to do here
67150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return false;
68150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
69150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
70150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // If we already have an image backing us, then it's time to return it
71150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (mImageBuffer.memHandle.getNativeHandle() != nullptr) {
72150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        // Drop our device texture image
73150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        if (mKHRimage != EGL_NO_IMAGE_KHR) {
74150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph            eglDestroyImageKHR(mDisplay, mKHRimage);
75150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph            mKHRimage = EGL_NO_IMAGE_KHR;
76150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        }
77150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
78150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        // Return it since we're done with it
79150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        mStreamHandler->doneWithFrame(mImageBuffer);
80150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
81150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
82150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Get the new image we want to use as our contents
83150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    mImageBuffer = mStreamHandler->getNewFrame();
84150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
85150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
86150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // create a GraphicBuffer from the existing handle
87150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(mImageBuffer.memHandle,
88150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                                     GraphicBuffer::CLONE_HANDLE,
89150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                                     mImageBuffer.width, mImageBuffer.height,
90150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                                     mImageBuffer.format, 1, // layer count
91150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                                     GRALLOC_USAGE_HW_TEXTURE,
92150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                                     mImageBuffer.stride);
93150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (pGfxBuffer.get() == nullptr) {
94150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
95150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        // Returning "true" in this error condition because we already released the
96150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        // previous image (if any) and so the texture may change in unpredictable ways now!
97150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return true;
98150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
99150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
100150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Get a GL compatible reference to the graphics buffer we've been given
101150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
102150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
103150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    mKHRimage = eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT,
104150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
105150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                  eglImageAttributes);
106150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (mKHRimage == EGL_NO_IMAGE_KHR) {
107150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        const char *msg = getEGLError();
108150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("error creating EGLImage: %s", msg);
109150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    } else {
110150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        // Update the texture handle we already created to refer to this gralloc buffer
111150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        glActiveTexture(GL_TEXTURE0);
112150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        glBindTexture(GL_TEXTURE_2D, glId());
113150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(mKHRimage));
114150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
115150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        // Initialize the sampling properties (it seems the sample may not work if this isn't done)
116150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        // The user of this texture may very well want to set their own filtering, but we're going
117150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        // to pay the (minor) price of setting this up for them to avoid the dreaded "black image"
118150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        // if they forget.
119150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        // TODO:  Can we do this once for the texture ID rather than ever refresh?
120150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
121150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
122150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
123150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
124150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
125150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
126150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    return true;
127150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph}
128150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
129150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
130150c580464a7a4d6b0ad3362f23f790ded65e7abScott RandolphVideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
131150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                             const char* evsCameraId,
132150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                             EGLDisplay glDisplay) {
133150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Set up the camera to feed this texture
134150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    sp<IEvsCamera> pCamera = pEnum->openCamera(evsCameraId);
135150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (pCamera.get() == nullptr) {
136150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("Failed to allocate new EVS Camera interface for %s", evsCameraId);
137150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return nullptr;
138150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
139150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
140150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Initialize the stream that will help us update this texture's contents
141150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    sp<StreamHandler> pStreamHandler = new StreamHandler(pCamera);
142150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (pStreamHandler.get() == nullptr) {
143150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("failed to allocate FrameHandler");
144150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return nullptr;
145150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
146150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
147150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Start the video stream
148150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (!pStreamHandler->startStream()) {
149150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        printf("Couldn't start the camera stream (%s)\n", evsCameraId);
150150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("start stream failed for %s", evsCameraId);
151150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return nullptr;
152150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
153150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
154150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    return new VideoTex(pEnum, pCamera, pStreamHandler, glDisplay);
155150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph}
156