Android Camera开发:使用TextureView和SurfaceTexture预览Camera 基础拍照demo
Google自Android4.0出了TextureView,为什么推出呢?就是为了弥补Surfaceview的不足,另外一方面也是为了平衡GlSurfaceView,当然这是本人揣度的。关于TextureView、Surfaceview、SurfaceTexture、GLSurfaceView的关系,待咱家推出GLSurfaceview预览Camera后再专门分析。本文主要介绍使用TextureView预览Camera。
其实关于如何用TextureView预览Camera,官网已经给出了demo,参见这里。另外,链接1 链接2也给出了完整的预览Camera的demo,但都是一堆东西染在一块。本文就利用前文 搭建的一个轻量级的Camera框架来快速替换掉Surfaceview。因为用Surfaceview预览的话传一个SurfaceHolder进去,用Textureview预览的话需要传进去一个SurfaceTexture。其他的Camera流程不变。
一、新建CameraTextureView类继承TextureView,并实现TextureView.SurfaceTextureListener接口。实现这个接口就像实现SurfaceHolder.Callback,最主要的目的是在SurfaceTexture准备好后能够知道,也即onSurfaceTextureAvailable这个函数。
CameraTextureView.java
- package org.yanzi.camera.preview;
- import org.yanzi.camera.CameraInterface;
- import android.content.Context;
- import android.graphics.PixelFormat;
- import android.graphics.SurfaceTexture;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- import android.view.TextureView;
- public class CameraTextureView extends TextureView implements TextureView.SurfaceTextureListener {
- private static final String TAG = "yanzi";
- Context mContext;
- SurfaceTexture mSurface;
- public CameraTextureView(Context context, AttributeSet attrs) {
- super(context, attrs);
- // TODO Auto-generated constructor stub
- mContext = context;
- this.setSurfaceTextureListener(this);
- }
- @Override
- public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
- int height) {
- // TODO Auto-generated method stub
- Log.i(TAG, "onSurfaceTextureAvailable...");
- mSurface = surface;
- // CameraInterface.getInstance().doStartPreview(surface, 1.33f);
- }
- @Override
- public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
- // TODO Auto-generated method stub
- Log.i(TAG, "onSurfaceTextureDestroyed...");
- CameraInterface.getInstance().doStopCamera();
- return true;
- }
- @Override
- public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
- int height) {
- // TODO Auto-generated method stub
- Log.i(TAG, "onSurfaceTextureSizeChanged...");
- }
- @Override
- public void onSurfaceTextureUpdated(SurfaceTexture surface) {
- // TODO Auto-generated method stub
- Log.i(TAG, "onSurfaceTextureUpdated...");
- }
- /* 让Activity能得到TextureView的SurfaceTexture
- * @see android.view.TextureView#getSurfaceTexture()
- */
- public SurfaceTexture _getSurfaceTexture(){
- return mSurface;
- }
- }
二、在布局文件里把它加上就行了,因为他的父类就是View,当成一般的View就行
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".CameraActivity" >
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
- <org.yanzi.camera.preview.CameraTextureView
- android:id="@+id/camera_textureview"
- android:layout_width="0dip"
- android:layout_height="0dip" />
- </FrameLayout>
- <ImageButton
- android:id="@+id/btn_shutter"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/btn_shutter_background"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
- android:layout_marginBottom="10dip"/>
- </RelativeLayout>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
三、在CameraInterface里,我封装了两个函数:
- /**使用Surfaceview开启预览
- * @param holder
- * @param previewRate
- */
- public void doStartPreview(SurfaceHolder holder, float previewRate){
- Log.i(TAG, "doStartPreview...");
- if(isPreviewing){
- mCamera.stopPreview();
- return;
- }
- if(mCamera != null){
- try {
- mCamera.setPreviewDisplay(holder);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- initCamera(previewRate);
- }
- }
- /**使用TextureView预览Camera
- * @param surface
- * @param previewRate
- */
- public void doStartPreview(SurfaceTexture surface, float previewRate){
- Log.i(TAG, "doStartPreview...");
- if(isPreviewing){
- mCamera.stopPreview();
- return;
- }
- if(mCamera != null){
- try {
- mCamera.setPreviewTexture(surface);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- initCamera(previewRate);
- }
- }
分别对应Surfaceview和TextureView预览。可以看到就是传进来的参数不一样,initCamera()的东西都一样。
- private void initCamera(float previewRate){
- if(mCamera != null){
- mParams = mCamera.getParameters();
- mParams.setPictureFormat(PixelFormat.JPEG);//设置拍照后存储的图片格式
- // CamParaUtil.getInstance().printSupportPictureSize(mParams);
- // CamParaUtil.getInstance().printSupportPreviewSize(mParams);
- //设置PreviewSize和PictureSize
- Size pictureSize = CamParaUtil.getInstance().getPropPictureSize(
- mParams.getSupportedPictureSizes(),previewRate, 800);
- mParams.setPictureSize(pictureSize.width, pictureSize.height);
- Size previewSize = CamParaUtil.getInstance().getPropPreviewSize(
- mParams.getSupportedPreviewSizes(), previewRate, 800);
- mParams.setPreviewSize(previewSize.width, previewSize.height);
- mCamera.setDisplayOrientation(90);
- // CamParaUtil.getInstance().printSupportFocusMode(mParams);
- List<String> focusModes = mParams.getSupportedFocusModes();
- if(focusModes.contains("continuous-video")){
- mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
- }
- mCamera.setParameters(mParams);
- mCamera.startPreview();//开启预览
- isPreviewing = true;
- mPreviwRate = previewRate;
- mParams = mCamera.getParameters(); //重新get一次
- Log.i(TAG, "最终设置:PreviewSize--With = " + mParams.getPreviewSize().width
- + "Height = " + mParams.getPreviewSize().height);
- Log.i(TAG, "最终设置:PictureSize--With = " + mParams.getPictureSize().width
- + "Height = " + mParams.getPictureSize().height);
- }
- }
四、在Activity里,依旧开一个线程去open Camera
- Thread openThread = new Thread(){
- @Override
- public void run() {
- // TODO Auto-generated method stub
- CameraInterface.getInstance().doOpenCamera(CameraActivity.this);
- }
- };
- openThread.start();
在Camera Open完的回调里开预览:
- @Override
- public void cameraHasOpened() {
- // TODO Auto-generated method stub
- SurfaceTexture surface = textureView._getSurfaceTexture();
- CameraInterface.getInstance().doStartPreview(surface, previewRate);
- }
之后就能正常运行了,可以看到与前文Surfaceview预览Camera 改动非常之小。
几个注意事项:
1、TextureView是Android 4.0之后加入的,低版本么这个类。TextureView必须工作在开启硬件加速的环境中,也即配置文件里Activity的设置项里:android:hardwareAccelerated="true" 默认的这个属性就是true,因此不用再写了。但如果写成false,可以看到onSurfaceTextureAvailable()这个回调就进不来了,TextureView没有了SurfaceTexture还玩个屁啊。
2、本文demo打开camera并预览的正常log是:
- Line 417: 06-22 12:37:43.682 I/yanzi ( 4917): Camera open....
- Line 489: 06-22 12:37:43.758 I/yanzi ( 4917): onSurfaceTextureAvailable...
- Line 533: 06-22 12:37:43.819 I/yanzi ( 4917): Camera open over....
- Line 535: 06-22 12:37:43.819 I/yanzi ( 4917): doStartPreview...
- Line 537: 06-22 12:37:43.825 I/yanzi ( 4917): PictureSize : w = 1280h = 720
- Line 539: 06-22 12:37:43.825 I/yanzi ( 4917): PreviewSize:w = 800h = 448
- Line 555: 06-22 12:37:43.874 I/yanzi ( 4917): 最终设置:PreviewSize--With = 800Height = 448
- Line 557: 06-22 12:37:43.874 I/yanzi ( 4917): 最终设置:PictureSize--With = 1280Height = 720
- Line 577: 06-22 12:37:44.106 I/yanzi ( 4917): onSurfaceTextureUpdated...
- Line 579: 06-22 12:37:44.138 I/yanzi ( 4917): onSurfaceTextureUpdated...
- Line 583: 06-22 12:37:44.169 I/yanzi ( 4917): onSurfaceTextureUpdated...
- Line 585: 06-22 12:37:44.220 I/yanzi ( 4917): onSurfaceTextureUpdated...
- Line 587: 06-22 12:37:44.253 I/yanzi ( 4917): onSurfaceTextureUpdated...
测试手机为中兴Geek,这个手机Camera还是很牛逼的,比手里的华为G700强,就是偶尔会连不上Camera Service,汗。从log可以看到,onSurfaceTextureAvailable这个回调需要一定时间。Camera.open()这句话用了130多ms。但有两点跟Surfaceview不同。第一,TextureView创建过程中没有进到onSurfaceTextureSizeChanged()这个函数里。而SurfaceView在创建过程中,从无到有的时候会进到大小发生变化回调里。第二,onSurfaceTextureUpdated()这个函数每上来一帧数据,这块就进来一次。这是跟Surfaceview相比,最伟大的一个地方。通过这个接口,可以将上来的SurfaceTexture送给OpenGL再去处理。这个回调是实时的,而非用Camera的PreviewCallback这种2次回调的方式。从时间看,基本上每32ms左右上来一帧数据,即每秒30帧,跟本手机的Camera的性能吻合。
3、Camera再执行startPreview时必须保证TextureView的SurfaceTexture上来了,如果因为一些性能原因onSurfaceTextureAvailable()这个回调上不来就开预览,就开不了的。如果发生这种情况,就在onSurfaceTextureAvailable()回调里执行open和startPreview操作,保证万无一失。
4、TextureView本身就有getSurfaceTexture()这个函数,我又封装了个:
- /* 让Activity能得到TextureView的SurfaceTexture
- * @see android.view.TextureView#getSurfaceTexture()
- */
- public SurfaceTexture _getSurfaceTexture(){
- return mSurface;
- }
这里的mSurface就是onSurfaceTextureAvailable()回调里传上来的SurfaceTexture。测试证明,开预览时直接调
textureView.getSurfaceTexture(),把它传给Camera: mCamera.setPreviewTexture(surface);也是能正常预览的。但是推荐使用前者,原因见官方上的这段话:
A TextureView's SurfaceTexture can be obtained either by invoking getSurfaceTexture()
or by using a TextureView.SurfaceTextureListener
. It is important to know that a SurfaceTexture is available only after the TextureView is attached to a window (and onAttachedToWindow()
has been invoked.) It is therefore highly recommended you use a listener to be notified when the SurfaceTexture becomes available.
两种方式获得SurfaceTexture,推荐使用监听。因为只有在TextureView执行完onAttachedToWindow时,它的tSurfaceTexture才上来。
5、SurfaceTexture和TextureView的关系:
Using a TextureView is simple: all you need to do is get its SurfaceTexture
. The SurfaceTexture
can then be used to render content
如果说TextureView是一幅画的话,那SurfaceTexture就是画布,真正渲染的载体是SurfaceTexture。
6、TextureView可以像一般View执行各种变化,其中有个textureView.setAlpha(1.0f);默认不写这句话,它的alpha也是1.0f,即不透明。如果设成透明0.0f,可以看到啥都看不到了,这一点跟Surfaceview刚好相反。Surfaceview的SurfaceHolder一般要设一下Transparent即透明。但TextureView因为是个view,任何一个png的照片透明度设成0肯定啥都看不到。
7、如果认为预览个Camera这就是TextureView和SurfaceTexture的使命的话,就大错特错了,真正用意是和OpenGL无缝连接。
--------------------本文系原创,转载请注明作者yanzi1225627
版本号:PlayCamera_V2.0.0[2014-6-22].zip
CSDN下载链接:http://download.csdn.net/detail/yanzi1225627/7540903
Android Camera开发:使用TextureView和SurfaceTexture预览Camera 基础拍照demo的更多相关文章
- 玩转Android Camera开发(二):使用TextureView和SurfaceTexture预览Camera 基础拍照demo
Google自Android4.0出了TextureView,为什么推出呢?就是为了弥补Surfaceview的不足,另外一方面也是为了平衡GlSurfaceView,当然这是本人揣度的.关于Text ...
- Android Camera开发:使用GLSurfaceView预览Camera 基础拍照
GLSurfaceView是OpenGL中的一个类,也是可以预览Camera的,而且在预览Camera上有其独到之处.独到之处在哪?当使用Surfaceview无能为力.痛不欲生时就只有使用GLSur ...
- 【转】玩转Android Camera开发(三):国内首发---使用GLSurfaceView预览Camera 基础拍照demo
http://blog.csdn.net/yanzi1225627/article/details/33339965 GLSurfaceView是OpenGL中的一个类,也是可以预览Camera的,而 ...
- 玩转Android Camera开发(三):国内首发---使用GLSurfaceView预览Camera 基础拍照demo
GLSurfaceView是OpenGL中的一个类,也是能够预览Camera的,并且在预览Camera上有其独到之处. 独到之处在哪?当使用Surfaceview无能为力.痛不欲生时就仅仅有使用GLS ...
- Android开发实践:掌握Camera的预览方向和拍照方向
http://ticktick.blog.51cto.com/823160/1592267?utm_source=tuicool&utm_medium=referral Android的Cam ...
- 玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo
杂家前文是在2012年的除夕之夜仓促完成,后来很多人指出了一些问题,琐事缠身一直没有进行升级.后来随着我自己的使用,越来越发现不出个升级版的demo是不行了.有时候就连我自己用这个demo测一些性能. ...
- Android开发 Camera2开发_2_预览分辨率或拍照分辨率的计算
前言 不管在Camera1或者Camera2在适配不同手机/不同使用场景的情况下都需要计算摄像头里提供的分辨率列表中最合适的那一个分辨率.所以在需要大量机型适配的app,是不建议不经过计算直接自定义分 ...
- Android Camera2采集摄像头原始数据并手动预览
Android Camera2采集摄像头原始数据并手动预览 最近研究了一下android摄像头开发相关的技术,也看了Google提供的Camera2Basic调用示例,以及网上一部分代码,但都是在Te ...
- SpringBoot+FreeMarker开发word文档下载,预览
背景: 开发一个根据模版,自动填充用户数据并下载word文档的功能 使用freemarker进行定义模版,然后把数据进行填充. maven依赖: <parent> <groupId& ...
随机推荐
- Java操作Oracle数据库以及调用存储过程
操作Oracle数据库 publicclass DBConnection { //jdbc:oracle:thin:@localhost:1521:orcl publicstaticf ...
- [BZOJ 1014] [JSOI2008] 火星人prefix 【Splay + Hash】
题目链接:BZOJ - 1014 题目分析 求两个串的 LCP ,一种常见的方法就是 二分+Hash,对于一个二分的长度 l,如果两个串的长度为 l 的前缀的Hash相等,就认为他们相等. 这里有修改 ...
- 如何用 React Native 创建一个iOS APP?(三)
前两部分,<如何用 React Native 创建一个iOS APP?>,<如何用 React Native 创建一个iOS APP (二)?>中,我们分别讲了用 React ...
- salt-API基本验证命令
配置SALT-API,网上有很多,作下来也很顺利. 我的参考: 作一下验证的记录: curl -k https://x.x.x.x:8000/login -H "Accept: applic ...
- php生成的中文文件名会变成乱码,应该这样解决
现在php有很多类库,会生成文件,比如生成zip文件,生成二维码等等.这些类库用起来很爽,但是一旦生成带有中文的文件名,极有可能出现乱码. 问题:生成的中文文件名会变成乱码 解决:使用函数:iconv ...
- hibernate异常:Could not determine type for: java.util.Set
根本原因:我实体类中的类型是raw,没法直接实例化的类型.private List<String> rightChoices;private Set<String> multi ...
- bzoj3790
观察发现,这道题目其实就相当于一个最小区间覆盖问题这里的区间是指以每个点为中心的最长回文串很久没写manacher,有点感动不得不说manacher是一个非常好的算法 ..] of char; c,l ...
- Python copy对象(copy与deepcopy)
Python中的对象之间赋值时是按引用传递的,如果需要拷贝对象,需要使用标准库中的copy模块. 1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. 2. copy.deep ...
- poj 1704 Georgia and Bob(阶梯博弈)
Georgia and Bob Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 8656 Accepted: 2751 D ...
- OFFSET & FETCH
OFFSET & FECTH 关键字与ORDER BY结合使用,实现对查询结果的分页 一.单独使用OFFSET: 示例:查询所有职员的信息,按雇佣日期排序并跳过前285条记录(共290条) U ...