xref: /aosp_15_r20/external/webrtc/test/fuzzers/vp9_encoder_references_fuzzer.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include <stdint.h>
12 
13 #include "absl/algorithm/container.h"
14 #include "absl/base/macros.h"
15 #include "absl/container/inlined_vector.h"
16 #include "api/array_view.h"
17 #include "api/field_trials_view.h"
18 #include "api/video/video_frame.h"
19 #include "api/video_codecs/video_codec.h"
20 #include "api/video_codecs/video_encoder.h"
21 #include "modules/video_coding/codecs/interface/libvpx_interface.h"
22 #include "modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h"
23 #include "modules/video_coding/frame_dependencies_calculator.h"
24 #include "rtc_base/numerics/safe_compare.h"
25 #include "test/fuzzers/fuzz_data_helper.h"
26 
27 // Fuzzer simulates various svc configurations and libvpx encoder dropping
28 // layer frames.
29 // Validates vp9 encoder wrapper produces consistent frame references.
30 namespace webrtc {
31 namespace {
32 
33 using test::FuzzDataHelper;
34 
35 constexpr int kBitrateEnabledBps = 100'000;
36 
37 class FrameValidator : public EncodedImageCallback {
38  public:
39   ~FrameValidator() override = default;
40 
OnEncodedImage(const EncodedImage & encoded_image,const CodecSpecificInfo * codec_specific_info)41   Result OnEncodedImage(const EncodedImage& encoded_image,
42                         const CodecSpecificInfo* codec_specific_info) override {
43     RTC_CHECK(codec_specific_info);
44     RTC_CHECK_EQ(codec_specific_info->codecType, kVideoCodecVP9);
45     if (codec_specific_info->codecSpecific.VP9.first_frame_in_picture) {
46       ++picture_id_;
47     }
48     int64_t frame_id = frame_id_++;
49     LayerFrame& layer_frame = frames_[frame_id % kMaxFrameHistorySize];
50     layer_frame.picture_id = picture_id_;
51     layer_frame.spatial_id = encoded_image.SpatialIndex().value_or(0);
52     layer_frame.frame_id = frame_id;
53     layer_frame.temporal_id =
54         codec_specific_info->codecSpecific.VP9.temporal_idx;
55     if (layer_frame.temporal_id == kNoTemporalIdx) {
56       layer_frame.temporal_id = 0;
57     }
58     layer_frame.vp9_non_ref_for_inter_layer_pred =
59         codec_specific_info->codecSpecific.VP9.non_ref_for_inter_layer_pred;
60     CheckVp9References(layer_frame, codec_specific_info->codecSpecific.VP9);
61 
62     if (codec_specific_info->generic_frame_info.has_value()) {
63       absl::InlinedVector<int64_t, 5> frame_dependencies =
64           dependencies_calculator_.FromBuffersUsage(
65               frame_id,
66               codec_specific_info->generic_frame_info->encoder_buffers);
67 
68       CheckGenericReferences(frame_dependencies,
69                              *codec_specific_info->generic_frame_info);
70       CheckGenericAndCodecSpecificReferencesAreConsistent(
71           frame_dependencies, *codec_specific_info, layer_frame);
72     }
73 
74     return Result(Result::OK);
75   }
76 
77  private:
78   // With 4 spatial layers and patterns up to 8 pictures, it should be enough to
79   // keep the last 32 frames to validate dependencies.
80   static constexpr size_t kMaxFrameHistorySize = 32;
81   struct LayerFrame {
82     int64_t frame_id;
83     int64_t picture_id;
84     int spatial_id;
85     int temporal_id;
86     bool vp9_non_ref_for_inter_layer_pred;
87   };
88 
CheckVp9References(const LayerFrame & layer_frame,const CodecSpecificInfoVP9 & vp9_info)89   void CheckVp9References(const LayerFrame& layer_frame,
90                           const CodecSpecificInfoVP9& vp9_info) {
91     if (layer_frame.frame_id == 0) {
92       RTC_CHECK(!vp9_info.inter_layer_predicted);
93     } else {
94       const LayerFrame& previous_frame = Frame(layer_frame.frame_id - 1);
95       if (vp9_info.inter_layer_predicted) {
96         RTC_CHECK(!previous_frame.vp9_non_ref_for_inter_layer_pred);
97         RTC_CHECK_EQ(layer_frame.picture_id, previous_frame.picture_id);
98       }
99       if (previous_frame.picture_id == layer_frame.picture_id) {
100         RTC_CHECK_GT(layer_frame.spatial_id, previous_frame.spatial_id);
101         // The check below would fail for temporal shift structures. Remove it
102         // or move it to !flexible_mode section when vp9 encoder starts
103         // supporting such structures.
104         RTC_CHECK_EQ(layer_frame.temporal_id, previous_frame.temporal_id);
105       }
106     }
107     if (!vp9_info.flexible_mode) {
108       if (vp9_info.gof.num_frames_in_gof > 0) {
109         gof_.CopyGofInfoVP9(vp9_info.gof);
110       }
111       RTC_CHECK_EQ(gof_.temporal_idx[vp9_info.gof_idx],
112                    layer_frame.temporal_id);
113     }
114   }
115 
CheckGenericReferences(rtc::ArrayView<const int64_t> frame_dependencies,const GenericFrameInfo & generic_info) const116   void CheckGenericReferences(rtc::ArrayView<const int64_t> frame_dependencies,
117                               const GenericFrameInfo& generic_info) const {
118     for (int64_t dependency_frame_id : frame_dependencies) {
119       RTC_CHECK_GE(dependency_frame_id, 0);
120       const LayerFrame& dependency = Frame(dependency_frame_id);
121       RTC_CHECK_GE(generic_info.spatial_id, dependency.spatial_id);
122       RTC_CHECK_GE(generic_info.temporal_id, dependency.temporal_id);
123     }
124   }
125 
CheckGenericAndCodecSpecificReferencesAreConsistent(rtc::ArrayView<const int64_t> frame_dependencies,const CodecSpecificInfo & info,const LayerFrame & layer_frame) const126   void CheckGenericAndCodecSpecificReferencesAreConsistent(
127       rtc::ArrayView<const int64_t> frame_dependencies,
128       const CodecSpecificInfo& info,
129       const LayerFrame& layer_frame) const {
130     const CodecSpecificInfoVP9& vp9_info = info.codecSpecific.VP9;
131     const GenericFrameInfo& generic_info = *info.generic_frame_info;
132 
133     RTC_CHECK_EQ(generic_info.spatial_id, layer_frame.spatial_id);
134     RTC_CHECK_EQ(generic_info.temporal_id, layer_frame.temporal_id);
135     auto picture_id_diffs =
136         rtc::MakeArrayView(vp9_info.p_diff, vp9_info.num_ref_pics);
137     RTC_CHECK_EQ(
138         frame_dependencies.size(),
139         picture_id_diffs.size() + (vp9_info.inter_layer_predicted ? 1 : 0));
140     for (int64_t dependency_frame_id : frame_dependencies) {
141       RTC_CHECK_GE(dependency_frame_id, 0);
142       const LayerFrame& dependency = Frame(dependency_frame_id);
143       if (dependency.spatial_id != layer_frame.spatial_id) {
144         RTC_CHECK(vp9_info.inter_layer_predicted);
145         RTC_CHECK_EQ(layer_frame.picture_id, dependency.picture_id);
146         RTC_CHECK_GT(layer_frame.spatial_id, dependency.spatial_id);
147       } else {
148         RTC_CHECK(vp9_info.inter_pic_predicted);
149         RTC_CHECK_EQ(layer_frame.spatial_id, dependency.spatial_id);
150         RTC_CHECK(absl::c_linear_search(
151             picture_id_diffs, layer_frame.picture_id - dependency.picture_id));
152       }
153     }
154   }
155 
Frame(int64_t frame_id) const156   const LayerFrame& Frame(int64_t frame_id) const {
157     auto& frame = frames_[frame_id % kMaxFrameHistorySize];
158     RTC_CHECK_EQ(frame.frame_id, frame_id);
159     return frame;
160   }
161 
162   GofInfoVP9 gof_;
163   int64_t frame_id_ = 0;
164   int64_t picture_id_ = 1;
165   FrameDependenciesCalculator dependencies_calculator_;
166   LayerFrame frames_[kMaxFrameHistorySize];
167 };
168 
169 class FieldTrials : public FieldTrialsView {
170  public:
FieldTrials(FuzzDataHelper & config)171   explicit FieldTrials(FuzzDataHelper& config)
172       : flags_(config.ReadOrDefaultValue<uint8_t>(0)) {}
173 
174   ~FieldTrials() override = default;
Lookup(absl::string_view key) const175   std::string Lookup(absl::string_view key) const override {
176     static constexpr absl::string_view kBinaryFieldTrials[] = {
177         "WebRTC-Vp9ExternalRefCtrl",
178         "WebRTC-Vp9IssueKeyFrameOnLayerDeactivation",
179     };
180     for (size_t i = 0; i < ABSL_ARRAYSIZE(kBinaryFieldTrials); ++i) {
181       if (key == kBinaryFieldTrials[i]) {
182         return (flags_ & (1u << i)) ? "Enabled" : "Disabled";
183       }
184     }
185 
186     // Ignore following field trials.
187     if (key == "WebRTC-CongestionWindow" ||
188         key == "WebRTC-UseBaseHeavyVP8TL3RateAllocation" ||
189         key == "WebRTC-SimulcastUpswitchHysteresisPercent" ||
190         key == "WebRTC-SimulcastScreenshareUpswitchHysteresisPercent" ||
191         key == "WebRTC-VideoRateControl" ||
192         key == "WebRTC-VP9-PerformanceFlags" ||
193         key == "WebRTC-VP9VariableFramerateScreenshare" ||
194         key == "WebRTC-VP9QualityScaler") {
195       return "";
196     }
197     // Crash when using unexpected field trial to decide if it should be fuzzed
198     // or have a constant value.
199     RTC_CHECK(false) << "Unfuzzed field trial " << key << "\n";
200   }
201 
202  private:
203   const uint8_t flags_;
204 };
205 
CodecSettings(FuzzDataHelper & rng)206 VideoCodec CodecSettings(FuzzDataHelper& rng) {
207   uint16_t config = rng.ReadOrDefaultValue<uint16_t>(0);
208   // Test up to to 4 spatial and 4 temporal layers.
209   int num_spatial_layers = 1 + (config & 0b11);
210   int num_temporal_layers = 1 + ((config >> 2) & 0b11);
211 
212   VideoCodec codec_settings = {};
213   codec_settings.codecType = kVideoCodecVP9;
214   codec_settings.maxFramerate = 30;
215   codec_settings.width = 320 << (num_spatial_layers - 1);
216   codec_settings.height = 180 << (num_spatial_layers - 1);
217   if (num_spatial_layers > 1) {
218     for (int sid = 0; sid < num_spatial_layers; ++sid) {
219       SpatialLayer& spatial_layer = codec_settings.spatialLayers[sid];
220       codec_settings.width = 320 << sid;
221       codec_settings.height = 180 << sid;
222       spatial_layer.width = codec_settings.width;
223       spatial_layer.height = codec_settings.height;
224       spatial_layer.targetBitrate = kBitrateEnabledBps * num_temporal_layers;
225       spatial_layer.maxFramerate = codec_settings.maxFramerate;
226       spatial_layer.numberOfTemporalLayers = num_temporal_layers;
227     }
228   }
229   codec_settings.VP9()->numberOfSpatialLayers = num_spatial_layers;
230   codec_settings.VP9()->numberOfTemporalLayers = num_temporal_layers;
231   int inter_layer_pred = (config >> 4) & 0b11;
232   // There are only 3 valid values.
233   codec_settings.VP9()->interLayerPred = static_cast<InterLayerPredMode>(
234       inter_layer_pred < 3 ? inter_layer_pred : 0);
235   codec_settings.VP9()->flexibleMode = (config & (1u << 6)) != 0;
236   codec_settings.SetFrameDropEnabled((config & (1u << 7)) != 0);
237   codec_settings.mode = VideoCodecMode::kRealtimeVideo;
238   return codec_settings;
239 }
240 
EncoderSettings()241 VideoEncoder::Settings EncoderSettings() {
242   return VideoEncoder::Settings(VideoEncoder::Capabilities(false),
243                                 /*number_of_cores=*/1,
244                                 /*max_payload_size=*/0);
245 }
246 
IsSupported(int num_spatial_layers,int num_temporal_layers,const VideoBitrateAllocation & allocation)247 bool IsSupported(int num_spatial_layers,
248                  int num_temporal_layers,
249                  const VideoBitrateAllocation& allocation) {
250   // VP9 encoder doesn't support certain configurations.
251   // BitrateAllocator shouldn't produce them.
252   if (allocation.get_sum_bps() == 0) {
253     // Ignore allocation that turns off all the layers.
254     // In such a case it is up to upper layer code not to call Encode.
255     return false;
256   }
257 
258   for (int tid = 0; tid < num_temporal_layers; ++tid) {
259     int min_enabled_spatial_id = -1;
260     int max_enabled_spatial_id = -1;
261     int num_enabled_spatial_layers = 0;
262     for (int sid = 0; sid < num_spatial_layers; ++sid) {
263       if (allocation.GetBitrate(sid, tid) > 0) {
264         if (min_enabled_spatial_id == -1) {
265           min_enabled_spatial_id = sid;
266         }
267         max_enabled_spatial_id = sid;
268         ++num_enabled_spatial_layers;
269       }
270     }
271     if (num_enabled_spatial_layers == 0) {
272       // Each temporal layer should be enabled because skipping a full frame is
273       // not supported in non-flexible mode.
274       return false;
275     }
276     if (max_enabled_spatial_id - min_enabled_spatial_id + 1 !=
277         num_enabled_spatial_layers) {
278       // To avoid odd spatial dependencies, there should be no gaps in active
279       // spatial layers.
280       return false;
281     }
282   }
283 
284   return true;
285 }
286 
287 struct LibvpxState {
LibvpxStatewebrtc::__anoncd39b5cc0111::LibvpxState288   LibvpxState() {
289     pkt.kind = VPX_CODEC_CX_FRAME_PKT;
290     pkt.data.frame.buf = pkt_buffer;
291     pkt.data.frame.sz = ABSL_ARRAYSIZE(pkt_buffer);
292     layer_id.spatial_layer_id = -1;
293   }
294 
295   uint8_t pkt_buffer[1000] = {};
296   vpx_codec_enc_cfg_t config = {};
297   vpx_codec_priv_output_cx_pkt_cb_pair_t callback = {};
298   vpx_image_t img = {};
299   vpx_svc_ref_frame_config_t ref_config = {};
300   vpx_svc_layer_id_t layer_id = {};
301   vpx_svc_frame_drop_t frame_drop = {};
302   vpx_codec_cx_pkt pkt = {};
303 };
304 
305 class StubLibvpx : public LibvpxInterface {
306  public:
StubLibvpx(LibvpxState * state)307   explicit StubLibvpx(LibvpxState* state) : state_(state) { RTC_CHECK(state_); }
308 
codec_enc_config_default(vpx_codec_iface_t * iface,vpx_codec_enc_cfg_t * cfg,unsigned int usage) const309   vpx_codec_err_t codec_enc_config_default(vpx_codec_iface_t* iface,
310                                            vpx_codec_enc_cfg_t* cfg,
311                                            unsigned int usage) const override {
312     state_->config = *cfg;
313     return VPX_CODEC_OK;
314   }
315 
codec_enc_init(vpx_codec_ctx_t * ctx,vpx_codec_iface_t * iface,const vpx_codec_enc_cfg_t * cfg,vpx_codec_flags_t flags) const316   vpx_codec_err_t codec_enc_init(vpx_codec_ctx_t* ctx,
317                                  vpx_codec_iface_t* iface,
318                                  const vpx_codec_enc_cfg_t* cfg,
319                                  vpx_codec_flags_t flags) const override {
320     RTC_CHECK(ctx);
321     ctx->err = VPX_CODEC_OK;
322     return VPX_CODEC_OK;
323   }
324 
img_wrap(vpx_image_t * img,vpx_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int stride_align,unsigned char * img_data) const325   vpx_image_t* img_wrap(vpx_image_t* img,
326                         vpx_img_fmt_t fmt,
327                         unsigned int d_w,
328                         unsigned int d_h,
329                         unsigned int stride_align,
330                         unsigned char* img_data) const override {
331     state_->img.fmt = fmt;
332     state_->img.d_w = d_w;
333     state_->img.d_h = d_h;
334     return &state_->img;
335   }
336 
codec_encode(vpx_codec_ctx_t * ctx,const vpx_image_t * img,vpx_codec_pts_t pts,uint64_t duration,vpx_enc_frame_flags_t flags,uint64_t deadline) const337   vpx_codec_err_t codec_encode(vpx_codec_ctx_t* ctx,
338                                const vpx_image_t* img,
339                                vpx_codec_pts_t pts,
340                                uint64_t duration,
341                                vpx_enc_frame_flags_t flags,
342                                uint64_t deadline) const override {
343     if (flags & VPX_EFLAG_FORCE_KF) {
344       state_->pkt.data.frame.flags = VPX_FRAME_IS_KEY;
345     } else {
346       state_->pkt.data.frame.flags = 0;
347     }
348     state_->pkt.data.frame.duration = duration;
349     return VPX_CODEC_OK;
350   }
351 
codec_control(vpx_codec_ctx_t * ctx,vp8e_enc_control_id ctrl_id,void * param) const352   vpx_codec_err_t codec_control(vpx_codec_ctx_t* ctx,
353                                 vp8e_enc_control_id ctrl_id,
354                                 void* param) const override {
355     if (ctrl_id == VP9E_REGISTER_CX_CALLBACK) {
356       state_->callback =
357           *reinterpret_cast<vpx_codec_priv_output_cx_pkt_cb_pair_t*>(param);
358     }
359     return VPX_CODEC_OK;
360   }
361 
codec_control(vpx_codec_ctx_t * ctx,vp8e_enc_control_id ctrl_id,vpx_svc_ref_frame_config_t * param) const362   vpx_codec_err_t codec_control(
363       vpx_codec_ctx_t* ctx,
364       vp8e_enc_control_id ctrl_id,
365       vpx_svc_ref_frame_config_t* param) const override {
366     switch (ctrl_id) {
367       case VP9E_SET_SVC_REF_FRAME_CONFIG:
368         state_->ref_config = *param;
369         break;
370       case VP9E_GET_SVC_REF_FRAME_CONFIG:
371         *param = state_->ref_config;
372         break;
373       default:
374         break;
375     }
376     return VPX_CODEC_OK;
377   }
378 
codec_control(vpx_codec_ctx_t * ctx,vp8e_enc_control_id ctrl_id,vpx_svc_layer_id_t * param) const379   vpx_codec_err_t codec_control(vpx_codec_ctx_t* ctx,
380                                 vp8e_enc_control_id ctrl_id,
381                                 vpx_svc_layer_id_t* param) const override {
382     switch (ctrl_id) {
383       case VP9E_SET_SVC_LAYER_ID:
384         state_->layer_id = *param;
385         break;
386       case VP9E_GET_SVC_LAYER_ID:
387         *param = state_->layer_id;
388         break;
389       default:
390         break;
391     }
392     return VPX_CODEC_OK;
393   }
394 
codec_control(vpx_codec_ctx_t * ctx,vp8e_enc_control_id ctrl_id,vpx_svc_frame_drop_t * param) const395   vpx_codec_err_t codec_control(vpx_codec_ctx_t* ctx,
396                                 vp8e_enc_control_id ctrl_id,
397                                 vpx_svc_frame_drop_t* param) const override {
398     if (ctrl_id == VP9E_SET_SVC_FRAME_DROP_LAYER) {
399       state_->frame_drop = *param;
400     }
401     return VPX_CODEC_OK;
402   }
403 
codec_enc_config_set(vpx_codec_ctx_t * ctx,const vpx_codec_enc_cfg_t * cfg) const404   vpx_codec_err_t codec_enc_config_set(
405       vpx_codec_ctx_t* ctx,
406       const vpx_codec_enc_cfg_t* cfg) const override {
407     state_->config = *cfg;
408     return VPX_CODEC_OK;
409   }
410 
img_alloc(vpx_image_t * img,vpx_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int align) const411   vpx_image_t* img_alloc(vpx_image_t* img,
412                          vpx_img_fmt_t fmt,
413                          unsigned int d_w,
414                          unsigned int d_h,
415                          unsigned int align) const override {
416     return nullptr;
417   }
img_free(vpx_image_t * img) const418   void img_free(vpx_image_t* img) const override {}
codec_enc_init_multi(vpx_codec_ctx_t * ctx,vpx_codec_iface_t * iface,vpx_codec_enc_cfg_t * cfg,int num_enc,vpx_codec_flags_t flags,vpx_rational_t * dsf) const419   vpx_codec_err_t codec_enc_init_multi(vpx_codec_ctx_t* ctx,
420                                        vpx_codec_iface_t* iface,
421                                        vpx_codec_enc_cfg_t* cfg,
422                                        int num_enc,
423                                        vpx_codec_flags_t flags,
424                                        vpx_rational_t* dsf) const override {
425     return VPX_CODEC_OK;
426   }
codec_destroy(vpx_codec_ctx_t * ctx) const427   vpx_codec_err_t codec_destroy(vpx_codec_ctx_t* ctx) const override {
428     return VPX_CODEC_OK;
429   }
codec_control(vpx_codec_ctx_t * ctx,vp8e_enc_control_id ctrl_id,uint32_t param) const430   vpx_codec_err_t codec_control(vpx_codec_ctx_t* ctx,
431                                 vp8e_enc_control_id ctrl_id,
432                                 uint32_t param) const override {
433     return VPX_CODEC_OK;
434   }
codec_control(vpx_codec_ctx_t * ctx,vp8e_enc_control_id ctrl_id,int param) const435   vpx_codec_err_t codec_control(vpx_codec_ctx_t* ctx,
436                                 vp8e_enc_control_id ctrl_id,
437                                 int param) const override {
438     return VPX_CODEC_OK;
439   }
codec_control(vpx_codec_ctx_t * ctx,vp8e_enc_control_id ctrl_id,int * param) const440   vpx_codec_err_t codec_control(vpx_codec_ctx_t* ctx,
441                                 vp8e_enc_control_id ctrl_id,
442                                 int* param) const override {
443     return VPX_CODEC_OK;
444   }
codec_control(vpx_codec_ctx_t * ctx,vp8e_enc_control_id ctrl_id,vpx_roi_map * param) const445   vpx_codec_err_t codec_control(vpx_codec_ctx_t* ctx,
446                                 vp8e_enc_control_id ctrl_id,
447                                 vpx_roi_map* param) const override {
448     return VPX_CODEC_OK;
449   }
codec_control(vpx_codec_ctx_t * ctx,vp8e_enc_control_id ctrl_id,vpx_active_map * param) const450   vpx_codec_err_t codec_control(vpx_codec_ctx_t* ctx,
451                                 vp8e_enc_control_id ctrl_id,
452                                 vpx_active_map* param) const override {
453     return VPX_CODEC_OK;
454   }
codec_control(vpx_codec_ctx_t * ctx,vp8e_enc_control_id ctrl_id,vpx_scaling_mode * param) const455   vpx_codec_err_t codec_control(vpx_codec_ctx_t* ctx,
456                                 vp8e_enc_control_id ctrl_id,
457                                 vpx_scaling_mode* param) const override {
458     return VPX_CODEC_OK;
459   }
codec_control(vpx_codec_ctx_t * ctx,vp8e_enc_control_id ctrl_id,vpx_svc_extra_cfg_t * param) const460   vpx_codec_err_t codec_control(vpx_codec_ctx_t* ctx,
461                                 vp8e_enc_control_id ctrl_id,
462                                 vpx_svc_extra_cfg_t* param) const override {
463     return VPX_CODEC_OK;
464   }
codec_control(vpx_codec_ctx_t * ctx,vp8e_enc_control_id ctrl_id,vpx_svc_spatial_layer_sync_t * param) const465   vpx_codec_err_t codec_control(
466       vpx_codec_ctx_t* ctx,
467       vp8e_enc_control_id ctrl_id,
468       vpx_svc_spatial_layer_sync_t* param) const override {
469     return VPX_CODEC_OK;
470   }
codec_control(vpx_codec_ctx_t * ctx,vp8e_enc_control_id ctrl_id,vpx_rc_funcs_t * param) const471   vpx_codec_err_t codec_control(vpx_codec_ctx_t* ctx,
472                                 vp8e_enc_control_id ctrl_id,
473                                 vpx_rc_funcs_t* param) const override {
474     return VPX_CODEC_OK;
475   }
codec_get_cx_data(vpx_codec_ctx_t * ctx,vpx_codec_iter_t * iter) const476   const vpx_codec_cx_pkt_t* codec_get_cx_data(
477       vpx_codec_ctx_t* ctx,
478       vpx_codec_iter_t* iter) const override {
479     return nullptr;
480   }
codec_error_detail(vpx_codec_ctx_t * ctx) const481   const char* codec_error_detail(vpx_codec_ctx_t* ctx) const override {
482     return nullptr;
483   }
codec_error(vpx_codec_ctx_t * ctx) const484   const char* codec_error(vpx_codec_ctx_t* ctx) const override {
485     return nullptr;
486   }
codec_err_to_string(vpx_codec_err_t err) const487   const char* codec_err_to_string(vpx_codec_err_t err) const override {
488     return nullptr;
489   }
490 
491  private:
492   LibvpxState* const state_;
493 };
494 
495 enum Actions {
496   kEncode,
497   kSetRates,
498 };
499 
500 // When a layer frame is marked for drop, drops all layer frames from that
501 // pictures with larger spatial ids.
DropAbove(uint8_t layers_mask,int sid)502 constexpr bool DropAbove(uint8_t layers_mask, int sid) {
503   uint8_t full_mask = (uint8_t{1} << (sid + 1)) - 1;
504   return (layers_mask & full_mask) != full_mask;
505 }
506 // inline unittests
507 static_assert(DropAbove(0b1011, /*sid=*/0) == false, "");
508 static_assert(DropAbove(0b1011, /*sid=*/1) == false, "");
509 static_assert(DropAbove(0b1011, /*sid=*/2) == true, "");
510 static_assert(DropAbove(0b1011, /*sid=*/3) == true, "");
511 
512 // When a layer frame is marked for drop, drops all layer frames from that
513 // pictures with smaller spatial ids.
DropBelow(uint8_t layers_mask,int sid,int num_layers)514 constexpr bool DropBelow(uint8_t layers_mask, int sid, int num_layers) {
515   return (layers_mask >> sid) != (1 << (num_layers - sid)) - 1;
516 }
517 // inline unittests
518 static_assert(DropBelow(0b1101, /*sid=*/0, 4) == true, "");
519 static_assert(DropBelow(0b1101, /*sid=*/1, 4) == true, "");
520 static_assert(DropBelow(0b1101, /*sid=*/2, 4) == false, "");
521 static_assert(DropBelow(0b1101, /*sid=*/3, 4) == false, "");
522 
523 }  // namespace
524 
FuzzOneInput(const uint8_t * data,size_t size)525 void FuzzOneInput(const uint8_t* data, size_t size) {
526   FuzzDataHelper helper(rtc::MakeArrayView(data, size));
527 
528   FrameValidator validator;
529   FieldTrials field_trials(helper);
530   // Setup call callbacks for the fake
531   LibvpxState state;
532 
533   // Initialize encoder
534   LibvpxVp9Encoder encoder(cricket::VideoCodec(),
535                            std::make_unique<StubLibvpx>(&state), field_trials);
536   VideoCodec codec = CodecSettings(helper);
537   if (encoder.InitEncode(&codec, EncoderSettings()) != WEBRTC_VIDEO_CODEC_OK) {
538     return;
539   }
540   RTC_CHECK_EQ(encoder.RegisterEncodeCompleteCallback(&validator),
541                WEBRTC_VIDEO_CODEC_OK);
542   {
543     // Enable all the layers initially. Encoder doesn't support producing
544     // frames when no layers are enabled.
545     LibvpxVp9Encoder::RateControlParameters parameters;
546     parameters.framerate_fps = 30.0;
547     for (int sid = 0; sid < codec.VP9()->numberOfSpatialLayers; ++sid) {
548       for (int tid = 0; tid < codec.VP9()->numberOfTemporalLayers; ++tid) {
549         parameters.bitrate.SetBitrate(sid, tid, kBitrateEnabledBps);
550       }
551     }
552     encoder.SetRates(parameters);
553   }
554 
555   std::vector<VideoFrameType> frame_types(1);
556   VideoFrame fake_image = VideoFrame::Builder()
557                               .set_video_frame_buffer(I420Buffer::Create(
558                                   int{codec.width}, int{codec.height}))
559                               .build();
560 
561   // Start producing frames at random.
562   while (helper.CanReadBytes(1)) {
563     uint8_t action = helper.Read<uint8_t>();
564     switch (action & 0b11) {
565       case kEncode: {
566         // bitmask of the action: SSSS-K00, where
567         // four S bit indicate which spatial layers should be produced,
568         // K bit indicates if frame should be a key frame.
569         frame_types[0] = (action & 0b100) ? VideoFrameType::kVideoFrameKey
570                                           : VideoFrameType::kVideoFrameDelta;
571         encoder.Encode(fake_image, &frame_types);
572         uint8_t encode_spatial_layers = (action >> 4);
573         for (size_t sid = 0; sid < state.config.ss_number_layers; ++sid) {
574           if (state.config.ss_target_bitrate[sid] == 0) {
575             // Don't encode disabled spatial layers.
576             continue;
577           }
578           bool drop = true;
579           switch (state.frame_drop.framedrop_mode) {
580             case FULL_SUPERFRAME_DROP:
581               drop = encode_spatial_layers == 0;
582               break;
583             case LAYER_DROP:
584               drop = (encode_spatial_layers & (1 << sid)) == 0;
585               break;
586             case CONSTRAINED_LAYER_DROP:
587               drop = DropBelow(encode_spatial_layers, sid,
588                                state.config.ss_number_layers);
589               break;
590             case CONSTRAINED_FROM_ABOVE_DROP:
591               drop = DropAbove(encode_spatial_layers, sid);
592               break;
593           }
594           if (!drop) {
595             state.layer_id.spatial_layer_id = sid;
596             state.callback.output_cx_pkt(&state.pkt, state.callback.user_priv);
597           }
598         }
599       } break;
600       case kSetRates: {
601         // bitmask of the action: (S2)(S1)(S0)01,
602         // where Sx is number of temporal layers to enable for spatial layer x
603         // In pariculat Sx = 0 indicates spatial layer x should be disabled.
604         LibvpxVp9Encoder::RateControlParameters parameters;
605         parameters.framerate_fps = 30.0;
606         for (int sid = 0; sid < codec.VP9()->numberOfSpatialLayers; ++sid) {
607           int temporal_layers = (action >> ((1 + sid) * 2)) & 0b11;
608           for (int tid = 0; tid < temporal_layers; ++tid) {
609             parameters.bitrate.SetBitrate(sid, tid, kBitrateEnabledBps);
610           }
611         }
612         if (IsSupported(codec.VP9()->numberOfSpatialLayers,
613                         codec.VP9()->numberOfTemporalLayers,
614                         parameters.bitrate)) {
615           encoder.SetRates(parameters);
616         }
617       } break;
618       default:
619         // Unspecificed values are noop.
620         break;
621     }
622   }
623 }
624 }  // namespace webrtc
625