增加六通道配置拍照

nx2024
liuguijing 6 months ago
parent ef21a79659
commit 9ba5867814

@ -54,6 +54,9 @@ android {
}
}
buildFeatures {
viewBinding true
}
}
dependencies {
@ -63,4 +66,20 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//CameraX
// implementation "androidx.camera:camera-core:1.4.1"
// implementation "androidx.camera:camera-camera2:1.4.1"
// implementation "androidx.camera:camera-view:1.4.1"
// implementation "androidx.camera:camera-lifecycle:1.4.1"
// implementation "androidx.camera:camera-video:1.4.1"
// CameraX core library using camera2 implementation
implementation "androidx.camera:camera-camera2:1.1.0"
// CameraX Lifecycle Library
implementation "androidx.camera:camera-lifecycle:1.1.0"
// CameraX View class
implementation "androidx.camera:camera-view:1.1.0"
}

@ -21,10 +21,12 @@
android:theme="@style/Theme.MpPreview"
android:requestLegacyExternalStorage="true"
tools:targetApi="30">
<activity
android:name=".CameraChannelActivity"
android:exported="false" />
<activity
android:name=".CameraActivity"
android:exported="false"
/>
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true">

@ -1101,7 +1101,8 @@ public class Camera2RawFragment extends Fragment {
Range<Integer> range = mCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
Rational rational = mCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP);
double step = rational.doubleValue();
captureBuilder.set(CaptureRequest.EDGE_MODE, CaptureRequest.EDGE_MODE_HIGH_QUALITY);
captureBuilder.set(CaptureRequest.NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
if (pic1 < 21) {
// mCharacteristics.get(CameraMetadata.CONTROL_AE_COMPENSATION_STEP)
ArrayList<PngPhotoBean> mlist = new ArrayList<>();

@ -0,0 +1,151 @@
package com.xypower.mppreview;
import static android.os.Environment.getExternalStoragePublicDirectory;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.CameraInfo;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.google.common.util.concurrent.ListenableFuture;
import com.xypower.mppreview.bean.Contants;
import com.xypower.mppreview.databinding.ActivityCameraChannelBinding;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CameraChannelActivity extends AppCompatActivity implements View.OnClickListener {
private com.xypower.mppreview.databinding.ActivityCameraChannelBinding viewBinding;
private int camerid;
private ImageCapture imageCapture;
private ExecutorService cameraExecutor;
private File outputDirectory;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewBinding = ActivityCameraChannelBinding.inflate(getLayoutInflater());
setContentView(viewBinding.getRoot());
camerid = getIntent().getIntExtra(Contants.CAMERAID, 0);
initEvent();
// 设置照片等保存的位置
outputDirectory = getOutputDirectory();
cameraExecutor = Executors.newSingleThreadExecutor();
startCamera(camerid);
}
@Override
protected void onDestroy() {
super.onDestroy();
cameraExecutor.shutdown();
}
private void initEvent() {
viewBinding.imageCaptureButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
takePhoto();
}
private void startCamera(int cameraid) {
// 将Camera的生命周期和Activity绑定在一起设定生命周期所有者这样就不用手动控制相机的启动和关闭。
ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
// 将你的相机和当前生命周期的所有者绑定所需的对象
ProcessCameraProvider processCameraProvider = cameraProviderFuture.get();
// 创建一个Preview 实例,并设置该实例的 surface 提供者provider
PreviewView viewFinder = viewBinding.viewFinder;
Preview preview = new Preview.Builder().build();
preview.setSurfaceProvider(viewFinder.getSurfaceProvider());
// 选择后置摄像头作为默认摄像头
// CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
List<CameraInfo> availableCameraInfos = processCameraProvider.getAvailableCameraInfos();
CameraInfo cameraInfo = availableCameraInfos.get(cameraid);
CameraSelector cameraSelector = cameraInfo.getCameraSelector();
// 创建拍照所需的实例
imageCapture = new ImageCapture.Builder().build();
// 设置预览帧分析
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder().build();
imageAnalysis.setAnalyzer(cameraExecutor, new MyAnalyzer());
// 重新绑定用例前先解绑
processCameraProvider.unbindAll();
// 绑定用例至相机
processCameraProvider.bindToLifecycle(CameraChannelActivity.this, cameraSelector, preview,imageCapture,imageAnalysis);
} catch (Exception e) {
Log.e(Contants.TAG, "用例绑定失败!" + e);
}
}, ContextCompat.getMainExecutor(this));
}
private void takePhoto() {
// 确保imageCapture 已经被实例化, 否则程序将可能崩溃
if (imageCapture != null) {
// 创建带时间戳的输出文件以保存图片,带时间戳是为了保证文件名唯一
File photoFile = new File(outputDirectory, new SimpleDateFormat(Contants.FILENAME_FORMAT, Locale.SIMPLIFIED_CHINESE).format(System.currentTimeMillis()) + ".jpg");
// 创建 output option 对象,用以指定照片的输出方式
ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(photoFile).build();
// 执行takePicture拍照方法
imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(this), new ImageCapture.OnImageSavedCallback() {// 保存照片时的回调
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
Uri savedUri = Uri.fromFile(photoFile);
String msg = "照片捕获成功! " + savedUri;
Toast.makeText(getBaseContext(), msg, Toast.LENGTH_SHORT).show();
Log.d(Contants.TAG, msg);
}
@Override
public void onError(@NonNull ImageCaptureException exception) {
Log.e(Contants.TAG, "Photo capture failed: " + exception.getMessage());
}
});
}
}
private File getOutputDirectory() {
File mediaDir = new File(getExternalMediaDirs()[0], getString(R.string.app_name));
boolean isExist = mediaDir.exists() || mediaDir.mkdir();
return isExist ? mediaDir : null;
}
}

@ -13,14 +13,12 @@ import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.text.Editable;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import com.xypower.mppreview.bean.Contants;
import com.xypower.mppreview.databinding.ActivityMainBinding;
import java.io.File;
@ -37,6 +35,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
private Button hdrtakepic;
private ActivityResultLauncher<Intent> photoResultLauncher;
private int picsize = 0;
private com.xypower.mppreview.databinding.ActivityMainBinding viewBinding;
protected native void test();
@ -44,7 +43,8 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(viewBinding.getRoot());
initView();
initActivityResult();
@ -82,12 +82,15 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
}
private void initView() {
hdrtakepic = findViewById(R.id.hdrtakepic);
systakepic = findViewById(R.id.systakepic);
Spinner spinner = findViewById(R.id.spinner);
hdrtakepic.setOnClickListener(this);
systakepic.setOnClickListener(this);
spinner.setOnItemSelectedListener(this);
viewBinding.hdrtakepic.setOnClickListener(this);
viewBinding.systakepic.setOnClickListener(this);
viewBinding.spinner.setOnItemSelectedListener(this);
viewBinding.channel1.setOnClickListener(this);
viewBinding.channel2.setOnClickListener(this);
viewBinding.channel3.setOnClickListener(this);
viewBinding.channel4.setOnClickListener(this);
viewBinding.channel5.setOnClickListener(this);
viewBinding.channel6.setOnClickListener(this);
}
private void initActivityResult() {
@ -135,10 +138,34 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
case R.id.systakepic:
PhotoUtil.openCamera(this, photoResultLauncher);
break;
case R.id.channel1:
openChannelActivity(0);
break;
case R.id.channel2:
openChannelActivity(1);
break;
case R.id.channel3:
openChannelActivity(2);
break;
case R.id.channel4:
openChannelActivity(3);
break;
case R.id.channel5:
openChannelActivity(4);
break;
case R.id.channel6:
openChannelActivity(5);
break;
}
}
public void openChannelActivity(int channel) {
Intent intent = new Intent(this, CameraChannelActivity.class);
intent.putExtra(Contants.CAMERAID, channel);
startActivity(intent);
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

@ -0,0 +1,21 @@
package com.xypower.mppreview;
import android.annotation.SuppressLint;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageProxy;
import com.xypower.mppreview.bean.Contants;
import java.util.Objects;
public class MyAnalyzer implements ImageAnalysis.Analyzer{
@SuppressLint("UnsafeOptInUsageError")
@Override
public void analyze(@NonNull ImageProxy image) {
Log.d(Contants.TAG, "Image's stamp is " + Objects.requireNonNull(image.getImage()).getTimestamp());
image.close();
}
}

@ -1,5 +1,10 @@
package com.xypower.mppreview.bean;
import java.io.File;
public class Contants {
public static final String TAG = "MpPriview";
public static final String HDRNUM = "hdrnum";
public static final String CAMERAID = "CAMERAID";
public static final String FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS";
}

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CameraChannelActivity">
<androidx.camera.view.PreviewView
android:id="@+id/viewFinder"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="@+id/image_capture_button"
android:layout_width="110dp"
android:layout_height="110dp"
android:layout_marginEnd="50dp"
android:layout_marginBottom="50dp"
android:elevation="2dp"
android:text="拍照"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/vertical_centerline"
app:layout_constraintLeft_toLeftOf="parent" />
<Button
android:id="@+id/video_capture_button"
android:layout_width="110dp"
android:layout_height="110dp"
android:layout_marginStart="50dp"
android:layout_marginBottom="50dp"
android:elevation="2dp"
android:text="预览"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/vertical_centerline" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/vertical_centerline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".50" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -29,7 +29,7 @@
<Button
android:id="@+id/hdrtakepic"
android:layout_width="wrap_content"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="HDR拍照"
@ -38,12 +38,64 @@
<Button
android:id="@+id/systakepic"
android:layout_width="wrap_content"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:text="拍照"
app:layout_constraintLeft_toRightOf="@id/hdrtakepic"
app:layout_constraintTop_toTopOf="@+id/hdrtakepic" />
<Button
android:id="@+id/channel1"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="通道一"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/hdrtakepic" />
<Button
android:id="@+id/channel2"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:text="通道二"
app:layout_constraintLeft_toRightOf="@+id/channel1"
app:layout_constraintTop_toTopOf="@+id/channel1" />
<Button
android:id="@+id/channel3"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:text="通道三"
app:layout_constraintLeft_toRightOf="@+id/channel2"
app:layout_constraintTop_toTopOf="@+id/channel1" />
<Button
android:id="@+id/channel4"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="通道四"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/channel1" />
<Button
android:id="@+id/channel5"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:text="通道五"
app:layout_constraintLeft_toRightOf="@+id/channel4"
app:layout_constraintTop_toTopOf="@+id/channel4" />
<Button
android:id="@+id/channel6"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:text="通道六"
app:layout_constraintLeft_toRightOf="@+id/channel5"
app:layout_constraintTop_toTopOf="@+id/channel4" />
</androidx.constraintlayout.widget.ConstraintLayout>
Loading…
Cancel
Save