視頻播放

一.在Android中,我們有三種方式來實現(xiàn)視頻的播放:
1丙曙、使用其自帶的播放器爸业。指定Action為ACTION_VIEW,Data為Uri,Type為其MIME類型亏镰。
2沃呢、使用VideoView來播放。在布局文件中使用VideoView結(jié)合MediaController來實現(xiàn)對其控制拆挥。
3薄霜、使用MediaPlayer類和SurfaceView來實現(xiàn),這種方式很靈活纸兔。
本地資源
內(nèi)部URI惰瓜,比如你可以通過ContentResolver來獲取
外部URL(流)

二.第一種方式--使用系統(tǒng)自帶的播放器
private String videoPath1 = "/storage/emulated/0/v1.mp4";

Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse(videoPath1);
intent.setDataAndType(uri, "video/mp4");
startActivity(intent);
三.第二種方式--使用VideoView結(jié)合MediaController來播放視頻

1.布局中添加VideoView

<VideoView
        android:id="@+id/video"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

2.具體代碼

private String[] videos = {"ace.mp4","v1.mp4","v2.mp4"};
private int mPosition = 0;
private void play2() {
     MediaController mediaController = new MediaController(this);
     mVideo.setMediaController(mediaController);
     mVideo.setVideoURI(Uri.parse("/storage/emulated/0/"+videos[mPosition]));
     mVideo.start();
     mediaController.setPrevNextListeners(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
            //下一首
           mPosition++;
           mPosition = mPosition%videos.length;//對視頻數(shù)量去余數(shù),以免越界汉矿,同時到達最后一首從第一首開始播
           mVideo.setVideoURI(Uri.parse("/storage/emulated/0/"+videos[mPosition]));
           mVideo.start();
       }
  }, new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              //上一首
                mPosition--;
                mPosition = mPosition<0?videos.length-1:mPosition;  //如果index小于0崎坊,設(shè)置為最后一首,不然就還是自己洲拇,沒有越界
                mVideo.setVideoURI(Uri.parse("/storage/emulated/0/"+videos[mPosition]));
                mVideo.start();
          }
     });
     //設(shè)置獲取焦點
    mVideo.requestFocus();
}

四.第三種方式--使用MediaPlayer類和SurfaceView來實現(xiàn)
MediaPlayer主要用于播放音頻奈揍,沒有提供圖像輸出界面,所以我們需要借助其他的組件來顯示MediaPlayer播放的圖像輸出赋续,我們可以使用SurfaceView來顯示
a.調(diào)用player.setDataSource()方法設(shè)置要播放的資源男翰,可以是文件、文件路徑纽乱、或者URL蛾绎。
b.調(diào)用MediaPlayer.setDisplay(holder)設(shè)置surfaceHolder,surfaceHolder可以通過surfaceview的getHolder()方法獲得鸦列。
c.調(diào)用MediaPlayer.prepare()來準備租冠。
d.調(diào)用MediaPlayer.start()來播放視頻。

1.布局中添加SurfaceView

<SurfaceView
        android:layout_gravity="center_vertical"
        android:id="@+id/surface"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

2.具體代碼

public class SurfaceActivity extends AppCompatActivity {
    private SurfaceView mSurface;
    private ArrayList<VideoBean> mData;
    private int mPosition;
    private int mWidth;
    private int mHeight;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_surface);
        getScreen();
        //獲取傳遞過來的數(shù)據(jù)
        Intent intent = getIntent();
        Bundle extras = intent.getExtras();
        mData = (ArrayList<VideoBean>) extras.getSerializable("data");
        mPosition = extras.getInt("position");
        initView();
    }
    //獲取屏幕寬高
    private void getScreen() {
        WindowManager systemService = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        Display defaultDisplay = systemService.getDefaultDisplay();
        DisplayMetrics metrics = new DisplayMetrics();
        defaultDisplay.getMetrics(metrics);
        mWidth = metrics.widthPixels;
        mHeight = metrics.heightPixels;
    }
    private void initView() {
        mSurface = (SurfaceView) findViewById(R.id.surface);
        final MediaPlayer mediaPlayer = new MediaPlayer();
        try {
            //設(shè)置播放的視頻路徑
            mediaPlayer.setDataSource(mData.get(mPosition).getData());
            //異步加載流媒體
            mediaPlayer.prepareAsync();
            //獲取SurfaceHolder
            SurfaceHolder holder = mSurface.getHolder();
            //確保surfaceHolder已經(jīng)準備好了薯嗤。因此需要給surfaceHolder設(shè)置一個callback顽爹,
            //調(diào)用addCallback()方法。Callback 有三個回調(diào)函數(shù)
            holder.addCallback(new SurfaceHolder.Callback() {
                @Override
                public void surfaceCreated(SurfaceHolder holder) {
                    //SurfaceHolder被創(chuàng)建的時候回調(diào)
                    mediaPlayer.setDisplay(holder);
                }
                @Override
                public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                }
                @Override
                public void surfaceDestroyed(SurfaceHolder holder) {
                //SurfaceHolder被銷毀的時候回調(diào)骆姐,在這里可以做一些釋放資源的操作镜粤,防止內(nèi)存泄漏
                }
            });
            //MediaPlayer加載流媒體完畢的監(jiān)聽
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    //獲取視頻的寬高
                    int videoHeight = mediaPlayer.getVideoHeight();
                    int videoWidth = mediaPlayer.getVideoWidth();
                    if (videoHeight > mHeight || videoWidth> mWidth){
                        //如果視頻的寬或者高超出屏幕,要縮放
                        float widthRatio = (float)videoWidth/(float)mWidth;
                        float heightRatio = (float)videoHeight/(float)mHeight;
                        //選擇大的進行縮放
                        float max = Math.max(widthRatio,heightRatio);
                        videoWidth = (int) Math.ceil(videoWidth/max);
                        videoHeight = (int) Math.ceil(videoHeight/max);
                        //設(shè)置surfaceview的布局參數(shù)
                        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(videoWidth, videoHeight);
                        //設(shè)置垂直居中
                        layoutParams.gravity = Gravity.CENTER_VERTICAL;
                        mSurface.setLayoutParams(layoutParams);
                    }
                    mediaPlayer.start();
                    //mediaPlayer.setLooping(true);
                }
            });
            mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    //播放完成監(jiān)聽
                    finish();
                }
            });
            mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                @Override
                public boolean onError(MediaPlayer mp, int what, int extra) {
                //發(fā)生錯誤監(jiān)聽
                    return false;
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

五.三種播放視頻方式的分析對比

1. android SDK自帶的 MediaPlayer+SurfaceView或者videoview (簡單快速,格式支持少)

2. MediaPlayer類是Androd多媒體框架中的一個重要組件诲锹,通過該類繁仁,我們可以以最小的步驟來獲取,解碼和播放音視頻归园。它支持三種不同的媒體來源:

在播放網(wǎng)絡(luò)上的視頻流時黄虱,Android原生的MediaPlayer支持兩種協(xié)議,HTTP和RTSP庸诱,這兩種協(xié)議最大的不同是捻浦,RTSP協(xié)議支持實時流媒體的播放晤揣,而HTTP協(xié)議不支持。因為VideoView的底層實現(xiàn)是MediaPlayer朱灿,因此VideoView也支持以上兩種協(xié)議昧识。 ?但是Android原生MediaPalyer支持的協(xié)議(不支持RTMP、MMS等)和封裝格式實在太有限了盗扒,如果我們想播放那些它不支持的視頻跪楞,這時候就需要第三方播放器了,很多第三方播放器的底層實現(xiàn)都是基于FFmpeg侣灶,后續(xù)我會專門來講講第三方播放器和FFmpeg的使用甸祭。

3. MediaPlayer主要用于播放音頻,沒有提供圖像輸出界面褥影,所以我們需要借助其他的組件來顯示MediaPlayer播放的圖像輸出池户,我們可以使用SurfaceView來顯示。

4. 除了使用MediaPlayer + SurfaceView播放視頻的方式凡怎,我們還可以使用VideoView來直接播放視頻校焦。

5. SurfaceView播放視頻時,如果不進行設(shè)置统倒,視頻寬高總是等于定義的SurfaceView布局寬高寨典,所以視頻可能會被拉伸變形。而使用VideoView時檐薯,視頻寬度等于VideoView布局寬凝赛,但是高是自適應(yīng)的注暗,自動調(diào)整寬高比到視頻原始比例坛缕,所以不會有拉伸。

6. 本地資源,內(nèi)部URI捆昏,比如你可以通過ContentResolver來獲取,外部URL(流)

六.播放視頻資源的格式限制

Android官方公布的文檔顯示MediaPlayer支持如下視頻格式:

 H.263 X X 3GPP (.3gp)

MPEG-4 (.mp4)? 

 H.264 AVC X 3GPP (.3gp)

 MPEG-4 (.mp4)? 

 MPEG-4 SP X 

3GPP (.3gp)

這些格式的視頻赚楚,基本上屬于手機支持的視頻格式。如果想觀看其他類型格式的視頻骗卜,比如flv等宠页,需要下載暴風(fēng)、迅雷等播放器寇仓。

七.三方視頻庫

1.Vitamio
Vitamio 是一款 Android與 iOS平臺上的全能多媒體開發(fā)框架举户,全面支持硬件解碼與 GPU渲染。Vitamio憑借其簡潔易用的 API接口贏得了全球眾多開發(fā)者的青睞遍烦。到目前俭嘁,全球已經(jīng)有超過 1800種應(yīng)用在使用 Vitamio,覆蓋用戶超過 2億服猪。

Vitamio 能夠流暢播放720P甚至1080P高清MKV供填,F(xiàn)LV拐云,MP4,MOV近她,TS叉瘩,RMVB等常見格式的視頻,還可以在 Android 與iOS上跨平臺支持 MMS, RTSP,RTMP, HLS(m3u8)等常見的多種視頻流媒體協(xié)議粘捎,包括點播與直播薇缅。
目前Vitamio的項目托管在Github上面:https://github.com/yixia
2.JiaoZiVideoPlayer(以前叫節(jié)操播放器)
Github:https://github.com/lipangit/JiaoZiVideoPlayer
3.ijkplayer
項目地址:https://github.com/Bilibili/ijkplayer
介紹:Ijkplayer 是Bilibili發(fā)布的基于 FFplay 的輕量級 Android/iOS 視頻播放器。實現(xiàn)了跨平臺功能攒磨,API 易于集成捅暴;編譯配置可裁剪,方便控制安裝包大羞志馈蓬痒;支持硬件加速解碼杨刨,更加省電圃阳;提供 Android 平臺下應(yīng)用彈幕集成的解決方案券时。

這里還有很多:http://www.sohu.com/a/149331808_733133

八.獲取視頻的第一幀
添加一個按鈕,點擊的時候切換橫豎屏

private void switchScreen() {
      //獲取當(dāng)前屏幕的方向
      int requestedOrientation = getRequestedOrientation();
      if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT){
            //設(shè)置屏幕方向,豎屏,切換為橫屏
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }else {       
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
    }

對應(yīng)Activity在清單文件中配置,因為屏幕切換的時候Activity會重建,添加配置后Activity就不會重建了

<activity android:name=".VideoViewActivity"
    //screensize,屏幕大小發(fā)生改變;
    //orientation屏幕方向發(fā)生改變
    //keyboardHidden鍵盤隱藏
    android:configChanges="screenSize|orientation|keyboardHidden"
 />
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末劫狠,一起剝皮案震驚了整個濱河市毁欣,隨后出現(xiàn)的幾起案子耳标,更是在濱河造成了極大的恐慌杠步,老刑警劉巖孩锡,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸟顺,死亡現(xiàn)場離奇詭異惦蚊,居然都是意外死亡,警方通過查閱死者的電腦和手機讯嫂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門蹦锋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人欧芽,你說我怎么就攤上這事莉掂。” “怎么了千扔?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵憎妙,是天一觀的道長。 經(jīng)常有香客問我曲楚,道長厘唾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任龙誊,我火速辦了婚禮抚垃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己讯柔,他們只是感情好抡蛙,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著魂迄,像睡著了一般粗截。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上捣炬,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天熊昌,我揣著相機與錄音,去河邊找鬼湿酸。 笑死婿屹,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的推溃。 我是一名探鬼主播昂利,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼铁坎!你這毒婦竟也來了蜂奸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤硬萍,失蹤者是張志新(化名)和其女友劉穎扩所,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體朴乖,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡祖屏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了买羞。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袁勺。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖哩都,靈堂內(nèi)的尸體忽然破棺而出魁兼,到底是詐尸還是另有隱情,我是刑警寧澤漠嵌,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站盖呼,受9級特大地震影響儒鹿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜几晤,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一约炎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦圾浅、人聲如沸掠手。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喷鸽。三九已至,卻和暖如春灸拍,著一層夾襖步出監(jiān)牢的瞬間做祝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工鸡岗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留混槐,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓轩性,卻偏偏與公主長得像声登,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子揣苏,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

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

  • 學(xué)習(xí)目標:Android視頻播放功能在Android應(yīng)用場景(掌握)視頻播放第一種方式使用系統(tǒng)自帶的播放器(掌握)...
    Anwfly閱讀 1,657評論 0 1
  • 視頻播放器在App是很常見的捌刮,有哪些視頻播放器呢?具體情況該用哪款呢舒岸?這里我總結(jié)了常用的視屏播放Videoview...
    奔跑吧李博閱讀 29,684評論 2 46
  • 音頻視頻播放在現(xiàn)在的應(yīng)用里面很常見绅作,傳統(tǒng)應(yīng)用發(fā)展到一定階段多少會引入音視頻資源,特別是現(xiàn)在短視頻被看作下一個增長爆...
    想飛的小小小魚閱讀 634評論 1 2
  • 一蛾派、流媒體 什么是流媒體技術(shù)?簡單的說俄认,就是邊下載,邊播放洪乍。也就是說眯杏,客戶端在播放前,無需下載整個媒體文件壳澳,而是在...
    szy啊閱讀 16,079評論 2 23
  • 我們有三種方式來實現(xiàn)視頻的播放: 1岂贩、使用其自帶的播放器。指定Action為ACTION_VIEW,Data為Ur...
    ItemWang閱讀 720評論 0 1