Android 音視頻開(kāi)發(fā) - VideoView
本篇文章主要介紹下Android 中的VideoView.
1: VideoView簡(jiǎn)介
VideoView是一個(gè)用于播放視頻的視圖組件,可以方便地在應(yīng)用程序中播放本地或網(wǎng)絡(luò)上的視頻文件镐确。
VideoView可以直接在布局文件中使用迈倍,也可以在代碼中動(dòng)態(tài)創(chuàng)建。
它封裝了MediaPlayer和SurfaceView,提供了簡(jiǎn)單的接口來(lái)控制視頻的播放和顯示坟瓢。
它提供了一系列方法來(lái)控制視頻的播放鳞仙、暫停、停止等操作峭判,并且支持全屏播放和視頻控制器的顯示开缎。
VideoView播放視頻非常簡(jiǎn)單,只需要指定視頻的URL或本地路徑.
2: 使用
以下是VideoView的簡(jiǎn)單使用:
2.1 布局
在XML布局文件中添加VideoView組件.
<VideoView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:id="@+id/videoview"
/>
2.2 設(shè)置視頻源
代碼如下:
videoView = findViewById(R.id.videoview);
videoView.setVideoPath("sdcard/test.mp4");
除了setVideoPath外,我們還可以調(diào)用:
- setVideoURI(Uri uri)
- setVideoURI(Uri uri, Map<String, String> headers)
當(dāng)然不管是setVideoPath或者setVideoURI實(shí)際都是執(zhí)行的setVideoURI(Uri uri, Map<String, String> headers).
源碼如下:
/**
* Sets video path.
*
* @param path the path of the video.
*/
public void setVideoPath(String path) {
setVideoURI(Uri.parse(path));
}
/**
* Sets video URI.
*
* @param uri the URI of the video.
*/
public void setVideoURI(Uri uri) {
setVideoURI(uri, null);
}
2.3 播放視頻
videoView.start();
我們可以看下start()的源碼:
@Override
public void start() {
if (isInPlaybackState()) {
mMediaPlayer.start();
mCurrentState = STATE_PLAYING;
}
mTargetState = STATE_PLAYING;
}
可以看到實(shí)際上調(diào)用mMediaPlayer.start();另外設(shè)置了當(dāng)前的狀態(tài)為STATE_PLAYING.
這里直接調(diào)用了mMediaPlayer.start();那mMediaPlayer是什么時(shí)機(jī)初始化的呢?
查看源碼可以看到:
private void openVideo() {
if (mUri == null || mSurfaceHolder == null) {
// not ready for playback just yet, will try again later
return;
}
// we shouldn't clear the target state, because somebody might have
// called start() previously
release(false);
if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
// TODO this should have a focus listener
mAudioManager.requestAudioFocus(null, mAudioAttributes, mAudioFocusType, 0 /*flags*/);
}
try {
mMediaPlayer = new MediaPlayer();
// TODO: create SubtitleController in MediaPlayer, but we need
// a context for the subtitle renderers
final Context context = getContext();
final SubtitleController controller = new SubtitleController(
context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer);
controller.registerRenderer(new WebVttRenderer(context));
controller.registerRenderer(new TtmlRenderer(context));
controller.registerRenderer(new Cea708CaptionRenderer(context));
controller.registerRenderer(new ClosedCaptionRenderer(context));
mMediaPlayer.setSubtitleAnchor(controller, this);
if (mAudioSession != 0) {
mMediaPlayer.setAudioSessionId(mAudioSession);
} else {
mAudioSession = mMediaPlayer.getAudioSessionId();
}
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
mMediaPlayer.setOnInfoListener(mInfoListener);
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
mCurrentBufferPercentage = 0;
mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
mMediaPlayer.setDisplay(mSurfaceHolder);
mMediaPlayer.setAudioAttributes(mAudioAttributes);
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.prepareAsync();
for (Pair<InputStream, MediaFormat> pending: mPendingSubtitleTracks) {
try {
mMediaPlayer.addSubtitleSource(pending.first, pending.second);
} catch (IllegalStateException e) {
mInfoListener.onInfo(
mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0);
}
}
// we don't set the target state here either, but preserve the
// target state that was there before.
mCurrentState = STATE_PREPARING;
attachMediaController();
} catch (IOException ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
return;
} catch (IllegalArgumentException ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
return;
} finally {
mPendingSubtitleTracks.clear();
}
}
可以看到openVideo()
- release()方法釋放正在播放的視頻.
- 初始化mMediaPlayer,傳入U(xiǎn)ri,設(shè)置狀態(tài) STATE_PREPARING林螃。
- attachMediaController()綁定MediaPlayer與VideoView奕删。
最后openVideo()則是在setVideoURI(Uri uri, Map<String, String> headers)內(nèi)調(diào)用。
這樣其實(shí)已經(jīng)可以播放指定的視頻了疗认。
下面的方法可選完残。
2.4 MediaController控制器
MediaController是一個(gè)用于控制媒體播放器的視圖組件。
MediaController的使用步驟如下:
- 創(chuàng)建一個(gè)MediaController對(duì)象:MediaController mediaController = new MediaController(context);
- 將MediaController與媒體播放器組件關(guān)聯(lián):mediaController.setMediaPlayer(mediaPlayer);
- 將MediaController添加到布局中:layout.addView(mediaController);
videoView.setMediaController(new MediaController(this));
videoView.start().
直接調(diào)用setMediaController,運(yùn)行后我們可以看到與之前直接調(diào)用start()的區(qū)別就是多了個(gè)控制器的顯示横漏。其中包含一組常用的媒體控制按鈕谨设,如播放/暫停、快進(jìn)/快退缎浇、前進(jìn)/后退等扎拣,并且可以與MediaPlayer或VideoView等媒體播放器組件進(jìn)行關(guān)聯(lián).
我們可以看下源碼:
public void setMediaController(MediaController controller) {
if (mMediaController != null) {
mMediaController.hide();
}
mMediaController = controller;
attachMediaController();
}
可以看到做的操作如下:
- 如果存在mMediaController,則調(diào)用hide方法素跺。
- 對(duì)mMediaController賦值
- attachMediaController
本文由博客一文多發(fā)平臺(tái) OpenWrite 發(fā)布二蓝!