1 // Copyright 2018 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 "media/gpu/v4l2/v4l2_vp8_accelerator.h"
6 
7 #define __LINUX_MEDIA_VP8_CTRLS_LEGACY_H
8 #include <linux/videodev2.h>
9 #include <linux/media/vp8-ctrls.h>
10 
11 #include <type_traits>
12 
13 #include "base/logging.h"
14 #include "base/numerics/safe_conversions.h"
15 #include "base/stl_util.h"
16 #include "media/gpu/macros.h"
17 #include "media/gpu/v4l2/v4l2_decode_surface.h"
18 #include "media/gpu/v4l2/v4l2_decode_surface_handler.h"
19 #include "media/gpu/v4l2/v4l2_device.h"
20 #include "media/gpu/vp8_picture.h"
21 #include "media/parsers/vp8_parser.h"
22 
23 namespace media {
24 namespace {
25 
FillV4L2SegmentationHeader(const Vp8SegmentationHeader & vp8_sgmnt_hdr,struct v4l2_vp8_segment_header * v4l2_sgmnt_hdr)26 void FillV4L2SegmentationHeader(
27     const Vp8SegmentationHeader& vp8_sgmnt_hdr,
28     struct v4l2_vp8_segment_header* v4l2_sgmnt_hdr) {
29 #define SET_V4L2_SGMNT_HDR_FLAG_IF(cond, flag) \
30   v4l2_sgmnt_hdr->flags |= ((vp8_sgmnt_hdr.cond) ? (flag) : 0)
31   SET_V4L2_SGMNT_HDR_FLAG_IF(segmentation_enabled,
32                              V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED);
33   SET_V4L2_SGMNT_HDR_FLAG_IF(update_mb_segmentation_map,
34                              V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP);
35   SET_V4L2_SGMNT_HDR_FLAG_IF(update_segment_feature_data,
36                              V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_FEATURE_DATA);
37   // TODO not sure about this one?
38   SET_V4L2_SGMNT_HDR_FLAG_IF(
39       segment_feature_mode == Vp8SegmentationHeader::FEATURE_MODE_DELTA,
40       V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE);
41   SET_V4L2_SGMNT_HDR_FLAG_IF(segment_feature_mode,
42                              V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_FEATURE_DATA);
43 #undef SET_V4L2_SGMNT_HDR_FLAG_IF
44 
45   SafeArrayMemcpy(v4l2_sgmnt_hdr->quant_update,
46                   vp8_sgmnt_hdr.quantizer_update_value);
47   SafeArrayMemcpy(v4l2_sgmnt_hdr->lf_update, vp8_sgmnt_hdr.lf_update_value);
48   SafeArrayMemcpy(v4l2_sgmnt_hdr->segment_probs, vp8_sgmnt_hdr.segment_prob);
49 }
50 
FillV4L2LoopFilterHeader(const Vp8LoopFilterHeader & vp8_loopfilter_hdr,struct v4l2_vp8_loopfilter_header * v4l2_lf_hdr)51 void FillV4L2LoopFilterHeader(const Vp8LoopFilterHeader& vp8_loopfilter_hdr,
52                               struct v4l2_vp8_loopfilter_header* v4l2_lf_hdr) {
53 #define SET_V4L2_LF_HDR_FLAG_IF(cond, flag) \
54   v4l2_lf_hdr->flags |= ((vp8_loopfilter_hdr.cond) ? (flag) : 0)
55   SET_V4L2_LF_HDR_FLAG_IF(loop_filter_adj_enable,
56                           V4L2_VP8_LF_HEADER_ADJ_ENABLE);
57   SET_V4L2_LF_HDR_FLAG_IF(mode_ref_lf_delta_update,
58                           V4L2_VP8_LF_HEADER_DELTA_UPDATE);
59   SET_V4L2_LF_HDR_FLAG_IF(type == Vp8LoopFilterHeader::LOOP_FILTER_TYPE_SIMPLE,
60                           V4L2_VP8_LF_FILTER_TYPE_SIMPLE);
61 #undef SET_V4L2_LF_HDR_FLAG_IF
62 
63 #define LF_HDR_TO_V4L2_LF_HDR(a) v4l2_lf_hdr->a = vp8_loopfilter_hdr.a;
64   LF_HDR_TO_V4L2_LF_HDR(level);
65   LF_HDR_TO_V4L2_LF_HDR(sharpness_level);
66 #undef LF_HDR_TO_V4L2_LF_HDR
67 
68   SafeArrayMemcpy(v4l2_lf_hdr->ref_frm_delta,
69                   vp8_loopfilter_hdr.ref_frame_delta);
70   SafeArrayMemcpy(v4l2_lf_hdr->mb_mode_delta, vp8_loopfilter_hdr.mb_mode_delta);
71 }
72 
FillV4L2QuantizationHeader(const Vp8QuantizationHeader & vp8_quant_hdr,struct v4l2_vp8_quantization_header * v4l2_quant_hdr)73 void FillV4L2QuantizationHeader(
74     const Vp8QuantizationHeader& vp8_quant_hdr,
75     struct v4l2_vp8_quantization_header* v4l2_quant_hdr) {
76   v4l2_quant_hdr->y_ac_qi = vp8_quant_hdr.y_ac_qi;
77   v4l2_quant_hdr->y_dc_delta = vp8_quant_hdr.y_dc_delta;
78   v4l2_quant_hdr->y2_dc_delta = vp8_quant_hdr.y2_dc_delta;
79   v4l2_quant_hdr->y2_ac_delta = vp8_quant_hdr.y2_ac_delta;
80   v4l2_quant_hdr->uv_dc_delta = vp8_quant_hdr.uv_dc_delta;
81   v4l2_quant_hdr->uv_ac_delta = vp8_quant_hdr.uv_ac_delta;
82 }
83 
FillV4L2Vp8EntropyHeader(const Vp8EntropyHeader & vp8_entropy_hdr,struct v4l2_vp8_entropy_header * v4l2_entropy_hdr)84 void FillV4L2Vp8EntropyHeader(
85     const Vp8EntropyHeader& vp8_entropy_hdr,
86     struct v4l2_vp8_entropy_header* v4l2_entropy_hdr) {
87   SafeArrayMemcpy(v4l2_entropy_hdr->coeff_probs, vp8_entropy_hdr.coeff_probs);
88   SafeArrayMemcpy(v4l2_entropy_hdr->y_mode_probs, vp8_entropy_hdr.y_mode_probs);
89   SafeArrayMemcpy(v4l2_entropy_hdr->uv_mode_probs,
90                   vp8_entropy_hdr.uv_mode_probs);
91   SafeArrayMemcpy(v4l2_entropy_hdr->mv_probs, vp8_entropy_hdr.mv_probs);
92 }
93 
94 }  // namespace
95 
96 class V4L2VP8Picture : public VP8Picture {
97  public:
V4L2VP8Picture(scoped_refptr<V4L2DecodeSurface> dec_surface)98   explicit V4L2VP8Picture(scoped_refptr<V4L2DecodeSurface> dec_surface)
99       : dec_surface_(std::move(dec_surface)) {}
100 
AsV4L2VP8Picture()101   V4L2VP8Picture* AsV4L2VP8Picture() override { return this; }
dec_surface()102   scoped_refptr<V4L2DecodeSurface> dec_surface() { return dec_surface_; }
103 
104  private:
~V4L2VP8Picture()105   ~V4L2VP8Picture() override {}
106 
107   scoped_refptr<V4L2DecodeSurface> dec_surface_;
108 
109   DISALLOW_COPY_AND_ASSIGN(V4L2VP8Picture);
110 };
111 
V4L2VP8Accelerator(V4L2DecodeSurfaceHandler * surface_handler,V4L2Device * device)112 V4L2VP8Accelerator::V4L2VP8Accelerator(
113     V4L2DecodeSurfaceHandler* surface_handler,
114     V4L2Device* device)
115     : surface_handler_(surface_handler), device_(device) {
116   DCHECK(surface_handler_);
117 }
118 
~V4L2VP8Accelerator()119 V4L2VP8Accelerator::~V4L2VP8Accelerator() {}
120 
CreateVP8Picture()121 scoped_refptr<VP8Picture> V4L2VP8Accelerator::CreateVP8Picture() {
122   scoped_refptr<V4L2DecodeSurface> dec_surface =
123       surface_handler_->CreateSurface();
124   if (!dec_surface)
125     return nullptr;
126 
127   return new V4L2VP8Picture(dec_surface);
128 }
129 
SubmitDecode(scoped_refptr<VP8Picture> pic,const Vp8ReferenceFrameVector & reference_frames)130 bool V4L2VP8Accelerator::SubmitDecode(
131     scoped_refptr<VP8Picture> pic,
132     const Vp8ReferenceFrameVector& reference_frames) {
133   struct v4l2_ctrl_vp8_frame_header v4l2_frame_hdr;
134   memset(&v4l2_frame_hdr, 0, sizeof(v4l2_frame_hdr));
135 
136   const auto& frame_hdr = pic->frame_hdr;
137 #define FHDR_TO_V4L2_FHDR(a) v4l2_frame_hdr.a = frame_hdr->a
138   FHDR_TO_V4L2_FHDR(version);
139   FHDR_TO_V4L2_FHDR(width);
140   FHDR_TO_V4L2_FHDR(horizontal_scale);
141   FHDR_TO_V4L2_FHDR(height);
142   FHDR_TO_V4L2_FHDR(vertical_scale);
143   FHDR_TO_V4L2_FHDR(prob_skip_false);
144   FHDR_TO_V4L2_FHDR(prob_intra);
145   FHDR_TO_V4L2_FHDR(prob_last);
146   FHDR_TO_V4L2_FHDR(prob_gf);
147 #undef FHDR_TO_V4L2_FHDR
148   v4l2_frame_hdr.coder_state.range = frame_hdr->bool_dec_range;
149   v4l2_frame_hdr.coder_state.value = frame_hdr->bool_dec_value;
150   v4l2_frame_hdr.coder_state.bit_count = frame_hdr->bool_dec_count;
151 
152 #define SET_V4L2_FRM_HDR_FLAG_IF(cond, flag) \
153   v4l2_frame_hdr.flags |= ((frame_hdr->cond) ? (flag) : 0)
154   SET_V4L2_FRM_HDR_FLAG_IF(frame_type == Vp8FrameHeader::KEYFRAME,
155                            V4L2_VP8_FRAME_HEADER_FLAG_KEY_FRAME);
156   SET_V4L2_FRM_HDR_FLAG_IF(sign_bias_golden,
157                            V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN);
158   SET_V4L2_FRM_HDR_FLAG_IF(sign_bias_alternate,
159                            V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT);
160   SET_V4L2_FRM_HDR_FLAG_IF(is_experimental,
161                            V4L2_VP8_FRAME_HEADER_FLAG_EXPERIMENTAL);
162   SET_V4L2_FRM_HDR_FLAG_IF(show_frame, V4L2_VP8_FRAME_HEADER_FLAG_SHOW_FRAME);
163   SET_V4L2_FRM_HDR_FLAG_IF(mb_no_skip_coeff,
164                            V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF);
165 #undef SET_V4L2_FRM_HDR_FLAG_IF
166 
167   FillV4L2SegmentationHeader(frame_hdr->segmentation_hdr,
168                              &v4l2_frame_hdr.segment_header);
169 
170   FillV4L2LoopFilterHeader(frame_hdr->loopfilter_hdr,
171                            &v4l2_frame_hdr.lf_header);
172 
173   FillV4L2QuantizationHeader(frame_hdr->quantization_hdr,
174                              &v4l2_frame_hdr.quant_header);
175 
176   FillV4L2Vp8EntropyHeader(frame_hdr->entropy_hdr,
177                            &v4l2_frame_hdr.entropy_header);
178 
179   v4l2_frame_hdr.first_part_size =
180       base::checked_cast<__u32>(frame_hdr->first_part_size);
181   v4l2_frame_hdr.first_part_header_bits =
182       base::checked_cast<__u32>(frame_hdr->macroblock_bit_offset);
183   v4l2_frame_hdr.num_dct_parts = frame_hdr->num_of_dct_partitions;
184 
185   static_assert(std::extent<decltype(v4l2_frame_hdr.dct_part_sizes)>() ==
186                     std::extent<decltype(frame_hdr->dct_partition_sizes)>(),
187                 "DCT partition size arrays must have equal number of elements");
188   for (size_t i = 0; i < frame_hdr->num_of_dct_partitions &&
189                      i < base::size(v4l2_frame_hdr.dct_part_sizes);
190        ++i)
191     v4l2_frame_hdr.dct_part_sizes[i] = frame_hdr->dct_partition_sizes[i];
192 
193   scoped_refptr<V4L2DecodeSurface> dec_surface =
194       VP8PictureToV4L2DecodeSurface(pic.get());
195   std::vector<scoped_refptr<V4L2DecodeSurface>> ref_surfaces;
196 
197   const auto last_frame = reference_frames.GetFrame(Vp8RefType::VP8_FRAME_LAST);
198   if (last_frame) {
199     scoped_refptr<V4L2DecodeSurface> last_frame_surface =
200         VP8PictureToV4L2DecodeSurface(last_frame.get());
201     v4l2_frame_hdr.last_frame_ts = last_frame_surface->GetReferenceID();
202     ref_surfaces.push_back(last_frame_surface);
203   }
204 
205   const auto golden_frame =
206       reference_frames.GetFrame(Vp8RefType::VP8_FRAME_GOLDEN);
207   if (golden_frame) {
208     scoped_refptr<V4L2DecodeSurface> golden_frame_surface =
209         VP8PictureToV4L2DecodeSurface(golden_frame.get());
210     v4l2_frame_hdr.golden_frame_ts = golden_frame_surface->GetReferenceID();
211     ref_surfaces.push_back(golden_frame_surface);
212   }
213 
214   const auto alt_frame =
215       reference_frames.GetFrame(Vp8RefType::VP8_FRAME_ALTREF);
216   if (alt_frame) {
217     scoped_refptr<V4L2DecodeSurface> alt_frame_surface =
218         VP8PictureToV4L2DecodeSurface(alt_frame.get());
219     v4l2_frame_hdr.alt_frame_ts = alt_frame_surface->GetReferenceID();
220     ref_surfaces.push_back(alt_frame_surface);
221   }
222 
223   struct v4l2_ext_control ctrl;
224   memset(&ctrl, 0, sizeof(ctrl));
225   ctrl.id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER;
226   ctrl.size = sizeof(v4l2_frame_hdr);
227   ctrl.ptr = &v4l2_frame_hdr;
228 
229   struct v4l2_ext_controls ext_ctrls;
230   memset(&ext_ctrls, 0, sizeof(ext_ctrls));
231   ext_ctrls.count = 1;
232   ext_ctrls.controls = &ctrl;
233   dec_surface->PrepareSetCtrls(&ext_ctrls);
234   if (device_->Ioctl(VIDIOC_S_EXT_CTRLS, &ext_ctrls) != 0) {
235     VPLOGF(1) << "ioctl() failed: VIDIOC_S_EXT_CTRLS";
236     return false;
237   }
238 
239   dec_surface->SetReferenceSurfaces(ref_surfaces);
240 
241   if (!surface_handler_->SubmitSlice(dec_surface.get(), frame_hdr->data,
242                                      frame_hdr->frame_size))
243     return false;
244 
245   DVLOGF(4) << "Submitting decode for surface: " << dec_surface->ToString();
246   surface_handler_->DecodeSurface(dec_surface);
247   return true;
248 }
249 
OutputPicture(scoped_refptr<VP8Picture> pic)250 bool V4L2VP8Accelerator::OutputPicture(scoped_refptr<VP8Picture> pic) {
251   // TODO(crbug.com/647725): Insert correct color space.
252   surface_handler_->SurfaceReady(VP8PictureToV4L2DecodeSurface(pic.get()),
253                                  pic->bitstream_id(), pic->visible_rect(),
254                                  VideoColorSpace());
255   return true;
256 }
257 
258 scoped_refptr<V4L2DecodeSurface>
VP8PictureToV4L2DecodeSurface(VP8Picture * pic)259 V4L2VP8Accelerator::VP8PictureToV4L2DecodeSurface(VP8Picture* pic) {
260   V4L2VP8Picture* v4l2_pic = pic->AsV4L2VP8Picture();
261   CHECK(v4l2_pic);
262   return v4l2_pic->dec_surface();
263 }
264 
265 }  // namespace media
266