Index: content/common/gpu/media/vaapi_video_decode_accelerator.cc |
diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/content/common/gpu/media/vaapi_video_decode_accelerator.cc |
index de3a7b56ea36feff98ca4b76a1d291203f473597..060c87d93926b4f6f132495dbb06509dd4248876 100644 |
--- a/content/common/gpu/media/vaapi_video_decode_accelerator.cc |
+++ b/content/common/gpu/media/vaapi_video_decode_accelerator.cc |
@@ -2,6 +2,8 @@ |
// 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_decode_accelerator.h" |
+ |
#include "base/bind.h" |
#include "base/logging.h" |
#include "base/metrics/histogram.h" |
@@ -10,22 +12,28 @@ |
#include "base/synchronization/waitable_event.h" |
#include "base/trace_event/trace_event.h" |
#include "content/common/gpu/gpu_channel.h" |
+#include "content/common/gpu/media/accelerated_video_decoder.h" |
+#include "content/common/gpu/media/h264_decoder.h" |
#include "content/common/gpu/media/vaapi_picture.h" |
-#include "content/common/gpu/media/vaapi_video_decode_accelerator.h" |
#include "media/base/bind_to_current_loop.h" |
#include "media/video/picture.h" |
#include "ui/gl/gl_bindings.h" |
#include "ui/gl/gl_image.h" |
-static void ReportToUMA( |
- content::VaapiH264Decoder::VAVDAH264DecoderFailure failure) { |
- UMA_HISTOGRAM_ENUMERATION( |
- "Media.VAVDAH264.DecoderFailure", |
- failure, |
- content::VaapiH264Decoder::VAVDA_H264_DECODER_FAILURES_MAX); |
+namespace content { |
+ |
+namespace { |
+// UMA errors that the VaapiVideoDecodeAccelerator class reports. |
+enum VAVDADecoderFailure { |
+ VAAPI_ERROR = 0, |
+ VAVDA_DECODER_FAILURES_MAX, |
+}; |
} |
-namespace content { |
+static void ReportToUMA(VAVDADecoderFailure failure) { |
+ UMA_HISTOGRAM_ENUMERATION("Media.VAVDA.DecoderFailure", failure, |
+ VAVDA_DECODER_FAILURES_MAX); |
+} |
#define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \ |
do { \ |
@@ -36,6 +44,104 @@ namespace content { |
} \ |
} while (0) |
+class VaapiVideoDecodeAccelerator::VaapiDecodeSurface |
+ : public base::RefCountedThreadSafe<VaapiDecodeSurface> { |
+ public: |
+ VaapiDecodeSurface(int32 bitstream_id, |
+ const scoped_refptr<VASurface>& va_surface); |
+ |
+ int32 bitstream_id() const { return bitstream_id_; } |
+ scoped_refptr<VASurface> va_surface() { return va_surface_; } |
+ |
+ private: |
+ friend class base::RefCountedThreadSafe<VaapiDecodeSurface>; |
+ ~VaapiDecodeSurface(); |
+ |
+ int32 bitstream_id_; |
+ scoped_refptr<VASurface> va_surface_; |
+}; |
+ |
+VaapiVideoDecodeAccelerator::VaapiDecodeSurface::VaapiDecodeSurface( |
+ int32 bitstream_id, |
+ const scoped_refptr<VASurface>& va_surface) |
+ : bitstream_id_(bitstream_id), va_surface_(va_surface) { |
+} |
+ |
+VaapiVideoDecodeAccelerator::VaapiDecodeSurface::~VaapiDecodeSurface() { |
+} |
+ |
+class VaapiH264Picture : public H264Picture { |
+ public: |
+ VaapiH264Picture(const scoped_refptr< |
+ VaapiVideoDecodeAccelerator::VaapiDecodeSurface>& dec_surface); |
+ |
+ VaapiH264Picture* AsVaapiH264Picture() override { return this; } |
+ scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface> dec_surface() { |
+ return dec_surface_; |
+ } |
+ |
+ private: |
+ ~VaapiH264Picture() override; |
+ |
+ scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface> dec_surface_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(VaapiH264Picture); |
+}; |
+ |
+VaapiH264Picture::VaapiH264Picture(const scoped_refptr< |
+ VaapiVideoDecodeAccelerator::VaapiDecodeSurface>& dec_surface) |
+ : dec_surface_(dec_surface) { |
+} |
+ |
+VaapiH264Picture::~VaapiH264Picture() { |
+} |
+ |
+class VaapiVideoDecodeAccelerator::VaapiH264Accelerator |
+ : public H264Decoder::H264Accelerator { |
+ public: |
+ VaapiH264Accelerator(VaapiVideoDecodeAccelerator* vaapi_dec, |
+ VaapiWrapper* vaapi_wrapper); |
+ ~VaapiH264Accelerator() override; |
+ |
+ // H264Decoder::H264Accelerator implementation. |
+ scoped_refptr<H264Picture> CreateH264Picture() override; |
+ |
+ bool SubmitFrameMetadata(const media::H264SPS* sps, |
+ const media::H264PPS* pps, |
+ const H264DPB& dpb, |
+ const H264Picture::Vector& ref_pic_listp0, |
+ const H264Picture::Vector& ref_pic_listb0, |
+ const H264Picture::Vector& ref_pic_listb1, |
+ const scoped_refptr<H264Picture>& pic) override; |
+ |
+ bool SubmitSlice(const media::H264PPS* pps, |
+ const media::H264SliceHeader* slice_hdr, |
+ const H264Picture::Vector& ref_pic_list0, |
+ const H264Picture::Vector& ref_pic_list1, |
+ const scoped_refptr<H264Picture>& pic, |
+ const uint8_t* data, |
+ size_t size) override; |
+ |
+ bool SubmitDecode(const scoped_refptr<H264Picture>& pic) override; |
+ bool OutputPicture(const scoped_refptr<H264Picture>& pic) override; |
+ |
+ void Reset() override; |
+ |
+ private: |
+ scoped_refptr<VaapiDecodeSurface> H264PictureToVaapiDecodeSurface( |
+ const scoped_refptr<H264Picture>& pic); |
+ |
+ void FillVAPicture(VAPictureH264* va_pic, scoped_refptr<H264Picture> pic); |
+ int FillVARefFramesFromDPB(const H264DPB& dpb, |
+ VAPictureH264* va_pics, |
+ int num_pics); |
+ |
+ VaapiWrapper* vaapi_wrapper_; |
+ VaapiVideoDecodeAccelerator* vaapi_dec_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(VaapiH264Accelerator); |
+}; |
+ |
VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0), size(0) { |
} |
@@ -124,20 +230,21 @@ bool VaapiVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
#endif // USE_X11 |
vaapi_wrapper_ = VaapiWrapper::CreateForVideoCodec( |
- VaapiWrapper::kDecode, profile, |
- base::Bind(&ReportToUMA, content::VaapiH264Decoder::VAAPI_ERROR)); |
+ VaapiWrapper::kDecode, profile, base::Bind(&ReportToUMA, VAAPI_ERROR)); |
if (!vaapi_wrapper_.get()) { |
DVLOG(1) << "Failed initializing VAAPI for profile " << profile; |
return false; |
} |
- decoder_.reset( |
- new VaapiH264Decoder( |
- vaapi_wrapper_.get(), |
- media::BindToCurrentLoop(base::Bind( |
- &VaapiVideoDecodeAccelerator::SurfaceReady, weak_this_)), |
- base::Bind(&ReportToUMA))); |
+ if (!(profile >= media::H264PROFILE_MIN && |
+ profile <= media::H264PROFILE_MAX)) { |
+ DLOG(ERROR) << "Unsupported profile " << profile; |
+ return false; |
+ } |
+ |
+ h264_accelerator_.reset(new VaapiH264Accelerator(this, vaapi_wrapper_.get())); |
+ decoder_.reset(new H264Decoder(h264_accelerator_.get())); |
CHECK(decoder_thread_.Start()); |
decoder_thread_proxy_ = decoder_thread_.message_loop_proxy(); |
@@ -146,23 +253,6 @@ bool VaapiVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
return true; |
} |
-void VaapiVideoDecodeAccelerator::SurfaceReady( |
- int32 input_id, |
- const scoped_refptr<VASurface>& va_surface) { |
- DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
- DCHECK(!awaiting_va_surfaces_recycle_); |
- |
- // Drop any requests to output if we are resetting or being destroyed. |
- if (state_ == kResetting || state_ == kDestroying) |
- return; |
- |
- pending_output_cbs_.push( |
- base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture, |
- weak_this_, va_surface, input_id)); |
- |
- TryOutputSurface(); |
-} |
- |
void VaapiVideoDecodeAccelerator::OutputPicture( |
const scoped_refptr<VASurface>& va_surface, |
int32 input_id, |
@@ -283,7 +373,7 @@ bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() { |
decoder_->SetStream( |
static_cast<uint8*>(curr_input_buffer_->shm->memory()), |
- curr_input_buffer_->size, curr_input_buffer_->id); |
+ curr_input_buffer_->size); |
return true; |
default: |
@@ -309,7 +399,9 @@ void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() { |
num_stream_bufs_at_decoder_); |
} |
-bool VaapiVideoDecodeAccelerator::FeedDecoderWithOutputSurfaces_Locked() { |
+// TODO(posciak): refactor the whole class to remove sleeping in wait for |
+// surfaces, and reschedule DecodeTask instead. |
+bool VaapiVideoDecodeAccelerator::WaitForSurfaces_Locked() { |
lock_.AssertAcquired(); |
DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); |
@@ -321,15 +413,6 @@ bool VaapiVideoDecodeAccelerator::FeedDecoderWithOutputSurfaces_Locked() { |
if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle) |
return false; |
- DCHECK(!awaiting_va_surfaces_recycle_); |
- while (!available_va_surfaces_.empty()) { |
- scoped_refptr<VASurface> va_surface( |
- new VASurface(available_va_surfaces_.front(), requested_pic_size_, |
- va_surface_release_cb_)); |
- available_va_surfaces_.pop_front(); |
- decoder_->ReuseSurface(va_surface); |
- } |
- |
return true; |
} |
@@ -349,7 +432,7 @@ void VaapiVideoDecodeAccelerator::DecodeTask() { |
while (GetInputBuffer_Locked()) { |
DCHECK(curr_input_buffer_.get()); |
- VaapiH264Decoder::DecResult res; |
+ AcceleratedVideoDecoder::DecodeResult res; |
{ |
// We are OK releasing the lock here, as decoder never calls our methods |
// directly and we will reacquire the lock before looking at state again. |
@@ -361,7 +444,7 @@ void VaapiVideoDecodeAccelerator::DecodeTask() { |
} |
switch (res) { |
- case VaapiH264Decoder::kAllocateNewSurfaces: |
+ case AcceleratedVideoDecoder::kAllocateNewSurfaces: |
DVLOG(1) << "Decoder requesting a new set of surfaces"; |
message_loop_->PostTask(FROM_HERE, base::Bind( |
&VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange, weak_this_, |
@@ -370,19 +453,19 @@ void VaapiVideoDecodeAccelerator::DecodeTask() { |
// We'll get rescheduled once ProvidePictureBuffers() finishes. |
return; |
- case VaapiH264Decoder::kRanOutOfStreamData: |
+ case AcceleratedVideoDecoder::kRanOutOfStreamData: |
ReturnCurrInputBuffer_Locked(); |
break; |
- case VaapiH264Decoder::kRanOutOfSurfaces: |
+ case AcceleratedVideoDecoder::kRanOutOfSurfaces: |
// No more output buffers in the decoder, try getting more or go to |
// sleep waiting for them. |
- if (!FeedDecoderWithOutputSurfaces_Locked()) |
+ if (!WaitForSurfaces_Locked()) |
return; |
break; |
- case VaapiH264Decoder::kDecodeError: |
+ case AcceleratedVideoDecoder::kDecodeError: |
RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream", |
PLATFORM_FAILURE, ); |
return; |
@@ -748,6 +831,390 @@ bool VaapiVideoDecodeAccelerator::CanDecodeOnIOThread() { |
return false; |
} |
+bool VaapiVideoDecodeAccelerator::DecodeSurface( |
+ const scoped_refptr<VaapiDecodeSurface>& dec_surface) { |
+ if (!vaapi_wrapper_->ExecuteAndDestroyPendingBuffers( |
+ dec_surface->va_surface()->id())) { |
+ DVLOG(1) << "Failed decoding picture"; |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+void VaapiVideoDecodeAccelerator::SurfaceReady( |
+ const scoped_refptr<VaapiDecodeSurface>& dec_surface) { |
+ if (message_loop_ != base::MessageLoop::current()) { |
+ message_loop_->PostTask( |
+ FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::SurfaceReady, |
+ weak_this_, dec_surface)); |
+ return; |
+ } |
+ |
+ DCHECK(!awaiting_va_surfaces_recycle_); |
+ |
+ { |
+ base::AutoLock auto_lock(lock_); |
+ // Drop any requests to output if we are resetting or being destroyed. |
+ if (state_ == kResetting || state_ == kDestroying) |
+ return; |
+ } |
+ |
+ pending_output_cbs_.push( |
+ base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture, weak_this_, |
+ dec_surface->va_surface(), dec_surface->bitstream_id())); |
+ |
+ TryOutputSurface(); |
+} |
+ |
+scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface> |
+VaapiVideoDecodeAccelerator::CreateSurface() { |
+ DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); |
+ base::AutoLock auto_lock(lock_); |
+ |
+ if (available_va_surfaces_.empty()) |
+ return nullptr; |
+ |
+ DCHECK(!awaiting_va_surfaces_recycle_); |
+ scoped_refptr<VASurface> va_surface( |
+ new VASurface(available_va_surfaces_.front(), requested_pic_size_, |
+ va_surface_release_cb_)); |
+ available_va_surfaces_.pop_front(); |
+ |
+ scoped_refptr<VaapiDecodeSurface> dec_surface = |
+ new VaapiDecodeSurface(curr_input_buffer_->id, va_surface); |
+ |
+ return dec_surface; |
+} |
+ |
+VaapiVideoDecodeAccelerator::VaapiH264Accelerator::VaapiH264Accelerator( |
+ VaapiVideoDecodeAccelerator* vaapi_dec, |
+ VaapiWrapper* vaapi_wrapper) |
+ : vaapi_wrapper_(vaapi_wrapper), vaapi_dec_(vaapi_dec) { |
+ DCHECK(vaapi_wrapper_); |
+ DCHECK(vaapi_dec_); |
+} |
+ |
+VaapiVideoDecodeAccelerator::VaapiH264Accelerator::~VaapiH264Accelerator() { |
+} |
+ |
+scoped_refptr<H264Picture> |
+VaapiVideoDecodeAccelerator::VaapiH264Accelerator::CreateH264Picture() { |
+ scoped_refptr<VaapiDecodeSurface> va_surface = vaapi_dec_->CreateSurface(); |
+ if (!va_surface) |
+ return nullptr; |
+ |
+ return new VaapiH264Picture(va_surface); |
+} |
+ |
+// Fill |va_pic| with default/neutral values. |
+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 VaapiVideoDecodeAccelerator::VaapiH264Accelerator::SubmitFrameMetadata( |
+ const media::H264SPS* sps, |
+ const media::H264PPS* pps, |
+ const H264DPB& dpb, |
+ const H264Picture::Vector& ref_pic_listp0, |
+ const H264Picture::Vector& ref_pic_listb0, |
+ const H264Picture::Vector& ref_pic_listb1, |
+ const scoped_refptr<H264Picture>& pic) { |
+ VAPictureParameterBufferH264 pic_param; |
+ memset(&pic_param, 0, sizeof(pic_param)); |
+ |
+#define FROM_SPS_TO_PP(a) pic_param.a = sps->a; |
+#define FROM_SPS_TO_PP2(a, b) pic_param.b = sps->a; |
+ FROM_SPS_TO_PP2(pic_width_in_mbs_minus1, picture_width_in_mbs_minus1); |
+ // This assumes non-interlaced video |
+ FROM_SPS_TO_PP2(pic_height_in_map_units_minus1, picture_height_in_mbs_minus1); |
+ FROM_SPS_TO_PP(bit_depth_luma_minus8); |
+ FROM_SPS_TO_PP(bit_depth_chroma_minus8); |
+#undef FROM_SPS_TO_PP |
+#undef FROM_SPS_TO_PP2 |
+ |
+#define FROM_SPS_TO_PP_SF(a) pic_param.seq_fields.bits.a = sps->a; |
+#define FROM_SPS_TO_PP_SF2(a, b) pic_param.seq_fields.bits.b = sps->a; |
+ FROM_SPS_TO_PP_SF(chroma_format_idc); |
+ FROM_SPS_TO_PP_SF2(separate_colour_plane_flag, |
+ residual_colour_transform_flag); |
+ FROM_SPS_TO_PP_SF(gaps_in_frame_num_value_allowed_flag); |
+ FROM_SPS_TO_PP_SF(frame_mbs_only_flag); |
+ FROM_SPS_TO_PP_SF(mb_adaptive_frame_field_flag); |
+ FROM_SPS_TO_PP_SF(direct_8x8_inference_flag); |
+ pic_param.seq_fields.bits.MinLumaBiPredSize8x8 = (sps->level_idc >= 31); |
+ FROM_SPS_TO_PP_SF(log2_max_frame_num_minus4); |
+ FROM_SPS_TO_PP_SF(pic_order_cnt_type); |
+ FROM_SPS_TO_PP_SF(log2_max_pic_order_cnt_lsb_minus4); |
+ FROM_SPS_TO_PP_SF(delta_pic_order_always_zero_flag); |
+#undef FROM_SPS_TO_PP_SF |
+#undef FROM_SPS_TO_PP_SF2 |
+ |
+#define FROM_PPS_TO_PP(a) pic_param.a = pps->a; |
+ FROM_PPS_TO_PP(num_slice_groups_minus1); |
+ pic_param.slice_group_map_type = 0; |
+ pic_param.slice_group_change_rate_minus1 = 0; |
+ FROM_PPS_TO_PP(pic_init_qp_minus26); |
+ FROM_PPS_TO_PP(pic_init_qs_minus26); |
+ FROM_PPS_TO_PP(chroma_qp_index_offset); |
+ FROM_PPS_TO_PP(second_chroma_qp_index_offset); |
+#undef FROM_PPS_TO_PP |
+ |
+#define FROM_PPS_TO_PP_PF(a) pic_param.pic_fields.bits.a = pps->a; |
+#define FROM_PPS_TO_PP_PF2(a, b) pic_param.pic_fields.bits.b = pps->a; |
+ FROM_PPS_TO_PP_PF(entropy_coding_mode_flag); |
+ FROM_PPS_TO_PP_PF(weighted_pred_flag); |
+ FROM_PPS_TO_PP_PF(weighted_bipred_idc); |
+ FROM_PPS_TO_PP_PF(transform_8x8_mode_flag); |
+ |
+ pic_param.pic_fields.bits.field_pic_flag = 0; |
+ FROM_PPS_TO_PP_PF(constrained_intra_pred_flag); |
+ FROM_PPS_TO_PP_PF2(bottom_field_pic_order_in_frame_present_flag, |
+ pic_order_present_flag); |
+ FROM_PPS_TO_PP_PF(deblocking_filter_control_present_flag); |
+ FROM_PPS_TO_PP_PF(redundant_pic_cnt_present_flag); |
+ pic_param.pic_fields.bits.reference_pic_flag = pic->ref; |
+#undef FROM_PPS_TO_PP_PF |
+#undef FROM_PPS_TO_PP_PF2 |
+ |
+ pic_param.frame_num = pic->frame_num; |
+ |
+ InitVAPicture(&pic_param.CurrPic); |
+ FillVAPicture(&pic_param.CurrPic, pic); |
+ |
+ // Init reference pictures' array. |
+ for (int i = 0; i < 16; ++i) |
+ InitVAPicture(&pic_param.ReferenceFrames[i]); |
+ |
+ // And fill it with picture info from DPB. |
+ FillVARefFramesFromDPB(dpb, pic_param.ReferenceFrames, |
+ arraysize(pic_param.ReferenceFrames)); |
+ |
+ pic_param.num_ref_frames = sps->max_num_ref_frames; |
+ |
+ if (!vaapi_wrapper_->SubmitBuffer(VAPictureParameterBufferType, |
+ sizeof(pic_param), |
+ &pic_param)) |
+ return false; |
+ |
+ VAIQMatrixBufferH264 iq_matrix_buf; |
+ memset(&iq_matrix_buf, 0, sizeof(iq_matrix_buf)); |
+ |
+ if (pps->pic_scaling_matrix_present_flag) { |
+ for (int i = 0; i < 6; ++i) { |
+ for (int j = 0; j < 16; ++j) |
+ iq_matrix_buf.ScalingList4x4[i][j] = pps->scaling_list4x4[i][j]; |
+ } |
+ |
+ for (int i = 0; i < 2; ++i) { |
+ for (int j = 0; j < 64; ++j) |
+ iq_matrix_buf.ScalingList8x8[i][j] = pps->scaling_list8x8[i][j]; |
+ } |
+ } else { |
+ for (int i = 0; i < 6; ++i) { |
+ for (int j = 0; j < 16; ++j) |
+ iq_matrix_buf.ScalingList4x4[i][j] = sps->scaling_list4x4[i][j]; |
+ } |
+ |
+ for (int i = 0; i < 2; ++i) { |
+ for (int j = 0; j < 64; ++j) |
+ iq_matrix_buf.ScalingList8x8[i][j] = sps->scaling_list8x8[i][j]; |
+ } |
+ } |
+ |
+ return vaapi_wrapper_->SubmitBuffer(VAIQMatrixBufferType, |
+ sizeof(iq_matrix_buf), |
+ &iq_matrix_buf); |
+} |
+ |
+bool VaapiVideoDecodeAccelerator::VaapiH264Accelerator::SubmitSlice( |
+ const media::H264PPS* pps, |
+ const media::H264SliceHeader* slice_hdr, |
+ const H264Picture::Vector& ref_pic_list0, |
+ const H264Picture::Vector& ref_pic_list1, |
+ const scoped_refptr<H264Picture>& pic, |
+ const uint8_t* data, |
+ size_t size) { |
+ VASliceParameterBufferH264 slice_param; |
+ memset(&slice_param, 0, sizeof(slice_param)); |
+ |
+ slice_param.slice_data_size = slice_hdr->nalu_size; |
+ slice_param.slice_data_offset = 0; |
+ slice_param.slice_data_flag = VA_SLICE_DATA_FLAG_ALL; |
+ slice_param.slice_data_bit_offset = slice_hdr->header_bit_size; |
+ |
+#define SHDRToSP(a) slice_param.a = slice_hdr->a; |
+ SHDRToSP(first_mb_in_slice); |
+ slice_param.slice_type = slice_hdr->slice_type % 5; |
+ SHDRToSP(direct_spatial_mv_pred_flag); |
+ |
+ // TODO posciak: make sure parser sets those even when override flags |
+ // in slice header is off. |
+ SHDRToSP(num_ref_idx_l0_active_minus1); |
+ SHDRToSP(num_ref_idx_l1_active_minus1); |
+ SHDRToSP(cabac_init_idc); |
+ SHDRToSP(slice_qp_delta); |
+ SHDRToSP(disable_deblocking_filter_idc); |
+ SHDRToSP(slice_alpha_c0_offset_div2); |
+ SHDRToSP(slice_beta_offset_div2); |
+ |
+ if (((slice_hdr->IsPSlice() || slice_hdr->IsSPSlice()) && |
+ pps->weighted_pred_flag) || |
+ (slice_hdr->IsBSlice() && pps->weighted_bipred_idc == 1)) { |
+ SHDRToSP(luma_log2_weight_denom); |
+ SHDRToSP(chroma_log2_weight_denom); |
+ |
+ SHDRToSP(luma_weight_l0_flag); |
+ SHDRToSP(luma_weight_l1_flag); |
+ |
+ SHDRToSP(chroma_weight_l0_flag); |
+ SHDRToSP(chroma_weight_l1_flag); |
+ |
+ for (int i = 0; i <= slice_param.num_ref_idx_l0_active_minus1; ++i) { |
+ slice_param.luma_weight_l0[i] = |
+ slice_hdr->pred_weight_table_l0.luma_weight[i]; |
+ slice_param.luma_offset_l0[i] = |
+ slice_hdr->pred_weight_table_l0.luma_offset[i]; |
+ |
+ for (int j = 0; j < 2; ++j) { |
+ slice_param.chroma_weight_l0[i][j] = |
+ slice_hdr->pred_weight_table_l0.chroma_weight[i][j]; |
+ slice_param.chroma_offset_l0[i][j] = |
+ slice_hdr->pred_weight_table_l0.chroma_offset[i][j]; |
+ } |
+ } |
+ |
+ if (slice_hdr->IsBSlice()) { |
+ for (int i = 0; i <= slice_param.num_ref_idx_l1_active_minus1; ++i) { |
+ slice_param.luma_weight_l1[i] = |
+ slice_hdr->pred_weight_table_l1.luma_weight[i]; |
+ slice_param.luma_offset_l1[i] = |
+ slice_hdr->pred_weight_table_l1.luma_offset[i]; |
+ |
+ for (int j = 0; j < 2; ++j) { |
+ slice_param.chroma_weight_l1[i][j] = |
+ slice_hdr->pred_weight_table_l1.chroma_weight[i][j]; |
+ slice_param.chroma_offset_l1[i][j] = |
+ slice_hdr->pred_weight_table_l1.chroma_offset[i][j]; |
+ } |
+ } |
+ } |
+ } |
+ |
+ static_assert( |
+ arraysize(slice_param.RefPicList0) == arraysize(slice_param.RefPicList1), |
+ "Invalid RefPicList sizes"); |
+ |
+ for (size_t i = 0; i < arraysize(slice_param.RefPicList0); ++i) { |
+ InitVAPicture(&slice_param.RefPicList0[i]); |
+ InitVAPicture(&slice_param.RefPicList1[i]); |
+ } |
+ |
+ for (size_t i = 0; |
+ i < ref_pic_list0.size() && i < arraysize(slice_param.RefPicList0); |
+ ++i) { |
+ if (ref_pic_list0[i]) |
+ FillVAPicture(&slice_param.RefPicList0[i], ref_pic_list0[i]); |
+ } |
+ for (size_t i = 0; |
+ i < ref_pic_list1.size() && i < arraysize(slice_param.RefPicList1); |
+ ++i) { |
+ if (ref_pic_list1[i]) |
+ FillVAPicture(&slice_param.RefPicList1[i], ref_pic_list1[i]); |
+ } |
+ |
+ if (!vaapi_wrapper_->SubmitBuffer(VASliceParameterBufferType, |
+ sizeof(slice_param), |
+ &slice_param)) |
+ return false; |
+ |
+ // Can't help it, blame libva... |
+ void* non_const_ptr = const_cast<uint8*>(data); |
+ return vaapi_wrapper_->SubmitBuffer(VASliceDataBufferType, size, |
+ non_const_ptr); |
+} |
+ |
+bool VaapiVideoDecodeAccelerator::VaapiH264Accelerator::SubmitDecode( |
+ const scoped_refptr<H264Picture>& pic) { |
+ DVLOG(4) << "Decoding POC " << pic->pic_order_cnt; |
+ scoped_refptr<VaapiDecodeSurface> dec_surface = |
+ H264PictureToVaapiDecodeSurface(pic); |
+ |
+ return vaapi_dec_->DecodeSurface(dec_surface); |
+} |
+ |
+bool VaapiVideoDecodeAccelerator::VaapiH264Accelerator::OutputPicture( |
+ const scoped_refptr<H264Picture>& pic) { |
+ scoped_refptr<VaapiDecodeSurface> dec_surface = |
+ H264PictureToVaapiDecodeSurface(pic); |
+ |
+ vaapi_dec_->SurfaceReady(dec_surface); |
+ |
+ return true; |
+} |
+ |
+void VaapiVideoDecodeAccelerator::VaapiH264Accelerator::Reset() { |
+ vaapi_wrapper_->DestroyPendingBuffers(); |
+} |
+ |
+scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface> |
+VaapiVideoDecodeAccelerator::VaapiH264Accelerator:: |
+ H264PictureToVaapiDecodeSurface(const scoped_refptr<H264Picture>& pic) { |
+ VaapiH264Picture* vaapi_pic = pic->AsVaapiH264Picture(); |
+ CHECK(vaapi_pic); |
+ return vaapi_pic->dec_surface(); |
+} |
+ |
+void VaapiVideoDecodeAccelerator::VaapiH264Accelerator::FillVAPicture( |
+ VAPictureH264* va_pic, |
+ scoped_refptr<H264Picture> pic) { |
+ scoped_refptr<VaapiDecodeSurface> dec_surface = |
+ H264PictureToVaapiDecodeSurface(pic); |
+ |
+ va_pic->picture_id = dec_surface->va_surface()->id(); |
+ va_pic->frame_idx = pic->frame_num; |
+ va_pic->flags = 0; |
+ |
+ switch (pic->field) { |
+ case H264Picture::FIELD_NONE: |
+ break; |
+ case H264Picture::FIELD_TOP: |
+ va_pic->flags |= VA_PICTURE_H264_TOP_FIELD; |
+ break; |
+ case H264Picture::FIELD_BOTTOM: |
+ va_pic->flags |= VA_PICTURE_H264_BOTTOM_FIELD; |
+ break; |
+ } |
+ |
+ if (pic->ref) { |
+ va_pic->flags |= pic->long_term ? VA_PICTURE_H264_LONG_TERM_REFERENCE |
+ : VA_PICTURE_H264_SHORT_TERM_REFERENCE; |
+ } |
+ |
+ va_pic->TopFieldOrderCnt = pic->top_field_order_cnt; |
+ va_pic->BottomFieldOrderCnt = pic->bottom_field_order_cnt; |
+} |
+ |
+int VaapiVideoDecodeAccelerator::VaapiH264Accelerator::FillVARefFramesFromDPB( |
+ const H264DPB& dpb, |
+ VAPictureH264* va_pics, |
+ int num_pics) { |
+ H264Picture::Vector::const_reverse_iterator rit; |
+ int i; |
+ |
+ // Return reference frames in reverse order of insertion. |
+ // Libva does not document this, but other implementations (e.g. mplayer) |
+ // do it this way as well. |
+ for (rit = dpb.rbegin(), i = 0; rit != dpb.rend() && i < num_pics; ++rit) { |
+ if ((*rit)->ref) |
+ FillVAPicture(&va_pics[i++], *rit); |
+ } |
+ |
+ return i; |
+} |
+ |
// static |
media::VideoDecodeAccelerator::SupportedProfiles |
VaapiVideoDecodeAccelerator::GetSupportedProfiles() { |