Files
ux/android/ffmpeg/ffmpeg_jni.cc
agra dc47fc0159 video: drain libavcodec's reorder buffer at end-of-stream
Closes H1 from the pre-ship review (the known-limit doc note added in
c0d55ba). The previous workaround was "first play-through truncates
the last ~16 frames; replay is fine because flush_buffers clears
libavcodec." That trade-off was OK for shipping but the proper fix
is to drain the reorder buffer before propagating EOS to ExoPlayer.

Media3's SimpleDecoder short-circuits the end-of-stream input buffer
and never invokes the subclass's decode(), so there's no hook to send
avcodec_send_packet(NULL). Every override worth overriding (decode
loop, queue methods, flush) is final on SimpleDecoder. So we
vendor a copy as FfmpegSimpleDecoder (Apache 2.0 attribution at the
top of the file) with one structural change: an EOS-drain state. On
EOS input, signalEndOfInput() flushes libavcodec's reorder queue,
then drainAtEndOfStream() is called on successive output buffers
until it reports DRAIN_DONE — at which point the loop attaches
BUFFER_FLAG_END_OF_STREAM and resumes normal teardown.

Everything else mirrors SimpleDecoder verbatim so upstream
improvements are cheap to pull forward.

  - FfmpegSimpleDecoder.java: vendored base class.
  - ffmpegVideoSignalEos JNI: sends avcodec_send_packet(NULL).
  - FfmpegVideoDecoder: extends the new base; signalEndOfInput
    forwards to the JNI; drainAtEndOfStream re-uses the existing
    ffmpegVideoReceiveFrame so per-frame PTS recovery and the
    pending_frame path from c0d55ba continue to work during drain.
2026-05-29 07:45:48 +03:00

17 KiB