diff options
author | wm4 <wm4@nowhere> | 2016-05-25 23:40:47 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2016-05-25 23:51:24 +0200 |
commit | 5c9f164caf88d8049477727450845cbab2ffead2 (patch) | |
tree | c925a21cdfb8503fa763f27ce9e0209ba287f2c7 /video/filter/refqueue.c | |
parent | fc18e1df6224229d5e95bb9d1855f88690e655b3 (diff) | |
download | mpv-5c9f164caf88d8049477727450845cbab2ffead2.tar.bz2 mpv-5c9f164caf88d8049477727450845cbab2ffead2.tar.xz |
vf_vavpp: make refqueue logic field-based
Abstracts the annoying framerate-doubling behavior.
Same deal as with refqueue introduction: the code size blows up, but at
least it can be reused for other filters.
Diffstat (limited to 'video/filter/refqueue.c')
-rw-r--r-- | video/filter/refqueue.c | 118 |
1 files changed, 89 insertions, 29 deletions
diff --git a/video/filter/refqueue.c b/video/filter/refqueue.c index 64c5b9b03b..8ca0e28f91 100644 --- a/video/filter/refqueue.c +++ b/video/filter/refqueue.c @@ -25,7 +25,9 @@ struct mp_refqueue { int needed_past_frames; int needed_future_frames; + int flags; + bool second_field; // current frame has to output a second field yet bool eof; // Queue of input frames, used to determine past/current/future frames. @@ -56,6 +58,50 @@ void mp_refqueue_set_refs(struct mp_refqueue *q, int past, int future) q->needed_future_frames = MPMAX(future, 1); // at least 1 for determining PTS } +// MP_MODE_* flags +void mp_refqueue_set_mode(struct mp_refqueue *q, int flags) +{ + q->flags = flags; +} + +// Whether the current frame should be deinterlaced. +bool mp_refqueue_should_deint(struct mp_refqueue *q) +{ + if (!mp_refqueue_has_output(q)) + return false; + + return (q->queue[q->pos]->fields & MP_IMGFIELD_INTERLACED) || + !(q->flags & MP_MODE_INTERLACED_ONLY); +} + +// Whether the current output frame is marked as interlaced. +bool mp_refqueue_is_interlaced(struct mp_refqueue *q) +{ + if (!mp_refqueue_has_output(q)) + return false; + + return q->queue[q->pos]->fields & MP_IMGFIELD_INTERLACED; +} + +// Whether the current output frame (field) is the top field, bottom field +// otherwise. (Assumes the caller forces deinterlacing.) +bool mp_refqueue_is_top_field(struct mp_refqueue *q) +{ + if (!mp_refqueue_has_output(q)) + return false; + + return !!(q->queue[q->pos]->fields & MP_IMGFIELD_TOP_FIRST) ^ q->second_field; +} + +// Whether top-field-first mode is enabled. +bool mp_refqueue_top_field_first(struct mp_refqueue *q) +{ + if (!mp_refqueue_has_output(q)) + return false; + + return q->queue[q->pos]->fields & MP_IMGFIELD_TOP_FIRST; +} + // Discard all state. void mp_refqueue_flush(struct mp_refqueue *q) { @@ -63,6 +109,7 @@ void mp_refqueue_flush(struct mp_refqueue *q) talloc_free(q->queue[n]); q->num_queue = 0; q->pos = -1; + q->second_field = false; q->eof = false; } @@ -93,13 +140,54 @@ bool mp_refqueue_has_output(struct mp_refqueue *q) return q->pos >= 0 && !mp_refqueue_need_input(q); } -// Advance current frame by 1 (or 2 fields if interlaced). +static bool output_next_field(struct mp_refqueue *q) +{ + if (q->second_field) + return false; + if (!(q->flags & MP_MODE_OUTPUT_FIELDS)) + return false; + if (!(q->queue[q->pos]->fields & MP_IMGFIELD_INTERLACED) && + (q->flags & MP_MODE_INTERLACED_ONLY)) + return false; + + assert(q->pos >= 0); + + // If there's no (reasonable) timestamp, also skip the field. + if (q->pos == 0) + return false; + + double pts = q->queue[q->pos]->pts; + double next_pts = q->queue[q->pos - 1]->pts; + if (pts == MP_NOPTS_VALUE || next_pts == MP_NOPTS_VALUE) + return false; + + double frametime = next_pts - pts; + if (frametime <= 0.0 || frametime >= 1.0) + return false; + + q->queue[q->pos]->pts = pts + frametime / 2; + q->second_field = true; + return true; +} + +// Advance current field, depending on interlace flags. +void mp_refqueue_next_field(struct mp_refqueue *q) +{ + if (!mp_refqueue_has_output(q)) + return; + + if (!output_next_field(q)) + mp_refqueue_next(q); +} + +// Advance to next input frame (skips fields even in field output mode). void mp_refqueue_next(struct mp_refqueue *q) { if (!mp_refqueue_has_output(q)) return; q->pos--; + q->second_field = false; assert(q->pos >= -1 && q->pos < q->num_queue); @@ -123,31 +211,3 @@ struct mp_image *mp_refqueue_get(struct mp_refqueue *q, int pos) int i = q->pos - pos; return i >= 0 && i < q->num_queue ? q->queue[i] : NULL; } - -// Get the pts of field 0/1 (0 being the first to output). -double mp_refqueue_get_field_pts(struct mp_refqueue *q, int field) -{ - assert(field == 0 || field == 1); - - if (q->pos < 0) - return MP_NOPTS_VALUE; - - double pts = q->queue[q->pos]->pts; - - if (field == 0 || pts == MP_NOPTS_VALUE) - return pts; - - if (q->pos == 0) - return MP_NOPTS_VALUE; - - double next_pts = q->queue[q->pos - 1]->pts; - if (next_pts == MP_NOPTS_VALUE) - return MP_NOPTS_VALUE; - - double frametime = next_pts - pts; - if (frametime <= 0.0 || frametime >= 1.0) - return MP_NOPTS_VALUE; - - return pts + frametime / 2; -} - |