Get into the habit of writing together! This is the 4th day of my participation in the "Nuggets Daily New Plan·April Update Challenge", click to view the details of the event .
Introduction to VideoView
I have previously introduced the use of MediaPlayer
+ SurfaceView
to realize the function of playing video. I accidentally found that the official packaged VideoView
components to realize the simple video playback function, and the MediaPlayer
+ SurfaceView
form is also used to control MediaPlayer
the playback of video files. The usage scenario is relatively simple, and it is suitable for the scenario of just playing the video. Its limited ability is not suitable for other functions such as adjusting the video brightness.
MediaController
In addition to the playback component VideoView
, there is also a MediaController
component that provides a playback operation bar function for video playback, which supports video playback, pause, fast forward, fast reverse and other functions. In addition, it also provides a progress bar function that can be dragged to a specified position to play the video.
use
VideoView
The package MediaPlayer
also provides a similar MediaPlayer
API. For example start
, the method is also the function of playing video, but it is best to set the setOnpreparedListener
callback result before calling the method to execute the method, and the method setVideoPath
will be actively executed after the prepareAsync
method is called. It VideoView
helps developers to encapsulate and implement many functions internally. In fact, it can also learn from its internal source code to realize a more comprehensive and more complete self-made player.
Common APIs | illustrate |
---|---|
setVideoPath | Set up video assets |
start | play |
pause | pause |
resume | replay |
seekTo | Play at a specified location |
isPlaying | Whether the video is playing |
getCurrentPosition | Get the current playback position |
setMediaController | Set up MediaController |
setOnpreparedListener | Listen for video loading completion event |
// 实例化videoView
videoView = new VideoView(this);
Uri uri = Uri.fromFile(new File("sdcard/DCIM","新世纪福音战士24.mp4"));
//加载视频资源
videoView.setVideoURI(uri);
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.addView(videoView);
setContentView(linearLayout);
//设置监听
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
//回调成功并播放视频
videoView.start();
}
});
//创建操作栏
MediaController mediaController = new MediaController(this);
videoView.setMediaController(mediaController);
mediaController.setMediaPlayer(videoView);
复制代码
Source code analysis
VideoView
Now that the two components are encapsulated MediaController
, many functions that have been tried to be implemented before are found in the process of use to see how they are implemented.
progress display
MediaController
A method show
can be seen inside the calling method when displayedpost(mShowProgress);
public void show(int timeout) {
if (!mShowing && mAnchor != null) {
setProgress();
if (mPauseButton != null) {
mPauseButton.requestFocus();
}
disableUnsupportedButtons();
updateFloatingWindowLayout();
mWindowManager.addView(mDecor, mDecorLayoutParams);
mShowing = true;
}
updatePausePlay();
// cause the progress bar to be updated even if mShowing
// was already true. This happens, for example, if we're
// paused with the progress bar showing the user hits play.
post(mShowProgress);
if (timeout != 0 && !mAccessibilityManager.isTouchExplorationEnabled()) {
removeCallbacks(mFadeOut);
postDelayed(mFadeOut, timeout);
}
}
复制代码
It can be seen that it mShowProgress
is one Runnable
, and the internal delay will call itself to update setProgress()
. setProgress()
The method is to read the MediaPlayer
playback progress to update the playback information.
private final Runnable mShowProgress = new Runnable() {
@Override
public void run() {
int pos = setProgress();
if (!mDragging && mShowing && mPlayer.isPlaying()) {
postDelayed(mShowProgress, 1000 - (pos % 1000));
}
}
};
复制代码
Play size adaptation
Before customizing the playback size adaptation, it VideoView
directly helps developers to achieve video playback adaptation internally. The detailed code can be onMeasure
directly rewritten. The approximate algorithm of the code is VideoView
to rewrite the calculated width and height by comparing the width and height of the layout and the width and height of the video VideoView
.
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
// + MeasureSpec.toString(heightMeasureSpec) + ")");
int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
if (mVideoWidth > 0 && mVideoHeight > 0) {
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) {
// the size is fixed
width = widthSpecSize;
height = heightSpecSize;
// for compatibility, we adjust size based on aspect ratio
if ( mVideoWidth * height < width * mVideoHeight ) {
//Log.i("@@@", "image too wide, correcting");
width = height * mVideoWidth / mVideoHeight;
} else if ( mVideoWidth * height > width * mVideoHeight ) {
//Log.i("@@@", "image too tall, correcting");
height = width * mVideoHeight / mVideoWidth;
}
} else if (widthSpecMode == MeasureSpec.EXACTLY) {
// only the width is fixed, adjust the height to match aspect ratio if possible
width = widthSpecSize;
height = width * mVideoHeight / mVideoWidth;
if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
// couldn't match aspect ratio within the constraints
height = heightSpecSize;
}
} else if (heightSpecMode == MeasureSpec.EXACTLY) {
// only the height is fixed, adjust the width to match aspect ratio if possible
height = heightSpecSize;
width = height * mVideoWidth / mVideoHeight;
if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
// couldn't match aspect ratio within the constraints
width = widthSpecSize;
}
} else {
// neither the width nor the height are fixed, try to use actual video size
width = mVideoWidth;
height = mVideoHeight;
if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
// too tall, decrease both width and height
height = heightSpecSize;
width = height * mVideoWidth / mVideoHeight;
}
if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
// too wide, decrease both width and height
width = widthSpecSize;
height = width * mVideoHeight / mVideoWidth;
}
}
} else {
// no size yet, just adopt the given spec sizes
}
setMeasuredDimension(width, height);
}
复制代码