Android拍照、录像、录音代码范例
- 格式:pdf
- 大小:254.93 KB
- 文档页数:6
Android的MediaRecorder框架介绍框架AndroidJNI应用服务器多线程第一部分 MediaRecorder概述Android的MediaRecorder包含了Audio和video的记录功能,在Android的界面上,Music和Video两个应用程序都是调用MediaRecorder实现的。
MediaRecorder在底层是基于OpenCore(PacketVideo)的库实现的,为了构建一个MediaRecorder程序,上层还包含了进程间通讯等内容,这种进程间通讯的基础是Android基本库中的Binder机制。
以开源的Android为例MediaRecorder的代码主要在以下的目录中:JAVA程序的路径:/packages/apps/SoundRecorder/src/com/android/soundrecorder/SoundRecorder.java JAVA Framework的路径:frameworks/base/media/java/android/media/MediaRecorder.javaJAVA本地调用部分(JNI):frameworks/base/media/jni/android_media_MediaRecorder.cpp这部分内容编译成为目标是libmedia_jni.so。
主要的头文件在以下的目录中:frameworks/base/include/media/多媒体底层库在以下的目录中:frameworks/base/media/libmedia/这部分的内容被编译成库libmedia.so。
多媒体服务部分:frameworks/base/media/libmediaplayerservice/MediaRecorder和MeidaPlayer使用相同的服务。
基于OpenCore部分PVAuthor是基于OpenCore的AuthorEngine的Android实现,代码在以下路径中: external/opencore/android/author这部分内容被编译成库libopencoreauthor.so。
Android使⽤系统相机进⾏拍照的步骤前⾔我们在⽇常的开发中有时候会遇到需要⽤到相机的需求,⽽相机也是很常⽤的东西,例如扫⼆维码啊拍照上传啊等等。
这⾥我不讲像qq那样⾃定义很强的拍照功能(事实上我也不会),讲个最简单的调⽤系统相机拍照并储存调⽤系统相机步骤这⾥我通过⼀个简单的例⼦来讲这个内容。
我⾃⼰写了⼀个demo,布局很简单:<Buttonandroid:id="@+id/button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="4dp"android:text="take phone"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="0.281"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><ImageViewandroid:id="@+id/imageView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="29dp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/button"app:srcCompat="@mipmap/ic_launcher_round" />就是⼀个按钮点击弹起相机,然后⼀个imageView显⽰拍到的照⽚。
Android调用系统摄像头拍照,并把照片保存到本地,然后显示在Imageviewimg=(ImageView)findView ById(R.id.img);take_picture=(Button)findViewById(R.id.take_picture);take_picture.setOnClickListener(new V iew.OnClickListener() {@Overridepublic void onClick(V iew v) {// TODO Auto-generated method stubIntent intent = new Intent( android.media.action.IMAGE_CAPTUREstartActivityForResult(intent,Activity.DEFAULT_KEYS_DIALER);});protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == Activity.RESULT_OK) {String sdStatus = Environment.getExternalStorageState();if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) { // 检测sd是否可用return;Bundle bundle = data.getExtras();Bitmap bitmap = (Bitmap) bundle.get( data // 获取相机返回的数据,并转换为Bitmap图片格式FileOutputStream b = null;File file = new File( /sdcard/myImage/file.mkdirs();// 创建文件夹,名称为myimage//照片的命名,目标文件夹下,以当前时间数字串为名称,即可确保每张照片名称不相同。
Android读取本地照⽚和视频相册实例代码前⾔项⽬中经常要选择本地照⽚或者视频的需求,如果去扫描整个SD卡就太耗时间,其实Android系统在启动时就已经把整个设备中的多媒体⽂件信息(⽂件名,类型,⼤⼩等)都存到了数据库,然后提供了ContentPrivider这个API来管理这个数据库,我们可以利⽤ContentPrivider来获取所有的照⽚和视频。
ContentPrivider初识先看下管理的的数据库在哪data/data/⽬录下:有很多这种⽂件夹(⽇历,联系⼈,下载管理,多媒体等)我们需要的照⽚和视频就在media下⾯,进去看看。
进去找到database然后打开external.db,就可以看到多张表(⾳频,⽂件,Log,图像,视频等)照⽚相册那么获取照⽚直接通过 ContentProvider读取Images这个数据库就OK了,这⾥开启⼯作线程读取所有.jpeg和.png的图⽚,附上代码段:/*** 读取⼿机中所有图⽚信息*/private void getAllPhotoInfo() {new Thread(new Runnable() {@Overridepublic void run() {List<MediaBean> mediaBeen = new ArrayList<>();HashMap<String,List<MediaBean>> allPhotosTemp = new HashMap<>();//所有照⽚Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;String[] projImage = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA,MediaStore.Images.Media.SIZE,MediaStore.Images.Media.DISPLAY_NAME};Cursor mCursor = getContentResolver().query(mImageUri,projImage,MediaStore.Images.Media.MIME_TYPE + "=? or " + MediaStore.Images.Media.MIME_TYPE + "=?",new String[]{"image/jpeg", "image/png"},MediaStore.Images.Media.DATE_MODIFIED+" desc");if(mCursor!=null){while (mCursor.moveToNext()) {// 获取图⽚的路径String path = mCursor.getString(mCursor.getColumnIndex(MediaStore.Images.Media.DATA));int size = mCursor.getInt(mCursor.getColumnIndex(MediaStore.Images.Media.SIZE))/1024;String displayName = mCursor.getString(mCursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));//⽤于展⽰相册初始化界⾯mediaBeen.add(new MediaBean(MediaBean.Type.Image,path,size,displayName));// 获取该图⽚的⽗路径名String dirPath = new File(path).getParentFile().getAbsolutePath();//存储对应关系if (allPhotosTemp.containsKey(dirPath)) {List<MediaBean> data = allPhotosTemp.get(dirPath);data.add(new MediaBean(MediaBean.Type.Image,path,size,displayName));continue;} else {List<MediaBean> data = new ArrayList<>();data.add(new MediaBean(MediaBean.Type.Image,path,size,displayName));allPhotosTemp.put(dirPath,data);}}mCursor.close();}//更新界⾯runOnUiThread(new Runnable() {@Overridepublic void run() {//...}});}}).start();}有四点需要注意:1. MediaBean是⽂件实体类,代码就不贴了2. 照⽚集合不是放在List<MediaBean>这样存储的,⽽是HashMap<String,List<MediaBean>>,这样把图⽚已⽂件夹(也就是⽗⽬录)分类,更节省内存,其次⽀持相册展⽰不同⽂件夹的照⽚3. 貌似没办法获取当前设备的拍照默认路径,有的设备是/DCIM,有的是/100andro还有/camera,那相册就默认展⽰最近所有照⽚吧。
Android调用手机拍照以及从相册选择照片/*用来标识请求照相功能的activity*/private static final int CAMERA_WITH_DATA = 3023;/*用来标识请求gallery的activity*/private static final int PHOTO_PICKED_WITH_DATA = 3021;/*拍照的照片存储位置*/private static final File PHOTO_DIR = newFile(Environment.getExternalStorageDirectory() + "/DCIM/Camera");private File mCurrentPhotoFile;//照相机拍照得到的图片private void doPickPhotoAction() {Context context = EditContact.this;// Wrap our context to inflate list items using correct themefinal Context dialogContext = new ContextThemeWrapper(context,android.R.style.Theme_Light);String cancel="返回";String[] choices;choices = new String[2];choices[0] = getString(R.string.take_photo); //拍照choices[1] = getString(R.string.pick_photo); //从相册中选择final ListAdapter adapter = new ArrayAdapter<String>(dialogContext,yout.simple_list_item_1, choices);final AlertDialog.Builder builder = new AlertDialog.Builder(dialogContext);builder.setTitle(R.string.attachToContact);builder.setSingleChoiceItems(adapter, -1,new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {dialog.dismiss();switch (which) {case 0:{Stringstatus=Environment.getExternalStorageState();if(status.equals(Environment.MEDIA_MOUNTED)){//判断是否有SD卡doTakePhoto();// 用户点击了从照相机获取}else{showToast("没有SD卡");}break;}case 1:doPickPhotoFromGallery();// 从相册中去获取break;}}});builder.setNegativeButton(cancel, newDialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}});builder.create().show();}}/*** 拍照获取图片**/protected void doTakePhoto() {try {// Launch camera to take photo for selected contactPHOTO_DIR.mkdirs();// 创建照片的存储目录mCurrentPhotoFile = new File(PHOTO_DIR, getPhotoFileName());// 给新照的照片文件命名final Intent intent = getTakePickIntent(mCurrentPhotoFile);startActivityForResult(intent, CAMERA_WITH_DATA);} catch (ActivityNotFoundException e) {Toast.makeText(this, R.string.photoPickerNotFoundText,Toast.LENGTH_LONG).show();}}public static Intent getTakePickIntent(File f) {Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null);intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));return intent;}/*** 用当前时间给取得的图片命名**/private String getPhotoFileName() {Date date = new Date(System.currentTimeMillis());SimpleDateFormat dateFormat = new SimpleDateFormat("'IMG'_yyyy-MM-dd HH:mm:ss");return dateFormat.format(date) + ".jpg";}// 请求Gallery程序protected void doPickPhotoFromGallery() {try {// Launch picker to choose photo for selected contactfinal Intent intent = getPhotoPickIntent();startActivityForResult(intent, PHOTO_PICKED_WITH_DATA);} catch (ActivityNotFoundException e) {Toast.makeText(this, R.string.photoPickerNotFoundText1,Toast.LENGTH_LONG).show();}}// 封装请求Gallery的intentpublic static Intent getPhotoPickIntent() {Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);intent.setType("image/*");intent.putExtra("crop", "true");intent.putExtra("aspectX", 1);intent.putExtra("aspectY", 1);intent.putExtra("outputX", 80);intent.putExtra("outputY", 80);intent.putExtra("return-data", true);return intent;}// 因为调用了Camera和Gally所以要判断他们各自的返回情况,他们启动时是这样的startActivityForResultprotected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode != RESULT_OK)return;switch (requestCode) {case PHOTO_PICKED_WITH_DATA: {// 调用Gallery返回的final Bitmap photo = data.getParcelableExtra("data");// 下面就是显示照片了System.out.println(photo);//缓存用户选择的图片img = getBitmapByte(photo);mEditor.setPhotoBitmap(photo);System.out.println("set new photo");break;}case CAMERA_WITH_DATA: {// 照相机程序返回的,再次调用图片剪辑程序去修剪图片doCropPhoto(mCurrentPhotoFile);break;}}}protected void doCropPhoto(File f) {try {// 启动gallery去剪辑这个照片final Intent intent = getCropImageIntent(Uri.fromFile(f));startActivityForResult(intent, PHOTO_PICKED_WITH_DATA);} catch (Exception e) {Toast.makeText(this, R.string.photoPickerNotFoundText,Toast.LENGTH_LONG).show();}}/*** Constructs an intent for image cropping. 调用图片剪辑程序*/public static Intent getCropImageIntent(Uri photoUri) {Intent intent = new Intent("com.android.camera.action.CROP");intent.setDataAndType(photoUri, "image/*");intent.putExtra("crop", "true");intent.putExtra("aspectX", 1);intent.putExtra("aspectY", 1);intent.putExtra("outputX", 80);intent.putExtra("outputY", 80);intent.putExtra("return-data", true);return intent;}。
Android Camera 调用流程Android Camera的代码结构Android的Camera代码主要在以下的目录中:Camera的JAVA部分packages/apps/Camera/。
其中Camera.java是主要实现的文件。
这部分内容编译成为目标是Camera.apkcom.android.camera这个包,几个主要的类文件如下:PhotoViewer:GalleryPicker.java(所有图片集)--->ImageGallery.java(某个Folder下图片列表)--->ViewImage.java(看某张具体图片)VideoPlayer:GalleryPicker.java(所有视频集)--->MovieView.java(看某一个视频)Camera:Camera.java(Camera取景及拍照)VideoCamera:VideoCamera.java(VideoCamera取景及摄像)Camera的framework供上层应用调用的部分base/core/java/android/hardware/Camera.java这部分目标是framework.jarCamera的JNI部分frameworks/base/core/jni/android_hardware_Camera.cpp这部分内容编译成为目标是libandroid_runtime.so。
Camera UI库部分frameworks/base/libs/camera这部分的内容被编译成库libcamera_client.so。
Camera服务部分frameworks/base/services/camera/libcameraservic这部分内容被编译成库libcameraservice.so。
Camera HAL层部分hardware/msm7k/libcamera或vendor/qcom/android-open/libcamera2为了实现一个具体功能的Camera,在HAL层需要一个硬件相关的Camera库(例如通过调用video for linux驱动程序和Jpeg编码程序实现或者直接用各个chip厂商实现的私有库来实现,比如Qualcomm实现的libcamera.so和libqcamera.so),实现CameraHardwareInterface规定的接口,来调用相关的库,驱动相关的driver,实现对camera 硬件的操作。
javacameraview用法Javacameraview是一个在Java中使用相机功能的开源库。
它提供了一些简单易用的方法来实现拍照、录像和预览相机画面等功能。
要使用javacameraview,首先需要在项目中引入该库。
你可以在Github上找到该库的源码,然后将它添加到你的项目中。
在使用javacameraview之前,你需要在AndroidManifest.xml文件中添加相机权限。
这可以通过在<manifest>标签内添加以下代码来实现:<uses-permission android:name="android.permission.CAMERA" />接下来,在你的布局文件中,你需要添加一个Javacameraview实例。
这可以通过使用以下代码在<RelativeLayout>或<FrameLayout>标签内来实现:<com.example.javacameraview.JavaCameraViewandroid:id="@+id/camera_view"android:layout_width="match_parent"android:layout_height="match_parent"/>在你的Activity或Fragment中,你需要初始化Javacameraview实例。
你可以通过以下代码在onCreate()方法中实现:JavaCameraView mJavaCameraView;protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);mJavaCameraView = (JavaCameraView) findViewById(R.id.camera_view);}接下来,在onResume()方法中,你需要调用startCamera()方法来启动相机预览功能,并设置相机预览的尺寸。
详解Android开发录⾳和播放⾳频的步骤(动态获取权限)步骤:配置权限:<manifest xmlns:android="/apk/res/android" package="com.work.mediaplay"><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission><uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>代码步骤:public class MainActivity extends AppCompatActivity implements View.OnClickListener{private Button btn_start, btn_stop;private ListView lv_content;private File sdcardfile = null;private String[] files;private MediaRecorder recorder=null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);initView();getSDCardFile();getFileList();}/*** ①实例化控件*/private void initView() {btn_start = (Button) findViewById(R.id.btn_stat);btn_stop = (Button) findViewById(R.id.btn_stop);lv_content = (ListView) findViewById(R.id.lv_content);//⑤给按钮添加监听事件btn_start.setOnClickListener(this);btn_stop.setOnClickListener(this);//设置起始状态开始按钮可⽤,停⽌按钮不可⽤btn_start.setEnabled(true);btn_stop.setEnabled(false);}/*** ②获取内存卡中⽂件的⽅法*/private void getSDCardFile() {if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//内存卡存在sdcardfile=Environment.getExternalStorageDirectory();//获取⽬录⽂件}else {Toast.makeText(this,"未找到内存卡",Toast.LENGTH_SHORT).show();}}/*** ③获取⽂件列表(listView中的数据源)* 返回指定⽂件类型的⽂件名的集合作为数据源*/private void getFileList(){if(sdcardfile!=null){files=sdcardfile.list(new MyFilter());lv_content.setAdapter(new ArrayAdapter<String>(this,yout.simple_list_item_1,files));//⑥给ListView中的元素添加点击播放事件lv_content.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {//⑩定义播放⾳频的⽅法play(files[position]);}}}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.btn_stat://⑧申请录制⾳频的动态权限if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED){ActivityCompat.requestPermissions(this,new String[]{android.Manifest.permission.RECORD_AUDIO},1);}else {startRecord();}break;case R.id.btn_stop:stopRcecord();break;}}/*** ④定义⼀个⽂件过滤器MyFilter的内部类,实现FilenameFilter接⼝* 重写⾥边accept⽅法*/class MyFilter implements FilenameFilter{@Overridepublic boolean accept(File pathname,String fileName) {return fileName.endsWith(".amr");}}/*** ⑦给两个按钮定义开始和暂停的⽅法**/private void startRecord(){if(recorder==null){recorder=new MediaRecorder();}recorder.setAudioSource(MediaRecorder.AudioSource.MIC);//设置⾳频源为⼿机麦克风recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);//设置输出格式3gprecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);//设置⾳频编码为amr格式 //获取内存卡的根⽬录,创建临时⽂件try {File file=File.createTempFile("录⾳_",".amr",sdcardfile);recorder.setOutputFile(file.getAbsolutePath());//设置⽂件输出路径//准备和启动录制⾳频recorder.prepare();recorder.start();} catch (IOException e) {e.printStackTrace();}//启动后交换两个按钮的可⽤状态btn_start.setEnabled(false);btn_stop.setEnabled(true);}private void stopRcecord(){if(recorder!=null){recorder.stop();recorder.release();recorder=null;}btn_start.setEnabled(true);btn_stop.setEnabled(false);//刷新列表数据getFileList();}/*** ⑨重写onRequestPermissionsResult⽅法* 获取动态权限请求的结果,再开启录制⾳频@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if(requestCode==1&&grantResults[0]==PackageManager.PERMISSION_GRANTED){startRecord();}else {Toast.makeText(this,"⽤户拒绝了权限",Toast.LENGTH_SHORT).show();}super.onRequestPermissionsResult(requestCode, permissions, grantResults);}/*** ⑩定义播放⾳频的⽅法*/private void play(String fileName){Intent intent=new Intent(Intent.ACTION_VIEW);//播放⾳频需要uri,从⽂件中获取,⽂件中需要路径Uri uri=Uri.fromFile(new File(sdcardfile.getAbsoluteFile()+File.separator+fileName));//设置播放数据和类型intent.setDataAndType(uri,"audio/*");startActivity(intent);}以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。