1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
media / gpu / test / video_frame_validator.h [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_GPU_TEST_VIDEO_FRAME_VALIDATOR_H_
#define MEDIA_GPU_TEST_VIDEO_FRAME_VALIDATOR_H_
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/files/file.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
#include "media/base/video_types.h"
#include "media/gpu/test/video_frame_helpers.h"
#include "ui/gfx/geometry/rect.h"
namespace media {
class VideoFrame;
class VideoFrameMapper;
namespace test {
// VideoFrameValidator validates the pixel content of each video frame.
// It maps a video frame by using VideoFrameMapper if needed. If the validation
// fails, the frame is processed by |corrupt_frame_processor_|.
// VideoFrameValidator is created by calling Create() of the child classes in
// below.
// Mapping and verification of a frame is a costly operation and will influence
// performance measurements.
class VideoFrameValidator : public VideoFrameProcessor {
public:
// This mode can be specified for PSNR and SSIM VideoFrameValidator.
enum class ValidationMode {
kThreshold, // Each frame's quality need to pass the specified threshold.
kAverage, // The average quality needs to pass the specified value.
};
// Get the model frame from |frame_index|.
using GetModelFrameCB =
base::RepeatingCallback<scoped_refptr<const VideoFrame>(size_t)>;
using CropHelper =
base::RepeatingCallback<gfx::Rect(const VideoFrame& frame)>;
VideoFrameValidator(const VideoFrameValidator&) = delete;
VideoFrameValidator& operator=(const VideoFrameValidator&) = delete;
~VideoFrameValidator() override;
// Prints information of frames on which the validation failed. This function
// is thread-safe.
void PrintMismatchedFramesInfo() const;
// Returns the number of frames on which the validation failed. This function
// is thread-safe.
size_t GetMismatchedFramesCount() const;
// Interface VideoFrameProcessor
void ProcessVideoFrame(scoped_refptr<const VideoFrame> video_frame,
size_t frame_index) final;
// Wait until all currently scheduled frame validations are done. Returns true
// if no corrupt frames were found. This function might take a long time to
// complete, depending on the platform.
bool WaitUntilDone() final;
protected:
struct MismatchedFrameInfo {
MismatchedFrameInfo(size_t frame_index) : frame_index(frame_index) {}
virtual ~MismatchedFrameInfo() = default;
virtual void Print() const = 0;
size_t frame_index;
};
VideoFrameValidator(
std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor,
CropHelper crop_helper);
// Start the frame validation thread.
bool Initialize();
SEQUENCE_CHECKER(validator_thread_sequence_checker_);
// Returns true if the processed frame or model frame should be cropped with
// CloneAndCropFrame() or VideoFrame::WrapVideoFrame().
bool ShouldCrop() const { return static_cast<bool>(crop_helper_); }
// This can be used by VideoFrameValidators to support cropping.
scoped_refptr<VideoFrame> CloneAndCropFrame(
scoped_refptr<const VideoFrame> frame) const;
private:
void CleanUpOnValidatorThread();
// Stop the frame validation thread.
void Destroy();
// Validate the |video_frame|'s content on the |frame_validator_thread_|.
void ProcessVideoFrameTask(scoped_refptr<const VideoFrame> video_frame,
size_t frame_index);
virtual std::unique_ptr<MismatchedFrameInfo> Validate(
scoped_refptr<const VideoFrame> frame,
size_t frame_index) = 0;
// Returns whether the overall validation passed.
virtual bool Passed() const;
std::unique_ptr<VideoFrameMapper> video_frame_mapper_;
// An optional video frame processor that all corrupted frames will be
// forwarded to. This can be used to e.g. write corrupted frames to disk.
std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor_;
// If |crop_helper_| is runnable, then ShouldCrop() will return true and
// CloneAndCropFrame() can be used.
const CropHelper crop_helper_;
// The number of frames currently queued for validation.
size_t num_frames_validating_ GUARDED_BY(frame_validator_lock_);
// The results of invalid frame data.
std::vector<std::unique_ptr<MismatchedFrameInfo>> mismatched_frames_
GUARDED_BY(frame_validator_lock_);
// Thread on which video frame validation is done.
base::Thread frame_validator_thread_;
mutable base::Lock frame_validator_lock_;
mutable base::ConditionVariable frame_validator_cv_;
SEQUENCE_CHECKER(validator_sequence_checker_);
};
// Returns a cropping rectangle containing the bottom |row_height| rows of the
// input frame. This can be used by VideoFrameValidator::CropHelper.
gfx::Rect BottomRowCrop(int row_height, const VideoFrame& frame);
constexpr int kDefaultBottomRowCropHeight = 2;
// Validate by converting the frame to be validated to |validation_format| to
// resolve pixel format differences on different platforms. Thereafter, it
// compares md5 values of the mapped and converted buffer with golden md5
// values. The golden values are prepared in advance and must be identical on
// all platforms.
class MD5VideoFrameValidator : public VideoFrameValidator {
public:
static std::unique_ptr<MD5VideoFrameValidator> Create(
const std::vector<std::string>& expected_frame_checksums,
VideoPixelFormat validation_format = PIXEL_FORMAT_I420,
std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor = nullptr,
CropHelper crop_helper = CropHelper());
~MD5VideoFrameValidator() override;
private:
struct MD5MismatchedFrameInfo;
MD5VideoFrameValidator(
const std::vector<std::string>& expected_frame_checksums,
VideoPixelFormat validation_format,
std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor,
CropHelper crop_helper);
MD5VideoFrameValidator(const MD5VideoFrameValidator&) = delete;
MD5VideoFrameValidator& operator=(const MD5VideoFrameValidator&) = delete;
// VideoFrameValidator implementation.
std::unique_ptr<MismatchedFrameInfo> Validate(
scoped_refptr<const VideoFrame> frame,
size_t frame_index) override;
// Returns md5 values of video frame represented by |video_frame|.
std::string ComputeMD5FromVideoFrame(const VideoFrame& video_frame) const;
const std::vector<std::string> expected_frame_checksums_;
const VideoPixelFormat validation_format_;
};
// Validate by comparing each byte of visible area of the frame to be validated.
// An absolute difference equal to or less than |torelance_| is allowed on
// the comparison.
class RawVideoFrameValidator : public VideoFrameValidator {
public:
constexpr static uint8_t kDefaultTolerance = 4;
static std::unique_ptr<RawVideoFrameValidator> Create(
const GetModelFrameCB& get_model_frame_cb,
std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor = nullptr,
uint8_t tolerance = kDefaultTolerance,
CropHelper crop_helper = CropHelper());
~RawVideoFrameValidator() override;
private:
struct RawMismatchedFrameInfo;
RawVideoFrameValidator(
const GetModelFrameCB& get_model_frame_cb,
std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor,
uint8_t tolerance,
CropHelper crop_helper);
std::unique_ptr<MismatchedFrameInfo> Validate(
scoped_refptr<const VideoFrame> frame,
size_t frame_index) override;
const GetModelFrameCB get_model_frame_cb_;
const uint8_t tolerance_;
};
// |tolerance_|, the validation on the frame passes.
class PSNRVideoFrameValidator : public VideoFrameValidator {
public:
constexpr static double kDefaultTolerance = 25.0;
static std::unique_ptr<PSNRVideoFrameValidator> Create(
const GetModelFrameCB& get_model_frame_cb,
std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor = nullptr,
ValidationMode validation_mode = ValidationMode::kThreshold,
double tolerance = kDefaultTolerance,
CropHelper crop_helper = CropHelper());
const std::map<size_t, double>& GetPSNRValues() const { return psnr_; }
~PSNRVideoFrameValidator() override;
private:
struct PSNRMismatchedFrameInfo;
PSNRVideoFrameValidator(
const GetModelFrameCB& get_model_frame_cb,
std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor,
ValidationMode validation_mode,
double tolerance,
CropHelper crop_helper);
std::unique_ptr<MismatchedFrameInfo> Validate(
scoped_refptr<const VideoFrame> frame,
size_t frame_index) override;
bool Passed() const override;
const GetModelFrameCB get_model_frame_cb_;
const CropHelper crop_helper_;
const double tolerance_;
const ValidationMode validation_mode_;
std::map<size_t, double> psnr_;
};
// Validate by computing SSIM from the frame to be validated and the model frame
// acquired by |get_model_frame_cb_|. If the SSIM value is equal to or more than
// |tolerance_|, the validation on the frame passes.
class SSIMVideoFrameValidator : public VideoFrameValidator {
public:
constexpr static double kDefaultTolerance = 0.70;
static std::unique_ptr<SSIMVideoFrameValidator> Create(
const GetModelFrameCB& get_model_frame_cb,
std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor = nullptr,
ValidationMode validation_mode = ValidationMode::kThreshold,
double tolerance = kDefaultTolerance,
CropHelper crop_helper = CropHelper());
const std::map<size_t, double>& GetSSIMValues() const { return ssim_; }
~SSIMVideoFrameValidator() override;
private:
struct SSIMMismatchedFrameInfo;
SSIMVideoFrameValidator(
const GetModelFrameCB& get_model_frame_cb,
std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor,
ValidationMode validation_mode,
double tolerance,
CropHelper crop_helper);
std::unique_ptr<MismatchedFrameInfo> Validate(
scoped_refptr<const VideoFrame> frame,
size_t frame_index) override;
bool Passed() const override;
const GetModelFrameCB get_model_frame_cb_;
const double tolerance_;
const ValidationMode validation_mode_;
std::map<size_t, double> ssim_;
};
// Validate by computing the log likelihood ratio of the frame to be validate
// and the model frame acquired by |get_model_frame_cb_|. If the log likelihood
// ratio is less than or equal to |tolerance_|, the validation on the frame
// passes.
class LogLikelihoodRatioVideoFrameValidator : public VideoFrameValidator {
public:
// Default tolerance value chosen empirically.
constexpr static double kDefaultTolerance = 1.015;
static std::unique_ptr<LogLikelihoodRatioVideoFrameValidator> Create(
const GetModelFrameCB& get_model_frame_cb,
std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor = nullptr,
ValidationMode validation_mode = ValidationMode::kThreshold,
double tolerance = kDefaultTolerance,
CropHelper crop_helper = CropHelper());
const std::map<size_t, double>& get_log_likelihood_ratio_values() const {
return log_likelihood_ratios_;
}
~LogLikelihoodRatioVideoFrameValidator() override;
private:
struct LogLikelihoodRatioMismatchedFrameInfo;
LogLikelihoodRatioVideoFrameValidator(
const GetModelFrameCB& get_model_frame_cb,
std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor,
ValidationMode validation_mode,
double tolerance,
CropHelper crop_helper);
std::unique_ptr<MismatchedFrameInfo> Validate(
scoped_refptr<const VideoFrame> frame,
size_t frame_index) override;
const GetModelFrameCB get_model_frame_cb_;
const double tolerance_;
std::map<size_t, double> log_likelihood_ratios_;
};
} // namespace test
} // namespace media
#endif // MEDIA_GPU_TEST_VIDEO_FRAME_VALIDATOR_H_