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