dav1d: add an option to skip decoding some frame types

Should be useful for scenarios like wanting only keyframes to quickly generate
a set of preview images of the whole stream.
This commit is contained in:
James Almer
2022-12-09 09:23:55 -03:00
parent 6f80bad2bd
commit ed63a74593
6 changed files with 89 additions and 8 deletions
+10 -1
View File
@@ -68,6 +68,13 @@ enum Dav1dInloopFilterType {
DAV1D_INLOOPFILTER_RESTORATION,
};
enum Dav1dDecodeFrameType {
DAV1D_DECODEFRAMETYPE_ALL = 0, ///< decode and return all frames
DAV1D_DECODEFRAMETYPE_REFERENCE = 1,///< decode and return frames referenced by other frames only
DAV1D_DECODEFRAMETYPE_INTRA = 2, ///< decode and return intra frames only (includes keyframes)
DAV1D_DECODEFRAMETYPE_KEY = 3, ///< decode and return keyframes only
};
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)
@@ -86,7 +93,9 @@ typedef struct Dav1dSettings {
///< once when shown, default 0)
enum Dav1dInloopFilterType inloop_filters; ///< postfilters to enable during decoding (default
///< DAV1D_INLOOPFILTER_ALL)
uint8_t reserved[20]; ///< reserved for future use
enum Dav1dDecodeFrameType decode_frame_type; ///< frame types to decode (default
///< DAV1D_DECODEFRAMETYPE_ALL)
uint8_t reserved[16]; ///< 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.7.0'
dav1d_soname_version = '6.8.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
@@ -194,6 +194,7 @@ struct Dav1dContext {
int strict_std_compliance;
int output_invisible_frames;
enum Dav1dInloopFilterType inloop_filters;
enum Dav1dDecodeFrameType decode_frame_type;
int drain;
enum PictureFlags frame_flags;
enum Dav1dEventFlags event_flags;
+4
View File
@@ -77,6 +77,7 @@ COLD void dav1d_default_settings(Dav1dSettings *const s) {
s->strict_std_compliance = 0;
s->output_invisible_frames = 0;
s->inloop_filters = DAV1D_INLOOPFILTER_ALL;
s->decode_frame_type = DAV1D_DECODEFRAMETYPE_ALL;
}
static void close_internal(Dav1dContext **const c_out, int flush);
@@ -144,6 +145,8 @@ COLD int dav1d_open(Dav1dContext **const c_out, const Dav1dSettings *const s) {
DAV1D_ERR(EINVAL));
validate_input_or_ret(s->operating_point >= 0 &&
s->operating_point <= 31, DAV1D_ERR(EINVAL));
validate_input_or_ret(s->decode_frame_type >= DAV1D_DECODEFRAMETYPE_ALL &&
s->decode_frame_type <= DAV1D_DECODEFRAMETYPE_KEY, DAV1D_ERR(EINVAL));
pthread_attr_t thread_attr;
if (pthread_attr_init(&thread_attr)) return DAV1D_ERR(ENOMEM);
@@ -164,6 +167,7 @@ COLD int dav1d_open(Dav1dContext **const c_out, const Dav1dSettings *const s) {
c->strict_std_compliance = s->strict_std_compliance;
c->output_invisible_frames = s->output_invisible_frames;
c->inloop_filters = s->inloop_filters;
c->decode_frame_type = s->decode_frame_type;
dav1d_data_props_set_defaults(&c->cached_error_props);
+56 -5
View File
@@ -289,9 +289,9 @@ static int read_frame_size(Dav1dContext *const c, GetBits *const gb,
if (dav1d_get_bit(gb)) {
const Dav1dThreadPicture *const ref =
&c->refs[c->frame_hdr->refidx[i]].p;
if (!ref->p.data[0]) return -1;
hdr->width[1] = ref->p.p.w;
hdr->height = ref->p.p.h;
if (!ref->p.frame_hdr) return -1;
hdr->width[1] = ref->p.frame_hdr->width[1];
hdr->height = ref->p.frame_hdr->height;
hdr->render_width = ref->p.frame_hdr->render_width;
hdr->render_height = ref->p.frame_hdr->render_height;
hdr->super_res.enabled = seqhdr->super_res && dav1d_get_bit(gb);
@@ -923,7 +923,7 @@ static int parse_frame_hdr(Dav1dContext *const c, GetBits *const gb) {
int off_after = -1;
int off_before_idx, off_after_idx;
for (int i = 0; i < 7; i++) {
if (!c->refs[hdr->refidx[i]].p.p.data[0]) goto error;
if (!c->refs[hdr->refidx[i]].p.p.frame_hdr) goto error;
const unsigned refpoc = c->refs[hdr->refidx[i]].p.p.frame_hdr->frame_offset;
const int diff = get_poc_diff(seqhdr->order_hint_n_bits, refpoc, poc);
@@ -951,7 +951,7 @@ static int parse_frame_hdr(Dav1dContext *const c, GetBits *const gb) {
unsigned off_before2 = 0xFFFFFFFFU;
int off_before2_idx;
for (int i = 0; i < 7; i++) {
if (!c->refs[hdr->refidx[i]].p.p.data[0]) goto error;
if (!c->refs[hdr->refidx[i]].p.p.frame_hdr) goto error;
const unsigned refpoc = c->refs[hdr->refidx[i]].p.p.frame_hdr->frame_offset;
if (get_poc_diff(seqhdr->order_hint_n_bits,
refpoc, off_before) < 0) {
@@ -1537,6 +1537,20 @@ int dav1d_parse_obus(Dav1dContext *const c, Dav1dData *const in, const int globa
if (c->seq_hdr && c->frame_hdr) {
if (c->frame_hdr->show_existing_frame) {
if (!c->refs[c->frame_hdr->existing_frame_idx].p.p.frame_hdr) goto error;
switch (c->refs[c->frame_hdr->existing_frame_idx].p.p.frame_hdr->frame_type) {
case DAV1D_FRAME_TYPE_INTER:
case DAV1D_FRAME_TYPE_SWITCH:
if (c->decode_frame_type > DAV1D_DECODEFRAMETYPE_REFERENCE)
goto skip;
break;
case DAV1D_FRAME_TYPE_INTRA:
if (c->decode_frame_type > DAV1D_DECODEFRAMETYPE_INTRA)
goto skip;
// fall-through
default:
break;
}
if (!c->refs[c->frame_hdr->existing_frame_idx].p.p.data[0]) goto error;
if (c->strict_std_compliance &&
!c->refs[c->frame_hdr->existing_frame_idx].p.showable)
@@ -1617,6 +1631,23 @@ int dav1d_parse_obus(Dav1dContext *const c, Dav1dData *const in, const int globa
}
c->frame_hdr = NULL;
} else if (c->n_tiles == c->frame_hdr->tiling.cols * c->frame_hdr->tiling.rows) {
switch (c->frame_hdr->frame_type) {
case DAV1D_FRAME_TYPE_INTER:
case DAV1D_FRAME_TYPE_SWITCH:
if (c->decode_frame_type > DAV1D_DECODEFRAMETYPE_REFERENCE ||
(c->decode_frame_type == DAV1D_DECODEFRAMETYPE_REFERENCE &&
!c->frame_hdr->refresh_frame_flags))
goto skip;
break;
case DAV1D_FRAME_TYPE_INTRA:
if (c->decode_frame_type > DAV1D_DECODEFRAMETYPE_INTRA ||
(c->decode_frame_type == DAV1D_DECODEFRAMETYPE_REFERENCE &&
!c->frame_hdr->refresh_frame_flags))
goto skip;
// fall-through
default:
break;
}
if (!c->n_tile_data)
goto error;
if ((res = dav1d_submit_frame(c)) < 0)
@@ -1629,6 +1660,26 @@ int dav1d_parse_obus(Dav1dContext *const c, Dav1dData *const in, const int globa
return len + init_byte_pos;
skip:
// update refs with only the headers in case we skip the frame
for (int i = 0; i < 8; i++) {
if (c->frame_hdr->refresh_frame_flags & (1 << i)) {
dav1d_thread_picture_unref(&c->refs[i].p);
c->refs[i].p.p.frame_hdr = c->frame_hdr;
c->refs[i].p.p.seq_hdr = c->seq_hdr;
c->refs[i].p.p.frame_hdr_ref = c->frame_hdr_ref;
c->refs[i].p.p.seq_hdr_ref = c->seq_hdr_ref;
dav1d_ref_inc(c->frame_hdr_ref);
dav1d_ref_inc(c->seq_hdr_ref);
}
}
dav1d_ref_dec(&c->frame_hdr_ref);
c->frame_hdr = NULL;
c->n_tiles = 0;
return len + init_byte_pos;
error:
dav1d_data_props_copy(&c->cached_error_props, &in->m);
dav1d_log(c, "Error parsing OBU data\n");
+17 -1
View File
@@ -62,6 +62,7 @@ enum {
ARG_NEG_STRIDE,
ARG_OUTPUT_INVISIBLE,
ARG_INLOOP_FILTERS,
ARG_DECODE_FRAME_TYPE,
};
static const struct option long_opts[] = {
@@ -88,6 +89,7 @@ static const struct option long_opts[] = {
{ "negstride", 0, NULL, ARG_NEG_STRIDE },
{ "outputinvisible", 1, NULL, ARG_OUTPUT_INVISIBLE },
{ "inloopfilters", 1, NULL, ARG_INLOOP_FILTERS },
{ "decodeframetype", 1, NULL, ARG_DECODE_FRAME_TYPE },
{ NULL, 0, NULL, 0 },
};
@@ -145,7 +147,9 @@ static void usage(const char *const app, const char *const reason, ...) {
" --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"
" --inloopfilters $str: which in-loop filters to enable (none, (no)deblock, (no)cdef, (no)restoration or all; default: all)\n");
" --inloopfilters $str: which in-loop filters to enable (none, (no)deblock, (no)cdef, (no)restoration or all; default: all)\n"
" --decodeframetype $str: which frame types to decode (reference, intra, key or all; default: all)\n"
);
exit(1);
}
@@ -235,6 +239,13 @@ static const EnumParseTable inloop_filters_tbl[] = {
{ "all", DAV1D_INLOOPFILTER_ALL },
};
static const EnumParseTable decode_frame_type_tbl[] = {
{ "all", DAV1D_DECODEFRAMETYPE_ALL },
{ "reference", DAV1D_DECODEFRAMETYPE_REFERENCE },
{ "intra", DAV1D_DECODEFRAMETYPE_INTRA },
{ "key", DAV1D_DECODEFRAMETYPE_KEY },
};
#define ARRAY_SIZE(n) (sizeof(n)/sizeof(*(n)))
static unsigned parse_enum(char *optarg, const EnumParseTable *const tbl,
@@ -381,6 +392,11 @@ void parse(const int argc, char *const *const argv,
parse_enum(optarg, inloop_filters_tbl,
ARRAY_SIZE(inloop_filters_tbl),ARG_INLOOP_FILTERS, argv[0]);
break;
case ARG_DECODE_FRAME_TYPE:
lib_settings->decode_frame_type =
parse_enum(optarg, decode_frame_type_tbl,
ARRAY_SIZE(decode_frame_type_tbl), ARG_DECODE_FRAME_TYPE, argv[0]);
break;
default:
usage(argv[0], NULL);
}