Android 音视频开发 - VideoView

Android 音视频开发 - VideoView

本篇文章主要介绍下Android 中的VideoView.

1: VideoView简介

VideoView是一个用于播放视频的视图组件,可以方便地在应用程序中播放本地或网络上的视频文件。

VideoView可以直接在布局文件中使用,也可以在代码中动态创建。

它封装了MediaPlayer和SurfaceView,提供了简单的接口来控制视频的播放和显示。

它提供了一系列方法来控制视频的播放、暂停、停止等操作,并且支持全屏播放和视频控制器的显示。

VideoView播放视频非常简单,只需要指定视频的URL或本地路径.

2: 使用

以下是VideoView的简单使用:

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 设置视频源

代码如下:

videoView = findViewById(R.id.videoview);
videoView.setVideoPath("sdcard/test.mp4");

除了setVideoPath外,我们还可以调用:

  1. setVideoURI(Uri uri)
  2. setVideoURI(Uri uri, Map<String, String> headers)

当然不管是setVideoPath或者setVideoURI实际都是执行的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;
}

可以看到实际上调用mMediaPlayer.start();另外设置了当前的状态为STATE_PLAYING.

这里直接调用了mMediaPlayer.start();那mMediaPlayer是什么时机初始化的呢?

查看源码可以看到:

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()

  1. release()方法释放正在播放的视频.
  2. 初始化mMediaPlayer,传入Uri,设置状态 STATE_PREPARING。
  3. attachMediaController()绑定MediaPlayer与VideoView。

最后openVideo()则是在setVideoURI(Uri uri, Map<String, String> headers)内调用。

这样其实已经可以播放指定的视频了。

下面的方法可选。

2.4 MediaController控制器

MediaController是一个用于控制媒体播放器的视图组件。

MediaController的使用步骤如下:

  1. 创建一个MediaController对象:MediaController mediaController = new MediaController(context);
  2. 将MediaController与媒体播放器组件关联:mediaController.setMediaPlayer(mediaPlayer);
  3. 将MediaController添加到布局中:layout.addView(mediaController);
videoView.setMediaController(new MediaController(this));
videoView.start().

直接调用setMediaController,运行后我们可以看到与之前直接调用start()的区别就是多了个控制器的显示。其中包含一组常用的媒体控制按钮,如播放/暂停、快进/快退、前进/后退等,并且可以与MediaPlayer或VideoView等媒体播放器组件进行关联.

我们可以看下源码:

public void setMediaController(MediaController controller) {
 if (mMediaController != null) {
 mMediaController.hide();
 }
 mMediaController = controller;
 attachMediaController();
}

可以看到做的操作如下:

  1. 如果存在mMediaController,则调用hide方法。
  2. 对mMediaController赋值
  3. attachMediaController

本文由博客一文多发平台 OpenWrite 发布!

作者:夏沫琅琊原文地址:https://www.cnblogs.com/zhjing/p/18119450

%s 个评论

要回复文章请先登录注册