コード例 #1
0
ファイル: video.c プロジェクト: prodigeni/mpv
static void reconfig_video(struct MPContext *mpctx,
                           const struct mp_image_params *params,
                           bool probe_only)
{
    struct MPOpts *opts = mpctx->opts;
    struct dec_video *d_video = mpctx->d_video;

    d_video->decoder_output = *params;

    set_allowed_vo_formats(d_video->vfilter, mpctx->video_out);

    // The event should happen _after_ filter and VO reconfig. Since we don't
    // have any fine grained locking, this is just as good.
    mp_notify(mpctx, MPV_EVENT_VIDEO_RECONFIG, NULL);

    if (video_reconfig_filters(d_video, params) < 0) {
        // Most video filters don't work with hardware decoding, so this
        // might be the reason filter reconfig failed.
        if (!probe_only &&
                video_vd_control(d_video, VDCTRL_FORCE_HWDEC_FALLBACK, NULL) == CONTROL_OK)
        {
            // Fallback active; decoder will return software format next
            // time. Don't abort video decoding.
            d_video->vfilter->initialized = 0;
        }
        return;
    }

    if (d_video->vfilter->initialized < 1)
        return;

    struct mp_image_params p = d_video->vfilter->output_params;
    const struct vo_driver *info = mpctx->video_out->driver;
    MP_INFO(mpctx, "VO: [%s] %dx%d => %dx%d %s\n",
            info->name, p.w, p.h, p.d_w, p.d_h, vo_format_name(p.imgfmt));
    MP_VERBOSE(mpctx, "VO: Description: %s\n", info->description);

    int r = vo_reconfig(mpctx->video_out, &p, 0);
    if (r < 0)
        d_video->vfilter->initialized = -1;

    if (r >= 0) {
        if (opts->gamma_gamma != 1000)
            video_set_colors(d_video, "gamma", opts->gamma_gamma);
        if (opts->gamma_brightness != 1000)
            video_set_colors(d_video, "brightness", opts->gamma_brightness);
        if (opts->gamma_contrast != 1000)
            video_set_colors(d_video, "contrast", opts->gamma_contrast);
        if (opts->gamma_saturation != 1000)
            video_set_colors(d_video, "saturation", opts->gamma_saturation);
        if (opts->gamma_hue != 1000)
            video_set_colors(d_video, "hue", opts->gamma_hue);
    }
}
コード例 #2
0
ファイル: vf_vo.c プロジェクト: CrimsonVoid/mpv
static int reconfig(struct vf_instance *vf, struct mp_image_params *p, int flags)
{
    if (p->w <= 0 || p->h <= 0 || p->d_w <= 0 || p->d_h <= 0) {
        mp_msg(MSGT_CPLAYER, MSGL_ERR, "VO: invalid dimensions!\n");
        return -1;
    }

    const struct vo_driver *info = video_out->driver;
    mp_msg(MSGT_CPLAYER, MSGL_INFO, "VO: [%s] %dx%d => %dx%d %s %s\n",
           info->name,
           p->w, p->h, p->d_w, p->d_h,
           vo_format_name(p->imgfmt),
           (flags & VOFLAG_FLIPPING) ? " [flip]" : "");
    mp_msg(MSGT_CPLAYER, MSGL_V, "VO: Description: %s\n", info->description);

    return vo_reconfig(video_out, p, flags);
}
コード例 #3
0
ファイル: video.c プロジェクト: Jim-Duke/mpv
void write_video(struct MPContext *mpctx, double endpts)
{
    struct MPOpts *opts = mpctx->opts;
    struct vo *vo = mpctx->video_out;

    if (!mpctx->d_video)
        return;

    // Actual playback starts when both audio and video are ready.
    if (mpctx->video_status == STATUS_READY)
        return;

    if (mpctx->paused && mpctx->video_status >= STATUS_READY)
        return;

    int r = video_output_image(mpctx, endpts);
    MP_TRACE(mpctx, "video_output_image: %d\n", r);

    if (r < 0)
        goto error;

    if (r == VD_WAIT) // Demuxer will wake us up for more packets to decode.
        return;

    if (r == VD_EOF) {
        mpctx->video_status =
            vo_still_displaying(vo) ? STATUS_DRAINING : STATUS_EOF;
        mpctx->delay = 0;
        mpctx->last_av_difference = 0;
        MP_DBG(mpctx, "video EOF (status=%d)\n", mpctx->video_status);
        return;
    }

    if (mpctx->video_status > STATUS_PLAYING)
        mpctx->video_status = STATUS_PLAYING;

    if (r != VD_NEW_FRAME) {
        mpctx->sleeptime = 0; // Decode more in next iteration.
        return;
    }

    // Filter output is different from VO input?
    struct mp_image_params p = mpctx->next_frames[0]->params;
    if (!vo->params || !mp_image_params_equal(&p, vo->params)) {
        // Changing config deletes the current frame; wait until it's finished.
        if (vo_still_displaying(vo))
            return;

        const struct vo_driver *info = mpctx->video_out->driver;
        char extra[20] = {0};
        if (p.w != p.d_w || p.h != p.d_h)
            snprintf(extra, sizeof(extra), " => %dx%d", p.d_w, p.d_h);
        MP_INFO(mpctx, "VO: [%s] %dx%d%s %s\n",
                info->name, p.w, p.h, extra, vo_format_name(p.imgfmt));
        MP_VERBOSE(mpctx, "VO: Description: %s\n", info->description);

        int vo_r = vo_reconfig(vo, &p, 0);
        if (vo_r < 0) {
            mpctx->error_playing = MPV_ERROR_VO_INIT_FAILED;
            goto error;
        }
        init_vo(mpctx);
    }

    mpctx->time_frame -= get_relative_time(mpctx);
    update_avsync_before_frame(mpctx);

    double time_frame = MPMAX(mpctx->time_frame, -1);
    int64_t pts = mp_time_us() + (int64_t)(time_frame * 1e6);

    // wait until VO wakes us up to get more frames
    if (!vo_is_ready_for_frame(vo, pts)) {
        if (video_feed_async_filter(mpctx) < 0)
            goto error;
        return;
    }

    assert(mpctx->num_next_frames >= 1);
    struct vo_frame dummy = {
        .pts = pts,
        .duration = -1,
        .num_frames = mpctx->num_next_frames,
    };
    for (int n = 0; n < dummy.num_frames; n++)
        dummy.frames[n] = mpctx->next_frames[n];
    struct vo_frame *frame = vo_frame_ref(&dummy);

    double diff = -1;
    double vpts0 = mpctx->next_frames[0]->pts;
    double vpts1 = MP_NOPTS_VALUE;
    if (mpctx->num_next_frames >= 2)
        vpts1 = mpctx->next_frames[1]->pts;
    if (vpts0 != MP_NOPTS_VALUE && vpts1 != MP_NOPTS_VALUE)
        diff = vpts1 - vpts0;
    if (diff < 0 && mpctx->d_video->fps > 0)
        diff = 1.0 / mpctx->d_video->fps; // fallback to demuxer-reported fps
    if (opts->untimed || vo->driver->untimed)
        diff = -1; // disable frame dropping and aspects of frame timing
    if (diff >= 0) {
        // expected A/V sync correction is ignored
        diff /= opts->playback_speed;
        if (mpctx->time_frame < 0)
            diff += mpctx->time_frame;
        frame->duration = MPCLAMP(diff, 0, 10) * 1e6;
    }

    mpctx->video_pts = mpctx->next_frames[0]->pts;
    mpctx->last_vo_pts = mpctx->video_pts;
    mpctx->playback_pts = mpctx->video_pts;

    update_avsync_after_frame(mpctx);

    mpctx->osd_force_update = true;
    update_osd_msg(mpctx);
    update_subtitles(mpctx);

    vo_queue_frame(vo, frame);

    shift_frames(mpctx);

    // The frames were shifted down; "initialize" the new first entry.
    if (mpctx->num_next_frames >= 1)
        handle_new_frame(mpctx);

    mpctx->shown_vframes++;
    if (mpctx->video_status < STATUS_PLAYING) {
        mpctx->video_status = STATUS_READY;
        // After a seek, make sure to wait until the first frame is visible.
        vo_wait_frame(vo);
        MP_VERBOSE(mpctx, "first video frame after restart shown\n");
    }
    screenshot_flip(mpctx);

    mp_notify(mpctx, MPV_EVENT_TICK, NULL);

    if (!mpctx->sync_audio_to_video)
        mpctx->video_status = STATUS_EOF;

    if (mpctx->video_status != STATUS_EOF) {
        if (mpctx->step_frames > 0) {
            mpctx->step_frames--;
            if (!mpctx->step_frames && !opts->pause)
                pause_player(mpctx);
        }
        if (mpctx->max_frames == 0 && !mpctx->stop_play)
            mpctx->stop_play = AT_END_OF_FILE;
        if (mpctx->max_frames > 0)
            mpctx->max_frames--;
    }

    mpctx->sleeptime = 0;
    return;

error:
    MP_FATAL(mpctx, "Could not initialize video chain.\n");
    uninit_video_chain(mpctx);
    error_on_track(mpctx, mpctx->current_track[STREAM_VIDEO][0]);
    handle_force_window(mpctx, true);
    mpctx->sleeptime = 0;
}
コード例 #4
0
ファイル: video.c プロジェクト: jeremiejig/mpv
// Fill the VO buffer with a newly filtered or decoded image.
// returns VD_* code
static int video_output_image(struct MPContext *mpctx, double endpts,
                              bool reconfig_ok)
{
    struct vf_chain *vf = mpctx->d_video->vfilter;
    struct vo *vo = mpctx->video_out;

    // Already enough video buffered in VO?
    // (This implies vo_has_next_frame(vo, false/true) returns true.)
    if (!vo_needs_new_image(vo) && vo->params)
        return 1;

    // Filter a new frame.
    int r = video_decode_and_filter(mpctx);
    if (r < 0)
        return r; // error

    vf_output_frame(vf, false);
    if (vf->output) {
        double pts = vf->output->pts;

        // Always add these; they make backstepping after seeking faster.
        add_frame_pts(mpctx, pts);

        bool drop = false;
        bool hrseek = mpctx->hrseek_active && mpctx->video_status == STATUS_SYNCING
                      && !mpctx->d_video->header->attached_picture;
        if (hrseek && pts < mpctx->hrseek_pts - .005)
            drop = true;
        if (endpts != MP_NOPTS_VALUE && pts >= endpts) {
            drop = true;
            r = VD_EOF;
        }
        if (drop) {
            talloc_free(vf->output);
            vf->output = NULL;
            return r;
        }
    }

    // Filter output is different from VO input?
    bool need_vo_reconfig = !vo->params  ||
        !mp_image_params_equal(&vf->output_params, vo->params);

    if (need_vo_reconfig) {
        // Draining VO buffers.
        if (vo_has_next_frame(vo, true))
            return 0; // EOF so that caller displays remaining VO frames

        // There was no decoded image yet - must not signal fake EOF.
        // Likewise, if there's no filtered frame yet, don't reconfig yet.
        if (!vf->output_params.imgfmt || !vf->output)
            return r;

        // Force draining.
        if (!reconfig_ok)
            return 0;

        struct mp_image_params p = vf->output_params;

        const struct vo_driver *info = mpctx->video_out->driver;
        MP_INFO(mpctx, "VO: [%s] %dx%d => %dx%d %s\n",
                info->name, p.w, p.h, p.d_w, p.d_h, vo_format_name(p.imgfmt));
        MP_VERBOSE(mpctx, "VO: Description: %s\n", info->description);

        int vo_r = vo_reconfig(vo, &p, 0);
        if (vo_r < 0) {
            vf->initialized = -1;
            return VD_ERROR;
        }
        init_vo(mpctx);
        // Display the frame queued after this immediately.
        // (Neutralizes frame time calculation in update_video.)
        mpctx->video_next_pts = MP_NOPTS_VALUE;
    }

    // Queue new frame, if there's one.
    struct mp_image *img = vf_read_output_frame(vf);
    if (img) {
        vo_queue_image(vo, img);
        return VD_PROGRESS;
    }

    return r; // includes the true EOF case
}
コード例 #5
0
ファイル: video.c プロジェクト: bagobor/mpv
void write_video(struct MPContext *mpctx, double endpts)
{
    struct MPOpts *opts = mpctx->opts;
    struct vo *vo = mpctx->video_out;

    if (!mpctx->d_video)
        return;

    // Actual playback starts when both audio and video are ready.
    if (mpctx->video_status == STATUS_READY)
        return;

    if (mpctx->paused && mpctx->video_status >= STATUS_READY)
        return;

    update_fps(mpctx);

    int r = video_output_image(mpctx, endpts);
    MP_TRACE(mpctx, "video_output_image: %d\n", r);

    if (r < 0)
        goto error;

    if (r == VD_WAIT) // Demuxer will wake us up for more packets to decode.
        return;

    if (r == VD_EOF) {
        mpctx->video_status =
            vo_still_displaying(vo) ? STATUS_DRAINING : STATUS_EOF;
        mpctx->delay = 0;
        mpctx->last_av_difference = 0;
        MP_VERBOSE(mpctx, "video EOF (status=%d)\n", mpctx->video_status);
        return;
    }

    if (mpctx->video_status > STATUS_PLAYING)
        mpctx->video_status = STATUS_PLAYING;

    mpctx->time_frame -= get_relative_time(mpctx);
    update_avsync_before_frame(mpctx);

    if (r != VD_NEW_FRAME) {
        mpctx->sleeptime = 0; // Decode more in next iteration.
        return;
    }

    // Filter output is different from VO input?
    struct mp_image_params p = mpctx->next_frame[0]->params;
    if (!vo->params || !mp_image_params_equal(&p, vo->params)) {
        // Changing config deletes the current frame; wait until it's finished.
        if (vo_still_displaying(vo))
            return;

        const struct vo_driver *info = mpctx->video_out->driver;
        MP_INFO(mpctx, "VO: [%s] %dx%d => %dx%d %s\n",
                info->name, p.w, p.h, p.d_w, p.d_h, vo_format_name(p.imgfmt));
        MP_VERBOSE(mpctx, "VO: Description: %s\n", info->description);

        int vo_r = vo_reconfig(vo, &p, 0);
        if (vo_r < 0)
            goto error;
        init_vo(mpctx);
        mpctx->time_frame = 0; // display immediately
    }

    double time_frame = MPMAX(mpctx->time_frame, -1);
    int64_t pts = mp_time_us() + (int64_t)(time_frame * 1e6);

    if (!vo_is_ready_for_frame(vo, pts))
        return; // wait until VO wakes us up to get more frames

    int64_t duration = -1;
    double diff = -1;
    double vpts0 = mpctx->next_frame[0] ? mpctx->next_frame[0]->pts : MP_NOPTS_VALUE;
    double vpts1 = mpctx->next_frame[1] ? mpctx->next_frame[1]->pts : MP_NOPTS_VALUE;
    if (vpts0 != MP_NOPTS_VALUE && vpts1 != MP_NOPTS_VALUE)
        diff = vpts1 - vpts0;
    if (diff < 0 && mpctx->d_video->fps > 0)
        diff = 1.0 / mpctx->d_video->fps; // fallback to demuxer-reported fps
    if (diff >= 0) {
        // expected A/V sync correction is ignored
        diff /= opts->playback_speed;
        if (mpctx->time_frame < 0)
            diff += mpctx->time_frame;
        duration = MPCLAMP(diff, 0, 10) * 1e6;
    }

    mpctx->video_pts = mpctx->next_frame[0]->pts;
    mpctx->last_vo_pts = mpctx->video_pts;
    mpctx->playback_pts = mpctx->video_pts;

    mpctx->osd_force_update = true;
    update_osd_msg(mpctx);
    update_subtitles(mpctx);

    vo_queue_frame(vo, mpctx->next_frame[0], pts, duration);
    mpctx->next_frame[0] = NULL;

    mpctx->shown_vframes++;
    if (mpctx->video_status < STATUS_PLAYING) {
        mpctx->video_status = STATUS_READY;
        // After a seek, make sure to wait until the first frame is visible.
        vo_wait_frame(vo);
    }
    update_avsync_after_frame(mpctx);
    screenshot_flip(mpctx);

    mp_notify(mpctx, MPV_EVENT_TICK, NULL);

    if (!mpctx->sync_audio_to_video)
        mpctx->video_status = STATUS_EOF;

    if (mpctx->video_status != STATUS_EOF) {
        if (mpctx->step_frames > 0) {
            mpctx->step_frames--;
            if (!mpctx->step_frames && !opts->pause)
                pause_player(mpctx);
        }
        if (mpctx->max_frames == 0)
            mpctx->stop_play = PT_NEXT_ENTRY;
        if (mpctx->max_frames > 0)
            mpctx->max_frames--;
    }

    mpctx->sleeptime = 0;
    return;

error:
    MP_FATAL(mpctx, "Could not initialize video chain.\n");
    int uninit = INITIALIZED_VCODEC;
    if (!opts->force_vo)
        uninit |= INITIALIZED_VO;
    uninit_player(mpctx, uninit);
    if (!mpctx->current_track[STREAM_AUDIO])
        mpctx->stop_play = PT_NEXT_ENTRY;
    mpctx->error_playing = true;
    handle_force_window(mpctx, true);
    mpctx->sleeptime = 0;
}