最近,在修改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
;
}
}
}
|
本文介绍了Android中的TextureView控件,它用于显示内容流,如视频或OpenGL场景,并强调其与SurfaceView的区别。TextureView允许进行视图变换,如动画效果。文章通过一个简单的例子展示了如何使用TextureView渲染相机预览。
2286

被折叠的 条评论
为什么被折叠?



