OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/gpu/media/vt_video_encode_accelerator_mac.h" | 5 #include "content/common/gpu/media/vt_video_encode_accelerator_mac.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/thread_task_runner_handle.h" | 9 #include "base/thread_task_runner_handle.h" |
10 #include "media/base/mac/coremedia_glue.h" | 10 #include "media/base/mac/coremedia_glue.h" |
11 #include "media/base/mac/corevideo_glue.h" | 11 #include "media/base/mac/corevideo_glue.h" |
12 #include "media/base/mac/video_frame_mac.h" | 12 #include "media/base/mac/video_frame_mac.h" |
| 13 #include "third_party/webrtc/system_wrappers/include/clock.h" |
13 | 14 |
14 namespace content { | 15 namespace content { |
15 | 16 |
16 namespace { | 17 namespace { |
17 | 18 |
18 // TODO(emircan): Check if we can find the actual system capabilities via | 19 // TODO(emircan): Check if we can find the actual system capabilities via |
19 // creating VTCompressionSessions with varying requirements. | 20 // creating VTCompressionSessions with varying requirements. |
20 // See crbug.com/584784. | 21 // See crbug.com/584784. |
21 const size_t kBitsPerByte = 8; | 22 const size_t kBitsPerByte = 8; |
22 const size_t kDefaultResolutionWidth = 640; | 23 const size_t kDefaultResolutionWidth = 640; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 size_t size) | 57 size_t size) |
57 : id(id), shm(std::move(shm)), size(size) {} | 58 : id(id), shm(std::move(shm)), size(size) {} |
58 const int32_t id; | 59 const int32_t id; |
59 const std::unique_ptr<base::SharedMemory> shm; | 60 const std::unique_ptr<base::SharedMemory> shm; |
60 const size_t size; | 61 const size_t size; |
61 | 62 |
62 private: | 63 private: |
63 DISALLOW_IMPLICIT_CONSTRUCTORS(BitstreamBufferRef); | 64 DISALLOW_IMPLICIT_CONSTRUCTORS(BitstreamBufferRef); |
64 }; | 65 }; |
65 | 66 |
| 67 // .5 is set as a minimum to prevent overcompensating for large temporary |
| 68 // overshoots. We don't want to degrade video quality too badly. |
| 69 // .95 is set to prevent oscillations. When a lower bitrate is set on the |
| 70 // encoder than previously set, its output seems to have a brief period of |
| 71 // drastically reduced bitrate, so we want to avoid that. In steady state |
| 72 // conditions, 0.95 seems to give us better overall bitrate over long periods |
| 73 // of time. |
66 VTVideoEncodeAccelerator::VTVideoEncodeAccelerator() | 74 VTVideoEncodeAccelerator::VTVideoEncodeAccelerator() |
67 : client_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 75 : bitrate_adjuster_(webrtc::Clock::GetRealTimeClock(), .5, .95), |
| 76 client_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
68 encoder_thread_("VTEncoderThread"), | 77 encoder_thread_("VTEncoderThread"), |
69 encoder_task_weak_factory_(this) { | 78 encoder_task_weak_factory_(this) { |
70 encoder_weak_ptr_ = encoder_task_weak_factory_.GetWeakPtr(); | 79 encoder_weak_ptr_ = encoder_task_weak_factory_.GetWeakPtr(); |
71 } | 80 } |
72 | 81 |
73 VTVideoEncodeAccelerator::~VTVideoEncodeAccelerator() { | 82 VTVideoEncodeAccelerator::~VTVideoEncodeAccelerator() { |
74 DVLOG(3) << __FUNCTION__; | 83 DVLOG(3) << __FUNCTION__; |
75 DCHECK(thread_checker_.CalledOnValidThread()); | 84 DCHECK(thread_checker_.CalledOnValidThread()); |
76 | 85 |
77 Destroy(); | 86 Destroy(); |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 media::VideoFrameMetadata::REFERENCE_TIME, &ref_time)) { | 267 media::VideoFrameMetadata::REFERENCE_TIME, &ref_time)) { |
259 ref_time = base::TimeTicks::Now(); | 268 ref_time = base::TimeTicks::Now(); |
260 } | 269 } |
261 auto timestamp_cm = CoreMediaGlue::CMTimeMake( | 270 auto timestamp_cm = CoreMediaGlue::CMTimeMake( |
262 frame->timestamp().InMicroseconds(), USEC_PER_SEC); | 271 frame->timestamp().InMicroseconds(), USEC_PER_SEC); |
263 // Wrap information we'll need after the frame is encoded in a heap object. | 272 // Wrap information we'll need after the frame is encoded in a heap object. |
264 // We'll get the pointer back from the VideoToolbox completion callback. | 273 // We'll get the pointer back from the VideoToolbox completion callback. |
265 std::unique_ptr<InProgressFrameEncode> request( | 274 std::unique_ptr<InProgressFrameEncode> request( |
266 new InProgressFrameEncode(frame->timestamp(), ref_time)); | 275 new InProgressFrameEncode(frame->timestamp(), ref_time)); |
267 | 276 |
| 277 // Update the bitrate if needed. |
| 278 RequestEncodingParametersChangeTask(bitrate_adjuster_.GetAdjustedBitrateBps(), |
| 279 frame_rate_); |
| 280 |
268 // We can pass the ownership of |request| to the encode callback if | 281 // We can pass the ownership of |request| to the encode callback if |
269 // successful. Otherwise let it fall out of scope. | 282 // successful. Otherwise let it fall out of scope. |
270 OSStatus status = videotoolbox_glue_->VTCompressionSessionEncodeFrame( | 283 OSStatus status = videotoolbox_glue_->VTCompressionSessionEncodeFrame( |
271 compression_session_, pixel_buffer, timestamp_cm, | 284 compression_session_, pixel_buffer, timestamp_cm, |
272 CoreMediaGlue::CMTime{0, 0, 0, 0}, frame_props, | 285 CoreMediaGlue::CMTime{0, 0, 0, 0}, frame_props, |
273 reinterpret_cast<void*>(request.get()), nullptr); | 286 reinterpret_cast<void*>(request.get()), nullptr); |
274 if (status != noErr) { | 287 if (status != noErr) { |
275 DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status; | 288 DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status; |
276 NotifyError(kPlatformFailureError); | 289 NotifyError(kPlatformFailureError); |
277 } else { | 290 } else { |
(...skipping 15 matching lines...) Expand all Loading... |
293 } | 306 } |
294 | 307 |
295 bitstream_buffer_queue_.push_back(std::move(buffer_ref)); | 308 bitstream_buffer_queue_.push_back(std::move(buffer_ref)); |
296 } | 309 } |
297 | 310 |
298 void VTVideoEncodeAccelerator::RequestEncodingParametersChangeTask( | 311 void VTVideoEncodeAccelerator::RequestEncodingParametersChangeTask( |
299 uint32_t bitrate, | 312 uint32_t bitrate, |
300 uint32_t framerate) { | 313 uint32_t framerate) { |
301 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 314 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
302 | 315 |
303 frame_rate_ = framerate > 1 ? framerate : 1; | |
304 target_bitrate_ = bitrate > 1 ? bitrate : 1; | |
305 | |
306 if (!compression_session_) { | 316 if (!compression_session_) { |
307 NotifyError(kPlatformFailureError); | 317 NotifyError(kPlatformFailureError); |
308 return; | 318 return; |
309 } | 319 } |
310 | 320 |
311 media::video_toolbox::SessionPropertySetter session_property_setter( | 321 bool rv; |
312 compression_session_, videotoolbox_glue_); | 322 if (framerate != static_cast<uint32_t>(frame_rate_)) { |
313 // TODO(emircan): See crbug.com/425352. | 323 frame_rate_ = framerate > 1 ? framerate : 1; |
314 bool rv = session_property_setter.Set( | 324 media::video_toolbox::SessionPropertySetter session_property_setter( |
315 videotoolbox_glue_->kVTCompressionPropertyKey_AverageBitRate(), | 325 compression_session_, videotoolbox_glue_); |
316 target_bitrate_); | 326 rv = session_property_setter.Set( |
317 rv &= session_property_setter.Set( | 327 videotoolbox_glue_->kVTCompressionPropertyKey_ExpectedFrameRate(), |
318 videotoolbox_glue_->kVTCompressionPropertyKey_ExpectedFrameRate(), | 328 frame_rate_); |
319 frame_rate_); | 329 DLOG_IF(ERROR, !rv) |
320 rv &= session_property_setter.Set( | 330 << "Couldn't change frame rate parameters of encode session."; |
321 videotoolbox_glue_->kVTCompressionPropertyKey_DataRateLimits(), | 331 } |
322 media::video_toolbox::ArrayWithIntegerAndFloat( | 332 |
323 target_bitrate_ / kBitsPerByte, 1.0f)); | 333 if (bitrate != static_cast<uint32_t>(adjusted_bitrate_)) { |
324 DLOG_IF(ERROR, !rv) << "Couldn't change session encoding parameters."; | 334 target_bitrate_ = bitrate > 1 ? bitrate : 1; |
| 335 bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_); |
| 336 adjusted_bitrate_ = bitrate_adjuster_.GetAdjustedBitrateBps(); |
| 337 media::video_toolbox::SessionPropertySetter session_property_setter( |
| 338 compression_session_, videotoolbox_glue_); |
| 339 rv = session_property_setter.Set( |
| 340 videotoolbox_glue_->kVTCompressionPropertyKey_AverageBitRate(), |
| 341 adjusted_bitrate_); |
| 342 rv &= session_property_setter.Set( |
| 343 videotoolbox_glue_->kVTCompressionPropertyKey_DataRateLimits(), |
| 344 media::video_toolbox::ArrayWithIntegerAndFloat( |
| 345 adjusted_bitrate_ / kBitsPerByte, 1.0f)); |
| 346 DLOG_IF(ERROR, !rv) |
| 347 << "Couldn't change bitrate parameters of encode session."; |
| 348 } |
325 } | 349 } |
326 | 350 |
327 void VTVideoEncodeAccelerator::DestroyTask() { | 351 void VTVideoEncodeAccelerator::DestroyTask() { |
328 DCHECK(thread_checker_.CalledOnValidThread() || | 352 DCHECK(thread_checker_.CalledOnValidThread() || |
329 (encoder_thread_.IsRunning() && | 353 (encoder_thread_.IsRunning() && |
330 encoder_thread_task_runner_->BelongsToCurrentThread())); | 354 encoder_thread_task_runner_->BelongsToCurrentThread())); |
331 | 355 |
332 // Cancel all encoder thread callbacks. | 356 // Cancel all encoder thread callbacks. |
333 encoder_task_weak_factory_.InvalidateWeakPtrs(); | 357 encoder_task_weak_factory_.InvalidateWeakPtrs(); |
334 | 358 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 CoreMediaGlue::kCMSampleAttachmentKey_NotSync()); | 445 CoreMediaGlue::kCMSampleAttachmentKey_NotSync()); |
422 | 446 |
423 size_t used_buffer_size = 0; | 447 size_t used_buffer_size = 0; |
424 const bool copy_rv = media::video_toolbox::CopySampleBufferToAnnexBBuffer( | 448 const bool copy_rv = media::video_toolbox::CopySampleBufferToAnnexBBuffer( |
425 encode_output->sample_buffer.get(), keyframe, buffer_ref->size, | 449 encode_output->sample_buffer.get(), keyframe, buffer_ref->size, |
426 reinterpret_cast<char*>(buffer_ref->shm->memory()), &used_buffer_size); | 450 reinterpret_cast<char*>(buffer_ref->shm->memory()), &used_buffer_size); |
427 if (!copy_rv) { | 451 if (!copy_rv) { |
428 DLOG(ERROR) << "Cannot copy output from SampleBuffer to AnnexBBuffer."; | 452 DLOG(ERROR) << "Cannot copy output from SampleBuffer to AnnexBBuffer."; |
429 used_buffer_size = 0; | 453 used_buffer_size = 0; |
430 } | 454 } |
| 455 bitrate_adjuster_.Update(used_buffer_size); |
431 | 456 |
432 client_task_runner_->PostTask( | 457 client_task_runner_->PostTask( |
433 FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_, | 458 FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_, |
434 buffer_ref->id, used_buffer_size, keyframe)); | 459 buffer_ref->id, used_buffer_size, keyframe)); |
435 } | 460 } |
436 | 461 |
437 bool VTVideoEncodeAccelerator::ResetCompressionSession() { | 462 bool VTVideoEncodeAccelerator::ResetCompressionSession() { |
438 DCHECK(thread_checker_.CalledOnValidThread()); | 463 DCHECK(thread_checker_.CalledOnValidThread()); |
439 | 464 |
440 DestroyCompressionSession(); | 465 DestroyCompressionSession(); |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
545 (encoder_thread_.IsRunning() && | 570 (encoder_thread_.IsRunning() && |
546 encoder_thread_task_runner_->BelongsToCurrentThread())); | 571 encoder_thread_task_runner_->BelongsToCurrentThread())); |
547 | 572 |
548 if (compression_session_) { | 573 if (compression_session_) { |
549 videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_); | 574 videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_); |
550 compression_session_.reset(); | 575 compression_session_.reset(); |
551 } | 576 } |
552 } | 577 } |
553 | 578 |
554 } // namespace content | 579 } // namespace content |
OLD | NEW |