Android视频直播、点播播放器哪家强?

10e*)

echo “IJK_NDK_REL= I J K N D K R E L " c a s e " IJK_NDK_REL" case " IJKNDKREL"case"IJK_NDK_REL” in
11*|12*|13*|14*)
if test -d A N D R O I D N D K / t o o l c h a i n s / a r m − l i n u x − a n d r o i d e a b i − 4.9 t h e n e c h o " N D K r {ANDROID_NDK}/toolchains/arm-linux-androideabi-4.9 then echo "NDKr ANDROIDNDK/toolchains/armlinuxandroideabi4.9thenecho"NDKrIJK_NDK_REL detected"
else
echo “You need the NDKr10e or later”
exit 1
fi
;;
*)
echo “You need the NDKr10e or later”
exit 1
;;
esac
;;
esac

可以看出来这里只支持10e,11,12,13,14,所以ndk版本低了不行,高了也不行,没办法,我们得去重新去官网下载低一点的版本,如r14b。

4.配置SDK和NDK路径

找到/home/(用户名)/目录,使用快捷键Ctrl + H显示隐藏文件,找到.bashrc文件打开,配置自己的SDK和NDK路径,例如:

export ANDROID_NDK=/home/leon/Android/andriod-ndk-r14b
export ANDROID_SDK=/home/leon/Android/Sdk
export PATH= A N D R O I D N D K : ANDROID_NDK: ANDROIDNDK:ANDROID_SDK:$PATH

配置完成后,重启命令行,输入ndk-build命令,如果不报命令行找不到,说明NDK环境变量配置成功。

编译IjkPlayer

Android环境搭建好后,就可以参考官方文档着手编译ijkplayer了。

sudo apt-get update
sudo apt-get install git //安装git
sudo apt-get install yasm //安装yasm

sudo dpkg-reconfigure dash //在弹出提示框选择“否”来使用bash

//下载ijkplayer到ijkplayer-android目录
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android
cd ijkplayer-android

//使用默认配置
cd config
rm module.sh
ln -s module-lite.sh module.sh

cd …
cd android/contrib
./compile-ffmpeg.sh clean //清理

cd ~/ijkplayer-android //返回源码根目录
./init-android.sh //主要是去下载ffmpeg

cd android/contrib
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all //编译ffmpeg,all是全部编译,需要等待一段时间

cd … //回到ijkplayer-android/android
./compile-ijk.sh all //编译ijkplayer

编译完成后,在android/ijkplayer目录下各个库模块当中找到生成的so库:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

既然so库已经生成,就可以使用Andorid Studio再次打开ijkplayer中的安卓示例项目(android/ijkplayer),运行后就可以播放示例视频了。这个带有so库的示例项目我已上传到Github,地址为github.com/uncleleonfa…,欢迎下载。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PLDroidPlayer

PLDroidPlayer 是七牛推出的一款适用于 Android 平台的播放器 SDK,采用全自研的跨平台播放内核,拥有丰富的功能和优异的性能,可高度定制化和二次开发。示例项目地址为:github.com/pili-engine…
PLDroidPlayer的集成要比ijkPlayer简单很多,不用自己编译so库,不用自己创建SurfaceView和TextureView来播放视频。可参考官方开发指南集成即可。

测试开发

为了保证测试的变量只是播放器引擎本身(这里暂时将播放器引擎简单的理解为各个播放器的MediaPlayer),我们定义一个公共的UI界面即VideoView来播放视频流,然后通过代理模式去代理不同的播放器引擎。这样VideoView在播放视频时,可以通过代理使用不同的播放引擎(MediaPlayer)来播放。我们这里主要测试播放器播放视频首开的时间,播放器播放视频过程中Cpu,内存的占用情况。测试项目地址为:github.com/uncleleonfa…,测试项目运行效果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

IMediaPlayer

定义统一的MediaPlayer接口。

public interface IMediaPlayer {

void prepareAsync() throws IllegalStateException;

void start() throws IllegalStateException;

void stop() throws IllegalStateException;

void pause() throws IllegalStateException;

void release();

void reset();


}

IMeidaPlayerProxy

定义MeidaPlayer的代理接口,所有MediaPlayer的代理必须实现newInstance接口创建MediaPlayer。

interface IMediaPlayerProxy {
IMediaPlayer newInstance();
}

IjkPlayer的MediaPlayer的代理

在使用IjkPlayer之前需要添加依赖,并且将编译好的so库添加到项目中的jniLibs下。

//添加ijkplayer依赖
dependencies {
compile ‘tv.danmaku.ijk.media:ijkplayer-java:0.8.4’
compile ‘tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4’
compile ‘tv.danmaku.ijk.media:ijkplayer-x86:0.8.4’

}

//IjkMediaPlayer代理,实现IMediaPlayer接口
public class IjkMediaPlayerProxy implements IMediaPlayerProxy, IMediaPlayer {

//声明一个IjkMediaPlayer对象
private IjkMediaPlayer mIjkMediaPlayer;

@Override
public IMediaPlayer newInstance() {
//创建IjkMeidaPlayer对象
mIjkMediaPlayer = new IjkMediaPlayer();
return this;
}

@Override
public void prepareAsync() throws IllegalStateException {
mIjkMediaPlayer.prepareAsync();
}

@Override
public void start() throws IllegalStateException {
mIjkMediaPlayer.start();
}

@Override
public void stop() throws IllegalStateException {
mIjkMediaPlayer.stop();
}

}

PLDroidPlayer的MediaPlayer代理

在使用PLMediaPlayer之前参考官方文档集成PLDroidPlayer

//PLMediaPlayer代理,实现IMediaPlayer接口
public class PLMediaPlayerProxy implements IMediaPlayerProxy, IMediaPlayer {

//定义PLMediaPlayer对象
private PLMediaPlayer mMediaPlayer;
//AVOptions为MediaPlayer的选项配置,例如可以配置开启硬解码
private AVOptions mAvOptions;

@Override
public IMediaPlayer newInstance() {
//创建PLDroidPlayer的PLMediaPlayer对象
mMediaPlayer = new PLMediaPlayer(mContext, mAvOptions);
return this;
}

@Override
public void prepareAsync() throws IllegalStateException {
mMediaPlayer.prepareAsync();
}

@Override
public void start() throws IllegalStateException {
mMediaPlayer.start();
}

@Override
public void stop() throws IllegalStateException {
mMediaPlayer.stop();
}


}

VideoView

VideoView仿照原生VideoView的实现,这里主要修改的是MediaPlayer的逻辑,方便配置使用不同播放器的MediaPlayer。

public class VideoView extends SurfaceView implements IMediaPlayer.OnPreparedListener,
IMediaPlayer.OnErrorListener,
IMediaPlayer.OnCompletionListener,
IMediaPlayer.OnInfoListener,
IMediaPlayer.OnVideoSizeChangeListener{

//定义MediaPlayer代理
private IMediaPlayerProxy mMediaPlayerProxy;

//定义VideoView使用的MediaPlayer
private IMediaPlayer mMediaPlayer;

//设置MediaPlayer的代理
public void setMediaPlayerProxy(IMediaPlayerProxy mediaPlayerProxy) {
mMediaPlayerProxy = mediaPlayerProxy;
}

//打开视频
private void openVideo() {
if (mVideoPath == null) {
return;
}
release();
//使用代理创建对应的MediaPlayer对象
mMediaPlayer = mMediaPlayerProxy.newInstance();
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.setDisplay(mSurfaceHolder);
mMediaPlayer.setLogEnabled(BuildConfig.DEBUG);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setOnInfoListener(this);
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.setOnErrorListener(this);
mMediaPlayer.setOnVideoSizeChangeListener(this);
try {
mMediaPlayer.setDataSource(mVideoPath);

mMediaPlayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
}

@Override
public void onPrepared(IMediaPlayer iMediaPlayer) {
iMediaPlayer.start();//开始播放
}
}

LogUtils

LogUtils用于采样cpu和内存数据,里面使用ScheduledThreadPoolExecutor每隔1s采样一次数据。

//开始采样
public void start() {
scheduler.scheduleWithFixedDelay(new SampleTask(), 0L, 1000L, TimeUnit.MILLISECONDS);
}
//停止采样
public void stop() {
scheduler.shutdown();
}

//采样任务
private class SampleTask implements Runnable {

@Override
public void run() {
float cpu = sampleCPU(); //采样CPU使用
float mem = sampleMemory(); //采样内存使用
}
}

LogView

LogView是打印Log的自定义控件,它由一个TextView和ScrollView组成,TextView在ScrollView内部,用来显示log,ScrollView用来滚动。

public class LogView extends RelativeLayout {

public LogView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.view_log, this);

final TextView textView = findViewById(R.id.tv);
final ScrollView scrollView = findViewById(R.id.scroll_view);
final StringBuilder stringBuilder = new StringBuilder();

//监听LogUtils的log
LogUtils.getInstance().setOnUpdateLogListener(new LogUtils.OnUpdateLogListener() {
@Override
public void onUpdate(final long timestamp, final String msg) {
//在主线程刷新界面
post(new Runnable() {
@Override
public void run() {
String dateString = mSimpleDateFormat.format(new Date(timestamp));
String log = dateString + ": " + msg + “\n”;
//添加一行log
stringBuilder.append(log);
//设置log显示
textView.setText(stringBuilder.toString());
//滚动ScrollView到底部
scrollView.fullScroll(View.FOCUS_DOWN);
}
});

}
});
}

}

测试

测试视频流是:

//点播MP4视频
String path = “http://hc.yinyuetai.com/uploads/videos/common/2B40015FD4683805AAD2D7D35A80F606.mp4?sc=364e86c8a7f42de3&br=783&rd=Android”;
//HLS直播流
String path = “http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8”;

在VieoView中,MediaPlayer开始准备播放之前,初始化LogUtils,埋点记录MediaPlayer的准备时间。

try {
//设置视频源
mMediaPlayer.setDataSource(mVideoPath);
//初始化LogUtils
LogUtils.getInstance().init(getContext());
//记录开始准备时间
LogUtils.getInstance().onStartPrepare();
mMediaPlayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}

当MediaPlayer准备好后,会回调onPrepared,再次记录准备结束时间,这样,准备结束时间减去准备开始时间就是MediaPlayer准备耗时,即我们的首开时间。

//准备好后的回调
@Override
public void onPrepared(IMediaPlayer iMediaPlayer) {
//记录准备结束时间
LogUtils.getInstance().onEndPrepare();
//开始播放
iMediaPlayer.start();
//开始每隔1s采样,播放结束后停止采样,主要用于点播采样
LogUtils.getInstance().start();

//开始每隔1s采样,采样5min,5min之后,自行停止,主要用于直播采样
//LogUtils.getInstance().startForDuration(5);
}

//播放结束
@Override
public void onCompletion(IMediaPlayer iMediaPlayer) {
//播放结束,停止采样
LogUtils.getInstance().stop();
}

测试IjkPlayer

创建一个IjkPlayerActivity使用IjkMediaPlayer来播放视频。

public class IjkPlayerActivity extends AppCompatActivity{

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ijkplayer);

//初始化IjkPlayer
IjkMediaPlayer.loadLibrariesOnce(null);
IjkMediaPlayer.native_profileBegin(“libijkplayer.so”);

VideoView videoView = findViewById(R.id.video_view);
//设置IjkMediaPlayer代理
videoView.setMediaPlayerProxy(new IjkMediaPlayerProxy());
String path = “视频url”
//设置视频url
videoView.setVideoPath(path);
}

@Override
protected void onStop() {
super.onStop();
//通知IjkMediaPlayer结束
IjkMediaPlayer.native_profileEnd();
}

}

另外,在VideoView初始化MediaPlayer时,可以调用enableMediaCodec()来开启IjkPlayer的硬解码:

private void openVideo() {

mMediaPlayer.enableMediaCodec();
}

测试PLDroidPlayer

创建一个PLDroidPlayerActivity使用PLMediaPlayer来播放视频。

public class PLDroidPlayerActivity extends AppCompatActivity{

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pldroid);

VideoView mVideoView = findViewById(R.id.video_view);

//配置AVoptions来开启硬编码,默认为软编码
AVOptions avOptions = new AVOptions();
avOptions.setInteger(AVOptions.KEY_MEDIACODEC, AVOptions.MEDIA_CODEC_HW_DECODE);

mVideoView.setMediaPlayerProxy(new PLMediaPlayerProxy(this, avOptions));
String path = “视频url”;
mVideoView.setVideoPath(path);
}

}

测试结果

Round 1

  • 机型:Moto G (2代)
  • 系统版本:5.1
  • 数据源:String path = “ivi.bupt.edu.cn/hls/cctv1hd…”;
  • 软硬编码:软解码
  • 采样时长:5min
  • IjkPlayer版本:0.8.4

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

[外链图片转存中…(img-g2SnFUnG-1715488481879)]

[外链图片转存中…(img-yvZzKxxq-1715488481880)]

[外链图片转存中…(img-QYDCHnhz-1715488481882)]

[外链图片转存中…(img-HVnj7oZX-1715488481884)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 27
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
视频点播软件 AppWizard has created this EtVod application for you. This application not only demonstrates the basics of using the Microsoft Foundation classes but is also a starting point for writing your application. This file contains a summary of what you will find in each of the files that make up your EtVod application. EtVod.dsp This file (the project file) contains information at the project level and is used to build a single project or subproject. Other users can share the project (.dsp) file, but they should export the makefiles locally. EtVod.h This is the main header file for the application. It includes other project specific headers (including Resource.h) and declares the CEtVodApp application class. EtVod.cpp This is the main application source file that contains the application class CEtVodApp. EtVod.rc This is a listing of all of the Microsoft Windows resources that the program uses. It includes the icons, bitmaps, and cursors that are stored in the RES subdirectory. This file can be directly edited in Microsoft Visual C++. EtVod.clw This file contains information used by ClassWizard to edit existing classes or add new classes. ClassWizard also uses this file to store information needed to create and edit message maps and dialog data maps and to create prototype member functions. resEtVod.ico This is an icon file, which is used as the application s icon. This icon is included by the main resource file EtVod.rc. resEtVod.rc2 This file contains resources that are not edited by Microsoft Visual C++. You should place all resources not editable by the resource editor in this file.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值