Home | History | Annotate | Download | only in media
      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(&current_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                                          &current_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(&current_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(&current_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