Verified Commit a98f5e60 authored by James Almer's avatar James Almer
Browse files

dav1d: add event flags to the decoding process

And a function to fetch them. Should be useful to signal changes in the
bitstream the user may want to know about.

Starting with two flags, DAV1D_EVENT_FLAG_NEW_SEQUENCE and
DAV1D_EVENT_FLAG_NEW_OP_PARAMS_INFO, which signal the presence of an updated
sequence header in the last returned (or to be returned) picture.
parent 54ad561d
Pipeline #88708 passed with stages
in 6 minutes and 47 seconds
......@@ -202,6 +202,35 @@ DAV1D_API void dav1d_close(Dav1dContext **c_out);
*/
DAV1D_API void dav1d_flush(Dav1dContext *c);
enum Dav1dEventFlags {
/**
* The last returned picture contains a reference to a new Sequence Header,
* either because it's the start of a new coded sequence, or the decoder was
* flushed before it was generated.
*/
DAV1D_EVENT_FLAG_NEW_SEQUENCE = 1 << 0,
/**
* The last returned picture contains a reference to a Sequence Header with
* new operating parameters information for the current coded sequence.
*/
DAV1D_EVENT_FLAG_NEW_OP_PARAMS_INFO = 1 << 1,
};
/**
* Fetch a combination of DAV1D_EVENT_FLAG_* event flags generated by the decoding
* process.
*
* @param c Input decoder instance.
* @param flags Where to write the flags.
*
* @return 0 on success, or < 0 (a negative DAV1D_ERR code) on error.
*
* @note Calling this function will clear all the event flags currently stored in
* the decoder.
*
*/
DAV1D_API int dav1d_get_event_flags(Dav1dContext *c, enum Dav1dEventFlags *flags);
# ifdef __cplusplus
}
# endif
......
......@@ -30,7 +30,7 @@ project('dav1d', ['c'],
'b_ndebug=if-release'],
meson_version: '>= 0.49.0')
dav1d_soname_version = '5.0.1'
dav1d_soname_version = '5.1.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]
......
......@@ -3316,8 +3316,10 @@ int dav1d_submit_frame(Dav1dContext *const c) {
if (out_delayed->p.data[0]) {
const unsigned progress = atomic_load_explicit(&out_delayed->progress[1],
memory_order_relaxed);
if (out_delayed->visible && progress != FRAME_ERROR)
if (out_delayed->visible && progress != FRAME_ERROR) {
dav1d_picture_ref(&c->out, &out_delayed->p);
c->event_flags |= dav1d_picture_get_event_flags(out_delayed);
}
dav1d_thread_picture_unref(out_delayed);
}
} else {
......@@ -3487,8 +3489,10 @@ int dav1d_submit_frame(Dav1dContext *const c) {
// move f->cur into output queue
if (c->n_fc == 1) {
if (f->frame_hdr->show_frame)
if (f->frame_hdr->show_frame) {
dav1d_picture_ref(&c->out, &f->sr_cur.p);
c->event_flags |= dav1d_picture_get_event_flags(&f->sr_cur);
}
} else {
dav1d_thread_picture_ref(out_delayed, &f->sr_cur);
}
......
......@@ -151,6 +151,8 @@ struct Dav1dContext {
int all_layers;
unsigned frame_size_limit;
int drain;
enum PictureFlags frame_flags;
enum Dav1dEventFlags event_flags;
Dav1dLogger logger;
......
......@@ -407,8 +407,10 @@ static int drain_picture(Dav1dContext *const c, Dav1dPicture *const out) {
const unsigned progress =
atomic_load_explicit(&out_delayed->progress[1],
memory_order_relaxed);
if (out_delayed->visible && progress != FRAME_ERROR)
if (out_delayed->visible && progress != FRAME_ERROR) {
dav1d_picture_ref(&c->out, &out_delayed->p);
c->event_flags |= dav1d_picture_get_event_flags(out_delayed);
}
dav1d_thread_picture_unref(out_delayed);
if (output_picture_ready(c))
return output_image(c, out, &c->out);
......@@ -689,6 +691,15 @@ static COLD void close_internal(Dav1dContext **const c_out, int flush) {
dav1d_freep_aligned(c_out);
}
int dav1d_get_event_flags(Dav1dContext *const c, enum Dav1dEventFlags *const flags) {
validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
validate_input_or_ret(flags != NULL, DAV1D_ERR(EINVAL));
*flags = c->event_flags;
c->event_flags = 0;
return 0;
}
void dav1d_picture_unref(Dav1dPicture *const p) {
dav1d_picture_unref_internal(p);
}
......
......@@ -1249,11 +1249,13 @@ int dav1d_parse_obus(Dav1dContext *const c, Dav1dData *const in, const int globa
// If we have read a sequence header which is different from
// the old one, this is a new video sequence and can't use any
// previous state. Free that state.
if (!c->seq_hdr)
if (!c->seq_hdr) {
c->frame_hdr = NULL;
c->frame_flags |= PICTURE_FLAG_NEW_SEQUENCE;
// see 7.5, operating_parameter_info is allowed to change in
// sequence headers of a single sequence
else if (memcmp(seq_hdr, c->seq_hdr, offsetof(Dav1dSequenceHeader, operating_parameter_info))) {
} else if (memcmp(seq_hdr, c->seq_hdr, offsetof(Dav1dSequenceHeader, operating_parameter_info))) {
c->frame_hdr = NULL;
c->mastering_display = NULL;
c->content_light = NULL;
......@@ -1266,6 +1268,12 @@ int dav1d_parse_obus(Dav1dContext *const c, Dav1dData *const in, const int globa
dav1d_ref_dec(&c->refs[i].refmvs);
dav1d_cdf_thread_unref(&c->cdf[i]);
}
c->frame_flags |= PICTURE_FLAG_NEW_SEQUENCE;
// If operating_parameter_info changed, signal it
} else if (memcmp(seq_hdr->operating_parameter_info, c->seq_hdr->operating_parameter_info,
sizeof(seq_hdr->operating_parameter_info)))
{
c->frame_flags |= PICTURE_FLAG_NEW_OP_PARAMS_INFO;
}
dav1d_ref_dec(&c->seq_hdr_ref);
c->seq_hdr_ref = ref;
......@@ -1537,6 +1545,7 @@ int dav1d_parse_obus(Dav1dContext *const c, Dav1dData *const in, const int globa
dav1d_picture_ref(&c->out,
&c->refs[c->frame_hdr->existing_frame_idx].p.p);
dav1d_data_props_copy(&c->out.m, &in->m);
c->event_flags |= dav1d_picture_get_event_flags(&c->refs[c->frame_hdr->existing_frame_idx].p);
} else {
// need to append this to the frame output queue
const unsigned next = c->frame_thread.next++;
......@@ -1553,8 +1562,10 @@ int dav1d_parse_obus(Dav1dContext *const c, Dav1dData *const in, const int globa
if (out_delayed->p.data[0]) {
const unsigned progress = atomic_load_explicit(&out_delayed->progress[1],
memory_order_relaxed);
if (out_delayed->visible && progress != FRAME_ERROR)
if (out_delayed->visible && progress != FRAME_ERROR) {
dav1d_picture_ref(&c->out, &out_delayed->p);
c->event_flags |= dav1d_picture_get_event_flags(out_delayed);
}
dav1d_thread_picture_unref(out_delayed);
}
dav1d_thread_picture_ref(out_delayed,
......
......@@ -194,6 +194,9 @@ int dav1d_thread_picture_alloc(Dav1dContext *const c, Dav1dFrameContext *const f
dav1d_ref_dec(&c->itut_t35_ref);
c->itut_t35 = NULL;
p->flags = c->frame_flags;
c->frame_flags = 0;
p->visible = f->frame_hdr->show_frame;
if (p->t) {
atomic_init(&p->progress[0], 0);
......@@ -254,6 +257,7 @@ void dav1d_thread_picture_ref(Dav1dThreadPicture *const dst,
dst->t = src->t;
dst->visible = src->visible;
dst->progress = src->progress;
dst->flags = src->flags;
}
void dav1d_picture_unref_internal(Dav1dPicture *const p) {
......@@ -322,3 +326,16 @@ void dav1d_thread_picture_signal(const Dav1dThreadPicture *const p,
pthread_cond_broadcast(&p->t->cond);
pthread_mutex_unlock(&p->t->lock);
}
enum Dav1dEventFlags dav1d_picture_get_event_flags(const Dav1dThreadPicture *const p) {
if (!p->flags)
return 0;
enum Dav1dEventFlags flags = 0;
if (p->flags & PICTURE_FLAG_NEW_SEQUENCE)
flags |= DAV1D_EVENT_FLAG_NEW_SEQUENCE;
if (p->flags & PICTURE_FLAG_NEW_OP_PARAMS_INFO)
flags |= DAV1D_EVENT_FLAG_NEW_OP_PARAMS_INFO;
return flags;
}
......@@ -43,9 +43,15 @@ enum PlaneType {
PLANE_TYPE_ALL,
};
enum PictureFlags {
PICTURE_FLAG_NEW_SEQUENCE = 1 << 0,
PICTURE_FLAG_NEW_OP_PARAMS_INFO = 1 << 1,
};
typedef struct Dav1dThreadPicture {
Dav1dPicture p;
int visible;
enum PictureFlags flags;
struct thread_data *t;
// [0] block data (including segmentation map and motion vectors)
// [1] pixel data
......@@ -114,4 +120,9 @@ int dav1d_default_picture_alloc(Dav1dPicture *p, void *cookie);
void dav1d_default_picture_release(Dav1dPicture *p, void *cookie);
void dav1d_picture_unref_internal(Dav1dPicture *p);
/**
* Get event flags from picture flags.
*/
enum Dav1dEventFlags dav1d_picture_get_event_flags(const Dav1dThreadPicture *p);
#endif /* DAV1D_SRC_PICTURE_H */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment