Modify ExoPlayer source code to get frame time

Recently, I was researching google's ExoPlayer. According to the project requirements, it is necessary to obtain the display time of the current frame. Looking at the source code, I found that decoding is performed in the MediaCodecVideoRenderer class. I found that there is time data in the processOutputBuffer function. According to the test, I know that presentationTimeUs is the display time, and then I want to way to give us time
Since you want to change the source code, first download the source code, the source code
Create a new module and copy the code and resources in the core, dash, hls, smoothstreaming, and ui folders to this module
Create a new interface VideoTimeListener
public interface VideoTimeListener {
    void onVideoTimeChanged(long time);
}
Modify MediaCodecVideoRenderer, add a VideoTimeListener and constructor
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();
}

  
Added inside renderOutputBuffer and 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





Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325801915&siteId=291194637