mirror of
https://github.com/mpv-player/mpv.git
synced 2025-12-28 05:33:14 +00:00
player: refactor: eliminate MPContext.d_video
Eventually we want the VO be driven by a A->V filter, so a decoder doesn't even have to exist. Some features definitely require a decoder though (like reporting the decoder in use, hardware decoding, etc.), so for each thing which accessed d_video, it has to be redecided if and how it can access decoder state. At least the "framedrop" property slightly changes semantics: you can now always set this property, even if no video is active. Some untested changes in this commit, but our bio-based distributed test suite has to take care of this.
This commit is contained in:
@@ -193,16 +193,15 @@ static void filter_reconfig(struct vo_chain *vo_c)
|
||||
static void recreate_video_filters(struct MPContext *mpctx)
|
||||
{
|
||||
struct MPOpts *opts = mpctx->opts;
|
||||
struct dec_video *d_video = mpctx->d_video;
|
||||
struct vo_chain *vo_c = mpctx->vo_chain;
|
||||
assert(d_video && vo_c);
|
||||
assert(vo_c);
|
||||
|
||||
vf_destroy(vo_c->vf);
|
||||
vo_c->vf = vf_new(mpctx->global);
|
||||
vo_c->vf->hwdec = d_video->hwdec_info;
|
||||
vo_c->vf->hwdec = vo_c->hwdec_info;
|
||||
vo_c->vf->wakeup_callback = wakeup_playloop;
|
||||
vo_c->vf->wakeup_callback_ctx = mpctx;
|
||||
vo_c->vf->container_fps = d_video->fps;
|
||||
vo_c->vf->container_fps = vo_c->container_fps;
|
||||
vo_control(vo_c->vo, VOCTRL_GET_DISPLAY_FPS, &vo_c->vf->display_fps);
|
||||
|
||||
vf_append_filter_list(vo_c->vf, opts->vf_settings);
|
||||
@@ -216,10 +215,9 @@ static void recreate_video_filters(struct MPContext *mpctx)
|
||||
|
||||
int reinit_video_filters(struct MPContext *mpctx)
|
||||
{
|
||||
struct dec_video *d_video = mpctx->d_video;
|
||||
struct vo_chain *vo_c = mpctx->vo_chain;
|
||||
|
||||
if (!d_video)
|
||||
if (!vo_c)
|
||||
return 0;
|
||||
bool need_reconfig = vo_c->vf->initialized != 0;
|
||||
|
||||
@@ -243,10 +241,10 @@ static void vo_chain_reset_state(struct vo_chain *vo_c)
|
||||
|
||||
void reset_video_state(struct MPContext *mpctx)
|
||||
{
|
||||
if (mpctx->d_video)
|
||||
video_reset(mpctx->d_video);
|
||||
if (mpctx->vo_chain)
|
||||
if (mpctx->vo_chain) {
|
||||
video_reset(mpctx->vo_chain->video_src);
|
||||
vo_chain_reset_state(mpctx->vo_chain);
|
||||
}
|
||||
|
||||
for (int n = 0; n < mpctx->num_next_frames; n++)
|
||||
mp_image_unrefp(&mpctx->next_frames[n]);
|
||||
@@ -266,7 +264,7 @@ void reset_video_state(struct MPContext *mpctx)
|
||||
mpctx->display_sync_drift_dir = 0;
|
||||
mpctx->display_sync_broken = false;
|
||||
|
||||
mpctx->video_status = mpctx->d_video ? STATUS_SYNCING : STATUS_EOF;
|
||||
mpctx->video_status = mpctx->vo_chain ? STATUS_SYNCING : STATUS_EOF;
|
||||
}
|
||||
|
||||
void uninit_video_out(struct MPContext *mpctx)
|
||||
@@ -282,20 +280,21 @@ void uninit_video_out(struct MPContext *mpctx)
|
||||
static void vo_chain_uninit(struct vo_chain *vo_c)
|
||||
{
|
||||
mp_image_unrefp(&vo_c->input_mpi);
|
||||
if (vo_c)
|
||||
if (vo_c) {
|
||||
vf_destroy(vo_c->vf);
|
||||
if (vo_c->video_src)
|
||||
video_uninit(vo_c->video_src);
|
||||
}
|
||||
talloc_free(vo_c);
|
||||
// this does not free the VO
|
||||
}
|
||||
|
||||
void uninit_video_chain(struct MPContext *mpctx)
|
||||
{
|
||||
if (mpctx->d_video) {
|
||||
if (mpctx->vo_chain) {
|
||||
reset_video_state(mpctx);
|
||||
vo_chain_uninit(mpctx->vo_chain);
|
||||
mpctx->vo_chain = NULL;
|
||||
video_uninit(mpctx->d_video);
|
||||
mpctx->d_video = NULL;
|
||||
mpctx->video_status = STATUS_EOF;
|
||||
mpctx->sync_audio_to_video = false;
|
||||
reselect_demux_streams(mpctx);
|
||||
@@ -307,7 +306,6 @@ void uninit_video_chain(struct MPContext *mpctx)
|
||||
int reinit_video_chain(struct MPContext *mpctx)
|
||||
{
|
||||
struct MPOpts *opts = mpctx->opts;
|
||||
assert(!mpctx->d_video);
|
||||
assert(!mpctx->vo_chain);
|
||||
struct track *track = mpctx->current_track[0][STREAM_VIDEO];
|
||||
struct sh_stream *sh = track ? track->stream : NULL;
|
||||
@@ -333,17 +331,21 @@ int reinit_video_chain(struct MPContext *mpctx)
|
||||
|
||||
update_window_title(mpctx, true);
|
||||
|
||||
struct dec_video *d_video = talloc_zero(NULL, struct dec_video);
|
||||
mpctx->d_video = d_video;
|
||||
struct vo_chain *vo_c = talloc_zero(NULL, struct vo_chain);
|
||||
mpctx->vo_chain = vo_c;
|
||||
vo_c->log = mpctx->log;
|
||||
vo_c->vo = mpctx->video_out;
|
||||
|
||||
vo_control(vo_c->vo, VOCTRL_GET_HWDEC_INFO, &vo_c->hwdec_info);
|
||||
|
||||
track->d_video = talloc_zero(NULL, struct dec_video);
|
||||
struct dec_video *d_video = track->d_video;
|
||||
d_video->global = mpctx->global;
|
||||
d_video->log = mp_log_new(d_video, mpctx->log, "!vd");
|
||||
d_video->opts = mpctx->opts;
|
||||
d_video->header = sh;
|
||||
d_video->fps = sh->codec->fps;
|
||||
|
||||
mpctx->vo_chain = talloc_zero(NULL, struct vo_chain);
|
||||
mpctx->vo_chain->log = d_video->log;
|
||||
mpctx->vo_chain->vo = mpctx->video_out;
|
||||
d_video->hwdec_info = vo_c->hwdec_info;
|
||||
|
||||
MP_VERBOSE(d_video, "Container reported FPS: %f\n", sh->codec->fps);
|
||||
|
||||
@@ -353,23 +355,24 @@ int reinit_video_chain(struct MPContext *mpctx)
|
||||
MP_INFO(mpctx, "Use --no-correct-pts to force FPS based timing.\n");
|
||||
}
|
||||
|
||||
vo_c->container_fps = d_video->fps;
|
||||
vo_c->video_src = d_video;
|
||||
|
||||
#if HAVE_ENCODING
|
||||
if (mpctx->encode_lavc_ctx)
|
||||
encode_lavc_set_video_fps(mpctx->encode_lavc_ctx, d_video->fps);
|
||||
#endif
|
||||
|
||||
vo_control(mpctx->video_out, VOCTRL_GET_HWDEC_INFO, &d_video->hwdec_info);
|
||||
|
||||
recreate_video_filters(mpctx);
|
||||
|
||||
if (!video_init_best_codec(d_video, opts->video_decoders))
|
||||
goto err_out;
|
||||
|
||||
bool saver_state = opts->pause || !opts->stop_screensaver;
|
||||
vo_control(mpctx->video_out, saver_state ? VOCTRL_RESTORE_SCREENSAVER
|
||||
: VOCTRL_KILL_SCREENSAVER, NULL);
|
||||
vo_control(vo_c->vo, saver_state ? VOCTRL_RESTORE_SCREENSAVER
|
||||
: VOCTRL_KILL_SCREENSAVER, NULL);
|
||||
|
||||
vo_set_paused(mpctx->video_out, mpctx->paused);
|
||||
vo_set_paused(vo_c->vo, mpctx->paused);
|
||||
|
||||
mpctx->sync_audio_to_video = !sh->attached_picture;
|
||||
|
||||
@@ -410,19 +413,19 @@ void mp_force_video_refresh(struct MPContext *mpctx)
|
||||
}
|
||||
}
|
||||
|
||||
static bool check_framedrop(struct MPContext *mpctx)
|
||||
static bool check_framedrop(struct MPContext *mpctx, struct vo_chain *vo_c)
|
||||
{
|
||||
struct MPOpts *opts = mpctx->opts;
|
||||
// check for frame-drop:
|
||||
if (mpctx->video_status == STATUS_PLAYING && !mpctx->paused &&
|
||||
mpctx->audio_status == STATUS_PLAYING && !ao_untimed(mpctx->ao))
|
||||
{
|
||||
float fps = mpctx->d_video->fps;
|
||||
float fps = vo_c->container_fps;
|
||||
double frame_time = fps > 0 ? 1.0 / fps : 0;
|
||||
// we should avoid dropping too many frames in sequence unless we
|
||||
// are too late. and we allow 100ms A-V delay here:
|
||||
int dropped_frames =
|
||||
mpctx->d_video->dropped_frames - mpctx->dropped_frames_start;
|
||||
vo_c->video_src->dropped_frames - mpctx->dropped_frames_start;
|
||||
if (mpctx->last_av_difference - 0.100 > dropped_frames * frame_time)
|
||||
return !!(opts->frame_dropping & 2);
|
||||
}
|
||||
@@ -433,14 +436,14 @@ static bool check_framedrop(struct MPContext *mpctx)
|
||||
// returns VD_* code
|
||||
static int decode_image(struct MPContext *mpctx)
|
||||
{
|
||||
struct dec_video *d_video = mpctx->d_video;
|
||||
struct vo_chain *vo_c = mpctx->vo_chain;
|
||||
struct dec_video *d_video = vo_c->video_src;
|
||||
|
||||
bool hrseek = mpctx->hrseek_active && mpctx->video_status == STATUS_SYNCING &&
|
||||
mpctx->hrseek_framedrop;
|
||||
video_set_start(d_video, hrseek ? mpctx->hrseek_pts : MP_NOPTS_VALUE);
|
||||
|
||||
video_set_framedrop(d_video, check_framedrop(mpctx));
|
||||
video_set_framedrop(d_video, check_framedrop(mpctx, vo_c));
|
||||
|
||||
video_work(d_video);
|
||||
|
||||
@@ -504,7 +507,7 @@ static int video_filter(struct MPContext *mpctx, bool eof)
|
||||
// Most video filters don't work with hardware decoding, so this
|
||||
// might be the reason why filter reconfig failed.
|
||||
if (vf->initialized < 0 &&
|
||||
video_vd_control(mpctx->d_video, VDCTRL_FORCE_HWDEC_FALLBACK, NULL)
|
||||
video_vd_control(vo_c->video_src, VDCTRL_FORCE_HWDEC_FALLBACK, NULL)
|
||||
== CONTROL_OK)
|
||||
{
|
||||
// Fallback active; decoder will return software format next
|
||||
@@ -630,7 +633,7 @@ static void handle_new_frame(struct MPContext *mpctx)
|
||||
mpctx->time_frame += frame_time / mpctx->video_speed;
|
||||
adjust_sync(mpctx, pts, frame_time);
|
||||
}
|
||||
mpctx->dropped_frames_start = mpctx->d_video->dropped_frames;
|
||||
mpctx->dropped_frames_start = mpctx->vo_chain->video_src->dropped_frames;
|
||||
MP_TRACE(mpctx, "frametime=%5.3f\n", frame_time);
|
||||
}
|
||||
|
||||
@@ -689,7 +692,8 @@ 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) {
|
||||
struct track *track = mpctx->current_track[0][STREAM_VIDEO];
|
||||
if (track && track->stream && track->stream->attached_picture) {
|
||||
if (vo_has_frame(mpctx->video_out))
|
||||
return VD_EOF;
|
||||
hrseek = false;
|
||||
@@ -1123,8 +1127,8 @@ static void calculate_frame_duration(struct MPContext *mpctx)
|
||||
{
|
||||
assert(mpctx->num_past_frames >= 1 && mpctx->num_next_frames >= 1);
|
||||
|
||||
double demux_duration =
|
||||
mpctx->d_video->fps > 0 ? 1.0 / mpctx->d_video->fps : -1;
|
||||
double demux_duration = mpctx->vo_chain->container_fps > 0
|
||||
? 1.0 / mpctx->vo_chain->container_fps : -1;
|
||||
double duration = -1;
|
||||
|
||||
if (mpctx->num_next_frames >= 2) {
|
||||
@@ -1175,10 +1179,10 @@ static void calculate_frame_duration(struct MPContext *mpctx)
|
||||
void write_video(struct MPContext *mpctx, double endpts)
|
||||
{
|
||||
struct MPOpts *opts = mpctx->opts;
|
||||
struct vo *vo = mpctx->video_out;
|
||||
|
||||
if (!mpctx->d_video)
|
||||
if (!mpctx->vo_chain)
|
||||
return;
|
||||
struct vo *vo = mpctx->vo_chain->vo;
|
||||
|
||||
// Actual playback starts when both audio and video are ready.
|
||||
if (mpctx->video_status == STATUS_READY)
|
||||
|
||||
Reference in New Issue
Block a user