本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!
上次讲解了MediaPlayer播放网络音频,介绍了MediaPlayer关于网络音频的缓冲和进度条控制的方法,这次再讲解MediaPlayer播放网络视频。播放网络视频比播放网络音频多需要一个SurfaceView而已,已经熟悉MediaPlayer播放网络音频之后,相信大家对播放网络视频也能很快地掌握。先来看看本文程序运行截图:
本文程序的视频来自http://daily3gp.com,大家可以替换程序中的视频链接,试试其他影片。
main.xml的源码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="fill_parent" android:layout_width="fill_parent">
- <SurfaceView android:id="@+id/surfaceView1"
- android:layout_height="fill_parent" android:layout_width="fill_parent"></SurfaceView>
- <LinearLayout android:layout_height="wrap_content"
- android:layout_width="fill_parent" android:layout_gravity="bottom"
- android:orientation="vertical">
- <LinearLayout android:orientation="horizontal"
- android:layout_gravity="center_horizontal" android:layout_marginTop="4.0dip"
- android:layout_height="wrap_content" android:layout_width="wrap_content">
- <Button android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:id="@+id/btnPlayUrl"
- android:text="播放网络视频"></Button>
- <Button android:layout_height="wrap_content" android:id="@+id/btnPause"
- android:text="暂停" android:layout_width="80dip"></Button>
- <Button android:layout_height="wrap_content"
- android:layout_width="80dip" android:text="停止" android:id="@+id/btnStop"></Button>
- </LinearLayout>
- <LinearLayout android:orientation="horizontal"
- android:layout_width="fill_parent" android:layout_height="wrap_content"
- android:layout_marginBottom="20dip">
- <SeekBar android:paddingRight="10dip" android:layout_gravity="center_vertical"
- android:paddingLeft="10dip" android:layout_weight="1.0"
- android:layout_height="wrap_content" android:layout_width="wrap_content"
- android:id="@+id/skbProgress" android:max="100"></SeekBar>
- </LinearLayout>
- </LinearLayout>
- </FrameLayout>
Player.java是本文的核心,Player.java实现了“进度条更新”、“数据缓冲”、“SurfaceHolder生命周期”等功能,其中“SurfaceHolder生命周期”是视频与音频播放的最大区别,通过surfaceCreated()、surfaceDestroyed()、surfaceChanged()可以创建/释放某些资源。下面这个地方需要注意一下:
- videoWidth = mediaPlayer.getVideoWidth();
- videoHeight = mediaPlayer.getVideoHeight();
- if (videoHeight != 0 && videoWidth != 0) {
- arg0.start();
- }
有些视频是android播放器不能播放的,不能播放时videoHeight=0,videoWidth=0,以此来判断是否播放视频。
Player.java源码如下:
- package com.videoplayer;
- import java.io.IOException;
- import java.util.Timer;
- import java.util.TimerTask;
- import android.media.AudioManager;
- import android.media.MediaPlayer;
- import android.media.MediaPlayer.OnBufferingUpdateListener;
- import android.media.MediaPlayer.OnCompletionListener;
- import android.os.Handler;
- import android.os.Message;
- import android.util.Log;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- import android.widget.SeekBar;
- public class Player implements OnBufferingUpdateListener,
- OnCompletionListener, MediaPlayer.OnPreparedListener,
- SurfaceHolder.Callback {
- private int videoWidth;
- private int videoHeight;
- public MediaPlayer mediaPlayer;
- private SurfaceHolder surfaceHolder;
- private SeekBar skbProgress;
- private Timer mTimer=new Timer();
- public Player(SurfaceView surfaceView,SeekBar skbProgress)
- {
- this.skbProgress=skbProgress;
- surfaceHolder=surfaceView.getHolder();
- surfaceHolder.addCallback(this);
- surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
- mTimer.schedule(mTimerTask, 0, 1000);
- }
- /*******************************************************
- * 通过定时器和Handler来更新进度条
- ******************************************************/
- TimerTask mTimerTask = new TimerTask() {
- @Override
- public void run() {
- if(mediaPlayer==null)
- return;
- if (mediaPlayer.isPlaying() && skbProgress.isPressed() == false) {
- handleProgress.sendEmptyMessage(0);
- }
- }
- };
- Handler handleProgress = new Handler() {
- public void handleMessage(Message msg) {
- int position = mediaPlayer.getCurrentPosition();
- int duration = mediaPlayer.getDuration();
- if (duration > 0) {
- long pos = skbProgress.getMax() * position / duration;
- skbProgress.setProgress((int) pos);
- }
- };
- };
- //*****************************************************
- public void play()
- {
- mediaPlayer.start();
- }
- public void playUrl(String videoUrl)
- {
- try {
- mediaPlayer.reset();
- mediaPlayer.setDataSource(videoUrl);
- mediaPlayer.prepare();//prepare之后自动播放
- //mediaPlayer.start();
- } catch (IllegalArgumentException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalStateException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- public void pause()
- {
- mediaPlayer.pause();
- }
- public void stop()
- {
- if (mediaPlayer != null) {
- mediaPlayer.stop();
- mediaPlayer.release();
- mediaPlayer = null;
- }
- }
- @Override
- public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
- Log.e("mediaPlayer", "surface changed");
- }
- @Override
- public void surfaceCreated(SurfaceHolder arg0) {
- try {
- mediaPlayer = new MediaPlayer();
- mediaPlayer.setDisplay(surfaceHolder);
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- mediaPlayer.setOnBufferingUpdateListener(this);
- mediaPlayer.setOnPreparedListener(this);
- } catch (Exception e) {
- Log.e("mediaPlayer", "error", e);
- }
- Log.e("mediaPlayer", "surface created");
- }
- @Override
- public void surfaceDestroyed(SurfaceHolder arg0) {
- Log.e("mediaPlayer", "surface destroyed");
- }
- @Override
- /**
- * 通过onPrepared播放
- */
- public void onPrepared(MediaPlayer arg0) {
- videoWidth = mediaPlayer.getVideoWidth();
- videoHeight = mediaPlayer.getVideoHeight();
- if (videoHeight != 0 && videoWidth != 0) {
- arg0.start();
- }
- Log.e("mediaPlayer", "onPrepared");
- }
- @Override
- public void onCompletion(MediaPlayer arg0) {
- // TODO Auto-generated method stub
- }
- @Override
- public void onBufferingUpdate(MediaPlayer arg0, int bufferingProgress) {
- skbProgress.setSecondaryProgress(bufferingProgress);
- int currentProgress=skbProgress.getMax()*mediaPlayer.getCurrentPosition()/mediaPlayer.getDuration();
- Log.e(currentProgress+"% play", bufferingProgress + "% buffer");
- }
- }
test_videoplayer.java是主程序,负责调用Player类,其中关键部分是SeekBarChangeEvent这个SeekBar拖动的事件:SeekBar的Progress是0~SeekBar.getMax()之内的数,而MediaPlayer.seekTo()的参数是0~MediaPlayer.getDuration()之内数,所以MediaPlayer.seekTo()的参数是(progress/seekBar.getMax())*MediaPlayer.getDuration()。
test_videoplayer.java源码如下:
- package com.videoplayer;
- import android.app.Activity;
- import android.content.pm.ActivityInfo;
- import android.net.Uri;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.SurfaceView;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.SeekBar;
- public class test_videoplayer extends Activity {
- private SurfaceView surfaceView;
- private Button btnPause, btnPlayUrl, btnStop;
- private SeekBar skbProgress;
- private Player player;
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView1);
- btnPlayUrl = (Button) this.findViewById(R.id.btnPlayUrl);
- btnPlayUrl.setOnClickListener(new ClickEvent());
- btnPause = (Button) this.findViewById(R.id.btnPause);
- btnPause.setOnClickListener(new ClickEvent());
- btnStop = (Button) this.findViewById(R.id.btnStop);
- btnStop.setOnClickListener(new ClickEvent());
- skbProgress = (SeekBar) this.findViewById(R.id.skbProgress);
- skbProgress.setOnSeekBarChangeListener(new SeekBarChangeEvent());
- player = new Player(surfaceView, skbProgress);
- }
- class ClickEvent implements OnClickListener {
- @Override
- public void onClick(View arg0) {
- if (arg0 == btnPause) {
- player.pause();
- } else if (arg0 == btnPlayUrl) {
- String url="http://daily3gp.com/vids/family_guy_penis_car.3gp";
- player.playUrl(url);
- } else if (arg0 == btnStop) {
- player.stop();
- }
- }
- }
- class SeekBarChangeEvent implements SeekBar.OnSeekBarChangeListener {
- int progress;
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress,
- boolean fromUser) {
- // 原本是(progress/seekBar.getMax())*player.mediaPlayer.getDuration()
- this.progress = progress * player.mediaPlayer.getDuration()
- / seekBar.getMax();
- }
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- // seekTo()的参数是相对与影片时间的数字,而不是与seekBar.getMax()相对的数字
- player.mediaPlayer.seekTo(progress);
- }
- }
- }
-
54楼
Android_Robot 2012-02-10 10:24发表 [回复] [引用] [举报]
- 还有就是在Android设备浏览器上输入楼主的链接"http://daily3gp.com/vids/family_guy_penis_car.3gp",显示的是"该视频是无效的流媒体,无法分流到此设备"
-
53楼
Android_Robot 2012-02-10 10:00发表 [回复] [引用] [举报]
- 请教楼主,如何才能得到支持“progressive download”的视频播放格式的链接?我在优酷上找到视频链接(http://xxxx.xx.xxxx.html)是没有用的,可能是因为优酷上的视屏是通过flash播放的......
-
52楼
chillser 2012-02-09 16:22发表 [回复] [引用] [举报]
- 发生了这个异常java.io.IOException: Prepare failed.: status=0xC8
-
51楼
huanranbingshi1 2012-01-12 18:01发表 [回复] [引用] [举报]
- 为什么在模拟器上可以播放,反而在真机上播放不了呢?
-
49楼
ziyouzhifeng007 2011-10-19 09:24发表 [回复] [引用] [举报]
- 楼主什么也没播放,该怎么办呢?求助。
-
48楼
ziyouzhifeng007 2011-10-18 17:18发表 [回复] [引用] [举报]
- 楼主用你的demo啥也没播放啊,只是肿么回事儿,请楼主指教!
-
47楼
ziyouzhifeng007 2011-10-18 17:02发表 [回复] [引用] [举报]
- 楼主为什么照着这个例子自己弄了个demo,什么也不能播放呢???
-
46楼
monlikey 2011-10-17 18:02发表 [回复] [引用] [举报]
-
你好 楼主
我使用了你的Demo,但是有bug的,报:: java.io.IOException: Prepare failed.: status=0xC8
我只是改了一下界面而已,视频是在你上面说的那个网站找的,但是还是不能播放视频。
thanks
kakarote
-
45楼
z303729470 2011-09-16 17:29发表 [回复] [引用] [举报]
-
LZ啊,你这个只能播放小文件啊,播放稍微大点的(譬如上10M的视频文件)就没反应了啊。。。。。。求解,希望LZ帮帮忙啊
-
Re:
hellogv 2011-09-17 10:54发表 [回复] [引用] [举报]
- 回复z303729470:兄弟,这是在线播放。。。你不是把视频放在资源里面了吧。。。
-
44楼
wanjianqiao 2011-09-06 17:39发表 [回复] [引用] [举报]
-
LZ,可否发一份源码呢?谢谢
wanjianqiao@126.com
-
42楼
scswlike1 2011-08-25 16:24发表 [回复] [引用] [举报]
-
请问下前辈,这个要在真实手机上才能播放出视频吗?
我在模拟器运行的,用的本地网络,但是运行到prepare()就不动了
Log.e("mediaPlayer", "准备播放");
mediaPlayer.prepare();//prepare之后自动播放
Log.e("mediaPlayer", "开始播放");
日志有准备播放,没有开始播放
播放网络视频不需要mediaPlayer.start();这段吧?
-
41楼
gg465164252 2011-08-22 17:15发表 [回复] [引用] [举报]
- 请问下博主,在开发中,遇到了问题,并且不知道怎么解决,这时怎么去思路?
-
40楼
chaijinjian 2011-08-16 17:03发表 [回复] [引用] [举报]
- 您好,hellogv,麻烦问一下,用mediaplayer播放网络的实时视频流怎么才能降低延时呢?
-
39楼
ly_sr 2011-08-14 10:30发表 [回复] [引用] [举报]
- 你知道“快手视频”系列吗?能估计出来他那个大概是怎么实现的吗?是自己抓的地址做适配,还是可能人家直接和来源网站合作,网站直接供源?
-
38楼
ly_sr 2011-08-13 20:37发表 [回复] [引用] [举报]
- 能不能用来播放swf格式的视频呢?比如我想播放优酷等网站的视频,虽然可以用WebView实现,但感觉效果不好。是不是优酷这些网站,带.swf格式其实是已经套了一个flash播放器了?突然自己觉得好像不能了……
-
37楼
xinyetonghua 2011-08-12 17:26发表 [回复] [引用] [举报]
- 膜拜
-
36楼
xinyetonghua 2011-08-12 17:26发表 [回复] [引用] [举报]
- 很好,很强大!
-
35楼
mingxiuping1988 2011-07-22 16:49发表 [回复] [引用] [举报]
- 谢了,都是很好的文章。。。
-
33楼
a573742376a 2011-06-28 17:18发表 [回复] [引用] [举报]
-
32楼
zhangbin2757 2011-06-15 17:21发表 [回复] [引用] [举报]
-
博主,你这个代码可能存在潜在问题!
由于player是在surfaceCreated回调中new出来的,而在播放playUrl()方法调用时,player可能还没有new出来(如果点击播放按钮够快的话),这时候就会出现空指针异常,我已经试过了!呵呵
-
30楼
gundumw100 2011-06-09 17:43发表 [回复] [引用] [举报]
- 使用更方便的VideoView吧,虽然VideoView extends SurfaceView implements MediaController.MediaPlayerControl
-
29楼
wangqilin8888 2011-05-25 16:49发表 [回复] [引用] [举报]
-
26楼
nanmoenituofo 2011-05-23 23:30发表 [回复] [引用] [举报]
- 很好啊
-
25楼
yao2004jessica 2011-05-23 12:49发表 [回复] [引用] [举报]
- 哦,标记一下
-
24楼
c_zone 2011-05-23 09:44发表 [回复] [引用] [举报]
- 用Handler即可实现进度条的实时更新,为什么还加个定时器啊!用TimerTask不增加了程序负载,降低了效率不是?赐教
-
21楼
as375256234 2011-05-22 10:15发表 [回复] [引用] [举报]
-
18楼
laozicaonimamazaicao 2011-05-21 15:07发表 [回复] [引用] [举报]
- 还是多分析android应用程序构架!要不然写一大堆程序还是不知所以然!
-
17楼
laozicaonimamazaicao 2011-05-21 15:07发表 [回复] [引用] [举报]
- 还是多分析android应用程序构架!要不然写一大堆程序还是不知所以然!
-
16楼
a395733088 2011-05-21 14:26发表 [回复] [引用] [举报]
-
http://www.woir-cn.info
有电脑的同学可以去看看 赚点外快 很划算的
-
15楼
a595862188 2011-05-21 13:21发表 [回复] [引用] [举报]
-
14楼
xb545470163 2011-05-21 00:07发表 [回复] [引用] [举报]
- 看来好多人学
-
13楼
wangchengcai2010 2011-05-20 22:01发表 [回复] [引用] [举报]
-
还是多分析android应用程序构架!
要不然写一大堆程序还是不知所以然!-
Re:
Sencha_Android 2011-05-21 10:41发表 [回复] [引用] [举报]
- 回复 wangchengcai2010:未请教
-
12楼
liying0515 2011-05-20 13:32发表 [回复] [引用] [举报]
-
11楼
helloword1 2011-05-20 11:30发表 [回复] [引用] [举报]
- 学习ing 很炫
-
10楼
meng_qing_shan 2011-05-20 10:12发表 [回复] [引用] [举报]
- 学习中
-
9楼
zj_1395201 2011-05-20 09:50发表 [回复] [引用] [举报]
- 请问博主:rtsp格式流媒体文件可以播放吗?模拟器2.2的。opencore中貌似支持,2.2源码中的说明也是可以播放http/rtsp的,但是具体测试了下不可以
-
8楼
kay226 2011-05-19 22:52发表 [回复] [引用] [举报]
- 博主,你好,我想问下,像你的这些课程一课一课的,在哪看的啊?
-
7楼
turbosun 2011-05-19 21:03发表 [回复] [引用] [举报]
-
为什么我的程序在执行到 test_vedioplayer.java player.playUrl(url)会抛出一个IOException?sunhh@bupt.edu.cn
-
Re:
hellogv 2011-05-19 22:19发表 [回复] [引用] [举报]
-
回复 turbosun:
先确定一下你的模拟器是否可以上网-
Re:
ycdx2001 2011-06-24 09:18发表 [回复] [引用] [举报]
- 回复 hellogv:我在运行也会出一个IOException,msg:repare failed.: status=0xC8,请指教。