Merge "[spatial svc] Remove encoding modes since we only need one mode at this time."
This commit is contained in:
commit
83269ff8ff
@ -28,16 +28,6 @@
|
|||||||
#include "vpx/vpx_encoder.h"
|
#include "vpx/vpx_encoder.h"
|
||||||
#include "./vpxstats.h"
|
#include "./vpxstats.h"
|
||||||
|
|
||||||
static const struct arg_enum_list encoding_mode_enum[] = {
|
|
||||||
{"i", INTER_LAYER_PREDICTION_I},
|
|
||||||
{"alt-ip", ALT_INTER_LAYER_PREDICTION_IP},
|
|
||||||
{"ip", INTER_LAYER_PREDICTION_IP},
|
|
||||||
{"gf", USE_GOLDEN_FRAME},
|
|
||||||
{NULL, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const arg_def_t encoding_mode_arg = ARG_DEF_ENUM(
|
|
||||||
"m", "encoding-mode", 1, "Encoding mode algorithm", encoding_mode_enum);
|
|
||||||
static const arg_def_t skip_frames_arg =
|
static const arg_def_t skip_frames_arg =
|
||||||
ARG_DEF("s", "skip-frames", 1, "input frames to skip");
|
ARG_DEF("s", "skip-frames", 1, "input frames to skip");
|
||||||
static const arg_def_t frames_arg =
|
static const arg_def_t frames_arg =
|
||||||
@ -74,15 +64,13 @@ static const arg_def_t max_bitrate_arg =
|
|||||||
ARG_DEF(NULL, "max-bitrate", 1, "Maximum bitrate");
|
ARG_DEF(NULL, "max-bitrate", 1, "Maximum bitrate");
|
||||||
|
|
||||||
static const arg_def_t *svc_args[] = {
|
static const arg_def_t *svc_args[] = {
|
||||||
&encoding_mode_arg, &frames_arg, &width_arg, &height_arg,
|
&frames_arg, &width_arg, &height_arg,
|
||||||
&timebase_arg, &bitrate_arg, &skip_frames_arg, &layers_arg,
|
&timebase_arg, &bitrate_arg, &skip_frames_arg, &layers_arg,
|
||||||
&kf_dist_arg, &scale_factors_arg, &quantizers_arg, &passes_arg,
|
&kf_dist_arg, &scale_factors_arg, &quantizers_arg, &passes_arg,
|
||||||
&pass_arg, &fpf_name_arg, &min_q_arg, &max_q_arg,
|
&pass_arg, &fpf_name_arg, &min_q_arg, &max_q_arg,
|
||||||
&min_bitrate_arg, &max_bitrate_arg, NULL
|
&min_bitrate_arg, &max_bitrate_arg, NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const SVC_ENCODING_MODE default_encoding_mode =
|
|
||||||
INTER_LAYER_PREDICTION_IP;
|
|
||||||
static const uint32_t default_frames_to_skip = 0;
|
static const uint32_t default_frames_to_skip = 0;
|
||||||
static const uint32_t default_frames_to_code = 60 * 60;
|
static const uint32_t default_frames_to_code = 60 * 60;
|
||||||
static const uint32_t default_width = 1920;
|
static const uint32_t default_width = 1920;
|
||||||
@ -131,7 +119,6 @@ static void parse_command_line(int argc, const char **argv_,
|
|||||||
// initialize SvcContext with parameters that will be passed to vpx_svc_init
|
// initialize SvcContext with parameters that will be passed to vpx_svc_init
|
||||||
svc_ctx->log_level = SVC_LOG_DEBUG;
|
svc_ctx->log_level = SVC_LOG_DEBUG;
|
||||||
svc_ctx->spatial_layers = default_spatial_layers;
|
svc_ctx->spatial_layers = default_spatial_layers;
|
||||||
svc_ctx->encoding_mode = default_encoding_mode;
|
|
||||||
|
|
||||||
// start with default encoder configuration
|
// start with default encoder configuration
|
||||||
res = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), enc_cfg, 0);
|
res = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), enc_cfg, 0);
|
||||||
@ -157,9 +144,7 @@ static void parse_command_line(int argc, const char **argv_,
|
|||||||
for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
|
for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
|
||||||
arg.argv_step = 1;
|
arg.argv_step = 1;
|
||||||
|
|
||||||
if (arg_match(&arg, &encoding_mode_arg, argi)) {
|
if (arg_match(&arg, &frames_arg, argi)) {
|
||||||
svc_ctx->encoding_mode = arg_parse_enum_or_int(&arg);
|
|
||||||
} else if (arg_match(&arg, &frames_arg, argi)) {
|
|
||||||
app_input->frames_to_code = arg_parse_uint(&arg);
|
app_input->frames_to_code = arg_parse_uint(&arg);
|
||||||
} else if (arg_match(&arg, &width_arg, argi)) {
|
} else if (arg_match(&arg, &width_arg, argi)) {
|
||||||
enc_cfg->g_w = arg_parse_uint(&arg);
|
enc_cfg->g_w = arg_parse_uint(&arg);
|
||||||
@ -264,12 +249,12 @@ static void parse_command_line(int argc, const char **argv_,
|
|||||||
|
|
||||||
printf(
|
printf(
|
||||||
"Codec %s\nframes: %d, skip: %d\n"
|
"Codec %s\nframes: %d, skip: %d\n"
|
||||||
"mode: %d, layers: %d\n"
|
"layers: %d\n"
|
||||||
"width %d, height: %d,\n"
|
"width %d, height: %d,\n"
|
||||||
"num: %d, den: %d, bitrate: %d,\n"
|
"num: %d, den: %d, bitrate: %d,\n"
|
||||||
"gop size: %d\n",
|
"gop size: %d\n",
|
||||||
vpx_codec_iface_name(vpx_codec_vp9_cx()), app_input->frames_to_code,
|
vpx_codec_iface_name(vpx_codec_vp9_cx()), app_input->frames_to_code,
|
||||||
app_input->frames_to_skip, svc_ctx->encoding_mode,
|
app_input->frames_to_skip,
|
||||||
svc_ctx->spatial_layers, enc_cfg->g_w, enc_cfg->g_h,
|
svc_ctx->spatial_layers, enc_cfg->g_w, enc_cfg->g_h,
|
||||||
enc_cfg->g_timebase.num, enc_cfg->g_timebase.den,
|
enc_cfg->g_timebase.num, enc_cfg->g_timebase.den,
|
||||||
enc_cfg->rc_target_bitrate, enc_cfg->kf_max_dist);
|
enc_cfg->rc_target_bitrate, enc_cfg->kf_max_dist);
|
||||||
|
@ -41,7 +41,6 @@ class SvcTest : public ::testing::Test {
|
|||||||
virtual ~SvcTest() {}
|
virtual ~SvcTest() {}
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
svc_.encoding_mode = INTER_LAYER_PREDICTION_IP;
|
|
||||||
svc_.log_level = SVC_LOG_DEBUG;
|
svc_.log_level = SVC_LOG_DEBUG;
|
||||||
svc_.log_print = 0;
|
svc_.log_print = 0;
|
||||||
|
|
||||||
@ -131,22 +130,13 @@ TEST_F(SvcTest, SetLayersOption) {
|
|||||||
EXPECT_EQ(3, svc_.spatial_layers);
|
EXPECT_EQ(3, svc_.spatial_layers);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SvcTest, SetEncodingMode) {
|
|
||||||
vpx_codec_err_t res = vpx_svc_set_options(&svc_, "encoding-mode=alt-ip");
|
|
||||||
EXPECT_EQ(VPX_CODEC_OK, res);
|
|
||||||
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
|
|
||||||
EXPECT_EQ(VPX_CODEC_OK, res);
|
|
||||||
codec_initialized_ = true;
|
|
||||||
EXPECT_EQ(ALT_INTER_LAYER_PREDICTION_IP, svc_.encoding_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SvcTest, SetMultipleOptions) {
|
TEST_F(SvcTest, SetMultipleOptions) {
|
||||||
vpx_codec_err_t res = vpx_svc_set_options(&svc_, "layers=2 encoding-mode=ip");
|
vpx_codec_err_t res =
|
||||||
|
vpx_svc_set_options(&svc_, "layers=2 scale-factors=1/3,2/3");
|
||||||
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
|
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
|
||||||
EXPECT_EQ(VPX_CODEC_OK, res);
|
EXPECT_EQ(VPX_CODEC_OK, res);
|
||||||
codec_initialized_ = true;
|
codec_initialized_ = true;
|
||||||
EXPECT_EQ(2, svc_.spatial_layers);
|
EXPECT_EQ(2, svc_.spatial_layers);
|
||||||
EXPECT_EQ(INTER_LAYER_PREDICTION_IP, svc_.encoding_mode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SvcTest, SetScaleFactorsOption) {
|
TEST_F(SvcTest, SetScaleFactorsOption) {
|
||||||
|
@ -194,23 +194,6 @@ static int svc_log(SvcContext *svc_ctx, SVC_LOG_LEVEL level,
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static vpx_codec_err_t set_option_encoding_mode(SvcContext *svc_ctx,
|
|
||||||
const char *value_str) {
|
|
||||||
if (strcmp(value_str, "i") == 0) {
|
|
||||||
svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_I;
|
|
||||||
} else if (strcmp(value_str, "alt-ip") == 0) {
|
|
||||||
svc_ctx->encoding_mode = ALT_INTER_LAYER_PREDICTION_IP;
|
|
||||||
} else if (strcmp(value_str, "ip") == 0) {
|
|
||||||
svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_IP;
|
|
||||||
} else if (strcmp(value_str, "gf") == 0) {
|
|
||||||
svc_ctx->encoding_mode = USE_GOLDEN_FRAME;
|
|
||||||
} else {
|
|
||||||
svc_log(svc_ctx, SVC_LOG_ERROR, "invalid encoding mode: %s", value_str);
|
|
||||||
return VPX_CODEC_INVALID_PARAM;
|
|
||||||
}
|
|
||||||
return VPX_CODEC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx,
|
static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx,
|
||||||
const char *quantizer_values) {
|
const char *quantizer_values) {
|
||||||
char *input_string;
|
char *input_string;
|
||||||
@ -344,10 +327,7 @@ static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
|
|||||||
res = VPX_CODEC_INVALID_PARAM;
|
res = VPX_CODEC_INVALID_PARAM;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (strcmp("encoding-mode", option_name) == 0) {
|
if (strcmp("layers", option_name) == 0) {
|
||||||
res = set_option_encoding_mode(svc_ctx, option_value);
|
|
||||||
if (res != VPX_CODEC_OK) break;
|
|
||||||
} else if (strcmp("layers", option_name) == 0) {
|
|
||||||
svc_ctx->spatial_layers = atoi(option_value);
|
svc_ctx->spatial_layers = atoi(option_value);
|
||||||
} else if (strcmp("scale-factors", option_name) == 0) {
|
} else if (strcmp("scale-factors", option_name) == 0) {
|
||||||
res = parse_scale_factors(svc_ctx, option_value);
|
res = parse_scale_factors(svc_ctx, option_value);
|
||||||
@ -591,62 +571,14 @@ static void calculate_enc_frame_flags(SvcContext *svc_ctx) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (svc_ctx->encoding_mode) {
|
if (si->layer == 0) {
|
||||||
case ALT_INTER_LAYER_PREDICTION_IP:
|
flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
|
||||||
if (si->layer == 0) {
|
} else if (is_keyframe) {
|
||||||
flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
|
flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
|
||||||
} else if (is_keyframe) {
|
} else {
|
||||||
if (si->layer == si->layers - 1) {
|
flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST);
|
||||||
flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
|
|
||||||
} else {
|
|
||||||
flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case INTER_LAYER_PREDICTION_I:
|
|
||||||
if (si->layer == 0) {
|
|
||||||
flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
|
|
||||||
} else if (is_keyframe) {
|
|
||||||
flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
|
|
||||||
} else {
|
|
||||||
flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case INTER_LAYER_PREDICTION_IP:
|
|
||||||
if (si->layer == 0) {
|
|
||||||
flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
|
|
||||||
} else if (is_keyframe) {
|
|
||||||
flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
|
|
||||||
} else {
|
|
||||||
flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case USE_GOLDEN_FRAME:
|
|
||||||
if (2 * si->layers - SVC_REFERENCE_FRAMES <= si->layer) {
|
|
||||||
if (si->layer == 0) {
|
|
||||||
flags = map_vp8_flags(USE_LAST | USE_GF | UPDATE_LAST);
|
|
||||||
} else if (is_keyframe) {
|
|
||||||
flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF);
|
|
||||||
} else {
|
|
||||||
flags = map_vp8_flags(USE_LAST | USE_ARF | USE_GF | UPDATE_LAST);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (si->layer == 0) {
|
|
||||||
flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
|
|
||||||
} else if (is_keyframe) {
|
|
||||||
flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
|
|
||||||
} else {
|
|
||||||
flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
svc_log(svc_ctx, SVC_LOG_ERROR, "unexpected encoding mode: %d\n",
|
|
||||||
svc_ctx->encoding_mode);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
si->enc_frame_flags = flags;
|
si->enc_frame_flags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -692,13 +624,6 @@ static void set_svc_parameters(SvcContext *svc_ctx,
|
|||||||
svc_params.flags = si->enc_frame_flags;
|
svc_params.flags = si->enc_frame_flags;
|
||||||
|
|
||||||
layer = si->layer;
|
layer = si->layer;
|
||||||
if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
|
|
||||||
si->frame_within_gop == 0) {
|
|
||||||
// layers 1 & 3 don't exist in this mode, use the higher one
|
|
||||||
if (layer == 0 || layer == 2) {
|
|
||||||
layer += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer,
|
if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer,
|
||||||
&svc_params.width,
|
&svc_params.width,
|
||||||
&svc_params.height)) {
|
&svc_params.height)) {
|
||||||
@ -720,21 +645,8 @@ static void set_svc_parameters(SvcContext *svc_ctx,
|
|||||||
svc_params.lst_fb_idx = si->layer;
|
svc_params.lst_fb_idx = si->layer;
|
||||||
|
|
||||||
// Use buffer i-1 for layer i Alt (Inter-layer prediction)
|
// Use buffer i-1 for layer i Alt (Inter-layer prediction)
|
||||||
if (si->layer != 0) {
|
svc_params.alt_fb_idx = (si->layer > 0) ? si->layer - 1 : 0;
|
||||||
const int use_higher_layer =
|
svc_params.gld_fb_idx = svc_params.lst_fb_idx;
|
||||||
svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
|
|
||||||
si->frame_within_gop == 0;
|
|
||||||
svc_params.alt_fb_idx = use_higher_layer ? si->layer - 2 : si->layer - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP) {
|
|
||||||
svc_params.gld_fb_idx = si->layer + 1;
|
|
||||||
} else {
|
|
||||||
if (si->layer < 2 * si->layers - SVC_REFERENCE_FRAMES)
|
|
||||||
svc_params.gld_fb_idx = svc_params.lst_fb_idx;
|
|
||||||
else
|
|
||||||
svc_params.gld_fb_idx = 2 * si->layers - 1 - si->layer;
|
|
||||||
}
|
|
||||||
|
|
||||||
svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, layer: %d, %dx%d, q: %d\n",
|
svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, layer: %d, %dx%d, q: %d\n",
|
||||||
si->encode_frame_count, si->layer, svc_params.width,
|
si->encode_frame_count, si->layer, svc_params.width,
|
||||||
@ -793,11 +705,6 @@ vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
|
|||||||
if (rawimg != NULL) {
|
if (rawimg != NULL) {
|
||||||
// encode each layer
|
// encode each layer
|
||||||
for (si->layer = 0; si->layer < si->layers; ++si->layer) {
|
for (si->layer = 0; si->layer < si->layers; ++si->layer) {
|
||||||
if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
|
|
||||||
si->is_keyframe && (si->layer == 1 || si->layer == 3)) {
|
|
||||||
svc_log(svc_ctx, SVC_LOG_DEBUG, "Skip encoding layer %d\n", si->layer);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
calculate_enc_frame_flags(svc_ctx);
|
calculate_enc_frame_flags(svc_ctx);
|
||||||
set_svc_parameters(svc_ctx, codec_ctx);
|
set_svc_parameters(svc_ctx, codec_ctx);
|
||||||
}
|
}
|
||||||
@ -936,7 +843,7 @@ static double calc_psnr(double d) {
|
|||||||
|
|
||||||
// dump accumulated statistics and reset accumulated values
|
// dump accumulated statistics and reset accumulated values
|
||||||
const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) {
|
const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) {
|
||||||
int number_of_frames, number_of_keyframes, encode_frame_count;
|
int number_of_frames, encode_frame_count;
|
||||||
int i, j;
|
int i, j;
|
||||||
uint32_t bytes_total = 0;
|
uint32_t bytes_total = 0;
|
||||||
double scale[COMPONENTS];
|
double scale[COMPONENTS];
|
||||||
@ -953,14 +860,9 @@ const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) {
|
|||||||
if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx);
|
if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx);
|
||||||
|
|
||||||
svc_log(svc_ctx, SVC_LOG_INFO, "\n");
|
svc_log(svc_ctx, SVC_LOG_INFO, "\n");
|
||||||
number_of_keyframes = encode_frame_count / si->kf_dist + 1;
|
|
||||||
for (i = 0; i < si->layers; ++i) {
|
for (i = 0; i < si->layers; ++i) {
|
||||||
number_of_frames = encode_frame_count;
|
number_of_frames = encode_frame_count;
|
||||||
|
|
||||||
if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
|
|
||||||
(i == 1 || i == 3)) {
|
|
||||||
number_of_frames -= number_of_keyframes;
|
|
||||||
}
|
|
||||||
svc_log(svc_ctx, SVC_LOG_INFO,
|
svc_log(svc_ctx, SVC_LOG_INFO,
|
||||||
"Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n",
|
"Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n",
|
||||||
i, (double)si->psnr_sum[i][0] / number_of_frames,
|
i, (double)si->psnr_sum[i][0] / number_of_frames,
|
||||||
|
@ -23,13 +23,6 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum SVC_ENCODING_MODE {
|
|
||||||
INTER_LAYER_PREDICTION_I,
|
|
||||||
ALT_INTER_LAYER_PREDICTION_IP,
|
|
||||||
INTER_LAYER_PREDICTION_IP,
|
|
||||||
USE_GOLDEN_FRAME
|
|
||||||
} SVC_ENCODING_MODE;
|
|
||||||
|
|
||||||
typedef enum SVC_LOG_LEVEL {
|
typedef enum SVC_LOG_LEVEL {
|
||||||
SVC_LOG_ERROR,
|
SVC_LOG_ERROR,
|
||||||
SVC_LOG_INFO,
|
SVC_LOG_INFO,
|
||||||
@ -39,7 +32,6 @@ typedef enum SVC_LOG_LEVEL {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
// public interface to svc_command options
|
// public interface to svc_command options
|
||||||
int spatial_layers; // number of layers
|
int spatial_layers; // number of layers
|
||||||
SVC_ENCODING_MODE encoding_mode; // svc encoding strategy
|
|
||||||
SVC_LOG_LEVEL log_level; // amount of information to display
|
SVC_LOG_LEVEL log_level; // amount of information to display
|
||||||
int log_print; // when set, printf log messages instead of returning the
|
int log_print; // when set, printf log messages instead of returning the
|
||||||
// message with svc_get_message
|
// message with svc_get_message
|
||||||
|
Loading…
x
Reference in New Issue
Block a user