Android上用摄像头拍照、录视频有两套API可用,Android5.0(API21)之前使用android.hardware.Camera类,之后推荐使用android.hardware.camera2包。目前这两套API都可以使用,Camera类用起来比较简单易懂,但功能少灵活性差,所以现在降级使用;Camera2框架功能强大,对摄像头的控制灵活,但由于大量使用回调方式,所以代码不是线性的,初学比较难懂,不易上手。

本篇先讲解使用Camera类拍照,Camera2框架将在后面介绍。

使用Camera类调用摄像头进行拍照的基本流程是:打开Camera对象、设置预览控件、开始预览、拍照、停止预览、释放资源。拍照后会停止预览,所以如果需要多次拍照的话,需要再次开始预览。要切换摄像头的话,需要先释放当前摄像头,再重新打开新的摄像头。流程和对应的代码如下图:

下面编写一个实现最基本的拍照功能的例子,例子运行在Android8.0(API26)上。例子的界面和主要代码如下:

界面上显示预览的控件用的是SurfaceView,需要将其holder设置到Camera上。实现预览功能时有一个问题,竖屏预览时图像以横屏显示,所以需旋转90度,方法是用语句mCamera.setDisplayOrientation(90)。但只是预览旋转了,生成的图片没有旋转。

拍照需要权限android.permission.CAMERA,也要求硬件支持。

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

拍照可能需要的时间比较长,所以采用异步方式。UI线程启动拍照后不等待结果,而是设置一个回调监听器PictureCallback,当照片数据生成后会回调其onPictureTaken方法,并将数据传入。

例子中将拍照生成的图片文件保存在应用的外部私有存储目录下,该目录可以用方法getExternalFilesDir(null)来获得,其实际位置为:Android/data/<package-name>/files/。向该目录下写文件不需要写外部存储权限。

为了查看拍摄的照片,例子调用了系统中的图片查看应用,为了将图片文件分享给该应用,需要定义一个FileProvider。

<providerandroid:name="androidx.core.content.FileProvider"android:authorities="${applicationId}.fileProvider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths" />
</provider>

FileProvider用到的file_paths.xml定义如下:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"><external-files-pathname="testdir"path="./"/>
</paths>

这里用到的Camera类拍照相关主要方法有:

  • static Camera open(int id):打开摄像头,返回摄像头的Camera对象,id为编号0,1,...切换摄像头时需释放原来Camera对象,再打开另一个摄像头。
  • static int getNumberOfCameras():获取设备摄像头数量,open时用的id都小于此值。
  • void setPreviewDisplay(SurfaceHolder holder):设置预览用的SurfaceHolder控件。
  • setDisplayOrientation(int angle):设置预览旋转角度,竖屏需要旋转90度。
  • void startPreview():开始预览。
  • void takePicture(Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback jpeg):拍照。因为需要一定时间,所以采用异步方式。拍照动作完成后,调用相应回调方法,传回相应数据,并停止预览。三个回调方法分别对应拍照完成、传回原始格式数据,传回jpeg格式数据。对于jpeg格式数据,可以直接保存为jpg格式图片文件,也可以通过BitmapFactory获得Bitmap点阵,然后再转换为其他格式。
  • void stopPreview():停止预览。
  • void release():释放资源。
  • Camera.Parameters getParameters():获取参数。
  • setParameters(Camera.Parameters params):设置参数。

还有一些比较有意思的方法,如startFaceDetection()、startSmoothZoom()等,这里不一一介绍了。

例子的完整代码如下:

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.FileProvider;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;public class MainActivity extends AppCompatActivity {File picFile;Uri picUri;SurfaceView preview;Camera mCamera;int cameraID = 0;boolean isPreviewing = false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);LinearLayout ll = new LinearLayout(this);ll.setOrientation(LinearLayout.VERTICAL);setContentView(ll);LinearLayout line1 = new LinearLayout(this);line1.setOrientation(LinearLayout.HORIZONTAL);ll.addView(line1);LinearLayout line2 = new LinearLayout(this);line2.setOrientation(LinearLayout.HORIZONTAL);ll.addView(line2);picFile = new File(getExternalFilesDir(null), "picture.jpg");//  定义多媒体文件的uri,在应用之间传递文件时需要用uriif(Build.VERSION.SDK_INT>=24){  //  Android 7 以后不能直接用file uri分享文件,要使用FileProviderString fileProviderAuthority = getPackageName() + ".fileProvider"; //  FileProvider的名字,FileProvider在应用配置文件AndroidManifest中定义//  格式为:content://com.zzk.a1508camera.fileProvider/testdir/picture.jpg, testdir是res/file_paths/file_paths.xml中定义的目录别名picUri = FileProvider.getUriForFile(MainActivity.this, fileProviderAuthority, picFile);} else {    //  Android 7 以前可以直接用file uri分享文件//  格式为:file:///storage/emulated/0/Android/data/com.zzk.a1508camera/files/picture.jpgpicUri = Uri.fromFile(picFile);}Button btnOpen = new Button(this);btnOpen.setText("Open");line1.addView(btnOpen);btnOpen.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0) {if (ActivityCompat.checkSelfPermission(getBaseContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, 101);return;}open(cameraID);}});Button btnStartPreview = new Button(this);btnStartPreview.setText("Start Preview");line1.addView(btnStartPreview);btnStartPreview.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0) {if(mCamera!=null) {mCamera.startPreview();isPreviewing = true;}}});Button btnTake = new Button(this);btnTake.setText("Take Photo");line1.addView(btnTake);btnTake.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0) {mCamera.takePicture(null, null, new PictureCallback(){@Overridepublic void onPictureTaken(byte[] arg0, Camera arg1) {FileOutputStream fos;try {fos = new FileOutputStream(picFile);fos.write(arg0);fos.close();} catch (IOException e) {e.printStackTrace();}}});isPreviewing = false;}});Button btnStopPreview = new Button(this);btnStopPreview.setText("Stop Preview");line2.addView(btnStopPreview);btnStopPreview.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0) {if(mCamera!=null) {mCamera.stopPreview();isPreviewing = false;}}});Button btnRelease = new Button(this);btnRelease.setText("Release");line2.addView(btnRelease);btnRelease.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0) {if(mCamera!=null) {mCamera.release();isPreviewing = false;}}});Button btnView = new Button(this);btnView.setText("View");line2.addView(btnView);btnView.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0) {if(picFile.exists()){Intent intent = new Intent(Intent.ACTION_VIEW);intent.setDataAndType(picUri, "image/*");intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //  授予对方读取该文件的权限startActivity(intent);}}});Button btnSwitch = new Button(this);btnSwitch.setText("Switch Camera");ll.addView(btnSwitch);btnSwitch.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0) {if(isPreviewing){cameraID++;if(cameraID>=Camera.getNumberOfCameras()) cameraID = 0;mCamera.stopPreview();mCamera.release();open(cameraID);mCamera.startPreview();}}});preview = new SurfaceView(this);ll.addView(preview);}@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {if(requestCode==101) {if(grantResults[0]== PackageManager.PERMISSION_GRANTED){open(cameraID);}}super.onRequestPermissionsResult(requestCode, permissions, grantResults);}void open(int id){mCamera = Camera.open(id);Camera.Parameters param = mCamera.getParameters();//param.setPictureFormat(PixelFormat.JPEG);//param.setPictureSize(1024, 768);mCamera.setParameters(param);mCamera.setDisplayOrientation(90);try {mCamera.setPreviewDisplay(preview.getHolder());} catch (IOException e) {e.printStackTrace();}Toast.makeText(getBaseContext(), "Camera opened", Toast.LENGTH_SHORT).show();}
}

Android多媒体功能开发(12)——使用Camera类拍照相关推荐

  1. Android多媒体功能开发(11)——使用AudioRecord类录制音频

    AudioRecord类优点是能录制到缓冲区,能够实现边录边播(AudioRecord + AudioTrack)以及对音频的实时处理(如QQ电话).缺点是输出是PCM格式的原始采集数据,如果直接保存 ...

  2. Android多媒体功能开发(6)——使用MediaPlayer类播放音频

    Android播放音频资源主要有两个类:MediaPlayer和SoundPool. MediaPlayer用于实现对一个音频的播放控制,侧重于启动.停止.暂停.位置控制等操作.不支持同时播放多个音频 ...

  3. Android多媒体功能开发(4)——调用系统Activity拍照、选择图片、查看图片、裁剪图片

    一.拍照 拍照界面就是调用系统照相机,动作为MediaStore.ACTION_IMAGE_CAPTURE.生成的照片有三种返回方式: 在调用拍照应用的Intent中通过EXTRA_OUTPUT属性设 ...

  4. 《Android多媒体应用开发实战详解:图像、音频、视频、2D和3D》——1.3节搭建Android应用开发环境...

    本节书摘来自异步社区<Android多媒体应用开发实战详解:图像.音频.视频.2D和3D>一书中的第1章,第1.3节搭建Android应用开发环境,作者 王石磊 , 吴峥,更多章节内容可以 ...

  5. 《Android多媒体应用开发实战详解:图像、音频、视频、2D和3D》——2.3节简析Android安装文件...

    本节书摘来自异步社区<Android多媒体应用开发实战详解:图像.音频.视频.2D和3D>一书中的第2章,第2.3节简析Android安装文件,作者 王石磊 , 吴峥,更多章节内容可以访问 ...

  6. 《Android多媒体应用开发实战详解:图像、音频、视频、2D和3D》——2.1节简析Android安装文件...

    本节书摘来自异步社区<Android多媒体应用开发实战详解:图像.音频.视频.2D和3D>一书中的第2章,第2.1节简析Android安装文件,作者 王石磊 , 吴峥,更多章节内容可以访问 ...

  7. 《Android多媒体应用开发实战详解:图像、音频、视频、2D和3D》——1.2节Android的巨大优势...

    本节书摘来自异步社区<Android多媒体应用开发实战详解:图像.音频.视频.2D和3D>一书中的第1章,第1.2节Android的巨大优势,作者 王石磊 , 吴峥,更多章节内容可以访问云 ...

  8. Android多功能智能相机(AI Camera)

    技术:JDK 1.7 + SDK 28 + Android Studio 3.4.2+手机Android 4.4以上 运行环境:Java + Android Camera API 源代码下载: htt ...

  9. Android多媒体应用开发-控制摄像头拍照

    现在的手机的功能可谓是五花八门,手机照相功能就是特别突出的一点,现在的手机照相机甚至成了专业数码照相机,可以拍摄出清晰的照片和录制高分辨率的视频.Android操作系统呢,提供了相应的功能来控制拍照: ...

最新文章

  1. 2022年,PyTorch在AI顶会的占比已经上80%了
  2. 研究生的研究人员发展课程
  3. XCTF-高手进阶区:lottery
  4. c:if test=/c:if 使用
  5. 42、Java服务内存OOM原因分析
  6. springboot实践1
  7. 2.Spring Boot 入门
  8. 解决pytorch DataLoader 加载数据报错UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0xe5 in position 1023
  9. 函数:使用数组名作为函数参数进行操作
  10. java 索引实现,Java创建ES索引实现
  11. 【CCCC】L3-006 迎风一刀斩 (30分),几何关系,找规律 (拼合多边形==斜边等价)
  12. Linux命令第一篇
  13. Hadoop安装教程_单机/伪分布式配置_Hadoop 2.7.7(2.7.7)/CentOS Linux release 7.4.1708
  14. Django中使用163邮箱发送邮件
  15. Spark简介、生态系统
  16. 「好书推荐」那些精彩的引人深思、充满反转的推理小说推荐
  17. 商用密码应用与安全性评估之(四)密码应用安全性评估实施要点
  18. 华硕笔记本刷BIOS
  19. C语言实现字母的大写转换成小写
  20. VMware卸载不干净导致无法重安

热门文章

  1. tomcat端口被占用的解决办法
  2. 前端开发需要学多长时间?
  3. Windows Server 2003 禁止关机事件跟踪
  4. 创业日志(二十九)身体是革命的本钱
  5. 织梦php源码,织梦 | php教程|php源码|php学习
  6. 7-5 单身狗 (25 分)
  7. mysql查看数据库创建语句_sql语句1数据库创建、查看
  8. 烧烤店引流客源最快的方法
  9. 海康工业网口相机组播功能
  10. SAP参数记忆功能失效