Index: content/common/gpu/media/vaapi_video_encode_accelerator.cc |
diff --git a/content/common/gpu/media/vaapi_video_encode_accelerator.cc b/content/common/gpu/media/vaapi_video_encode_accelerator.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6cfdd9d1faa3ec46d02428d206cceb5bcd97d7d0 |
--- /dev/null |
+++ b/content/common/gpu/media/vaapi_video_encode_accelerator.cc |
@@ -0,0 +1,1061 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/common/gpu/media/vaapi_video_encode_accelerator.h" |
+ |
+#include "base/bind.h" |
+#include "base/callback.h" |
+#include "base/command_line.h" |
+#include "base/message_loop/message_loop_proxy.h" |
+#include "base/metrics/histogram.h" |
+#include "base/numerics/safe_conversions.h" |
+#include "content/common/gpu/media/h264_dpb.h" |
+#include "content/public/common/content_switches.h" |
+#include "media/base/bind_to_current_loop.h" |
+#include "third_party/libva/va/va_enc_h264.h" |
+ |
+#define DVLOGF(level) DVLOG(level) << __FUNCTION__ << "(): " |
+ |
+#define NOTIFY_ERROR(error, msg) \ |
+ do { \ |
+ SetState(kError); \ |
+ DVLOGF(1) << msg; \ |
+ DVLOGF(1) << "Calling NotifyError(" << error << ")"; \ |
+ NotifyError(error); \ |
+ } while (0) |
+ |
+namespace content { |
+ |
+namespace { |
+// Need 2 surfaces for each frame: one for input data and one for |
+// reconstructed picture, which is later used for reference. |
+const size_t kMinSurfacesToEncode = 2; |
+ |
+// Subjectively chosen. |
+const size_t kNumInputBuffers = 4; |
+const size_t kMaxNumReferenceFrames = 4; |
+ |
+// We need up to kMaxNumReferenceFrames surfaces for reference, plus one |
+// for input and one for encode (which will be added to the set of reference |
+// frames for subsequent frames). Actual execution of HW encode is done |
+// in parallel, and we want to process more frames in the meantime. |
+// To have kNumInputBuffers in flight, we need a full set of reference + |
+// encode surfaces (i.e. kMaxNumReferenceFrames + kMinSurfacesToEncode), and |
+// (kNumInputBuffers - 1) of kMinSurfacesToEncode for the remaining frames |
+// in flight. |
+const size_t kNumSurfaces = kMaxNumReferenceFrames + kMinSurfacesToEncode + |
+ kMinSurfacesToEncode * (kNumInputBuffers - 1); |
+ |
+// An IDR every 128 frames, an I frame every 30 and no B frames. |
+const int kIDRPeriod = 128; |
+const int kIPeriod = 30; |
+const int kIPPeriod = 1; |
+ |
+const int kDefaultFramerate = 30; |
+ |
+// HRD parameters (ch. E.2.2 in spec). |
+const int kBitRateScale = 0; // bit_rate_scale for SPS HRD parameters. |
+const int kCPBSizeScale = 0; // cpb_size_scale for SPS HRD parameters. |
+ |
+const int kDefaultQP = 26; |
+// All Intel codecs can do at least 4.1. |
+const int kDefaultLevelIDC = 41; |
+const int kChromaFormatIDC = 1; // 4:2:0 |
+ |
+// Arbitrarily chosen bitrate window size for rate control, in ms. |
+const int kCPBWindowSizeMs = 1500; |
+ |
+// UMA errors that the VaapiVideoEncodeAccelerator class reports. |
+enum VAVEAEncoderFailure { |
+ VAAPI_ERROR = 0, |
+ VAVEA_ENCODER_FAILURES_MAX, |
+}; |
+ |
+} |
+ |
+// Round |value| up to |alignment|, which must be a power of 2. |
+static inline size_t RoundUpToPowerOf2(size_t value, size_t alignment) { |
+ // Check that |alignment| is a power of 2. |
+ DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); |
+ return ((value + (alignment - 1)) & ~(alignment - 1)); |
+} |
+ |
+static void ReportToUMA(VAVEAEncoderFailure failure) { |
+ UMA_HISTOGRAM_ENUMERATION( |
+ "Media.VAVEA.EncoderFailure", |
+ failure, |
+ VAVEA_ENCODER_FAILURES_MAX); |
+} |
+ |
+struct VaapiVideoEncodeAccelerator::InputFrameRef { |
+ InputFrameRef(const scoped_refptr<media::VideoFrame>& frame, |
+ bool force_keyframe) |
+ : frame(frame), force_keyframe(force_keyframe) {} |
+ const scoped_refptr<media::VideoFrame> frame; |
+ const bool force_keyframe; |
+}; |
+ |
+struct VaapiVideoEncodeAccelerator::BitstreamBufferRef { |
+ BitstreamBufferRef(int32 id, scoped_ptr<base::SharedMemory> shm, size_t size) |
+ : id(id), shm(shm.Pass()), size(size) {} |
+ const int32 id; |
+ const scoped_ptr<base::SharedMemory> shm; |
+ const size_t size; |
+}; |
+ |
+// static |
+std::vector<media::VideoEncodeAccelerator::SupportedProfile> |
+VaapiVideoEncodeAccelerator::GetSupportedProfiles() { |
+ std::vector<SupportedProfile> profiles; |
+ |
+ const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
+ if (!cmd_line->HasSwitch(switches::kEnableVaapiAcceleratedVideoEncode)) |
+ return profiles; |
+ |
+ SupportedProfile profile; |
+ profile.profile = media::H264PROFILE_MAIN; |
+ profile.max_resolution.SetSize(1920, 1088); |
+ profile.max_framerate.numerator = kDefaultFramerate; |
+ profile.max_framerate.denominator = 1; |
+ profiles.push_back(profile); |
+ |
+ // This is actually only constrained (see crbug.com/345569). |
+ profile.profile = media::H264PROFILE_BASELINE; |
+ profiles.push_back(profile); |
+ |
+ profile.profile = media::H264PROFILE_HIGH; |
+ profiles.push_back(profile); |
+ |
+ return profiles; |
+} |
+ |
+static unsigned int Log2OfPowerOf2(unsigned int x) { |
+ CHECK_GT(x, 0u); |
+ DCHECK_EQ(x & (x - 1), 0u); |
+ |
+ int log = 0; |
+ while (x) { |
+ x >>= 1; |
+ ++log; |
+ } |
+ return log; |
+} |
+ |
+VaapiVideoEncodeAccelerator::VaapiVideoEncodeAccelerator(Display* x_display) |
+ : profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), |
+ mb_width_(0), |
+ mb_height_(0), |
+ output_buffer_byte_size_(0), |
+ x_display_(x_display), |
+ state_(kUninitialized), |
+ frame_num_(0), |
+ last_idr_frame_num_(0), |
+ bitrate_(0), |
+ framerate_(0), |
+ cpb_size_(0), |
+ encoding_parameters_changed_(false), |
+ encoder_thread_("VAVEAEncoderThread"), |
+ child_message_loop_proxy_(base::MessageLoopProxy::current()), |
+ weak_this_ptr_factory_(this) { |
+ DVLOGF(4); |
+ weak_this_ = weak_this_ptr_factory_.GetWeakPtr(); |
+ |
+ max_ref_idx_l0_size_ = kMaxNumReferenceFrames; |
+ qp_ = kDefaultQP; |
+ idr_period_ = kIDRPeriod; |
+ i_period_ = kIPeriod; |
+ ip_period_ = kIPPeriod; |
+} |
+ |
+VaapiVideoEncodeAccelerator::~VaapiVideoEncodeAccelerator() { |
+ DVLOGF(4); |
+ DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
+ DCHECK(!encoder_thread_.IsRunning()); |
+} |
+ |
+bool VaapiVideoEncodeAccelerator::Initialize( |
+ media::VideoFrame::Format format, |
+ const gfx::Size& input_visible_size, |
+ media::VideoCodecProfile output_profile, |
+ uint32 initial_bitrate, |
+ Client* client) { |
+ DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
+ DCHECK(!encoder_thread_.IsRunning()); |
+ DCHECK_EQ(state_, kUninitialized); |
+ |
+ DVLOGF(1) << "Initializing VAVEA, input_format: " |
+ << media::VideoFrame::FormatToString(format) |
+ << ", input_visible_size: " << input_visible_size.ToString() |
+ << ", output_profile: " << output_profile |
+ << ", initial_bitrate: " << initial_bitrate; |
+ |
+ client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); |
+ client_ = client_ptr_factory_->GetWeakPtr(); |
+ |
+ if (output_profile < media::H264PROFILE_BASELINE || |
+ output_profile > media::H264PROFILE_MAIN) { |
+ DVLOGF(1) << "Unsupported output profile: " << output_profile; |
+ return false; |
+ } |
+ |
+ if (format != media::VideoFrame::I420) { |
+ DVLOGF(1) << "Unsupported input format: " |
+ << media::VideoFrame::FormatToString(format); |
+ return false; |
+ } |
+ |
+ profile_ = output_profile; |
+ visible_size_ = input_visible_size; |
+ // 4:2:0 format has to be 2-aligned. |
+ DCHECK_EQ(visible_size_.width() % 2, 0); |
+ DCHECK_EQ(visible_size_.height() % 2, 0); |
+ coded_size_ = gfx::Size(RoundUpToPowerOf2(visible_size_.width(), 16), |
+ RoundUpToPowerOf2(visible_size_.height(), 16)); |
+ mb_width_ = coded_size_.width() / 16; |
+ mb_height_ = coded_size_.height() / 16; |
+ output_buffer_byte_size_ = coded_size_.GetArea(); |
+ |
+ UpdateRates(initial_bitrate, kDefaultFramerate); |
+ |
+ vaapi_wrapper_ = VaapiWrapper::Create(VaapiWrapper::kEncode, |
+ output_profile, |
+ x_display_, |
+ base::Bind(&ReportToUMA, VAAPI_ERROR)); |
+ if (!vaapi_wrapper_) { |
+ DVLOGF(1) << "Failed initializing VAAPI"; |
+ return false; |
+ } |
+ |
+ if (!encoder_thread_.Start()) { |
+ DVLOGF(1) << "Failed to start encoder thread"; |
+ return false; |
+ } |
+ encoder_thread_proxy_ = encoder_thread_.message_loop_proxy(); |
+ |
+ // Finish the remaining initialization on the encoder thread. |
+ encoder_thread_proxy_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&VaapiVideoEncodeAccelerator::InitializeTask, |
+ base::Unretained(this))); |
+ |
+ return true; |
+} |
+ |
+void VaapiVideoEncodeAccelerator::InitializeTask() { |
+ DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); |
+ DCHECK_EQ(state_, kUninitialized); |
+ DVLOGF(4); |
+ |
+ va_surface_release_cb_ = media::BindToCurrentLoop( |
+ base::Bind(&VaapiVideoEncodeAccelerator::RecycleVASurfaceID, |
+ base::Unretained(this))); |
+ |
+ if (!vaapi_wrapper_->CreateSurfaces( |
+ coded_size_, kNumSurfaces, &available_va_surface_ids_)) { |
+ NOTIFY_ERROR(kPlatformFailureError, "Failed creating VASurfaces"); |
+ return; |
+ } |
+ |
+ UpdateSPS(); |
+ GeneratePackedSPS(); |
+ |
+ UpdatePPS(); |
+ GeneratePackedPPS(); |
+ |
+ child_message_loop_proxy_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&Client::RequireBitstreamBuffers, |
+ client_, |
+ kNumInputBuffers, |
+ coded_size_, |
+ output_buffer_byte_size_)); |
+ |
+ SetState(kEncoding); |
+} |
+ |
+void VaapiVideoEncodeAccelerator::RecycleVASurfaceID( |
+ VASurfaceID va_surface_id) { |
+ DVLOGF(4) << "va_surface_id: " << va_surface_id; |
+ DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); |
+ |
+ available_va_surface_ids_.push_back(va_surface_id); |
+ EncodeFrameTask(); |
+} |
+ |
+void VaapiVideoEncodeAccelerator::BeginFrame(bool force_keyframe) { |
+ memset(¤t_pic_, 0, sizeof(current_pic_)); |
+ |
+ current_pic_.frame_num = frame_num_++; |
+ frame_num_ %= idr_period_; |
+ |
+ if (current_pic_.frame_num % i_period_ == 0 || force_keyframe) |
+ current_pic_.type = media::H264SliceHeader::kISlice; |
+ else |
+ current_pic_.type = media::H264SliceHeader::kPSlice; |
+ |
+ if (current_pic_.frame_num % idr_period_ == 0) { |
+ current_pic_.idr = true; |
+ last_idr_frame_num_ = current_pic_.frame_num; |
+ ref_pic_list0_.clear(); |
+ } |
+ |
+ if (current_pic_.type != media::H264SliceHeader::kBSlice) |
+ current_pic_.ref = true; |
+ |
+ current_pic_.pic_order_cnt = current_pic_.frame_num * 2; |
+ current_pic_.top_field_order_cnt = current_pic_.pic_order_cnt; |
+ current_pic_.pic_order_cnt_lsb = current_pic_.pic_order_cnt; |
+ |
+ current_encode_job_->keyframe = |
+ (current_pic_.type == media::H264SliceHeader::kISlice); |
+ |
+ DVLOGF(4) << "Starting a new frame, type: " << current_pic_.type |
+ << (force_keyframe ? " (forced keyframe)" : "") |
+ << " frame_num: " << current_pic_.frame_num |
+ << " POC: " << current_pic_.pic_order_cnt; |
+} |
+ |
+void VaapiVideoEncodeAccelerator::EndFrame() { |
+ // Store the picture on the list of reference pictures and keep the list |
+ // below maximum size, dropping oldest references. |
+ if (current_pic_.ref) |
+ ref_pic_list0_.push_front(current_encode_job_->recon_surface); |
+ size_t max_num_ref_frames = |
+ base::checked_cast<size_t>(current_sps_.max_num_ref_frames); |
+ while (ref_pic_list0_.size() > max_num_ref_frames) |
+ ref_pic_list0_.pop_back(); |
+ |
+ submitted_encode_jobs_.push(make_linked_ptr(current_encode_job_.release())); |
+} |
+ |
+static void InitVAPicture(VAPictureH264* va_pic) { |
+ memset(va_pic, 0, sizeof(*va_pic)); |
+ va_pic->picture_id = VA_INVALID_ID; |
+ va_pic->flags = VA_PICTURE_H264_INVALID; |
+} |
+ |
+bool VaapiVideoEncodeAccelerator::SubmitFrameParameters() { |
+ VAEncSequenceParameterBufferH264 seq_param; |
+ memset(&seq_param, 0, sizeof(seq_param)); |
+ |
+#define SPS_TO_SP(a) seq_param.a = current_sps_.a; |
+ SPS_TO_SP(seq_parameter_set_id); |
+ SPS_TO_SP(level_idc); |
+ |
+ seq_param.intra_period = i_period_; |
+ seq_param.intra_idr_period = idr_period_; |
+ seq_param.ip_period = ip_period_; |
+ seq_param.bits_per_second = bitrate_; |
+ |
+ SPS_TO_SP(max_num_ref_frames); |
+ seq_param.picture_width_in_mbs = mb_width_; |
+ seq_param.picture_height_in_mbs = mb_height_; |
+ |
+#define SPS_TO_SP_FS(a) seq_param.seq_fields.bits.a = current_sps_.a; |
+ SPS_TO_SP_FS(chroma_format_idc); |
+ SPS_TO_SP_FS(frame_mbs_only_flag); |
+ SPS_TO_SP_FS(log2_max_frame_num_minus4); |
+ SPS_TO_SP_FS(pic_order_cnt_type); |
+ SPS_TO_SP_FS(log2_max_pic_order_cnt_lsb_minus4); |
+#undef SPS_TO_SP_FS |
+ |
+ SPS_TO_SP(bit_depth_luma_minus8); |
+ SPS_TO_SP(bit_depth_chroma_minus8); |
+ |
+ SPS_TO_SP(frame_cropping_flag); |
+ if (current_sps_.frame_cropping_flag) { |
+ SPS_TO_SP(frame_crop_left_offset); |
+ SPS_TO_SP(frame_crop_right_offset); |
+ SPS_TO_SP(frame_crop_top_offset); |
+ SPS_TO_SP(frame_crop_bottom_offset); |
+ } |
+ |
+ SPS_TO_SP(vui_parameters_present_flag); |
+#define SPS_TO_SP_VF(a) seq_param.vui_fields.bits.a = current_sps_.a; |
+ SPS_TO_SP_VF(timing_info_present_flag); |
+#undef SPS_TO_SP_VF |
+ SPS_TO_SP(num_units_in_tick); |
+ SPS_TO_SP(time_scale); |
+#undef SPS_TO_SP |
+ |
+ if (!vaapi_wrapper_->SubmitBuffer(VAEncSequenceParameterBufferType, |
+ sizeof(seq_param), |
+ &seq_param)) |
+ return false; |
+ |
+ VAEncPictureParameterBufferH264 pic_param; |
+ memset(&pic_param, 0, sizeof(pic_param)); |
+ |
+ pic_param.CurrPic.picture_id = current_encode_job_->recon_surface->id(); |
+ pic_param.CurrPic.TopFieldOrderCnt = current_pic_.top_field_order_cnt; |
+ pic_param.CurrPic.BottomFieldOrderCnt = current_pic_.bottom_field_order_cnt; |
+ pic_param.CurrPic.flags = 0; |
+ |
+ for (size_t i = 0; i < arraysize(pic_param.ReferenceFrames); ++i) |
+ InitVAPicture(&pic_param.ReferenceFrames[i]); |
+ |
+ DCHECK_LE(ref_pic_list0_.size(), arraysize(pic_param.ReferenceFrames)); |
+ RefPicList::const_iterator iter = ref_pic_list0_.begin(); |
+ for (size_t i = 0; |
+ i < arraysize(pic_param.ReferenceFrames) && iter != ref_pic_list0_.end(); |
+ ++iter, ++i) { |
+ pic_param.ReferenceFrames[i].picture_id = (*iter)->id(); |
+ pic_param.ReferenceFrames[i].flags = 0; |
+ } |
+ |
+ pic_param.coded_buf = current_encode_job_->coded_buffer; |
+ pic_param.pic_parameter_set_id = current_pps_.pic_parameter_set_id; |
+ pic_param.seq_parameter_set_id = current_pps_.seq_parameter_set_id; |
+ pic_param.frame_num = current_pic_.frame_num; |
+ pic_param.pic_init_qp = qp_; |
+ pic_param.num_ref_idx_l0_active_minus1 = max_ref_idx_l0_size_ - 1; |
+ pic_param.pic_fields.bits.idr_pic_flag = current_pic_.idr; |
+ pic_param.pic_fields.bits.reference_pic_flag = current_pic_.ref; |
+#define PPS_TO_PP_PF(a) pic_param.pic_fields.bits.a = current_pps_.a; |
+ PPS_TO_PP_PF(entropy_coding_mode_flag); |
+ PPS_TO_PP_PF(transform_8x8_mode_flag); |
+ PPS_TO_PP_PF(deblocking_filter_control_present_flag); |
+#undef PPS_TO_PP_PF |
+ |
+ if (!vaapi_wrapper_->SubmitBuffer(VAEncPictureParameterBufferType, |
+ sizeof(pic_param), |
+ &pic_param)) |
+ return false; |
+ |
+ VAEncSliceParameterBufferH264 slice_param; |
+ memset(&slice_param, 0, sizeof(slice_param)); |
+ |
+ slice_param.num_macroblocks = mb_width_ * mb_height_; |
+ slice_param.macroblock_info = VA_INVALID_ID; |
+ slice_param.slice_type = current_pic_.type; |
+ slice_param.pic_parameter_set_id = current_pps_.pic_parameter_set_id; |
+ slice_param.idr_pic_id = last_idr_frame_num_; |
+ slice_param.pic_order_cnt_lsb = current_pic_.pic_order_cnt_lsb; |
+ slice_param.num_ref_idx_active_override_flag = true; |
+ |
+ for (size_t i = 0; i < arraysize(slice_param.RefPicList0); ++i) |
+ InitVAPicture(&slice_param.RefPicList0[i]); |
+ |
+ for (size_t i = 0; i < arraysize(slice_param.RefPicList1); ++i) |
+ InitVAPicture(&slice_param.RefPicList1[i]); |
+ |
+ DCHECK_LE(ref_pic_list0_.size(), arraysize(slice_param.RefPicList0)); |
+ iter = ref_pic_list0_.begin(); |
+ for (size_t i = 0; |
+ i < arraysize(slice_param.RefPicList0) && iter != ref_pic_list0_.end(); |
+ ++iter, ++i) { |
+ InitVAPicture(&slice_param.RefPicList0[i]); |
+ slice_param.RefPicList0[i].picture_id = (*iter)->id(); |
+ slice_param.RefPicList0[i].flags = 0; |
+ } |
+ |
+ if (!vaapi_wrapper_->SubmitBuffer(VAEncSliceParameterBufferType, |
+ sizeof(slice_param), |
+ &slice_param)) |
+ return false; |
+ |
+ VAEncMiscParameterRateControl rate_control_param; |
+ memset(&rate_control_param, 0, sizeof(rate_control_param)); |
+ rate_control_param.bits_per_second = bitrate_; |
+ rate_control_param.target_percentage = 90; |
+ rate_control_param.window_size = kCPBWindowSizeMs; |
+ rate_control_param.initial_qp = qp_; |
+ rate_control_param.rc_flags.bits.disable_frame_skip = true; |
+ |
+ if (!vaapi_wrapper_->SubmitVAEncMiscParamBuffer( |
+ VAEncMiscParameterTypeRateControl, |
+ sizeof(rate_control_param), |
+ &rate_control_param)) |
+ return false; |
+ |
+ VAEncMiscParameterFrameRate framerate_param; |
+ memset(&framerate_param, 0, sizeof(framerate_param)); |
+ framerate_param.framerate = framerate_; |
+ if (!vaapi_wrapper_->SubmitVAEncMiscParamBuffer( |
+ VAEncMiscParameterTypeFrameRate, |
+ sizeof(framerate_param), |
+ &framerate_param)) |
+ return false; |
+ |
+ VAEncMiscParameterHRD hrd_param; |
+ memset(&hrd_param, 0, sizeof(hrd_param)); |
+ hrd_param.buffer_size = cpb_size_; |
+ hrd_param.initial_buffer_fullness = cpb_size_ / 2; |
+ if (!vaapi_wrapper_->SubmitVAEncMiscParamBuffer(VAEncMiscParameterTypeHRD, |
+ sizeof(hrd_param), |
+ &hrd_param)) |
+ return false; |
+ |
+ return true; |
+} |
+ |
+bool VaapiVideoEncodeAccelerator::SubmitHeadersIfNeeded() { |
+ if (current_pic_.type != media::H264SliceHeader::kISlice) |
+ return true; |
+ |
+ // Submit PPS. |
+ VAEncPackedHeaderParameterBuffer par_buffer; |
+ memset(&par_buffer, 0, sizeof(par_buffer)); |
+ par_buffer.type = VAEncPackedHeaderSequence; |
+ par_buffer.bit_length = packed_sps_.BytesInBuffer() * 8; |
+ |
+ if (!vaapi_wrapper_->SubmitBuffer(VAEncPackedHeaderParameterBufferType, |
+ sizeof(par_buffer), |
+ &par_buffer)) |
+ return false; |
+ |
+ if (!vaapi_wrapper_->SubmitBuffer(VAEncPackedHeaderDataBufferType, |
+ packed_sps_.BytesInBuffer(), |
+ packed_sps_.data())) |
+ return false; |
+ |
+ // Submit PPS. |
+ memset(&par_buffer, 0, sizeof(par_buffer)); |
+ par_buffer.type = VAEncPackedHeaderPicture; |
+ par_buffer.bit_length = packed_pps_.BytesInBuffer() * 8; |
+ |
+ if (!vaapi_wrapper_->SubmitBuffer(VAEncPackedHeaderParameterBufferType, |
+ sizeof(par_buffer), |
+ &par_buffer)) |
+ return false; |
+ |
+ if (!vaapi_wrapper_->SubmitBuffer(VAEncPackedHeaderDataBufferType, |
+ packed_pps_.BytesInBuffer(), |
+ packed_pps_.data())) |
+ return false; |
+ |
+ return true; |
+} |
+ |
+bool VaapiVideoEncodeAccelerator::ExecuteEncode() { |
+ DVLOGF(3) << "Encoding frame_num: " << current_pic_.frame_num; |
+ return vaapi_wrapper_->ExecuteAndDestroyPendingBuffers( |
+ current_encode_job_->input_surface->id()); |
+} |
+ |
+bool VaapiVideoEncodeAccelerator::UploadFrame( |
+ const scoped_refptr<media::VideoFrame>& frame) { |
+ return vaapi_wrapper_->UploadVideoFrameToSurface( |
+ frame, current_encode_job_->input_surface->id()); |
+} |
+ |
+void VaapiVideoEncodeAccelerator::TryToReturnBitstreamBuffer() { |
+ DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); |
+ |
+ if (state_ != kEncoding) |
+ return; |
+ |
+ if (submitted_encode_jobs_.empty() || available_bitstream_buffers_.empty()) |
+ return; |
+ |
+ linked_ptr<BitstreamBufferRef> buffer = available_bitstream_buffers_.front(); |
+ available_bitstream_buffers_.pop(); |
+ |
+ uint8* target_data = reinterpret_cast<uint8*>(buffer->shm->memory()); |
+ |
+ linked_ptr<EncodeJob> encode_job = submitted_encode_jobs_.front(); |
+ submitted_encode_jobs_.pop(); |
+ |
+ size_t data_size = 0; |
+ if (!vaapi_wrapper_->DownloadAndDestroyCodedBuffer( |
+ encode_job->coded_buffer, |
+ encode_job->input_surface->id(), |
+ target_data, |
+ buffer->size, |
+ &data_size)) { |
+ NOTIFY_ERROR(kPlatformFailureError, "Failed downloading coded buffer"); |
+ return; |
+ } |
+ |
+ DVLOGF(3) << "Returning bitstream buffer " |
+ << (encode_job->keyframe ? "(keyframe)" : "") |
+ << " id: " << buffer->id << " size: " << data_size; |
+ |
+ child_message_loop_proxy_->PostTask(FROM_HERE, |
+ base::Bind(&Client::BitstreamBufferReady, |
+ client_, |
+ buffer->id, |
+ data_size, |
+ encode_job->keyframe)); |
+} |
+ |
+void VaapiVideoEncodeAccelerator::Encode( |
+ const scoped_refptr<media::VideoFrame>& frame, |
+ bool force_keyframe) { |
+ DVLOGF(3) << "Frame timestamp: " << frame->timestamp().InMilliseconds() |
+ << " force_keyframe: " << force_keyframe; |
+ DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
+ |
+ encoder_thread_proxy_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&VaapiVideoEncodeAccelerator::EncodeTask, |
+ base::Unretained(this), |
+ frame, |
+ force_keyframe)); |
+} |
+ |
+bool VaapiVideoEncodeAccelerator::PrepareNextJob() { |
+ if (available_va_surface_ids_.size() < kMinSurfacesToEncode) |
+ return false; |
+ |
+ DCHECK(!current_encode_job_); |
+ current_encode_job_.reset(new EncodeJob()); |
+ |
+ if (!vaapi_wrapper_->CreateCodedBuffer(output_buffer_byte_size_, |
+ ¤t_encode_job_->coded_buffer)) { |
+ NOTIFY_ERROR(kPlatformFailureError, "Failed creating coded buffer"); |
+ return false; |
+ } |
+ |
+ current_encode_job_->input_surface = |
+ new VASurface(available_va_surface_ids_.back(), va_surface_release_cb_); |
+ available_va_surface_ids_.pop_back(); |
+ |
+ current_encode_job_->recon_surface = |
+ new VASurface(available_va_surface_ids_.back(), va_surface_release_cb_); |
+ available_va_surface_ids_.pop_back(); |
+ |
+ // Reference surfaces are needed until the job is done, but they get |
+ // removed from ref_pic_list0_ when it's full at the end of job submission. |
+ // Keep refs to them along with the job and only release after sync. |
+ current_encode_job_->reference_surfaces = ref_pic_list0_; |
+ |
+ return true; |
+} |
+ |
+void VaapiVideoEncodeAccelerator::EncodeTask( |
+ const scoped_refptr<media::VideoFrame>& frame, |
+ bool force_keyframe) { |
+ DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); |
+ DCHECK_NE(state_, kUninitialized); |
+ |
+ encoder_input_queue_.push( |
+ make_linked_ptr(new InputFrameRef(frame, force_keyframe))); |
+ EncodeFrameTask(); |
+} |
+ |
+void VaapiVideoEncodeAccelerator::EncodeFrameTask() { |
+ DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); |
+ |
+ if (state_ != kEncoding || encoder_input_queue_.empty()) |
+ return; |
+ |
+ if (!PrepareNextJob()) { |
+ DVLOGF(4) << "Not ready for next frame yet"; |
+ return; |
+ } |
+ |
+ linked_ptr<InputFrameRef> frame_ref = encoder_input_queue_.front(); |
+ encoder_input_queue_.pop(); |
+ |
+ if (!UploadFrame(frame_ref->frame)) { |
+ NOTIFY_ERROR(kPlatformFailureError, "Failed uploading source frame to HW."); |
+ return; |
+ } |
+ |
+ BeginFrame(frame_ref->force_keyframe || encoding_parameters_changed_); |
+ encoding_parameters_changed_ = false; |
+ |
+ if (!SubmitFrameParameters()) { |
+ NOTIFY_ERROR(kPlatformFailureError, "Failed submitting frame parameters."); |
+ return; |
+ } |
+ |
+ if (!SubmitHeadersIfNeeded()) { |
+ NOTIFY_ERROR(kPlatformFailureError, "Failed submitting frame headers."); |
+ return; |
+ } |
+ |
+ if (!ExecuteEncode()) { |
+ NOTIFY_ERROR(kPlatformFailureError, "Failed submitting encode job to HW."); |
+ return; |
+ } |
+ |
+ EndFrame(); |
+ TryToReturnBitstreamBuffer(); |
+} |
+ |
+void VaapiVideoEncodeAccelerator::UseOutputBitstreamBuffer( |
+ const media::BitstreamBuffer& buffer) { |
+ DVLOGF(4) << "id: " << buffer.id(); |
+ DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
+ |
+ if (buffer.size() < output_buffer_byte_size_) { |
+ NOTIFY_ERROR(kInvalidArgumentError, "Provided bitstream buffer too small"); |
+ return; |
+ } |
+ |
+ scoped_ptr<base::SharedMemory> shm( |
+ new base::SharedMemory(buffer.handle(), false)); |
+ if (!shm->Map(buffer.size())) { |
+ NOTIFY_ERROR(kPlatformFailureError, "Failed mapping shared memory."); |
+ return; |
+ } |
+ |
+ scoped_ptr<BitstreamBufferRef> buffer_ref( |
+ new BitstreamBufferRef(buffer.id(), shm.Pass(), buffer.size())); |
+ |
+ encoder_thread_proxy_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&VaapiVideoEncodeAccelerator::UseOutputBitstreamBufferTask, |
+ base::Unretained(this), |
+ base::Passed(&buffer_ref))); |
+} |
+ |
+void VaapiVideoEncodeAccelerator::UseOutputBitstreamBufferTask( |
+ scoped_ptr<BitstreamBufferRef> buffer_ref) { |
+ DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); |
+ DCHECK_NE(state_, kUninitialized); |
+ |
+ available_bitstream_buffers_.push(make_linked_ptr(buffer_ref.release())); |
+ TryToReturnBitstreamBuffer(); |
+} |
+ |
+void VaapiVideoEncodeAccelerator::RequestEncodingParametersChange( |
+ uint32 bitrate, |
+ uint32 framerate) { |
+ DVLOGF(2) << "bitrate: " << bitrate << " framerate: " << framerate; |
+ DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
+ |
+ encoder_thread_proxy_->PostTask( |
+ FROM_HERE, |
+ base::Bind( |
+ &VaapiVideoEncodeAccelerator::RequestEncodingParametersChangeTask, |
+ base::Unretained(this), |
+ bitrate, |
+ framerate)); |
+} |
+ |
+void VaapiVideoEncodeAccelerator::UpdateRates(uint32 bitrate, |
+ uint32 framerate) { |
+ if (encoder_thread_.IsRunning()) |
+ DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); |
+ DCHECK_NE(bitrate, 0u); |
+ DCHECK_NE(framerate, 0u); |
+ bitrate_ = bitrate; |
+ framerate_ = framerate; |
+ cpb_size_ = bitrate_ * kCPBWindowSizeMs / 1000; |
+} |
+ |
+void VaapiVideoEncodeAccelerator::RequestEncodingParametersChangeTask( |
+ uint32 bitrate, |
+ uint32 framerate) { |
+ DVLOGF(2) << "bitrate: " << bitrate << " framerate: " << framerate; |
+ DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); |
+ DCHECK_NE(state_, kUninitialized); |
+ |
+ UpdateRates(bitrate, framerate); |
+ |
+ UpdateSPS(); |
+ GeneratePackedSPS(); |
+ |
+ // Submit new parameters along with next frame that will be processed. |
+ encoding_parameters_changed_ = true; |
+} |
+ |
+void VaapiVideoEncodeAccelerator::Destroy() { |
+ DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
+ |
+ // Can't call client anymore after Destroy() returns. |
+ client_ptr_factory_.reset(); |
+ weak_this_ptr_factory_.InvalidateWeakPtrs(); |
+ |
+ // Early-exit encoder tasks if they are running and join the thread. |
+ if (encoder_thread_.IsRunning()) { |
+ encoder_thread_.message_loop()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&VaapiVideoEncodeAccelerator::DestroyTask, |
+ base::Unretained(this))); |
+ encoder_thread_.Stop(); |
+ } |
+ |
+ delete this; |
+} |
+ |
+void VaapiVideoEncodeAccelerator::DestroyTask() { |
+ DVLOGF(2); |
+ DCHECK(encoder_thread_proxy_->BelongsToCurrentThread()); |
+ SetState(kError); |
+} |
+ |
+void VaapiVideoEncodeAccelerator::UpdateSPS() { |
+ memset(¤t_sps_, 0, sizeof(media::H264SPS)); |
+ |
+ // Spec A.2 and A.3. |
+ switch (profile_) { |
+ case media::H264PROFILE_BASELINE: |
+ // Due to crbug.com/345569, we don't distinguish between constrained |
+ // and non-constrained baseline profiles. Since many codecs can't do |
+ // non-constrained, and constrained is usually what we mean (and it's a |
+ // subset of non-constrained), default to it. |
+ current_sps_.profile_idc = media::H264SPS::kProfileIDCBaseline; |
+ current_sps_.constraint_set0_flag = true; |
+ break; |
+ case media::H264PROFILE_MAIN: |
+ current_sps_.profile_idc = media::H264SPS::kProfileIDCMain; |
+ current_sps_.constraint_set1_flag = true; |
+ break; |
+ case media::H264PROFILE_HIGH: |
+ current_sps_.profile_idc = media::H264SPS::kProfileIDCHigh; |
+ break; |
+ default: |
+ NOTIMPLEMENTED(); |
+ return; |
+ } |
+ |
+ current_sps_.level_idc = kDefaultLevelIDC; |
+ current_sps_.seq_parameter_set_id = 0; |
+ current_sps_.chroma_format_idc = kChromaFormatIDC; |
+ |
+ DCHECK_GE(idr_period_, 1u << 4); |
+ current_sps_.log2_max_frame_num_minus4 = Log2OfPowerOf2(idr_period_) - 4; |
+ current_sps_.pic_order_cnt_type = 0; |
+ current_sps_.log2_max_pic_order_cnt_lsb_minus4 = |
+ Log2OfPowerOf2(idr_period_ * 2) - 4; |
+ current_sps_.max_num_ref_frames = max_ref_idx_l0_size_; |
+ |
+ current_sps_.frame_mbs_only_flag = true; |
+ |
+ DCHECK_GT(mb_width_, 0u); |
+ DCHECK_GT(mb_height_, 0u); |
+ current_sps_.pic_width_in_mbs_minus1 = mb_width_ - 1; |
+ DCHECK(current_sps_.frame_mbs_only_flag); |
+ current_sps_.pic_height_in_map_units_minus1 = mb_height_ - 1; |
+ |
+ if (visible_size_ != coded_size_) { |
+ // Visible size differs from coded size, fill crop information. |
+ current_sps_.frame_cropping_flag = true; |
+ DCHECK(!current_sps_.separate_colour_plane_flag); |
+ // Spec table 6-1. Only 4:2:0 for now. |
+ DCHECK_EQ(current_sps_.chroma_format_idc, 1); |
+ // Spec 7.4.2.1.1. Crop is in crop units, which is 2 pixels for 4:2:0. |
+ const unsigned int crop_unit_x = 2; |
+ const unsigned int crop_unit_y = 2 * (2 - current_sps_.frame_mbs_only_flag); |
+ current_sps_.frame_crop_left_offset = 0; |
+ current_sps_.frame_crop_right_offset = |
+ (coded_size_.width() - visible_size_.width()) / crop_unit_x; |
+ current_sps_.frame_crop_top_offset = 0; |
+ current_sps_.frame_crop_bottom_offset = |
+ (coded_size_.height() - visible_size_.height()) / crop_unit_y; |
+ } |
+ |
+ current_sps_.vui_parameters_present_flag = true; |
+ current_sps_.timing_info_present_flag = true; |
+ current_sps_.num_units_in_tick = 1; |
+ current_sps_.time_scale = framerate_ * 2; // See equation D-2 in spec. |
+ current_sps_.fixed_frame_rate_flag = true; |
+ |
+ current_sps_.nal_hrd_parameters_present_flag = true; |
+ // H.264 spec ch. E.2.2. |
+ current_sps_.cpb_cnt_minus1 = 0; |
+ current_sps_.bit_rate_scale = kBitRateScale; |
+ current_sps_.cpb_size_scale = kCPBSizeScale; |
+ current_sps_.bit_rate_value_minus1[0] = |
+ (bitrate_ >> |
+ (kBitRateScale + media::H264SPS::kBitRateScaleConstantTerm)) - 1; |
+ current_sps_.cpb_size_value_minus1[0] = |
+ (cpb_size_ >> |
+ (kCPBSizeScale + media::H264SPS::kCPBSizeScaleConstantTerm)) - 1; |
+ current_sps_.cbr_flag[0] = true; |
+ current_sps_.initial_cpb_removal_delay_length_minus_1 = |
+ media::H264SPS::kDefaultInitialCPBRemovalDelayLength - 1; |
+ current_sps_.cpb_removal_delay_length_minus1 = |
+ media::H264SPS::kDefaultInitialCPBRemovalDelayLength - 1; |
+ current_sps_.dpb_output_delay_length_minus1 = |
+ media::H264SPS::kDefaultDPBOutputDelayLength - 1; |
+ current_sps_.time_offset_length = media::H264SPS::kDefaultTimeOffsetLength; |
+ current_sps_.low_delay_hrd_flag = false; |
+} |
+ |
+void VaapiVideoEncodeAccelerator::GeneratePackedSPS() { |
+ packed_sps_.Reset(); |
+ |
+ packed_sps_.BeginNALU(media::H264NALU::kSPS, 3); |
+ |
+ packed_sps_.AppendBits(8, current_sps_.profile_idc); |
+ packed_sps_.AppendBool(current_sps_.constraint_set0_flag); |
+ packed_sps_.AppendBool(current_sps_.constraint_set1_flag); |
+ packed_sps_.AppendBool(current_sps_.constraint_set2_flag); |
+ packed_sps_.AppendBool(current_sps_.constraint_set3_flag); |
+ packed_sps_.AppendBool(current_sps_.constraint_set4_flag); |
+ packed_sps_.AppendBool(current_sps_.constraint_set5_flag); |
+ packed_sps_.AppendBits(2, 0); // reserved_zero_2bits |
+ packed_sps_.AppendBits(8, current_sps_.level_idc); |
+ packed_sps_.AppendUE(current_sps_.seq_parameter_set_id); |
+ |
+ if (current_sps_.profile_idc == media::H264SPS::kProfileIDCHigh) { |
+ packed_sps_.AppendUE(current_sps_.chroma_format_idc); |
+ if (current_sps_.chroma_format_idc == 3) |
+ packed_sps_.AppendBool(current_sps_.separate_colour_plane_flag); |
+ packed_sps_.AppendUE(current_sps_.bit_depth_luma_minus8); |
+ packed_sps_.AppendUE(current_sps_.bit_depth_chroma_minus8); |
+ packed_sps_.AppendBool(current_sps_.qpprime_y_zero_transform_bypass_flag); |
+ packed_sps_.AppendBool(current_sps_.seq_scaling_matrix_present_flag); |
+ CHECK(!current_sps_.seq_scaling_matrix_present_flag); |
+ } |
+ |
+ packed_sps_.AppendUE(current_sps_.log2_max_frame_num_minus4); |
+ packed_sps_.AppendUE(current_sps_.pic_order_cnt_type); |
+ if (current_sps_.pic_order_cnt_type == 0) |
+ packed_sps_.AppendUE(current_sps_.log2_max_pic_order_cnt_lsb_minus4); |
+ else if (current_sps_.pic_order_cnt_type == 1) { |
+ CHECK(1); |
+ } |
+ |
+ packed_sps_.AppendUE(current_sps_.max_num_ref_frames); |
+ packed_sps_.AppendBool(current_sps_.gaps_in_frame_num_value_allowed_flag); |
+ packed_sps_.AppendUE(current_sps_.pic_width_in_mbs_minus1); |
+ packed_sps_.AppendUE(current_sps_.pic_height_in_map_units_minus1); |
+ |
+ packed_sps_.AppendBool(current_sps_.frame_mbs_only_flag); |
+ if (!current_sps_.frame_mbs_only_flag) |
+ packed_sps_.AppendBool(current_sps_.mb_adaptive_frame_field_flag); |
+ |
+ packed_sps_.AppendBool(current_sps_.direct_8x8_inference_flag); |
+ |
+ packed_sps_.AppendBool(current_sps_.frame_cropping_flag); |
+ if (current_sps_.frame_cropping_flag) { |
+ packed_sps_.AppendUE(current_sps_.frame_crop_left_offset); |
+ packed_sps_.AppendUE(current_sps_.frame_crop_right_offset); |
+ packed_sps_.AppendUE(current_sps_.frame_crop_top_offset); |
+ packed_sps_.AppendUE(current_sps_.frame_crop_bottom_offset); |
+ } |
+ |
+ packed_sps_.AppendBool(current_sps_.vui_parameters_present_flag); |
+ if (current_sps_.vui_parameters_present_flag) { |
+ packed_sps_.AppendBool(false); // aspect_ratio_info_present_flag |
+ packed_sps_.AppendBool(false); // overscan_info_present_flag |
+ packed_sps_.AppendBool(false); // video_signal_type_present_flag |
+ packed_sps_.AppendBool(false); // chroma_loc_info_present_flag |
+ |
+ packed_sps_.AppendBool(current_sps_.timing_info_present_flag); |
+ if (current_sps_.timing_info_present_flag) { |
+ packed_sps_.AppendBits(32, current_sps_.num_units_in_tick); |
+ packed_sps_.AppendBits(32, current_sps_.time_scale); |
+ packed_sps_.AppendBool(current_sps_.fixed_frame_rate_flag); |
+ } |
+ |
+ packed_sps_.AppendBool(current_sps_.nal_hrd_parameters_present_flag); |
+ if (current_sps_.nal_hrd_parameters_present_flag) { |
+ packed_sps_.AppendUE(current_sps_.cpb_cnt_minus1); |
+ packed_sps_.AppendBits(4, current_sps_.bit_rate_scale); |
+ packed_sps_.AppendBits(4, current_sps_.cpb_size_scale); |
+ CHECK_LT(base::checked_cast<size_t>(current_sps_.cpb_cnt_minus1), |
+ arraysize(current_sps_.bit_rate_value_minus1)); |
+ for (int i = 0; i <= current_sps_.cpb_cnt_minus1; ++i) { |
+ packed_sps_.AppendUE(current_sps_.bit_rate_value_minus1[i]); |
+ packed_sps_.AppendUE(current_sps_.cpb_size_value_minus1[i]); |
+ packed_sps_.AppendBool(current_sps_.cbr_flag[i]); |
+ } |
+ packed_sps_.AppendBits( |
+ 5, current_sps_.initial_cpb_removal_delay_length_minus_1); |
+ packed_sps_.AppendBits(5, current_sps_.cpb_removal_delay_length_minus1); |
+ packed_sps_.AppendBits(5, current_sps_.dpb_output_delay_length_minus1); |
+ packed_sps_.AppendBits(5, current_sps_.time_offset_length); |
+ } |
+ |
+ packed_sps_.AppendBool(false); // vcl_hrd_parameters_flag |
+ if (current_sps_.nal_hrd_parameters_present_flag) |
+ packed_sps_.AppendBool(current_sps_.low_delay_hrd_flag); |
+ |
+ packed_sps_.AppendBool(false); // pic_struct_present_flag |
+ packed_sps_.AppendBool(false); // bitstream_restriction_flag |
+ } |
+ |
+ packed_sps_.FinishNALU(); |
+} |
+ |
+void VaapiVideoEncodeAccelerator::UpdatePPS() { |
+ memset(¤t_pps_, 0, sizeof(media::H264PPS)); |
+ |
+ current_pps_.seq_parameter_set_id = current_sps_.seq_parameter_set_id; |
+ current_pps_.pic_parameter_set_id = 0; |
+ |
+ current_pps_.entropy_coding_mode_flag = |
+ current_sps_.profile_idc >= media::H264SPS::kProfileIDCMain; |
+ |
+ CHECK_GT(max_ref_idx_l0_size_, 0u); |
+ current_pps_.num_ref_idx_l0_default_active_minus1 = max_ref_idx_l0_size_ - 1; |
+ current_pps_.num_ref_idx_l1_default_active_minus1 = 0; |
+ DCHECK_LE(qp_, 51u); |
+ current_pps_.pic_init_qp_minus26 = qp_ - 26; |
+ current_pps_.deblocking_filter_control_present_flag = true; |
+ current_pps_.transform_8x8_mode_flag = |
+ (current_sps_.profile_idc == media::H264SPS::kProfileIDCHigh); |
+} |
+ |
+void VaapiVideoEncodeAccelerator::GeneratePackedPPS() { |
+ packed_pps_.Reset(); |
+ |
+ packed_pps_.BeginNALU(media::H264NALU::kPPS, 3); |
+ |
+ packed_pps_.AppendUE(current_pps_.pic_parameter_set_id); |
+ packed_pps_.AppendUE(current_pps_.seq_parameter_set_id); |
+ packed_pps_.AppendBool(current_pps_.entropy_coding_mode_flag); |
+ packed_pps_.AppendBool( |
+ current_pps_.bottom_field_pic_order_in_frame_present_flag); |
+ CHECK_EQ(current_pps_.num_slice_groups_minus1, 0); |
+ packed_pps_.AppendUE(current_pps_.num_slice_groups_minus1); |
+ |
+ packed_pps_.AppendUE(current_pps_.num_ref_idx_l0_default_active_minus1); |
+ packed_pps_.AppendUE(current_pps_.num_ref_idx_l1_default_active_minus1); |
+ |
+ packed_pps_.AppendBool(current_pps_.weighted_pred_flag); |
+ packed_pps_.AppendBits(2, current_pps_.weighted_bipred_idc); |
+ |
+ packed_pps_.AppendSE(current_pps_.pic_init_qp_minus26); |
+ packed_pps_.AppendSE(current_pps_.pic_init_qs_minus26); |
+ packed_pps_.AppendSE(current_pps_.chroma_qp_index_offset); |
+ |
+ packed_pps_.AppendBool(current_pps_.deblocking_filter_control_present_flag); |
+ packed_pps_.AppendBool(current_pps_.constrained_intra_pred_flag); |
+ packed_pps_.AppendBool(current_pps_.redundant_pic_cnt_present_flag); |
+ |
+ packed_pps_.AppendBool(current_pps_.transform_8x8_mode_flag); |
+ packed_pps_.AppendBool(current_pps_.pic_scaling_matrix_present_flag); |
+ DCHECK(!current_pps_.pic_scaling_matrix_present_flag); |
+ packed_pps_.AppendSE(current_pps_.second_chroma_qp_index_offset); |
+ |
+ packed_pps_.FinishNALU(); |
+} |
+ |
+void VaapiVideoEncodeAccelerator::SetState(State state) { |
+ // Only touch state on encoder thread, unless it's not running. |
+ if (encoder_thread_.IsRunning() && |
+ !encoder_thread_proxy_->BelongsToCurrentThread()) { |
+ encoder_thread_proxy_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&VaapiVideoEncodeAccelerator::SetState, |
+ base::Unretained(this), |
+ state)); |
+ return; |
+ } |
+ |
+ DVLOGF(1) << "setting state to: " << state; |
+ state_ = state; |
+} |
+ |
+void VaapiVideoEncodeAccelerator::NotifyError(Error error) { |
+ if (!child_message_loop_proxy_->BelongsToCurrentThread()) { |
+ child_message_loop_proxy_->PostTask( |
+ FROM_HERE, |
+ base::Bind( |
+ &VaapiVideoEncodeAccelerator::NotifyError, weak_this_, error)); |
+ return; |
+ } |
+ |
+ if (client_) { |
+ client_->NotifyError(error); |
+ client_ptr_factory_.reset(); |
+ } |
+} |
+ |
+VaapiVideoEncodeAccelerator::EncodeJob::EncodeJob() |
+ : coded_buffer(VA_INVALID_ID), keyframe(false) { |
+} |
+ |
+VaapiVideoEncodeAccelerator::EncodeJob::~EncodeJob() { |
+} |
+ |
+} // namespace content |