Android三种播放视频的方式

在Android中,我们有三种方式来实现视频的播放:
1、使用其自带的播放器。指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型。
2、使用VideoView来播放。在布局文件中使用VideoView结合MediaController来实现对其控制。
3、使用MediaPlayer类和SurfaceView来实现,这种方式很灵活。

1、调用其自带的播放器:

Uri uri = Uri.parse(Environment.getExternalStorageDirectory().getPath()+"/Test_Movie.m4v");     
//调用系统自带的播放器    
    Intent intent = new Intent(Intent.ACTION_VIEW);    
    Log.v("URI:::::::::", uri.toString());    
    intent.setDataAndType(uri, "video/mp4");    
    startActivity(intent); ```

2、使用VideoView来实现:

Uri uri = Uri.parse(Environment.getExternalStorageDirectory().getPath()+"/Test_Movie.m4v");
VideoView videoView = (VideoView)this.findViewById(R.id.video_view);
videoView.setMediaController(new MediaController(this));
videoView.setVideoURI(uri);
videoView.start();
videoView.requestFocus(); ```

我们可以试想ImageView能显示图片,而VideoView就是用来显示视频的
使用VideoView播放视频的步骤如下

【1】在界面布局中定义VideoView

<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=".MainActivity">

   <VideoView
       android:id="@+id/videoview"
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1"/>
    <Button
        android:id="@+id/button"
        android:text="播放"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>```

【2】调用如下两个方法加载指定视频

setVideoPath(String Path);加载路径下的视频 
setVideoURL(URL url);加载url所对应的视频。

mVideoView.setVideoPath(Environment.getExternalStorageDirectory()+"/aa.mp4");```
【3】权限

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>```
【4】调用 
start()、stop()、pause()控制播放 

【5】实际中常常结合MediaController类,它提供一个友好的图像控制界面控制视频播放;

mVideoView.setMediaController(new MediaController(MainActivity.this));```

完整程序代码如下

public class MainActivity extends Activity {

    private VideoView mVideoView;
    private Button mButton;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mVideoView= (VideoView) findViewById(R.id.videoview);
        mButton= (Button) findViewById(R.id.button);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //得到sdcard下面aa.mp4的視頻文件
                //两种调用方式
//                File videofile =new File("/mut/extSdCard/DCIM/Camera/20150915_160202.mp4");
//                mVideoView.setVideoPath(videofile.getAbsolutePath());
                mVideoView.setVideoPath(Environment.getExternalStorageDirectory()+"/20150915_160202.mp4");
                mVideoView.setMediaController(new MediaController(MainActivity.this));
                mVideoView.start();
            }
        });
    }


}```
这里可以参考:[[Android基础] VideoView](http://www.jianshu.com/p/2d3b221a2ee7)

3、使用MediaPlayer:

package demo.camera;
import java.io.IOException;
import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnInfoListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnSeekCompleteListener;
import android.media.MediaPlayer.OnVideoSizeChangedListener;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.LinearLayout;
/**

  • 该实例中使用MediaPlayer完成播放,同时界面使用SurfaceView来实现
  • 这里我们实现MediaPlayer中很多状态变化时的监听器
  • 使用Mediaplayer时,也可以使用MediaController类,但是需要实现MediaController.mediaController接口
  • 实现一些控制方法。
  • 然后,设置controller.setMediaPlayer(),setAnchorView(),setEnabled(),show()就可以了,这里不再实现
  • @author Administrator

*/
public class VideoSurfaceDemo extends Activity implements OnCompletionListener,OnErrorListener,OnInfoListener,
OnPreparedListener, OnSeekCompleteListener,OnVideoSizeChangedListener,SurfaceHolder.Callback{
private Display currDisplay;
private SurfaceView surfaceView;
private SurfaceHolder holder;
private MediaPlayer player;
private int vWidth,vHeight;
//private boolean readyToPlay = false;

public void onCreate(Bundle savedInstanceState){    
    super.onCreate(savedInstanceState);    
    this.setContentView(R.layout.video_surface);    
                
    surfaceView = (SurfaceView)this.findViewById(R.id.video_surface);    
    //给SurfaceView添加CallBack监听    
    holder = surfaceView.getHolder();    
    holder.addCallback(this);    
    //为了可以播放视频或者使用Camera预览,我们需要指定其Buffer类型    
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);    
        
    //下面开始实例化MediaPlayer对象    
    player = new MediaPlayer();    
    player.setOnCompletionListener(this);    
    player.setOnErrorListener(this);    
    player.setOnInfoListener(this);    
    player.setOnPreparedListener(this);    
    player.setOnSeekCompleteListener(this);    
    player.setOnVideoSizeChangedListener(this);    
    Log.v("Begin:::", "surfaceDestroyed called");    
    //然后指定需要播放文件的路径,初始化MediaPlayer    
    String dataPath = Environment.getExternalStorageDirectory().getPath()+"/Test_Movie.m4v";    
    try {    
        player.setDataSource(dataPath);    
        Log.v("Next:::", "surfaceDestroyed called");    
    } catch (IllegalArgumentException e) {    
        e.printStackTrace();    
    } catch (IllegalStateException e) {    
        e.printStackTrace();    
    } catch (IOException e) {    
        e.printStackTrace();    
    }    
    //然后,我们取得当前Display对象    
    currDisplay = this.getWindowManager().getDefaultDisplay();    
}    
    
@Override    
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {    
    // 当Surface尺寸等参数改变时触发    
    Log.v("Surface Change:::", "surfaceChanged called");    
}    
@Override    
public void surfaceCreated(SurfaceHolder holder) {    
    // 当SurfaceView中的Surface被创建的时候被调用    
    //在这里我们指定MediaPlayer在当前的Surface中进行播放    
    player.setDisplay(holder);    
    //在指定了MediaPlayer播放的容器后,我们就可以使用prepare或者prepareAsync来准备播放了    
    player.prepareAsync();    
        
}    
@Override    
public void surfaceDestroyed(SurfaceHolder holder) {    
        
    Log.v("Surface Destory:::", "surfaceDestroyed called");    
}    
@Override    
public void onVideoSizeChanged(MediaPlayer arg0, int arg1, int arg2) {    
    // 当video大小改变时触发    
    //这个方法在设置player的source后至少触发一次    
    Log.v("Video Size Change", "onVideoSizeChanged called");    
        
}    
@Override    
public void onSeekComplete(MediaPlayer arg0) {    
    // seek操作完成时触发    
    Log.v("Seek Completion", "onSeekComplete called");    
        
}    
@Override    
public void onPrepared(MediaPlayer player) {    
    // 当prepare完成后,该方法触发,在这里我们播放视频    
        
    //首先取得video的宽和高    
    vWidth = player.getVideoWidth();    
    vHeight = player.getVideoHeight();    
        
    if(vWidth > currDisplay.getWidth() || vHeight > currDisplay.getHeight()){    
        //如果video的宽或者高超出了当前屏幕的大小,则要进行缩放    
        float wRatio = (float)vWidth/(float)currDisplay.getWidth();    
        float hRatio = (float)vHeight/(float)currDisplay.getHeight();    
            
        //选择大的一个进行缩放    
        float ratio = Math.max(wRatio, hRatio);    
            
        vWidth = (int)Math.ceil((float)vWidth/ratio);    
        vHeight = (int)Math.ceil((float)vHeight/ratio);    
            
        //设置surfaceView的布局参数    
        surfaceView.setLayoutParams(new LinearLayout.LayoutParams(vWidth, vHeight));    
            
        //然后开始播放视频    
            
        player.start();    
    }    
}    
@Override    
public boolean onInfo(MediaPlayer player, int whatInfo, int extra) {    
    // 当一些特定信息出现或者警告时触发    
    switch(whatInfo){    
    case MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING:    
        break;    
    case MediaPlayer.MEDIA_INFO_METADATA_UPDATE:      
        break;    
    case MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING:    
        break;    
    case MediaPlayer.MEDIA_INFO_NOT_SEEKABLE:     
        break;    
    }    
    return false;    
}    
@Override    
public boolean onError(MediaPlayer player, int whatError, int extra) {    
    Log.v("Play Error:::", "onError called");    
    switch (whatError) {    
    case MediaPlayer.MEDIA_ERROR_SERVER_DIED:    
        Log.v("Play Error:::", "MEDIA_ERROR_SERVER_DIED");    
        break;    
    case MediaPlayer.MEDIA_ERROR_UNKNOWN:    
        Log.v("Play Error:::", "MEDIA_ERROR_UNKNOWN");    
        break;    
    default:    
        break;    
    }    
    return false;    
}    
@Override    
public void onCompletion(MediaPlayer player) {    
    // 当MediaPlayer播放完成后触发    
    Log.v("Play Over:::", "onComletion called");    
    this.finish();    
}    

} ```
1)获得MediaPlayer实例:
可以使用直接new的方式:
MediaPlayer mp = new MediaPlayer();
也可以使用create的方式,如:
MediaPlayer mp = MediaPlayer.create(this, R.raw.test);//这时就不用调用setDataSource了

2) 设置要播放的文件:
MediaPlayer要播放的文件主要包括3个来源:
a. 用户在应用中事先自带的resource资源
例如:MediaPlayer.create(this, R.raw.test);
b. 存储在SD卡或其他文件路径下的媒体文件
例如:mp.setDataSource("/sdcard/test.mp3");
c. 网络上的媒体文件
例如:mp.setDataSource("http://www.citynorth.cn/music/confucius.mp3");

MediaPlayer的setDataSource一共四个方法:
setDataSource (String path)
setDataSource (FileDescriptor fd)
setDataSource (Context context, Uri uri)
setDataSource (FileDescriptor fd, long offset, long length)

其中使用FileDescriptor时,需要将文件放到与res文件夹平级的assets文件夹里,然后使用:
AssetFileDescriptor fileDescriptor = getAssets().openFd("rain.mp3");
m_mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(), fileDescriptor.getLength());
来设置datasource

3)对播放器的主要控制方法:
Android通过控制播放器的状态的方式来控制媒体文件的播放,其中:
prepare()和prepareAsync() 提供了同步和异步两种方式设置播放器进入prepare状态,需要注意的是,如果MediaPlayer实例是由create方法创建的,那么第一次启动播放前不需要再调用prepare()了,因为create方法里已经调用过了。
start()是真正启动文件播放的方法,
pause()和stop()比较简单,起到暂停和停止播放的作用,
seekTo()是定位方法,可以让播放器从指定的位置开始播放,需要注意的是该方法是个异步方法,也就是说该方法返回时并不意味着定位完成,尤其是播放的网络文件,真正定位完成时会触发OnSeekComplete.onSeekComplete(),如果需要是可以调用setOnSeekCompleteListener(OnSeekCompleteListener)设置监听器来处理的。
release()可以释放播放器占用的资源,一旦确定不再使用播放器时应当尽早调用它释放资源。
reset()可以使播放器从Error状态中恢复过来,重新会到Idle状态。

4)设置播放器的监听器:
MediaPlayer提供了一些设置不同监听器的方法来更好地对播放器的工作状态进行监听,以期及时处理各种情况,
如: setOnCompletionListener(MediaPlayer.OnCompletionListener listener)、
setOnErrorListener(MediaPlayer.OnErrorListener listener)等,设置播放器时需要考虑到播放器可能出现的情况设置好监听和处理逻辑,以保持播放器的健壮性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容