Reworks high-bit-depth profiles
Splits profile 2 into Profile 2 and 3, where profile 2 ony supports 420 sampling, while profile 3 adds 422/444 and alpha. Keeps room for further expansion. Also makes some minor changes in the decoder parameters, replacing --convert-to-8bit with output-bit-depth. Change-Id: I713525880512de6c36698d212795db1543c1d0dd
This commit is contained in:
@@ -26,14 +26,17 @@ extern "C" {
|
|||||||
#define MI_MASK (MI_BLOCK_SIZE - 1)
|
#define MI_MASK (MI_BLOCK_SIZE - 1)
|
||||||
|
|
||||||
// Bitstream profiles indicated by 2 bits in the uncompressed header.
|
// Bitstream profiles indicated by 2 bits in the uncompressed header.
|
||||||
// 00: Profile 0. 4:2:0 only.
|
// 00: Profile 0. 8-bit 4:2:0 only.
|
||||||
// 10: Profile 1. adds 4:4:4, 4:2:2, alpha.
|
// 10: Profile 1. Adds 4:4:4, 4:2:2, alpha to Profile 0.
|
||||||
// 01: Profile 2. Supports 10-bit and 12-bit color only.
|
// 01: Profile 2. Supports 10-bit and 12-bit color only, with 4:2:0 sampling.
|
||||||
// 11: Undefined profile.
|
// 110: Profile 3. Supports 10-bit and 12-bit color only, with 4:2:2/4:4:4
|
||||||
|
// sampling and alpha.
|
||||||
|
// 111: Undefined profile.
|
||||||
typedef enum BITSTREAM_PROFILE {
|
typedef enum BITSTREAM_PROFILE {
|
||||||
PROFILE_0,
|
PROFILE_0,
|
||||||
PROFILE_1,
|
PROFILE_1,
|
||||||
PROFILE_2,
|
PROFILE_2,
|
||||||
|
PROFILE_3,
|
||||||
MAX_PROFILES
|
MAX_PROFILES
|
||||||
} BITSTREAM_PROFILE;
|
} BITSTREAM_PROFILE;
|
||||||
|
|
||||||
|
@@ -1109,9 +1109,11 @@ static void error_handler(void *data) {
|
|||||||
vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME, "Truncated packet");
|
vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME, "Truncated packet");
|
||||||
}
|
}
|
||||||
|
|
||||||
static BITSTREAM_PROFILE read_profile(struct vp9_read_bit_buffer *rb) {
|
BITSTREAM_PROFILE vp9_read_profile(struct vp9_read_bit_buffer *rb) {
|
||||||
int profile = vp9_rb_read_bit(rb);
|
int profile = vp9_rb_read_bit(rb);
|
||||||
profile |= vp9_rb_read_bit(rb) << 1;
|
profile |= vp9_rb_read_bit(rb) << 1;
|
||||||
|
if (profile > 2)
|
||||||
|
profile += vp9_rb_read_bit(rb);
|
||||||
return (BITSTREAM_PROFILE) profile;
|
return (BITSTREAM_PROFILE) profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1127,7 +1129,7 @@ static size_t read_uncompressed_header(VP9Decoder *pbi,
|
|||||||
vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM,
|
vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM,
|
||||||
"Invalid frame marker");
|
"Invalid frame marker");
|
||||||
|
|
||||||
cm->profile = read_profile(rb);
|
cm->profile = vp9_read_profile(rb);
|
||||||
if (cm->profile >= MAX_PROFILES)
|
if (cm->profile >= MAX_PROFILES)
|
||||||
vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM,
|
vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM,
|
||||||
"Unsupported bitstream profile");
|
"Unsupported bitstream profile");
|
||||||
@@ -1173,7 +1175,7 @@ static size_t read_uncompressed_header(VP9Decoder *pbi,
|
|||||||
cm->color_space = (COLOR_SPACE)vp9_rb_read_literal(rb, 3);
|
cm->color_space = (COLOR_SPACE)vp9_rb_read_literal(rb, 3);
|
||||||
if (cm->color_space != SRGB) {
|
if (cm->color_space != SRGB) {
|
||||||
vp9_rb_read_bit(rb); // [16,235] (including xvycc) vs [0,255] range
|
vp9_rb_read_bit(rb); // [16,235] (including xvycc) vs [0,255] range
|
||||||
if (cm->profile >= PROFILE_1) {
|
if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) {
|
||||||
cm->subsampling_x = vp9_rb_read_bit(rb);
|
cm->subsampling_x = vp9_rb_read_bit(rb);
|
||||||
cm->subsampling_y = vp9_rb_read_bit(rb);
|
cm->subsampling_y = vp9_rb_read_bit(rb);
|
||||||
vp9_rb_read_bit(rb); // has extra plane
|
vp9_rb_read_bit(rb); // has extra plane
|
||||||
@@ -1181,7 +1183,7 @@ static size_t read_uncompressed_header(VP9Decoder *pbi,
|
|||||||
cm->subsampling_y = cm->subsampling_x = 1;
|
cm->subsampling_y = cm->subsampling_x = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cm->profile >= PROFILE_1) {
|
if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) {
|
||||||
cm->subsampling_y = cm->subsampling_x = 0;
|
cm->subsampling_y = cm->subsampling_x = 0;
|
||||||
vp9_rb_read_bit(rb); // has extra plane
|
vp9_rb_read_bit(rb); // has extra plane
|
||||||
} else {
|
} else {
|
||||||
|
@@ -18,6 +18,7 @@ extern "C" {
|
|||||||
|
|
||||||
struct VP9Common;
|
struct VP9Common;
|
||||||
struct VP9Decoder;
|
struct VP9Decoder;
|
||||||
|
struct vp9_read_bit_buffer;
|
||||||
|
|
||||||
void vp9_init_dequantizer(struct VP9Common *cm);
|
void vp9_init_dequantizer(struct VP9Common *cm);
|
||||||
|
|
||||||
@@ -25,6 +26,8 @@ void vp9_decode_frame(struct VP9Decoder *pbi,
|
|||||||
const uint8_t *data, const uint8_t *data_end,
|
const uint8_t *data, const uint8_t *data_end,
|
||||||
const uint8_t **p_data_end);
|
const uint8_t **p_data_end);
|
||||||
|
|
||||||
|
BITSTREAM_PROFILE vp9_read_profile(struct vp9_read_bit_buffer *rb);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1036,8 +1036,27 @@ static void write_sync_code(struct vp9_write_bit_buffer *wb) {
|
|||||||
static void write_profile(BITSTREAM_PROFILE profile,
|
static void write_profile(BITSTREAM_PROFILE profile,
|
||||||
struct vp9_write_bit_buffer *wb) {
|
struct vp9_write_bit_buffer *wb) {
|
||||||
assert(profile < MAX_PROFILES);
|
assert(profile < MAX_PROFILES);
|
||||||
vp9_wb_write_bit(wb, profile & 1);
|
switch (profile) {
|
||||||
vp9_wb_write_bit(wb, profile >> 1);
|
case PROFILE_0:
|
||||||
|
vp9_wb_write_bit(wb, 0);
|
||||||
|
vp9_wb_write_bit(wb, 0);
|
||||||
|
break;
|
||||||
|
case PROFILE_1:
|
||||||
|
vp9_wb_write_bit(wb, 1);
|
||||||
|
vp9_wb_write_bit(wb, 0);
|
||||||
|
break;
|
||||||
|
case PROFILE_2:
|
||||||
|
vp9_wb_write_bit(wb, 0);
|
||||||
|
vp9_wb_write_bit(wb, 1);
|
||||||
|
break;
|
||||||
|
case PROFILE_3:
|
||||||
|
vp9_wb_write_bit(wb, 1);
|
||||||
|
vp9_wb_write_bit(wb, 1);
|
||||||
|
vp9_wb_write_bit(wb, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_uncompressed_header(VP9_COMP *cpi,
|
static void write_uncompressed_header(VP9_COMP *cpi,
|
||||||
@@ -1063,16 +1082,15 @@ static void write_uncompressed_header(VP9_COMP *cpi,
|
|||||||
vp9_wb_write_literal(wb, cs, 3);
|
vp9_wb_write_literal(wb, cs, 3);
|
||||||
if (cs != SRGB) {
|
if (cs != SRGB) {
|
||||||
vp9_wb_write_bit(wb, 0); // 0: [16, 235] (i.e. xvYCC), 1: [0, 255]
|
vp9_wb_write_bit(wb, 0); // 0: [16, 235] (i.e. xvYCC), 1: [0, 255]
|
||||||
if (cm->profile >= PROFILE_1) {
|
if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) {
|
||||||
vp9_wb_write_bit(wb, cm->subsampling_x);
|
vp9_wb_write_bit(wb, cm->subsampling_x);
|
||||||
vp9_wb_write_bit(wb, cm->subsampling_y);
|
vp9_wb_write_bit(wb, cm->subsampling_y);
|
||||||
vp9_wb_write_bit(wb, 0); // has extra plane
|
vp9_wb_write_bit(wb, 0); // has extra plane
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(cm->profile == PROFILE_1);
|
assert(cm->profile == PROFILE_1 || cm->profile == PROFILE_3);
|
||||||
vp9_wb_write_bit(wb, 0); // has extra plane
|
vp9_wb_write_bit(wb, 0); // has extra plane
|
||||||
}
|
}
|
||||||
|
|
||||||
write_frame_size(cm, wb);
|
write_frame_size(cm, wb);
|
||||||
} else {
|
} else {
|
||||||
if (!cm->show_frame)
|
if (!cm->show_frame)
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "vp9/decoder/vp9_decoder.h"
|
#include "vp9/decoder/vp9_decoder.h"
|
||||||
#include "vp9/decoder/vp9_read_bit_buffer.h"
|
#include "vp9/decoder/vp9_read_bit_buffer.h"
|
||||||
|
#include "vp9/decoder/vp9_decodeframe.h"
|
||||||
|
|
||||||
#include "vp9/vp9_iface_common.h"
|
#include "vp9/vp9_iface_common.h"
|
||||||
|
|
||||||
@@ -112,12 +113,11 @@ static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data,
|
|||||||
{
|
{
|
||||||
struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
|
struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
|
||||||
const int frame_marker = vp9_rb_read_literal(&rb, 2);
|
const int frame_marker = vp9_rb_read_literal(&rb, 2);
|
||||||
const int version = vp9_rb_read_bit(&rb);
|
const BITSTREAM_PROFILE profile = vp9_read_profile(&rb);
|
||||||
(void) vp9_rb_read_bit(&rb); // unused version bit
|
|
||||||
|
|
||||||
if (frame_marker != VP9_FRAME_MARKER)
|
if (frame_marker != VP9_FRAME_MARKER)
|
||||||
return VPX_CODEC_UNSUP_BITSTREAM;
|
return VPX_CODEC_UNSUP_BITSTREAM;
|
||||||
if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM;
|
if (profile >= MAX_PROFILES) return VPX_CODEC_UNSUP_BITSTREAM;
|
||||||
|
|
||||||
if (vp9_rb_read_bit(&rb)) { // show an existing frame
|
if (vp9_rb_read_bit(&rb)) { // show an existing frame
|
||||||
return VPX_CODEC_OK;
|
return VPX_CODEC_OK;
|
||||||
@@ -136,16 +136,17 @@ static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data,
|
|||||||
vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_2) {
|
vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_2) {
|
||||||
return VPX_CODEC_UNSUP_BITSTREAM;
|
return VPX_CODEC_UNSUP_BITSTREAM;
|
||||||
}
|
}
|
||||||
|
if (profile > PROFILE_1)
|
||||||
|
rb.bit_offset += 1; // Bit-depth 10 or 12
|
||||||
colorspace = vp9_rb_read_literal(&rb, 3);
|
colorspace = vp9_rb_read_literal(&rb, 3);
|
||||||
if (colorspace != sRGB) {
|
if (colorspace != sRGB) {
|
||||||
rb.bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range
|
rb.bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range
|
||||||
if (version == 1) {
|
if (profile == PROFILE_1 || profile == PROFILE_3) {
|
||||||
rb.bit_offset += 2; // subsampling x/y
|
rb.bit_offset += 2; // subsampling x/y
|
||||||
rb.bit_offset += 1; // has extra plane
|
rb.bit_offset += 1; // has extra plane
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (version == 1) {
|
if (profile == PROFILE_1 || profile == PROFILE_3) {
|
||||||
rb.bit_offset += 1; // has extra plane
|
rb.bit_offset += 1; // has extra plane
|
||||||
} else {
|
} else {
|
||||||
// RGB is only available in version 1
|
// RGB is only available in version 1
|
||||||
|
33
vpxdec.c
33
vpxdec.c
@@ -84,9 +84,9 @@ static const arg_def_t fb_arg =
|
|||||||
static const arg_def_t md5arg = ARG_DEF(
|
static const arg_def_t md5arg = ARG_DEF(
|
||||||
NULL, "md5", 0, "Compute the MD5 sum of the decoded frame");
|
NULL, "md5", 0, "Compute the MD5 sum of the decoded frame");
|
||||||
#if CONFIG_VP9_HIGH
|
#if CONFIG_VP9_HIGH
|
||||||
static const arg_def_t convertto8bitarg = ARG_DEF(
|
static const arg_def_t outbitdeptharg = ARG_DEF(
|
||||||
NULL, "convert-to-8bit", 0,
|
NULL, "output-bit-depth", 1,
|
||||||
"Output 8-bit frames even for high bitdepth streams");
|
"Output bit-depth for decoded frames");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const arg_def_t *all_args[] = {
|
static const arg_def_t *all_args[] = {
|
||||||
@@ -96,7 +96,7 @@ static const arg_def_t *all_args[] = {
|
|||||||
&md5arg,
|
&md5arg,
|
||||||
&error_concealment,
|
&error_concealment,
|
||||||
#if CONFIG_VP9_HIGH
|
#if CONFIG_VP9_HIGH
|
||||||
&convertto8bitarg,
|
&outbitdeptharg,
|
||||||
#endif
|
#endif
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
@@ -579,7 +579,7 @@ int main_loop(int argc, const char **argv_) {
|
|||||||
int use_y4m = 1;
|
int use_y4m = 1;
|
||||||
vpx_codec_dec_cfg_t cfg = {0};
|
vpx_codec_dec_cfg_t cfg = {0};
|
||||||
#if CONFIG_VP9_HIGH
|
#if CONFIG_VP9_HIGH
|
||||||
int convert_to_8bit = 0;
|
int out_bit_depth = 0;
|
||||||
#endif
|
#endif
|
||||||
#if CONFIG_VP8_DECODER
|
#if CONFIG_VP8_DECODER
|
||||||
vp8_postproc_cfg_t vp8_pp_cfg = {0};
|
vp8_postproc_cfg_t vp8_pp_cfg = {0};
|
||||||
@@ -662,8 +662,8 @@ int main_loop(int argc, const char **argv_) {
|
|||||||
num_external_frame_buffers = arg_parse_uint(&arg);
|
num_external_frame_buffers = arg_parse_uint(&arg);
|
||||||
|
|
||||||
#if CONFIG_VP9_HIGH
|
#if CONFIG_VP9_HIGH
|
||||||
else if (arg_match(&arg, &convertto8bitarg, argi)) {
|
else if (arg_match(&arg, &outbitdeptharg, argi)) {
|
||||||
convert_to_8bit = 1;
|
out_bit_depth = arg_parse_uint(&arg);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -850,7 +850,6 @@ int main_loop(int argc, const char **argv_) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
if (arg_skip)
|
if (arg_skip)
|
||||||
fprintf(stderr, "Skipping first %d frames.\n", arg_skip);
|
fprintf(stderr, "Skipping first %d frames.\n", arg_skip);
|
||||||
while (arg_skip) {
|
while (arg_skip) {
|
||||||
@@ -980,23 +979,21 @@ int main_loop(int argc, const char **argv_) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if CONFIG_VP9_HIGH
|
#if CONFIG_VP9_HIGH
|
||||||
if (convert_to_8bit) {
|
|
||||||
// Convert to an 8bit image
|
// Convert to an 8bit image
|
||||||
if (img->fmt & VPX_IMG_FMT_HIGH) {
|
if (img->fmt & VPX_IMG_FMT_HIGH) {
|
||||||
unsigned int bit_depth;
|
vpx_bit_depth_t bit_depth;
|
||||||
unsigned int shift = 0; // BITS_8 default
|
|
||||||
if (vpx_codec_control(&decoder, VP9D_GET_BIT_DEPTH, &bit_depth)) {
|
if (vpx_codec_control(&decoder, VP9D_GET_BIT_DEPTH, &bit_depth)) {
|
||||||
// Fallback to 8bit
|
// Fallback to 8bit
|
||||||
bit_depth = VPX_BITS_8;
|
bit_depth = VPX_BITS_8;
|
||||||
}
|
}
|
||||||
switch (bit_depth) {
|
if (out_bit_depth != 8 &&
|
||||||
case VPX_BITS_10: // BITS_10
|
out_bit_depth != bit_depth * 2 + 8) {
|
||||||
shift = 2;
|
fprintf(stderr, "Does not support bit-depth conversion to: %d.\n",
|
||||||
break;
|
out_bit_depth);
|
||||||
case VPX_BITS_12: // BITS_12
|
return EXIT_FAILURE;
|
||||||
shift = 4;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
if (out_bit_depth == 8) {
|
||||||
|
unsigned int shift = (int)bit_depth * 2;
|
||||||
if (!img_8bit) {
|
if (!img_8bit) {
|
||||||
img_8bit = vpx_img_alloc(NULL, img->fmt - VPX_IMG_FMT_HIGH,
|
img_8bit = vpx_img_alloc(NULL, img->fmt - VPX_IMG_FMT_HIGH,
|
||||||
img->d_w, img->d_h, 16);
|
img->d_w, img->d_h, 16);
|
||||||
|
19
vpxenc.c
19
vpxenc.c
@@ -362,6 +362,13 @@ static const int vp8_arg_ctrl_map[] = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_VP9_ENCODER
|
#if CONFIG_VP9_ENCODER
|
||||||
|
static const struct arg_enum_list aq_mode_enum[] = {
|
||||||
|
{"off", 0},
|
||||||
|
{"variance", 1},
|
||||||
|
{"complexity", 2},
|
||||||
|
{"cyclic", 3},
|
||||||
|
{NULL, 0}
|
||||||
|
};
|
||||||
static const arg_def_t tile_cols =
|
static const arg_def_t tile_cols =
|
||||||
ARG_DEF(NULL, "tile-columns", 1, "Number of tile columns to use, log2");
|
ARG_DEF(NULL, "tile-columns", 1, "Number of tile columns to use, log2");
|
||||||
static const arg_def_t tile_rows =
|
static const arg_def_t tile_rows =
|
||||||
@@ -369,10 +376,8 @@ static const arg_def_t tile_rows =
|
|||||||
static const arg_def_t lossless = ARG_DEF(NULL, "lossless", 1, "Lossless mode");
|
static const arg_def_t lossless = ARG_DEF(NULL, "lossless", 1, "Lossless mode");
|
||||||
static const arg_def_t frame_parallel_decoding = ARG_DEF(
|
static const arg_def_t frame_parallel_decoding = ARG_DEF(
|
||||||
NULL, "frame-parallel", 1, "Enable frame parallel decodability features");
|
NULL, "frame-parallel", 1, "Enable frame parallel decodability features");
|
||||||
static const arg_def_t aq_mode = ARG_DEF(
|
static const arg_def_t aq_mode = ARG_DEF_ENUM(
|
||||||
NULL, "aq-mode", 1,
|
NULL, "aq-mode", 1, "Adaptive quantization mode", aq_mode_enum);
|
||||||
"Adaptive quantization mode (0: off (default), 1: variance 2: complexity, "
|
|
||||||
"3: cyclic refresh)");
|
|
||||||
static const arg_def_t frame_periodic_boost = ARG_DEF(
|
static const arg_def_t frame_periodic_boost = ARG_DEF(
|
||||||
NULL, "frame_boost", 1,
|
NULL, "frame_boost", 1,
|
||||||
"Enable frame periodic boost (0: off (default), 1: on)");
|
"Enable frame periodic boost (0: off (default), 1: on)");
|
||||||
@@ -385,12 +390,12 @@ static const struct arg_enum_list bitdepth_enum[] = {
|
|||||||
{NULL, 0}
|
{NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const arg_def_t bitdeptharg = ARG_DEF_ENUM(NULL, "bit-depth", 1,
|
static const arg_def_t bitdeptharg = ARG_DEF_ENUM("b", "bit-depth", 1,
|
||||||
"Bit depth for codec "
|
"Bit depth for codec "
|
||||||
"(8 for version <=1, "
|
"(8 for version <=1, "
|
||||||
"10 or 12 for version 2)",
|
"10 or 12 for version 2)",
|
||||||
bitdepth_enum);
|
bitdepth_enum);
|
||||||
static const arg_def_t inbitdeptharg = ARG_DEF("b", "input-bit-depth", 1,
|
static const arg_def_t inbitdeptharg = ARG_DEF(NULL, "input-bit-depth", 1,
|
||||||
"Bit depth of input");
|
"Bit depth of input");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1161,7 +1166,7 @@ static void validate_stream_config(const struct stream_state *stream,
|
|||||||
experimental_bitstream.long_name);
|
experimental_bitstream.long_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the stream bit depth is greater than the input bit depth
|
// Check that the codec bit depth is greater than the input bit depth
|
||||||
if (stream->config.cfg.g_in_bit_depth >
|
if (stream->config.cfg.g_in_bit_depth >
|
||||||
stream->config.cfg.g_bit_depth * 2 + 8) {
|
stream->config.cfg.g_bit_depth * 2 + 8) {
|
||||||
fatal("Stream %d: input bit depth (%d) less than stream bit depth (%d)",
|
fatal("Stream %d: input bit depth (%d) less than stream bit depth (%d)",
|
||||||
|
Reference in New Issue
Block a user