模拟微信短视频拍摄
来源:互联网 发布:交互设计类软件 编辑:程序博客网 时间:2024/04/28 20:03
本文主要讲述了在Android项目中模仿微信的拍摄和上传短视频功能,点击开始拍摄,设置最长拍摄时间,现在把实现思路和代码整理出来分享给Android程序员兄弟们,希望给他们的开发工作带来帮助。
1.视频录制自定义控件:
1
<span style=
"font-size: medium;"
>
/**
2
* 视频播放控件
3
*/
4
public
class
MovieRecorderView
extends
LinearLayout
implements
OnErrorListener {
5
6
private
SurfaceView mSurfaceView;
7
private
SurfaceHolder mSurfaceHolder;
8
private
ProgressBar mProgressBar;
9
10
private
MediaRecorder mMediaRecorder;
11
private
Camera mCamera;
12
private
Timer mTimer;
// 计时器
13
private
OnRecordFinishListener mOnRecordFinishListener;
// 录制完成回调接口
14
15
private
int
mWidth;
// 视频分辨率宽度
16
private
int
mHeight;
// 视频分辨率高度
17
private
boolean
isOpenCamera;
// 是否一开始就打开摄像头
18
private
int
mRecordMaxTime;
// 一次拍摄最长时间
19
private
int
mTimeCount;
// 时间计数
20
private
File mVecordFile =
null
;
// 文件
21
22
public
MovieRecorderView(Context context) {
23
this
(context,
null
);
24
}
25
26
public
MovieRecorderView(Context context, AttributeSet attrs) {
27
this
(context, attrs,
0
);
28
}
29
30
@SuppressLint
(
"NewApi"
)
31
public
MovieRecorderView(Context context, AttributeSet attrs,
int
defStyle) {
32
super
(context, attrs, defStyle);
33
34
TypedArray a = context.obtainStyledAttributes(attrs,
35
R.styleable.MovieRecorderView, defStyle,
0
);
36
mWidth = a.getInteger(R.styleable.MovieRecorderView_width,
320
);
// 默认320
37
mHeight = a.getInteger(R.styleable.MovieRecorderView_height,
240
);
// 默认240
38
39
isOpenCamera = a.getBoolean(
40
R.styleable.MovieRecorderView_is_open_camera,
true
);
// 默认打开
41
mRecordMaxTime = a.getInteger(
42
R.styleable.MovieRecorderView_record_max_time,
10
);
// 默认为10
43
44
LayoutInflater.from(context)
45
.inflate(R.layout.movie_recorder_view,
this
);
46
mSurfaceView = (SurfaceView) findViewById(R.id.surfaceview);
47
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
48
mProgressBar.setMax(mRecordMaxTime);
// 设置进度条最大量
49
50
mSurfaceHolder = mSurfaceView.getHolder();
51
mSurfaceHolder.addCallback(
new
CustomCallBack());
52
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
53
54
a.recycle();
55
}
56
57
/**
58
*
59
*/
60
private
class
CustomCallBack
implements
Callback {
61
62
@Override
63
public
void
surfaceCreated(SurfaceHolder holder) {
64
if
(!isOpenCamera)
65
return
;
66
try
{
67
initCamera();
68
}
catch
(IOException e) {
69
e.printStackTrace();
70
}
71
}
72
73
@Override
74
public
void
surfaceChanged(SurfaceHolder holder,
int
format,
int
width,
75
int
height) {
76
77
}
78
79
@Override
80
public
void
surfaceDestroyed(SurfaceHolder holder) {
81
if
(!isOpenCamera)
82
return
;
83
freeCameraResource();
84
}
85
86
}
87
88
/**
89
* 初始化摄像头
90
*/
91
private
void
initCamera()
throws
IOException {
92
if
(mCamera !=
null
) {
93
freeCameraResource();
94
}
95
try
{
96
mCamera = Camera.open();
97
}
catch
(Exception e) {
98
e.printStackTrace();
99
freeCameraResource();
100
}
101
if
(mCamera ==
null
)
102
return
;
103
104
setCameraParams();
105
mCamera.setDisplayOrientation(
90
);
106
mCamera.setPreviewDisplay(mSurfaceHolder);
107
mCamera.startPreview();
108
mCamera.unlock();
109
}
110
111
/**
112
* 设置摄像头为竖屏
113
*/
114
private
void
setCameraParams() {
115
if
(mCamera !=
null
) {
116
Parameters params = mCamera.getParameters();
117
params.set(
"orientation"
,
"portrait"
);
118
mCamera.setParameters(params);
119
}
120
}
121
122
/**
123
* 释放摄像头资源
124
*/
125
private
void
freeCameraResource() {
126
if
(mCamera !=
null
) {
127
mCamera.setPreviewCallback(
null
);
128
mCamera.stopPreview();
129
mCamera.lock();
130
mCamera.release();
131
mCamera =
null
;
132
}
133
}
134
135
private
void
createRecordDir() {
136
//录制的视频保存文件夹
137
File sampleDir =
new
File(Environment.getExternalStorageDirectory()
138
+ File.separator +
"ysb/video/"
);
//录制视频的保存地址
139
if
(!sampleDir.exists()) {
140
sampleDir.mkdirs();
141
}
142
File vecordDir = sampleDir;
143
// 创建文件
144
try
{
145
mVecordFile = File.createTempFile(
"recording"
,
".mp4"
, vecordDir);
// mp4格式的录制的视频文件
146
}
catch
(IOException e) {
147
e.printStackTrace();
148
}
149
}
150
151
/**
152
* 初始化
153
* @throws IOException
154
*/
155
@SuppressLint
(
"NewApi"
)
156
private
void
initRecord()
throws
IOException {
157
mMediaRecorder =
new
MediaRecorder();
158
mMediaRecorder.reset();
159
if
(mCamera !=
null
)
160
mMediaRecorder.setCamera(mCamera);
161
mMediaRecorder.setOnErrorListener(
this
);
162
mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
163
mMediaRecorder.setVideoSource(VideoSource.CAMERA);
// 视频源
164
mMediaRecorder.setAudioSource(AudioSource.MIC);
// 音频源
165
mMediaRecorder.setOutputFormat(OutputFormat.MPEG_4);
// 视频输出格式
166
mMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB);
// 音频格式
167
mMediaRecorder.setVideoSize(mWidth, mHeight);
// 设置分辨率:
168
// mMediaRecorder.setVideoFrameRate(16);// 这个我把它去掉了,感觉没什么用
169
mMediaRecorder.setVideoEncodingBitRate(
1
*
1024
*
1024
*
100
);
// 设置帧频率,然后就清晰了
170
mMediaRecorder.setOrientationHint(
90
);
// 输出旋转90度,保持竖屏录制
171
mMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);
// 视频录制格式
172
// mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000);
173
mMediaRecorder.setOutputFile(mVecordFile.getAbsolutePath());
174
mMediaRecorder.prepare();
175
try
{
176
mMediaRecorder.start();
177
}
catch
(IllegalStateException e) {
178
e.printStackTrace();
179
}
catch
(RuntimeException e) {
180
e.printStackTrace();
181
}
catch
(Exception e) {
182
e.printStackTrace();
183
}
184
}
185
186
/**
187
* 开始录制视频
188
* @param fileName
189
* 视频储存位置
190
* @param onRecordFinishListener
191
* 达到指定时间之后回调接口
192
*/
193
public
void
record(
final
OnRecordFinishListener onRecordFinishListener) {
194
this
.mOnRecordFinishListener = onRecordFinishListener;
195
createRecordDir();
196
try
{
197
if
(!isOpenCamera)
// 如果未打开摄像头,则打开
198
initCamera();
199
initRecord();
200
mTimeCount =
0
;
// 时间计数器重新赋值
201
mTimer =
new
Timer();
202
mTimer.schedule(
new
TimerTask() {
203
204
@Override
205
public
void
run() {
206
mTimeCount++;
207
mProgressBar.setProgress(mTimeCount);
// 设置进度条
208
if
(mTimeCount == mRecordMaxTime) {
// 达到指定时间,停止拍摄
209
stop();
210
if
(mOnRecordFinishListener !=
null
)
211
mOnRecordFinishListener.onRecordFinish();
212
}
213
}
214
},
0
,
1000
);
215
}
catch
(IOException e) {
216
e.printStackTrace();
217
}
218
}
219
220
/**
221
* 停止拍摄
222
*/
223
public
void
stop() {
224
stopRecord();
225
releaseRecord();
226
freeCameraResource();
227
}
228
229
/**
230
* 停止录制
231
*/
232
public
void
stopRecord() {
233
mProgressBar.setProgress(
0
);
234
if
(mTimer !=
null
)
235
mTimer.cancel();
236
if
(mMediaRecorder !=
null
) {
237
// 设置后不会崩
238
mMediaRecorder.setOnErrorListener(
null
);
239
mMediaRecorder.setPreviewDisplay(
null
);
240
try
{
241
mMediaRecorder.stop();
242
}
catch
(IllegalStateException e) {
243
e.printStackTrace();
244
}
catch
(RuntimeException e) {
245
e.printStackTrace();
246
}
catch
(Exception e) {
247
e.printStackTrace();
248
}
249
}
250
}
251
252
/**
253
* 释放资源
254
*/
255
private
void
releaseRecord() {
256
if
(mMediaRecorder !=
null
) {
257
mMediaRecorder.setOnErrorListener(
null
);
258
try
{
259
mMediaRecorder.release();
260
}
catch
(IllegalStateException e) {
261
e.printStackTrace();
262
}
catch
(Exception e) {
263
e.printStackTrace();
264
}
265
}
266
mMediaRecorder =
null
;
267
}
268
269
public
int
getTimeCount() {
270
return
mTimeCount;
271
}
272
273
//返回录制的视频文件
274
public
File getmVecordFile() {
275
return
mVecordFile;
276
}
277
278
/**
279
* 录制完成回调接口
280
*/
281
public
interface
OnRecordFinishListener {
282
public
void
onRecordFinish();
283
}
284
285
@Override
286
public
void
onError(MediaRecorder mr,
int
what,
int
extra) {
287
try
{
288
if
(mr !=
null
)
289
mr.reset();
290
}
catch
(IllegalStateException e) {
291
e.printStackTrace();
292
}
catch
(Exception e) {
293
e.printStackTrace();
294
}
295
}
296
}</span>
2.视频录制界面文件movie_recorder_view.xml:
1
<span style=
"font-size: medium;"
><?xml version=
"1.0"
encoding=
"utf-8"
?>
2
<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
3
xmlns:tools=
"http://schemas.android.com/tools"
4
android:layout_width=
"match_parent"
5
android:layout_height=
"match_parent"
6
android:background=
"@android:color/background_dark"
7
android:orientation=
"vertical"
>
8
9
<SurfaceView
10
android:id=
"@+id/surfaceview"
11
android:layout_width=
"fill_parent"
12
android:layout_height=
"0dp"
13
android:layout_weight=
"1"
14
/>
15
16
<ProgressBar
17
android:id=
"@+id/progressBar"
18
style=
"?android:attr/progressBarStyleHorizontal"
19
android:layout_width=
"match_parent"
20
android:layout_height=
"2dp"
21
/>
22
23
</LinearLayout></span>
做好这些准备工作,下面我们就可以开始设计我们的视频录制功能了。PS:以上代码取至网上,在此向大牛致敬。
3.拍摄主界面,拍摄界面有两部分组成,上面是视频拍摄控件显示,下面是用户点击拍摄按钮,配置文件:
1
<span style=
"font-size: medium;"
><?xml version=
"1.0"
encoding=
"utf-8"
?>
2
<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
3
xmlns:tools=
"http://schemas.android.com/tools"
4
android:layout_width=
"match_parent"
5
android:layout_height=
"match_parent"
6
android:background=
"@android:color/white"
7
android:orientation=
"vertical"
>
8
9
<com.example.wechatvideorecorddemo.MovieRecorderView
10
android:id=
"@+id/movieRecorderView"
11
android:layout_width=
"match_parent"
12
android:layout_height=
"0dp"
13
android:layout_weight=
"1"
14
android:layout_margin=
"3dp"
/>
15
16
<Button
17
android:id=
"@+id/shoot_button"
18
android:layout_width=
"wrap_content"
19
android:layout_height=
"wrap_content"
20
android:layout_gravity=
"center"
21
android:background=
"@drawable/bg_movie_add_shoot"
22
android:text=
"按住拍"
23
android:textColor=
"#20b6ff"
/>
24
25
</LinearLayout></span>
4.有了主界面的视图,下面我们就开始书写我们的Activity文件MainActivity.java:
1
<span style=
"font-size: medium;"
>
public
class
MainActivity
extends
Activity {
2
3
private
MovieRecorderView mRecorderView;
//视频录制控件
4
private
Button mShootBtn;
//视频开始录制按钮
5
private
boolean
isFinish =
true
;
6
private
boolean
success =
false
;
//防止录制完成后出现多次跳转事件
7
8
@Override
9
protected
void
onCreate(Bundle savedInstanceState) {
10
super
.onCreate(savedInstanceState);
11
setContentView(R.layout.activity_main);
12
mRecorderView = (MovieRecorderView) findViewById(R.id.movieRecorderView);
13
mShootBtn = (Button) findViewById(R.id.shoot_button);
14
15
//用户长按事件监听
16
mShootBtn.setOnTouchListener(
new
OnTouchListener() {
17
18
@Override
19
public
boolean
onTouch(View v, MotionEvent event) {
20
if
(event.getAction() == MotionEvent.ACTION_DOWN) {
//用户按下拍摄按钮
21
mShootBtn.setBackgroundResource(R.drawable.bg_movie_add_shoot_select);
22
mRecorderView.record(
new
OnRecordFinishListener() {
23
24
@Override
25
public
void
onRecordFinish() {
26
if
(!success&&mRecorderView.getTimeCount()<
10
){
//判断用户按下时间是否大于10秒
27
success =
true
;
28
handler.sendEmptyMessage(
1
);
29
}
30
}
31
});
32
}
else
if
(event.getAction() == MotionEvent.ACTION_UP) {
//用户抬起拍摄按钮
33
mShootBtn.setBackgroundResource(R.drawable.bg_movie_add_shoot);
34
if
(mRecorderView.getTimeCount() >
3
){
//判断用户按下时间是否大于3秒
35
if
(!success){
36
success =
true
;
37
handler.sendEmptyMessage(
1
);
38
}
39
}
else
{
40
success =
false
;
41
if
(mRecorderView.getmVecordFile() !=
null
)
42
mRecorderView.getmVecordFile().delete();
//删除录制的过短视频
43
mRecorderView.stop();
//停止录制
44
Toast.makeText(MainActivity.
this
,
"视频录制时间太短"
, Toast.LENGTH_SHORT).show();
45
}
46
}
47
return
true
;
48
}
49
});
50
}
51
52
@Override
53
public
void
onResume() {
54
super
.onResume();
55
isFinish =
true
;
56
if
(mRecorderView.getmVecordFile() !=
null
)
57
mRecorderView.getmVecordFile().delete();
//视频使用后删除
58
}
59
60
@Override
61
public
void
onSaveInstanceState(Bundle outState) {
62
super
.onSaveInstanceState(outState);
63
isFinish =
false
;
64
success =
false
;
65
mRecorderView.stop();
//停止录制
66
}
67
68
@Override
69
public
void
onPause() {
70
super
.onPause();
71
}
72
73
@Override
74
public
void
onDestroy() {
75
super
.onDestroy();
76
}
77
78
private
Handler handler =
new
Handler() {
79
@Override
80
public
void
handleMessage(Message msg) {
81
if
(success){
82
finishActivity();
83
}
84
}
85
};
86
87
//视频录制结束后,跳转的函数
88
private
void
finishActivity() {
89
if
(isFinish) {
90
mRecorderView.stop();
91
Intent intent =
new
Intent(
this
, SuccessActivity.
class
);
92
Bundle bundle =
new
Bundle();
93
bundle.putString(
"text"
, mRecorderView.getmVecordFile().toString());
94
intent.putExtras(bundle);
95
startActivity(intent);
96
}
97
success =
false
;
98
}
99
100
/**
101
* 录制完成回调
102
*/
103
public
interface
OnShootCompletionListener {
104
public
void
OnShootSuccess(String path,
int
second);
105
public
void
OnShootFailure();
106
}
107
}</span>
到这里我们仿微信的短视频拍摄就已经大功告成,那么下面我们检验一下,我们录制的效果如何,下面我以Android提供的视频播放控件(VideoView)为大家介绍一下如何播放录制的短视频。
5.播放视频的配置文件activity_success.xml:
1
<span style=
"font-size: medium;"
><?xml version=
"1.0"
encoding=
"utf-8"
?>
2
<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
3
xmlns:tools=
"http://schemas.android.com/tools"
4
android:layout_width=
"match_parent"
5
android:layout_height=
"match_parent"
6
android:background=
"@android:color/white"
7
android:orientation=
"vertical"
>
8
9
<TextView
10
android:id=
"@+id/text"
11
android:layout_width=
"wrap_content"
12
android:layout_height=
"wrap_content"
13
android:layout_gravity=
"center"
14
android:text=
"@string/app_name"
/>
15
<LinearLayout
16
android:layout_width=
"match_parent"
17
android:layout_height=
"wrap_content"
18
android:orientation=
"horizontal"
19
>
20
<Button
21
android:id=
"@+id/button1"
22
android:layout_width=
"match_parent"
23
android:layout_height=
"wrap_content"
24
android:layout_weight=
"1"
25
android:gravity=
"center"
26
android:padding=
"5dp"
27
android:text=
"播放"
28
/>
29
<Button
30
android:id=
"@+id/button2"
31
android:layout_width=
"match_parent"
32
android:layout_height=
"wrap_content"
33
android:layout_weight=
"1"
34
android:gravity=
"center"
35
android:padding=
"5dp"
36
android:text=
"暂停"
37
/>
38
<Button
39
android:id=
"@+id/button3"
40
android:layout_width=
"match_parent"
41
android:layout_height=
"wrap_content"
42
android:layout_weight=
"1"
43
android:gravity=
"center"
44
android:padding=
"5dp"
45
android:text=
"重播"
46
/>
47
<Button
48
android:id=
"@+id/button4"
49
android:layout_width=
"match_parent"
50
android:layout_height=
"wrap_content"
51
android:layout_weight=
"1"
52
android:gravity=
"center"
53
android:padding=
"5dp"
54
android:text=
"视频长度"
55
/>
56
</LinearLayout>
57
<VideoView
58
android:id=
"@+id/videoView1"
59
android:layout_width=
"wrap_content"
60
android:layout_height=
"500dp"
/>
61
62
</LinearLayout></span>
6.视频播放的控制代码SuccessActivity.java:
1
<span style=
"font-size: medium;"
>
public
class
SuccessActivity
extends
Activity
implements
OnClickListener{
2
3
private
TextView text;
//视频保存的路径
4
private
Button button1;
//播放开关
5
private
Button button2;
//暂停开关
6
private
Button button3;
//重新播放开关
7
private
Button button4;
//视频大小开关
8
private
VideoView videoView1;
//视频播放控件
9
private
String file;
//视频路径
10
11
@Override
12
protected
void
onCreate(Bundle savedInstanceState) {
13
super
.onCreate(savedInstanceState);
14
setContentView(R.layout.activity_success);
15
Bundle bundle = getIntent().getExtras();
16
file = bundle.getString(
"text"
);
//获得拍摄的短视频保存地址
17
init();
18
setValue();
19
}
20
21
//初始化
22
private
void
init() {
23
text = (TextView) findViewById(R.id.text);
24
button1 = (Button) findViewById(R.id.button1);
25
button2 = (Button) findViewById(R.id.button2);
26
button3 = (Button) findViewById(R.id.button3);
27
button4 = (Button) findViewById(R.id.button4);
28
videoView1 = (VideoView) findViewById(R.id.videoView1);
29
}
30
31
//设置
32
private
void
setValue() {
33
text.setText(file);
34
button1.setOnClickListener(
this
);
35
button2.setOnClickListener(
this
);
36
button3.setOnClickListener(
this
);
37
button4.setOnClickListener(
this
);
38
videoView1.setVideoPath(file);
39
}
40
41
@Override
42
public
void
onClick(View v) {
43
switch
(v.getId()) {
44
case
R.id.button1:
45
videoView1.start();
46
break
;
47
48
case
R.id.button2:
49
videoView1.pause();
50
break
;
51
52
case
R.id.button3:
53
videoView1.resume();
54
videoView1.start();
55
break
;
56
57
case
R.id.button4:
58
Toast.makeText(
this
,
"视频长度:"
+(videoView1.getDuration()/
1024
)+
"M"
, Toast.LENGTH_SHORT).show();
59
break
;
60
61
default
:
62
break
;
63
}
64
}
65
66
}</span>
功能界面截图:
好了,到这里关于拍摄短视频的知识就和大家分享完毕,具体的实现很简单,相信大家看到这里已经已经学会了。
本文到此结束,需要的朋友可以参考下。
0 0
- 模拟微信短视频拍摄
- 视频拍摄
- 视频拍摄类
- 拍摄照片和视频
- Android 拍摄视频
- android-视频拍摄
- AVFoundation拍摄视频
- android 拍摄视频
- 如何用摄像头拍摄视频
- iphone ios 视频拍摄旋转
- iOS视频拍摄与压缩
- iOS视频拍摄与压缩
- iOS视频拍摄与压缩
- iOS 视频拍摄与压缩
- iOS视频拍摄与压缩
- android拍摄视频的实现
- Swift教程-视频拍摄教程
- iOS视频拍摄与压缩
- Android Error: android.os.NetworkOnMainThreadException
- HBuilder Android平台离线打包支付插件配置
- 用qt编译Android应用(windows和Linux)
- Email 发邮件完整代码(Java实现)
- Linux源代码目录分析
- 模拟微信短视频拍摄
- Android签名简介
- Android BitmapShader 实战 实现圆形、圆角图片
- 黑马程序员---集合框架(二)
- 正则表达式
- bcb NumberUpDown 设置
- DB2_ 如何从系统编目中获得有用的信息
- github Object-C javascript 消息互通 WebViewJavascriptBridge
- 《iOS总结》 <Error>: CGContextSaveGState: invalid context 0x0.