mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-27 19:24:06 +00:00
Add --slices=tiles and --slices=wpp
This encapsulates tiles or WPP rows into their own slices, making it possible to send them as soon as they are done, instead of waiting for the other substreams to finish and coding the substream offsets in the slice header.
This commit is contained in:
parent
0d4d0e869c
commit
52904d3e9f
|
@ -23,7 +23,7 @@ AC_CONFIG_SRCDIR([src/encmain.c])
|
||||||
#
|
#
|
||||||
# Here is a somewhat sane guide to lib versioning: http://apr.apache.org/versioning.html
|
# Here is a somewhat sane guide to lib versioning: http://apr.apache.org/versioning.html
|
||||||
ver_major=3
|
ver_major=3
|
||||||
ver_minor=14
|
ver_minor=15
|
||||||
ver_release=0
|
ver_release=0
|
||||||
|
|
||||||
# Prevents configure from adding a lot of defines to the CFLAGS
|
# Prevents configure from adding a lot of defines to the CFLAGS
|
||||||
|
|
22
src/cfg.c
22
src/cfg.c
|
@ -126,6 +126,8 @@ int kvz_config_init(kvz_config *cfg)
|
||||||
cfg->roi.height = 0;
|
cfg->roi.height = 0;
|
||||||
cfg->roi.dqps = NULL;
|
cfg->roi.dqps = NULL;
|
||||||
|
|
||||||
|
cfg->slices = KVZ_SLICES_NONE;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,9 +734,20 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
|
||||||
// -1 means automatic selection
|
// -1 means automatic selection
|
||||||
cfg->owf = -1;
|
cfg->owf = -1;
|
||||||
}
|
}
|
||||||
} else if OPT("slice-addresses") {
|
} else if OPT("slices") {
|
||||||
fprintf(stderr, "--slice-addresses doesn't do anything, because slices are not implemented.\n");
|
if (!strcmp(value, "tiles")) {
|
||||||
|
cfg->slices = KVZ_SLICES_TILES;
|
||||||
|
return 1;
|
||||||
|
} else if (!strcmp(value, "wpp")) {
|
||||||
|
cfg->slices = KVZ_SLICES_WPP;
|
||||||
|
return 1;
|
||||||
|
} else if (!strcmp(value, "tiles+wpp")) {
|
||||||
|
cfg->slices = KVZ_SLICES_TILES | KVZ_SLICES_WPP;
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
return parse_slice_specification(value, &cfg->slice_count, &cfg->slice_addresses_in_ts);
|
return parse_slice_specification(value, &cfg->slice_count, &cfg->slice_addresses_in_ts);
|
||||||
|
}
|
||||||
|
|
||||||
} else if OPT("threads") {
|
} else if OPT("threads") {
|
||||||
cfg->threads = atoi(value);
|
cfg->threads = atoi(value);
|
||||||
if (cfg->threads == 0 && !strcmp(value, "auto")) {
|
if (cfg->threads == 0 && !strcmp(value, "auto")) {
|
||||||
|
@ -1279,5 +1292,10 @@ int kvz_config_validate(const kvz_config *const cfg)
|
||||||
error = 1;
|
error = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((cfg->slices & KVZ_SLICES_WPP) && !cfg->wpp) {
|
||||||
|
fprintf(stderr, "Input error: --slices=wpp does not work without --wpp.\n");
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return !error;
|
return !error;
|
||||||
}
|
}
|
||||||
|
|
13
src/cli.c
13
src/cli.c
|
@ -84,7 +84,7 @@ static const struct option long_options[] = {
|
||||||
{ "wpp", no_argument, NULL, 0 },
|
{ "wpp", no_argument, NULL, 0 },
|
||||||
{ "no-wpp", no_argument, NULL, 0 },
|
{ "no-wpp", no_argument, NULL, 0 },
|
||||||
{ "owf", required_argument, NULL, 0 },
|
{ "owf", required_argument, NULL, 0 },
|
||||||
{ "slice-addresses", required_argument, NULL, 0 },
|
{ "slices", required_argument, NULL, 0 },
|
||||||
{ "threads", required_argument, NULL, 0 },
|
{ "threads", required_argument, NULL, 0 },
|
||||||
{ "cpuid", required_argument, NULL, 0 },
|
{ "cpuid", required_argument, NULL, 0 },
|
||||||
{ "pu-depth-inter", required_argument, NULL, 0 },
|
{ "pu-depth-inter", required_argument, NULL, 0 },
|
||||||
|
@ -461,13 +461,10 @@ void print_help(void)
|
||||||
" positions of tiles rows separation coordinates.\n"
|
" positions of tiles rows separation coordinates.\n"
|
||||||
" Can also be u followed by and a single int n,\n"
|
" Can also be u followed by and a single int n,\n"
|
||||||
" in which case it produces rows of uniform height.\n"
|
" in which case it produces rows of uniform height.\n"
|
||||||
/*
|
" --slices <string> : Control how slices are used\n"
|
||||||
" --slice-addresses <string>|u<int> :\n"
|
" - tiles: put tiles in independent slices\n"
|
||||||
" Specifies a comma separated list of LCU\n"
|
" - wpp: put rows in dependent slices\n"
|
||||||
" positions in tile scan order of tile separations.\n"
|
" - tiles+wpp: do both\n"
|
||||||
" Can also be u followed by and a single int n,\n"
|
|
||||||
" in which case it produces uniform slice length.\n"
|
|
||||||
*/
|
|
||||||
"\n"
|
"\n"
|
||||||
/* Word wrap to this width to stay under 80 characters (including ") ************/
|
/* Word wrap to this width to stay under 80 characters (including ") ************/
|
||||||
"Video Usability Information:\n"
|
"Video Usability Information:\n"
|
||||||
|
|
|
@ -194,8 +194,6 @@ encoder_control_t* kvz_encoder_control_init(kvz_config *const cfg) {
|
||||||
encoder->rdo = 1;
|
encoder->rdo = 1;
|
||||||
encoder->full_intra_search = 0;
|
encoder->full_intra_search = 0;
|
||||||
|
|
||||||
encoder->pps.dependent_slice_segments_enabled_flag = 0;
|
|
||||||
|
|
||||||
// Interlacing
|
// Interlacing
|
||||||
encoder->in.source_scan_type = (int8_t)cfg->source_scan_type;
|
encoder->in.source_scan_type = (int8_t)cfg->source_scan_type;
|
||||||
encoder->vui.field_seq_flag = encoder->cfg->source_scan_type != 0;
|
encoder->vui.field_seq_flag = encoder->cfg->source_scan_type != 0;
|
||||||
|
@ -378,8 +376,32 @@ encoder_control_t* kvz_encoder_control_init(kvz_config *const cfg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cfg->slices & KVZ_SLICES_WPP) {
|
||||||
|
// Each WPP row will be put into a dependent slice.
|
||||||
|
encoder->pps.dependent_slice_segments_enabled_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
//Slices
|
//Slices
|
||||||
{
|
if (cfg->slices & KVZ_SLICES_TILES) {
|
||||||
|
// Configure a single independent slice per tile.
|
||||||
|
|
||||||
|
int *slice_addresses_in_ts;
|
||||||
|
encoder->slice_count = encoder->tiles_num_tile_columns * encoder->tiles_num_tile_rows;
|
||||||
|
encoder->slice_addresses_in_ts = slice_addresses_in_ts = MALLOC(int, encoder->slice_count);
|
||||||
|
|
||||||
|
int slice_id = 0;
|
||||||
|
for (int tile_row = 0; tile_row < encoder->tiles_num_tile_rows; ++tile_row) {
|
||||||
|
for (int tile_col = 0; tile_col < encoder->tiles_num_tile_columns; ++tile_col) {
|
||||||
|
int x = tiles_col_bd[tile_col];
|
||||||
|
int y = tiles_row_bd[tile_row];
|
||||||
|
int rs = y * encoder->in.width_in_lcu + x;
|
||||||
|
int ts = tiles_ctb_addr_rs_to_ts[rs];
|
||||||
|
slice_addresses_in_ts[slice_id] = ts;
|
||||||
|
slice_id += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
int *slice_addresses_in_ts;
|
int *slice_addresses_in_ts;
|
||||||
encoder->slice_count = encoder->cfg->slice_count;
|
encoder->slice_count = encoder->cfg->slice_count;
|
||||||
if (encoder->slice_count == 0) {
|
if (encoder->slice_count == 0) {
|
||||||
|
|
|
@ -809,6 +809,11 @@ void kvz_encoder_state_write_bitstream_slice_header(
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool first_slice_segment_in_pic = (state->slice->start_in_rs == 0);
|
bool first_slice_segment_in_pic = (state->slice->start_in_rs == 0);
|
||||||
|
if ((state->encoder_control->cfg->slices & KVZ_SLICES_WPP)
|
||||||
|
&& state->wfrow->lcu_offset_y > 0)
|
||||||
|
{
|
||||||
|
first_slice_segment_in_pic = false;
|
||||||
|
}
|
||||||
|
|
||||||
WRITE_U(stream, first_slice_segment_in_pic, 1, "first_slice_segment_in_pic_flag");
|
WRITE_U(stream, first_slice_segment_in_pic, 1, "first_slice_segment_in_pic_flag");
|
||||||
|
|
||||||
|
@ -827,6 +832,9 @@ void kvz_encoder_state_write_bitstream_slice_header(
|
||||||
int lcu_cnt = encoder->in.width_in_lcu * encoder->in.height_in_lcu;
|
int lcu_cnt = encoder->in.width_in_lcu * encoder->in.height_in_lcu;
|
||||||
int num_bits = kvz_math_ceil_log2(lcu_cnt);
|
int num_bits = kvz_math_ceil_log2(lcu_cnt);
|
||||||
int slice_start_rs = state->slice->start_in_rs;
|
int slice_start_rs = state->slice->start_in_rs;
|
||||||
|
if (state->encoder_control->cfg->slices & KVZ_SLICES_WPP) {
|
||||||
|
slice_start_rs += state->wfrow->lcu_offset_y * state->tile->frame->width_in_lcu;
|
||||||
|
}
|
||||||
WRITE_U(stream, slice_start_rs, num_bits, "slice_segment_address");
|
WRITE_U(stream, slice_start_rs, num_bits, "slice_segment_address");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,6 +949,11 @@ static void encoder_state_write_bitstream_children(encoder_state_t * const state
|
||||||
for (int i = 0; state->children[i].encoder_control; ++i) {
|
for (int i = 0; state->children[i].encoder_control; ++i) {
|
||||||
if (state->children[i].type == ENCODER_STATE_TYPE_SLICE) {
|
if (state->children[i].type == ENCODER_STATE_TYPE_SLICE) {
|
||||||
encoder_state_write_slice_header(&state->stream, &state->children[i], true);
|
encoder_state_write_slice_header(&state->stream, &state->children[i], true);
|
||||||
|
} else if (state->children[i].type == ENCODER_STATE_TYPE_WAVEFRONT_ROW) {
|
||||||
|
if ((state->encoder_control->cfg->slices & KVZ_SLICES_WPP) && i != 0) {
|
||||||
|
// Add header for dependent WPP row slice.
|
||||||
|
encoder_state_write_slice_header(&state->stream, &state->children[i], false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
kvz_encoder_state_write_bitstream(&state->children[i]);
|
kvz_encoder_state_write_bitstream(&state->children[i]);
|
||||||
kvz_bitstream_move(&state->stream, &state->children[i].stream);
|
kvz_bitstream_move(&state->stream, &state->children[i].stream);
|
||||||
|
|
|
@ -331,7 +331,13 @@ static void encoder_state_worker_encode_lcu(void * opaque)
|
||||||
kvz_encode_coding_tree(state, lcu->position.x << MAX_DEPTH, lcu->position.y << MAX_DEPTH, 0);
|
kvz_encode_coding_tree(state, lcu->position.x << MAX_DEPTH, lcu->position.y << MAX_DEPTH, 0);
|
||||||
|
|
||||||
bool end_of_slice_segment_flag;
|
bool end_of_slice_segment_flag;
|
||||||
{
|
if (state->encoder_control->cfg->slices & KVZ_SLICES_WPP) {
|
||||||
|
// Slice segments end after each WPP row.
|
||||||
|
end_of_slice_segment_flag = lcu->last_column;
|
||||||
|
} else if (state->encoder_control->cfg->slices & KVZ_SLICES_TILES) {
|
||||||
|
// Slices end after each tile.
|
||||||
|
end_of_slice_segment_flag = lcu->last_column && lcu->last_row;
|
||||||
|
} else {
|
||||||
// Slice ends after the last row of the last tile.
|
// Slice ends after the last row of the last tile.
|
||||||
int last_tile_id = -1 + encoder->tiles_num_tile_columns * encoder->tiles_num_tile_rows;
|
int last_tile_id = -1 + encoder->tiles_num_tile_columns * encoder->tiles_num_tile_rows;
|
||||||
bool is_last_tile = state->tile->id == last_tile_id;
|
bool is_last_tile = state->tile->id == last_tile_id;
|
||||||
|
@ -528,7 +534,7 @@ static void encoder_state_worker_encode_children(void * opaque)
|
||||||
encoder_state_t *sub_state = opaque;
|
encoder_state_t *sub_state = opaque;
|
||||||
encoder_state_encode(sub_state);
|
encoder_state_encode(sub_state);
|
||||||
|
|
||||||
if (sub_state->type == ENCODER_STATE_TYPE_WAVEFRONT_ROW) {
|
if (sub_state->is_leaf && sub_state->type == ENCODER_STATE_TYPE_WAVEFRONT_ROW) {
|
||||||
// Set the last wavefront job of this row as the job that completes
|
// Set the last wavefront job of this row as the job that completes
|
||||||
// the bitstream for this wavefront row state.
|
// the bitstream for this wavefront row state.
|
||||||
|
|
||||||
|
|
|
@ -188,6 +188,16 @@ enum kvz_chroma_format {
|
||||||
KVZ_CSP_444 = 3,
|
KVZ_CSP_444 = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Chroma subsampling format used for encoding.
|
||||||
|
* \since 3.15.0
|
||||||
|
*/
|
||||||
|
enum kvz_slices {
|
||||||
|
KVZ_SLICES_NONE,
|
||||||
|
KVZ_SLICES_TILES = (1 << 0), /*!< \brief Put each tile in a slice. */
|
||||||
|
KVZ_SLICES_WPP = (1 << 1), /*!< \brief Put each row in a slice. */
|
||||||
|
};
|
||||||
|
|
||||||
// Map from input format to chroma format.
|
// Map from input format to chroma format.
|
||||||
#define KVZ_FORMAT2CSP(format) ((enum kvz_chroma_format)"\0\1\2\3"[format])
|
#define KVZ_FORMAT2CSP(format) ((enum kvz_chroma_format)"\0\1\2\3"[format])
|
||||||
|
|
||||||
|
@ -325,6 +335,8 @@ typedef struct kvz_config
|
||||||
int32_t height;
|
int32_t height;
|
||||||
uint8_t *dqps;
|
uint8_t *dqps;
|
||||||
} roi; /*!< \since 3.14.0 \brief Map of delta QPs for region of interest coding. */
|
} roi; /*!< \since 3.14.0 \brief Map of delta QPs for region of interest coding. */
|
||||||
|
|
||||||
|
unsigned slices; /*!< \since 3.15.0 \brief How to map slices to frame. */
|
||||||
} kvz_config;
|
} kvz_config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue