add --inloopfilters to enable/disable postfilters dynamically

(To be used alongside --filmgrain.)

Addresses part of #310.
This commit is contained in:
Ronald S. Bultje
2022-01-14 16:27:42 -05:00
parent 19326c40ca
commit 9a691b3131
6 changed files with 50 additions and 7 deletions
+13 -1
View File
@@ -58,6 +58,16 @@ typedef struct Dav1dLogger {
void (*callback)(void *cookie, const char *format, va_list ap);
} Dav1dLogger;
enum Dav1dInloopFilterType {
DAV1D_INLOOPFILTER_NONE = 0,
DAV1D_INLOOPFILTER_DEBLOCK = 1 << 0,
DAV1D_INLOOPFILTER_CDEF = 1 << 1,
DAV1D_INLOOPFILTER_RESTORATION = 1 << 2,
DAV1D_INLOOPFILTER_ALL = DAV1D_INLOOPFILTER_DEBLOCK |
DAV1D_INLOOPFILTER_CDEF |
DAV1D_INLOOPFILTER_RESTORATION,
};
typedef struct Dav1dSettings {
int n_threads; ///< number of threads (0 = number of logical cores in host system, default 0)
int max_frame_delay; ///< Set to 1 for low-latency decoding (0 = ceil(sqrt(n_threads)), default 0)
@@ -74,7 +84,9 @@ typedef struct Dav1dSettings {
///< to all visible frames. Because of show-existing-frame, this
///< means some frames may appear twice (once when coded,
///< once when shown, default 0)
uint8_t reserved[24]; ///< reserved for future use
enum Dav1dInloopFilterType inloop_filters; ///< postfilters to enable during decoding (default
///< DAV1D_INLOOPFILTER_ALL)
uint8_t reserved[20]; ///< reserved for future use
} Dav1dSettings;
/**
+1 -1
View File
@@ -30,7 +30,7 @@ project('dav1d', ['c'],
'b_ndebug=if-release'],
meson_version: '>= 0.49.0')
dav1d_soname_version = '6.3.0'
dav1d_soname_version = '6.4.0'
dav1d_api_version_array = dav1d_soname_version.split('.')
dav1d_api_version_major = dav1d_api_version_array[0]
dav1d_api_version_minor = dav1d_api_version_array[1]
+1
View File
@@ -158,6 +158,7 @@ struct Dav1dContext {
unsigned frame_size_limit;
int strict_std_compliance;
int output_invisible_frames;
enum Dav1dInloopFilterType inloop_filters;
int drain;
enum PictureFlags frame_flags;
enum Dav1dEventFlags event_flags;
+2
View File
@@ -76,6 +76,7 @@ COLD void dav1d_default_settings(Dav1dSettings *const s) {
s->frame_size_limit = 0;
s->strict_std_compliance = 0;
s->output_invisible_frames = 0;
s->inloop_filters = DAV1D_INLOOPFILTER_ALL;
}
static void close_internal(Dav1dContext **const c_out, int flush);
@@ -131,6 +132,7 @@ COLD int dav1d_open(Dav1dContext **const c_out, const Dav1dSettings *const s) {
c->frame_size_limit = s->frame_size_limit;
c->strict_std_compliance = s->strict_std_compliance;
c->output_invisible_frames = s->output_invisible_frames;
c->inloop_filters = s->inloop_filters;
if (dav1d_mem_pool_init(&c->seq_hdr_pool) ||
dav1d_mem_pool_init(&c->frame_hdr_pool) ||
+12 -4
View File
@@ -2046,6 +2046,11 @@ int bytefn(dav1d_recon_b_inter)(Dav1dTaskContext *const t, const enum BlockSize
}
void bytefn(dav1d_filter_sbrow_deblock_cols)(Dav1dFrameContext *const f, const int sby) {
if (!(f->c->inloop_filters & DAV1D_INLOOPFILTER_DEBLOCK) ||
(!f->frame_hdr->loopfilter.level_y[0] && !f->frame_hdr->loopfilter.level_y[1]))
{
return;
}
const int y = sby * f->sb_step * 4;
const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
pixel *const p[3] = {
@@ -2054,9 +2059,8 @@ void bytefn(dav1d_filter_sbrow_deblock_cols)(Dav1dFrameContext *const f, const i
f->lf.p[2] + (y * PXSTRIDE(f->cur.stride[1]) >> ss_ver)
};
Av1Filter *mask = f->lf.mask + (sby >> !f->seq_hdr->sb128) * f->sb128w;
if (f->frame_hdr->loopfilter.level_y[0] || f->frame_hdr->loopfilter.level_y[1])
bytefn(dav1d_loopfilter_sbrow_cols)(f, p, mask, sby,
f->lf.start_of_tile_row[sby]);
bytefn(dav1d_loopfilter_sbrow_cols)(f, p, mask, sby,
f->lf.start_of_tile_row[sby]);
}
void bytefn(dav1d_filter_sbrow_deblock_rows)(Dav1dFrameContext *const f, const int sby) {
@@ -2068,7 +2072,9 @@ void bytefn(dav1d_filter_sbrow_deblock_rows)(Dav1dFrameContext *const f, const i
f->lf.p[2] + (y * PXSTRIDE(f->cur.stride[1]) >> ss_ver)
};
Av1Filter *mask = f->lf.mask + (sby >> !f->seq_hdr->sb128) * f->sb128w;
if (f->frame_hdr->loopfilter.level_y[0] || f->frame_hdr->loopfilter.level_y[1]) {
if (f->c->inloop_filters & DAV1D_INLOOPFILTER_DEBLOCK &&
(f->frame_hdr->loopfilter.level_y[0] || f->frame_hdr->loopfilter.level_y[1]))
{
bytefn(dav1d_loopfilter_sbrow_rows)(f, p, mask, sby);
}
if (f->seq_hdr->cdef || f->lf.restore_planes) {
@@ -2079,6 +2085,7 @@ void bytefn(dav1d_filter_sbrow_deblock_rows)(Dav1dFrameContext *const f, const i
void bytefn(dav1d_filter_sbrow_cdef)(Dav1dTaskContext *const tc, const int sby) {
const Dav1dFrameContext *const f = tc->f;
if (!(f->c->inloop_filters & DAV1D_INLOOPFILTER_CDEF)) return;
const int sbsz = f->sb_step;
const int y = sby * sbsz * 4;
const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
@@ -2140,6 +2147,7 @@ void bytefn(dav1d_filter_sbrow_resize)(Dav1dFrameContext *const f, const int sby
}
void bytefn(dav1d_filter_sbrow_lr)(Dav1dFrameContext *const f, const int sby) {
if (!(f->c->inloop_filters & DAV1D_INLOOPFILTER_RESTORATION)) return;
const int y = sby * f->sb_step * 4;
const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
pixel *const sr_p[3] = {
+21 -1
View File
@@ -61,6 +61,7 @@ enum {
ARG_CPU_MASK,
ARG_NEG_STRIDE,
ARG_OUTPUT_INVISIBLE,
ARG_INLOOP_FILTERS,
};
static const struct option long_opts[] = {
@@ -86,6 +87,7 @@ static const struct option long_opts[] = {
{ "cpumask", 1, NULL, ARG_CPU_MASK },
{ "negstride", 0, NULL, ARG_NEG_STRIDE },
{ "outputinvisible", 1, NULL, ARG_OUTPUT_INVISIBLE },
{ "inloopfilters", 1, NULL, ARG_INLOOP_FILTERS },
{ NULL, 0, NULL, 0 },
};
@@ -142,7 +144,8 @@ static void usage(const char *const app, const char *const reason, ...) {
" --cpumask $mask: restrict permitted CPU instruction sets (0" ALLOWED_CPU_MASKS "; default: -1)\n"
" --negstride: use negative picture strides\n"
" this is mostly meant as a developer option\n"
" --outputinvisible $num: whether to output invisible (alt-ref) frames (default: 0)\n");
" --outputinvisible $num: whether to output invisible (alt-ref) frames (default: 0)\n"
" --inloopfilters $str: which in-loop filters to enable (none, (no)deblock, (no)cdef, (no)restoration or all; default: all)\n");
exit(1);
}
@@ -221,6 +224,18 @@ static const EnumParseTable cpu_mask_tbl[] = {
{ "none", 0 },
};
static const EnumParseTable inloop_filters_tbl[] = {
{ "none", DAV1D_INLOOPFILTER_NONE },
{ "deblock", DAV1D_INLOOPFILTER_DEBLOCK },
{ "nodeblock", DAV1D_INLOOPFILTER_ALL - DAV1D_INLOOPFILTER_DEBLOCK },
{ "cdef", DAV1D_INLOOPFILTER_CDEF },
{ "nocdef", DAV1D_INLOOPFILTER_ALL - DAV1D_INLOOPFILTER_CDEF },
{ "restoration", DAV1D_INLOOPFILTER_RESTORATION },
{ "norestoration", DAV1D_INLOOPFILTER_ALL - DAV1D_INLOOPFILTER_RESTORATION },
{ "all", DAV1D_INLOOPFILTER_ALL },
{ 0 },
};
#define ARRAY_SIZE(n) (sizeof(n)/sizeof(*(n)))
static unsigned parse_enum(char *optarg, const EnumParseTable *const tbl,
@@ -362,6 +377,11 @@ void parse(const int argc, char *const *const argv,
lib_settings->output_invisible_frames =
!!parse_unsigned(optarg, ARG_OUTPUT_INVISIBLE, argv[0]);
break;
case ARG_INLOOP_FILTERS:
lib_settings->inloop_filters =
parse_enum(optarg, inloop_filters_tbl,
ARRAY_SIZE(inloop_filters_tbl),ARG_INLOOP_FILTERS, argv[0]);
break;
default:
usage(argv[0], NULL);
}