165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/* 265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Copyright (C) 2011 The Android Open Source Project 365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Licensed under the Apache License, Version 2.0 (the "License"); 565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * you may not use this file except in compliance with the License. 665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * You may obtain a copy of the License at 765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * http://www.apache.org/licenses/LICENSE-2.0 965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 1065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Unless required by applicable law or agreed to in writing, software 1165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * distributed under the License is distributed on an "AS IS" BASIS, 1265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * See the License for the specific language governing permissions and 1465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * limitations under the License. 1565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 1665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennpackage android.filterpacks.videosrc; 1965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 2065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.content.Context; 2165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.Filter; 2265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FilterContext; 2365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.Frame; 2465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FrameFormat; 2565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FrameManager; 2665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.GenerateFieldPort; 2765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.GenerateFinalPort; 2865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.GLFrame; 2965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.KeyValueMap; 3065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.MutableFrameFormat; 3165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.NativeFrame; 3265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.Program; 3365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.ShaderProgram; 3465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.format.ImageFormat; 3565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.graphics.SurfaceTexture; 3665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.hardware.Camera; 3765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.os.ConditionVariable; 3865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.opengl.Matrix; 3965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 4065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.io.IOException; 4165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.List; 4265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.Set; 4365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 4465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.util.Log; 4565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 4665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/** 4765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * @hide 4865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 4965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennpublic class CameraSource extends Filter { 5065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 5165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** User-visible parameters */ 5265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 5365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Camera ID to use for input. Defaults to 0. */ 5465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "id", hasDefault = true) 5565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private int mCameraId = 0; 5665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 5765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Frame width to request from camera. Actual size may not match requested. */ 5865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "width", hasDefault = true) 5965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private int mWidth = 320; 6065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 6165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Frame height to request from camera. Actual size may not match requested. */ 6265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "height", hasDefault = true) 6365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private int mHeight = 240; 6465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 6565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Stream framerate to request from camera. Actual frame rate may not match requested. */ 6665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "framerate", hasDefault = true) 6765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private int mFps = 30; 6865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 6965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Whether the filter should always wait for a new frame from the camera 7065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * before providing output. If set to false, the filter will keep 7165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * outputting the last frame it received from the camera if multiple process 7265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * calls are received before the next update from the Camera. Defaults to true. 7365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 7465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFinalPort(name = "waitForNewFrame", hasDefault = true) 7565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mWaitForNewFrame = true; 7665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 7765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private Camera mCamera; 7865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private GLFrame mCameraFrame; 7965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private SurfaceTexture mSurfaceTexture; 8065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private ShaderProgram mFrameExtractor; 8165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private MutableFrameFormat mOutputFormat; 8265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 8365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private float[] mCameraTransform; 8465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private float[] mMappedCoords; 8565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // These default source coordinates perform the necessary flip 8665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // for converting from OpenGL origin to MFF/Bitmap origin. 8765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final float[] mSourceCoords = { 0, 1, 0, 1, 8865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 1, 0, 1, 8965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0, 0, 0, 1, 9065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 0, 0, 1 }; 9165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 9265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final int NEWFRAME_TIMEOUT = 100; //ms 9365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final int NEWFRAME_TIMEOUT_REPEAT = 10; 9465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 9565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mNewFrameAvailable; 9665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 9765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private Camera.Parameters mCameraParameters; 9865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 9965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final String mFrameShader = 10065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "#extension GL_OES_EGL_image_external : require\n" + 10165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "precision mediump float;\n" + 10265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "uniform samplerExternalOES tex_sampler_0;\n" + 10365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "varying vec2 v_texcoord;\n" + 10465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "void main() {\n" + 10565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn " gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n" + 10665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "}\n"; 10765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 10865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private final boolean mLogVerbose; 10965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final String TAG = "CameraSource"; 11065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 11165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public CameraSource(String name) { 11265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn super(name); 11365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCameraTransform = new float[16]; 11465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMappedCoords = new float[16]; 11565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 11665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE); 11765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 11865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 11965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 12065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void setupPorts() { 12165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Add input port 12265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn addOutputPort("video", ImageFormat.create(ImageFormat.COLORSPACE_RGBA, 12365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn FrameFormat.TARGET_GPU)); 12465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 12565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 12665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private void createFormats() { 12765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat = ImageFormat.create(mWidth, mHeight, 12865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ImageFormat.COLORSPACE_RGBA, 12965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn FrameFormat.TARGET_GPU); 13065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 13165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 13265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 13365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void prepare(FilterContext context) { 13465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Preparing"); 13565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Compile shader TODO: Move to onGLEnvSomething? 13665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFrameExtractor = new ShaderProgram(context, mFrameShader); 13765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 13865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 13965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 14065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void open(FilterContext context) { 14165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Opening"); 14265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Open camera 14365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCamera = Camera.open(mCameraId); 14465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 14565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Set parameters 14665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn getCameraParameters(); 14765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCamera.setParameters(mCameraParameters); 14865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 14965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Create frame formats 15065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn createFormats(); 15165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 15265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Bind it to our camera frame 15365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCameraFrame = (GLFrame)context.getFrameManager().newBoundFrame(mOutputFormat, 15465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn GLFrame.EXTERNAL_TEXTURE, 15565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0); 15665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture = new SurfaceTexture(mCameraFrame.getTextureId()); 15765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn try { 15865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCamera.setPreviewTexture(mSurfaceTexture); 15965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } catch (IOException e) { 16065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Could not bind camera surface texture: " + 16165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn e.getMessage() + "!"); 16265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 16365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 16465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Connect SurfaceTexture to callback 16565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture.setOnFrameAvailableListener(onCameraFrameAvailableListener); 16665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Start the preview 16765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNewFrameAvailable = false; 16865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCamera.startPreview(); 16965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 17065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 17165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 17265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void process(FilterContext context) { 17365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Processing new frame"); 17465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 17565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mWaitForNewFrame) { 17665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int waitCount = 0; 17765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn while (!mNewFrameAvailable) { 17865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (waitCount == NEWFRAME_TIMEOUT_REPEAT) { 17965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Timeout waiting for new frame"); 18065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 18165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn try { 18265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn this.wait(NEWFRAME_TIMEOUT); 18365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } catch (InterruptedException e) { 18465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Interrupted while waiting for new frame"); 18565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 18665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 18765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNewFrameAvailable = false; 18865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Got new frame"); 18965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 19065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 19165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture.updateTexImage(); 19265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 19365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Using frame extractor in thread: " + Thread.currentThread()); 19465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture.getTransformMatrix(mCameraTransform); 19565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Matrix.multiplyMM(mMappedCoords, 0, 19665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCameraTransform, 0, 19765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSourceCoords, 0); 19865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFrameExtractor.setSourceRegion(mMappedCoords[0], mMappedCoords[1], 19965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMappedCoords[4], mMappedCoords[5], 20065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMappedCoords[8], mMappedCoords[9], 20165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMappedCoords[12], mMappedCoords[13]); 20265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 20365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Frame output = context.getFrameManager().newFrame(mOutputFormat); 20465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFrameExtractor.process(mCameraFrame, output); 20565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 20665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn long timestamp = mSurfaceTexture.getTimestamp(); 20765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Timestamp: " + (timestamp / 1000000000.0) + " s"); 20865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn output.setTimestamp(timestamp); 20965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 21065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn pushOutput("video", output); 21165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 21265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Release pushed frame 21365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn output.release(); 21465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 21565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Done processing new frame"); 21665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 21765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 21865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 21965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void close(FilterContext context) { 22065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Closing"); 22165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 22265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCamera.release(); 22365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCamera = null; 22465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture.release(); 22565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture = null; 22665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 22765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 22865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 22965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void tearDown(FilterContext context) { 23065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mCameraFrame != null) { 23165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCameraFrame.release(); 23265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 23365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 23465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 23565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 23665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void fieldPortValueUpdated(String name, FilterContext context) { 23765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (name.equals("framerate")) { 23865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn getCameraParameters(); 23965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int closestRange[] = findClosestFpsRange(mFps, mCameraParameters); 24065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCameraParameters.setPreviewFpsRange(closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], 24165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); 24265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCamera.setParameters(mCameraParameters); 24365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 24465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 24565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 24665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized public Camera.Parameters getCameraParameters() { 24765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn boolean closeCamera = false; 24865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mCameraParameters == null) { 24965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mCamera == null) { 25065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCamera = Camera.open(mCameraId); 25165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closeCamera = true; 25265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 25365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCameraParameters = mCamera.getParameters(); 25465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 25565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (closeCamera) { 25665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCamera.release(); 25765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCamera = null; 25865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 25965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 26065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 26165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int closestSize[] = findClosestSize(mWidth, mHeight, mCameraParameters); 26265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mWidth = closestSize[0]; 26365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mHeight = closestSize[1]; 26465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCameraParameters.setPreviewSize(mWidth, mHeight); 26565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 26665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int closestRange[] = findClosestFpsRange(mFps, mCameraParameters); 26765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 26865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCameraParameters.setPreviewFpsRange(closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], 26965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); 27065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 27165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return mCameraParameters; 27265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 27365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 27465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Update camera parameters. Image resolution cannot be changed. */ 27565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized public void setCameraParameters(Camera.Parameters params) { 27665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn params.setPreviewSize(mWidth, mHeight); 27765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCameraParameters = params; 27865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (isOpen()) { 27965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCamera.setParameters(mCameraParameters); 28065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 28165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 28265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 28365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private int[] findClosestSize(int width, int height, Camera.Parameters parameters) { 28465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes(); 28565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int closestWidth = -1; 28665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int closestHeight = -1; 28765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int smallestWidth = previewSizes.get(0).width; 28865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int smallestHeight = previewSizes.get(0).height; 28965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (Camera.Size size : previewSizes) { 29065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Best match defined as not being larger in either dimension than 29165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // the requested size, but as close as possible. The below isn't a 29265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // stable selection (reording the size list can give different 29365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // results), but since this is a fallback nicety, that's acceptable. 29465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if ( size.width <= width && 29565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn size.height <= height && 29665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn size.width >= closestWidth && 29765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn size.height >= closestHeight) { 29865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closestWidth = size.width; 29965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closestHeight = size.height; 30065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 30165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if ( size.width < smallestWidth && 30265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn size.height < smallestHeight) { 30365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn smallestWidth = size.width; 30465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn smallestHeight = size.height; 30565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 30665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 30765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (closestWidth == -1) { 30865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Requested size is smaller than any listed size; match with smallest possible 30965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closestWidth = smallestWidth; 31065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closestHeight = smallestHeight; 31165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 31265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 31365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) { 31465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Log.v(TAG, 31565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "Requested resolution: (" + width + ", " + height 31665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn + "). Closest match: (" + closestWidth + ", " 31765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn + closestHeight + ")."); 31865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 31965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int[] closestSize = {closestWidth, closestHeight}; 32065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return closestSize; 32165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 32265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 32365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private int[] findClosestFpsRange(int fps, Camera.Parameters params) { 32465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn List<int[]> supportedFpsRanges = params.getSupportedPreviewFpsRange(); 32565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int[] closestRange = supportedFpsRanges.get(0); 32665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (int[] range : supportedFpsRanges) { 32765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] < fps*1000 && 32865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] > fps*1000 && 32965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] > 33065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] && 33165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] < 33265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]) { 33365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closestRange = range; 33465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 33565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 33665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Requested fps: " + fps 33765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn + ".Closest frame rate range: [" 33865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn + closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] / 1000. 33965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn + "," 34065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn + closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] / 1000. 34165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn + "]"); 34265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 34365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return closestRange; 34465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 34565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 34665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private SurfaceTexture.OnFrameAvailableListener onCameraFrameAvailableListener = 34765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn new SurfaceTexture.OnFrameAvailableListener() { 34865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 34965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void onFrameAvailable(SurfaceTexture surfaceTexture) { 35065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "New frame from camera"); 35165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized(CameraSource.this) { 35265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNewFrameAvailable = true; 35365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn CameraSource.this.notify(); 35465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 35565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 35665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn }; 35765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 35865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 359