对于很多初次尝试播放器的同学而言,在完成基本的开发的下一步,是需要对整个播放状况有个初步的认识,其中需要涉及到埋点设计和实现,因此这一块,对于新手而言是非常有难度的。
之前写过文章 基于 Android EXOPlayer 创建视频播放器 介绍过 ExoPlayer。它是谷歌开源的一款播放器,目前用于 YouTube 生产线,我推荐新手区学习它的原因,它整体包很小,里面有很多不错的实现帮助我们去理解播放最基本的事情。当然如果在生产线,还需要结合自己的实际情况取舍,可以参考 Ijkplayer、ExoPlayer、VLC播放器综合比较 的对比,再做实际选择,这里从 ExoPlayer 为基础,分析整个如何确保我们播放体验(QoE)文档。
接入 AnalyticsListener
AnalyticsListener
是 Exoplayer 里面实现的一个接口,用于使用该播放器的开发同学方便的进行播放指标相关的统计。
class VideoQoEListener() : AnalyticsListener {
override fun onRenderedFirstFrame(eventTime: AnalyticsListener.EventTime, surface: Surface?) {
// Add Your Code to Send First Rendered Time
}
// ...
}
val videoQoEListener = VideoQoEListener()
// exoplayer instance
player.addAnalyticsListener(videoQoEListener)
AnalyticsListener 常用指标说明
AnalyticsListener 提供了非常多的方法方便开发者进行调用,你可以去 官方文档 查看具体的含义,这里罗列一些非常有用的方法。
onMetadata
@Override
public void onMetadata(EventTime eventTime, Metadata metadata) {
// TODO Handle Some Video MetaData
}
onMetadata
是一个非常重要的监听函数,你可以通过该方法判断视屏元信息的获取,并且拿到一些和视频 Header 相关的信息。
onVolumeChanged
@Override
public void onVolumeChanged(EventTime eventTime, float volume) {
// 比较简单用于监听音量变化
}
onRenderedFirstFrame
@Override
public void onRenderedFirstFrame(EventTime eventTime, @Nullable Surface surface) {
// TODO
}
顾名思义,表示第一帧解码完成,经常性的用于我们统计视频的起播时间。
onDroppedVideoFrames
@Override
public void onDroppedVideoFrames(EventTime eventTime, int droppedFrames, long elapsedMs) {
// TODO
}
onDroppedVideoFrames
也非常有意义,可以用于我们出现的一些音画同步的现象上报。
onVideoSizeChanged
@Override
public void onVideoSizeChanged(EventTime eventTime, int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
// TODO
}
这个比较好理解,主要用于 UI 的一些监听,当视频 PlayerView 发送改变后触发。
onBandwidthEstimate
@Override
public void onBandwidthEstimate(EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate) {
Log.e(TAG, "onBandwidthEstimate: 带宽估计 总加载时间"+totalLoadTimeMs+" 已加载的字节总数"+totalBytesLoaded +"应该是网速"+bitrateEstimate/(1024*1024));
}
onBandwidthEstimate
也是非常有效的一个手段,用于检测用户的网络状况,你可以非常便捷的上报用户的宽带速度预估情况。
onSeekStarted 和 onSeekProcessed
@Override
public void onSeekStarted(EventTime eventTime) {
Log.e(TAG, "onSeekStarted:开始seek " );
}
@Override
public void onSeekProcessed(EventTime eventTime) {
Log.e(TAG, "onSeekProcessed: seek 处理" );
}
onSeekStarted
和 onSeekProcessed
用于用户触发 Seek 操作的监听。
onLoadStarted 与 onLoadCompleted
@Override
public void onLoadStarted(EventTime eventTime, MediaSourceEventListener.LoadEventInfo loadEventInfo, MediaSourceEventListener.MediaLoadData mediaLoadData) {
// showLoading();
}
@Override
public void onLoadCompleted(EventTime eventTime, MediaSourceEventListener.LoadEventInfo loadEventInfo, MediaSourceEventListener.MediaLoadData mediaLoadData) {
// dissmissLoading();
}
我们监听 Streaming 一个重要目标就是能够知道用户数目时候产生了卡顿,而网络卡顿更是最为常见的一种,因此我们需要知道什么时候视频触发了数据加载,以及加载完成耗时多少,因此 onLoadStarted
和 onLoadCompleted
也经常会被用来设计卡顿监听的重要方法。
onDecoderEnabled
@Override
public void onDecoderEnabled(EventTime eventTime, int trackType, DecoderCounters decoderCounters) {
// TODO 当解码器就绪
}
onDecoderEnabled 一般可以用来判断对当前视屏编码的支持力度,如果不支持当前格式,改周期函数是不会触发的。
前文提到的一些都是初入播放器大家比较关心的一些性能指标接口方法,实际如果我们从事 QoE 的设计时候,还需要更多细节化的考虑,从用户侧的埋点,到数据搜集后的分析都有大量工作要做 。这里强烈推荐 media-analytics-player-plug-in-data-reference-guide 里面涵盖了基本的 QoE 指标以及具体含义。