修改ExoPlayer源码,获取帧时间

 

最近在研究google的ExoPlayer,根据项目需求,需要获得当前帧的显示时间,看源码发现解码在MediaCodecVideoRenderer这个类中执行解码,发现processOutputBuffer函数内有时间数据,根据测试知道presentationTimeUs是显示时间,然后就是想办法把时间给我们了

既然想改源码,那先下载源码,源码

新建个module,把core,dash,hls,smoothstreaming,ui文件夹内的代码和资源都复制到这个module内

新建个interface VideoTimeListener

public interface VideoTimeListener {
    void onVideoTimeChanged(long time);
}

修改MediaCodecVideoRenderer,添加一个VideoTimeListener和构造函数

private VideoTimeListener timeListener;
public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector,
                               long allowedJoiningTimeMs,
                               @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
                               boolean playClearSamplesWithoutKeys, @Nullable Handler eventHandler,
                               @Nullable VideoRendererEventListener eventListener,VideoTimeListener timeListener, int maxDroppedFramesToNotify) {
  super(C.TRACK_TYPE_VIDEO, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys);
  this.allowedJoiningTimeMs = allowedJoiningTimeMs;
  this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
  this.context = context.getApplicationContext();
  frameReleaseTimeHelper = new VideoFrameReleaseTimeHelper(context);
  eventDispatcher = new EventDispatcher(eventHandler, eventListener);
  deviceNeedsAutoFrcWorkaround = deviceNeedsAutoFrcWorkaround();
  pendingOutputStreamOffsetsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT];
  outputStreamOffsetUs = C.TIME_UNSET;
  joiningDeadlineMs = C.TIME_UNSET;
  currentWidth = Format.NO_VALUE;
  currentHeight = Format.NO_VALUE;
  currentPixelWidthHeightRatio = Format.NO_VALUE;
  pendingPixelWidthHeightRatio = Format.NO_VALUE;
  scalingMode = C.VIDEO_SCALING_MODE_DEFAULT;

  this.timeListener = timeListener;

  clearReportedVideoSize();
}

在renderOutputBuffer和renderOutputBufferV21内添加 

 

 

 

protected void renderOutputBuffer(MediaCodec codec, int index, long presentationTimeUs) {
  //...省略代码
  if(timeListener != null){
    timeListener.onVideoTimeChanged(presentationTimeUs/1000);
  }
}
@TargetApi(21)
protected void renderOutputBufferV21(
    MediaCodec codec, int index, long presentationTimeUs, long releaseTimeNs) {
  //...省略代码
  if(timeListener != null){
    timeListener.onVideoTimeChanged(presentationTimeUs/1000);
  }
}

修改RenderersFactory的createRenderers

Renderer[] createRenderers(Handler eventHandler,
                           VideoRendererEventListener videoRendererEventListener,
                           AudioRendererEventListener audioRendererEventListener,
                           VideoTimeListener videoTimeListener,TextOutput textRendererOutput,
                           MetadataOutput metadataRendererOutput);

修改DefaultRenderersFactory的createRenderers和buildVideoRenderers

@Override
public Renderer[] createRenderers(Handler eventHandler,
    VideoRendererEventListener videoRendererEventListener,
    AudioRendererEventListener audioRendererEventListener,
    VideoTimeListener videoTimeListener,
    TextOutput textRendererOutput, MetadataOutput metadataRendererOutput) {
  ArrayList<Renderer> renderersList = new ArrayList<>();
  buildVideoRenderers(context, drmSessionManager, allowedVideoJoiningTimeMs,
      eventHandler, videoRendererEventListener,videoTimeListener, extensionRendererMode, renderersList);
  //省略代码
  return renderersList.toArray(new Renderer[renderersList.size()]);
}

protected void buildVideoRenderers(Context context,
    @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
    long allowedVideoJoiningTimeMs, Handler eventHandler,
    VideoRendererEventListener eventListener,VideoTimeListener videoTimeListener, @ExtensionRendererMode int extensionRendererMode,
    ArrayList<Renderer> out) {
  out.add(new MediaCodecVideoRenderer(context, MediaCodecSelector.DEFAULT,
      allowedVideoJoiningTimeMs, drmSessionManager, false, eventHandler, eventListener,videoTimeListener,
      MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY));
  //省略代码
}

修改SimpleExoPlayer的构造函数

private final CopyOnWriteArraySet<VideoTimeListener> videoTimeListeners;
protected SimpleExoPlayer(
    RenderersFactory renderersFactory,
    TrackSelector trackSelector,
    LoadControl loadControl,
    Clock clock) {
  componentListener = new ComponentListener();
  videoListeners = new CopyOnWriteArraySet<>();
  textOutputs = new CopyOnWriteArraySet<>();
  metadataOutputs = new CopyOnWriteArraySet<>();
  videoDebugListeners = new CopyOnWriteArraySet<>();
  audioDebugListeners = new CopyOnWriteArraySet<>();
  videoTimeListeners = new CopyOnWriteArraySet<>();
  Looper eventLooper = Looper.myLooper() != null ? Looper.myLooper() : Looper.getMainLooper();
  Handler eventHandler = new Handler(eventLooper);
  renderers = renderersFactory.createRenderers(eventHandler, componentListener, componentListener,
      componentListener, componentListener,componentListener);
  //省略代码
}

在SimpleExoPlayer添加函数

public void addVideoTiemListener(VideoTimeListener listener){
  videoTimeListeners.add(listener);
}
public void removeVideoTiemListener(VideoTimeListener listener){
  videoTimeListeners.remove(listener);
}

修改ComponentListener

ComponentListener implements VideoRendererEventListener,
    AudioRendererEventListener, TextOutput, MetadataOutput, SurfaceHolder.Callback,
    TextureView.SurfaceTextureListener,VideoTimeListener
@Override
public void onVideoTimeChanged(long time) {
  for (VideoTimeListener videoTimeListener : videoTimeListeners) {
    videoTimeListener.onVideoTimeChanged(time);
  }
}

好了,准备工作完成,在exoplayer初始化的时候

player.addVideoTiemListener(new VideoTimeListener() {
    @Override
    public void onVideoTimeChanged(long time) {
        videoTime = time;
    }
});

经过和ffmpeg解码出来的数据对比

exoplayer数据

ffmpeg

例子代码

百度云

密码:addl

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值