14a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala/* 24a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * Copyright (C) 2011 The Android Open Source Project 34a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * 44a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * Licensed under the Apache License, Version 2.0 (the "License"); 54a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * you may not use this file except in compliance with the License. 64a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * You may obtain a copy of the License at 74a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * 84a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * http://www.apache.org/licenses/LICENSE-2.0 94a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * 104a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * Unless required by applicable law or agreed to in writing, software 114a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * distributed under the License is distributed on an "AS IS" BASIS, 124a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * See the License for the specific language governing permissions and 144a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * limitations under the License. 154a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala */ 164a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 174a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 184a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalapackage android.filterpacks.videosrc; 194a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 204a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.content.Context; 214a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.Filter; 224a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.FilterContext; 234a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.Frame; 244a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.FrameFormat; 254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.FrameManager; 2621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport android.filterfw.core.GenerateFieldPort; 2721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport android.filterfw.core.GenerateFinalPort; 2821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport android.filterfw.core.GLFrame; 294a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.KeyValueMap; 304a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.MutableFrameFormat; 314a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.NativeFrame; 324a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.Program; 334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.ShaderProgram; 3421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport android.filterfw.format.ImageFormat; 354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.graphics.SurfaceTexture; 364a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.hardware.Camera; 374a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.os.ConditionVariable; 38855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvalaimport android.opengl.Matrix; 394a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 404a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.io.IOException; 414a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.util.List; 424a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.util.Set; 434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.util.Log; 454a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 46a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala/** 47a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala * @hide 48a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala */ 494a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalapublic class CameraSource extends Filter { 504a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 514a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala /** User-visible parameters */ 524a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 534a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala /** Camera ID to use for input. Defaults to 0. */ 5421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn @GenerateFieldPort(name = "id", hasDefault = true) 554a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private int mCameraId = 0; 564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala /** Frame width to request from camera. Actual size may not match requested. */ 5821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn @GenerateFieldPort(name = "width", hasDefault = true) 594a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private int mWidth = 320; 604a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 614a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala /** Frame height to request from camera. Actual size may not match requested. */ 6221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn @GenerateFieldPort(name = "height", hasDefault = true) 634a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private int mHeight = 240; 644a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 654a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala /** Stream framerate to request from camera. Actual frame rate may not match requested. */ 6621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn @GenerateFieldPort(name = "framerate", hasDefault = true) 674a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private int mFps = 30; 684a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 694a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala /** Whether the filter should always wait for a new frame from the camera 704a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * before providing output. If set to false, the filter will keep 714a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * outputting the last frame it received from the camera if multiple process 724a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * calls are received before the next update from the Camera. Defaults to true. 734a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala */ 7421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn @GenerateFinalPort(name = "waitForNewFrame", hasDefault = true) 754a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private boolean mWaitForNewFrame = true; 764a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 774a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private Camera mCamera; 784a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private GLFrame mCameraFrame; 794a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private SurfaceTexture mSurfaceTexture; 804a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private ShaderProgram mFrameExtractor; 814a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private MutableFrameFormat mOutputFormat; 82855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala 834a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private float[] mCameraTransform; 84855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala private float[] mMappedCoords; 85855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala // These default source coordinates perform the necessary flip 86855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala // for converting from OpenGL origin to MFF/Bitmap origin. 87855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala private static final float[] mSourceCoords = { 0, 1, 0, 1, 88855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala 1, 1, 0, 1, 89855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala 0, 0, 0, 1, 90855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala 1, 0, 0, 1 }; 914a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 92e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala private static final int NEWFRAME_TIMEOUT = 100; //ms 93e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala private static final int NEWFRAME_TIMEOUT_REPEAT = 10; 94e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala 95e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala private boolean mNewFrameAvailable; 96e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala 9724455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala private Camera.Parameters mCameraParameters; 9824455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala 9921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn private static final String mFrameShader = 1004a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala "#extension GL_OES_EGL_image_external : require\n" + 1014a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala "precision mediump float;\n" + 1024a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala "uniform samplerExternalOES tex_sampler_0;\n" + 1034a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala "varying vec2 v_texcoord;\n" + 1044a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala "void main() {\n" + 105855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala " gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n" + 1064a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala "}\n"; 1074a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 1088dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala private final boolean mLogVerbose; 1094a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private static final String TAG = "CameraSource"; 1104a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 1114a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala public CameraSource(String name) { 1124a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala super(name); 1134a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala mCameraTransform = new float[16]; 114855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala mMappedCoords = new float[16]; 11557774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala 11657774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE); 1174a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 1184a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 1194a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala @Override 12021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn public void setupPorts() { 12121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn // Add input port 12221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn addOutputPort("video", ImageFormat.create(ImageFormat.COLORSPACE_RGBA, 12321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn FrameFormat.TARGET_GPU)); 1244a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 1254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 12621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn private void createFormats() { 12721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn mOutputFormat = ImageFormat.create(mWidth, mHeight, 12821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn ImageFormat.COLORSPACE_RGBA, 12921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn FrameFormat.TARGET_GPU); 1304a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 1314a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 1324a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala @Override 1334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala public void prepare(FilterContext context) { 13457774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala if (mLogVerbose) Log.v(TAG, "Preparing"); 1354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala // Compile shader TODO: Move to onGLEnvSomething? 136511360e61650864ea22a171159efe073c80d0cdbMarius Renn mFrameExtractor = new ShaderProgram(context, mFrameShader); 1374a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 1384a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 1394a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala @Override 14021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn public void open(FilterContext context) { 14157774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala if (mLogVerbose) Log.v(TAG, "Opening"); 1424a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala // Open camera 1434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala mCamera = Camera.open(mCameraId); 1444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 1454a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala // Set parameters 14624455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala getCameraParameters(); 14724455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala mCamera.setParameters(mCameraParameters); 1484a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 14921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn // Create frame formats 15021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn createFormats(); 15121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn 1524a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala // Bind it to our camera frame 153edfc0941e7a9480d2bbc70e842015e6fa56a2c3fEddy Talvala mCameraFrame = (GLFrame)context.getFrameManager().newBoundFrame(mOutputFormat, 154edfc0941e7a9480d2bbc70e842015e6fa56a2c3fEddy Talvala GLFrame.EXTERNAL_TEXTURE, 155edfc0941e7a9480d2bbc70e842015e6fa56a2c3fEddy Talvala 0); 1564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala mSurfaceTexture = new SurfaceTexture(mCameraFrame.getTextureId()); 1574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala try { 1584a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala mCamera.setPreviewTexture(mSurfaceTexture); 1594a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } catch (IOException e) { 1604a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala throw new RuntimeException("Could not bind camera surface texture: " + 1614a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala e.getMessage() + "!"); 1624a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 1634a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 1644a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala // Connect SurfaceTexture to callback 1654a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala mSurfaceTexture.setOnFrameAvailableListener(onCameraFrameAvailableListener); 1664a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala // Start the preview 167e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala mNewFrameAvailable = false; 1684a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala mCamera.startPreview(); 1694a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 1704a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 1714a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala @Override 17221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn public void process(FilterContext context) { 17357774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala if (mLogVerbose) Log.v(TAG, "Processing new frame"); 1744a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 1754a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala if (mWaitForNewFrame) { 176e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala int waitCount = 0; 177e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala while (!mNewFrameAvailable) { 178e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala if (waitCount == NEWFRAME_TIMEOUT_REPEAT) { 179e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala throw new RuntimeException("Timeout waiting for new frame"); 180e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala } 181e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala try { 182e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala this.wait(NEWFRAME_TIMEOUT); 183e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala } catch (InterruptedException e) { 184e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala if (mLogVerbose) Log.v(TAG, "Interrupted while waiting for new frame"); 185e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala } 1864a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 187e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala mNewFrameAvailable = false; 188e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala if (mLogVerbose) Log.v(TAG, "Got new frame"); 1894a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 1904a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 1914a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala mSurfaceTexture.updateTexImage(); 1924a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 19357774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala if (mLogVerbose) Log.v(TAG, "Using frame extractor in thread: " + Thread.currentThread()); 1944a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala mSurfaceTexture.getTransformMatrix(mCameraTransform); 195855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala Matrix.multiplyMM(mMappedCoords, 0, 196855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala mCameraTransform, 0, 197855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala mSourceCoords, 0); 198855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala mFrameExtractor.setSourceRegion(mMappedCoords[0], mMappedCoords[1], 199855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala mMappedCoords[4], mMappedCoords[5], 200855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala mMappedCoords[8], mMappedCoords[9], 201855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala mMappedCoords[12], mMappedCoords[13]); 2024a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 2034a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala Frame output = context.getFrameManager().newFrame(mOutputFormat); 2044a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala mFrameExtractor.process(mCameraFrame, output); 2054a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 2068dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala long timestamp = mSurfaceTexture.getTimestamp(); 2078dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala if (mLogVerbose) Log.v(TAG, "Timestamp: " + (timestamp / 1000000000.0) + " s"); 2088dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala output.setTimestamp(timestamp); 2098dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala 21021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn pushOutput("video", output); 2114a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 2124a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala // Release pushed frame 2134a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala output.release(); 2144a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 21557774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala if (mLogVerbose) Log.v(TAG, "Done processing new frame"); 2164a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 2174a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 2184a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala @Override 2194a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala public void close(FilterContext context) { 22057774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala if (mLogVerbose) Log.v(TAG, "Closing"); 2214a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 2224a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala mCamera.release(); 22324455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala mCamera = null; 224aae596d15186de172632499692d44bc5436108f7Eino-Ville Talvala mSurfaceTexture.release(); 2254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala mSurfaceTexture = null; 2264a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 2274a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 2284a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala @Override 2294a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala public void tearDown(FilterContext context) { 2304a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala if (mCameraFrame != null) { 2314a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala mCameraFrame.release(); 2324a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 2334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 2344a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 2354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala @Override 23621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn public void fieldPortValueUpdated(String name, FilterContext context) { 23721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn if (name.equals("framerate")) { 23824455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala getCameraParameters(); 23924455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala int closestRange[] = findClosestFpsRange(mFps, mCameraParameters); 24024455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala mCameraParameters.setPreviewFpsRange(closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], 24124455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); 24224455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala mCamera.setParameters(mCameraParameters); 2434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 2444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 2454a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 24624455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala synchronized public Camera.Parameters getCameraParameters() { 2479aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala boolean closeCamera = false; 24824455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala if (mCameraParameters == null) { 24924455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala if (mCamera == null) { 25024455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala mCamera = Camera.open(mCameraId); 25124455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala closeCamera = true; 25224455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala } 25324455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala mCameraParameters = mCamera.getParameters(); 25424455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala 25524455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala if (closeCamera) { 25624455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala mCamera.release(); 25724455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala mCamera = null; 25824455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala } 25924455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala } 2609aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala 2619aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala int closestSize[] = findClosestSize(mWidth, mHeight, mCameraParameters); 2629aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala mWidth = closestSize[0]; 2639aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala mHeight = closestSize[1]; 2649aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala mCameraParameters.setPreviewSize(mWidth, mHeight); 2659aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala 2669aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala int closestRange[] = findClosestFpsRange(mFps, mCameraParameters); 2679aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala 2689aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala mCameraParameters.setPreviewFpsRange(closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], 2699aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); 2709aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala 27124455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala return mCameraParameters; 2724a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 2734a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 2744a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala /** Update camera parameters. Image resolution cannot be changed. */ 27524455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala synchronized public void setCameraParameters(Camera.Parameters params) { 2764a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala params.setPreviewSize(mWidth, mHeight); 27724455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala mCameraParameters = params; 27824455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala if (isOpen()) { 27924455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala mCamera.setParameters(mCameraParameters); 28024455ce2cc781f52c2171d0b388314393d4f7111Eino-Ville Talvala } 2814a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 2824a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 2839aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala private int[] findClosestSize(int width, int height, Camera.Parameters parameters) { 2849aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes(); 2859aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala int closestWidth = -1; 2869aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala int closestHeight = -1; 2879aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala int smallestWidth = previewSizes.get(0).width; 2889aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala int smallestHeight = previewSizes.get(0).height; 2899aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala for (Camera.Size size : previewSizes) { 2909aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala // Best match defined as not being larger in either dimension than 2919aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala // the requested size, but as close as possible. The below isn't a 2929aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala // stable selection (reording the size list can give different 2939aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala // results), but since this is a fallback nicety, that's acceptable. 294277939c4df0abdadfef5ff19b4b33480bd9a0c20Eino-Ville Talvala if ( size.width <= width && 295277939c4df0abdadfef5ff19b4b33480bd9a0c20Eino-Ville Talvala size.height <= height && 2969aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala size.width >= closestWidth && 2979aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala size.height >= closestHeight) { 2989aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala closestWidth = size.width; 2999aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala closestHeight = size.height; 3009aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala } 3019aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala if ( size.width < smallestWidth && 3029aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala size.height < smallestHeight) { 3039aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala smallestWidth = size.width; 3049aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala smallestHeight = size.height; 3059aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala } 3069aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala } 3079aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala if (closestWidth == -1) { 3089aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala // Requested size is smaller than any listed size; match with smallest possible 3099aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala closestWidth = smallestWidth; 3109aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala closestHeight = smallestHeight; 3119aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala } 3129aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala 3139aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala if (mLogVerbose) { 3149aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala Log.v(TAG, 3159aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala "Requested resolution: (" + width + ", " + height 3169aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala + "). Closest match: (" + closestWidth + ", " 3179aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala + closestHeight + ")."); 3189aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala } 3199aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala int[] closestSize = {closestWidth, closestHeight}; 3209aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala return closestSize; 3219aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala } 3229aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala 3234a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private int[] findClosestFpsRange(int fps, Camera.Parameters params) { 3244a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala List<int[]> supportedFpsRanges = params.getSupportedPreviewFpsRange(); 3254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala int[] closestRange = supportedFpsRanges.get(0); 3264a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala for (int[] range : supportedFpsRanges) { 3274a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala if (range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] < fps*1000 && 3284a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] > fps*1000 && 3294a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] > 3304a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] && 3314a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] < 3324a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]) { 3334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala closestRange = range; 3344a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 3354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 3369aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala if (mLogVerbose) Log.v(TAG, "Requested fps: " + fps 3379aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala + ".Closest frame rate range: [" 3389aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala + closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] / 1000. 3399aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala + "," 3409aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala + closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] / 1000. 3419aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala + "]"); 3429aeeed4a7a5ab115727a0545ea343dcc4f966851Eino-Ville Talvala 3434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala return closestRange; 3444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 3454a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 3464a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala private SurfaceTexture.OnFrameAvailableListener onCameraFrameAvailableListener = 3474a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala new SurfaceTexture.OnFrameAvailableListener() { 34833d107bf315c9cc01a02a7a4a2c10a01f62e8c85Wei Hua @Override 3494a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala public void onFrameAvailable(SurfaceTexture surfaceTexture) { 35057774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala if (mLogVerbose) Log.v(TAG, "New frame from camera"); 351e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala synchronized(CameraSource.this) { 352e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala mNewFrameAvailable = true; 353e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala CameraSource.this.notify(); 354e23bf25c468aec0e8a12746c56edcf6a8ff68aedEino-Ville Talvala } 3554a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala } 3564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala }; 3574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala 3584a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala} 359