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 3 // found in the LICENSE file. 4 5 #include "content/common/gpu/media/vaapi_video_encode_accelerator.h" 6 7 #include "base/bind.h" 8 #include "base/callback.h" 9 #include "base/command_line.h" 10 #include "base/message_loop/message_loop_proxy.h" 11 #include "base/metrics/histogram.h" 12 #include "base/numerics/safe_conversions.h" 13 #include "content/common/gpu/media/h264_dpb.h" 14 #include "content/public/common/content_switches.h" 15 #include "media/base/bind_to_current_loop.h" 16 #include "third_party/libva/va/va_enc_h264.h" 17 18 #define DVLOGF(level) DVLOG(level) << __FUNCTION__ << "(): " 19 20 #define NOTIFY_ERROR(error, msg) \ 21 do { \ 22 SetState(kError); \ 23 DVLOGF(1) << msg; \ 24 DVLOGF(1) << "Calling NotifyError(" << error << ")"; \ 25 NotifyError(error); \ 26 } while (0) 27 28 namespace content { 29 30 namespace { 31 // Need 2 surfaces for each frame: one for input data and one for 32 // reconstructed picture, which is later used for reference. 33 const size_t kMinSurfacesToEncode = 2; 34 35 // Subjectively chosen. 36 const size_t kNumInputBuffers = 4; 37 const size_t kMaxNumReferenceFrames = 4; 38 39 // We need up to kMaxNumReferenceFrames surfaces for reference, plus one 40 // for input and one for encode (which will be added to the set of reference 41 // frames for subsequent frames). Actual execution of HW encode is done 42 // in parallel, and we want to process more frames in the meantime. 43 // To have kNumInputBuffers in flight, we need a full set of reference + 44 // encode surfaces (i.e. kMaxNumReferenceFrames + kMinSurfacesToEncode), and 45 // (kNumInputBuffers - 1) of kMinSurfacesToEncode for the remaining frames 46 // in flight. 47 const size_t kNumSurfaces = kMaxNumReferenceFrames + kMinSurfacesToEncode + 48 kMinSurfacesToEncode * (kNumInputBuffers - 1); 49 50 // An IDR every 128 frames, an I frame every 30 and no B frames. 51 const int kIDRPeriod = 128; 52 const int kIPeriod = 30; 53 const int kIPPeriod = 1; 54 55 const int kDefaultFramerate = 30; 56 57 // HRD parameters (ch. E.2.2 in spec). 58 const int kBitRateScale = 0; // bit_rate_scale for SPS HRD parameters. 59 const int kCPBSizeScale = 0; // cpb_size_scale for SPS HRD parameters. 60 61 const int kDefaultQP = 26; 62 // All Intel codecs can do at least 4.1. 63 const int kDefaultLevelIDC = 41; 64 const int kChromaFormatIDC = 1; // 4:2:0 65 66 // Arbitrarily chosen bitrate window size for rate control, in ms. 67 const int kCPBWindowSizeMs = 1500; 68 69 // UMA errors that the VaapiVideoEncodeAccelerator class reports. 70 enum VAVEAEncoderFailure { 71 VAAPI_ERROR = 0, 72 VAVEA_ENCODER_FAILURES_MAX, 73 }; 74 75 } 76 77 // Round |value| up to |alignment|, which must be a power of 2. 78 static inline size_t RoundUpToPowerOf2(size_t value, size_t alignment) { 79 // Check that |alignment| is a power of 2. 80 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); 81 return ((value + (alignment - 1)) & ~(alignment - 1)); 82 } 83 84 static void ReportToUMA(VAVEAEncoderFailure failure) { 85 UMA_HISTOGRAM_ENUMERATION( 86 "Media.VAVEA.EncoderFailure", 87 failure, 88 VAVEA_ENCODER_FAILURES_MAX); 89 } 90 91 struct VaapiVideoEncodeAccelerator::InputFrameRef { 92 InputFrameRef(const scoped_refptr<media::VideoFrame>& frame, 93 bool force_keyframe) 94 : frame(frame), force_keyframe(force_keyframe) {} 95 const scoped_refptr<media::VideoFrame> frame; 96 const bool force_keyframe; 97 }; 98 99 struct VaapiVideoEncodeAccelerator::BitstreamBufferRef { 100 BitstreamBufferRef(int32 id, scoped_ptr<base::SharedMemory> shm, size_t size) 101 : id(id), shm(shm.Pass()), size(size) {} 102 const int32 id; 103 const scoped_ptr<base::SharedMemory> shm; 104 const size_t size; 105 }; 106 107 std::vector<media::VideoEncodeAccelerator::SupportedProfile> 108 VaapiVideoEncodeAccelerator::GetSupportedProfiles() { 109 std::vector<SupportedProfile> profiles; 110 111 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); 112 if (cmd_line->HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode)) 113 return profiles; 114 115 std::vector<media::VideoCodecProfile> hw_profiles = 116 VaapiWrapper::GetSupportedEncodeProfiles( 117 x_display_, base::Bind(&base::DoNothing)); 118 119 media::VideoEncodeAccelerator::SupportedProfile profile; 120 profile.max_resolution.SetSize(1920, 1088); 121 profile.max_framerate_numerator = kDefaultFramerate; 122 profile.max_framerate_denominator = 1; 123 for (size_t i = 0; i < hw_profiles.size(); i++) { 124 profile.profile = hw_profiles[i]; 125 profiles.push_back(profile); 126 } 127 return profiles; 128 } 129 130 static unsigned int Log2OfPowerOf2(unsigned int x) { 131 CHECK_GT(x, 0u); 132 DCHECK_EQ(x & (x - 1), 0u); 133 134 int log = 0; 135 while (x) { 136 x >>= 1; 137 ++log; 138 } 139 return log; 140 } 141 142 VaapiVideoEncodeAccelerator::VaapiVideoEncodeAccelerator(Display* x_display) 143 : profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), 144 mb_width_(0), 145 mb_height_(0), 146 output_buffer_byte_size_(0), 147 x_display_(x_display), 148 state_(kUninitialized), 149 frame_num_(0), 150 last_idr_frame_num_(0), 151 bitrate_(0), 152 framerate_(0), 153 cpb_size_(0), 154 encoding_parameters_changed_(false), 155 encoder_thread_("VAVEAEncoderThread"), 156 child_message_loop_proxy_(base::MessageLoopProxy::current()), 157 weak_this_ptr_factory_(this) { 158 DVLOGF(4); 159 weak_this_ = weak_this_ptr_factory_.GetWeakPtr(); 160 161 max_ref_idx_l0_size_ = kMaxNumReferenceFrames; 162 qp_ = kDefaultQP; 163 idr_period_ = kIDRPeriod; 164 i_period_ = kIPeriod; 165 ip_period_ = kIPPeriod; 166 } 167 168 VaapiVideoEncodeAccelerator::~VaapiVideoEncodeAccelerator() { 169 DVLOGF(4); 170 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); 171 DCHECK(!encoder_thread_.IsRunning()); 172 } 173 174 bool VaapiVideoEncodeAccelerator::Initialize( 175 media::VideoFrame::Format format, 176 const gfx::Size& input_visible_size, 177 media::VideoCodecProfile output_profile, 178 uint32 initial_bitrate, 179 Client* client) { 180 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); 181 DCHECK(!encoder_thread_.IsRunning()); 182 DCHECK_EQ(state_, kUninitialized); 183 184 DVLOGF(1) << "Initializing VAVEA, input_format: " 185 << media::VideoFrame::FormatToString(format) 186 << ", input_visible_size: " << input_visible_size.ToString() 187 << ", output_profile: " << output_profile 188 << ", initial_bitrate: " << initial_bitrate; 189 190 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); 191 client_ = client_ptr_factory_->GetWeakPtr(); 192 193 if (output_profile < media::H264PROFILE_BASELINE || 194 output_profile > media::H264PROFILE_MAIN) { 195 DVLOGF(1) << "Unsupported output profile: " << output_profile; 196 return false; 197 } 198 199 if (format != media::VideoFrame::I420) { 200 DVLOGF(1) << "Unsupported input format: " 201 << media::VideoFrame::FormatToString(format); 202 return false; 203 } 204 205 profile_ = output_profile; 206 visible_size_ = input_visible_size; 207 // 4:2:0 format has to be 2-aligned. 208 DCHECK_EQ(visible_size_.width() % 2, 0); 209 DCHECK_EQ(visible_size_.height() % 2, 0); 210 coded_size_ = gfx::Size(RoundUpToPowerOf2(visible_size_.width(), 16), 211 RoundUpToPowerOf2(visible_size_.height(), 16)); 212 mb_width_ = coded_size_.width() / 16; 213 mb_height_ = coded_size_.height() / 16; 214 output_buffer_byte_size_ = coded_size_.GetArea(); 215 216 UpdateRates(initial_bitrate, kDefaultFramerate); 217 218 vaapi_wrapper_ = VaapiWrapper::Create(VaapiWrapper::kEncode, 219 output_profile, 220 x_display_, 221 base::Bind(&ReportToUMA, VAAPI_ERROR)); 222 if (!vaapi_wrapper_) { 223 DVLOGF(1) << "Failed initializing VAAPI"; 224 return false; 225 } 226 227 if (!encoder_thread_.Start()) { 228 DVLOGF(1) << "Failed to start encoder thread"; 229 return false; 230 } 231 encoder_thread_proxy_ = encoder_thread_.message_loop_proxy(); 232 233 // Finish the remaining initialization on the encoder thread. 234 encoder_thread_proxy_->PostTask( 235 FROM_HERE, 236 base::Bind(&VaapiVideoEncodeAccelerator::InitializeTask, 237 base::Unretained(this))); 238 239 return true; 240 } 241 242 void VaapiVideoEncodeAccelerator::InitializeTask() { 243 DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); 244 DCHECK_EQ(state_, kUninitialized); 245 DVLOGF(4); 246 247 va_surface_release_cb_ = media::BindToCurrentLoop( 248 base::Bind(&VaapiVideoEncodeAccelerator::RecycleVASurfaceID, 249 base::Unretained(this))); 250 251 if (!vaapi_wrapper_->CreateSurfaces( 252 coded_size_, kNumSurfaces, &available_va_surface_ids_)) { 253 NOTIFY_ERROR(kPlatformFailureError, "Failed creating VASurfaces"); 254 return; 255 } 256 257 UpdateSPS(); 258 GeneratePackedSPS(); 259 260 UpdatePPS(); 261 GeneratePackedPPS(); 262 263 child_message_loop_proxy_->PostTask( 264 FROM_HERE, 265 base::Bind(&Client::RequireBitstreamBuffers, 266 client_, 267 kNumInputBuffers, 268 coded_size_, 269 output_buffer_byte_size_)); 270 271 SetState(kEncoding); 272 } 273 274 void VaapiVideoEncodeAccelerator::RecycleVASurfaceID( 275 VASurfaceID va_surface_id) { 276 DVLOGF(4) << "va_surface_id: " << va_surface_id; 277 DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); 278 279 available_va_surface_ids_.push_back(va_surface_id); 280 EncodeFrameTask(); 281 } 282 283 void VaapiVideoEncodeAccelerator::BeginFrame(bool force_keyframe) { 284 memset(¤t_pic_, 0, sizeof(current_pic_)); 285 286 current_pic_.frame_num = frame_num_++; 287 frame_num_ %= idr_period_; 288 289 if (current_pic_.frame_num % i_period_ == 0 || force_keyframe) 290 current_pic_.type = media::H264SliceHeader::kISlice; 291 else 292 current_pic_.type = media::H264SliceHeader::kPSlice; 293 294 if (current_pic_.frame_num % idr_period_ == 0) { 295 current_pic_.idr = true; 296 last_idr_frame_num_ = current_pic_.frame_num; 297 ref_pic_list0_.clear(); 298 } 299 300 if (current_pic_.type != media::H264SliceHeader::kBSlice) 301 current_pic_.ref = true; 302 303 current_pic_.pic_order_cnt = current_pic_.frame_num * 2; 304 current_pic_.top_field_order_cnt = current_pic_.pic_order_cnt; 305 current_pic_.pic_order_cnt_lsb = current_pic_.pic_order_cnt; 306 307 current_encode_job_->keyframe = 308 (current_pic_.type == media::H264SliceHeader::kISlice); 309 310 DVLOGF(4) << "Starting a new frame, type: " << current_pic_.type 311 << (force_keyframe ? " (forced keyframe)" : "") 312 << " frame_num: " << current_pic_.frame_num 313 << " POC: " << current_pic_.pic_order_cnt; 314 } 315 316 void VaapiVideoEncodeAccelerator::EndFrame() { 317 // Store the picture on the list of reference pictures and keep the list 318 // below maximum size, dropping oldest references. 319 if (current_pic_.ref) 320 ref_pic_list0_.push_front(current_encode_job_->recon_surface); 321 size_t max_num_ref_frames = 322 base::checked_cast<size_t>(current_sps_.max_num_ref_frames); 323 while (ref_pic_list0_.size() > max_num_ref_frames) 324 ref_pic_list0_.pop_back(); 325 326 submitted_encode_jobs_.push(make_linked_ptr(current_encode_job_.release())); 327 } 328 329 static void InitVAPicture(VAPictureH264* va_pic) { 330 memset(va_pic, 0, sizeof(*va_pic)); 331 va_pic->picture_id = VA_INVALID_ID; 332 va_pic->flags = VA_PICTURE_H264_INVALID; 333 } 334 335 bool VaapiVideoEncodeAccelerator::SubmitFrameParameters() { 336 VAEncSequenceParameterBufferH264 seq_param; 337 memset(&seq_param, 0, sizeof(seq_param)); 338 339 #define SPS_TO_SP(a) seq_param.a = current_sps_.a; 340 SPS_TO_SP(seq_parameter_set_id); 341 SPS_TO_SP(level_idc); 342 343 seq_param.intra_period = i_period_; 344 seq_param.intra_idr_period = idr_period_; 345 seq_param.ip_period = ip_period_; 346 seq_param.bits_per_second = bitrate_; 347 348 SPS_TO_SP(max_num_ref_frames); 349 seq_param.picture_width_in_mbs = mb_width_; 350 seq_param.picture_height_in_mbs = mb_height_; 351 352 #define SPS_TO_SP_FS(a) seq_param.seq_fields.bits.a = current_sps_.a; 353 SPS_TO_SP_FS(chroma_format_idc); 354 SPS_TO_SP_FS(frame_mbs_only_flag); 355 SPS_TO_SP_FS(log2_max_frame_num_minus4); 356 SPS_TO_SP_FS(pic_order_cnt_type); 357 SPS_TO_SP_FS(log2_max_pic_order_cnt_lsb_minus4); 358 #undef SPS_TO_SP_FS 359 360 SPS_TO_SP(bit_depth_luma_minus8); 361 SPS_TO_SP(bit_depth_chroma_minus8); 362 363 SPS_TO_SP(frame_cropping_flag); 364 if (current_sps_.frame_cropping_flag) { 365 SPS_TO_SP(frame_crop_left_offset); 366 SPS_TO_SP(frame_crop_right_offset); 367 SPS_TO_SP(frame_crop_top_offset); 368 SPS_TO_SP(frame_crop_bottom_offset); 369 } 370 371 SPS_TO_SP(vui_parameters_present_flag); 372 #define SPS_TO_SP_VF(a) seq_param.vui_fields.bits.a = current_sps_.a; 373 SPS_TO_SP_VF(timing_info_present_flag); 374 #undef SPS_TO_SP_VF 375 SPS_TO_SP(num_units_in_tick); 376 SPS_TO_SP(time_scale); 377 #undef SPS_TO_SP 378 379 if (!vaapi_wrapper_->SubmitBuffer(VAEncSequenceParameterBufferType, 380 sizeof(seq_param), 381 &seq_param)) 382 return false; 383 384 VAEncPictureParameterBufferH264 pic_param; 385 memset(&pic_param, 0, sizeof(pic_param)); 386 387 pic_param.CurrPic.picture_id = current_encode_job_->recon_surface->id(); 388 pic_param.CurrPic.TopFieldOrderCnt = current_pic_.top_field_order_cnt; 389 pic_param.CurrPic.BottomFieldOrderCnt = current_pic_.bottom_field_order_cnt; 390 pic_param.CurrPic.flags = 0; 391 392 for (size_t i = 0; i < arraysize(pic_param.ReferenceFrames); ++i) 393 InitVAPicture(&pic_param.ReferenceFrames[i]); 394 395 DCHECK_LE(ref_pic_list0_.size(), arraysize(pic_param.ReferenceFrames)); 396 RefPicList::const_iterator iter = ref_pic_list0_.begin(); 397 for (size_t i = 0; 398 i < arraysize(pic_param.ReferenceFrames) && iter != ref_pic_list0_.end(); 399 ++iter, ++i) { 400 pic_param.ReferenceFrames[i].picture_id = (*iter)->id(); 401 pic_param.ReferenceFrames[i].flags = 0; 402 } 403 404 pic_param.coded_buf = current_encode_job_->coded_buffer; 405 pic_param.pic_parameter_set_id = current_pps_.pic_parameter_set_id; 406 pic_param.seq_parameter_set_id = current_pps_.seq_parameter_set_id; 407 pic_param.frame_num = current_pic_.frame_num; 408 pic_param.pic_init_qp = qp_; 409 pic_param.num_ref_idx_l0_active_minus1 = max_ref_idx_l0_size_ - 1; 410 pic_param.pic_fields.bits.idr_pic_flag = current_pic_.idr; 411 pic_param.pic_fields.bits.reference_pic_flag = current_pic_.ref; 412 #define PPS_TO_PP_PF(a) pic_param.pic_fields.bits.a = current_pps_.a; 413 PPS_TO_PP_PF(entropy_coding_mode_flag); 414 PPS_TO_PP_PF(transform_8x8_mode_flag); 415 PPS_TO_PP_PF(deblocking_filter_control_present_flag); 416 #undef PPS_TO_PP_PF 417 418 if (!vaapi_wrapper_->SubmitBuffer(VAEncPictureParameterBufferType, 419 sizeof(pic_param), 420 &pic_param)) 421 return false; 422 423 VAEncSliceParameterBufferH264 slice_param; 424 memset(&slice_param, 0, sizeof(slice_param)); 425 426 slice_param.num_macroblocks = mb_width_ * mb_height_; 427 slice_param.macroblock_info = VA_INVALID_ID; 428 slice_param.slice_type = current_pic_.type; 429 slice_param.pic_parameter_set_id = current_pps_.pic_parameter_set_id; 430 slice_param.idr_pic_id = last_idr_frame_num_; 431 slice_param.pic_order_cnt_lsb = current_pic_.pic_order_cnt_lsb; 432 slice_param.num_ref_idx_active_override_flag = true; 433 434 for (size_t i = 0; i < arraysize(slice_param.RefPicList0); ++i) 435 InitVAPicture(&slice_param.RefPicList0[i]); 436 437 for (size_t i = 0; i < arraysize(slice_param.RefPicList1); ++i) 438 InitVAPicture(&slice_param.RefPicList1[i]); 439 440 DCHECK_LE(ref_pic_list0_.size(), arraysize(slice_param.RefPicList0)); 441 iter = ref_pic_list0_.begin(); 442 for (size_t i = 0; 443 i < arraysize(slice_param.RefPicList0) && iter != ref_pic_list0_.end(); 444 ++iter, ++i) { 445 InitVAPicture(&slice_param.RefPicList0[i]); 446 slice_param.RefPicList0[i].picture_id = (*iter)->id(); 447 slice_param.RefPicList0[i].flags = 0; 448 } 449 450 if (!vaapi_wrapper_->SubmitBuffer(VAEncSliceParameterBufferType, 451 sizeof(slice_param), 452 &slice_param)) 453 return false; 454 455 VAEncMiscParameterRateControl rate_control_param; 456 memset(&rate_control_param, 0, sizeof(rate_control_param)); 457 rate_control_param.bits_per_second = bitrate_; 458 rate_control_param.target_percentage = 90; 459 rate_control_param.window_size = kCPBWindowSizeMs; 460 rate_control_param.initial_qp = qp_; 461 rate_control_param.rc_flags.bits.disable_frame_skip = true; 462 463 if (!vaapi_wrapper_->SubmitVAEncMiscParamBuffer( 464 VAEncMiscParameterTypeRateControl, 465 sizeof(rate_control_param), 466 &rate_control_param)) 467 return false; 468 469 VAEncMiscParameterFrameRate framerate_param; 470 memset(&framerate_param, 0, sizeof(framerate_param)); 471 framerate_param.framerate = framerate_; 472 if (!vaapi_wrapper_->SubmitVAEncMiscParamBuffer( 473 VAEncMiscParameterTypeFrameRate, 474 sizeof(framerate_param), 475 &framerate_param)) 476 return false; 477 478 VAEncMiscParameterHRD hrd_param; 479 memset(&hrd_param, 0, sizeof(hrd_param)); 480 hrd_param.buffer_size = cpb_size_; 481 hrd_param.initial_buffer_fullness = cpb_size_ / 2; 482 if (!vaapi_wrapper_->SubmitVAEncMiscParamBuffer(VAEncMiscParameterTypeHRD, 483 sizeof(hrd_param), 484 &hrd_param)) 485 return false; 486 487 return true; 488 } 489 490 bool VaapiVideoEncodeAccelerator::SubmitHeadersIfNeeded() { 491 if (current_pic_.type != media::H264SliceHeader::kISlice) 492 return true; 493 494 // Submit PPS. 495 VAEncPackedHeaderParameterBuffer par_buffer; 496 memset(&par_buffer, 0, sizeof(par_buffer)); 497 par_buffer.type = VAEncPackedHeaderSequence; 498 par_buffer.bit_length = packed_sps_.BytesInBuffer() * 8; 499 500 if (!vaapi_wrapper_->SubmitBuffer(VAEncPackedHeaderParameterBufferType, 501 sizeof(par_buffer), 502 &par_buffer)) 503 return false; 504 505 if (!vaapi_wrapper_->SubmitBuffer(VAEncPackedHeaderDataBufferType, 506 packed_sps_.BytesInBuffer(), 507 packed_sps_.data())) 508 return false; 509 510 // Submit PPS. 511 memset(&par_buffer, 0, sizeof(par_buffer)); 512 par_buffer.type = VAEncPackedHeaderPicture; 513 par_buffer.bit_length = packed_pps_.BytesInBuffer() * 8; 514 515 if (!vaapi_wrapper_->SubmitBuffer(VAEncPackedHeaderParameterBufferType, 516 sizeof(par_buffer), 517 &par_buffer)) 518 return false; 519 520 if (!vaapi_wrapper_->SubmitBuffer(VAEncPackedHeaderDataBufferType, 521 packed_pps_.BytesInBuffer(), 522 packed_pps_.data())) 523 return false; 524 525 return true; 526 } 527 528 bool VaapiVideoEncodeAccelerator::ExecuteEncode() { 529 DVLOGF(3) << "Encoding frame_num: " << current_pic_.frame_num; 530 return vaapi_wrapper_->ExecuteAndDestroyPendingBuffers( 531 current_encode_job_->input_surface->id()); 532 } 533 534 bool VaapiVideoEncodeAccelerator::UploadFrame( 535 const scoped_refptr<media::VideoFrame>& frame) { 536 return vaapi_wrapper_->UploadVideoFrameToSurface( 537 frame, current_encode_job_->input_surface->id()); 538 } 539 540 void VaapiVideoEncodeAccelerator::TryToReturnBitstreamBuffer() { 541 DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); 542 543 if (state_ != kEncoding) 544 return; 545 546 if (submitted_encode_jobs_.empty() || available_bitstream_buffers_.empty()) 547 return; 548 549 linked_ptr<BitstreamBufferRef> buffer = available_bitstream_buffers_.front(); 550 available_bitstream_buffers_.pop(); 551 552 uint8* target_data = reinterpret_cast<uint8*>(buffer->shm->memory()); 553 554 linked_ptr<EncodeJob> encode_job = submitted_encode_jobs_.front(); 555 submitted_encode_jobs_.pop(); 556 557 size_t data_size = 0; 558 if (!vaapi_wrapper_->DownloadAndDestroyCodedBuffer( 559 encode_job->coded_buffer, 560 encode_job->input_surface->id(), 561 target_data, 562 buffer->size, 563 &data_size)) { 564 NOTIFY_ERROR(kPlatformFailureError, "Failed downloading coded buffer"); 565 return; 566 } 567 568 DVLOGF(3) << "Returning bitstream buffer " 569 << (encode_job->keyframe ? "(keyframe)" : "") 570 << " id: " << buffer->id << " size: " << data_size; 571 572 child_message_loop_proxy_->PostTask(FROM_HERE, 573 base::Bind(&Client::BitstreamBufferReady, 574 client_, 575 buffer->id, 576 data_size, 577 encode_job->keyframe)); 578 } 579 580 void VaapiVideoEncodeAccelerator::Encode( 581 const scoped_refptr<media::VideoFrame>& frame, 582 bool force_keyframe) { 583 DVLOGF(3) << "Frame timestamp: " << frame->timestamp().InMilliseconds() 584 << " force_keyframe: " << force_keyframe; 585 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); 586 587 encoder_thread_proxy_->PostTask( 588 FROM_HERE, 589 base::Bind(&VaapiVideoEncodeAccelerator::EncodeTask, 590 base::Unretained(this), 591 frame, 592 force_keyframe)); 593 } 594 595 bool VaapiVideoEncodeAccelerator::PrepareNextJob() { 596 if (available_va_surface_ids_.size() < kMinSurfacesToEncode) 597 return false; 598 599 DCHECK(!current_encode_job_); 600 current_encode_job_.reset(new EncodeJob()); 601 602 if (!vaapi_wrapper_->CreateCodedBuffer(output_buffer_byte_size_, 603 ¤t_encode_job_->coded_buffer)) { 604 NOTIFY_ERROR(kPlatformFailureError, "Failed creating coded buffer"); 605 return false; 606 } 607 608 current_encode_job_->input_surface = 609 new VASurface(available_va_surface_ids_.back(), va_surface_release_cb_); 610 available_va_surface_ids_.pop_back(); 611 612 current_encode_job_->recon_surface = 613 new VASurface(available_va_surface_ids_.back(), va_surface_release_cb_); 614 available_va_surface_ids_.pop_back(); 615 616 // Reference surfaces are needed until the job is done, but they get 617 // removed from ref_pic_list0_ when it's full at the end of job submission. 618 // Keep refs to them along with the job and only release after sync. 619 current_encode_job_->reference_surfaces = ref_pic_list0_; 620 621 return true; 622 } 623 624 void VaapiVideoEncodeAccelerator::EncodeTask( 625 const scoped_refptr<media::VideoFrame>& frame, 626 bool force_keyframe) { 627 DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); 628 DCHECK_NE(state_, kUninitialized); 629 630 encoder_input_queue_.push( 631 make_linked_ptr(new InputFrameRef(frame, force_keyframe))); 632 EncodeFrameTask(); 633 } 634 635 void VaapiVideoEncodeAccelerator::EncodeFrameTask() { 636 DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); 637 638 if (state_ != kEncoding || encoder_input_queue_.empty()) 639 return; 640 641 if (!PrepareNextJob()) { 642 DVLOGF(4) << "Not ready for next frame yet"; 643 return; 644 } 645 646 linked_ptr<InputFrameRef> frame_ref = encoder_input_queue_.front(); 647 encoder_input_queue_.pop(); 648 649 if (!UploadFrame(frame_ref->frame)) { 650 NOTIFY_ERROR(kPlatformFailureError, "Failed uploading source frame to HW."); 651 return; 652 } 653 654 BeginFrame(frame_ref->force_keyframe || encoding_parameters_changed_); 655 encoding_parameters_changed_ = false; 656 657 if (!SubmitFrameParameters()) { 658 NOTIFY_ERROR(kPlatformFailureError, "Failed submitting frame parameters."); 659 return; 660 } 661 662 if (!SubmitHeadersIfNeeded()) { 663 NOTIFY_ERROR(kPlatformFailureError, "Failed submitting frame headers."); 664 return; 665 } 666 667 if (!ExecuteEncode()) { 668 NOTIFY_ERROR(kPlatformFailureError, "Failed submitting encode job to HW."); 669 return; 670 } 671 672 EndFrame(); 673 TryToReturnBitstreamBuffer(); 674 } 675 676 void VaapiVideoEncodeAccelerator::UseOutputBitstreamBuffer( 677 const media::BitstreamBuffer& buffer) { 678 DVLOGF(4) << "id: " << buffer.id(); 679 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); 680 681 if (buffer.size() < output_buffer_byte_size_) { 682 NOTIFY_ERROR(kInvalidArgumentError, "Provided bitstream buffer too small"); 683 return; 684 } 685 686 scoped_ptr<base::SharedMemory> shm( 687 new base::SharedMemory(buffer.handle(), false)); 688 if (!shm->Map(buffer.size())) { 689 NOTIFY_ERROR(kPlatformFailureError, "Failed mapping shared memory."); 690 return; 691 } 692 693 scoped_ptr<BitstreamBufferRef> buffer_ref( 694 new BitstreamBufferRef(buffer.id(), shm.Pass(), buffer.size())); 695 696 encoder_thread_proxy_->PostTask( 697 FROM_HERE, 698 base::Bind(&VaapiVideoEncodeAccelerator::UseOutputBitstreamBufferTask, 699 base::Unretained(this), 700 base::Passed(&buffer_ref))); 701 } 702 703 void VaapiVideoEncodeAccelerator::UseOutputBitstreamBufferTask( 704 scoped_ptr<BitstreamBufferRef> buffer_ref) { 705 DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); 706 DCHECK_NE(state_, kUninitialized); 707 708 available_bitstream_buffers_.push(make_linked_ptr(buffer_ref.release())); 709 TryToReturnBitstreamBuffer(); 710 } 711 712 void VaapiVideoEncodeAccelerator::RequestEncodingParametersChange( 713 uint32 bitrate, 714 uint32 framerate) { 715 DVLOGF(2) << "bitrate: " << bitrate << " framerate: " << framerate; 716 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); 717 718 encoder_thread_proxy_->PostTask( 719 FROM_HERE, 720 base::Bind( 721 &VaapiVideoEncodeAccelerator::RequestEncodingParametersChangeTask, 722 base::Unretained(this), 723 bitrate, 724 framerate)); 725 } 726 727 void VaapiVideoEncodeAccelerator::UpdateRates(uint32 bitrate, 728 uint32 framerate) { 729 if (encoder_thread_.IsRunning()) 730 DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); 731 DCHECK_NE(bitrate, 0u); 732 DCHECK_NE(framerate, 0u); 733 bitrate_ = bitrate; 734 framerate_ = framerate; 735 cpb_size_ = bitrate_ * kCPBWindowSizeMs / 1000; 736 } 737 738 void VaapiVideoEncodeAccelerator::RequestEncodingParametersChangeTask( 739 uint32 bitrate, 740 uint32 framerate) { 741 DVLOGF(2) << "bitrate: " << bitrate << " framerate: " << framerate; 742 DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); 743 DCHECK_NE(state_, kUninitialized); 744 745 // This is a workaround to zero being temporarily, as part of the initial 746 // setup, provided by the webrtc video encode and a zero bitrate and 747 // framerate not being accepted by VAAPI 748 // TODO: This code is common with v4l2_video_encode_accelerator.cc, perhaps 749 // it could be pulled up to RTCVideoEncoder 750 if (bitrate < 1) 751 bitrate = 1; 752 if (framerate < 1) 753 framerate = 1; 754 755 UpdateRates(bitrate, framerate); 756 757 UpdateSPS(); 758 GeneratePackedSPS(); 759 760 // Submit new parameters along with next frame that will be processed. 761 encoding_parameters_changed_ = true; 762 } 763 764 void VaapiVideoEncodeAccelerator::Destroy() { 765 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); 766 767 // Can't call client anymore after Destroy() returns. 768 client_ptr_factory_.reset(); 769 weak_this_ptr_factory_.InvalidateWeakPtrs(); 770 771 // Early-exit encoder tasks if they are running and join the thread. 772 if (encoder_thread_.IsRunning()) { 773 encoder_thread_.message_loop()->PostTask( 774 FROM_HERE, 775 base::Bind(&VaapiVideoEncodeAccelerator::DestroyTask, 776 base::Unretained(this))); 777 encoder_thread_.Stop(); 778 } 779 780 delete this; 781 } 782 783 void VaapiVideoEncodeAccelerator::DestroyTask() { 784 DVLOGF(2); 785 DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); 786 SetState(kError); 787 } 788 789 void VaapiVideoEncodeAccelerator::UpdateSPS() { 790 memset(¤t_sps_, 0, sizeof(media::H264SPS)); 791 792 // Spec A.2 and A.3. 793 switch (profile_) { 794 case media::H264PROFILE_BASELINE: 795 // Due to crbug.com/345569, we don't distinguish between constrained 796 // and non-constrained baseline profiles. Since many codecs can't do 797 // non-constrained, and constrained is usually what we mean (and it's a 798 // subset of non-constrained), default to it. 799 current_sps_.profile_idc = media::H264SPS::kProfileIDCBaseline; 800 current_sps_.constraint_set0_flag = true; 801 break; 802 case media::H264PROFILE_MAIN: 803 current_sps_.profile_idc = media::H264SPS::kProfileIDCMain; 804 current_sps_.constraint_set1_flag = true; 805 break; 806 case media::H264PROFILE_HIGH: 807 current_sps_.profile_idc = media::H264SPS::kProfileIDCHigh; 808 break; 809 default: 810 NOTIMPLEMENTED(); 811 return; 812 } 813 814 current_sps_.level_idc = kDefaultLevelIDC; 815 current_sps_.seq_parameter_set_id = 0; 816 current_sps_.chroma_format_idc = kChromaFormatIDC; 817 818 DCHECK_GE(idr_period_, 1u << 4); 819 current_sps_.log2_max_frame_num_minus4 = Log2OfPowerOf2(idr_period_) - 4; 820 current_sps_.pic_order_cnt_type = 0; 821 current_sps_.log2_max_pic_order_cnt_lsb_minus4 = 822 Log2OfPowerOf2(idr_period_ * 2) - 4; 823 current_sps_.max_num_ref_frames = max_ref_idx_l0_size_; 824 825 current_sps_.frame_mbs_only_flag = true; 826 827 DCHECK_GT(mb_width_, 0u); 828 DCHECK_GT(mb_height_, 0u); 829 current_sps_.pic_width_in_mbs_minus1 = mb_width_ - 1; 830 DCHECK(current_sps_.frame_mbs_only_flag); 831 current_sps_.pic_height_in_map_units_minus1 = mb_height_ - 1; 832 833 if (visible_size_ != coded_size_) { 834 // Visible size differs from coded size, fill crop information. 835 current_sps_.frame_cropping_flag = true; 836 DCHECK(!current_sps_.separate_colour_plane_flag); 837 // Spec table 6-1. Only 4:2:0 for now. 838 DCHECK_EQ(current_sps_.chroma_format_idc, 1); 839 // Spec 7.4.2.1.1. Crop is in crop units, which is 2 pixels for 4:2:0. 840 const unsigned int crop_unit_x = 2; 841 const unsigned int crop_unit_y = 2 * (2 - current_sps_.frame_mbs_only_flag); 842 current_sps_.frame_crop_left_offset = 0; 843 current_sps_.frame_crop_right_offset = 844 (coded_size_.width() - visible_size_.width()) / crop_unit_x; 845 current_sps_.frame_crop_top_offset = 0; 846 current_sps_.frame_crop_bottom_offset = 847 (coded_size_.height() - visible_size_.height()) / crop_unit_y; 848 } 849 850 current_sps_.vui_parameters_present_flag = true; 851 current_sps_.timing_info_present_flag = true; 852 current_sps_.num_units_in_tick = 1; 853 current_sps_.time_scale = framerate_ * 2; // See equation D-2 in spec. 854 current_sps_.fixed_frame_rate_flag = true; 855 856 current_sps_.nal_hrd_parameters_present_flag = true; 857 // H.264 spec ch. E.2.2. 858 current_sps_.cpb_cnt_minus1 = 0; 859 current_sps_.bit_rate_scale = kBitRateScale; 860 current_sps_.cpb_size_scale = kCPBSizeScale; 861 current_sps_.bit_rate_value_minus1[0] = 862 (bitrate_ >> 863 (kBitRateScale + media::H264SPS::kBitRateScaleConstantTerm)) - 1; 864 current_sps_.cpb_size_value_minus1[0] = 865 (cpb_size_ >> 866 (kCPBSizeScale + media::H264SPS::kCPBSizeScaleConstantTerm)) - 1; 867 current_sps_.cbr_flag[0] = true; 868 current_sps_.initial_cpb_removal_delay_length_minus_1 = 869 media::H264SPS::kDefaultInitialCPBRemovalDelayLength - 1; 870 current_sps_.cpb_removal_delay_length_minus1 = 871 media::H264SPS::kDefaultInitialCPBRemovalDelayLength - 1; 872 current_sps_.dpb_output_delay_length_minus1 = 873 media::H264SPS::kDefaultDPBOutputDelayLength - 1; 874 current_sps_.time_offset_length = media::H264SPS::kDefaultTimeOffsetLength; 875 current_sps_.low_delay_hrd_flag = false; 876 } 877 878 void VaapiVideoEncodeAccelerator::GeneratePackedSPS() { 879 packed_sps_.Reset(); 880 881 packed_sps_.BeginNALU(media::H264NALU::kSPS, 3); 882 883 packed_sps_.AppendBits(8, current_sps_.profile_idc); 884 packed_sps_.AppendBool(current_sps_.constraint_set0_flag); 885 packed_sps_.AppendBool(current_sps_.constraint_set1_flag); 886 packed_sps_.AppendBool(current_sps_.constraint_set2_flag); 887 packed_sps_.AppendBool(current_sps_.constraint_set3_flag); 888 packed_sps_.AppendBool(current_sps_.constraint_set4_flag); 889 packed_sps_.AppendBool(current_sps_.constraint_set5_flag); 890 packed_sps_.AppendBits(2, 0); // reserved_zero_2bits 891 packed_sps_.AppendBits(8, current_sps_.level_idc); 892 packed_sps_.AppendUE(current_sps_.seq_parameter_set_id); 893 894 if (current_sps_.profile_idc == media::H264SPS::kProfileIDCHigh) { 895 packed_sps_.AppendUE(current_sps_.chroma_format_idc); 896 if (current_sps_.chroma_format_idc == 3) 897 packed_sps_.AppendBool(current_sps_.separate_colour_plane_flag); 898 packed_sps_.AppendUE(current_sps_.bit_depth_luma_minus8); 899 packed_sps_.AppendUE(current_sps_.bit_depth_chroma_minus8); 900 packed_sps_.AppendBool(current_sps_.qpprime_y_zero_transform_bypass_flag); 901 packed_sps_.AppendBool(current_sps_.seq_scaling_matrix_present_flag); 902 CHECK(!current_sps_.seq_scaling_matrix_present_flag); 903 } 904 905 packed_sps_.AppendUE(current_sps_.log2_max_frame_num_minus4); 906 packed_sps_.AppendUE(current_sps_.pic_order_cnt_type); 907 if (current_sps_.pic_order_cnt_type == 0) 908 packed_sps_.AppendUE(current_sps_.log2_max_pic_order_cnt_lsb_minus4); 909 else if (current_sps_.pic_order_cnt_type == 1) { 910 CHECK(1); 911 } 912 913 packed_sps_.AppendUE(current_sps_.max_num_ref_frames); 914 packed_sps_.AppendBool(current_sps_.gaps_in_frame_num_value_allowed_flag); 915 packed_sps_.AppendUE(current_sps_.pic_width_in_mbs_minus1); 916 packed_sps_.AppendUE(current_sps_.pic_height_in_map_units_minus1); 917 918 packed_sps_.AppendBool(current_sps_.frame_mbs_only_flag); 919 if (!current_sps_.frame_mbs_only_flag) 920 packed_sps_.AppendBool(current_sps_.mb_adaptive_frame_field_flag); 921 922 packed_sps_.AppendBool(current_sps_.direct_8x8_inference_flag); 923 924 packed_sps_.AppendBool(current_sps_.frame_cropping_flag); 925 if (current_sps_.frame_cropping_flag) { 926 packed_sps_.AppendUE(current_sps_.frame_crop_left_offset); 927 packed_sps_.AppendUE(current_sps_.frame_crop_right_offset); 928 packed_sps_.AppendUE(current_sps_.frame_crop_top_offset); 929 packed_sps_.AppendUE(current_sps_.frame_crop_bottom_offset); 930 } 931 932 packed_sps_.AppendBool(current_sps_.vui_parameters_present_flag); 933 if (current_sps_.vui_parameters_present_flag) { 934 packed_sps_.AppendBool(false); // aspect_ratio_info_present_flag 935 packed_sps_.AppendBool(false); // overscan_info_present_flag 936 packed_sps_.AppendBool(false); // video_signal_type_present_flag 937 packed_sps_.AppendBool(false); // chroma_loc_info_present_flag 938 939 packed_sps_.AppendBool(current_sps_.timing_info_present_flag); 940 if (current_sps_.timing_info_present_flag) { 941 packed_sps_.AppendBits(32, current_sps_.num_units_in_tick); 942 packed_sps_.AppendBits(32, current_sps_.time_scale); 943 packed_sps_.AppendBool(current_sps_.fixed_frame_rate_flag); 944 } 945 946 packed_sps_.AppendBool(current_sps_.nal_hrd_parameters_present_flag); 947 if (current_sps_.nal_hrd_parameters_present_flag) { 948 packed_sps_.AppendUE(current_sps_.cpb_cnt_minus1); 949 packed_sps_.AppendBits(4, current_sps_.bit_rate_scale); 950 packed_sps_.AppendBits(4, current_sps_.cpb_size_scale); 951 CHECK_LT(base::checked_cast<size_t>(current_sps_.cpb_cnt_minus1), 952 arraysize(current_sps_.bit_rate_value_minus1)); 953 for (int i = 0; i <= current_sps_.cpb_cnt_minus1; ++i) { 954 packed_sps_.AppendUE(current_sps_.bit_rate_value_minus1[i]); 955 packed_sps_.AppendUE(current_sps_.cpb_size_value_minus1[i]); 956 packed_sps_.AppendBool(current_sps_.cbr_flag[i]); 957 } 958 packed_sps_.AppendBits( 959 5, current_sps_.initial_cpb_removal_delay_length_minus_1); 960 packed_sps_.AppendBits(5, current_sps_.cpb_removal_delay_length_minus1); 961 packed_sps_.AppendBits(5, current_sps_.dpb_output_delay_length_minus1); 962 packed_sps_.AppendBits(5, current_sps_.time_offset_length); 963 } 964 965 packed_sps_.AppendBool(false); // vcl_hrd_parameters_flag 966 if (current_sps_.nal_hrd_parameters_present_flag) 967 packed_sps_.AppendBool(current_sps_.low_delay_hrd_flag); 968 969 packed_sps_.AppendBool(false); // pic_struct_present_flag 970 packed_sps_.AppendBool(false); // bitstream_restriction_flag 971 } 972 973 packed_sps_.FinishNALU(); 974 } 975 976 void VaapiVideoEncodeAccelerator::UpdatePPS() { 977 memset(¤t_pps_, 0, sizeof(media::H264PPS)); 978 979 current_pps_.seq_parameter_set_id = current_sps_.seq_parameter_set_id; 980 current_pps_.pic_parameter_set_id = 0; 981 982 current_pps_.entropy_coding_mode_flag = 983 current_sps_.profile_idc >= media::H264SPS::kProfileIDCMain; 984 985 CHECK_GT(max_ref_idx_l0_size_, 0u); 986 current_pps_.num_ref_idx_l0_default_active_minus1 = max_ref_idx_l0_size_ - 1; 987 current_pps_.num_ref_idx_l1_default_active_minus1 = 0; 988 DCHECK_LE(qp_, 51u); 989 current_pps_.pic_init_qp_minus26 = qp_ - 26; 990 current_pps_.deblocking_filter_control_present_flag = true; 991 current_pps_.transform_8x8_mode_flag = 992 (current_sps_.profile_idc == media::H264SPS::kProfileIDCHigh); 993 } 994 995 void VaapiVideoEncodeAccelerator::GeneratePackedPPS() { 996 packed_pps_.Reset(); 997 998 packed_pps_.BeginNALU(media::H264NALU::kPPS, 3); 999 1000 packed_pps_.AppendUE(current_pps_.pic_parameter_set_id); 1001 packed_pps_.AppendUE(current_pps_.seq_parameter_set_id); 1002 packed_pps_.AppendBool(current_pps_.entropy_coding_mode_flag); 1003 packed_pps_.AppendBool( 1004 current_pps_.bottom_field_pic_order_in_frame_present_flag); 1005 CHECK_EQ(current_pps_.num_slice_groups_minus1, 0); 1006 packed_pps_.AppendUE(current_pps_.num_slice_groups_minus1); 1007 1008 packed_pps_.AppendUE(current_pps_.num_ref_idx_l0_default_active_minus1); 1009 packed_pps_.AppendUE(current_pps_.num_ref_idx_l1_default_active_minus1); 1010 1011 packed_pps_.AppendBool(current_pps_.weighted_pred_flag); 1012 packed_pps_.AppendBits(2, current_pps_.weighted_bipred_idc); 1013 1014 packed_pps_.AppendSE(current_pps_.pic_init_qp_minus26); 1015 packed_pps_.AppendSE(current_pps_.pic_init_qs_minus26); 1016 packed_pps_.AppendSE(current_pps_.chroma_qp_index_offset); 1017 1018 packed_pps_.AppendBool(current_pps_.deblocking_filter_control_present_flag); 1019 packed_pps_.AppendBool(current_pps_.constrained_intra_pred_flag); 1020 packed_pps_.AppendBool(current_pps_.redundant_pic_cnt_present_flag); 1021 1022 packed_pps_.AppendBool(current_pps_.transform_8x8_mode_flag); 1023 packed_pps_.AppendBool(current_pps_.pic_scaling_matrix_present_flag); 1024 DCHECK(!current_pps_.pic_scaling_matrix_present_flag); 1025 packed_pps_.AppendSE(current_pps_.second_chroma_qp_index_offset); 1026 1027 packed_pps_.FinishNALU(); 1028 } 1029 1030 void VaapiVideoEncodeAccelerator::SetState(State state) { 1031 // Only touch state on encoder thread, unless it's not running. 1032 if (encoder_thread_.IsRunning() && 1033 !encoder_thread_proxy_->BelongsToCurrentThread()) { 1034 encoder_thread_proxy_->PostTask( 1035 FROM_HERE, 1036 base::Bind(&VaapiVideoEncodeAccelerator::SetState, 1037 base::Unretained(this), 1038 state)); 1039 return; 1040 } 1041 1042 DVLOGF(1) << "setting state to: " << state; 1043 state_ = state; 1044 } 1045 1046 void VaapiVideoEncodeAccelerator::NotifyError(Error error) { 1047 if (!child_message_loop_proxy_->BelongsToCurrentThread()) { 1048 child_message_loop_proxy_->PostTask( 1049 FROM_HERE, 1050 base::Bind( 1051 &VaapiVideoEncodeAccelerator::NotifyError, weak_this_, error)); 1052 return; 1053 } 1054 1055 if (client_) { 1056 client_->NotifyError(error); 1057 client_ptr_factory_.reset(); 1058 } 1059 } 1060 1061 VaapiVideoEncodeAccelerator::EncodeJob::EncodeJob() 1062 : coded_buffer(VA_INVALID_ID), keyframe(false) { 1063 } 1064 1065 VaapiVideoEncodeAccelerator::EncodeJob::~EncodeJob() { 1066 } 1067 1068 } // namespace content 1069