博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android视频播放-SurfaceView和Mediaplayer
阅读量:6627 次
发布时间:2019-06-25

本文共 7713 字,大约阅读时间需要 25 分钟。

好几天没写博客了,处理了一点个人私事加上平时加班,基本上时间不充裕,上篇文章讲了一下用Mediaplayer来播放音乐,这次就讲讲使用Mediaplayer来和SurfaceView配合播放一个视频流媒体。MediaPlayer不仅可以播放视频,还可以与SurfaceView的配合,SurfaceView主要用于显示MediaPlayer播放的视频流媒体的画面渲染,两者可以一起协同播放视频。

基础维护

先来看下要实现的界面:

 

如果你看过上篇文章,就发现其实很简单的就是多了一个进度条,还有一个就是SurfaceView,就是下面那块黑色区域;

布局文件代码:

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
<LinearLayout 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"
    
android:orientation=
"vertical"
    
tools:context=
"com.example.googlevideo.MainActivity" 
>
 
    
<EditText
        
android:id=
"@+id/edit_musicPath"
        
android:layout_width=
"match_parent"
        
android:layout_height=
"wrap_content"
        
android:hint=
"输入MV的路径" 
/>
 
    
<SeekBar
        
android:id=
"@+id/seekBar_video"
        
android:layout_width=
"match_parent"
        
android:layout_height=
"wrap_content" 
/>
 
    
<LinearLayout
        
android:layout_width=
"match_parent"
        
android:layout_height=
"wrap_content"
        
android:orientation=
"horizontal" 
>
 
        
<Button
            
android:id=
"@+id/btn_Play"
            
android:layout_width=
"wrap_content"
            
android:layout_height=
"wrap_content"
            
android:onClick=
"playEvent"
            
android:text=
"播放" 
/>
 
        
<Button
            
android:id=
"@+id/btn_Pause"
            
android:layout_width=
"wrap_content"
            
android:layout_height=
"wrap_content"
            
android:onClick=
"pauseEvent"
            
android:text=
"暂停" 
/>
 
        
<Button
            
android:id=
"@+id/btn_Stop"
            
android:layout_width=
"wrap_content"
            
android:layout_height=
"wrap_content"
            
android:onClick=
"stopEvent"
            
android:text=
"停止" 
/>
 
        
<Button
            
android:id=
"@+id/btn_Replay"
            
android:layout_width=
"wrap_content"
            
android:layout_height=
"wrap_content"
            
android:onClick=
"replayEvent"
            
android:text=
"重播" 
/>
    
</LinearLayout>
 
    
<SurfaceView
        
android:id=
"@+id/surface_video"
        
android:layout_width=
"match_parent"
        
android:layout_height=
"match_parent" 
/>
 
</LinearLayout>

 Demo实现

实现Demo之前应该讲讲视频播放的原理,先确定视频的格式,这个和解码相关,不同的格式视频编码不同,然后通过编码格式进行解码,最后得到一帧一帧的图像,并把这些图像快速的显示在界面上,即为播放一段视频。SurfaceView在Android中就是完成这个功能的。SurfaceView是配合MediaPlayer使用的,MediaPlayer也提供了相应的方法设置SurfaceView显示图片,只需要为MediaPlayer指定SurfaceView显示图像即可。它的完整签名:void setDisplay(SurfaceHolder sh)。它需要传递一个SurfaceHolder对象,SurfaceHolder可以理解为SurfaceView装载需要显示的一帧帧图像的容器,它可以通过SurfaceHolder.getHolder()方法获得。使用MediaPlayer配合SurfaceView播放视频的步骤与播放使用MediaPlayer播放MP3大体一致,只需要额外设置显示的SurfaceView即可。

先准备一段能播放的视频:

 

播放视频效果图:

代码如下:

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
editText = (EditText) findViewById(R.id.edit_musicPath);
     
pathString = editText.getText().toString().trim();
    
File file = 
new 
File(pathString);
    
if 
(file.exists()) {
        
try 
{
            
mediaPlayer = 
new 
MediaPlayer();
            
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            
mediaPlayer.setDataSource(pathString);
            
//通过SurfaceView获取的Holder
            
mediaPlayer.setDisplay(holder);
            
mediaPlayer.prepare();
            
mediaPlayer.start();
            
btn_PlayButton.setEnabled(
false
);
            
//设置Bar的最大值
            
int 
max=mediaPlayer.getDuration();
            
seekBarVideo.setMax(max);
            
//定时器更新进度条
            
timer=
new  
Timer();
            
timeTask=
new 
TimerTask() {
                 
                
@Override
                
public 
void 
run() {
                    
// TODO Auto-generated method stub
                    
seekBarVideo.setProgress(mediaPlayer.getCurrentPosition());
                
}
            
};     
            
timer.schedule(timeTask, 
0
500
);
            
//视频播放完之后重新设置显示
            
mediaPlayer.setOnCompletionListener(
new 
OnCompletionListener() {
                 
                
@Override
                
public 
void 
onCompletion(MediaPlayer mp) {
                    
// TODO Auto-generated method stub
                    
btn_PlayButton.setEnabled(
true
);
                
}
            
});
 
        
catch 
(IOException e) {
            
// TODO Auto-generated catch block
            
e.printStackTrace();
        
}
    
else 
{
        
Toast.makeText(
this
"Sorry,你输入的路径有问题,请仔细检查"
, Toast.LENGTH_SHORT)
                
.show();
    
}

   SeekBar的使用: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//设置Bar的最大值
            
int 
max=mediaPlayer.getDuration();
            
seekBarVideo.setMax(max);
            
//定时器更新进度条
            
timer=
new  
Timer();
            
timeTask=
new 
TimerTask() {
                 
                
@Override
                
public 
void 
run() {
                    
// TODO Auto-generated method stub
                    
seekBarVideo.setProgress(mediaPlayer.getCurrentPosition());
                
}
            
};     
            
timer.schedule(timeTask, 
0
500
);

 其中holder是SurfaceHolder,在onCreate中获取:

1
2
3
4
surfaceView = (SurfaceView) findViewById(R.id.surface_video);
    
holder = surfaceView.getHolder();
    
//兼容4.0以后的手机版本,本身是不维护的
    
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

 如果正在播放视频,最小化的时候是会有声音的,需要在回调函数中处理一下:

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
holder.addCallback(
new 
Callback() {
     
 
    
@Override
    
public 
void 
surfaceDestroyed(SurfaceHolder holder) {
        
// TODO Auto-generated method stub
        
Log.i(tag, 
"销毁了Holder"
);
        
if 
(mediaPlayer!=
null
&&mediaPlayer.isPlaying()) {
            
currentPosition=mediaPlayer.getCurrentPosition();
            
mediaPlayer.stop();
            
mediaPlayer.release();
            
mediaPlayer=
null
;
            
timer.cancel();
            
timeTask.cancel();
            
timer=
null
;
            
timeTask=
null
;
        
}
    
}
     
    
@Override
    
public 
void 
surfaceCreated(SurfaceHolder holder) {
        
// TODO Auto-generated method stub
        
Log.i(tag,
"创建了Holder"
);
        
if 
(currentPosition>
0
) {
            
try 
{
                
mediaPlayer = 
new 
MediaPlayer();
                
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                
mediaPlayer.setDataSource(pathString);
                
//通过SurfaceView获取的Holder
                
mediaPlayer.setDisplay(holder);
                
mediaPlayer.prepare();
                
mediaPlayer.start();
                
mediaPlayer.seekTo(currentPosition);
                
btn_PlayButton.setEnabled(
false
);
                
//视频播放完之后重新设置显示
                
mediaPlayer.setOnCompletionListener(
new 
OnCompletionListener() {
 
                            
@Override
                            
public 
void 
onCompletion(MediaPlayer mp) {
                                
// TODO Auto-generated method stub
                                
btn_PlayButton.setEnabled(
true
);
                            
}
                        
});
                 
                
int 
max=mediaPlayer.getDuration();
                
seekBarVideo.setMax(max);
                
//定时器更新进度条
                
timer=
new  
Timer();
                
timeTask=
new 
TimerTask() {
                     
                    
@Override
                    
public 
void 
run() {
                        
// TODO Auto-generated method stub
                        
seekBarVideo.setProgress(mediaPlayer.getCurrentPosition());
                    
}
                
};     
                
timer.schedule(timeTask, 
0
500
);
            
catch 
(Exception e) {
                
// TODO: handle exception
            
}
        
}
    
}
     
    
@Override
    
public 
void 
surfaceChanged(SurfaceHolder holder, 
int 
format, 
int 
width,
            
int 
height) {
        
// TODO Auto-generated method stub
        
Log.i(tag,
"改变了Holder"
);
    
}
});

  进度条是SeekBar,如果需要快进或者后退的时候是需要将焦点赋值给mediaPlayer的:

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
seekBarVideo=(SeekBar) findViewById(R.id.seekBar_video);
    
seekBarVideo.setOnSeekBarChangeListener(
new 
OnSeekBarChangeListener() {
         
        
@Override
        
public 
void 
onStopTrackingTouch(SeekBar seekBar) {
            
// TODO Auto-generated method stub
            
int 
position=seekBar.getProgress();
            
if 
(mediaPlayer!=
null
&&mediaPlayer.isPlaying()) {
                
mediaPlayer.seekTo(position);
            
}
        
}
         
        
@Override
        
public 
void 
onStartTrackingTouch(SeekBar seekBar) {
            
// TODO Auto-generated method stub
             
        
}
         
        
@Override
        
public 
void 
onProgressChanged(SeekBar seekBar, 
int 
progress,
                
boolean 
fromUser) {
            
// TODO Auto-generated method stub
             
        
}
    
});

  暂停事件:

1
2
3
4
5
6
7
8
9
10
11
public 
void 
pauseEvent(View view) {
    
if 
(btn_PauseButton.getText().equals(
"继续"
)) {
        
mediaPlayer.start();
        
btn_PauseButton.setText(
"暂停"
);
        
return
;
    
}
    
if 
(mediaPlayer != 
null 
&& mediaPlayer.isPlaying()) {
        
mediaPlayer.pause();
        
btn_PauseButton.setText(
"继续"
);
    
}
}

 停止事件:

1
2
3
4
5
6
7
8
9
10
11
public 
void 
stopEvent(View view) {
    
if 
(mediaPlayer != 
null 
&& mediaPlayer.isPlaying()) {
        
btn_PlayButton.setEnabled(
true
);
        
mediaPlayer.stop();
        
// 释放mediaplayer否则的话会占用内存
        
mediaPlayer.release();
        
mediaPlayer = 
null
;
    
}
    
btn_PauseButton.setText(
"暂停"
);
    
btn_PlayButton.setEnabled(
true
);
}

  重播事件:

1
2
3
4
5
6
7
8
9
10
public 
void 
replayEvent(View view) {
    
surfaceView.setVisibility(View.VISIBLE);
    
if 
(mediaPlayer != 
null 
&& mediaPlayer.isPlaying()) {
        
mediaPlayer.seekTo(
0
);
    
else 
{
        
playEvent(view);
    
}
    
// 重播的时候应该设置播放的状态
    
btn_PlayButton.setEnabled(
true
);
}
本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4099433.html,如需转载请自行联系原作者
你可能感兴趣的文章
课后作业—阅读笔记
查看>>
linux popen获取ip地址,使用popen函数读取命令输出失败
查看>>
python 编辑html文件内容,使用Python解析和编辑HTML文件
查看>>
切换 ip 批处理
查看>>
CommandArgument 绑定多个参数
查看>>
dropdownlist可以多选。类似的例子。。。
查看>>
Objective-C 内存管理
查看>>
Linux下rz,sz与ssh的配合使用
查看>>
pku 1054 The Troublesome Frog 暴力+剪枝
查看>>
串行,并行,并发
查看>>
Porting .Net RSA xml keys to Java
查看>>
检测 nginx.conf 是否配置正确
查看>>
最长公共子序列|最长公共子串|最长重复子串|最长不重复子串|最长回文子串|最长递增子序列|最大子数组和...
查看>>
linux NFS
查看>>
Jquery DataTable基本使用
查看>>
leetcode 674. Longest Continuous Increasing Subsequence
查看>>
Extensions in UWP Community Toolkit - SurfaceDialTextbox
查看>>
Java中CAS详解
查看>>
Linux系统实战项目——sudo日志审计
查看>>
Android Application Task Activities的关系
查看>>