1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/mojo/services/mojo_video_encode_accelerator_service.h"
10 #include "base/logging.h"
11 #include "base/task/bind_post_task.h"
12 #include "base/task/sequenced_task_runner.h"
13 #include "base/trace_event/trace_event.h"
14 #include "media/base/bitstream_buffer.h"
15 #include "media/base/limits.h"
16 #include "media/base/media_util.h"
17 #include "media/mojo/mojom/video_encoder_info.mojom.h"
18 #include "media/mojo/services/mojo_media_log.h"
19 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
20 #include "mojo/public/cpp/system/platform_handle.h"
25 void MojoVideoEncodeAcceleratorService::Create(
26 mojo::PendingReceiver<mojom::VideoEncodeAccelerator> receiver,
27 CreateAndInitializeVideoEncodeAcceleratorCallback create_vea_callback,
28 const gpu::GpuPreferences& gpu_preferences,
29 const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
30 const gpu::GPUInfo::GPUDevice& gpu_device) {
31 mojo::MakeSelfOwnedReceiver(
32 std::make_unique<MojoVideoEncodeAcceleratorService>(
33 std::move(create_vea_callback), gpu_preferences, gpu_workarounds,
38 MojoVideoEncodeAcceleratorService::MojoVideoEncodeAcceleratorService(
39 CreateAndInitializeVideoEncodeAcceleratorCallback create_vea_callback,
40 const gpu::GpuPreferences& gpu_preferences,
41 const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
42 const gpu::GPUInfo::GPUDevice& gpu_device)
43 : create_vea_callback_(std::move(create_vea_callback)),
44 gpu_preferences_(gpu_preferences),
45 gpu_workarounds_(gpu_workarounds),
46 gpu_device_(gpu_device),
47 output_buffer_size_(0),
50 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
53 MojoVideoEncodeAcceleratorService::~MojoVideoEncodeAcceleratorService() {
55 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
58 void MojoVideoEncodeAcceleratorService::Initialize(
59 const media::VideoEncodeAccelerator::Config& config,
60 mojo::PendingAssociatedRemote<mojom::VideoEncodeAcceleratorClient> client,
61 mojo::PendingRemote<mojom::MediaLog> media_log,
62 InitializeCallback success_callback) {
63 DVLOG(1) << __func__ << " " << config.AsHumanReadableString();
64 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
65 DCHECK(config.input_format == PIXEL_FORMAT_I420 ||
66 config.input_format == PIXEL_FORMAT_NV12)
67 << "Only I420 or NV12 format supported, got "
68 << VideoPixelFormatToString(config.input_format);
69 TRACE_EVENT1("media", "MojoVideoEncodeAcceleratorService::Initialize",
70 "config", config.AsHumanReadableString());
72 media_log_ = std::make_unique<MojoMediaLog>(
73 std::move(media_log), base::SequencedTaskRunner::GetCurrentDefault());
75 if (gpu_workarounds_.disable_accelerated_vp8_encode &&
76 config.output_profile == VP8PROFILE_ANY) {
77 MEDIA_LOG(ERROR, media_log_.get())
78 << __func__ << " VP8 encoding disabled by GPU policy";
79 std::move(success_callback).Run(false);
83 if (gpu_workarounds_.disable_accelerated_vp9_encode &&
84 config.output_profile >= VP9PROFILE_PROFILE0 &&
85 config.output_profile <= VP9PROFILE_PROFILE3) {
86 MEDIA_LOG(ERROR, media_log_.get())
87 << __func__ << " VP9 encoding disabled by GPU policy";
88 std::move(success_callback).Run(false);
92 if (gpu_workarounds_.disable_accelerated_h264_encode &&
93 config.output_profile >= H264PROFILE_MIN &&
94 config.output_profile <= H264PROFILE_MAX) {
95 MEDIA_LOG(ERROR, media_log_.get())
96 << __func__ << " H.264 encoding disabled by GPU policy";
97 std::move(success_callback).Run(false);
102 MEDIA_LOG(ERROR, media_log_.get())
103 << __func__ << " VEA is already initialized";
104 std::move(success_callback).Run(false);
109 MEDIA_LOG(ERROR, media_log_.get()) << __func__ << "null |client|";
110 std::move(success_callback).Run(false);
113 vea_client_.Bind(std::move(client));
115 if (config.input_visible_size.width() > limits::kMaxDimension ||
116 config.input_visible_size.height() > limits::kMaxDimension ||
117 config.input_visible_size.GetArea() > limits::kMaxCanvas) {
118 MEDIA_LOG(ERROR, media_log_.get())
119 << __func__ << "too large input_visible_size "
120 << config.input_visible_size.ToString();
121 std::move(success_callback).Run(false);
125 encoder_ = std::move(create_vea_callback_)
126 .Run(config, this, gpu_preferences_, gpu_workarounds_,
127 gpu_device_, media_log_->Clone());
129 MEDIA_LOG(ERROR, media_log_.get())
130 << __func__ << " Error creating or initializing VEA";
131 std::move(success_callback).Run(false);
135 std::move(success_callback).Run(true);
139 void MojoVideoEncodeAcceleratorService::Encode(
140 const scoped_refptr<VideoFrame>& frame,
141 const media::VideoEncoder::EncodeOptions& options,
142 EncodeCallback callback) {
143 DVLOG(2) << __func__ << " tstamp=" << frame->timestamp();
144 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
145 TRACE_EVENT2("media", "MojoVideoEncodeAcceleratorService::Encode",
146 "timestamp", frame->timestamp().InMicroseconds(), "keyframe",
149 DLOG(ERROR) << __func__ << " Failed to encode, the encoder is invalid";
150 std::move(callback).Run();
154 if (frame->coded_size() != input_coded_size_ &&
155 frame->storage_type() != media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER) {
156 NotifyErrorStatus({EncoderStatus::Codes::kInvalidInputFrame,
157 "wrong input coded size, expected " +
158 input_coded_size_.ToString() + ", got " +
159 frame->coded_size().ToString()});
160 std::move(callback).Run();
164 if (MediaTraceIsEnabled()) {
165 timestamps_.Put(frame->timestamp().InMicroseconds(),
166 base::TimeTicks::Now());
169 frame->AddDestructionObserver(
170 base::BindPostTaskToCurrentDefault(std::move(callback)));
171 encoder_->Encode(frame, options);
174 void MojoVideoEncodeAcceleratorService::UseOutputBitstreamBuffer(
175 int32_t bitstream_buffer_id,
176 base::UnsafeSharedMemoryRegion region) {
177 DVLOG(2) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id;
178 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
179 TRACE_EVENT1("media",
180 "MojoVideoEncodeAcceleratorService::UseOutputBitstreamBuffer",
181 "id", bitstream_buffer_id);
184 if (!region.IsValid()) {
185 NotifyErrorStatus({EncoderStatus::Codes::kInvalidOutputBuffer,
186 "invalid shared memory region"});
189 if (bitstream_buffer_id < 0) {
191 {EncoderStatus::Codes::kInvalidOutputBuffer,
192 "bitstream_buffer_id=" + base::NumberToString(bitstream_buffer_id) +
197 auto memory_size = region.GetSize();
198 if (memory_size < output_buffer_size_) {
200 {EncoderStatus::Codes::kInvalidOutputBuffer,
201 "bitstream_buffer_id=" + base::NumberToString(bitstream_buffer_id) +
202 " has a size of " + base::NumberToString(memory_size) +
203 "B, different from expected " +
204 base::NumberToString(output_buffer_size_) + "B"});
208 encoder_->UseOutputBitstreamBuffer(
209 BitstreamBuffer(bitstream_buffer_id, std::move(region), memory_size));
212 void MojoVideoEncodeAcceleratorService::
213 RequestEncodingParametersChangeWithLayers(
214 const media::VideoBitrateAllocation& bitrate_allocation,
215 uint32_t framerate) {
216 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
217 TRACE_EVENT2("media",
218 "MojoVideoEncodeAcceleratorService::"
219 "RequestEncodingParametersChangeWithLayers",
220 "bitrate_allocation", bitrate_allocation.ToString(), "framerate",
226 DVLOG(2) << __func__ << " bitrate=" << bitrate_allocation.GetSumBps()
227 << " framerate=" << framerate;
229 encoder_->RequestEncodingParametersChange(bitrate_allocation, framerate);
232 void MojoVideoEncodeAcceleratorService::
233 RequestEncodingParametersChangeWithBitrate(const media::Bitrate& bitrate,
234 uint32_t framerate) {
235 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
236 TRACE_EVENT2("media",
237 "MojoVideoEncodeAcceleratorService::"
238 "RequestEncodingParametersChangeWithBitrate",
239 "bitrate", bitrate.ToString(), "framerate", framerate);
243 DVLOG(2) << __func__ << " bitrate=" << bitrate.target_bps()
244 << " framerate=" << framerate;
246 encoder_->RequestEncodingParametersChange(bitrate, framerate);
249 void MojoVideoEncodeAcceleratorService::IsFlushSupported(
250 IsFlushSupportedCallback callback) {
251 DVLOG(2) << __func__;
252 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
255 DLOG(ERROR) << __func__
256 << " Failed to detect flush support, the encoder is invalid";
257 std::move(callback).Run(false);
261 bool flush_support = encoder_->IsFlushSupported();
262 std::move(callback).Run(flush_support);
265 void MojoVideoEncodeAcceleratorService::Flush(FlushCallback callback) {
266 DVLOG(2) << __func__;
267 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
270 DLOG(ERROR) << __func__ << " Failed to flush, the encoder is invalid";
271 std::move(callback).Run(false);
275 encoder_->Flush(std::move(callback));
278 void MojoVideoEncodeAcceleratorService::RequireBitstreamBuffers(
279 unsigned int input_count,
280 const gfx::Size& input_coded_size,
281 size_t output_buffer_size) {
282 DVLOG(2) << __func__ << " input_count=" << input_count
283 << " input_coded_size=" << input_coded_size.ToString()
284 << " output_buffer_size=" << output_buffer_size;
285 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
286 TRACE_EVENT2("media",
287 "MojoVideoEncodeAcceleratorService::RequireBitstreamBuffers",
288 "input_coded_size", input_coded_size.ToString(),
289 "output_buffer_size", output_buffer_size);
294 output_buffer_size_ = output_buffer_size;
295 input_coded_size_ = input_coded_size;
297 vea_client_->RequireBitstreamBuffers(input_count, input_coded_size,
301 void MojoVideoEncodeAcceleratorService::BitstreamBufferReady(
302 int32_t bitstream_buffer_id,
303 const media::BitstreamBufferMetadata& metadata) {
304 DVLOG(2) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id
305 << ", payload_size=" << metadata.payload_size_bytes
306 << "B, key_frame=" << metadata.key_frame;
307 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
308 TRACE_EVENT2("media",
309 "MojoVideoEncodeAcceleratorService::BitstreamBufferReady",
310 "timestamp", metadata.timestamp.InMicroseconds(),
311 "bitstream_buffer_id", bitstream_buffer_id);
312 if (MediaTraceIsEnabled() && metadata.end_of_picture()) {
313 int64_t timestamp = metadata.timestamp.InMicroseconds();
314 const auto timestamp_it = timestamps_.Peek(timestamp);
315 if (timestamp_it != timestamps_.end()) {
316 TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
317 "media", "MojoVEAService::EncodingFrameDuration", timestamp,
318 timestamp_it->second);
319 TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP1(
320 "media", "MojoVEAService::EncodingFrameDuration", timestamp,
321 base::TimeTicks::Now(), "timestamp", timestamp);
328 vea_client_->BitstreamBufferReady(bitstream_buffer_id, metadata);
331 void MojoVideoEncodeAcceleratorService::NotifyErrorStatus(
332 const EncoderStatus& status) {
333 DVLOG(1) << __func__;
334 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
335 CHECK(!status.is_ok());
338 LOG(ERROR) << "Call NotifyErrorStatus(): code="
339 << static_cast<int>(status.code())
340 << ", message=" << status.message();
341 vea_client_->NotifyErrorStatus(status);
344 void MojoVideoEncodeAcceleratorService::NotifyEncoderInfoChange(
345 const ::media::VideoEncoderInfo& info) {
346 DVLOG(4) << __func__;
347 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
351 vea_client_->NotifyEncoderInfoChange(info);