Android三種播放視頻的方式

在Android中堤如,我們有三種方式來實(shí)現(xiàn)視頻的播放:
1、使用其自帶的播放器窒朋。指定Action為ACTION_VIEW,Data為Uri搀罢,Type為其MIME類型。
2侥猩、使用VideoView來播放榔至。在布局文件中使用VideoView結(jié)合MediaController來實(shí)現(xiàn)對(duì)其控制。
3欺劳、使用MediaPlayer類和SurfaceView來實(shí)現(xiàn)唧取,這種方式很靈活。

1划提、調(diào)用其自帶的播放器:

Uri uri = Uri.parse(Environment.getExternalStorageDirectory().getPath()+"/Test_Movie.m4v");     
//調(diào)用系統(tǒng)自帶的播放器    
    Intent intent = new Intent(Intent.ACTION_VIEW);    
    Log.v("URI:::::::::", uri.toString());    
    intent.setDataAndType(uri, "video/mp4");    
    startActivity(intent); ```

2枫弟、使用VideoView來實(shí)現(xiàn):

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】調(diào)用如下兩個(gè)方法加載指定視頻

setVideoPath(String Path)鹏往;加載路徑下的視頻 
setVideoURL(URL url);加載url所對(duì)應(yīng)的視頻淡诗。

mVideoView.setVideoPath(Environment.getExternalStorageDirectory()+"/aa.mp4");```
【3】權(quán)限

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

【5】實(shí)際中常常結(jié)合MediaController類韩容,它提供一個(gè)友好的圖像控制界面控制視頻播放;

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的視頻文件
                //兩種調(diào)用方式
//                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基礎(chǔ)] VideoView](http://www.reibang.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;
/**

  • 該實(shí)例中使用MediaPlayer完成播放群凶,同時(shí)界面使用SurfaceView來實(shí)現(xiàn)
  • 這里我們實(shí)現(xiàn)MediaPlayer中很多狀態(tài)變化時(shí)的監(jiān)聽器
  • 使用Mediaplayer時(shí),也可以使用MediaController類哄辣,但是需要實(shí)現(xiàn)MediaController.mediaController接口
  • 實(shí)現(xiàn)一些控制方法座掘。
  • 然后递惋,設(shè)置controller.setMediaPlayer(),setAnchorView(),setEnabled(),show()就可以了,這里不再實(shí)現(xiàn)
  • @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監(jiān)聽    
    holder = surfaceView.getHolder();    
    holder.addCallback(this);    
    //為了可以播放視頻或者使用Camera預(yù)覽溢陪,我們需要指定其Buffer類型    
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);    
        
    //下面開始實(shí)例化MediaPlayer對(duì)象    
    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();    
    }    
    //然后,我們?nèi)〉卯?dāng)前Display對(duì)象    
    currDisplay = this.getWindowManager().getDefaultDisplay();    
}    
    
@Override    
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {    
    // 當(dāng)Surface尺寸等參數(shù)改變時(shí)觸發(fā)    
    Log.v("Surface Change:::", "surfaceChanged called");    
}    
@Override    
public void surfaceCreated(SurfaceHolder holder) {    
    // 當(dāng)SurfaceView中的Surface被創(chuàng)建的時(shí)候被調(diào)用    
    //在這里我們指定MediaPlayer在當(dāng)前的Surface中進(jìn)行播放    
    player.setDisplay(holder);    
    //在指定了MediaPlayer播放的容器后形真,我們就可以使用prepare或者prepareAsync來準(zhǔn)備播放了    
    player.prepareAsync();    
        
}    
@Override    
public void surfaceDestroyed(SurfaceHolder holder) {    
        
    Log.v("Surface Destory:::", "surfaceDestroyed called");    
}    
@Override    
public void onVideoSizeChanged(MediaPlayer arg0, int arg1, int arg2) {    
    // 當(dāng)video大小改變時(shí)觸發(fā)    
    //這個(gè)方法在設(shè)置player的source后至少觸發(fā)一次    
    Log.v("Video Size Change", "onVideoSizeChanged called");    
        
}    
@Override    
public void onSeekComplete(MediaPlayer arg0) {    
    // seek操作完成時(shí)觸發(fā)    
    Log.v("Seek Completion", "onSeekComplete called");    
        
}    
@Override    
public void onPrepared(MediaPlayer player) {    
    // 當(dāng)prepare完成后杉编,該方法觸發(fā),在這里我們播放視頻    
        
    //首先取得video的寬和高    
    vWidth = player.getVideoWidth();    
    vHeight = player.getVideoHeight();    
        
    if(vWidth > currDisplay.getWidth() || vHeight > currDisplay.getHeight()){    
        //如果video的寬或者高超出了當(dāng)前屏幕的大小咆霜,則要進(jìn)行縮放    
        float wRatio = (float)vWidth/(float)currDisplay.getWidth();    
        float hRatio = (float)vHeight/(float)currDisplay.getHeight();    
            
        //選擇大的一個(gè)進(jìn)行縮放    
        float ratio = Math.max(wRatio, hRatio);    
            
        vWidth = (int)Math.ceil((float)vWidth/ratio);    
        vHeight = (int)Math.ceil((float)vHeight/ratio);    
            
        //設(shè)置surfaceView的布局參數(shù)    
        surfaceView.setLayoutParams(new LinearLayout.LayoutParams(vWidth, vHeight));    
            
        //然后開始播放視頻    
            
        player.start();    
    }    
}    
@Override    
public boolean onInfo(MediaPlayer player, int whatInfo, int extra) {    
    // 當(dāng)一些特定信息出現(xiàn)或者警告時(shí)觸發(fā)    
    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) {    
    // 當(dāng)MediaPlayer播放完成后觸發(fā)    
    Log.v("Play Over:::", "onComletion called");    
    this.finish();    
}    

} ```
1)獲得MediaPlayer實(shí)例:
可以使用直接new的方式:
MediaPlayer mp = new MediaPlayer();
也可以使用create的方式邓馒,如:
MediaPlayer mp = MediaPlayer.create(this, R.raw.test);//這時(shí)就不用調(diào)用setDataSource了

2) 設(shè)置要播放的文件:
MediaPlayer要播放的文件主要包括3個(gè)來源:
a. 用戶在應(yīng)用中事先自帶的resource資源
例如:MediaPlayer.create(this, R.raw.test);
b. 存儲(chǔ)在SD卡或其他文件路徑下的媒體文件
例如:mp.setDataSource("/sdcard/test.mp3");
c. 網(wǎng)絡(luò)上的媒體文件
例如:mp.setDataSource("http://www.citynorth.cn/music/confucius.mp3");

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

其中使用FileDescriptor時(shí),需要將文件放到與res文件夾平級(jí)的assets文件夾里蛾坯,然后使用:
AssetFileDescriptor fileDescriptor = getAssets().openFd("rain.mp3");
m_mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(), fileDescriptor.getLength());
來設(shè)置datasource

3)對(duì)播放器的主要控制方法:
Android通過控制播放器的狀態(tài)的方式來控制媒體文件的播放光酣,其中:
prepare()和prepareAsync() 提供了同步和異步兩種方式設(shè)置播放器進(jìn)入prepare狀態(tài),需要注意的是脉课,如果MediaPlayer實(shí)例是由create方法創(chuàng)建的救军,那么第一次啟動(dòng)播放前不需要再調(diào)用prepare()了,因?yàn)閏reate方法里已經(jīng)調(diào)用過了倘零。
start()是真正啟動(dòng)文件播放的方法唱遭,
pause()和stop()比較簡(jiǎn)單,起到暫停和停止播放的作用呈驶,
seekTo()是定位方法拷泽,可以讓播放器從指定的位置開始播放,需要注意的是該方法是個(gè)異步方法袖瞻,也就是說該方法返回時(shí)并不意味著定位完成司致,尤其是播放的網(wǎng)絡(luò)文件,真正定位完成時(shí)會(huì)觸發(fā)OnSeekComplete.onSeekComplete()聋迎,如果需要是可以調(diào)用setOnSeekCompleteListener(OnSeekCompleteListener)設(shè)置監(jiān)聽器來處理的蚌吸。
release()可以釋放播放器占用的資源,一旦確定不再使用播放器時(shí)應(yīng)當(dāng)盡早調(diào)用它釋放資源砌庄。
reset()可以使播放器從Error狀態(tài)中恢復(fù)過來羹唠,重新會(huì)到Idle狀態(tài)。

4)設(shè)置播放器的監(jiān)聽器:
MediaPlayer提供了一些設(shè)置不同監(jiān)聽器的方法來更好地對(duì)播放器的工作狀態(tài)進(jìn)行監(jiān)聽娄昆,以期及時(shí)處理各種情況佩微,
如: setOnCompletionListener(MediaPlayer.OnCompletionListener listener)、
setOnErrorListener(MediaPlayer.OnErrorListener listener)等,設(shè)置播放器時(shí)需要考慮到播放器可能出現(xiàn)的情況設(shè)置好監(jiān)聽和處理邏輯萌焰,以保持播放器的健壯性哺眯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市扒俯,隨后出現(xiàn)的幾起案子奶卓,更是在濱河造成了極大的恐慌一疯,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夺姑,死亡現(xiàn)場(chǎng)離奇詭異墩邀,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)盏浙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門眉睹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人废膘,你說我怎么就攤上這事竹海。” “怎么了丐黄?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵斋配,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我灌闺,道長(zhǎng)艰争,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任菩鲜,我火速辦了婚禮,結(jié)果婚禮上惦积,老公的妹妹穿的比我還像新娘接校。我一直安慰自己,他們只是感情好狮崩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布蛛勉。 她就那樣靜靜地躺著,像睡著了一般睦柴。 火紅的嫁衣襯著肌膚如雪诽凌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天坦敌,我揣著相機(jī)與錄音侣诵,去河邊找鬼。 笑死狱窘,一個(gè)胖子當(dāng)著我的面吹牛杜顺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蘸炸,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼躬络,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了搭儒?” 一聲冷哼從身側(cè)響起穷当,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤提茁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后馁菜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體茴扁,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡火邓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纤勒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡粹湃,死狀恐怖为鳄,靈堂內(nèi)的尸體忽然破棺而出腕让,到底是詐尸還是另有隱情纯丸,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布俊扭,位于F島的核電站萨惑,受9級(jí)特大地震影響仇矾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜若未,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望萍嬉。 院中可真熱鬧,春花似錦磕道、人聲如沸行冰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)漓雅。三九已至朽色,卻和暖如春葫男,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背旺遮。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工趣效, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人讯私。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓斤寇,卻偏偏與公主長(zhǎng)得像桶癣,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子娘锁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容