android TextureView 浅析

本文介绍了Android中的TextureView控件,它用于显示内容流,如视频或OpenGL场景,并强调其与SurfaceView的区别。TextureView允许进行视图变换,如动画效果。文章通过一个简单的例子展示了如何使用TextureView渲染相机预览。
部署运行你感兴趣的模型镜像

最近,在修改Android4.4的原生相机Camera2,很习惯的去寻找SurfaceView,结果任凭我使用grep还是ack,都无法搜索到SurfaceView,最后还是通过代码CameraActivity-->CameraModule-->PhotoUI-->R.layout.photo_module找到,原来是使用了TextureView。不是很了解此控件,百度之,在官方API文档中找到此控件:

 

官方文档大概的意思是:

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

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

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

使用TextureView很简单:你需要使用的就是SurfaceTexture,SurfaceTexture可以用于呈现内容。

 

下面是我写一个小例子来演示如何渲染相机预览到TextureView,在官方文档例子的基础上稍微改动了一下:

main.xml:

 

?
1
2
3
4
<!--?xml version= 1.0 encoding=utf- 8 ?-->
<linearlayout android:layout_height= "fill_parent" android:layout_width= "fill_parent" android:orientation= "horizontal" xmlns:android= "http://schemas.android.com/apk/res/android" >
 
     <framelayout android:id= "@+id/camera_preview" android:layout_height= "fill_parent" android:layout_weight= "1" android:layout_width= "fill_parent" ><button android:id= "@+id/button_capture" android:layout_gravity= "center" android:layout_height= "wrap_content" android:layout_width= "wrap_content" android:text= "Capture" ></button></framelayout></linearlayout>

 

CameraPreview.java:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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:

 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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:
  + 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:
  + 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 ;
         }
     }
 
}

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值