Camera2 完整相机demo(预览拍照录制视频) 菜鸟教程

一 .功能介绍(UI布局)

打开camera app

        首先会进入拍照模式的预览界面:

拍照的预览界面

                                                           总共就四个控件

                                              1.整体的预览控件TextureView

                                              2.左下角的缩略图ImageView

                                              3.中间的拍照按钮ImageButton

                                              4.切换摄像头的ImageButton

主要是两个Fragment  通过ViewPage 左右滑动切换拍照模式跟录像模式具体实现在后面,在我的Demo中向左滑动切换到录像模式

        进入录像的预览模式:

录像的预览界面

                                                            总共就五个控件

                                              1.整体的预览控件TextureView

                                              2.左下角的缩略图ImageView

                                              3.中间的拍照按钮ImageButton

                                              4.切换摄像头的ImageButton

                                              5.顶部的计时器Chronometer

二 .UI的代码部分

        1.首先是 activity_main.xml中

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.viewpager.widget.ViewPager
        android:layout_gravity="center"
        android:id="@+id/change_page"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

<!--标题 <androidx.viewpager.widget.PagerTitleStrip
            android:layout_gravity="top"
            android:id="@+id/page_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            >-->


    </androidx.viewpager.widget.ViewPager>

</RelativeLayout>

主界面主要是注册了一个ViewPager     注释的部分是之前准备的标题栏,是想通过标题提示是录像界面还是拍照界面,但是自己没有找到把标题栏背景变成透明的方法于是就抛弃了,我方在这里如果后续找到的话及时更新.  

        2.其次是 Mainactivity.java中

package com.example.camera;

import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.view.View;

import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private ViewPager change_page;    //拍照录像切换
    private List<Fragment> layoutList;   //布局集合(拍照录像切换)
    //private List<String> titleList;      //标题集合(拍照录像切换)
    private MyPagerAdapter myPagerAdapter;


    //初始化视图界面(拍照/摄像)
    private void initView(){
        change_page = findViewById(R.id.change_page);
        layoutList = new ArrayList<>();
        layoutList.add(new TakePictureFragment());
        layoutList.add(new RecorderVideoFragment());

//        titleList = new ArrayList<>();
//        titleList.add("拍照");
//        titleList.add("录像");
        //设置适配器
        myPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), layoutList);
        change_page.setAdapter(myPagerAdapter);
    }

    //活动的创建
    @Override
    protected void onCreate(Bundle saveInstanceState) {
        super.onCreate(saveInstanceState);
        setContentView(R.layout.activity_main);
        initView();

        //隐藏通知栏状态栏
        if (Build.VERSION.SDK_INT >= 21) {
            View decorView=getWindow().getDecorView();//获取当前界面的decorView
            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    |View.SYSTEM_UI_FLAG_FULLSCREEN//隐藏状态栏
                    |View.SYSTEM_UI_FLAG_LAYOUT_STABLE//保持整个View的稳定,使其不会随着SystemUI的变化而变化;
                    |View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION//让导航栏悬浮在Activity上
                  //  |View.SYSTEM_UI_FLAG_HIDE_NAVIGATION//隐藏导航栏
                    |View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;//沉浸模式且状态栏和导航栏出现片刻后会自动隐藏
            decorView.setSystemUiVisibility(option);
            getWindow().setStatusBarColor(Color.TRANSPARENT);//设置透明颜色
            getWindow().setNavigationBarColor(Color.TRANSPARENT);
        }
        ActionBar actionBar=getSupportActionBar();
        actionBar.hide();
    }
    
    protected  void onDestroy() {
        super.onDestroy();
        TakePictureFragment.closeCamera();
    }
}

主活动中:

1.做了初始化视图界面添加两个碎片TakePictureFragment和RecorderVideoFragment

2.因为ViewPage要用到PagerAdapter 将默认的界面设置成了拍照预览界面

3.onCreate中做了个沉浸式通知栏(隐藏状态栏和通知栏)

4.onDestroy中调用了TakePictureFrament中的closeCamera

5.注释掉的部分同上是标题栏

        3.MyPagerAdapter.java中

package com.example.camera;

import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;

import java.util.List;

public  class MyPagerAdapter extends FragmentPagerAdapter {
    private List<Fragment> layoutList;
//    private List<String> titleList;
    public MyPagerAdapter(FragmentManager manager, List<Fragment> layoutList ){
        super(manager);
        this.layoutList = layoutList;
//        this.titleList = titleList;
    }
    @Override
    public int getCount() {
        // 页面数
        return layoutList.size();
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        return layoutList.get(position);
    }

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        super.setPrimaryItem(container, position, object);
    }
}

这个类继承FragmentPageAdapter跟ViewPage联合使用,注:ViewPage跟activity也可以不一定是需要Fragment主要的功能就是通过左右滑动来切换fragment

        3.fragment_take_picture.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextureView
        android:id="@+id/textureView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

    <ImageButton
        android:background="@drawable/shape_white_ring"
        android:id="@+id/takePicture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/shape_take_photo"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="50dp"
        />

    <ImageView
        android:id="@+id/image_show"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_marginLeft="50dp"
        android:layout_marginBottom="50dp" />
    <ImageButton
        android:id="@+id/change"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/ic_baseline_flip_camera_android_24"
        android:layout_alignParentBottom="true"
        android:layout_marginRight="50dp"
        android:layout_marginBottom="50dp"
        android:layout_alignParentRight="true"
        />
</RelativeLayout>

        4 TakePpictureFragment.java中

package com.example.camera;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.RectF;
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.MeteringRectangle;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class TakePictureFragment extends Fragment implements View.OnClickListener {
    private static final String TAG = "TakePictureFragment";

    private static final SparseIntArray ORIENTATION = new SparseIntArray();

    static {
        //手机ROTATION逆时针旋转
        ORIENTATION.append(Surface.ROTATION_0, 90);
        ORIENTATION.append(Surface.ROTATION_90, 0);
        ORIENTATION.append(Surface.ROTATION_180, 270);
        ORIENTATION.append(Surface.ROTATION_270, 180);
    }

    private TextureView textureView;  //预览框控件
    private ImageButton takePicture;    //拍照按钮
    private ImageButton change;      //前后摄像头切换按钮
    private ImageView mImageView;     // 缩略图显示
    private String mCameraId;         // 摄像头Id
    private Size mPreviewSize;      //获取分辨率
    private ImageReader mImageReader;  //图片阅读器
    private static CameraDevice mCameraDevice;   //摄像头设备
    private static CameraCaptureSession mCaptureSession;   //获取会话
    private CaptureRequest mPreviewRequest;      //获取预览请求
    private CaptureRequest.Builder mPreviewRequestBuilder;   //获取到预览请求的Builder通过它创建预览请求
    private Surface mPreviewSurface;  //预览显示图

    //权限申请
    private String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.RECORD_AUDIO};
    private List<String> permissionList = new ArrayList();

    private ArrayList<String> imageList = new ArrayList<>();  //图片集合
    protected boolean isCreated=false;   //Fragment是否创建成功
    private boolean isVisible;   //Fragment是否可见


    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreateView: success");
        View view = inflater.inflate(R.layout.fragment_take_picture, container, false);
        //注册监听控件
        initView(view);
        textureView.setSurfaceTextureListener(textureListener);   //surfaceView回调里面配置相机打开相机
        takePicture.setOnClickListener(this);      //拍照监听
        mImageView.setOnClickListener(this);   //缩略图监听
        change.setOnClickListener(this);     //摄像头切换监听
        getPermission();         //申请权限
        //显示最后一张图
        isCreated = true;     //Fragment View 创建成功
        return view;      //显示当前View
    }

    // 第一步:获取权限

    /**
     * 获取拍照和读写权限
     */
    private void getPermission() {
        Log.d(TAG, "getPermission: success");
        //版本判断 当手机系统大于23时,才有必要去判断权限是否获取
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //权限是否已经 授权 GRANTED-授权  DINIED-拒绝
            for (String permission : permissions) {
                //检查权限是否全部授予
                if (ContextCompat.checkSelfPermission(getContext(), permission) != PackageManager.PERMISSION_GRANTED) {
                    //如果没有就添加到权限集合
                    permissionList.add(permission);
                }
            }
            //是空返回ture
            if (!permissionList.isEmpty()) {
                requestPermissions(permissionList.toArray(new String[permissionList.size()]), 1);
            } else {
                //表示全都授权了
                textureView.setSurfaceTextureListener(textureListener);
                //显示最后一张图片  最新
                setLastImagePath();
            }
        }
    }
    //权限回调
    @Override
    public void onRequestPermis
  • 17
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
### 回答1: 安卓camera2拍照录制视频demo是基于安卓相机API的一个示例应用程序,用于演示如何使用安卓相机2 API来实现拍照录制视频功能。 在此示例应用程序中,首先需要初始化相机设备并获取相机特性、参数等信息。然后,可以通过创建一个用于预览的SurfaceView或TextureView,并将其设置为相机预览输出目标。 在拍照功能方面,可以通过设置拍照的一些参数,如图片格式、拍照模式、闪光灯模式等。然后,可以通过调用相机拍照方法,触发相机拍照操作,并在拍照完成后保存图片。 在录制视频功能方面,需要创建一个用于录制视频的MediaRecorder对象,并设置视频的输出格式、编码格式、视频大小等参数。然后,可以通过设置相机预览输出目标为MediaRecorder的Surface,并调用MediaRecorder的start方法开始录制视频,调用stop方法停止录制。 此外,在实际开发中,还需要处理相机权限的获取和申请,以及相机的生命周期管理,如在Activity的onResume和onPause方法中初始化和释放相机等。还可以根据需要添加其他功能,如自动对焦、曝光调节等。 总之,安卓camera2拍照录制视频demo提供了一个基本的框架和实现思路,供开发者参考和借鉴,在此基础上可以根据实际需求进行扩展和定制。 ### 回答2: 安卓Camera2是用于在安卓设备上进行相机操作的API。它提供了更多的功能和控制选项,可以实现更高级的相机操作,比如手动对焦、曝光控制、帧率控制等。 要编写一个拍照录制视频Demo,首先需要获取相机的权限。在AndroidManifest.xml文件中添加相机权限的声明: <uses-permission android:name="android.permission.CAMERA" /> 然后,在布局文件中添加一个相机预览的SurfaceView: <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> 接下来,在Activity中获取相机实例并进行相关配置。首先创建一个CameraManager对象,通过它来获取相机ID和打开相机CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); String cameraId = cameraManager.getCameraIdList()[0]; cameraManager.openCamera(cameraId, cameraStateCallback, null); 在相机状态回调中,可以配置相机预览的Surface和启动预览CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { try { // 设置相机预览的Surface CaptureRequest.Builder requestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); requestBuilder.addTarget(surfaceView.getHolder().getSurface()); // 启动预览 session.setRepeatingRequest(requestBuilder.build(), null, null); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { // 配置失败处理 } }; 最后,编写点击拍照录制视频的逻辑。点击拍照时,创建一个ImageReader对象,设置监听器来处理拍照结果: ImageReader imageReader = ImageReader.newInstance(imageWidth, imageHeight, ImageFormat.JPEG, 1); imageReader.setOnImageAvailableListener(onImageAvailableListener, null); ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { // 处理拍照结果 } }; 点击开始录制视频时,创建一个MediaRecorder对象,并配置输出文件、音频源、视频源等参数。然后使用CameraCaptureSession进行录制会话: MediaRecorder mediaRecorder = new MediaRecorder(); mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); // 配置输出文件,视频尺寸等参数 sessionStateCallback.onConfigured(cameraCaptureSession); // 启动预览 mediaRecorder.prepare(); mediaRecorder.start(); 以上是一个简单的安卓Camera2拍照录制视频Demo的实现。通过Camera2 API可以实现更多的相机功能和控制选项,可以根据实际需求进行更多的定制和扩展。 ### 回答3: 安卓的Camera2 API是一个强大的相机框架,可以实现高效的拍照录制视频功能。 首先,我们需要在AndroidManifest.xml文件中声明相机和音频录制权限。例如: <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> 然后,我们需要在Activity或Fragment中创建一个CameraManager对象来管理相机设备。例如: private CameraManager mCameraManager; mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); 接下来,我们需要获取可用的相机列表,并选择一个需要使用的相机设备。例如: String cameraId = null; try { for (String id : mCameraManager.getCameraIdList()) { CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id); int facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (facing == CameraCharacteristics.LENS_FACING_BACK) { cameraId = id; break; } } } catch (CameraAccessException e) { e.printStackTrace(); } 然后,我们可以打开相机设备并开始预览。例如: try { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { mCameraManager.openCamera(cameraId, mCameraStateCallback, null); } } catch (CameraAccessException e) { e.printStackTrace(); } 在相机预览过程中,我们可以设置一些相机参数,例如预览尺寸、拍照尺寸、闪光灯模式等。例如: CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureBuilder.addTarget(mPreviewSurface); captureBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); 然后,我们可以通过调用CameraCaptureSession的capture方法来拍照。例如: mCameraCaptureSession.capture(captureBuilder.build(), mCaptureCallback, null); 如果要录制视频,可以通过MediaRecorder来实现。例如: private void startRecording() throws IOException { mMediaRecorder = new MediaRecorder(); mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mMediaRecorder.setOutputFile(mOutputFile.getAbsolutePath()); // 设置视频参数 mMediaRecorder.setVideoEncodingBitRate(10000000); mMediaRecorder.setVideoFrameRate(30); mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight()); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // 设置音频参数 mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); mMediaRecorder.setAudioChannels(1); mMediaRecorder.setAudioSamplingRate(16000); mMediaRecorder.setAudioEncodingBitRate(32000); mMediaRecorder.prepare(); mMediaRecorder.start(); } 最后,我们可以在相机的onClosed方法中释放相机资源和停止录制。例如: @Override public void onClosed(CameraDevice camera) { mCameraDevice.close(); mCameraDevice = null; if (mMediaRecorder != null) { mMediaRecorder.stop(); mMediaRecorder.reset(); mMediaRecorder.release(); mMediaRecorder = null; } } 通过上述步骤,我们可以实现一个简单的安卓Camera2拍照录制视频demo。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值