package net.ossrs.yasea; import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.ImageFormat; import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.ImageReader; import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.opengl.Matrix; import android.support.v4.app.ActivityCompat; import android.util.AttributeSet; import android.util.Log; import android.util.Range; import android.util.Size; import android.view.Surface; import com.seu.magicfilter.base.gpuimage.GPUImageFilter; import com.seu.magicfilter.utils.MagicFilterFactory; import com.seu.magicfilter.utils.MagicFilterType; import com.seu.magicfilter.utils.OpenGLUtils; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; /** * Created by Leo Ma on 2016/2/25. */ public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Renderer { private final static String TAG = "SrsCameraView"; private GPUImageFilter magicFilter; private SurfaceTexture surfaceTexture; private int mOESTextureId = OpenGLUtils.NO_TEXTURE; private int mSurfaceWidth; private int mSurfaceHeight; private int mPreviewWidth; private int mPreviewHeight; private volatile boolean mIsEncoding; private boolean mIsTorchOn = false; private float mInputAspectRatio; private float mOutputAspectRatio; private float[] mProjectionMatrix = new float[16]; private float[] mSurfaceMatrix = new float[16]; private float[] mTransformMatrix = new float[16]; private ByteBuffer mGLPreviewBuffer; private int mCamId = -1; private int mPreviewRotation = 90; private int mPreviewOrientation = Configuration.ORIENTATION_PORTRAIT; private Thread worker; private final Object writeLock = new Object(); private ConcurrentLinkedQueue mGLIntBufferCache = new ConcurrentLinkedQueue<>(); private PreviewCallback mPrevCb; private CameraCallbacksHandler cameraCallbacksHandler = new CameraCallbacksHandler(); private CameraDevice mCameraDevice;//摄像头设备 private Size imageDimension; private ImageReader imageReader; private CaptureRequest.Builder captureRequestBuilder; private CameraCaptureSession cameraCaptureSession; private CameraManager cameraManager;//摄像头管理类 private String[] cameraNames;//摄像头名称列表 private CameraItemData curItem;//当前选中的摄像头参数 private ArrayList itemlist = new ArrayList<>(); public SrsCameraView(Context context) { this(context, null); } public SrsCameraView(Context context, AttributeSet attrs) { super(context, attrs); setEGLContextClientVersion(2); setRenderer(this); setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); initCameraData(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { int cameraid = 0; GLES20.glDisable(GL10.GL_DITHER); GLES20.glClearColor(0, 0, 0, 0); String id = curItem.getId(); magicFilter = new GPUImageFilter(MagicFilterType.NONE); try { cameraid = Integer.parseInt(id); } catch (Exception e) { cameraid = 0; } magicFilter.setOrtation(cameraid); magicFilter.init(getContext().getApplicationContext()); magicFilter.onInputSizeChanged(mPreviewWidth, mPreviewHeight); mOESTextureId = OpenGLUtils.getExternalOESTextureID(); surfaceTexture = new SurfaceTexture(mOESTextureId); surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() { @Override public void onFrameAvailable(SurfaceTexture surfaceTexture) { requestRender(); } }); // For camera preview on activity creation } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { GLES20.glViewport(0, 0, width, height); mSurfaceWidth = width; mSurfaceHeight = height; magicFilter.onDisplaySizeChanged(width, height); magicFilter.onInputSizeChanged(mPreviewWidth, mPreviewHeight); mOutputAspectRatio = width > height ? (float) width / height : (float) height / width; float aspectRatio = mOutputAspectRatio / mInputAspectRatio; if (width > height) { Matrix.orthoM(mProjectionMatrix, 0, -1.0f, 1.0f, -aspectRatio, aspectRatio, -1.0f, 1.0f); } else { Matrix.orthoM(mProjectionMatrix, 0, -aspectRatio, aspectRatio, -1.0f, 1.0f, -1.0f, 1.0f); } } @Override public void onDrawFrame(GL10 gl) { if (mSurfaceWidth != mPreviewWidth || mSurfaceHeight != mPreviewHeight) { Log.e(TAG, String.format("Surface dimensions differ from Preview. May be a buffer overflow. Surface: %dx%d, Preview: %dx%d ", mSurfaceWidth, mSurfaceHeight, mPreviewWidth, mPreviewHeight)); return; } //清除屏幕颜色缓冲区 GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); surfaceTexture.updateTexImage(); surfaceTexture.getTransformMatrix(mSurfaceMatrix); Matrix.multiplyMM(mTransformMatrix, 0, mSurfaceMatrix, 0, mProjectionMatrix, 0); magicFilter.setTextureTransformMatrix(mTransformMatrix); magicFilter.onDrawFrame(mOESTextureId); if (mIsEncoding) { mGLIntBufferCache.add(magicFilter.getGLFboBuffer()); synchronized (writeLock) { writeLock.notifyAll(); } } } public void setPreviewCallback(PreviewCallback cb) { mPrevCb = cb; } //选择sizeMap中大于并且接近width和height的size private Size getOptimalSize(Size[] outputSizes, int width, int height) { Size tempSize = new Size(width, height); List sizes = new ArrayList<>(); for (Size outputSize : outputSizes) { if (width > height) { //横屏的时候 if (outputSize.getHeight() > height && outputSize.getWidth() > width) { sizes.add(outputSize); } } else { //竖屏的时候 if (outputSize.getWidth() > height && outputSize.getHeight() > width) { sizes.add(outputSize); } } } if (sizes.size() > 0) { //如果有多个符合条件找到一个差距最小的,最接近预览分辨率的 tempSize = sizes.get(0); int minnum = 999999; for (Size size : sizes) { int num = size.getHeight() * size.getHeight() - width * height; if (num < minnum) { minnum = num; tempSize = size; } } } return tempSize; /*if (sizes.size() > 0) { return Collections.min(sizes, new Comparator() { @Override public int compare(Size size, Size t1) { return Long.signum(size.getWidth() * size.getHeight() - t1.getWidth() * t1.getHeight()); } }); } return outputSizes[0];*/ } public int[] setPreviewResolution(int width, int height) { mPreviewWidth = width; mPreviewHeight = height; getHolder().setFixedSize(mPreviewWidth, mPreviewHeight); mGLPreviewBuffer = ByteBuffer.allocate(mPreviewWidth * mPreviewHeight * 4); mInputAspectRatio = mPreviewWidth > mPreviewHeight ? (float) mPreviewWidth / mPreviewHeight : (float) mPreviewHeight / mPreviewWidth; return new int[]{mPreviewWidth, mPreviewHeight}; } public boolean setFilter(final MagicFilterType type) { queueEvent(new Runnable() { @Override public void run() { if (magicFilter != null) { magicFilter.destroy(); } magicFilter = MagicFilterFactory.initFilters(type); if (magicFilter != null) { magicFilter.init(getContext().getApplicationContext()); magicFilter.onInputSizeChanged(mPreviewWidth, mPreviewHeight); magicFilter.onDisplaySizeChanged(mSurfaceWidth, mSurfaceHeight); } } }); requestRender(); return true; } private void deleteTextures() { if (mOESTextureId != OpenGLUtils.NO_TEXTURE) { queueEvent(new Runnable() { @Override public void run() { GLES20.glDeleteTextures(1, new int[]{mOESTextureId}, 0); mOESTextureId = OpenGLUtils.NO_TEXTURE; } }); } } public void setCameraId(CameraItemData item) { stopTorch(); curItem = item; setPreviewOrientation(mPreviewOrientation); } protected int getRotateDeg() { try { int rotate = ((Activity) getContext()).getWindowManager().getDefaultDisplay().getRotation(); switch (rotate) { case Surface.ROTATION_0: return 0; case Surface.ROTATION_90: return 90; case Surface.ROTATION_180: return 180; case Surface.ROTATION_270: return 270; } } catch (Exception e) { e.printStackTrace(); } return -1; } public void setPreviewOrientation(int orientation) { mPreviewOrientation = orientation; } public int getCameraId() { return mCamId; } public void enableEncoding() { worker = new Thread(new Runnable() { @Override public void run() { while (!Thread.interrupted()) { while (!mGLIntBufferCache.isEmpty()) { try { IntBuffer picture = mGLIntBufferCache.poll(); mGLPreviewBuffer.asIntBuffer().put(picture.array()); mPrevCb.onGetRgbaFrame(mGLPreviewBuffer.array(), mPreviewWidth, mPreviewHeight); } catch (Exception e) { cameraCallbacksHandler.onError(e); e.printStackTrace(); worker.interrupt(); break; } } // Waiting for next frame synchronized (writeLock) { try { // isEmpty() may take some time, so we set timeout to detect next frame writeLock.wait(500); } catch (InterruptedException ie) { worker.interrupt(); } } } } }); worker.start(); mIsEncoding = true; } public void disableEncoding() { mIsEncoding = false; mGLIntBufferCache.clear(); if (mGLPreviewBuffer != null) { mGLPreviewBuffer.clear(); } if (worker != null) { worker.interrupt(); try { worker.join(); } catch (InterruptedException e) { e.printStackTrace(); worker.interrupt(); } worker = null; } } //相机状态变化时会调用这里的回调函数 private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { //相机打开时执行 Log.e(TAG, "onOpened"); mCameraDevice = camera; //创建相机预览会话 createCameraPreviewSession(); } @Override public void onDisconnected(CameraDevice camera) { //相机链接断开 Log.e("dsdsfd", "fdsdf"); } @Override public void onError(CameraDevice camera, int error) { Log.e("dsdsfd", "fdsdf"); } }; private void createCameraPreviewSession() { // SurfaceTexture surfaceTexture=new SurfaceTexture(); // assert surfaceTexture!=null; // surfaceTexture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight()); //预览的输出画面 Surface surface = new Surface(surfaceTexture); try { //预览请求 captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureRequestBuilder.addTarget(surface); mCameraDevice.createCaptureSession(Arrays.asList(surface, imageReader.getSurface()), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { if (mCameraDevice == null) { return; } cameraCaptureSession = session; updatePreview(); } @Override public void onConfigureFailed(CameraCaptureSession session) { Log.e("dkkd", "fdsa"); } }, null); } catch (CameraAccessException e) { throw new RuntimeException(e); } } private void updatePreview() { captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); CaptureRequest captureRequest = captureRequestBuilder.build(); try { cameraCaptureSession.setRepeatingRequest(captureRequest, null, null); } catch (CameraAccessException e) { throw new RuntimeException(e); } } public void startCamera() { try { if (curItem == null) { curItem = itemlist.get(0); } //通过cameraId获取Camera参数 String cameraId = curItem.getId(); CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); imageDimension = map.getOutputSizes(SurfaceTexture.class)[0]; imageReader = ImageReader.newInstance(640, 480, ImageFormat.YUV_420_888, 10); // imageReader.setOnImageAvailableListener(onImageAvailableListener,null); if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { return; } cameraManager.openCamera(cameraId, stateCallback, null); } catch (CameraAccessException e) { throw new RuntimeException(e); } } public void stopCamera() { disableEncoding(); stopTorch(); if (cameraCaptureSession != null) { cameraCaptureSession.close(); cameraCaptureSession = null; } if (mCameraDevice != null) { mCameraDevice.close(); mCameraDevice = null; } } public List initCameraData() { itemlist = new ArrayList(); cameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);//获取摄像头管理类 try { cameraNames = cameraManager.getCameraIdList();//获取摄像头名称列表 } catch (CameraAccessException e) { throw new RuntimeException(e); } for (String cameraName : cameraNames) { CameraItemData itemData = new CameraItemData(); itemData.setId(cameraName);//摄像头编号 CameraCharacteristics characteristics = null; try { characteristics = cameraManager.getCameraCharacteristics(cameraName);//获取摄像头各种特性 } catch (CameraAccessException e) { throw new RuntimeException(e); } int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); itemData.setSensorOrientation(sensorOrientation);//摄像头朝向 Range[] ranges = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); itemData.setFPS_RANGES(ranges);// Long aLong = characteristics.get(CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION); itemData.setMAX_FRAME_DURATION(aLong); int lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING); itemData.setLENS_FACING(lensFacing); switch (lensFacing) { case CameraMetadata.LENS_FACING_FRONT: Log.e("lensFacing(前后摄):", "front"); break; case CameraMetadata.LENS_FACING_BACK: Log.e("lensFacing(前后摄):", "back"); break; case CameraMetadata.LENS_FACING_EXTERNAL: Log.e("lensFacing(前后摄):", "external"); break; } List list = new ArrayList<>(); Size[] supportedSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.YUV_420_888); for (Size size : supportedSizes) { int width = size.getWidth(); int height = size.getHeight(); // 在这里处理支持的分辨率格式 int[] temp = {width, height}; list.add(temp); } itemData.setSupportedSizes(list);//摄像头输出格式 itemlist.add(itemData); } return itemlist; } public List getCameraData() { return itemlist; } private int[] adaptFpsRange(int expectedFps, List fpsRanges) { expectedFps *= 1000; int[] closestRange = fpsRanges.get(0); int measure = Math.abs(closestRange[0] - expectedFps) + Math.abs(closestRange[1] - expectedFps); for (int[] range : fpsRanges) { if (range[0] <= expectedFps && range[1] >= expectedFps) { int curMeasure = Math.abs(range[0] - expectedFps) + Math.abs(range[1] - expectedFps); if (curMeasure < measure) { closestRange = range; measure = curMeasure; } } } return closestRange; } public void setOrtation(int cameraid) { magicFilter.setOrtation(cameraid); } public void stopTorch() { // if (mCamera != null) { // try { // Camera.Parameters params = mCamera.getParameters(); // params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); // mCamera.setParameters(params); // } catch (Exception e) { // e.printStackTrace(); // } // } } public interface PreviewCallback { void onGetRgbaFrame(byte[] data, int width, int height); } static public class CameraCallbacksHandler implements CameraCallbacks { @Override public void onCameraParameters(Camera.Parameters params) { } @Override public void onError(Exception e) { //stop publish } } public interface CameraCallbacks { void onCameraParameters(Camera.Parameters params); void onError(Exception e); } public void setCameraCallbacksHandler(CameraCallbacksHandler cameraCallbacksHandler) { this.cameraCallbacksHandler = cameraCallbacksHandler; } }