From 13a9f9458f5c81b91ec56f224bfa10c540453ab2 Mon Sep 17 00:00:00 2001 From: Matthew Date: Wed, 23 Oct 2024 11:10:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6camera2=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 3 + .../java/com/xypower/mplive/MainActivity.java | 64 +-- app/src/main/res/values/colors.xml | 5 + app/src/main/res/values/strings.xml | 4 + app/src/main/res/values/styles.xml | 9 + app/src/main/res/values/themes.xml | 10 + build.gradle | 2 + library/src/main/AndroidManifest.xml | 1 + .../java/net/ossrs/yasea/CameraItemData.java | 63 +++ .../main/java/net/ossrs/yasea/CameraView.java | 258 ++++++++++ .../java/net/ossrs/yasea/SrsCameraView.java | 452 ++++++++++-------- .../java/net/ossrs/yasea/SrsPublisher.java | 42 +- 12 files changed, 662 insertions(+), 251 deletions(-) create mode 100644 app/src/main/res/values/themes.xml create mode 100644 library/src/main/java/net/ossrs/yasea/CameraItemData.java create mode 100644 library/src/main/java/net/ossrs/yasea/CameraView.java diff --git a/app/build.gradle b/app/build.gradle index 22439f2..d1754ae 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,6 +30,9 @@ android { signingConfig signingConfigs.config } } + buildFeatures { + viewBinding true + } } diff --git a/app/src/main/java/com/xypower/mplive/MainActivity.java b/app/src/main/java/com/xypower/mplive/MainActivity.java index acf1d40..9a497e8 100644 --- a/app/src/main/java/com/xypower/mplive/MainActivity.java +++ b/app/src/main/java/com/xypower/mplive/MainActivity.java @@ -28,6 +28,7 @@ import com.dev.devapi.api.SysApi; import com.github.faucamp.simplertmp.RtmpHandler; import com.seu.magicfilter.utils.MagicFilterType; +import net.ossrs.yasea.CameraItemData; import net.ossrs.yasea.SrsCameraView; import net.ossrs.yasea.SrsEncodeHandler; import net.ossrs.yasea.SrsPublisher; @@ -35,10 +36,11 @@ import net.ossrs.yasea.SrsRecordHandler; import java.io.IOException; import java.net.SocketException; +import java.util.List; import java.util.Random; public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpListener, - SrsRecordHandler.SrsRecordListener, SrsEncodeHandler.SrsEncodeListener { + SrsRecordHandler.SrsRecordListener, SrsEncodeHandler.SrsEncodeListener { private static final String TAG = "MpLive"; public final static int RC_CAMERA = 100; @@ -50,7 +52,8 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL private Button btnPause; private SharedPreferences sp; - private String rtmpUrl = "rtmp://192.168.50.250/live/0"; + // private String rtmpUrl = "rtmp://192.168.50.250/live/0"; + private String rtmpUrl = "rtmp://61.169.135.146/live/abcd"; private String recPath = Environment.getExternalStorageDirectory().getPath() + "/test.mp4"; private SrsPublisher mPublisher; @@ -61,22 +64,19 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL private boolean isPermissionGranted = false; private Handler mHandler; + private int cameraId = 0; + private List cameraData; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mHandler = new Handler(); - SysApi.setCam3V3Enable(true); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); setContentView(R.layout.activity_main); - // response screen rotation event setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); - requestPermission(); } @@ -89,7 +89,7 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL //2. 权限没有开启,请求权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE}, RC_CAMERA); - }else{ + } else { //权限已经开启,做相应事情 isPermissionGranted = true; try { @@ -137,40 +137,44 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL btnPause.setEnabled(false); Intent intent = getIntent(); + String url = intent.getStringExtra("url"); + if (!TextUtils.isEmpty(url)) { + rtmpUrl = url; + } mCameraView = (SrsCameraView) findViewById(R.id.glsurfaceview_camera); int rotation = intent.getIntExtra("rotation", -1); if (rotation != -1) { + //设置图像显示方向 mCameraView.setPreviewOrientation(rotation); } - - mPublisher = new SrsPublisher(mCameraView); - - - - String url = intent.getStringExtra("url"); - if (!TextUtils.isEmpty(url)) { - rtmpUrl = url; + cameraData = mCameraView.getCameraData(); + int size = cameraData.size(); + if (size == 0) { + Toast.makeText(getApplicationContext(), "没有查询到摄像头", Toast.LENGTH_SHORT).show(); } - + mPublisher = new SrsPublisher(mCameraView); mPublisher.setEncodeHandler(new SrsEncodeHandler(this)); mPublisher.setRtmpHandler(new RtmpHandler(this)); mPublisher.setRecordHandler(new SrsRecordHandler(this)); - mPublisher.setPreviewResolution(mWidth, mHeight); + + mPublisher.setPreviewResolution(mWidth, mHeight);//设置预览宽高 mPublisher.setOutputResolution(mHeight, mWidth); // 这里要和preview反过来 + mPublisher.setVideoHDMode(); if (intent.hasExtra("cameraId")) { - int cameraId = intent.getIntExtra("cameraId", 0); + cameraId = intent.getIntExtra("cameraId", 0); mPublisher.switchCameraFace(cameraId); } mPublisher.startCamera(); - mCameraView.setCameraCallbacksHandler(new SrsCameraView.CameraCallbacksHandler(){ + mCameraView.setCameraCallbacksHandler(new SrsCameraView.CameraCallbacksHandler() { @Override public void onCameraParameters(Camera.Parameters params) { //params.setFocusMode("custom-focus"); //params.setWhiteBalance("custom-balance"); //etc... + Log.e("fsfs", "fsdf"); } }); @@ -195,7 +199,7 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL } }, 1000); } - + btnPublish.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -229,10 +233,10 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL btnPause.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - if(btnPause.getText().toString().equals("Pause")){ + if (btnPause.getText().toString().equals("Pause")) { mPublisher.pausePublish(); btnPause.setText("resume"); - }else{ + } else { mPublisher.resumePublish(); btnPause.setText("Pause"); } @@ -242,7 +246,11 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL btnSwitchCamera.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - mPublisher.switchCameraFace((mPublisher.getCameraId() + 1) % Camera.getNumberOfCameras()); + int size = cameraData.size(); + if (size > 0) { + int i = (++cameraId) % size; + mPublisher.switchCameraFace(i); + } } }); @@ -352,10 +360,10 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL @Override protected void onStart() { super.onStart(); - if(mPublisher.getCamera() == null && isPermissionGranted){ - //if the camera was busy and available again - mPublisher.startCamera(); - } +// if(mPublisher.getCamera() == null && isPermissionGranted){ +// //if the camera was busy and available again +// mPublisher.startCamera(); +// } } @Override diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 2a12c47..9b8ffd5 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -3,4 +3,9 @@ #3F51B5 #303F9F #FF4081 + #FF039BE5 + #FF01579B + #FF40C4FF + #FF00B0FF + #66000000 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d22a28d..897560f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,7 @@ 欣影视频流 + FullscreenActivity + Dummy Button + DUMMY\nCONTENT + FullscreenActivity2 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 6f19b47..5cb080f 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -8,4 +8,13 @@ @color/colorAccent + + + + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..e9a0a41 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index d04fe78..0bda327 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,7 @@ buildscript { repositories { jcenter() google() + mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:4.1.1' @@ -17,6 +18,7 @@ allprojects { repositories { jcenter() google() + mavenCentral() } } diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml index dfe74c1..8311ade 100644 --- a/library/src/main/AndroidManifest.xml +++ b/library/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + diff --git a/library/src/main/java/net/ossrs/yasea/CameraItemData.java b/library/src/main/java/net/ossrs/yasea/CameraItemData.java new file mode 100644 index 0000000..dea7f0c --- /dev/null +++ b/library/src/main/java/net/ossrs/yasea/CameraItemData.java @@ -0,0 +1,63 @@ +package net.ossrs.yasea; + +import android.util.Range; + +import java.util.List; + +//摄像头对象类 +public class CameraItemData { + public String id;//摄像头编号 + public int sensorOrientation;//摄像头朝向 + public Range[] FPS_RANGES;//FPS + public Long MAX_FRAME_DURATION;//最大帧率 + public int LENS_FACING;//前置后置 + public List supportedSizes;//支持处理的分辨率 + + public List getSupportedSizes() { + return supportedSizes; + } + + public void setSupportedSizes(List supportedSizes) { + this.supportedSizes = supportedSizes; + } + + public int getLENS_FACING() { + return LENS_FACING; + } + + public void setLENS_FACING(int LENS_FACING) { + this.LENS_FACING = LENS_FACING; + } + + public Long getMAX_FRAME_DURATION() { + return MAX_FRAME_DURATION; + } + + public void setMAX_FRAME_DURATION(Long MAX_FRAME_DURATION) { + this.MAX_FRAME_DURATION = MAX_FRAME_DURATION; + } + + public Range[] getFPS_RANGES() { + return FPS_RANGES; + } + + public void setFPS_RANGES(Range[] FPS_RANGES) { + this.FPS_RANGES = FPS_RANGES; + } + + public int getSensorOrientation() { + return sensorOrientation; + } + + public void setSensorOrientation(int sensorOrientation) { + this.sensorOrientation = sensorOrientation; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } +} diff --git a/library/src/main/java/net/ossrs/yasea/CameraView.java b/library/src/main/java/net/ossrs/yasea/CameraView.java new file mode 100644 index 0000000..d397e4c --- /dev/null +++ b/library/src/main/java/net/ossrs/yasea/CameraView.java @@ -0,0 +1,258 @@ +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.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.CaptureRequest; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.ViewGroup; + +import java.util.ArrayList; +import java.util.List; + +/** + * 本类的主要功能是 : 开启摄像头 + *

+ * 1,初始化,{@link CameraView#initCamera()} + * 2,权限,{@link CameraView#onRequestPermissionsResult(int, String[], int[])} + * 3,生命周期,{@link CameraView#onPause()} + * + * @author koko 2023/10/12 11:38 + */ +public class CameraView extends SurfaceView { + private static final String TAG = "CameraView"; + private static final int CAMERA_PERMISSION_REQUEST_CODE = 22; + private CameraDevice mCameraDevice; + private CameraCaptureSession mCaptureSession; + private CaptureRequest.Builder mPreviewBuilder; + public CameraView(Context context) { + super(context); + initView(); + } + public CameraView(Context context, AttributeSet attrs) { + super(context, attrs); + initView(); + } + public CameraView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initView(); + } + public CameraView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + initView(); + } + private void initView() { + SurfaceHolder surfaceHolder = getHolder(); + surfaceHolder.addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(SurfaceHolder holder) { + Log.e(TAG, "surfaceCreated: "); + // 初始化相机 + // 在需要使用相机的地方进行权限检查 + if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + // 如果权限未被授予,则请求相机权限 + ActivityCompat.requestPermissions((Activity) getContext(), + new String[]{Manifest.permission.CAMERA}, + CAMERA_PERMISSION_REQUEST_CODE); + } else { + // 如果权限已被授予,则直接打开相机 + openCamera(); + } + } + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + Log.e(TAG, "surfaceChanged: "); + // 更新相机预览尺寸 + updatePreview(); + } + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + Log.e(TAG, "surfaceDestroyed: "); + // 释放相机资源 + closeCamera(); + } + }); + } + /** + * 初始化相机 + */ + public void initCamera() { + changeCameraOri(getResources().getConfiguration().orientation); + } + // 处理权限请求的回调 + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + // 相机权限已被授予,打开相机 + openCamera(); + } else { + // 相机权限被拒绝,显示一个提示消息或执行其他操作 + } + } + } + /** + * 暂停 + */ + protected void onPause() { + closeCamera(); + } + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + changeCameraOri(newConfig.orientation); + } + /** + * 横竖屏处理 + * @param orientation 横竖屏 + */ + private void changeCameraOri(int orientation) { + float ratioScreen = 0.28f; + float ratioCamera = 16 / 9f; + //以窄边为标准 + //竖屏 +// int screenWidthPortrait = (int) (com.smart.camera2.PhoneHelper.getScreenWidthReal(getContext()) * ratioScreen); + int screenWidthPortrait = (int) 1080; + int screenHeightPortrait = (int) (screenWidthPortrait * ratioCamera); + //横屏 +// int screenHeightLandScape = (int) (com.smart.camera2.PhoneHelper.getScreenHeightReal(getContext()) * ratioScreen); + int screenHeightLandScape = (int) 1920; + int screenWidthLandScape = (int) (screenHeightLandScape * ratioCamera); + ViewGroup.LayoutParams layoutParams = getLayoutParams(); + if (layoutParams == null) { + return; + } + switch (orientation) { + case Configuration.ORIENTATION_PORTRAIT: + Log.i(TAG, "onConfigurationChanged: " + "竖屏"); + // 竖屏1080-1920 + layoutParams.width = screenWidthPortrait; + layoutParams.height = screenHeightPortrait; + break; + case Configuration.ORIENTATION_LANDSCAPE: + Log.i(TAG, "onConfigurationChanged: " + "横屏"); + // 横屏1920-1080 + layoutParams.width = screenWidthLandScape; + layoutParams.height = screenHeightLandScape; + break; + } + setLayoutParams(layoutParams); + } + /** + * 打开相机 + */ + private void openCamera() { + CameraManager cameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE); + getHolder().setFixedSize(9999, 9999); + try { + String cameraId = getFrontCameraId(cameraManager); + if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + return; + } + cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() { + @Override + public void onOpened(CameraDevice camera) { + mCameraDevice = camera; + Log.e(TAG, "onOpened: "); + createCaptureSession(); + } + @Override + public void onDisconnected(CameraDevice camera) { + Log.e(TAG, "onDisconnected: "); + } + @Override + public void onError(CameraDevice camera, int error) { + Log.e(TAG, "onError: "); + } + }, null); + } catch (CameraAccessException e) { + e.printStackTrace(); + } + } + /** + * 关闭相机 + */ + private void closeCamera() { + Log.e(TAG, "closeCamera: "); + if (mCaptureSession != null) { + mCaptureSession.close(); + mCaptureSession = null; + } + if (mCameraDevice != null) { + mCameraDevice.close(); + mCameraDevice = null; + } + } + /** + * 刷新 + */ + private void updatePreview() { + if (mCameraDevice == null) { + return; + } + if (mCaptureSession == null) { + return; + } + try { + mCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), null, null); + } catch (CameraAccessException e) { + e.printStackTrace(); + } + } + /** + * 获取相机 + * @param cameraManager cameraManager + * @return 相机id + * @throws CameraAccessException 异常 + */ + private String getFrontCameraId(CameraManager cameraManager) throws CameraAccessException { + String[] cameraIds = cameraManager.getCameraIdList(); + for (String cameraId : cameraIds) { + CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); + Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); + if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) { + return cameraId; + } + } + return cameraIds[0]; + } + /** + * 创建CaptureSession + */ + private void createCaptureSession() { + try { + SurfaceHolder surfaceHolder = getHolder(); + surfaceHolder.setFixedSize(getWidth(), getHeight()); + List surfaces = new ArrayList<>(); + surfaces.add(surfaceHolder.getSurface()); + mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); + mPreviewBuilder.addTarget(surfaceHolder.getSurface()); + mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() { + @Override + public void onConfigured(CameraCaptureSession session) { + mCaptureSession = session; + Log.e(TAG, "onConfigured: "); + updatePreview(); + } + @Override + public void onConfigureFailed(CameraCaptureSession session) { + // 配置会话失败 + } + }, null); + } catch (CameraAccessException e) { + e.printStackTrace(); + } + } +} diff --git a/library/src/main/java/net/ossrs/yasea/SrsCameraView.java b/library/src/main/java/net/ossrs/yasea/SrsCameraView.java index c57962e..57ee598 100644 --- a/library/src/main/java/net/ossrs/yasea/SrsCameraView.java +++ b/library/src/main/java/net/ossrs/yasea/SrsCameraView.java @@ -2,15 +2,27 @@ package net.ossrs.yasea; 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.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; @@ -18,9 +30,10 @@ import com.seu.magicfilter.utils.MagicFilterFactory; import com.seu.magicfilter.utils.MagicFilterType; import com.seu.magicfilter.utils.OpenGLUtils; -import java.io.IOException; 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; @@ -47,8 +60,6 @@ public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Render private float[] mProjectionMatrix = new float[16]; private float[] mSurfaceMatrix = new float[16]; private float[] mTransformMatrix = new float[16]; - - private Camera mCamera; private ByteBuffer mGLPreviewBuffer; private int mCamId = -1; private int mPreviewRotation = 90; @@ -59,6 +70,15 @@ public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Render 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); @@ -70,6 +90,7 @@ public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Render setEGLContextClientVersion(2); setRenderer(this); setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); + initCameraData(); } @Override @@ -89,15 +110,7 @@ public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Render requestRender(); } }); - // For camera preview on activity creation - if (mCamera != null) { - try { - mCamera.setPreviewTexture(surfaceTexture); - } catch (IOException ioe) { - ioe.printStackTrace(); - } - } } @Override @@ -119,17 +132,17 @@ public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Render @Override public void onDrawFrame(GL10 gl) { - - - if(mSurfaceWidth != mPreviewWidth || mSurfaceHeight != mPreviewHeight){ + + + if (mSurfaceWidth != mPreviewWidth || mSurfaceHeight != mPreviewHeight) { //May be a buffer overflow in enableEncoding() //mPreviewWidth changed but onSurfaceCreated fired after enable encoding (mIsEncoding == true) //could be calling magicFilter.onInputSizeChanged(width, height) in setPreviewResolution() after changing mGLPreviewBuffer? //or start the encoder only after onSurfaceCreated ... 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); @@ -140,8 +153,8 @@ public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Render magicFilter.setTextureTransformMatrix(mTransformMatrix); magicFilter.onDrawFrame(mOESTextureId); - if (mIsEncoding) { - mGLIntBufferCache.add(magicFilter.getGLFboBuffer()); + if (mIsEncoding) { + mGLIntBufferCache.add(magicFilter.getGLFboBuffer()); synchronized (writeLock) { writeLock.notifyAll(); } @@ -151,40 +164,74 @@ public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Render public void setPreviewCallback(PreviewCallback cb) { mPrevCb = cb; } - - public Camera getCamera(){ - return this.mCamera; - } - public void setPreviewCallback(Camera.PreviewCallback previewCallback){ - this.mCamera.setPreviewCallback(previewCallback); + + + //选择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) { - mCamera = openCamera(); - + + public int[] setPreviewResolution(int width, int height) { +// mCamera = openCamera(); + + mPreviewWidth = width; mPreviewHeight = height; - Camera.Size rs = adaptPreviewResolution(mCamera.new Size(width, height)); - if (rs != null) { - mPreviewWidth = rs.width; - mPreviewHeight = rs.height; - } - +// Camera.Size rs = adaptPreviewResolution(mCamera.new Size(width, height)); +// if (rs != null) { +// mPreviewWidth = rs.width; +// mPreviewHeight = rs.height; +// } + getHolder().setFixedSize(mPreviewWidth, mPreviewHeight); - - mCamera.getParameters().setPreviewSize(mPreviewWidth, mPreviewHeight); + +// mCamera.getParameters().setPreviewSize(mPreviewWidth, mPreviewHeight); mGLPreviewBuffer = ByteBuffer.allocate(mPreviewWidth * mPreviewHeight * 4); - mInputAspectRatio = mPreviewWidth > mPreviewHeight ? - (float) mPreviewWidth / mPreviewHeight : (float) mPreviewHeight / mPreviewWidth; + mInputAspectRatio = mPreviewWidth > mPreviewHeight ? (float) mPreviewWidth / mPreviewHeight : (float) mPreviewHeight / mPreviewWidth; - return new int[] { mPreviewWidth, mPreviewHeight }; + return new int[]{mPreviewWidth, mPreviewHeight}; } public boolean setFilter(final MagicFilterType type) { - if (mCamera == null) { - return false; - } queueEvent(new Runnable() { @Override @@ -209,16 +256,16 @@ public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Render queueEvent(new Runnable() { @Override public void run() { - GLES20.glDeleteTextures(1, new int[]{ mOESTextureId }, 0); + GLES20.glDeleteTextures(1, new int[]{mOESTextureId}, 0); mOESTextureId = OpenGLUtils.NO_TEXTURE; } }); } } - public void setCameraId(int id) { + public void setCameraId(CameraItemData item) { stopTorch(); - mCamId = id; + curItem = item; setPreviewOrientation(mPreviewOrientation); } @@ -235,40 +282,16 @@ public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Render case Surface.ROTATION_270: return 270; } - }catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); } return -1; } - + public void setPreviewOrientation(int orientation) { mPreviewOrientation = orientation; - Camera.CameraInfo info = new Camera.CameraInfo(); - Camera.getCameraInfo(mCamId, info); - - int rotateDeg = getRotateDeg(); - - if (orientation == Configuration.ORIENTATION_PORTRAIT) { - if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { - mPreviewRotation = info.orientation % 360; - mPreviewRotation = (360 - mPreviewRotation) % 360; // compensate the mirror - } else { - mPreviewRotation = (info.orientation + 360) % 360; - } - } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { - if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { - mPreviewRotation = (info.orientation - 90) % 360; - mPreviewRotation = (360 - mPreviewRotation) % 360; // compensate the mirror - } else { - mPreviewRotation = (info.orientation + 90) % 360; - } - } - - if(rotateDeg > 0){ - mPreviewRotation = mPreviewRotation % rotateDeg; - } - + setRotation(180); } public int getCameraId() { @@ -285,7 +308,7 @@ public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Render IntBuffer picture = mGLIntBufferCache.poll(); mGLPreviewBuffer.asIntBuffer().put(picture.array()); mPrevCb.onGetRgbaFrame(mGLPreviewBuffer.array(), mPreviewWidth, mPreviewHeight); - }catch (Exception e){ + } catch (Exception e) { cameraCallbacksHandler.onError(e); e.printStackTrace(); worker.interrupt(); @@ -328,133 +351,170 @@ public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Render } } - public boolean startCamera() { - if (mCamera == null) { - mCamera = openCamera(); - if (mCamera == null) { - return false; - } + //相机状态变化时会调用这里的回调函数 + private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { + @Override + public void onOpened(CameraDevice camera) { + //相机打开时执行 + Log.e(TAG, "onOpened"); + mCameraDevice = camera; + //创建相机预览会话 + createCameraPreviewSession(); } - Camera.Parameters params = mCamera.getParameters(); - //params.setPictureSize(mPreviewWidth, mPreviewHeight); - params.setPreviewSize(mPreviewWidth, mPreviewHeight); - int[] range = adaptFpsRange(SrsEncoder.VFPS, params.getSupportedPreviewFpsRange()); - params.setPreviewFpsRange(range[0], range[1]); - params.setPreviewFormat(ImageFormat.NV21); - params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); - params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO); - params.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO); - params.setRecordingHint(true); - - List supportedFocusModes = params.getSupportedFocusModes(); - if (supportedFocusModes != null && !supportedFocusModes.isEmpty()) { - if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { - params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); - } else if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { - params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); - mCamera.autoFocus(null); - } else { - params.setFocusMode(supportedFocusModes.get(0)); - } + @Override + public void onDisconnected(CameraDevice camera) { + //相机链接断开 + Log.e("dsdsfd", "fdsdf"); + } - List supportedFlashModes = params.getSupportedFlashModes(); - if (supportedFlashModes != null && !supportedFlashModes.isEmpty()) { - if (supportedFlashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) { - if (mIsTorchOn) { - params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); + @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(); } - } else { - params.setFlashMode(supportedFlashModes.get(0)); - } + + @Override + public void onConfigureFailed(CameraCaptureSession session) { + Log.e("dkkd", "fdsa"); + } + }, null); + } catch (CameraAccessException e) { + throw new RuntimeException(e); } - cameraCallbacksHandler.onCameraParameters(params); - mCamera.setParameters(params); - mCamera.setDisplayOrientation(mPreviewRotation); + } + + private void updatePreview() { + captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + CaptureRequest captureRequest = captureRequestBuilder.build(); try { - mCamera.setPreviewTexture(surfaceTexture); - } catch (IOException e) { - e.printStackTrace(); + cameraCaptureSession.setRepeatingRequest(captureRequest, null, null); + } catch (CameraAccessException e) { + throw new RuntimeException(e); } - mCamera.startPreview(); + } - return true; + 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 (Activity.checkSelfPermission(getContext(), android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + // } + cameraManager.openCamera(cameraId, stateCallback, null); + + } catch (CameraAccessException e) { + throw new RuntimeException(e); + } } public void stopCamera() { disableEncoding(); - stopTorch(); - if (mCamera != null) { - mCamera.setPreviewCallback(null); - mCamera.stopPreview(); - mCamera.release(); - mCamera = null; + if (cameraCaptureSession != null) { + cameraCaptureSession.close(); + cameraCaptureSession = null; + } + if (mCameraDevice != null) { + mCameraDevice.close(); + mCameraDevice = null; } } - protected Camera openCamera() { - Camera camera = null; - if (mCamId < 0) { - Camera.CameraInfo info = new Camera.CameraInfo(); - int numCameras = Camera.getNumberOfCameras(); - int frontCamId = -1; - int backCamId = -1; - for (int i = 0; i < numCameras; i++) { - Camera.getCameraInfo(i, info); - if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { - backCamId = i; - } else if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { - frontCamId = i; - break; - } - } - if (frontCamId != -1) { - mCamId = frontCamId; - } else if (backCamId != -1) { - mCamId = backCamId; - } else { - mCamId = 0; - } - } - + public List initCameraData() { + itemlist = new ArrayList(); + cameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);//获取摄像头管理类 try { - camera = Camera.open(mCamId); - - camera.setErrorCallback(new Camera.ErrorCallback(){ - @Override - public void onError(int error, Camera camera) { - //may be Camera.CAMERA_ERROR_EVICTED - Camera was disconnected due to use by higher priority user - stopCamera(); - } - }); - - }catch (Exception e){ - e.printStackTrace(); + cameraNames = cameraManager.getCameraIdList();//获取摄像头名称列表 + } catch (CameraAccessException e) { + throw new RuntimeException(e); } - - return camera; - } - private Camera.Size adaptPreviewResolution(Camera.Size resolution) { - float diff = 100f; - float xdy = (float) resolution.width / (float) resolution.height; - Camera.Size best = null; - for (Camera.Size size : mCamera.getParameters().getSupportedPreviewSizes()) { - if (size.equals(resolution)) { - return size; + 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; } - float tmp = Math.abs(((float) size.width / (float) size.height) - xdy); - if (tmp < diff) { - diff = tmp; - best = size; + + 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 best; + return itemlist; + } + + + public List getCameraData() { + return itemlist; } private int[] adaptFpsRange(int expectedFps, List fpsRanges) { @@ -473,58 +533,44 @@ public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Render return closestRange; } - public boolean startTorch() { - if (mCamera != null) { - Camera.Parameters params = mCamera.getParameters(); - List supportedFlashModes = params.getSupportedFlashModes(); - if (supportedFlashModes != null && !supportedFlashModes.isEmpty()) { - if (supportedFlashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) { - params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); - mCamera.setParameters(params); - return true; - } - } - } - return false; - } - 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(); - } - } +// 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{ + + 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; - } + } } diff --git a/library/src/main/java/net/ossrs/yasea/SrsPublisher.java b/library/src/main/java/net/ossrs/yasea/SrsPublisher.java index a8c9988..e39910b 100644 --- a/library/src/main/java/net/ossrs/yasea/SrsPublisher.java +++ b/library/src/main/java/net/ossrs/yasea/SrsPublisher.java @@ -1,6 +1,5 @@ package net.ossrs.yasea; -import android.hardware.Camera; import android.media.AudioRecord; import android.media.audiofx.AcousticEchoCanceler; import android.media.audiofx.AutomaticGainControl; @@ -9,6 +8,7 @@ import com.github.faucamp.simplertmp.RtmpHandler; import com.seu.magicfilter.utils.MagicFilterType; import java.io.File; +import java.util.List; /** * Created by Leo Ma on 2016/7/25. @@ -160,11 +160,13 @@ public class SrsPublisher { stopCamera(); mEncoder.stop(); } - public void pauseEncode(){ + + public void pauseEncode() { stopAudio(); mCameraView.disableEncoding(); mCameraView.stopTorch(); } + private void resumeEncode() { startAudio(); mCameraView.enableEncoding(); @@ -177,8 +179,9 @@ public class SrsPublisher { startEncode(); } } - public void resumePublish(){ - if(mFlvMuxer != null) { + + public void resumePublish() { + if (mFlvMuxer != null) { mEncoder.resume(); resumeEncode(); } @@ -191,12 +194,13 @@ public class SrsPublisher { } } - public void pausePublish(){ + public void pausePublish() { if (mFlvMuxer != null) { mEncoder.pause(); pauseEncode(); } } + public boolean startRecord(String recPath) { return mMp4Muxer != null && mMp4Muxer.record(new File(recPath)); } @@ -219,12 +223,12 @@ public class SrsPublisher { } } - public boolean isAllFramesUploaded(){ + public boolean isAllFramesUploaded() { return mFlvMuxer.getVideoFrameCacheNumber().get() == 0; } - public int getVideoFrameCacheCount(){ - if(mFlvMuxer != null) { + public int getVideoFrameCacheCount() { + if (mFlvMuxer != null) { return mFlvMuxer.getVideoFrameCacheNumber().get(); } return 0; @@ -257,10 +261,7 @@ public class SrsPublisher { public int getCameraId() { return mCameraView.getCameraId(); } - - public Camera getCamera() { - return mCameraView.getCamera(); - } + public void setPreviewResolution(int width, int height) { int resolution[] = mCameraView.setPreviewResolution(width, height); @@ -309,14 +310,15 @@ public class SrsPublisher { } public void switchCameraFace(int id) { - + List cameraData = mCameraView.getCameraData(); + CameraItemData item = cameraData.get(id); + if (mEncoder != null && mEncoder.isEnabled()) { mEncoder.pause(); - } - + } mCameraView.stopCamera(); - mCameraView.setCameraId(id); - if (id == 0) { + mCameraView.setCameraId(item); + if (item.getLENS_FACING() == 0) { mEncoder.setCameraBackFace(); } else { mEncoder.setCameraFrontFace(); @@ -325,11 +327,11 @@ public class SrsPublisher { mCameraView.enableEncoding(); } mCameraView.startCamera(); - + if (mEncoder != null && mEncoder.isEnabled()) { mEncoder.resume(); - } - + } + } public void setRtmpHandler(RtmpHandler handler) {