Android之TextureView浅析

近期,在改动Android4.4的原生相机Camera2,非常习惯的去寻找SurfaceView,结果任凭我使用grep还是ack。都无法搜索到SurfaceView,最后还是通过代码CameraActivity-->CameraModule-->PhotoUI-->R.layout.photo_module找到,原来是使用了TextureView。

不是非常了解此控件。百度之。在官方API文档中找到此控件:

http://android.toolib.net/reference/android/view/TextureView.html

官方文档大概的意思是:

TextureView能够用来显示内容流。这样一个内容流比如能够视频或者OpenGL的场景。内容流能够来自本应用程序以及其它进程。

Textureview必须在硬件加速开启的窗体中。

与SurfaceView相比。TextureView不会创建一个单独的窗体,这使得它能够像一般的View一样运行一些变换操作,比方移动、动画等等,比如,你能够通过调用myView.setAlpha(0.5f)将TextureView设置成半透明。

使用TextureView非常easy:你须要使用的就是SurfaceTexture。SurfaceTexture能够用于呈现内容。

以下是我写一个小样例来演示怎样渲染相机预览到TextureView。在官方文档样例的基础上略微修改了一下:

main.xml:

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

    <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1" />

    <Button
        android:id="@+id/button_capture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Capture" />

</LinearLayout>

CameraPreview.java:

import java.io.IOException;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.view.TextureView;

@SuppressLint("NewApi")
public class CameraPreview extends TextureView implements
        TextureView.SurfaceTextureListener {
    private Camera mCamera;
    private TextureView mTextureView;
    public CameraPreview(Context context , Camera camera) {
        super(context);
        mCamera = camera;
        // TODO Auto-generated constructor stub
    }

    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
            int height) {
//        mCamera = Camera.open();
        try {
            mCamera.setPreviewTexture(surface);
            mCamera.startPreview();
        } catch (IOException ioe) {
            // Something bad happened
        }
    }

    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
            int height) {
        // Ignored, Camera does all the work for us
    }

    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        mCamera.stopPreview();
        mCamera.release();
        return true;
    }

    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        // Invoked every time there's a new Camera preview frame
    }

}

CameraTest.java:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Toast;

import com.example.mycamera.R.id;

@SuppressLint("NewApi")
public class CameraTest extends Activity {
    public static final int MEDIA_TYPE_IMAGE = 1;
    public static final int MEDIA_TYPE_VIDEO = 2;
    private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
    private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200;
    private Camera mCamera;
    private CameraPreview mPreview;
    private static final String TAG = "ERROR";
    private PictureCallback mPicture = new PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
            if (pictureFile == null) {
                Log.d(TAG,
                        "Error creating media file, check storage permissions: "
                                + "e.getMessage()");
                return;
            }
            try {
                FileOutputStream fos = new FileOutputStream(pictureFile);
                fos.write(data);
                fos.close();
            } catch (FileNotFoundException e) {
                Log.d(TAG, "File not found: " + e.getMessage());
            } catch (IOException e) {
                Log.d(TAG, "Error accessing file: " + e.getMessage());
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        // 创建Camera实例
        mCamera = getCameraInstance();
        // 创建Preview view并将其设为activity中的内容
        mPreview = new CameraPreview(this, mCamera);
        mPreview.setSurfaceTextureListener(mPreview);
        //设置浑浊
        mPreview.setAlpha(0.5f);
        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
        // preview.setAlpha(0.0f);
        preview.addView(mPreview);
        // 在Capture按钮中增加listener
        Button captureButton = (Button) findViewById(id.button_capture);
        captureButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 从摄像头获取图片
                mCamera.takePicture(null, null, mPicture);
            }
        });
    }

    /** 安全获取Camera对象实例的方法 */

    public static Camera getCameraInstance() {
        Camera c = null;
        try {
            c = Camera.open(); // 试图获取Camera实例
        }
        catch (Exception e) {
            // 摄像头不可用(正被占用或不存在)
        }
        return c; // 不可用则返回null
    }

    /** 为保存图片或视频创建File */
    private static File getOutputMediaFile(int type) {
        // 安全起见,在使用前应该
        // 用Environment.getExternalStorageState()检查SD卡是否已装入
        File mediaStorageDir = new File(
                Environment
                        .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
                "MyCameraApp");
        // 假设期望图片在应用程序卸载后还存在、且能被其他应用程序共享,
        // 则此保存位置最合适
        // 假设不存在的话,则创建存储文件夹
        if (!mediaStorageDir.exists()) {
            if (!mediaStorageDir.mkdirs()) {
                Log.d("MyCameraApp", "failed to create directory");
                return null;
            }
            Log.d("MyCameraApp", "failed to create directory");
        }
        // 创建媒体文件名称
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                .format(new Date());
        File mediaFile;
        if (type == MEDIA_TYPE_IMAGE) {
            mediaFile = new File(mediaStorageDir.getPath() + File.separator
                    + "IMG_" + timeStamp + ".jpg");
        } else if (type == MEDIA_TYPE_VIDEO) {
            mediaFile = new File(mediaStorageDir.getPath() + File.separator
                    + "VID_" + timeStamp + ".mp4");
        } else {
            return null;
        }
        return mediaFile;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                // 捕获的图像保存到Intent指定的fileUri
                Toast.makeText(this, "Image saved to:\n" + data.getData(),
                        Toast.LENGTH_LONG).show();
            } else if (resultCode == RESULT_CANCELED) {
                // 用户取消了图像捕获
            } else {
                // 图像捕获失败,提示用户
            }
        }

        if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                // 捕获的视频保存到Intent指定的fileUri
                Toast.makeText(this, "Video saved to:\n" + data.getData(),
                        Toast.LENGTH_LONG).show();
            } else if (resultCode == RESULT_CANCELED) {
                // 用户取消了视频捕获
            } else {
                // 视频捕获失败,提示用户
            }
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        releaseCamera(); // 在暂停事件中马上释放摄像头
    }

    private void releaseCamera() {
        if (mCamera != null) {
            mCamera.release(); // 为其他应用释放摄像头
            mCamera = null;
        }
    }

}
时间: 2024-08-03 17:04:10

Android之TextureView浅析的相关文章

Android源码浅析(一)——VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置

Android源码浅析(一)--VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置 最近地方工作,就是接触源码的东西了,所以好东西还是要分享,系列开了这么多,完结 的也没几个,主要还是自己覆盖的太广了,却又不精通,嘿嘿,工作需要,所以写下了本篇博客 一.VMware 12 我选择的虚拟机试VMware,挺好用的感觉,下载VMware就不说了,善用搜索键嘛,这里我提供一个我现在在用的 下载地址:链接:http://pan.baidu.com/s/1k

Android使用TextureView播放视频

1.引言 如果你想显示一段在线视频或者任意的数据流比如视频或者OpenGL 场景,你可以用android中的TextureView做到. 1).TextureView的兄弟SurfaceView 应用程序的视频或者opengl内容往往是显示在一个特别的UI控件中:SurfaceView.SurfaceView的工作方式是创建一个置于应用窗口之后的新窗口.这种 方式的效率非常高,因为SurfaceView窗口刷新的时候不需要重绘应用程序的窗口(android普通窗口的视图绘制机制是一层一层的,任何

(Android系统)android log机制浅析

在android下面debug,最主要的方式就是用logcat抓log了,我们可能有尝试过使用printf来打印,当然结果是不行的,这里有时间就看了一下android平台下log的flow,在此做个笔记以作记录 我们一般使用ALOGD来打印log,所以这里就跟一下ALOGD的flow system/core/include/log/log.h system/core/include/log/log.h #ifndef ALOGD #define ALOGD(...) ((void)ALOG(LO

Android源码浅析(三)——Android AOSP 5.1.1源码的同步sync和编译make,搭建Samba服务器进行更便捷的烧录刷机

Android源码浅析(三)--Android AOSP 5.1.1源码的同步sync和编译make,搭建Samba服务器进行更便捷的烧录刷机 最近比较忙,而且又要维护自己的博客,视频和公众号,也就没仔细的梳理源码的入门逻辑,今天也就来讲一个源码的玩法,各位看官,一起学习学习! 看本篇博客之前,先看下我的前面两篇 Android源码浅析(一)--VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置 Android源码浅析(二)--Ubuntu Roo

Android的线程浅析 补充

一.Looper的两点疑问 1) 问题一:Looper.loop()是处理消息,所有消息or部分消息? 2) 问题二:处理完消息后,结束or等待? Android官方示例文档代码:   class LooperThread extends Thread {       public Handler mHandler;       public void run() {           Looper.prepare();           mHandler = new Handler() {

Android线程机制浅析(ppt)

Android线程机制浅析(ppt)

Android源码浅析(二)——Ubuntu Root,Git,VMware Tools,安装输入法,主题美化,Dock,安装JDK和配置环境

Android源码浅析(二)--Ubuntu Root,Git,VMware Tools,安装输入法,主题美化,Dock,安装JDK和配置环境 接着上篇,上片主要是介绍了一些安装工具的小知识点Android源码浅析(一)--VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置,其实Ubuntu Kylin 16.04 LTS也只是为了体验,我们为了追求稳定,还是使用了Ubuntu14.04 这里提供一个国内镜像的下载链接,可以用迅雷,下载下来之后后缀

Android L 漫游浅析

这篇文章主要是分析在Android L 源代码中对手机漫游的处理.当然我这里所说的漫游指的是国际漫游.通常我们判断手机是否在国际漫游,第一个想法就是比较网络上获取的MCC+MNC是否与手机中的IMSI相同,如果不同就判断为漫游了.如果是漫游的话,手机上最直观的可以看到就是两个地方了: a . 手机的屏幕的状态拦上手机信号角标的左下方是否有"R"显示. b . Setting --->About phone --->Status --->Roming 当然这是最粗略的比

Android应用框架浅析

http://blog.csdn.net/yanbober/article/category/3206943 Android应用层View绘制流程与源码分析   http://blog.csdn.net/yanbober/article/details/46128379 Android应用进程间通信之Messenger信使使用及源码浅析  http://blog.csdn.net/yanbober/article/details/48373341 Android应用Context详解及源码解析