Commit c647a3bd authored by Dale Curtis's avatar Dale Curtis Committed by Commit Bot

Implement VEA::Flush() for VTVideoEncodeAccelerator.

This is required for WebCodecs and others to actually be able to
get the last few frames out of the encoder.

Note: A followup CL will actually enable hardware encoding on
macOS once MojoVEA::Flush() support has landed.

R=eugene

Bug: 1110279
Test: Layout tests now pass.
Change-Id: I9e1c7fa94e69c3214dcb92ea21157ec4bc267873
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2536353
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
Commit-Queue: Eugene Zemtsov <eugene@chromium.org>
Reviewed-by: default avatarEugene Zemtsov <eugene@chromium.org>
Auto-Submit: Dale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#827541}
parent 84cf3e38
......@@ -7,6 +7,7 @@
#include <memory>
#include "base/logging.h"
#include "base/mac/mac_logging.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/threading/thread_task_runner_handle.h"
......@@ -142,6 +143,9 @@ bool VTVideoEncodeAccelerator::Initialize(const Config& config,
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(client);
// Clients are expected to call Flush() before reinitializing the encoder.
DCHECK_EQ(pending_encodes_, 0);
if (config.input_format != PIXEL_FORMAT_I420 &&
config.input_format != PIXEL_FORMAT_NV12) {
DLOG(ERROR) << "Input format not supported= "
......@@ -254,6 +258,19 @@ void VTVideoEncodeAccelerator::Destroy() {
delete this;
}
void VTVideoEncodeAccelerator::Flush(FlushCallback flush_callback) {
DCHECK(thread_checker_.CalledOnValidThread());
encoder_thread_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&VTVideoEncodeAccelerator::FlushTask,
base::Unretained(this), std::move(flush_callback)));
}
bool VTVideoEncodeAccelerator::IsFlushSupported() {
return true;
}
void VTVideoEncodeAccelerator::EncodeTask(scoped_refptr<VideoFrame> frame,
bool force_keyframe) {
DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
......@@ -284,12 +301,13 @@ void VTVideoEncodeAccelerator::EncodeTask(scoped_refptr<VideoFrame> frame,
// We can pass the ownership of |request| to the encode callback if
// successful. Otherwise let it fall out of scope.
OSStatus status = VTCompressionSessionEncodeFrame(
compression_session_, pixel_buffer, timestamp_cm, CMTime{0, 0, 0, 0},
compression_session_, pixel_buffer, timestamp_cm, kCMTimeInvalid,
frame_props, reinterpret_cast<void*>(request.get()), nullptr);
if (status != noErr) {
DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status;
NotifyError(kPlatformFailureError);
} else {
++pending_encodes_;
CHECK(request.release());
}
}
......@@ -360,8 +378,6 @@ void VTVideoEncodeAccelerator::DestroyTask() {
// Cancel all encoder thread callbacks.
encoder_task_weak_factory_.InvalidateWeakPtrs();
// This call blocks until all pending frames are flushed out.
DestroyCompressionSession();
}
......@@ -408,6 +424,9 @@ void VTVideoEncodeAccelerator::CompressionCallbackTask(
std::unique_ptr<EncodeOutput> encode_output) {
DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
--pending_encodes_;
DCHECK_GE(pending_encodes_, 0);
if (status != noErr) {
DLOG(ERROR) << " encode failed: " << status;
NotifyError(kPlatformFailureError);
......@@ -440,6 +459,7 @@ void VTVideoEncodeAccelerator::ReturnBitstreamBuffer(
base::BindOnce(&Client::BitstreamBufferReady, client_, buffer_ref->id,
BitstreamBufferMetadata(
0, false, encode_output->capture_timestamp)));
MaybeRunFlushCallback();
return;
}
......@@ -466,6 +486,7 @@ void VTVideoEncodeAccelerator::ReturnBitstreamBuffer(
&Client::BitstreamBufferReady, client_, buffer_ref->id,
BitstreamBufferMetadata(used_buffer_size, keyframe,
encode_output->capture_timestamp)));
MaybeRunFlushCallback();
}
bool VTVideoEncodeAccelerator::ResetCompressionSession() {
......@@ -557,4 +578,48 @@ void VTVideoEncodeAccelerator::DestroyCompressionSession() {
}
}
void VTVideoEncodeAccelerator::FlushTask(FlushCallback flush_callback) {
DVLOG(3) << __func__;
DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
DCHECK(flush_callback);
if (!compression_session_) {
client_task_runner_->PostTask(
FROM_HERE, base::BindOnce(std::move(flush_callback), false));
return;
}
// Even though this will block until all frames are returned, the frames will
// be posted to the current task runner, so we can't run the flush callback
// at this time.
OSStatus status =
VTCompressionSessionCompleteFrames(compression_session_, kCMTimeInvalid);
if (status != noErr) {
OSSTATUS_DLOG(ERROR, status)
<< " VTCompressionSessionCompleteFrames failed: " << status;
client_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(std::move(flush_callback), /*success=*/false));
return;
}
pending_flush_cb_ = std::move(flush_callback);
MaybeRunFlushCallback();
}
void VTVideoEncodeAccelerator::MaybeRunFlushCallback() {
DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
if (!pending_flush_cb_)
return;
if (pending_encodes_ || !encoder_output_queue_.empty())
return;
client_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(std::move(pending_flush_cb_), /*success=*/true));
}
} // namespace media
......@@ -38,6 +38,8 @@ class MEDIA_GPU_EXPORT VTVideoEncodeAccelerator
void RequestEncodingParametersChange(uint32_t bitrate,
uint32_t framerate) override;
void Destroy() override;
void Flush(FlushCallback flush_callback) override;
bool IsFlushSupported() override;
private:
// Holds the associated data of a video frame being processed.
......@@ -93,6 +95,11 @@ class MEDIA_GPU_EXPORT VTVideoEncodeAccelerator
// encoding work).
void DestroyCompressionSession();
// Flushes the encoder. The flush callback won't be run until all pending
// encodes have been completed.
void FlushTask(FlushCallback flush_callback);
void MaybeRunFlushCallback();
base::ScopedCFTypeRef<VTCompressionSessionRef> compression_session_;
gfx::Size input_visible_size_;
......@@ -131,6 +138,11 @@ class MEDIA_GPU_EXPORT VTVideoEncodeAccelerator
base::Thread encoder_thread_;
scoped_refptr<base::SingleThreadTaskRunner> encoder_thread_task_runner_;
// Tracking information for ensuring flushes aren't completed until all
// pending encodes have been returned.
int pending_encodes_ = 0;
FlushCallback pending_flush_cb_;
// Declared last to ensure that all weak pointers are invalidated before
// other destructors run.
base::WeakPtr<VTVideoEncodeAccelerator> encoder_weak_ptr_;
......
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