Commit 5e2d7023 authored by Chih-Yu Huang's avatar Chih-Yu Huang Committed by Commit Bot

media/gpu: VaapiVD: Support VP9 show_existing_frame feature.

The VP9 show_existing_frame feature allows a decoded frame be
outputted multiple times. This CL supports this feature at VaapiVD
implementation. Before sending VideoFrame to the client, we set the
correct timestamp corresponding to the buffer ID. This makes it
possible for the same video frame memory to be output several times
with different timestamps.

BUG=chromium:941330
TEST=Play video with show_existing_frame at File app.

Change-Id: I1b690a3ed3e3709ed3161014df9a180d93dd09dd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1687531
Commit-Queue: Chih-Yu Huang <akahuang@chromium.org>
Reviewed-by: default avatarHirokazu Honda <hiroh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#676752}
parent 55bd574d
...@@ -296,6 +296,9 @@ void VaapiVideoDecoder::QueueDecodeTask(scoped_refptr<DecoderBuffer> buffer, ...@@ -296,6 +296,9 @@ void VaapiVideoDecoder::QueueDecodeTask(scoped_refptr<DecoderBuffer> buffer,
return; return;
} }
if (!buffer->end_of_stream())
buffer_id_to_timestamp_.emplace(next_buffer_id_, buffer->timestamp());
decode_task_queue_.emplace(std::move(buffer), next_buffer_id_, decode_task_queue_.emplace(std::move(buffer), next_buffer_id_,
std::move(decode_cb)); std::move(decode_cb));
...@@ -459,7 +462,7 @@ scoped_refptr<VASurface> VaapiVideoDecoder::CreateSurface() { ...@@ -459,7 +462,7 @@ scoped_refptr<VASurface> VaapiVideoDecoder::CreateSurface() {
} }
void VaapiVideoDecoder::SurfaceReady(const scoped_refptr<VASurface>& va_surface, void VaapiVideoDecoder::SurfaceReady(const scoped_refptr<VASurface>& va_surface,
int32_t /*buffer_id*/, int32_t buffer_id,
const gfx::Rect& visible_rect, const gfx::Rect& visible_rect,
const VideoColorSpace& /*color_space*/) { const VideoColorSpace& /*color_space*/) {
DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
...@@ -474,13 +477,19 @@ void VaapiVideoDecoder::SurfaceReady(const scoped_refptr<VASurface>& va_surface, ...@@ -474,13 +477,19 @@ void VaapiVideoDecoder::SurfaceReady(const scoped_refptr<VASurface>& va_surface,
frame_pool_->SetFrameFormat(*frame_layout_, visible_rect_, natural_size); frame_pool_->SetFrameFormat(*frame_layout_, visible_rect_, natural_size);
} }
auto it = buffer_id_to_timestamp_.find(buffer_id);
DCHECK(it != buffer_id_to_timestamp_.end());
base::TimeDelta timestamp = it->second;
buffer_id_to_timestamp_.erase(it);
// Find the frame associated with the surface. We won't erase it from // Find the frame associated with the surface. We won't erase it from
// |output_frames_| yet, as the decoder might still be using it for reference. // |output_frames_| yet, as the decoder might still be using it for reference.
DCHECK_EQ(output_frames_.count(va_surface->id()), 1u); DCHECK_EQ(output_frames_.count(va_surface->id()), 1u);
OutputFrameTask(output_frames_[va_surface->id()]); OutputFrameTask(output_frames_[va_surface->id()], timestamp);
} }
void VaapiVideoDecoder::OutputFrameTask(scoped_refptr<VideoFrame> video_frame) { void VaapiVideoDecoder::OutputFrameTask(scoped_refptr<VideoFrame> video_frame,
base::TimeDelta timestamp) {
DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
DCHECK_EQ(state_, State::kDecoding); DCHECK_EQ(state_, State::kDecoding);
DCHECK(video_frame); DCHECK(video_frame);
...@@ -490,10 +499,12 @@ void VaapiVideoDecoder::OutputFrameTask(scoped_refptr<VideoFrame> video_frame) { ...@@ -490,10 +499,12 @@ void VaapiVideoDecoder::OutputFrameTask(scoped_refptr<VideoFrame> video_frame) {
// modify the attributes of the frame directly, we wrap the frame into a new // modify the attributes of the frame directly, we wrap the frame into a new
// frame with updated attributes. The old frame is bound to a destruction // frame with updated attributes. The old frame is bound to a destruction
// observer so it's not destroyed before the wrapped frame. // observer so it's not destroyed before the wrapped frame.
if (video_frame->visible_rect() != visible_rect_) { if (video_frame->visible_rect() != visible_rect_ ||
video_frame->timestamp() != timestamp) {
gfx::Size natural_size = GetNaturalSize(visible_rect_, pixel_aspect_ratio_); gfx::Size natural_size = GetNaturalSize(visible_rect_, pixel_aspect_ratio_);
scoped_refptr<VideoFrame> wrapped_frame = VideoFrame::WrapVideoFrame( scoped_refptr<VideoFrame> wrapped_frame = VideoFrame::WrapVideoFrame(
*video_frame, video_frame->format(), visible_rect_, natural_size); *video_frame, video_frame->format(), visible_rect_, natural_size);
wrapped_frame->set_timestamp(timestamp);
wrapped_frame->AddDestructionObserver( wrapped_frame->AddDestructionObserver(
base::BindOnce(base::DoNothing::Once<scoped_refptr<VideoFrame>>(), base::BindOnce(base::DoNothing::Once<scoped_refptr<VideoFrame>>(),
std::move(video_frame))); std::move(video_frame)));
......
...@@ -121,7 +121,8 @@ class VaapiVideoDecoder : public media::VideoDecoder, ...@@ -121,7 +121,8 @@ class VaapiVideoDecoder : public media::VideoDecoder,
void ClearDecodeTaskQueue(DecodeStatus status); void ClearDecodeTaskQueue(DecodeStatus status);
// Output a single |video_frame| on the decoder thread. // Output a single |video_frame| on the decoder thread.
void OutputFrameTask(scoped_refptr<VideoFrame> video_frame); void OutputFrameTask(scoped_refptr<VideoFrame> video_frame,
base::TimeDelta timestamp);
// Called when a different output frame resolution is requested on the decoder // Called when a different output frame resolution is requested on the decoder
// thread. This happens when either decoding just started or a resolution // thread. This happens when either decoding just started or a resolution
// change occurred in the video stream. // change occurred in the video stream.
...@@ -177,6 +178,9 @@ class VaapiVideoDecoder : public media::VideoDecoder, ...@@ -177,6 +178,9 @@ class VaapiVideoDecoder : public media::VideoDecoder,
// Video frame converter. // Video frame converter.
std::unique_ptr<VideoFrameConverter> frame_converter_; std::unique_ptr<VideoFrameConverter> frame_converter_;
// The mapping between buffer id and the timestamp.
std::map<int32_t, base::TimeDelta> buffer_id_to_timestamp_;
// Queue containing all requested decode tasks. // Queue containing all requested decode tasks.
base::queue<DecodeTask> decode_task_queue_; base::queue<DecodeTask> decode_task_queue_;
// The decode task we're currently trying to execute. // The decode task we're currently trying to execute.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment