summaryrefslogtreecommitdiffstats
path: root/video/filter
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-06-01 01:39:30 +0200
committerwm4 <wm4@nowhere>2015-06-01 01:39:30 +0200
commitebc5237c3600311e19e25c0118b0352012d3e627 (patch)
tree40fa3baf06dffc05b02af706dac1e5407dba342d /video/filter
parent56c4cdf36938c714968a616afe98809902b83fc8 (diff)
downloadmpv-ebc5237c3600311e19e25c0118b0352012d3e627.tar.bz2
mpv-ebc5237c3600311e19e25c0118b0352012d3e627.tar.xz
vf_vavpp: provide future/past frames to driver
This was missing for extended deinterlacer. Unfortunately, these deinterlacer still do not work. The provided future frame (which is all the deinterlacers want) seems to be correct, though. One minor behavioral change is that this always keeps the previous frame for PTS computations. This could be avoided (in order to keep exactly the same behavior as before), but it seems more elegant and should not do any harm. (Also, if we really cared about reducing hw frame refs, a more worthy goal is producing the field output incrementally.)
Diffstat (limited to 'video/filter')
-rw-r--r--video/filter/vf_vavpp.c127
1 files changed, 97 insertions, 30 deletions
diff --git a/video/filter/vf_vavpp.c b/video/filter/vf_vavpp.c
index 770e68bfce..642420a544 100644
--- a/video/filter/vf_vavpp.c
+++ b/video/filter/vf_vavpp.c
@@ -15,6 +15,8 @@
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <assert.h>
+
#include <va/va.h>
#include <va/va_vpp.h>
@@ -35,9 +37,16 @@ static bool check_error(struct vf_instance *vf, VAStatus status, const char *msg
struct surface_refs {
VASurfaceID *surfaces;
- int num_required;
+ int num_surfaces;
};
+static void add_surface(void *ta_ctx, struct surface_refs *refs, struct mp_image *s)
+{
+ VASurfaceID id = va_surface_id(s);
+ if (id != VA_INVALID_ID)
+ MP_TARRAY_APPEND(ta_ctx, refs->surfaces, refs->num_surfaces, id);
+}
+
struct pipeline {
VABufferID *filters;
int num_filters;
@@ -48,7 +57,6 @@ struct pipeline {
};
struct vf_priv_s {
- double prev_pts;
int deint_type; // 0: none, 1: discard, 2: double fps
bool do_deint;
VABufferID buffers[VAProcFilterCount];
@@ -61,10 +69,20 @@ struct vf_priv_s {
struct pipeline pipe;
struct mp_image_pool *pool;
int current_rt_format;
+
+ int needed_future_frames;
+ int needed_past_frames;
+
+ // Queue of input frames, used to determine past/current/future frames.
+ // queue[0] is the newest frame, queue[num_queue - 1] the oldest.
+ struct mp_image **queue;
+ int num_queue;
+ // queue[current_pos] is the current frame, unless current_pos is not a
+ // valid index.
+ int current_pos;
};
static const struct vf_priv_s vf_priv_default = {
- .prev_pts = MP_NOPTS_VALUE,
.config = VA_INVALID_ID,
.context = VA_INVALID_ID,
.deint_type = 2,
@@ -80,6 +98,15 @@ static const int deint_algorithm[] = {
[5] = VAProcDeinterlacingMotionCompensated,
};
+static void flush_frames(struct vf_instance *vf)
+{
+ struct vf_priv_s *p = vf->priv;
+ for (int n = 0; n < p->num_queue; n++)
+ talloc_free(p->queue[n]);
+ p->num_queue = 0;
+ p->current_pos = -1;
+}
+
static bool update_pipeline(struct vf_instance *vf, bool deint)
{
struct vf_priv_s *p = vf->priv;
@@ -91,7 +118,7 @@ static bool update_pipeline(struct vf_instance *vf, bool deint)
}
if (filters == p->pipe.filters && num_filters == p->pipe.num_filters)
return true;
- p->pipe.forward.num_required = p->pipe.backward.num_required = 0;
+ p->pipe.forward.num_surfaces = p->pipe.backward.num_surfaces = 0;
p->pipe.num_input_colors = p->pipe.num_output_colors = 0;
p->pipe.num_filters = 0;
p->pipe.filters = NULL;
@@ -110,8 +137,8 @@ static bool update_pipeline(struct vf_instance *vf, bool deint)
p->pipe.num_filters = num_filters;
p->pipe.num_input_colors = caps.num_input_color_standards;
p->pipe.num_output_colors = caps.num_output_color_standards;
- MP_TARRAY_GROW(vf, p->pipe.forward.surfaces, caps.num_forward_references);
- MP_TARRAY_GROW(vf, p->pipe.backward.surfaces, caps.num_backward_references);
+ p->needed_future_frames = caps.num_forward_references;
+ p->needed_past_frames = caps.num_backward_references;
return true;
}
@@ -178,10 +205,22 @@ static struct mp_image *render(struct vf_instance *vf, struct mp_image *in,
param->filter_flags = flags;
param->filters = p->pipe.filters;
param->num_filters = p->pipe.num_filters;
+
+ for (int n = 0; n < p->needed_future_frames; n++) {
+ int idx = p->current_pos - 1 - n;
+ if (idx >= 0 && idx < p->num_queue)
+ add_surface(p, &p->pipe.forward, p->queue[idx]);
+ }
param->forward_references = p->pipe.forward.surfaces;
+ param->num_forward_references = p->pipe.forward.num_surfaces;
+
+ for (int n = 0; n < p->needed_past_frames; n++) {
+ int idx = p->current_pos + 1 + n;
+ if (idx >= 0 && idx < p->num_queue)
+ add_surface(p, &p->pipe.backward, p->queue[idx]);
+ }
param->backward_references = p->pipe.backward.surfaces;
- param->num_forward_references = 0;
- param->num_backward_references = 0;
+ param->num_backward_references = p->pipe.backward.num_surfaces;
vaUnmapBuffer(p->display, buffer);
@@ -200,9 +239,14 @@ cleanup:
return NULL;
}
-static void process(struct vf_instance *vf, struct mp_image *in)
+static void output_frames(struct vf_instance *vf)
{
struct vf_priv_s *p = vf->priv;
+
+ struct mp_image *in = p->queue[p->current_pos];
+ double prev_pts = p->current_pos + 1 < p->num_queue
+ ? p->queue[p->current_pos + 1]->pts : MP_NOPTS_VALUE;
+
bool deint = p->do_deint && p->deint_type > 0;
if (!update_pipeline(vf, deint) || !p->pipe.filters) { // no filtering
vf_add_output_frame(vf, mp_image_new_ref(in));
@@ -220,8 +264,8 @@ static void process(struct vf_instance *vf, struct mp_image *in)
// first-field only
if (field == VA_FRAME_PICTURE || (p->do_deint && p->deint_type < 2))
return;
- double add = (in->pts - p->prev_pts) * 0.5;
- if (p->prev_pts == MP_NOPTS_VALUE || add <= 0.0 || add > 0.5) // no pts, skip it
+ double add = (in->pts - prev_pts) * 0.5;
+ if (prev_pts == MP_NOPTS_VALUE || add <= 0.0 || add > 0.5) // no pts, skip it
return;
struct mp_image *out2 = render(vf, in, get_deint_field(p, 1, in) | csp);
if (!out2) // cannot render
@@ -249,27 +293,46 @@ static struct mp_image *upload(struct vf_instance *vf, struct mp_image *in)
static int filter_ext(struct vf_instance *vf, struct mp_image *in)
{
struct vf_priv_s *p = vf->priv;
- if (!in)
- return 0;
- int rt_format = in->imgfmt == IMGFMT_VAAPI ? va_surface_rt_format(in)
- : VA_RT_FORMAT_YUV420;
- if (!p->pool || p->current_rt_format != rt_format) {
- talloc_free(p->pool);
- p->pool = mp_image_pool_new(20);
- va_pool_set_allocator(p->pool, p->va, rt_format);
- p->current_rt_format = rt_format;
+
+ if (in) {
+ int rt_format = in->imgfmt == IMGFMT_VAAPI ? va_surface_rt_format(in)
+ : VA_RT_FORMAT_YUV420;
+ if (!p->pool || p->current_rt_format != rt_format) {
+ talloc_free(p->pool);
+ p->pool = mp_image_pool_new(20);
+ va_pool_set_allocator(p->pool, p->va, rt_format);
+ p->current_rt_format = rt_format;
+ }
+ if (in->imgfmt != IMGFMT_VAAPI) {
+ struct mp_image *tmp = upload(vf, in);
+ talloc_free(in);
+ in = tmp;
+ if (!in)
+ return -1;
+ }
}
- if (in->imgfmt != IMGFMT_VAAPI) {
- struct mp_image *tmp = upload(vf, in);
- talloc_free(in);
- in = tmp;
- if (!in)
- return -1;
+
+ if (in) {
+ MP_TARRAY_INSERT_AT(p, p->queue, p->num_queue, 0, in);
+ p->current_pos++;
+ assert(p->num_queue != 1 || p->current_pos == 0);
}
- process(vf, in);
- p->prev_pts = in->pts;
- talloc_free(in);
+ // Discard unneeded past frames.
+ // Note that we keep at least 1 past frame (for PTS calculations).
+ while (p->num_queue - (p->current_pos + 1) > MPMAX(p->needed_past_frames, 1)) {
+ assert(p->num_queue > 0);
+ talloc_free(p->queue[p->num_queue - 1]);
+ p->num_queue--;
+ }
+
+ if (p->current_pos < p->needed_future_frames && in)
+ return 0; // wait until future frames have been filled
+
+ if (p->current_pos >= 0 && p->current_pos < p->num_queue) {
+ output_frames(vf);
+ p->current_pos--;
+ }
return 0;
}
@@ -278,10 +341,10 @@ static int reconfig(struct vf_instance *vf, struct mp_image_params *in,
{
struct vf_priv_s *p = vf->priv;
- p->prev_pts = MP_NOPTS_VALUE;
p->params = *in;
*out = *in;
out->imgfmt = IMGFMT_VAAPI;
+ flush_frames(vf);
return 0;
}
@@ -295,6 +358,7 @@ static void uninit(struct vf_instance *vf)
if (p->config != VA_INVALID_ID)
vaDestroyConfig(p->display, p->config);
talloc_free(p->pool);
+ flush_frames(vf);
}
static int query_format(struct vf_instance *vf, unsigned int imgfmt)
@@ -315,6 +379,9 @@ static int control(struct vf_instance *vf, int request, void* data)
case VFCTRL_SET_DEINTERLACE:
p->do_deint = *(int*)data;
return true;
+ case VFCTRL_SEEK_RESET:
+ flush_frames(vf);
+ return true;
default:
return CONTROL_UNKNOWN;
}