summaryrefslogtreecommitdiffstats
path: root/player/video.c
diff options
context:
space:
mode:
Diffstat (limited to 'player/video.c')
-rw-r--r--player/video.c228
1 files changed, 47 insertions, 181 deletions
diff --git a/player/video.c b/player/video.c
index 483043f358..48b02ecec7 100644
--- a/player/video.c
+++ b/player/video.c
@@ -39,8 +39,7 @@
#include "stream/stream.h"
#include "sub/osd.h"
#include "video/hwdec.h"
-#include "video/decode/dec_video.h"
-#include "video/decode/vd.h"
+#include "filters/f_decoder_wrapper.h"
#include "video/out/vo.h"
#include "audio/decode/dec_audio.h"
@@ -55,7 +54,6 @@ enum {
VD_PROGRESS = 1, // progress, but no output; repeat call with no waiting
VD_NEW_FRAME = 2, // the call produced a new frame
VD_WAIT = 3, // no EOF, but no output; wait until wakeup
- VD_RECONFIG = 4,
};
static const char av_desync_help_text[] =
@@ -93,17 +91,7 @@ int reinit_video_filters(struct MPContext *mpctx)
static void vo_chain_reset_state(struct vo_chain *vo_c)
{
- mp_image_unrefp(&vo_c->input_mpi);
vo_seek_reset(vo_c->vo);
-
- if (vo_c->video_src)
- video_reset(vo_c->video_src);
-
- // Prepare for continued playback after a seek.
- if (!vo_c->input_mpi && vo_c->cached_coverart)
- vo_c->input_mpi = mp_image_new_ref(vo_c->cached_coverart);
-
- vo_c->filter_src_got_eof = false;
}
void reset_video_state(struct MPContext *mpctx)
@@ -123,7 +111,6 @@ void reset_video_state(struct MPContext *mpctx)
mpctx->num_past_frames = 0;
mpctx->total_avsync_change = 0;
mpctx->last_av_difference = 0;
- mpctx->dropped_frames_start = 0;
mpctx->mistimed_frames_total = 0;
mpctx->drop_message_shown = 0;
mpctx->display_sync_drift_dir = 0;
@@ -148,16 +135,15 @@ static void vo_chain_uninit(struct vo_chain *vo_c)
if (track) {
assert(track->vo_c == vo_c);
track->vo_c = NULL;
- assert(track->d_video == vo_c->video_src);
- track->d_video = NULL;
- video_uninit(vo_c->video_src);
+ if (vo_c->dec_src)
+ assert(track->dec->f->pins[0] == vo_c->dec_src);
+ talloc_free(track->dec->f);
+ track->dec = NULL;
}
if (vo_c->filter_src)
mp_pin_disconnect(vo_c->filter_src);
- mp_image_unrefp(&vo_c->input_mpi);
- mp_image_unrefp(&vo_c->cached_coverart);
talloc_free(vo_c->filter->f);
talloc_free(vo_c);
// this does not free the VO
@@ -178,36 +164,25 @@ void uninit_video_chain(struct MPContext *mpctx)
int init_video_decoder(struct MPContext *mpctx, struct track *track)
{
- assert(!track->d_video);
+ assert(!track->dec);
if (!track->stream)
goto err_out;
- 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 = track->stream;
- d_video->codec = track->stream->codec;
- d_video->fps = d_video->header->codec->fps;
+ struct mp_filter *parent = mpctx->filter_root;
+ // If possible, set this as parent so the decoder gets the hwdec and DR
+ // interfaces.
// Note: at least mpv_opengl_cb_uninit_gl() relies on being able to get
// rid of all references to the VO by destroying the VO chain. Thus,
// decoders not linked to vo_chain must not use the hwdec context.
- if (mpctx->vo_chain) {
- d_video->hwdec_devs = mpctx->vo_chain->hwdec_devs;
- d_video->vo = mpctx->vo_chain->vo;
- }
-
- MP_VERBOSE(d_video, "Container reported FPS: %f\n", d_video->fps);
+ if (track->vo_c)
+ parent = track->vo_c->filter->f;
- if (d_video->opts->force_fps) {
- d_video->fps = d_video->opts->force_fps;
- MP_INFO(mpctx, "FPS forced to %5.3f.\n", d_video->fps);
- MP_INFO(mpctx, "Use --no-correct-pts to force FPS based timing.\n");
- }
+ track->dec = mp_decoder_wrapper_create(parent, track->stream);
+ if (!track->dec)
+ goto err_out;
- if (!video_init_best_codec(d_video))
+ if (!mp_decoder_wrapper_reinit(track->dec))
goto err_out;
return 1;
@@ -216,8 +191,6 @@ err_out:
if (track->sink)
mp_pin_disconnect(track->sink);
track->sink = NULL;
- video_uninit(track->d_video);
- track->d_video = NULL;
error_on_track(mpctx, track);
return 0;
}
@@ -232,6 +205,14 @@ void reinit_video_chain(struct MPContext *mpctx)
reinit_video_chain_src(mpctx, track);
}
+static void filter_update_subtitles(void *ctx, double pts)
+{
+ struct MPContext *mpctx = ctx;
+
+ if (osd_get_render_subs_in_filter(mpctx->osd))
+ update_subtitles(mpctx, pts);
+}
+
// (track=NULL creates a blank chain, used for lavfi-complex)
void reinit_video_chain_src(struct MPContext *mpctx, struct track *track)
{
@@ -266,8 +247,8 @@ void reinit_video_chain_src(struct MPContext *mpctx, struct track *track)
mp_output_chain_create(mpctx->filter_root, MP_OUTPUT_CHAIN_VIDEO);
vo_c->filter->container_fps = vo_c->container_fps;
mp_output_chain_set_vo(vo_c->filter, vo_c->vo);
-
- vo_c->hwdec_devs = vo_c->vo->hwdec_devs;
+ vo_c->filter->update_subtitles = filter_update_subtitles;
+ vo_c->filter->update_subtitles_ctx = mpctx;
if (track) {
vo_c->track = track;
@@ -275,12 +256,14 @@ void reinit_video_chain_src(struct MPContext *mpctx, struct track *track)
if (!init_video_decoder(mpctx, track))
goto err_out;
- vo_c->video_src = track->d_video;
- vo_c->container_fps = vo_c->video_src->fps;
+ vo_c->dec_src = track->dec->f->pins[0];
+ vo_c->container_fps = track->dec->fps;
vo_c->is_coverart = !!track->stream->attached_picture;
track->vo_c = vo_c;
vo_c->track = track;
+
+ mp_pin_connect(vo_c->filter->f->pins[0], vo_c->dec_src);
}
#if HAVE_ENCODING
@@ -328,129 +311,23 @@ void mp_force_video_refresh(struct MPContext *mpctx)
}
}
-static bool check_framedrop(struct MPContext *mpctx, struct vo_chain *vo_c)
+static void 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) &&
- vo_c->video_src)
+ vo_c->track && vo_c->track->dec && (opts->frame_dropping & 2))
{
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 =
- 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);
- }
- return false;
-}
-
-// Read a packet, store decoded image into d_video->waiting_decoded_mpi
-// returns VD_* code
-static int decode_image(struct MPContext *mpctx)
-{
- struct vo_chain *vo_c = mpctx->vo_chain;
- if (vo_c->input_mpi)
- return VD_PROGRESS;
-
- int res = DATA_EOF;
- if (vo_c->filter_src) {
- struct mp_frame frame = mp_pin_out_read(vo_c->filter_src);
- if (frame.type == MP_FRAME_EOF) {
- res = DATA_EOF;
- vo_c->filter_src_got_eof = true;
- } else if (frame.type == MP_FRAME_VIDEO) {
- res = DATA_OK;
- vo_c->input_mpi = frame.data;
- vo_c->filter_src_got_eof = false;
- } else if (frame.type) {
- MP_ERR(vo_c, "unexpected frame type\n");
- mp_frame_unref(&frame);
- res = DATA_EOF;
- } else {
- res = vo_c->filter_src_got_eof ? DATA_EOF : DATA_WAIT;
- }
- } else if (vo_c->video_src) {
- struct dec_video *d_video = vo_c->video_src;
- bool hrseek = mpctx->hrseek_active && mpctx->hrseek_framedrop &&
- mpctx->video_status == STATUS_SYNCING;
- video_set_start(d_video, hrseek ? mpctx->hrseek_pts : MP_NOPTS_VALUE);
-
- video_set_framedrop(d_video, check_framedrop(mpctx, vo_c));
-
- video_work(d_video);
- res = video_get_frame(d_video, &vo_c->input_mpi);
- }
-
- switch (res) {
- case DATA_WAIT: return VD_WAIT;
- case DATA_OK:
- case DATA_STARVE:
- case DATA_AGAIN: return VD_PROGRESS;
- case DATA_EOF: return VD_EOF;
- default: abort();
- }
-}
-
-static int video_filter(struct MPContext *mpctx, bool eof)
-{
- struct vo_chain *vo_c = mpctx->vo_chain;
-
- if (vo_c->input_mpi || eof) {
- struct mp_frame frame = {MP_FRAME_VIDEO, vo_c->input_mpi};
- if (!vo_c->input_mpi) {
- frame = MP_EOF_FRAME;
- if (vo_c->filter->got_input_eof)
- return vo_c->filter->got_output_eof ? VD_EOF : VD_WAIT;
- }
- if (mp_pin_in_needs_data(vo_c->filter->f->pins[0])) {
- if (osd_get_render_subs_in_filter(mpctx->osd))
- update_subtitles(mpctx, vo_c->input_mpi->pts);
- mp_pin_in_write(vo_c->filter->f->pins[0], frame);
- vo_c->input_mpi = NULL;
- return VD_PROGRESS;
- }
- }
-
- return VD_WAIT;
-}
-
-// Make sure at least 1 filtered image is available, decode new video if needed.
-// returns VD_* code
-// A return value of VD_PROGRESS doesn't necessarily output a frame, but makes
-// the promise that calling this function again will eventually do something.
-static int video_decode_and_filter(struct MPContext *mpctx)
-{
- struct vo_chain *vo_c = mpctx->vo_chain;
-
- int r = video_filter(mpctx, false);
- if (r < 0)
- return r;
-
- if (!vo_c->input_mpi) {
- if (vo_c->cached_coverart) {
- // Don't ever decode it twice, not even after seek resets.
- // (On seek resets, input_mpi is set to the cached image.)
- r = VD_EOF;
- } else {
- // Decode a new image, or at least feed the decoder a packet.
- r = decode_image(mpctx);
- if (r == VD_WAIT)
- return r;
- }
- }
-
- if (vo_c->input_mpi) {
- if (vo_c->is_coverart && !vo_c->cached_coverart)
- vo_c->cached_coverart = mp_image_new_ref(vo_c->input_mpi);
- } else if (r == VD_EOF) {
- r = video_filter(mpctx, true);
+ // it's a crappy heuristic; avoid getting upset by incorrect fps
+ if (fps <= 20 || fps >= 500)
+ return;
+ double frame_time = 1.0 / fps;
+ // try to drop as many frames as we appear to be behind
+ vo_c->track->dec->attempt_framedrops =
+ MPCLAMP((mpctx->last_av_difference - 0.010) / frame_time, 0, 100);
}
-
- return r;
}
/* Modify video timing to match the audio timeline. There are two main
@@ -511,9 +388,6 @@ static void handle_new_frame(struct MPContext *mpctx)
mpctx->time_frame += frame_time / mpctx->video_speed;
adjust_sync(mpctx, pts, frame_time);
}
- struct dec_video *d_video = mpctx->vo_chain->video_src;
- if (d_video)
- mpctx->dropped_frames_start = d_video->dropped_frames;
MP_TRACE(mpctx, "frametime=%5.3f\n", frame_time);
}
@@ -586,18 +460,11 @@ static int video_output_image(struct MPContext *mpctx)
int r = VD_PROGRESS;
if (needs_new_frame(mpctx)) {
// Filter a new frame.
- if (!mp_pin_out_request_data(vo_c->filter->f->pins[1])) {
- r = video_decode_and_filter(mpctx);
- if (r < 0)
- return r; // error
- }
struct mp_image *img = NULL;
struct mp_frame frame = mp_pin_out_read(vo_c->filter->f->pins[1]);
- if (frame.type == MP_FRAME_NONE && vo_c->filter->got_output_eof)
- frame = MP_EOF_FRAME;
- if (frame.type == MP_FRAME_NONE)
- return video_decode_and_filter(mpctx);
- if (frame.type == MP_FRAME_EOF) {
+ if (frame.type == MP_FRAME_NONE) {
+ r = vo_c->filter->got_output_eof ? VD_EOF : VD_WAIT;
+ } else if (frame.type == MP_FRAME_EOF) {
r = VD_EOF;
} else if (frame.type == MP_FRAME_VIDEO) {
img = frame.data;
@@ -657,11 +524,11 @@ static bool check_for_hwdec_fallback(struct MPContext *mpctx)
{
struct vo_chain *vo_c = mpctx->vo_chain;
- if (!vo_c->filter->failed_output_conversion || !vo_c->video_src)
+ if (!vo_c->filter->failed_output_conversion || !vo_c->track)
return false;
- if (video_vd_control(vo_c->video_src, VDCTRL_FORCE_HWDEC_FALLBACK, NULL)
- != CONTROL_OK)
+ if (mp_decoder_wrapper_control(vo_c->track->dec,
+ VDCTRL_FORCE_HWDEC_FALLBACK, NULL) != CONTROL_OK)
return false;
mp_output_chain_reset_harder(vo_c->filter);
@@ -1213,11 +1080,8 @@ void write_video(struct MPContext *mpctx)
// wait until VO wakes us up to get more frames
// (NB: in theory, the 1st frame after display sync mode change uses the
// wrong waiting mode)
- if (!vo_is_ready_for_frame(vo, mpctx->display_sync_active ? -1 : pts)) {
- if (video_decode_and_filter(mpctx) < 0)
- goto error;
+ if (!vo_is_ready_for_frame(vo, mpctx->display_sync_active ? -1 : pts))
return;
- }
assert(mpctx->num_next_frames >= 1);
@@ -1269,6 +1133,8 @@ void write_video(struct MPContext *mpctx)
vo_queue_frame(vo, frame);
+ check_framedrop(mpctx, vo_c);
+
// The frames were shifted down; "initialize" the new first entry.
if (mpctx->num_next_frames >= 1)
handle_new_frame(mpctx);