Android audio and video went deep into 1949th using ijkplayer as a video player (with source code download) and androiw.player

Source: Internet
Author: User

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.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.