1. 程式人生 > >使用MediaPlayer播放音視訊精煉詳解

使用MediaPlayer播放音視訊精煉詳解

這裡寫圖片描述

一、前期基礎知識儲備

MediaPlayer是一個支援音訊及視訊檔案播放的Android類,可播放不同來源(本地 網路)、多種格式(如WAV/MP3/MPEG-4/3GPP/Ogg Vorbis)的多媒體檔案。
多媒體檔案可以是儲存在應用程式的 res/raw 資料夾下,也可以是儲存在手機的檔案系統中,甚至可以是來自與網路的流媒體。raw資料夾負責存放那些不需要Android編譯系統特別處理的各類檔案,res下預設是沒有raw資料夾的,建立方法如下:
這裡寫圖片描述
這裡寫圖片描述
例項化一個MediaPlayer物件一共有三種方法:
1)create(Context context, Uri uri, SurfaceHolder holder)
Convenience method to create a MediaPlayer for a given Uri.
2)create

(Context context, int resid)
Convenience method to create a MediaPlayer for a given resource id.
3)create(Context context, Uri uri)
Convenience method to create a MediaPlayer for a given Uri.
注意: 你只能通過標準輸出裝置來播放音訊檔案。目前來講,就是通過手機的揚聲器和藍芽耳機。 不能在通話時播放音訊檔案。
使用MediaPlayer時申請的許可權:
1)<uses-permission android:name="android.permission.INTERNET" />
Internet Permission - 如果你打算使用 MediaPlayer 來播放網路流媒體內容,那麼你的應用需要有這個許可權;
2)<uses-permission android:name="android.permission.WAKE_LOCK" />
Wake Lock Permission - 如果你想要應用不滅屏或者程序不進入休眠狀態,或者你像要在你的應用程式中使用 MediaPlayer.setScreenOnWhilePlaying() 方法或 MediaPlayer.setWakeMode() 方法, 你需要新增這個許可權

二、上程式碼,具體實現

以下是程式碼的整體設計圖:
這裡寫圖片描述


從圖中可以看到程式碼中包含一個Fragment即一個用於託管Fragemnt的Activity。MyAudioMediaPlayer是我們編寫的類,用於封裝MediaPlayer類。也可以選擇不封裝MediaPlayer類,而讓Fragment直接與MediaPLayer進行互動。不過,為了保持程式碼的整潔與獨立,這裡使用了封裝MediaPlayer類的設計。
(1)Fragment程式碼及Fragemnt的佈局檔案;

public class HelloMoonFragment extends Fragment {
    private MyAudioPlayer mPlayer;
    private Button mPlayButton;
    private Button mStopButton;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_hello_moon, container, false);

        mPlayButton = (Button) view.findViewById(R.id.hellomoon_playBtn);
        mPlayButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPlayer.play(getActivity());
            }
        });
        mStopButton = (Button) view.findViewById(R.id.hellomoon_stopBtn);
        mStopButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPlayer.stop();
            }
        });
        return view;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mPlayer.stop();
    }
}
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:src="@drawable/bv"
        android:contentDescription="圖片也可以有文字屬性?"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerInside"
        android:layout_weight="1"/>

    <TableRow
        android:gravity="center|bottom"
        android:layout_weight="0">

        <Button
            android:id="@+id/hellomoon_playBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="play"/>

        <Button
            android:id="@+id/hellomoon_stopBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="stop"/>
    </TableRow>
</TableLayout>

使用MediaPlayer之後,Fragment中要覆寫onDestroy()方法,這是因為MediaPlayer執行在一個不同的執行緒中,這裡在Fragment的銷燬方法中呼叫MediaPlayer的銷燬方法,防止MediaPlayer一直佔用著音訊解碼硬體及其他系統資源,而這些系統資源是由所有應用所共享的。
(2)Activity程式碼及Activity的佈局檔案;

public class PaintPositionInTest extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        PaintPositionIn paintPositionIn = new PaintPositionIn(this);
        setContentView(R.layout.activity_hello_moon);
    }
}
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/helloMoonFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="com.example.administrator.animation_practice.fragment.HelloMoonFragment">

</fragment>

這裡用Fragemnt的靜態載入方法,將其直接新增進Activity的佈局檔案,使用靜態載入Fragment的方式失去了靈活性和掌控能力,但是對於Activity的靜態部分而言,靜態載入也是一個不錯的選擇。
(3)封裝MediaPlayer類的MyAudioPlayer類;

public class MyAudioPlayer {
    private MediaPlayer mPlayer;

    public void stop(){
        if (mPlayer != null){
            mPlayer.release();
            mPlayer = null;
        }
    }

    public void play(Context c){
        stop();

        mPlayer = MediaPlayer.create(c, R.raw.one_small_step);
        mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                stop();
            }
        });
        try {
            mPlayer.prepare(); //預載入音訊 使用時放置在try catch中
        } catch (IOException e) {
            e.printStackTrace();
        }
        mPlayer.start(); //正式載入音訊
    }
}

play()方法中,呼叫對應的create(Context context, int resid)建立mPlayer例項;並且在方法的開頭呼叫stop()方法,可避免使用者多次點選Play按鈕建立多個MediaPlayer例項的情況的發生。同時設立監聽器,音訊檔案播放完之後,立即呼叫stop()方法,儘可能快遞釋放MediaPlayer例項及其佔用的資源。
stop()方法中,釋放MediaPlayer例項並將mPlayer變數設定為null,呼叫Media.release()方法,銷燬該例項。
封裝MediaPlayer之後,之後管理播放器的狀態會更加的方便,實際開發中,相機、音訊播放、視訊播放等多媒體行為,生命週期、狀態非常多,需要多重控制,封裝程式碼之後可以更加方便的管理。

三、使用MediaPlayer播放視訊

在Android系統中,快速重新整理顯示的可檢視像(比如視訊、相機預覽)是在SurfaceView中顯示的,準確地說,是在SurfaceView內嵌的Surface中顯示的。通過SurfaceView的SurfaceHolder,可實現Surface上顯示視訊。使用MediaPlayer播放視訊的關鍵程式碼在於將MediaPlayer類與SurfaceHolder關聯起來,方法為:
MediaPlayer.setDisplay(SurfaceHolder);

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback{

    ...
    private SurfaceView mSurfaceView;
    private String mMediaPath;
    private MediaPlayer mMediaPlayer;
    private SurfaceHolder mSurfaceHolder;
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //6.0及以上系統請求執行時許可權 利用許可權申請工具類
        requestCameraAndStoragePermission();

        mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
        mSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); //必須-設定Surface不需要維護自己的緩衝區
        initBtnClick();

        SurfaceHolder holder =  mSurfaceView.getHolder();
        holder.addCallback(this);
    }

    private void requestCameraAndStoragePermission() {
        ...
        ...
    };

    ......
    ......

    private void initBtnClick() {

        mPlayBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mMediaPlayer == null) {
                    mMediaPlayer = new MediaPlayer();
                    mMediaPlayer.reset();
                    Uri uri = Uri.parse(mMediaPath);
                    mMediaPlayer = MediaPlayer.create(MainActivity.this,uri);
                    mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                    mMediaPlayer.setDisplay(mSurfaceHolder);
                    try{
                        mMediaPlayer.prepare();
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    mMediaPlayer.start();
                }
            }
        });

    }


    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        mSurfaceHolder = surfaceHolder;
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        mSurfaceHolder = surfaceHolder;
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        mSurfaceView = null;
        mSurfaceHolder = null;
        releaseMediaRecorder();

        if (mCamera != null) {
            mCamera.release();
            mCamera = null;
        }
        if (mMediaPlayer != null){
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
    }
}

通常來說,使用VideoView例項播放視訊更加容易些,不同於SurfaceView同MediaPlayer的互動,VideoView是與MediaController互動的,這樣可以方便地提供視訊播放介面。

相關推薦

使用MediaPlayer播放視訊精煉

一、前期基礎知識儲備 MediaPlayer是一個支援音訊及視訊檔案播放的Android類,可播放不同來源(本地 網路)、多種格式(如WAV/MP3/MPEG-4/3GPP/Ogg Vorbis)的多媒體檔案。 多媒體檔案可以是儲存在應用程式的 re

Android劉海屏適配精煉

一、前期基礎知識儲備 話不多說,這麼多劉海屏手機今年集中爆發,所以儘管劉海屏不好看,但是還是要適配。 2017年蘋果X開啟了劉海屏時代,2018年集中爆發,紛紛採取劉海屏這一策略來實現全面屏的概念,所以Android手機對於劉海屏的適配也是比較重要的。所謂適配劉海屏,其實就是處理與

SQLite資料庫精煉

一、前期基礎知識儲備 Android本地化儲存三種方式: ①檔案儲存,儲存簡單二進位制資料和文字資料; ②SharedPreference儲存,鍵值對儲存,儲存資料型別多樣,儲存方式單一; ③SQLite資料庫儲存,Android內建資料庫,儲存複雜關係型資料,質的飛躍。 SQLi

Android提高第二十一篇之MediaPlayer播放網路視訊

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

振鈴訊號、撥號音、回鈴、忙音

轉自:https://www.cnblogs.com/sddai/p/8847950.html 1、振鈴訊號 用來呼叫被叫使用者。鈴流為25±3Hz正弦波,諧波失真不大於10%,輸出電壓有效值90+-15V,振鈴採用5s斷續,即一秒送,4s斷,斷、續時間偏差不超過±10%。 2、撥號音

Android FFmpeg系列——4 子執行緒播放視訊

利用工作閒餘時間,終於實現在子執行緒播放音視訊! 上一接學習了在 C 使用多執行緒,接著就是利用 C 多執行緒同時播放音視訊(暫時還不同步)。 不多說,直接上碼。 程式碼 // C 層播放器結構體 typedef struct _Player { //

程序間通訊(IPC機制)精煉

一、前期基礎知識儲備IPC定義:IPC是intent-Process Communication的縮寫,含義為程序間通訊或者跨程序通訊,是指兩個程序之間進行資料交換的過程。IPC不是Android所獨有的,任何一個作業系統都需要有相應的IPC機制,比如Windows上可以通過

Java執行緒阻塞方法sleep()和wait()精煉

一、前期基礎知識儲備 sleep()和wait()方法都是Java中造成執行緒阻塞的方法。感興趣的讀者可以參見筆者之前的文章《Java中什麼方法導致執行緒阻塞》,裡面詳細講述了為什麼Java要造成執行緒阻塞和Java中造成執行緒阻塞的幾種方法。 執行緒的生命週期 這

讀寫(read&write)視訊(video) 及 程式碼

讀取(read&write)視訊(video) 詳解 及 程式碼本文地址: http://blog.csdn.net/caroline_wendy/article/details/1708439

Android程序保活精煉

一、前期基礎知識儲備在之前的文章《如何保證Service在後臺不被殺死?》中,筆者分析了為什麼要保活Service、Service的幾種保活方法和Service保活的意義。今天的這篇文章就更進一步,講解程序保活的方法和意義。(1)什麼是程序保活?拿我們的手機應用程式QQ來說,

C# 使用SDL2實現Mp4檔案播放視訊

播放音視訊的關鍵:視訊的格式是H264,音訊的格式是AAC。使用ffmpeg探測流的方式來實現音視訊流的解碼播放。資料處理邏輯:H264->YUV     AAC->PCM。SDL2工具類using SDL2; using System; using System

Android之MediaPlayer播放網路視訊的實現方法

前段時間忙於工作,現在有時間來分享一下: 這篇文章主要介紹了Android的MediaPlayer播放網路視訊的實現方法,是一個非常實用的功能,需要的朋友可以參考下 前面講解了MediaPlayer播放網路音訊,主要介紹了MediaPlayer關於網路音訊

視訊小程式wx.requestpayment用法,實現小程式線上支付功能

開發小程式商城,外賣小程式,銷售型小程式等,具有線上支付功能的,都會使用wx.requestpayment()這個介面。好多學員反饋說這個介面很難,今天子恆老師跟你分享一下,怎麼使用wx.requestpayment實現微信支付。一、 使用wx.requestpayment實

ubuntu下 gstreamer 的配置及播放視訊例子

Gstreamer安裝: 使用sudo apt-get install 安裝 sudo apt-get install libgstreamer0.10-dev gstreamer-tools gstreamer0.10-tools gstreamer0.10-

Android使用GPUImage實現濾鏡效果精煉(一)

一、前期基礎知識詳解 “濾鏡通常用於相機鏡頭作為調色、新增效果之用。如UV鏡、偏振鏡、星光鏡、各種色彩濾光片。濾鏡也是繪圖軟體中用於製造特殊效果的工具統稱,以Photoshop為例,它擁有風格化、畫筆描邊、模糊、扭曲、銳化、視訊、素描、紋理、畫素化、渲染、藝術效果、其他

QT QMediaPlayer 播放視訊檔案

QMediaPlayer類是QT自帶的多媒體類。 實現簡單的音視訊播放是很簡單的。 QMediaPlayer qtaudioPlayer; qtaudioPlayer->setMedia(QUrl::fromLocalFile(filePath)); qtaudio

視訊採集

為了管理從相機或者麥克風等這樣的裝置捕獲到的資訊,我們需要輸入物件(input)和輸出物件(output),並且使用一個會話(AVCaptureSession)來管理 input 和 output 之前的資料流: 類名 簡介 AVC

Android中記憶體洩漏超級精煉

一、前期基礎知識儲備 (1)什麼是記憶體? JAVA是在JVM所虛擬出的記憶體環境中執行的,JVM的記憶體可分為三個區:堆(heap)、棧(stack)和方法區(method)。 棧(stack):是簡單的資料結構,但在計算機中使用廣泛。棧最顯著的特徵是:LIF

Android混淆精煉+常用庫混淆+通用混淆模板

一、前期基礎知識詳解 筆者最近開發一個專案,是在開源專案基礎上構築的,在最近一個版本釋出前夕,出現了一個奇怪的問題:在測試手機上執行的應用,功能正常,但是在打出release正式包之後,測試時發現上傳功能失效,不能上傳資料,即debug包功能正常,release

SharedPreference儲存精煉

前期基礎知識儲備 之前做應用時碰到一個問題:在使用者初次進入某個介面時,需要彈出一個提示,或者在EditText上顯示一個hint;而使用者之後進入就不再彈出提示了。思考之後就選擇了SharedPreferences這個輕型的資料儲存方式。儲存一個布林型值作為ke