Skip to content

Commit

Permalink
[MediaFoundation] Request next frame during onPlaying event
Browse files Browse the repository at this point in the history
OS: Win10, Win11

During OnPlaying event, a frame request should be called to get
the first frame to output at the earliest possible time. This
is the earliest time when a frame is available. Current
implementation waits for render to be called, while
StartPlayingFrom's call for RequestNextFrameBetweenTimestamps
may not output a result if the media engine is not yet ready
to output a frame.

Bug: 1355520
Change-Id: Ice60ac41ca4b8cae9b0687626e93017d0a4406f0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3852409
Reviewed-by: Xiaohan Wang <xhwang@chromium.org>
Commit-Queue: Daoyuan Li <daoyuanli@microsoft.com>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1041097}
  • Loading branch information
daoyuanli9 authored and Chromium LUCI CQ committed Aug 30, 2022
1 parent bd577dd commit 395b2b1
Show file tree
Hide file tree
Showing 8 changed files with 19 additions and 40 deletions.
23 changes: 4 additions & 19 deletions media/mojo/clients/win/media_foundation_renderer_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,6 @@ void MediaFoundationRendererClient::StartPlayingFrom(base::TimeDelta time) {
SignalMediaPlayingStateChange(true);
next_video_frame_.reset();
mojo_renderer_->StartPlayingFrom(time);
// Request the first frame (if we are not in frame server mode this just
// gets dropped).
base::TimeTicks request_min = base::TimeTicks::Now();
base::TimeTicks request_max =
base::TimeTicks::Now() + GetPreferredRenderInterval();

renderer_extension_->RequestNextFrameBetweenTimestamps(request_min,
request_max);
}

void MediaFoundationRendererClient::SetPlaybackRate(double playback_rate) {
Expand Down Expand Up @@ -356,22 +348,15 @@ scoped_refptr<VideoFrame> MediaFoundationRendererClient::Render(
return nullptr;
}

base::TimeTicks next_request_min = deadline_max;
base::TimeTicks next_request_max =
deadline_max + GetPreferredRenderInterval();

auto callback =
[](base::TimeTicks deadline_min, base::TimeTicks deadline_max,
base::WeakPtr<MediaFoundationRendererClient> renderer_client) {
if (renderer_client.MaybeValid()) {
renderer_client->renderer_extension_
->RequestNextFrameBetweenTimestamps(deadline_min, deadline_max);
[](base::WeakPtr<MediaFoundationRendererClient> renderer_client) {
if (renderer_client) {
renderer_client->renderer_extension_->RequestNextFrame();
}
};

media_task_runner_->PostTask(
FROM_HERE, base::BindOnce(callback, next_request_min, next_request_max,
weak_factory_.GetWeakPtr()));
FROM_HERE, base::BindOnce(callback, weak_factory_.GetWeakPtr()));

// TODO(crbug.com/1298093): Need to report underflow when we don't have a
// frame ready for presentation by calling OnBufferingStateChange
Expand Down
6 changes: 3 additions & 3 deletions media/mojo/clients/win/media_foundation_renderer_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,9 @@ class MediaFoundationRendererClient
void OnOverlayStateChanged(const gpu::Mailbox& mailbox, bool promoted);
void UpdateRenderMode();

// This class is constructed on the main thread and used exclusively on the
// media thread. Hence we store PendingRemotes so we can bind the Remotes
// on the media task runner during/after Initialize().
// This class is constructed on the main thread. Hence we store
// PendingRemotes so we can bind the Remotes on the media task
// runner during/after Initialize().
scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
std::unique_ptr<MediaLog> media_log_;
std::unique_ptr<MojoRenderer> mojo_renderer_;
Expand Down
6 changes: 2 additions & 4 deletions media/mojo/mojom/renderer_extensions.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,10 @@ interface MediaFoundationRendererExtension {
// Notify that the frame has been displayed and can be reused.
NotifyFrameReleased(mojo_base.mojom.UnguessableToken frame_token);

// Request a frame from the media engine if it is available for a specific
// time.
// Request a frame from the media engine if it is available
// The frame will be returned async via the
// MediaFoundationRendererClientExtension::OnFrameAvailable callback.
RequestNextFrameBetweenTimestamps(mojo_base.mojom.TimeTicks deadline_min,
mojo_base.mojom.TimeTicks deadline_max);
RequestNextFrame();

// Notify which rendering mode to be using for future video frames.
SetMediaFoundationRenderingMode(MediaFoundationRenderingMode mode);
Expand Down
6 changes: 2 additions & 4 deletions media/mojo/services/media_foundation_renderer_wrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,8 @@ void MediaFoundationRendererWrapper::NotifyFrameReleased(
renderer_->NotifyFrameReleased(frame_token);
}

void MediaFoundationRendererWrapper::RequestNextFrameBetweenTimestamps(
base::TimeTicks deadline_min,
base::TimeTicks deadline_max) {
renderer_->RequestNextFrameBetweenTimestamps(deadline_min, deadline_max);
void MediaFoundationRendererWrapper::RequestNextFrame() {
renderer_->RequestNextFrame();
}

void MediaFoundationRendererWrapper::SetMediaFoundationRenderingMode(
Expand Down
3 changes: 1 addition & 2 deletions media/mojo/services/media_foundation_renderer_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ class MediaFoundationRendererWrapper final
void SetOutputRect(const gfx::Rect& output_rect,
SetOutputRectCallback callback) override;
void NotifyFrameReleased(const base::UnguessableToken& frame_token) override;
void RequestNextFrameBetweenTimestamps(base::TimeTicks deadline_min,
base::TimeTicks deadline_max) override;
void RequestNextFrame() override;
void SetMediaFoundationRenderingMode(
MediaFoundationRenderingMode mode) override;

Expand Down
8 changes: 5 additions & 3 deletions media/renderers/win/media_foundation_renderer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,10 @@ void MediaFoundationRenderer::OnPlaying() {
OnBufferingStateChange(
BufferingState::BUFFERING_HAVE_ENOUGH,
BufferingStateChangeReason::BUFFERING_CHANGE_REASON_UNKNOWN);

// Earliest time to request first frame to screen
RequestNextFrame();

// The OnPlaying callback from MediaEngineNotifyImpl lets us know that an
// MF_MEDIA_ENGINE_EVENT_PLAYING message has been received. At this point we
// can safely start sending Statistics as any asynchronous Flush action in
Expand Down Expand Up @@ -968,9 +972,7 @@ void MediaFoundationRenderer::OnError(PipelineStatus status,
renderer_client_->OnError(new_status);
}

void MediaFoundationRenderer::RequestNextFrameBetweenTimestamps(
base::TimeTicks deadline_min,
base::TimeTicks deadline_max) {
void MediaFoundationRenderer::RequestNextFrame() {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
if (rendering_mode_ != MediaFoundationRenderingMode::FrameServer) {
return;
Expand Down
3 changes: 1 addition & 2 deletions media/renderers/win/media_foundation_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ class MEDIA_EXPORT MediaFoundationRenderer
void SetOutputRect(const gfx::Rect& output_rect,
SetOutputRectCB callback) override;
void NotifyFrameReleased(const base::UnguessableToken& frame_token) override;
void RequestNextFrameBetweenTimestamps(base::TimeTicks deadline_min,
base::TimeTicks deadline_max) override;
void RequestNextFrame() override;
void SetMediaFoundationRenderingMode(
MediaFoundationRenderingMode render_mode) override;

Expand Down
4 changes: 1 addition & 3 deletions media/renderers/win/media_foundation_renderer_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ class MEDIA_EXPORT MediaFoundationRendererExtension {
const base::UnguessableToken& frame_token) = 0;

// Request a new frame to be provided to the client.
virtual void RequestNextFrameBetweenTimestamps(
base::TimeTicks deadline_min,
base::TimeTicks deadline_max) = 0;
virtual void RequestNextFrame() = 0;

// Change which mode we are using for video frame rendering.
virtual void SetMediaFoundationRenderingMode(
Expand Down

0 comments on commit 395b2b1

Please sign in to comment.