| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/vaapi_video_encode_accelerator.h" | 5 #include "content/common/gpu/media/vaapi_video_encode_accelerator.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback.h" | 8 #include "base/callback.h" |
| 9 #include "base/message_loop/message_loop_proxy.h" | |
| 10 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 11 #include "base/numerics/safe_conversions.h" | 10 #include "base/numerics/safe_conversions.h" |
| 12 #include "content/common/gpu/media/h264_dpb.h" | 11 #include "content/common/gpu/media/h264_dpb.h" |
| 13 #include "media/base/bind_to_current_loop.h" | 12 #include "media/base/bind_to_current_loop.h" |
| 14 #include "third_party/libva/va/va_enc_h264.h" | 13 #include "third_party/libva/va/va_enc_h264.h" |
| 15 | 14 |
| 16 #define DVLOGF(level) DVLOG(level) << __FUNCTION__ << "(): " | 15 #define DVLOGF(level) DVLOG(level) << __FUNCTION__ << "(): " |
| 17 | 16 |
| 18 #define NOTIFY_ERROR(error, msg) \ | 17 #define NOTIFY_ERROR(error, msg) \ |
| 19 do { \ | 18 do { \ |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 mb_height_(0), | 125 mb_height_(0), |
| 127 output_buffer_byte_size_(0), | 126 output_buffer_byte_size_(0), |
| 128 state_(kUninitialized), | 127 state_(kUninitialized), |
| 129 frame_num_(0), | 128 frame_num_(0), |
| 130 idr_pic_id_(0), | 129 idr_pic_id_(0), |
| 131 bitrate_(0), | 130 bitrate_(0), |
| 132 framerate_(0), | 131 framerate_(0), |
| 133 cpb_size_(0), | 132 cpb_size_(0), |
| 134 encoding_parameters_changed_(false), | 133 encoding_parameters_changed_(false), |
| 135 encoder_thread_("VAVEAEncoderThread"), | 134 encoder_thread_("VAVEAEncoderThread"), |
| 136 child_message_loop_proxy_(base::MessageLoopProxy::current()), | 135 child_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 137 weak_this_ptr_factory_(this) { | 136 weak_this_ptr_factory_(this) { |
| 138 DVLOGF(4); | 137 DVLOGF(4); |
| 139 weak_this_ = weak_this_ptr_factory_.GetWeakPtr(); | 138 weak_this_ = weak_this_ptr_factory_.GetWeakPtr(); |
| 140 | 139 |
| 141 max_ref_idx_l0_size_ = kMaxNumReferenceFrames; | 140 max_ref_idx_l0_size_ = kMaxNumReferenceFrames; |
| 142 qp_ = kDefaultQP; | 141 qp_ = kDefaultQP; |
| 143 idr_period_ = kIDRPeriod; | 142 idr_period_ = kIDRPeriod; |
| 144 i_period_ = kIPeriod; | 143 i_period_ = kIPeriod; |
| 145 ip_period_ = kIPPeriod; | 144 ip_period_ = kIPPeriod; |
| 146 } | 145 } |
| 147 | 146 |
| 148 VaapiVideoEncodeAccelerator::~VaapiVideoEncodeAccelerator() { | 147 VaapiVideoEncodeAccelerator::~VaapiVideoEncodeAccelerator() { |
| 149 DVLOGF(4); | 148 DVLOGF(4); |
| 150 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 149 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 151 DCHECK(!encoder_thread_.IsRunning()); | 150 DCHECK(!encoder_thread_.IsRunning()); |
| 152 } | 151 } |
| 153 | 152 |
| 154 bool VaapiVideoEncodeAccelerator::Initialize( | 153 bool VaapiVideoEncodeAccelerator::Initialize( |
| 155 media::VideoFrame::Format format, | 154 media::VideoFrame::Format format, |
| 156 const gfx::Size& input_visible_size, | 155 const gfx::Size& input_visible_size, |
| 157 media::VideoCodecProfile output_profile, | 156 media::VideoCodecProfile output_profile, |
| 158 uint32 initial_bitrate, | 157 uint32 initial_bitrate, |
| 159 Client* client) { | 158 Client* client) { |
| 160 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 159 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 161 DCHECK(!encoder_thread_.IsRunning()); | 160 DCHECK(!encoder_thread_.IsRunning()); |
| 162 DCHECK_EQ(state_, kUninitialized); | 161 DCHECK_EQ(state_, kUninitialized); |
| 163 | 162 |
| 164 DVLOGF(1) << "Initializing VAVEA, input_format: " | 163 DVLOGF(1) << "Initializing VAVEA, input_format: " |
| 165 << media::VideoFrame::FormatToString(format) | 164 << media::VideoFrame::FormatToString(format) |
| 166 << ", input_visible_size: " << input_visible_size.ToString() | 165 << ", input_visible_size: " << input_visible_size.ToString() |
| 167 << ", output_profile: " << output_profile | 166 << ", output_profile: " << output_profile |
| 168 << ", initial_bitrate: " << initial_bitrate; | 167 << ", initial_bitrate: " << initial_bitrate; |
| 169 | 168 |
| 170 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); | 169 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 200 base::Bind(&ReportToUMA, VAAPI_ERROR)); | 199 base::Bind(&ReportToUMA, VAAPI_ERROR)); |
| 201 if (!vaapi_wrapper_.get()) { | 200 if (!vaapi_wrapper_.get()) { |
| 202 DVLOGF(1) << "Failed initializing VAAPI for profile " << output_profile; | 201 DVLOGF(1) << "Failed initializing VAAPI for profile " << output_profile; |
| 203 return false; | 202 return false; |
| 204 } | 203 } |
| 205 | 204 |
| 206 if (!encoder_thread_.Start()) { | 205 if (!encoder_thread_.Start()) { |
| 207 LOG(ERROR) << "Failed to start encoder thread"; | 206 LOG(ERROR) << "Failed to start encoder thread"; |
| 208 return false; | 207 return false; |
| 209 } | 208 } |
| 210 encoder_thread_proxy_ = encoder_thread_.message_loop_proxy(); | 209 encoder_thread_proxy_ = encoder_thread_.task_runner(); |
| 211 | 210 |
| 212 // Finish the remaining initialization on the encoder thread. | 211 // Finish the remaining initialization on the encoder thread. |
| 213 encoder_thread_proxy_->PostTask( | 212 encoder_thread_proxy_->PostTask( |
| 214 FROM_HERE, | 213 FROM_HERE, |
| 215 base::Bind(&VaapiVideoEncodeAccelerator::InitializeTask, | 214 base::Bind(&VaapiVideoEncodeAccelerator::InitializeTask, |
| 216 base::Unretained(this))); | 215 base::Unretained(this))); |
| 217 | 216 |
| 218 return true; | 217 return true; |
| 219 } | 218 } |
| 220 | 219 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 232 NOTIFY_ERROR(kPlatformFailureError, "Failed creating VASurfaces"); | 231 NOTIFY_ERROR(kPlatformFailureError, "Failed creating VASurfaces"); |
| 233 return; | 232 return; |
| 234 } | 233 } |
| 235 | 234 |
| 236 UpdateSPS(); | 235 UpdateSPS(); |
| 237 GeneratePackedSPS(); | 236 GeneratePackedSPS(); |
| 238 | 237 |
| 239 UpdatePPS(); | 238 UpdatePPS(); |
| 240 GeneratePackedPPS(); | 239 GeneratePackedPPS(); |
| 241 | 240 |
| 242 child_message_loop_proxy_->PostTask( | 241 child_task_runner_->PostTask( |
| 243 FROM_HERE, | 242 FROM_HERE, |
| 244 base::Bind(&Client::RequireBitstreamBuffers, | 243 base::Bind(&Client::RequireBitstreamBuffers, client_, kNumInputBuffers, |
| 245 client_, | 244 coded_size_, output_buffer_byte_size_)); |
| 246 kNumInputBuffers, | |
| 247 coded_size_, | |
| 248 output_buffer_byte_size_)); | |
| 249 | 245 |
| 250 SetState(kEncoding); | 246 SetState(kEncoding); |
| 251 } | 247 } |
| 252 | 248 |
| 253 void VaapiVideoEncodeAccelerator::RecycleVASurfaceID( | 249 void VaapiVideoEncodeAccelerator::RecycleVASurfaceID( |
| 254 VASurfaceID va_surface_id) { | 250 VASurfaceID va_surface_id) { |
| 255 DVLOGF(4) << "va_surface_id: " << va_surface_id; | 251 DVLOGF(4) << "va_surface_id: " << va_surface_id; |
| 256 DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); | 252 DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); |
| 257 | 253 |
| 258 available_va_surface_ids_.push_back(va_surface_id); | 254 available_va_surface_ids_.push_back(va_surface_id); |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 549 buffer->size, | 545 buffer->size, |
| 550 &data_size)) { | 546 &data_size)) { |
| 551 NOTIFY_ERROR(kPlatformFailureError, "Failed downloading coded buffer"); | 547 NOTIFY_ERROR(kPlatformFailureError, "Failed downloading coded buffer"); |
| 552 return; | 548 return; |
| 553 } | 549 } |
| 554 | 550 |
| 555 DVLOGF(3) << "Returning bitstream buffer " | 551 DVLOGF(3) << "Returning bitstream buffer " |
| 556 << (encode_job->keyframe ? "(keyframe)" : "") | 552 << (encode_job->keyframe ? "(keyframe)" : "") |
| 557 << " id: " << buffer->id << " size: " << data_size; | 553 << " id: " << buffer->id << " size: " << data_size; |
| 558 | 554 |
| 559 child_message_loop_proxy_->PostTask(FROM_HERE, | 555 child_task_runner_->PostTask( |
| 560 base::Bind(&Client::BitstreamBufferReady, | 556 FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_, buffer->id, |
| 561 client_, | 557 data_size, encode_job->keyframe)); |
| 562 buffer->id, | |
| 563 data_size, | |
| 564 encode_job->keyframe)); | |
| 565 } | 558 } |
| 566 | 559 |
| 567 void VaapiVideoEncodeAccelerator::Encode( | 560 void VaapiVideoEncodeAccelerator::Encode( |
| 568 const scoped_refptr<media::VideoFrame>& frame, | 561 const scoped_refptr<media::VideoFrame>& frame, |
| 569 bool force_keyframe) { | 562 bool force_keyframe) { |
| 570 DVLOGF(3) << "Frame timestamp: " << frame->timestamp().InMilliseconds() | 563 DVLOGF(3) << "Frame timestamp: " << frame->timestamp().InMilliseconds() |
| 571 << " force_keyframe: " << force_keyframe; | 564 << " force_keyframe: " << force_keyframe; |
| 572 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 565 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 573 | 566 |
| 574 encoder_thread_proxy_->PostTask( | 567 encoder_thread_proxy_->PostTask( |
| 575 FROM_HERE, | 568 FROM_HERE, |
| 576 base::Bind(&VaapiVideoEncodeAccelerator::EncodeTask, | 569 base::Bind(&VaapiVideoEncodeAccelerator::EncodeTask, |
| 577 base::Unretained(this), | 570 base::Unretained(this), |
| 578 frame, | 571 frame, |
| 579 force_keyframe)); | 572 force_keyframe)); |
| 580 } | 573 } |
| 581 | 574 |
| 582 bool VaapiVideoEncodeAccelerator::PrepareNextJob() { | 575 bool VaapiVideoEncodeAccelerator::PrepareNextJob() { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 656 return; | 649 return; |
| 657 } | 650 } |
| 658 | 651 |
| 659 EndFrame(); | 652 EndFrame(); |
| 660 TryToReturnBitstreamBuffer(); | 653 TryToReturnBitstreamBuffer(); |
| 661 } | 654 } |
| 662 | 655 |
| 663 void VaapiVideoEncodeAccelerator::UseOutputBitstreamBuffer( | 656 void VaapiVideoEncodeAccelerator::UseOutputBitstreamBuffer( |
| 664 const media::BitstreamBuffer& buffer) { | 657 const media::BitstreamBuffer& buffer) { |
| 665 DVLOGF(4) << "id: " << buffer.id(); | 658 DVLOGF(4) << "id: " << buffer.id(); |
| 666 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 659 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 667 | 660 |
| 668 if (buffer.size() < output_buffer_byte_size_) { | 661 if (buffer.size() < output_buffer_byte_size_) { |
| 669 NOTIFY_ERROR(kInvalidArgumentError, "Provided bitstream buffer too small"); | 662 NOTIFY_ERROR(kInvalidArgumentError, "Provided bitstream buffer too small"); |
| 670 return; | 663 return; |
| 671 } | 664 } |
| 672 | 665 |
| 673 scoped_ptr<base::SharedMemory> shm( | 666 scoped_ptr<base::SharedMemory> shm( |
| 674 new base::SharedMemory(buffer.handle(), false)); | 667 new base::SharedMemory(buffer.handle(), false)); |
| 675 if (!shm->Map(buffer.size())) { | 668 if (!shm->Map(buffer.size())) { |
| 676 NOTIFY_ERROR(kPlatformFailureError, "Failed mapping shared memory."); | 669 NOTIFY_ERROR(kPlatformFailureError, "Failed mapping shared memory."); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 693 DCHECK_NE(state_, kUninitialized); | 686 DCHECK_NE(state_, kUninitialized); |
| 694 | 687 |
| 695 available_bitstream_buffers_.push(make_linked_ptr(buffer_ref.release())); | 688 available_bitstream_buffers_.push(make_linked_ptr(buffer_ref.release())); |
| 696 TryToReturnBitstreamBuffer(); | 689 TryToReturnBitstreamBuffer(); |
| 697 } | 690 } |
| 698 | 691 |
| 699 void VaapiVideoEncodeAccelerator::RequestEncodingParametersChange( | 692 void VaapiVideoEncodeAccelerator::RequestEncodingParametersChange( |
| 700 uint32 bitrate, | 693 uint32 bitrate, |
| 701 uint32 framerate) { | 694 uint32 framerate) { |
| 702 DVLOGF(2) << "bitrate: " << bitrate << " framerate: " << framerate; | 695 DVLOGF(2) << "bitrate: " << bitrate << " framerate: " << framerate; |
| 703 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 696 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 704 | 697 |
| 705 encoder_thread_proxy_->PostTask( | 698 encoder_thread_proxy_->PostTask( |
| 706 FROM_HERE, | 699 FROM_HERE, |
| 707 base::Bind( | 700 base::Bind( |
| 708 &VaapiVideoEncodeAccelerator::RequestEncodingParametersChangeTask, | 701 &VaapiVideoEncodeAccelerator::RequestEncodingParametersChangeTask, |
| 709 base::Unretained(this), | 702 base::Unretained(this), |
| 710 bitrate, | 703 bitrate, |
| 711 framerate)); | 704 framerate)); |
| 712 } | 705 } |
| 713 | 706 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 745 UpdateRates(bitrate, framerate); | 738 UpdateRates(bitrate, framerate); |
| 746 | 739 |
| 747 UpdateSPS(); | 740 UpdateSPS(); |
| 748 GeneratePackedSPS(); | 741 GeneratePackedSPS(); |
| 749 | 742 |
| 750 // Submit new parameters along with next frame that will be processed. | 743 // Submit new parameters along with next frame that will be processed. |
| 751 encoding_parameters_changed_ = true; | 744 encoding_parameters_changed_ = true; |
| 752 } | 745 } |
| 753 | 746 |
| 754 void VaapiVideoEncodeAccelerator::Destroy() { | 747 void VaapiVideoEncodeAccelerator::Destroy() { |
| 755 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 748 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 756 | 749 |
| 757 // Can't call client anymore after Destroy() returns. | 750 // Can't call client anymore after Destroy() returns. |
| 758 client_ptr_factory_.reset(); | 751 client_ptr_factory_.reset(); |
| 759 weak_this_ptr_factory_.InvalidateWeakPtrs(); | 752 weak_this_ptr_factory_.InvalidateWeakPtrs(); |
| 760 | 753 |
| 761 // Early-exit encoder tasks if they are running and join the thread. | 754 // Early-exit encoder tasks if they are running and join the thread. |
| 762 if (encoder_thread_.IsRunning()) { | 755 if (encoder_thread_.IsRunning()) { |
| 763 encoder_thread_.message_loop()->PostTask( | 756 encoder_thread_.message_loop()->PostTask( |
| 764 FROM_HERE, | 757 FROM_HERE, |
| 765 base::Bind(&VaapiVideoEncodeAccelerator::DestroyTask, | 758 base::Bind(&VaapiVideoEncodeAccelerator::DestroyTask, |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1043 base::Unretained(this), | 1036 base::Unretained(this), |
| 1044 state)); | 1037 state)); |
| 1045 return; | 1038 return; |
| 1046 } | 1039 } |
| 1047 | 1040 |
| 1048 DVLOGF(1) << "setting state to: " << state; | 1041 DVLOGF(1) << "setting state to: " << state; |
| 1049 state_ = state; | 1042 state_ = state; |
| 1050 } | 1043 } |
| 1051 | 1044 |
| 1052 void VaapiVideoEncodeAccelerator::NotifyError(Error error) { | 1045 void VaapiVideoEncodeAccelerator::NotifyError(Error error) { |
| 1053 if (!child_message_loop_proxy_->BelongsToCurrentThread()) { | 1046 if (!child_task_runner_->BelongsToCurrentThread()) { |
| 1054 child_message_loop_proxy_->PostTask( | 1047 child_task_runner_->PostTask( |
| 1055 FROM_HERE, | 1048 FROM_HERE, base::Bind(&VaapiVideoEncodeAccelerator::NotifyError, |
| 1056 base::Bind( | 1049 weak_this_, error)); |
| 1057 &VaapiVideoEncodeAccelerator::NotifyError, weak_this_, error)); | |
| 1058 return; | 1050 return; |
| 1059 } | 1051 } |
| 1060 | 1052 |
| 1061 if (client_) { | 1053 if (client_) { |
| 1062 client_->NotifyError(error); | 1054 client_->NotifyError(error); |
| 1063 client_ptr_factory_.reset(); | 1055 client_ptr_factory_.reset(); |
| 1064 } | 1056 } |
| 1065 } | 1057 } |
| 1066 | 1058 |
| 1067 VaapiVideoEncodeAccelerator::EncodeJob::EncodeJob() | 1059 VaapiVideoEncodeAccelerator::EncodeJob::EncodeJob() |
| 1068 : coded_buffer(VA_INVALID_ID), keyframe(false) { | 1060 : coded_buffer(VA_INVALID_ID), keyframe(false) { |
| 1069 } | 1061 } |
| 1070 | 1062 |
| 1071 VaapiVideoEncodeAccelerator::EncodeJob::~EncodeJob() { | 1063 VaapiVideoEncodeAccelerator::EncodeJob::~EncodeJob() { |
| 1072 } | 1064 } |
| 1073 | 1065 |
| 1074 } // namespace content | 1066 } // namespace content |
| OLD | NEW |