-
Notifications
You must be signed in to change notification settings - Fork 121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[android] Refine video decoder for tunnel mode #1835
Conversation
Codecov Report
@@ Coverage Diff @@
## main #1835 +/- ##
==========================================
+ Coverage 57.57% 57.80% +0.22%
==========================================
Files 1906 1915 +9
Lines 94789 95191 +402
==========================================
+ Hits 54573 55023 +450
+ Misses 40216 40168 -48 |
017e57b
to
6630398
Compare
starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
Show resolved
Hide resolved
@@ -26,7 +26,7 @@ namespace shared { | |||
|
|||
namespace { | |||
|
|||
const SbTimeMonotonic kBufferTooLateThreshold = -32 * kSbTimeMillisecond; | |||
const SbTimeMonotonic kBufferTooLateThreshold = -16 * kSbTimeMillisecond; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also used for non-tunneled playback, and is probably carefully tuned. What's the implications for non-tunneled playback if it's reduced?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think 32ms is a too large tolerance for dropped frames. But as it's carefully tuned, I changed it back to 32ms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's ok to modify it with a fallback plan (i.e. if this causes issues in production, we'll revert the behavior from the backend).
@@ -107,8 +107,10 @@ void VideoRenderAlgorithm::Render( | |||
frames->pop_front(); | |||
++dropped_frames_; | |||
} else if (early_us < kBufferReadyThreshold) { | |||
auto status = draw_frame_cb(frames->front(), adjusted_release_time_ns); | |||
SB_DCHECK(status == VideoRendererSink::kReleased); | |||
if (!video_decoder_->IsTunnelMode()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems to me that what the algorithm for non-tunneled mode does is:
- If the frame arrives too late (16 or 32 ms later than the time it should be displayed), we drop it.
- Else if the frame should be rendered in the next 50 ms, we display it.
- Else do nothing.
What do we want for tunnel mode frames? Will we get the same accuracy after tick interval is reduced to 10ms?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides prerolling and dropped frame calculation, calling sink_->Render()
is to pop out cached frames, so renderer would ask for new video frames. It's ok to reduce the tick interval to 10ms and I have reduced it in the latest patch.
5c92f07
to
95ccd7a
Compare
1. Send placeholder frames to video renderer in tunnel mode. 2. Calculate dropped frames based on the placeholder frames. 3. Determing preroll status based on the placeholder frames. 4. Add OnFirstTunnelFrameReadyListener. 5. Remove video frame tracker as it's no longer needed. b/175890319 b/175888740 b/302198176 b/253469969
95ccd7a
to
81ecfbd
Compare
} | ||
}; | ||
mMediaCodec.setOnFrameRenderedListener(mTunnelModeFrameRendererListener, null); | ||
// TODO (b/306236129): disable the listeners as frames to be discarded would invoke the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are not implementing BUFFER_FLAG_DECODE_ONLY now, do we still need to remove the two listeners here?
Also nit:
- Remove the space after TODO
- Refine the commit message mentioning that OnFirstTunnelFrameReadyListener is commented out.
mMediaCodec.setOnFrameRenderedListener(null, null); | ||
mMediaCodec.setOnFirstTunnelFrameReadyListener(null, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's also comment them out, since the setting of them are commented out. Also, if we are going to set the callback to null, we should set variables like mTunnelModeFrameRendererListener to null too.
@@ -1304,6 +1303,47 @@ private int getAudioFormat(int channelCount) { | |||
} | |||
} | |||
|
|||
private void addOnFrameRenderedListener() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: "set" instead of "add".
} | ||
|
||
@RequiresApi(31) | ||
private void addOnFirstTunnelFrameReadyListener() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: "set" instead of "add", also append "V31" to the function name.
void OnMediaCodecFrameRendered(SbTime frame_timestamp) override {} | ||
void OnFirstTunnelFrameReady() override {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add NOTREACHED() here.
} | ||
// Send placeholders of frames to renderer, so it can end prerolling and | ||
// calculate dropped frames. | ||
decoder_status_cb_(kNeedMoreInput, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- The timestamp of the frames might not be monotonic, and may get dropped in https://github.com/youtube/cobalt/blob/24.lts.13/starboard/shared/starboard/player/filter/video_renderer_internal_impl.cc#L280C37-L280C37.
- We are sending the pseudo decoded frames back, before they are actually written to the platform. Note that MediaDecoder maintains a queue and there can be a delay between this call and the queuing of buffer to the platform. Shall we send the decoded frames after queueInputBuffer()?
|
||
if (tunnel_mode_audio_session_id_ != -1) { | ||
SbTime max_timestamp = input_buffers[0]->timestamp(); | ||
if (IsTunnelMode()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous code does rate control at line 797, just want to double check if rate control is handled in tunnel mode.
} | ||
|
||
void VideoDecoder::OnTunnelModePrerollTimeout() { | ||
void VideoDecoder::TunnelModeTick() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Under the current algorithm, the moment we queue the input buffer to the platform, we know whether the frame will be considered as dropped. We cannot determine this in the current implementation because in the call chain of WriteInputBuffers() doesn't have access to the current media time.
It would be great if we can find an elegant way to make this decision, instead of ticking 100 times a second.
@@ -26,7 +26,7 @@ namespace shared { | |||
|
|||
namespace { | |||
|
|||
const SbTimeMonotonic kBufferTooLateThreshold = -32 * kSbTimeMillisecond; | |||
const SbTimeMonotonic kBufferTooLateThreshold = -16 * kSbTimeMillisecond; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's ok to modify it with a fallback plan (i.e. if this causes issues in production, we'll revert the behavior from the backend).
b/175890319
b/175888740
b/302198176
b/253469969