예제 #1
0
파일: video.c 프로젝트: Jim-Duke/mpv
// Fill mpctx->next_frames[] with a newly filtered or decoded image.
// returns VD_* code
static int video_output_image(struct MPContext *mpctx, double endpts)
{
    bool hrseek = mpctx->hrseek_active && mpctx->video_status == STATUS_SYNCING;

    if (mpctx->d_video->header->attached_picture) {
        if (vo_has_frame(mpctx->video_out))
            return VD_EOF;
        if (mpctx->num_next_frames >= 1)
            return VD_NEW_FRAME;
        int r = video_decode_and_filter(mpctx);
        video_filter(mpctx, true); // force EOF filtering (avoid decoding more)
        mpctx->next_frames[0] = vf_read_output_frame(mpctx->d_video->vfilter);
        if (mpctx->next_frames[0]) {
            mpctx->next_frames[0]->pts = MP_NOPTS_VALUE;
            mpctx->num_next_frames = 1;
        }
        return r <= 0 ? VD_EOF : VD_PROGRESS;
    }

    if (have_new_frame(mpctx, false))
        return VD_NEW_FRAME;

    // Get a new frame if we need one.
    int r = VD_PROGRESS;
    if (needs_new_frame(mpctx)) {
        // Filter a new frame.
        r = video_decode_and_filter(mpctx);
        if (r < 0)
            return r; // error
        struct mp_image *img = vf_read_output_frame(mpctx->d_video->vfilter);
        if (img) {
            // Always add these; they make backstepping after seeking faster.
            add_frame_pts(mpctx, img->pts);

            if (endpts != MP_NOPTS_VALUE && img->pts >= endpts) {
                r = VD_EOF;
            } else if (mpctx->max_frames == 0) {
                r = VD_EOF;
            } else if (hrseek && mpctx->hrseek_lastframe) {
                mp_image_setrefp(&mpctx->saved_frame, img);
            } else if (hrseek && img->pts < mpctx->hrseek_pts - .005) {
                /* just skip */
            } else {
                add_new_frame(mpctx, img);
                img = NULL;
            }
            talloc_free(img);
        }
    }

    // Last-frame seek
    if (r <= 0 && hrseek && mpctx->hrseek_lastframe && mpctx->saved_frame) {
        add_new_frame(mpctx, mpctx->saved_frame);
        mpctx->saved_frame = NULL;
        r = VD_PROGRESS;
    }

    return have_new_frame(mpctx, r <= 0) ? VD_NEW_FRAME : r;
}
예제 #2
0
파일: video.c 프로젝트: xnoreq/mpv
// Fill mpctx->next_frame[] with a newly filtered or decoded image.
// returns VD_* code
static int video_output_image(struct MPContext *mpctx, double endpts)
{
    bool hrseek = mpctx->hrseek_active && mpctx->video_status == STATUS_SYNCING;

    if (mpctx->d_video->header->attached_picture) {
        if (vo_has_frame(mpctx->video_out))
            return VD_EOF;
        if (mpctx->next_frame[0])
            return VD_NEW_FRAME;
        int r = video_decode_and_filter(mpctx);
        video_filter(mpctx, true); // force EOF filtering (avoid decoding more)
        mpctx->next_frame[0] = vf_read_output_frame(mpctx->d_video->vfilter);
        if (mpctx->next_frame[0])
            mpctx->next_frame[0]->pts = MP_NOPTS_VALUE;
        return r <= 0 ? VD_EOF : VD_PROGRESS;
    }

    if (have_new_frame(mpctx))
        return VD_NEW_FRAME;

    if (!mpctx->next_frame[0] && mpctx->next_frame[1]) {
        mpctx->next_frame[0] = mpctx->next_frame[1];
        mpctx->next_frame[1] = NULL;

        double pts = mpctx->next_frame[0]->pts;
        double last_pts = mpctx->video_pts;
        if (last_pts == MP_NOPTS_VALUE)
            last_pts = pts;
        double frame_time = pts - last_pts;
        if (frame_time < 0 || frame_time >= 60) {
            // Assume a PTS difference >= 60 seconds is a discontinuity.
            MP_WARN(mpctx, "Jump in video pts: %f -> %f\n", last_pts, pts);
            frame_time = 0;
        }
        mpctx->video_next_pts = pts;
        if (mpctx->d_audio)
            mpctx->delay -= frame_time;
        if (mpctx->video_status >= STATUS_READY) {
            mpctx->time_frame += frame_time / mpctx->opts->playback_speed;
            adjust_sync(mpctx, pts, frame_time);
        }
        mpctx->dropped_frames = 0;
        MP_TRACE(mpctx, "frametime=%5.3f\n", frame_time);
    }

    if (have_new_frame(mpctx))
        return VD_NEW_FRAME;

    // Get a new frame if we need one.
    int r = VD_PROGRESS;
    if (!mpctx->next_frame[1]) {
        // Filter a new frame.
        r = video_decode_and_filter(mpctx);
        if (r < 0)
            return r; // error
        struct mp_image *img = vf_read_output_frame(mpctx->d_video->vfilter);
        if (img) {
            // Always add these; they make backstepping after seeking faster.
            add_frame_pts(mpctx, img->pts);

            bool drop = false;
            if ((endpts != MP_NOPTS_VALUE && img->pts >= endpts) ||
                mpctx->max_frames == 0)
            {
                drop = true;
                r = VD_EOF;
            }
            if (!drop && hrseek && mpctx->hrseek_lastframe) {
                mp_image_setrefp(&mpctx->saved_frame, img);
                drop = true;
            }
            if (hrseek && img->pts < mpctx->hrseek_pts - .005)
                drop = true;
            if (drop) {
                talloc_free(img);
            } else {
                mpctx->next_frame[1] = img;
            }
        }
    }

    // On EOF, always allow the playloop to use the remaining frame.
    if (have_new_frame(mpctx) || (r <= 0 && mpctx->next_frame[0]))
        return VD_NEW_FRAME;

    // Last-frame seek
    if (r <= 0 && hrseek && mpctx->hrseek_lastframe && mpctx->saved_frame) {
        mpctx->next_frame[1] = mpctx->saved_frame;
        mpctx->saved_frame = NULL;
        return VD_PROGRESS;
    }

    return r;
}