https://blog.csdn.net/fukaimei/article/details/80553709

前 言
ijkplayer框架是由B站在GitHub开源的一款比较好用的开源网络播放器框架,它能支持在Android、IOS等平台上编译移植使用。而且支持多种视频格式的播放,而且编码的速度比传统的开源网络播放器还要快。除此之外,ijkplayer框架支持网络视频播放时弹幕的推送等功能。

开发环境
Android Studio 3.1.2
JDK 1.8

开发前准备
在Android Studio新建的项目里引入ijkplayer框架(ijkplayer框架GitHub下载地址)作为依赖项,并在build.gradle(Module:app)引入文件。如下图所示。

implementation project(':ijkplayer-java')
1
在主项目的下\app\src\main\目录下新建一个jniLibs目录,并把ijkplayer框架需要支持的.so文件拷贝粘贴进去,如下图所示。

编码与实现
在Android Studio的\res\layout目录下新建一个activity_play.xml文件作为视频播放器的显示界面,布局代码如下。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_play"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black"
    android:gravity="center"
    android:keepScreenOn="true"
    tools:context=".player.PlayActivity">

<FrameLayout
        android:id="@+id/fl_surface_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

<com.fukaimei.cloudtv.widget.media.IjkVideoView
            android:id="@+id/video_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center" />

<RelativeLayout
            android:id="@+id/rl_loading_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

<TextView
                android:id="@+id/tv_loading_info"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/pb_loading"
                android:layout_centerInParent="true"
                android:layout_marginTop="@dimen/dimen_12dp"
                android:textColor="@color/white"
                android:textSize="@dimen/dimen_32sp" />

<!--android:indeterminate 表示不确定的进度-->
            <ProgressBar
                android:id="@+id/pb_loading"
                android:layout_width="@dimen/dimen_120dp"
                android:layout_height="@dimen/dimen_120dp"
                android:layout_centerInParent="true"
                android:layout_marginTop="@dimen/dimen_120dp"
                android:indeterminate="false"
                android:indeterminateDrawable="@drawable/video_loading"
                android:padding="@dimen/dimen_10dp" />

</RelativeLayout>

<TextView
            android:id="@+id/tv_horiontal_gesture"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:shadowColor="@color/black"
            android:shadowDx="1.0"
            android:shadowDy="1.0"
            android:textColor="@color/white"
            android:textSize="@dimen/dimen_64sp"
            android:textStyle="bold"
            android:visibility="gone" />

<TextView
            android:id="@+id/tv_vertical_gesture"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@drawable/black_bg"
            android:gravity="center_horizontal"
            android:paddingBottom="@dimen/dimen_40dp"
            android:paddingLeft="@dimen/dimen_100dp"
            android:paddingRight="@dimen/dimen_100dp"
            android:paddingTop="@dimen/dimen_40dp"
            android:textColor="@color/white"
            android:textSize="@dimen/dimen_64sp"
            android:textStyle="bold"
            android:visibility="gone" />

<FrameLayout
            android:id="@+id/fl_player_top_container"
            android:layout_width="match_parent"
            android:layout_height="@dimen/dimen_70dp"
            android:layout_gravity="top"
            android:background="@color/player_panel_background_color"
            android:paddingBottom="@dimen/dimen_10dp"
            android:paddingTop="@dimen/dimen_10dp">

<LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:orientation="horizontal">

<ImageView
                    android:id="@+id/iv_player_close"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:paddingLeft="@dimen/dimen_15dp"
                    android:paddingRight="@dimen/dimen_15dp"
                    android:src="@drawable/titlebar_return_white" />

<TextView
                    android:id="@+id/tv_player_video_name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:ellipsize="end"
                    android:singleLine="true"
                    android:textColor="@color/white"
                    android:textSize="@dimen/dimen_32sp" />

</LinearLayout>

<LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="right|center_vertical"
                android:orientation="horizontal">

<TextView
                    android:id="@+id/tv_sys_time"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:layout_marginRight="@dimen/dimen_10dp"
                    android:textColor="@color/white"
                    android:textSize="@dimen/dimen_32sp" />

<ImageView
                    android:id="@+id/iv_battery"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:layout_marginRight="@dimen/dimen_10dp" />

</LinearLayout>

</FrameLayout>

<ImageView
            android:id="@+id/iv_player_center_pause"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@drawable/player_pause_selector"
            android:visibility="gone" />

</FrameLayout>

<LinearLayout
        android:id="@+id/ll_player_bottom_layout"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dimen_70dp"
        android:layout_alignParentBottom="true"
        android:background="@color/player_panel_background_color"
        android:gravity="center"
        android:orientation="horizontal">

<CheckBox
            android:id="@+id/cb_play_pause"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/dimen_26dp"
            android:button="@drawable/player_playbtn_selector"
            android:checked="true" />

<ImageView
            android:id="@+id/iv_next_video"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/dimen_10dp"
            android:src="@drawable/panel_next_selector" />

<TextView
            android:id="@+id/tv_current_video_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:textColor="@color/white"
            android:textSize="@dimen/dimen_20sp" />

<SeekBar
            android:id="@+id/sb_player_seekbar"
            style="@style/playerSeekBarStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_weight="1.0"
            android:indeterminate="false"
            android:max="100"
            android:paddingLeft="@dimen/dimen_10dp"
            android:paddingRight="@dimen/dimen_10dp"
            android:progress="0"
            android:thumbOffset="@dimen/dimen_10dp" />

<TextView
            android:id="@+id/tv_total_video_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/dimen_10dp"
            android:textColor="@color/white"
            android:textSize="@dimen/dimen_20sp" />

<TextView
            android:id="@+id/tv_bitstream"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/dimen_10dp"
            android:layout_marginRight="@dimen/dimen_10dp"
            android:textColor="@color/white"
            android:textSize="@dimen/dimen_20sp" />

</LinearLayout>
</RelativeLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
在Android Studio的app\src\main\java\目录下新建一个PlayActivity,java文件作为处理视频播放器的逻辑代码,逻辑代码如下。

package com.fukaimei.cloudtv.player;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.preference.PreferenceManager;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.CheckBox;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;

import com.fukaimei.cloudtv.R;
import com.fukaimei.cloudtv.base.BaseActivity;
//import com.fukaimei.cloudtv.detail.AlbumDetailActivity;
//import com.fukaimei.cloudtv.model.sohu.Video;
import com.fukaimei.cloudtv.utils.DateUtils;
import com.fukaimei.cloudtv.utils.SysUtils;
import com.fukaimei.cloudtv.widget.media.IjkVideoView;

import java.text.NumberFormat;
import java.util.Formatter;
import java.util.Locale;

import tv.danmaku.ijk.media.player.IMediaPlayer;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;

public class PlayActivity extends BaseActivity implements GestureDetectorController.IGestureListener {

private static final String TAG = PlayActivity.class.getSimpleName();
    private static final int CHECK_TIME = 1;
    private static final int CHECK_BATTERY = 2;
    private static final int CHECK_PROGRESS = 3;
    private static final int AUTO_HIDE_TIME = 10000;
    private static final int AFTER_DRAGGLE_HIDE_TIME = 3000;
    private String mUrl;
    private int mStreamType;
    private int mCurrentPosition;
//    private Video mVideo;
    private IjkVideoView mVideoView;
    private RelativeLayout mLoadingLayout;
    private TextView mLoadingText;
    private FrameLayout mTopLayout;
    private LinearLayout mBottomLayout;
    private ImageView mBackButton;
    private TextView mVideoNameView;
    private TextView mSysTimeView;
    private ImageView mBigPauseButton;
    private CheckBox mPlayOrPauseButton;
    private TextView mVideoCurrentTime;
    private TextView mVideoTotalTime;
    private TextView mBitStreamView;
    private EventHandler mEventHandler;
    private boolean mIsPanelShowing = false;
    private int mBatteryLevel;
    private ImageView mBatteryView;
    private boolean mIsMove = false;//是否在屏幕上滑动
    private SeekBar mSeekBar;
    private Formatter mFormatter;
    private StringBuilder mFormatterBuilder;
    private boolean mIsDragging;
    private GestureDetectorController mGestureController;
    private TextView mDragHorizontalView;
    private TextView mDragVerticalView;
    private long mScrollProgress;
    private boolean mIsHorizontalScroll;
    private boolean mIsVerticalScroll;
    private int mCurrentLight;
    private int mMaxLight = 255;
    private int mCurrentVolume;
    private int mMaxVolume = 10;
    private AudioManager mAudioManager;
    private String mLiveTitle;//直播节目标题

@Override
    protected int getLayoutId() {
        return R.layout.activity_play;
    }

@Override
    protected void onResume() {
        super.onResume();
    }

@Override
    protected void onPause() {
        super.onPause();
        if (mBatteryReceiver != null) {
            unregisterReceiver(mBatteryReceiver);
            mBatteryReceiver = null;
        }
        //释放audiofocus
        mAudioManager.abandonAudioFocus(null);
    }

/**
     * 通过广播获取系统电量情况
     */
    private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            mBatteryLevel = intent.getIntExtra("level", 0);
            Log.d(TAG, ">> mBatteryReceiver onReceive mBatteryLevel=" + mBatteryLevel);
        }
    };

@Override
    public void onScrollStart(GestureDetectorController.ScrollType type) {
        mIsMove = true;
        switch (type) {
            case HORIZONTAL:
                mDragHorizontalView.setVisibility(View.VISIBLE);
                mScrollProgress = -1;
                mIsHorizontalScroll = true;//水平滑动标识
                break;
            case VERTICAL_LEFT:
                setComposeDrawableAndText(mDragVerticalView, R.drawable.ic_light, this);
                mDragVerticalView.setVisibility(View.VISIBLE);
                updateVerticalText(mCurrentLight, mMaxLight);
                mIsVerticalScroll = true;
                break;
            case VERTICAL_RIGH:
                if (mCurrentVolume > 0) {
                    setComposeDrawableAndText(mDragVerticalView, R.drawable.volume_normal, this);
                } else {
                    setComposeDrawableAndText(mDragVerticalView, R.drawable.volume_no, this);
                }
                mDragVerticalView.setVisibility(View.VISIBLE);
                updateVerticalText(mCurrentVolume, mMaxVolume);
                mIsVerticalScroll = true;
                break;
        }
    }

//用于组合图片及文字
    private void setComposeDrawableAndText(TextView textView, int drawableId, Context context) {
        Drawable drawable = context.getResources().getDrawable(drawableId);
        //这四个参数表示把drawable绘制在矩形区域
        drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
        //设置图片在文字的上方
        //The Drawables must already have had drawable.setBounds called.
        textView.setCompoundDrawables(null, drawable, null, null);
    }

//更新垂直方向上滑动时的百分比
    private void updateVerticalText(int current, int total) {
        NumberFormat formater = NumberFormat.getPercentInstance();
        formater.setMaximumFractionDigits(0);//设置整数部分允许最大小数位 66.5%->66%
        String percent = formater.format((double) (current) / (double) total);
        mDragVerticalView.setText(percent);
    }

//更新水平方向seek的进度, duration表示变化后的duration
    private void updateHorizontalText(long duration) {
        String text = stringForTime((int) duration) + "/" + stringForTime(mVideoView.getDuration());
        mDragHorizontalView.setText(text);
    }

// 更新进度
    @Override
    public void onScrollHorizontal(float x1, float x2) {
        int width = getResources().getDisplayMetrics().widthPixels;
        int MAX_SEEK_STEP = 300000;//最大滑动5分钟
        int offset = (int) (x2 / width * MAX_SEEK_STEP) + mVideoView.getCurrentPosition();
        long progress = Math.max(0, Math.min(mVideoView.getDuration(), offset));
        mScrollProgress = progress;
        updateHorizontalText(progress);
    }

@Override
    public void onScrollVerticalLeft(float y1, float y2) {
        int height = getResources().getDisplayMetrics().heightPixels;
        int offset = (int) (mMaxLight * y1) / height;
        if (Math.abs(offset) > 0) {
            mCurrentLight += offset;//得到变化后的亮度
            mCurrentLight = Math.max(0, Math.min(mMaxLight, mCurrentLight));
            // 更新系统亮度
            SysUtils.setBrightness(this, mCurrentLight);
            SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
            editor.putInt("shared_preferences_light", mCurrentLight);
            editor.commit();
            updateVerticalText(mCurrentLight, mMaxLight);
        }
    }

@Override
    public void onScrollVerticalRight(float y1, float y2) {
        int height = getResources().getDisplayMetrics().heightPixels;
        int offset = (int) (mMaxVolume * y1) / height;
        if (Math.abs(offset) > 0) {
            mCurrentVolume += offset;//得到变化后的声音
            mCurrentVolume = Math.max(0, Math.min(mMaxVolume, mCurrentVolume));
            // 更新系统声音
            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, mCurrentVolume / 10, 0);
            updateVerticalText(mCurrentVolume, mMaxVolume);
        }
    }

class EventHandler extends Handler {
        public EventHandler(Looper looper) {
            super(looper);
        }

@Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case CHECK_TIME:
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mSysTimeView.setText(DateUtils.getCurrentTime());
                        }
                    });
                    break;
                case CHECK_BATTERY:
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            setCurrentBattery();
                        }
                    });
                    break;
                case CHECK_PROGRESS:
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            long duration = mVideoView.getDuration();
                            long nowduration = (mSeekBar.getProgress() * duration) / 1000L;
                            mVideoCurrentTime.setText(stringForTime((int) nowduration));
                        }
                    });
                    break;
            }
        }
    }

@Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            if (mIsMove == false) {
                toggleTopAndBottomLayout();
            } else {
                mIsMove = false;
            }
            //水平方向,up时,seek到对应位置播放
            if (mIsHorizontalScroll) {
                mIsHorizontalScroll = false;
                mVideoView.seekTo((int) mScrollProgress);
                //一次down,up结束后mDragHorizontalView隐藏
                mDragHorizontalView.setVisibility(View.GONE);
            }
            if (mIsVerticalScroll) {
                mDragVerticalView.setVisibility(View.GONE);
                mIsVerticalScroll = false;
            }
        }
        return mGestureController.onTouchEvent(event);
    }

@Override
    protected void initView() {
        mUrl = getIntent().getStringExtra("url");
//        mUrl = "http://ivi.bupt.edu.cn/hls/cctv1.m3u8";
//        mLiveTitle = "CCTV-1综合";
        mLiveTitle = getIntent().getStringExtra("title");
        mStreamType = getIntent().getIntExtra("type", 0);
        mCurrentPosition = getIntent().getIntExtra("currentPosition", 0);
//        mVideo = getIntent().getParcelableExtra("video");
//        Log.d(TAG, ">> ulr " + mUrl + ", mStreamType " + mStreamType + ", mCurrentPosition " + mCurrentPosition);
//        Log.d(TAG, ">> video " + mVideo);
        mEventHandler = new EventHandler(Looper.myLooper());
        initAudio();
        initLight();
        initGesture();
        initTopAndBottomView();
        initCenterView();
        initListener();
        //init player
        mVideoView = bindViewId(R.id.video_view);
        IjkMediaPlayer.loadLibrariesOnce(null);
        IjkMediaPlayer.native_profileBegin("libijkplayer.so");
        mLoadingLayout = bindViewId(R.id.rl_loading_layout);
        mLoadingText = bindViewId(R.id.tv_loading_info);
        mLoadingText.setText("正在加载中...");
        mVideoView.setVideoURI(Uri.parse(mUrl));
        mVideoView.setOnPreparedListener(new IMediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(IMediaPlayer mp) {
                mVideoView.start();
            }
        });
        mVideoView.setOnInfoListener(new IMediaPlayer.OnInfoListener() {
            @Override
            public boolean onInfo(IMediaPlayer mp, int what, int extra) {
                switch (what) {
                    case IjkMediaPlayer.MEDIA_INFO_BUFFERING_START:
                        mLoadingLayout.setVisibility(View.VISIBLE);
                        break;
                    case IjkMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
                    case IjkMediaPlayer.MEDIA_INFO_BUFFERING_END:
                        mLoadingLayout.setVisibility(View.GONE);
                        break;
                }
                return false;
            }
        });
        registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
        toggleTopAndBottomLayout();
    }

private void initCenterView() {
        mDragHorizontalView = bindViewId(R.id.tv_horiontal_gesture);
        mDragVerticalView = bindViewId(R.id.tv_vertical_gesture);
    }

private void initAudio() {
        mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
        setVolumeControlStream(AudioManager.STREAM_MUSIC);
        mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
        mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) * 10;// 系统声音取值是0-10,*10为了和百分比相关
        mCurrentVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC) * 10;
    }

private void initLight() {
        mCurrentLight = SysUtils.getDefaultBrightness(this);
        if (mCurrentLight == -1) {//获取不到亮度sharedpreferences文件
            mCurrentLight = SysUtils.getBrightness(this);
        }
    }

private void initGesture() {
        mGestureController = new GestureDetectorController(this, this);
    }

private void initTopAndBottomView() {
        mTopLayout = bindViewId(R.id.fl_player_top_container);
        mBottomLayout = bindViewId(R.id.ll_player_bottom_layout);
        mBackButton = bindViewId(R.id.iv_player_close);//返回按钮
        mVideoNameView = bindViewId(R.id.tv_player_video_name);//video标题
        mBatteryView = bindViewId(R.id.iv_battery);
        mSysTimeView = bindViewId(R.id.tv_sys_time);//系统时间
        mBigPauseButton = bindViewId(R.id.iv_player_center_pause);//屏幕中央暂停按钮
        mPlayOrPauseButton = bindViewId(R.id.cb_play_pause);//底部播放暂停按钮
        mVideoCurrentTime = bindViewId(R.id.tv_current_video_time);//当前播放进度
        mVideoTotalTime = bindViewId(R.id.tv_total_video_time);//视频总时长
        mBitStreamView = bindViewId(R.id.tv_bitstream);//码流
        mSeekBar = bindViewId(R.id.sb_player_seekbar);
        mSeekBar.setMax(1000);
        mSeekBar.setOnSeekBarChangeListener(mSeekBarChangeListener);
        mFormatterBuilder = new StringBuilder();
        mFormatter = new Formatter(mFormatterBuilder, Locale.getDefault());
    }

private void initListener() {
        mBackButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        mBigPauseButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mVideoView.start();
                updatePlayPauseStatus(true);
            }
        });
        mPlayOrPauseButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handlePlayPause();
            }
        });
    }

private void toggleTopAndBottomLayout() {
        if (mIsPanelShowing) {
            hideTopAndBottomLayout();
        } else {
            showTopAndBottomLayout();
            //先显示,没有任何操作,就5s后隐藏
            mEventHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    hideTopAndBottomLayout();
                }
            }, AUTO_HIDE_TIME);
        }
    }

private void showTopAndBottomLayout() {
        mIsPanelShowing = true;
        mTopLayout.setVisibility(View.VISIBLE);
        mBottomLayout.setVisibility(View.VISIBLE);
        updateProgress();
        if (mEventHandler != null) {
            mEventHandler.removeMessages(CHECK_TIME);
            Message msg = mEventHandler.obtainMessage(CHECK_TIME);
            mEventHandler.sendMessage(msg);

mEventHandler.removeMessages(CHECK_BATTERY);
            Message batterymsg = mEventHandler.obtainMessage(CHECK_BATTERY);
            mEventHandler.sendMessage(batterymsg);

mEventHandler.removeMessages(CHECK_PROGRESS);
            Message progressmsg = mEventHandler.obtainMessage(CHECK_PROGRESS);
            mEventHandler.sendMessage(progressmsg);
        }
        switch (mStreamType) {
//            case AlbumDetailActivity.StreamType.SUPER:
//                mBitStreamView.setText(getResources().getString(R.string.stream_super));
//                break;
//            case AlbumDetailActivity.StreamType.NORMAL:
//                mBitStreamView.setText(getResources().getString(R.string.stream_normal));
//                break;
//            case AlbumDetailActivity.StreamType.HIGH:
//                mBitStreamView.setText(getResources().getString(R.string.stream_high));
//                break;
            default:
                break;
        }
    }

private void hideTopAndBottomLayout() {
        if (mIsDragging == true) {
            return;
        }
        mIsPanelShowing = false;
        mTopLayout.setVisibility(View.GONE);
        mBottomLayout.setVisibility(View.GONE);
    }

private void handlePlayPause() {
        //TODO
        if (mVideoView.isPlaying()) {//视频正在播放
            mVideoView.pause();
            updatePlayPauseStatus(false);
        } else {
            mVideoView.start();
            updatePlayPauseStatus(true);
        }
    }

private void updatePlayPauseStatus(boolean isPlaying) {
        mBigPauseButton.setVisibility(isPlaying ? View.GONE : View.VISIBLE);
        mPlayOrPauseButton.invalidate();
        mPlayOrPauseButton.setChecked(isPlaying);
        mPlayOrPauseButton.refreshDrawableState();
    }

@Override
    protected void initData() {
//        Log.d(TAG, ">> initData mVideo=" + mVideo);
//        if (mVideo != null) {
//            Log.d(TAG, ">> initData mVideoName" + mVideo.getVideoName());
//            mVideoNameView.setText(mVideo.getVideoName());
//        }
        if (mLiveTitle != null) {
            mVideoNameView.setText(mLiveTitle);
        }
    }

private void setCurrentBattery() {
        Log.d(TAG, ">> setCurrentBattery level " + mBatteryLevel);
        if (0 < mBatteryLevel && mBatteryLevel <= 10) {
            mBatteryView.setBackgroundResource(R.drawable.ic_battery_10);
        } else if (10 < mBatteryLevel && mBatteryLevel <= 20) {
            mBatteryView.setBackgroundResource(R.drawable.ic_battery_20);
        } else if (20 < mBatteryLevel && mBatteryLevel <= 50) {
            mBatteryView.setBackgroundResource(R.drawable.ic_battery_50);
        } else if (50 < mBatteryLevel && mBatteryLevel <= 80) {
            mBatteryView.setBackgroundResource(R.drawable.ic_battery_80);
        } else if (80 < mBatteryLevel && mBatteryLevel <= 100) {
            mBatteryView.setBackgroundResource(R.drawable.ic_battery_100);
        }
    }

@Override
    protected void onStop() {
        super.onStop();
        if (mVideoView != null) {
            mVideoView.stopPlayback();
        }
    }

private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
        // seekbar进度发生变化时回调
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            if (!fromUser) {
                return;
            }
            long duration = mVideoView.getDuration();//视频时长
            long nowPosition = (duration * progress) / 1000L;
            mVideoCurrentTime.setText(stringForTime((int) nowPosition));
        }

// seekbar开始拖动时回调
        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            mIsDragging = true;
        }

// seekbar拖动完成后回调
        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            mIsDragging = false;
            int progress = seekBar.getProgress();//最后拖动停止的进度
            long duration = mVideoView.getDuration();//视频时长
            long newPosition = (duration * progress) / 1000L;//当前的进度
            mVideoView.seekTo((int) newPosition);
            mEventHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    hideTopAndBottomLayout();
                }
            }, AFTER_DRAGGLE_HIDE_TIME);
        }
    };

private void updateProgress() {
        int currentPosition = mVideoView.getCurrentPosition();//当前的视频位置
        int duration = mVideoView.getDuration();//视频时长
        if (mSeekBar != null) {
            if (duration > 0) {
                //转成long型,避免溢出
                long pos = currentPosition * 1000L / duration;
                mSeekBar.setProgress((int) pos);
            }
            int perent = mVideoView.getBufferPercentage();//已经缓冲的进度
            mSeekBar.setSecondaryProgress(perent);//设置缓冲进度
            mVideoCurrentTime.setText(stringForTime(currentPosition));
            mVideoTotalTime.setText(stringForTime(duration));
        }
    }

private String stringForTime(int timeMs) {
        int totalSeconds = timeMs / 1000;
        int seconds = totalSeconds % 60; //换成秒
        int minutes = (totalSeconds / 60) % 60;
        int hours = (totalSeconds / 3600);
        mFormatterBuilder.setLength(0);
        if (hours > 0) {
            return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
        } else {
            return mFormatter.format("%02d:%02d", minutes, seconds).toString();
        }
    }

//从直播模块跳转过来
    public static void launch(Activity activity, String url, String title) {
        Intent intent = new Intent(activity, PlayActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intent.putExtra("url", url);
        intent.putExtra("title", title);
        activity.startActivity(intent);
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
在该文件的逻辑代码中onScrollStart()方法主要实现的是对一些手势在设备屏幕上滑动进行进行监听,比如在设备横屏的情况左下上下滑调节屏幕的亮度,右上下滑调节音量的大小;setComposeDrawableAndText()方法主要实现的是用于组合图片及文字;updateVerticalText()方法主要实现的是用于更新垂直方向上滑动时的百分比;onScrollHorizontal()方法主要实现的是更新播放视频的进度。

测试与运行截图

APK下载
apk Demo下载体验地址

————————————————
版权声明:本文为CSDN博主「_彼岸雨敲窗_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/fukaimei/article/details/80553709

Android开发-基于ijkplayer框架开发网络电视直播播放器的实现相关推荐

  1. 基于ijkplayer实现低延迟直播播放器

    文章目录 前言 rtmp产生延迟的原因 如何减少播放器播放延迟 追帧策略定义和工程实现细节 直播播放器追帧策略 基于ijkplayer[^1]的工程实现 总结 推荐免费直播学习课程: [c/c++Li ...

  2. [嵌入式Linux项目实战开发]基于QT4.7.4的音乐播放器实现与设计【2018年给力项目】

    [嵌入式Linux项目实战开发]基于QT4.7.4的音乐播放器实现与设计[2018年给力项目]是[创科之龙]团队aiku嵌入式视频教程系列制作的现有的音乐播放器. 主要功能实现: 1.新建工程,基类选 ...

  3. 基于ijkplayer封装的UE4安卓播放器插件

    基于ijkplayer封装的UE4安卓播放器插件 关于 ijkplayerUE4 相关的 Github 地址 使用方法 运行后的demo 关于 ijkplayerUE4 基于bilibili开源项目 ...

  4. GSYVideoPlayer(基于ijkplayer)之rtmp协议播放器的简单应用

    基于ijkplayer的GSYVideoPlayer rtmp协议播放器的简单应用 **添加依赖** **Manifest配置** **Layout布局** activity_start.xml ac ...

  5. 【基于Ijkplayer】安卓机顶盒电视播放器开发

    前言 Ijkplayer是B站开源的一款多媒体播放引擎,其基于ffmpeg开并支持很多的在线媒体播放格式.本文实现了在安卓TV上播放各大电视台的直播,其格式是.m3u8.当然了只要是编译的Ijkpla ...

  6. 基于Qt5GUI框架+SQLite的音乐播放器

    目录 音乐播放器 3 一.概述 3 主要内容: 3 已实现的目标: 3 二.主要类的设计 3 1)依次介绍各个主要类的设计: 3 2)综上所述,各个类之间的关系大致如下图所示: 6 三.程序的功能特点 ...

  7. 基于VUE框架的网页音乐播放器(可自适应手机布局)

    该项目是大三上学期学VUE课程老师带我们做的一个项目,整个布局使用VUE框架,界面简洁,功能简单.apI是使用网易云音乐的API. 一.项目展示 二.项目代码 我使用的软件是VScode,该项目的代码 ...

  8. 基于ArkUI框架开发——图片模糊处理的实现

    原文:基于ArkUI框架开发--图片模糊处理的实现,点击链接查看更多技术内容. 现在市面上有很多APP,都或多或少对图片有模糊上的设计,所以,图片模糊效果到底怎么实现的呢? 首先,我们来了解下模糊效果 ...

  9. 基于JFinal框架开发的企业办公系统-JFinalOA v1.1源码

    简介: JFinalOA 是基于 JFinal 框架开发的企业办公系统. 使用框架介绍: JFinal 4.6+enjoy模版引擎 Shiro控制权限 flowable流程引擎 BootStrap M ...

最新文章

  1. OpenCASCADE:读IGES
  2. 区块链技术解决物联网安全问题
  3. unity3d 大地图接壤_架空世界地图制作指南(六)气候带
  4. 解决opensips NAT 问题和ACK不能正常转发问题
  5. 终于圆了天文梦!马化腾称腾讯将发布探星计划 还提到了《王者荣耀》
  6. 【干货】史上最全的Tensorflow学习资源汇总(转)
  7. Java程序员要求具备的10项技能
  8. 浅谈数据中心白盒交换机开发
  9. 运气真不错:3月取到的TeaVM恰好能够运行,之前之后都有问题
  10. 我的世界服务器修改地图,《我的世界手机版》地图编辑器介绍 怎么修改地图信息...
  11. 软件模块划分(实现与管理)
  12. java excel 水印_Java 添加Excel水印
  13. GNSS/INS组合导航(六):惯性导航误差建模
  14. c语言printf分析,C语言 printf详解
  15. [发布] QQGame 连连看辅助工具(限制功能版)
  16. linux 删除swp文件,linux E325: 注意 发现交换文件 *.swp 解决方法
  17. 使用System.setOut()
  18. html组态插件_组态 web组态 插件 编辑器 使用说明书
  19. 高德地图轨迹回放、点的弹跳效果、浏览器环境监测、设置地图的主题样式、GPS坐标转为高德坐标、地图加载提示、地图DOM事件、修改图层等API接口
  20. Visual Studio Code安装教程(超详细)

热门文章

  1. 1亿妹纸大姨妈的神器美柚:上云要切合业务需求,更要货比三家
  2. 【七夕如何根据情侣倾听的音乐进行薅羊毛】背景音乐是否会影响情侣对酒的选择
  3. 有哪些强大好用的音频格式转换软件?
  4. 【活动报名】大数据的流向,究竟去向何处?——深圳站
  5. python语言中代码注释可以使用_以下选项中,Python语言中代码注释使用的符号是: ( )...
  6. 【Python入门教程】第15篇 if条件语句
  7. 人工智能行业调查研究报告(算法导论调查研究报告)
  8. 男脸型测试配发型软件,男士测脸型配发型app 百度拍照测脸型
  9. 【爆肝整理】现代网络安全基础术语词典,网络安全学习者必备
  10. 演讲比赛流程管理系统(C++)