Android audio and video went deep into 1949th using ijkplayer as a video player (with source code download) and androiw.player
Project address
Https://github.com/979451341/Myijkplayer
Some time ago, I thought it was difficult to make FFmpeg a video player. Although there was no problem in playing the video, I still needed to drag the progress bar to set the playing progress, that can be postponed .....
Now let's take a look at ijkplayer, the most well-known Video Player framework on mobile terminals, which is based on FFmpeg, SDL, and Android native API MediaCodec. He does not have a playback interface. We need to do this, so I am going to create an ijkplayer-based video player. Let's just talk about the ijkplayer source code, I will write a blog about ijkplayer source code later.
1. First, let's take a look at how ijkplayer works.
Here I introduce ijkplayer by adding dependencies.
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8'
Then let's talk about how ijkplayer plays a video.
Ijkplayer creates a Mediaplayer and assigns a value to an interface class for each video playback. Here, it selects the decoding type when it is created, because it is hard to solve the problem based on Android native API MediaCodec, fast Speed and poor compatibility. If it is based on FFmpeg, it is soft solution, which is slow and compatible. However, this compatibility problem is caused by the dependency of various processors when we introduce dependencies, therefore, you can use hard decoding. The compatibility issues are basically caused by different mobile phone processors.
IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer ();
ijkMediaPlayer.native_setLogLevel (IjkMediaPlayer.IJK_LOG_DEBUG);
// // Enable hard decoding
ijkMediaPlayer.setOption (IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
IMediaPlayer mMediaPlayer = null;
mMediaPlayer = ijkMediaPlayer;
For IjkMediaPlayer source code, I only post one function. From the loadLibrary below, it is still implemented based on FFmpeg and SDL.
public static void loadLibrariesOnce(IjkLibLoader libLoader) {
Class var1 = IjkMediaPlayer.class;
synchronized(IjkMediaPlayer.class) {
if(!mIsLibLoaded) {
if(libLoader == null) {
libLoader = sLocalLibLoader;
}
libLoader.loadLibrary("ijkffmpeg");
libLoader.loadLibrary("ijksdl");
libLoader.loadLibrary("ijkplayer");
mIsLibLoaded = true;
}
}
}
Okay, let's go back to the IMediaPlayer of the interface class. Let's take a look at the source code. Through these interface functions, we can all know how to use this ijkplayer. We all have a bottom, what are setDataSource and setDisplay, set the playback source and screen information. There are also start, stop, pause, video playing start, stop, pause, there are a lot of interfaces, these are to listen to the player status
public interface IMediaPlayer {
。。。。。。
void setDisplay(SurfaceHolder var1);
void setDataSource(Context var1, Uri var2) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
@TargetApi(14)
void setDataSource(Context var1, Uri var2, Map<String, String> var3) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
void setDataSource(FileDescriptor var1) throws IOException, IllegalArgumentException, IllegalStateException;
void setDataSource(String var1) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
String getDataSource();
void prepareAsync() throws IllegalStateException;
void start() throws IllegalStateException;
void stop() throws IllegalStateException;
void pause() throws IllegalStateException;
void setScreenOnWhilePlaying(boolean var1);
int getVideoWidth();
int getVideoHeight();
boolean isPlaying();
void seekTo(long var1) throws IllegalStateException;
long getCurrentPosition();
long getDuration();
void release();
void reset();
void setVolume(float var1, float var2);
int getAudioSessionId();
MediaInfo getMediaInfo();
/** @deprecated */
@Deprecated
void setLogEnabled(boolean var1);
/** @deprecated */
@Deprecated
boolean isPlayable();
void setOnPreparedListener(IMediaPlayer.OnPreparedListener var1);
void setOnCompletionListener(IMediaPlayer.OnCompletionListener var1);
void setOnBufferingUpdateListener(IMediaPlayer.OnBufferingUpdateListener var1);
void setOnSeekCompleteListener(IMediaPlayer.OnSeekCompleteListener var1);
void setOnVideoSizeChangedListener(IMediaPlayer.OnVideoSizeChangedListener var1);
void setOnErrorListener(IMediaPlayer.OnErrorListener var1);
void setOnInfoListener(IMediaPlayer.OnInfoListener var1);
void setOnTimedTextListener(IMediaPlayer.OnTimedTextListener var1);
void setAudioStreamType(int var1);
/** @deprecated */
@Deprecated
void setKeepInBackground(boolean var1);
int getVideoSarNum();
int getVideoSarDen();
/** @deprecated */
@Deprecated
void setWakeMode(Context var1, int var2);
void setLooping(boolean var1);
boolean isLooping();
ITrackInfo[] getTrackInfo();
void setSurface(Surface var1);
void setDataSource(IMediaDataSource var1);
public interface OnTimedTextListener {
void onTimedText(IMediaPlayer var1, IjkTimedText var2);
}
public interface OnInfoListener {
boolean onInfo(IMediaPlayer var1, int var2, int var3);
}
public interface OnErrorListener {
boolean onError(IMediaPlayer var1, int var2, int var3);
}
public interface OnVideoSizeChangedListener {
void onVideoSizeChanged(IMediaPlayer var1, int var2, int var3, int var4, int var5);
}
public interface OnSeekCompleteListener {
void onSeekComplete(IMediaPlayer var1);
}
public interface OnBufferingUpdateListener {
void onBufferingUpdate(IMediaPlayer var1, int var2);
}
public interface OnCompletionListener {
void onCompletion(IMediaPlayer var1);
}
public interface OnPreparedListener {
void onPrepared(IMediaPlayer var1);
}
}
2. Write Interface
Full Screen playback
// Really full screen, hidden status bar, AtionBar, navigation bar
@Override
public void onWindowFocusChanged (boolean hasFocus) {
super.onWindowFocusChanged (hasFocus);
if (hasFocus && Build.VERSION.SDK_INT> = 19) {
View decorView = getWindow (). GetDecorView ();
decorView.setSystemUiVisibility (
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
}
Then there are two topics in the upper and lower sections, responsible for some player control, and the top is responsible for setting the return and set buttons. The playing/pause buttons, playing progress bars, and stop buttons must be set at the bottom.
<com.example.zth.two.VideoPlayerIJK
android:id="@+id/ijk_player"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<include
android:id="@+id/include_play_top"
layout="@layout/include_play_top"
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:layout_height="50dp" />
<include
android:id="@+id/include_play_bottom"
layout="@layout/include_play_bottom"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="50dp" />
The upper and lower columns need to be hidden when users watch the video. When users click the screen, two columns are displayed for users to use.
The timer is used to record the current time from the last time the user clicks the screen. If the video exceeds 3 seconds, the topic is hidden. If the video is clicked on the screen, it is restored, use Animation to hide and restore data.
timer = new Timer();
timerTask = new TimerTask() {
@Override
public void run() {
long t = System.currentTimeMillis();
if (t - time > 3000 && menu_visible) {
time = t;
handler.post(new Runnable() {
@Override
public void run() {
Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.move_bottom);
rl_bottom.startAnimation(animation);
Animation animation_top = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.move_top);
rl_top.startAnimation(animation_top);
menu_visible = false;
}
});
}
}
};
You also need to load the box, which is hidden in the video loading interface callback.
<ProgressBar
android:id="@+id/pb_loading"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:layout_marginTop="60dp"
android:indeterminate="false"
android:indeterminateDrawable="@drawable/video_loading"
android:padding="5dp" />
3. Playback implementation
Here I use an ijkplayer class encapsulated by another blogger.
Let's talk about the running process of this class.
Create a MediaPlayer and assign values to an interface class. The interface is exposed.
IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer ();
ijkMediaPlayer.native_setLogLevel (IjkMediaPlayer.IJK_LOG_DEBUG);
// // Enable hard decoding
ijkMediaPlayer.setOption (IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
mMediaPlayer = ijkMediaPlayer;
if (listener! = null) {
mMediaPlayer.setOnPreparedListener (listener);
mMediaPlayer.setOnInfoListener (listener);
mMediaPlayer.setOnSeekCompleteListener (listener);
mMediaPlayer.setOnBufferingUpdateListener (listener);
mMediaPlayer.setOnErrorListener (listener);
}
Set the playing source. The playing source can be the local video path, the network video url, the network RTMP streaming url, and the SurfaceView configuration information.
try {
mMediaPlayer.setDataSource (mPath);
} catch (IOException e) {
e.printStackTrace ();
}
// Set the view for mediaPlayer
mMediaPlayer.setDisplay (surfaceView.getHolder ());
mMediaPlayer.prepareAsync ();
Call the IMediaPlayer control functions to start playing.
public void start() {
if (mMediaPlayer != null) {
mMediaPlayer.start();
}
}
There is also lifecycle control for the activity, where native_profileEnd is equivalent to a smart pause, and continues to play the video when the screen is back.
@Override
protected void onStop() {
IjkMediaPlayer.native_profileEnd();
handler.removeCallbacksAndMessages(null);
super.onStop();
}
Stops Playing videos and releases resources when the Activity ends.
@Override
protected void onDestroy() {
if (ijkPlayer != null) {
ijkPlayer.stop();
ijkPlayer.release();
ijkPlayer = null;
}
super.onDestroy();
}
At last, there is a playback progress. Here, I use handler to call it and update the playback time display and progress bar cyclically.
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REFRESH:
if (ijkPlayer.isPlaying()) {
refresh();
handler.sendEmptyMessageDelayed(MSG_REFRESH, 1000);
}
break;
}
}
};
private void refresh() {
long current = ijkPlayer.getCurrentPosition() / 1000;
long duration = ijkPlayer.getDuration() / 1000;
Log.v("zzw", current + " " + duration);
long current_second = current % 60;
long current_minute = current / 60;
long total_second = duration % 60;
long total_minute = duration / 60;
String time = current_minute + ":" + current_second + "/" + total_minute + ":" + total_second;
tvTime.setText(time);
if(duration != 0){
seekBar.setProgress((int) (current * 100 / duration));
}
}
When you drag the progress bar, cancel the handler to send the message, and drag it to the end to update the playback progress.
seekBar.setOnSeekBarChangeListener (new SeekBar.OnSeekBarChangeListener () {
@Override
public void onProgressChanged (SeekBar seekBar, int i, boolean b) {
// progress changes
}
@Override
public void onStartTrackingTouch (SeekBar seekBar) {
// start dragging
handler.removeCallbacksAndMessages (null);
}
@Override
public void onStopTrackingTouch (SeekBar seekBar) {
// Stop dragging
ijkPlayer.seekTo (ijkPlayer.getDuration () * seekBar.getProgress () / 100);
handler.sendEmptyMessageDelayed (MSG_REFRESH, 100);
}
});
When playing a network video or a network RTMP streaming, you can only get the video duration and current time, but the pause and stop operations are still effective.
In addition, if you want to play the video again, you need to re-setVideoPath and start
View results
Local Video Playback
Play RTMP streaming
Play online videos
Ijkplayer does not seem easy to use, but it does not implement switching between a small window and a full screen ...... I'll take a look at ijkplayer in the next two days.