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