Skip to content
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

Closed

Conversation

jasonzhangxx
Copy link
Contributor

@jasonzhangxx jasonzhangxx commented Oct 23, 2023

  1. Send placeholder frames to video renderer in tunnel mode.
  2. Calculate dropped frames based on the placeholder frames.
  3. Determine 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

@codecov
Copy link

codecov bot commented Oct 24, 2023

Codecov Report

Merging #1835 (81ecfbd) into main (896a0ec) will increase coverage by 0.22%.
Report is 149 commits behind head on main.
The diff coverage is n/a.

@@            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     

see 51 files with indirect coverage changes

starboard/android/shared/video_decoder.cc Outdated Show resolved Hide resolved
@@ -26,7 +26,7 @@ namespace shared {

namespace {

const SbTimeMonotonic kBufferTooLateThreshold = -32 * kSbTimeMillisecond;
const SbTimeMonotonic kBufferTooLateThreshold = -16 * kSbTimeMillisecond;
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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()) {
Copy link
Contributor

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:

  1. If the frame arrives too late (16 or 32 ms later than the time it should be displayed), we drop it.
  2. Else if the frame should be rendered in the next 50 ms, we display it.
  3. Else do nothing.

What do we want for tunnel mode frames? Will we get the same accuracy after tick interval is reduced to 10ms?

Copy link
Contributor Author

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.

@jasonzhangxx jasonzhangxx force-pushed the tunnel-dropped-frames branch 2 times, most recently from 5c92f07 to 95ccd7a Compare October 31, 2023 17:24
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
}
};
mMediaCodec.setOnFrameRenderedListener(mTunnelModeFrameRendererListener, null);
// TODO (b/306236129): disable the listeners as frames to be discarded would invoke the
Copy link
Contributor

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:

  1. Remove the space after TODO
  2. Refine the commit message mentioning that OnFirstTunnelFrameReadyListener is commented out.

Comment on lines +857 to +858
mMediaCodec.setOnFrameRenderedListener(null, null);
mMediaCodec.setOnFirstTunnelFrameReadyListener(null, null);
Copy link
Contributor

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() {
Copy link
Contributor

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() {
Copy link
Contributor

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.

Comment on lines +74 to +75
void OnMediaCodecFrameRendered(SbTime frame_timestamp) override {}
void OnFirstTunnelFrameReady() override {}
Copy link
Contributor

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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 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.
  2. 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()) {
Copy link
Contributor

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() {
Copy link
Contributor

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;
Copy link
Contributor

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).

@jasonzhangxx jasonzhangxx marked this pull request as draft November 16, 2023 23:40
@jasonzhangxx jasonzhangxx deleted the tunnel-dropped-frames branch February 1, 2024 21:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants