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/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 317093e..b0b8af3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + @@ -8,7 +9,9 @@ - + + @@ -27,4 +34,4 @@ - + \ No newline at end of file diff --git a/app/src/main/java/com/xypower/mplive/MainActivity.java b/app/src/main/java/com/xypower/mplive/MainActivity.java index acf1d40..2a46e3c 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; + 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,48 @@ 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); - mPublisher.switchCameraFace(cameraId); + cameraId = intent.getIntExtra("cameraId", 0); + CameraItemData itemData = cameraData.get(cameraId); + mPublisher.switchCameraFace(itemData); } 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 +203,7 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL } }, 1000); } - + btnPublish.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -229,10 +237,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 +250,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(cameraData.get(i)); + } } }); @@ -352,10 +364,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/java/com/xypower/mplive/TESTActivity.java b/app/src/main/java/com/xypower/mplive/TESTActivity.java new file mode 100644 index 0000000..0edc618 --- /dev/null +++ b/app/src/main/java/com/xypower/mplive/TESTActivity.java @@ -0,0 +1,232 @@ +package com.xypower.mplive; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.ImageFormat; +import android.graphics.SurfaceTexture; +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.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.StreamConfigurationMap; +import android.media.Image; +import android.media.ImageReader; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.ActivityCompat; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.util.Size; +import android.view.Surface; +import android.view.TextureView; +import android.view.View; +import android.widget.Toast; + +import java.util.Arrays; + +public class TESTActivity extends AppCompatActivity { + + private static final String TAG = "Camera2Demo"; + private TextureView textureView; + private CameraDevice mCameraDevice; + private Size imageDimension; + private CaptureRequest.Builder captureRequestBuilder; + private CameraCaptureSession cameraCaptureSession; + private ImageReader imageReader; + + private CaptureRequest captureRequest; + + + @SuppressLint("MissingInflatedId") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + setContentView(R.layout.activity_fullscreen); + initPermission(); //权限申请 + textureView = findViewById(R.id.texture_view); + textureView.setSurfaceTextureListener(textureListener); + final CameraCaptureSession.CaptureCallback CaptureCallback + = new CameraCaptureSession.CaptureCallback() { + + @Override + public void onCaptureCompleted(@NonNull CameraCaptureSession session, + @NonNull CaptureRequest request, + @NonNull TotalCaptureResult result) { + //点击拍照后调用此回调 此处弹出提示 + Toast.makeText(TESTActivity.this,"Saved:xx/xx/xx/xx.jpg",Toast.LENGTH_SHORT).show(); + } + }; + findViewById(R.id.picture).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + //创建了一个拍照的请求 + final CaptureRequest.Builder captureBuilder = + mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); + //与imageReader关联,当点击拍照获取到可用图片时,会触发ImageReader的回调,可在ImageReader的回调中对图片进行保存等处理 + captureBuilder.addTarget(imageReader.getSurface()); + cameraCaptureSession.capture(captureBuilder.build(),CaptureCallback,null); + } catch (CameraAccessException e) { + throw new RuntimeException(e); + } + } + }); + } + + + private final TextureView.SurfaceTextureListener textureListener = + new TextureView.SurfaceTextureListener() { + @Override + public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) { + Log.e(TAG, "onSurfaceTextureAvailable"); + openCamera(); + } + + @Override + public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) { + Log.e(TAG, "onSurfaceTextureSizeChanged"); + } + + @Override + public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) { + Log.e(TAG, "onSurfaceTextureDestroyed"); + return false; + } + + @Override + public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) { + Log.e(TAG, "onSurfaceTextureUpdated"); + } + }; + //相机状态变化时会调用这里的回调函数 + private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { + @Override + public void onOpened(@NonNull CameraDevice camera) { + //相机打开时执行 + Log.e(TAG, "onOpened"); + mCameraDevice=camera; + //创建相机预览会话 + createCameraPreviewSession(); + } + + @Override + public void onDisconnected(@NonNull CameraDevice camera) { + //相机链接断开 + } + + @Override + public void onError(@NonNull CameraDevice camera, int error) { + + } + }; + + private void openCamera() { + CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); + try { + //通过cameraId获取Camera参数 + String cameraId = cameraManager.getCameraIdList()[2]; + 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(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + // TODO: Consider calling + // ActivityCompat#requestPermissions + // here to request the missing permissions, and then overriding + // public void onRequestPermissionsResult(int requestCode, String[] permissions, + // int[] grantResults) + // to handle the case where the user grants the permission. See the documentation + // for ActivityCompat#requestPermissions for more details. + return; + } + cameraManager.openCamera(cameraId, stateCallback, null); + + } catch (CameraAccessException e) { + throw new RuntimeException(e); + } + } + private boolean initPermission(){ + ActivityCompat.requestPermissions(TESTActivity.this, new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.CAMERA}, 1); + // 高版本Android SDK时使用如下代码 +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { +// if(!Environment.isExternalStorageManager()){ +// Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION); +// startActivity(intent); +// return false; +// } +// } + + + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (checkSelfPermission(android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + requestPermissions(new String[] {Manifest.permission.CAMERA}, 1); + return false; + } + } + return true; + } + private void createCameraPreviewSession(){ + SurfaceTexture surfaceTexture=textureView.getSurfaceTexture(); + 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(@NonNull CameraCaptureSession session) { + if (mCameraDevice == null) { + return; + } + cameraCaptureSession = session; + updatePreview(); + } + + @Override + public void onConfigureFailed(@NonNull CameraCaptureSession session) { + Toast.makeText(TESTActivity.this, "Configuration change", Toast.LENGTH_SHORT).show(); + } + }, null); + } catch (CameraAccessException e) { + throw new RuntimeException(e); + } + + + } + private void updatePreview(){ + captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + captureRequest = captureRequestBuilder.build(); + + try { + cameraCaptureSession.setRepeatingRequest(captureRequest,null,null); + } catch (CameraAccessException e) { + throw new RuntimeException(e); + } + } + private final ImageReader.OnImageAvailableListener onImageAvailableListener= + new ImageReader.OnImageAvailableListener() { + @Override + public void onImageAvailable(ImageReader reader) { + Image image=null; + image=reader.acquireLatestImage(); + Log.e("lkx","1"); + //此处可对图片进行处理 比如保存到本地 + image.close(); + } + }; +} diff --git a/app/src/main/res/layout/activity_fullscreen.xml b/app/src/main/res/layout/activity_fullscreen.xml new file mode 100644 index 0000000..8dc3699 --- /dev/null +++ b/app/src/main/res/layout/activity_fullscreen.xml @@ -0,0 +1,21 @@ + + + + +