Skip to content

Commit fc769cb

Browse files
authored
[android] Refine video render algorithm (#5551)
1. Allow VideoRenderAlgorithm release first frame as soon as possible. 2. Besides the first frame, other frames will be released after any audio frame has been consumed. Bug: 186660620
1 parent 4711be3 commit fc769cb

File tree

5 files changed

+53
-5
lines changed

5 files changed

+53
-5
lines changed

starboard/android/shared/audio_track_audio_sink_type.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
#include "starboard/android/shared/audio_track_audio_sink_type.h"
1616

1717
#include <unistd.h>
18+
1819
#include <algorithm>
20+
#include <memory>
1921
#include <string>
2022
#include <vector>
2123

@@ -27,6 +29,7 @@
2729
#include "starboard/common/scoped_timer.h"
2830
#include "starboard/common/string.h"
2931
#include "starboard/common/time.h"
32+
#include "starboard/shared/starboard/features.h"
3033
#include "starboard/shared/starboard/media/media_util.h"
3134
#include "starboard/shared/starboard/player/filter/common.h"
3235
#include "starboard/thread.h"
@@ -215,6 +218,9 @@ void AudioTrackAudioSink::AudioThreadFunc() {
215218

216219
int last_playback_head_position = 0;
217220

221+
bool release_frames_after_audio_starts = features::FeatureList::IsEnabled(
222+
features::kReleaseVideoFramesAfterAudioStarts);
223+
218224
while (!quit_) {
219225
int playback_head_position = 0;
220226
int64_t frames_consumed_at = 0;
@@ -282,6 +288,12 @@ void AudioTrackAudioSink::AudioThreadFunc() {
282288
last_playback_head_event_at = -1;
283289
ScopedTimer timer("Play");
284290
bridge_.Play();
291+
if (release_frames_after_audio_starts) {
292+
// To promptly re-evaluate and update audio state, we restart the loop
293+
// after calling AudioTrack.play() on Android, as this operation often
294+
// takes hundreds of milliseconds.
295+
continue;
296+
}
285297
}
286298

287299
if (!is_playing || frames_in_buffer == 0) {

starboard/android/shared/video_render_algorithm.cc

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515
#include "starboard/android/shared/video_render_algorithm.h"
1616

1717
#include <algorithm>
18+
#include <list>
1819

20+
#include "cobalt/android/jni_headers/VideoFrameReleaseTimeHelper_jni.h"
1921
#include "starboard/android/shared/media_common.h"
2022
#include "starboard/common/check_op.h"
2123
#include "starboard/common/log.h"
22-
23-
#include "cobalt/android/jni_headers/VideoFrameReleaseTimeHelper_jni.h"
24+
#include "starboard/shared/starboard/features.h"
2425

2526
namespace starboard {
2627

@@ -43,7 +44,10 @@ jlong GetSystemNanoTime() {
4344
VideoRenderAlgorithmAndroid::VideoRenderAlgorithmAndroid(
4445
MediaCodecVideoDecoder* video_decoder,
4546
VideoFrameTracker* frame_tracker)
46-
: video_decoder_(video_decoder), frame_tracker_(frame_tracker) {
47+
: video_decoder_(video_decoder),
48+
frame_tracker_(frame_tracker),
49+
release_frames_after_audio_starts_(features::FeatureList::IsEnabled(
50+
features::kReleaseVideoFramesAfterAudioStarts)) {
4751
SB_CHECK(video_decoder_);
4852
video_decoder_->SetPlaybackRate(playback_rate_);
4953
}
@@ -70,9 +74,22 @@ void VideoRenderAlgorithmAndroid::Render(
7074
double playback_rate;
7175
int64_t playback_time = media_time_provider->GetCurrentMediaTime(
7276
&is_audio_playing, &is_audio_eos_played, &is_underflow, &playback_rate);
73-
if (!is_audio_playing) {
74-
break;
77+
78+
if (release_frames_after_audio_starts_) {
79+
// After the first frame, stop rendering if audio isn't playing, or if
80+
// audio playback hasn't advanced past the current seek_to_time (or
81+
// initial time 0). This ensures video doesn't run ahead if audio is
82+
// stalled or hasn't consumed frames yet.
83+
if (first_frame_released_ &&
84+
(!is_audio_playing || playback_time == seek_to_time_)) {
85+
break;
86+
}
87+
} else {
88+
if (!is_audio_playing) {
89+
break;
90+
}
7591
}
92+
7693
if (playback_rate != playback_rate_) {
7794
playback_rate_ = playback_rate;
7895
video_decoder_->SetPlaybackRate(playback_rate);
@@ -116,6 +133,7 @@ void VideoRenderAlgorithmAndroid::Render(
116133
draw_frame_cb(frames->front(), adjusted_release_time_ns);
117134
SB_DCHECK_EQ(status, VideoRendererSink::kReleased);
118135
frames->pop_front();
136+
first_frame_released_ = true;
119137
} else {
120138
break;
121139
}
@@ -126,6 +144,8 @@ void VideoRenderAlgorithmAndroid::Seek(int64_t seek_to_time) {
126144
if (frame_tracker_) {
127145
frame_tracker_->Seek(seek_to_time);
128146
}
147+
first_frame_released_ = false;
148+
seek_to_time_ = seek_to_time;
129149
}
130150

131151
int VideoRenderAlgorithmAndroid::GetDroppedFrames() {

starboard/android/shared/video_render_algorithm.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ class VideoRenderAlgorithmAndroid : public VideoRenderAlgorithm {
5353
double playback_rate_ = 1.0;
5454
VideoFrameReleaseTimeHelper video_frame_release_time_helper_;
5555
int dropped_frames_ = 0;
56+
bool first_frame_released_ = false;
57+
int64_t seek_to_time_ = 0; // microseconds
58+
59+
const bool release_frames_after_audio_starts_;
5660
};
5761

5862
} // namespace starboard

starboard/extension/feature_config.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ STARBOARD_FEATURE(kForceResetAudioDecoder, "ForceResetAudioDecoder", false)
122122
// enabling tunnel mode on all playbacks.
123123
STARBOARD_FEATURE(kForceTunnelMode, "ForceTunnelMode", false)
124124

125+
// Cobalt VideoRenderAlgorithm used to release video frames immediately after
126+
// playback starts. Set the following variable to true to make it release video
127+
// frames until the underlying audio sink actually starts.
128+
STARBOARD_FEATURE(kReleaseVideoFramesAfterAudioStarts,
129+
"ReleaseVideoFramesAfterAudioStarts",
130+
false)
131+
125132
// By default, set the following to true to use stub decoder as audio/video
126133
// decoder.
127134
STARBOARD_FEATURE(kUseStubAudioDecoder, "UseStubAudioDecoder", false)
@@ -135,6 +142,7 @@ STARBOARD_FEATURE(kUseStubVideoDecoder, "UseStubVideoDecoder", false)
135142
STARBOARD_FEATURE(kVideoDecoderDelayUsecOverride,
136143
"VideoDecoderDelayUsecOverride",
137144
false)
145+
138146
#endif // BUILDFLAG(IS_ANDROID) && (SB_API_VERSION >= 17)
139147
FEATURE_LIST_END
140148

starboard/shared/starboard/player/player_internal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,11 @@ class SbPlayerPrivateImpl final : public SbPlayerPrivate {
7979
void WriteEndOfStream(SbMediaType stream_type) final;
8080
void SetBounds(int z_index, int x, int y, int width, int height) final;
8181
void GetInfo(SbPlayerInfo* out_player_info) final;
82+
83+
// TODO (b/456786219): as SbPlayer doesn't support pause, we should remove
84+
// unused pause related functions.
8285
void SetPause(bool pause) final;
86+
8387
void SetPlaybackRate(double playback_rate) final;
8488
void SetVolume(double volume) final;
8589

0 commit comments

Comments
 (0)