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:
+10
-1
@@ -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
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user