Android提高之MediaPlayer播放网络视频的实现方法
作者:shichen2014 发布时间:2021-07-03 06:25:29
前面讲解了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);
}
}
}
感兴趣的读者可以自己动手测试一下本文实例代码,相信对大家进行Android程序开发有一定的借鉴作用。


猜你喜欢
- 老大让我check out 一个分支,可我在idea 右下角找了半天也没找到最后才发现:因为是刚创建的分支,我得先更新一下项目,连这个都不懂
- 本文实例讲述了C#使用windows服务开启应用程序的方法。分享给大家供大家参考。具体如下:使用windows服务开启应用程序,会遇到如下问
- 本文实例为大家分享了Android实现透明动画的具体代码,供大家参考,具体内容如下首页是有一个 Activitypublic class A
- ionic App 解决android端在真机上 tab处于顶部的Bug在app.js 页面中添加以下代码.config(function(
- 本文实例为大家分享了Java文件操作的具体代码,供大家参考,具体内容如下简介本程序主要采用了FileInputStream和FileOutp
- C#支持的位逻辑运算符如表2.9所示。运算符号意义运算对象类型运算结果类型对象数实例~位逻辑非运算整型,字符型整型1~a&位逻辑与运
- VSCode配置C语言环境VSCode是一款强大编辑器,开源,免费,海量插件,支持很多编程语言。其中的很多功能可以大大地提高我们的学习与工作
- 本文实例讲述了简单记事本java实现代码。分享给大家供大家参考。具体如下:完整代码如下:import java.awt.*;import j
- 最近在修改Android7.0原生平台的一些bug,其中有关Android Beam传输文件的一些问题还是蛮多的。所以特地找时间总结下曾经踏
- 一、概念从本质上来说,它就是一个匿名函数,可以用来直接实现接口中的方法,从而简化代码。但是Lambda有一个限制,不能实现接口中的所有方法,
- 我们学习网络编程最熟悉的莫过于Http,好,我们就从Http入手,首先我们肯定要了解一下h
- sidebarDepth: 3条件构造器说明以下出现的第一个入参boolean condition表示该条件是否加入最后生成的SQL中,例如
- java接口返回参数按照请求参数进行排序在项目实际开发中可能遇到过这种问题,接口请求参数顺序是[a,b,c],结果返回的数据是[bObjec
- 实现效果:奔溃的线程侠:(单线程)主线程正在处理刷新图片的请求时,无法再接受其他请求,从而陷入阻塞的死循环状态。绘制图片import jav
- 1.介绍当系统准备为用户提供一系列相关对象,又不想让用户代码和这些对象形成耦合时,就可以使用抽象工厂模式。2.如何实现1)抽象产品--Car
- 前言本文简单介绍抽象类,接口以及它们的异同点,另附简单的代码举例。一、抽象类是什么?在 Java 语言中使用 abstract class
- 本文同时讨论了IComparable和IComparer接口,原因有两点。这两个接口经常一起使用。虽然接口类似且名称相似,但它们却有不同的用
- Android 原生的按钮点击状态是有变化的,但是如果是自己加了一个.png格式的图片为背景色,按钮点击就不会有任何效果,为了达到点击按钮有
- DBUtils工具包一.介绍DBUtils是Apache组织开源的数据库工具类。二.使用步骤①.创建QueryRunner对象②.调用upd
- 一、项目需求二、项目思路1、菜单制作2、中奖号码生成 getNumber (随机数 Math.random)3、购买号码和中奖号码比对 生成