From 72308256e45e9184bb1578ad2cd40830e091ce13 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 25 Mar 2015 14:33:20 +0100 Subject: vf_vapoursynth: handle approximate EOF draining Handling this perfectly with VapourSynth is probably not possible: you either need to tell it the total number of input frames in advance, or deliver an infinite stream. With playback, EOF can happen at an unpredictable point, for which the VapourSynth API has no mechanism at all. We handle EOF by returning an error to the filter, which will the filter return all pending frame callbacks. We still can try to handle it approximately: if the filter requests a frame past EOF, then send it an error. This seems to work relatively well with filters which don't request future frames. --- video/filter/vf_vapoursynth.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/video/filter/vf_vapoursynth.c b/video/filter/vf_vapoursynth.c index 5afee78b17..db0bce3210 100644 --- a/video/filter/vf_vapoursynth.c +++ b/video/filter/vf_vapoursynth.c @@ -72,6 +72,8 @@ struct vf_priv_s { int max_requests; // upper bound for requested[] array bool failed; // frame callback returned with an error bool shutdown; // ask node to return + bool eof; // drain remaining data + int64_t frames_sent; bool initializing; // filters are being built bool in_node_active; // node might still be called @@ -315,6 +317,7 @@ static int filter_ext(struct vf_instance *vf, struct mp_image *mpi) { struct vf_priv_s *p = vf->priv; int ret = 0; + bool eof = !mpi; if (!p->out_node) { talloc_free(mpi); @@ -323,13 +326,12 @@ static int filter_ext(struct vf_instance *vf, struct mp_image *mpi) MPSWAP(struct mp_image *, p->next_image, mpi); - if (!mpi) - return 0; - - // Turn PTS into frame duration (the pts field is abused for storing it) - if (p->out_pts == MP_NOPTS_VALUE) - p->out_pts = mpi->pts; - mpi->pts = p->next_image ? p->next_image->pts - mpi->pts : 0; + if (mpi) { + // Turn PTS into frame duration (the pts field is abused for storing it) + if (p->out_pts == MP_NOPTS_VALUE) + p->out_pts = mpi->pts; + mpi->pts = p->next_image ? p->next_image->pts - mpi->pts : 0; + } // Try to get new frames until we get rid of the input mpi. pthread_mutex_lock(&p->lock); @@ -344,6 +346,7 @@ static int filter_ext(struct vf_instance *vf, struct mp_image *mpi) // Make the input frame available to infiltGetFrame(). if (mpi && locked_need_input(vf)) { + p->frames_sent++; p->buffered[p->num_buffered++] = talloc_steal(p->buffered, mpi); mpi = NULL; pthread_cond_broadcast(&p->wakeup); @@ -351,8 +354,14 @@ static int filter_ext(struct vf_instance *vf, struct mp_image *mpi) locked_read_output(vf); - if (!mpi) + if (!mpi) { + if (eof && p->frames_sent && !p->eof) { + MP_VERBOSE(vf, "input EOF\n"); + p->eof = true; + pthread_cond_broadcast(&p->wakeup); + } break; + } pthread_cond_wait(&p->wakeup, &p->lock); } pthread_mutex_unlock(&p->lock); @@ -374,7 +383,7 @@ static int filter_out(struct vf_instance *vf) break; // If the VS filter wants new input, there's no guarantee that we can // actually finish any time soon without feeding new input. - if (locked_need_input(vf)) + if (!p->eof && locked_need_input(vf)) break; pthread_cond_wait(&p->wakeup, &p->lock); } @@ -468,6 +477,14 @@ static const VSFrameRef *VS_CC infiltGetFrame(int frameno, int activationReason, continue; } } + if (frameno >= p->in_frameno + p->num_buffered) { + // If we think EOF was reached, don't wait for new input, and assume + // the VS filter has reached EOF. + if (p->eof) { + p->shutdown = true; + continue; + } + } if (frameno < p->in_frameno + p->num_buffered) { struct mp_image *img = p->buffered[frameno - p->in_frameno]; ret = alloc_vs_frame(p, &img->params); @@ -539,6 +556,8 @@ static void destroy_vs(struct vf_instance *vf) assert(num_requested(p) == 0); // async callback didn't return? p->shutdown = false; + p->eof = false; + p->frames_sent = 0; // Kill filtered images that weren't returned yet for (int n = 0; n < p->max_requests; n++) mp_image_unrefp(&p->requested[n]); -- cgit v1.2.3