根据项目需要实现这个功能,所以又开始改exoplayer源码了。我以前也改过修改ExoPlayer源码,获取帧时间,现在我要在这个的基础上进行修改
修改VideoTimeListener.java,添加新的回调函数
public interface VideoTimeListener {
void onVideoTimeChanged(long time);
Surface onSurface(Surface surface);
void onSizeChanged(int width,int height);
void onRelease();
void onStart();
void onStop();
}
接下来修改SimpleExoPlayer.java的ComponentListener内代码,添加上边的函数
@Override
public Surface onSurface(Surface surface) {
for (VideoTimeListener videoTimeListener : videoTimeListeners) {
return videoTimeListener.onSurface(surface);
}
return surface;
}
@Override
public void onSizeChanged(int width, int height) {
for (VideoTimeListener videoTimeListener : videoTimeListeners) {
videoTimeListener.onSizeChanged(width,height);
}
}
@Override
public void onRelease() {
for (VideoTimeListener videoTimeListener : videoTimeListeners) {
videoTimeListener.onRelease();
}
}
@Override
public void onStart() {
for (VideoTimeListener videoTimeListener : videoTimeListeners) {
videoTimeListener.onStart();
}
}
@Override
public void onStop() {
for (VideoTimeListener videoTimeListener : videoTimeListeners) {
videoTimeListener.onStop();
}
}
好了,这样就可以监听exoplayer的解码线程的生命周期了,exoplayer的解码线程我没找到,不过找到了解码调用的类MediaCodecVideoRenderer.java
下面要添加代码的函数都在MediaCodecVideoRenderer.java内
先在setSurface(Surface surface)内添加代码
private void setSurface(Surface surface) throws ExoPlaybackException {
Surface s = null;
if(timeListener != null){
s = timeListener.onSurface(surface);
}
if(s != null){
surface = s;
}
//省略代码
}
在configureCodec(MediaCodecInfo codecInfo, MediaCodec codec, Format format,MediaCrypto crypto)内添加代码
@Override
protected void configureCodec(MediaCodecInfo codecInfo, MediaCodec codec, Format format,
MediaCrypto crypto) throws DecoderQueryException {
//省略代码
if(timeListener != null){
timeListener.onSizeChanged(mediaFormat.getInteger(MediaFormat.KEY_WIDTH),mediaFormat.getInteger(MediaFormat.KEY_HEIGHT));
}
codec.configure(mediaFormat, surface, crypto, 0);
if (Util.SDK_INT >= 23 && tunneling) {
tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec);
}
}
这里要注意,正常情况下configureCodec比setSurface先运行,可是我在debug模式下,没打断点的时候是setSurface比configureCodec先运行
在onStarted()和onStopped()内添加代码,这样就可以监听开始播放和停止播放了,需要注意的是在播放时候seekTo会调用onStarted和onStopped,所以要回调的地方判断一下
@Override
protected void onStarted() {
super.onStarted();
droppedFrames = 0;
droppedFrameAccumulationStartTimeMs = SystemClock.elapsedRealtime();
lastRenderTimeUs = SystemClock.elapsedRealtime() * 1000;
if(timeListener != null){
timeListener.onStart();
}
}
@Override
protected void onStopped() {
joiningDeadlineMs = C.TIME_UNSET;
maybeNotifyDroppedFrames();
super.onStopped();
if(timeListener != null){
timeListener.onStop();
}
}
在onDisabled()内添加代码
@Override
protected void onDisabled() {
if (timeListener != null) {
timeListener.onRelease();
}
//省略代码
}
添加属性
private long timeUsIndex;
private long timeIndex;
private long timeUs;
在上面的configureCodec函数内初始化
timeUsIndex = timeIndex = 0;
将在renderOutputBufferV21和renderOutputBuffer内获取帧时间的代码删掉,改成
timeUsIndex++;
timeUs = presentationTimeUs;
重写render(long positionUs, long elapsedRealtimeUs)函数,这个函数是MediaCodecVideoRenderer的父类的,他会每隔几毫秒调用一次,就算不解码也会调用,用它来进行渲染
@Override
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
while (timeIndex < timeUsIndex){
timeIndex++;
if(surface != null && timeListener != null && timeIndex == timeUsIndex){
timeListener.onVideoTimeChanged(timeUs/1000);
}
}
super.render(positionUs, elapsedRealtimeUs);
}
大致就这样
基于这篇写的全景播放器