summaryrefslogtreecommitdiffstats
path: root/core/mplayer.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/mplayer.c')
-rw-r--r--core/mplayer.c595
1 files changed, 365 insertions, 230 deletions
diff --git a/core/mplayer.c b/core/mplayer.c
index 041b7da67b..5a9f45d280 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -94,16 +94,10 @@
#include "osdep/timer.h"
#include "core/input/input.h"
-
#include "core/encode.h"
-int slave_mode = 0;
-int enable_mouse_movements = 0;
-
#include "osdep/priority.h"
-char *heartbeat_cmd;
-
#include "stream/tv.h"
#include "stream/stream_radio.h"
#ifdef CONFIG_DVBIN
@@ -181,8 +175,7 @@ static const char av_desync_help_text[] = _(
"- Slow video output.\n"
" Try a different -vo driver (-vo help for a list) or try -framedrop!\n"
"- Playing a video file with --vo=opengl with higher FPS than the monitor.\n"
-" This is due to vsync limiting the framerate. Try --no-vsync, or a\n"
-" different VO.\n"
+" This is due to vsync limiting the framerate.\n"
"- Playing from a slow network source.\n"
" Download the file instead.\n"
"- Try to find out whether audio or video is causing this by experimenting\n"
@@ -194,36 +187,11 @@ static const char av_desync_help_text[] = _(
//**************************************************************************//
#include "core/mp_fifo.h"
-
-static int drop_frame_cnt; // total number of dropped frames
-
-// seek:
-static int64_t seek_to_byte;
-static double step_sec;
-
-// this dvdsub_id was selected via slang
-// use this to allow dvdnav to follow -slang across stream resets,
-// in particular the subtitle ID for a language changes
-int dvdsub_lang_id;
-int forced_subs_only = 0;
-
-// A-V sync:
-static float default_max_pts_correction = -1;
-float audio_delay = 0;
-static int ignore_start = 0;
-
-double force_fps = 0;
-static int force_srate = 0;
-static int play_n_frames = -1;
-static int play_n_frames_mf = -1;
-
#include "sub/ass_mp.h"
// ---
-int use_filedir_conf;
-
#include "core/mp_common.h"
#include "core/command.h"
@@ -307,10 +275,10 @@ static void print_stream(struct MPContext *mpctx, struct track *t, int id)
if (t->title)
mp_msg(MSGT_CPLAYER, MSGL_INFO, " '%s'", t->title);
const char *codec = s ? s->codec : NULL;
- if (s && t->type == STREAM_SUB)
- codec = sh_sub_type2str(s->sub->type);
- if (t->sh_sub) // external subs hack
- codec = sh_sub_type2str(t->sh_sub->type);
+ if (!codec && t->sh_sub) // external subs hack
+ codec = t->sh_sub->gsh->codec;
+ if (!codec && t->subdata)
+ codec = t->subdata->codec;
mp_msg(MSGT_CPLAYER, MSGL_INFO, " (%s)", codec ? codec : "<unknown>");
if (t->is_external)
mp_msg(MSGT_CPLAYER, MSGL_INFO, " (external)");
@@ -399,9 +367,6 @@ static void print_file_properties(struct MPContext *mpctx, const char *filename)
}
}
-/// step size of mixer changes
-int volstep = 3;
-
// Time used to seek external tracks to.
static double get_main_demux_pts(struct MPContext *mpctx)
{
@@ -440,7 +405,7 @@ static void init_demux_stream(struct MPContext *mpctx, enum stream_type type)
demuxer_switch_track(stream->demuxer, type, stream);
if (track->is_external) {
double pts = get_main_demux_pts(mpctx);
- demux_seek(stream->demuxer, pts, audio_delay, SEEK_ABSOLUTE);
+ demux_seek(stream->demuxer, pts, mpctx->audio_delay, SEEK_ABSOLUTE);
}
}
}
@@ -484,6 +449,8 @@ static void uninit_subs(struct demuxer *demuxer)
void uninit_player(struct MPContext *mpctx, unsigned int mask)
{
+ struct MPOpts *opts = &mpctx->opts;
+
mask &= mpctx->initialized_flags;
mp_msg(MSGT_CPLAYER, MSGL_DBG2, "\n*** uninit(0x%X)\n", mask);
@@ -500,7 +467,7 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask)
mpctx->initialized_flags &= ~INITIALIZED_SUB;
struct track *track = mpctx->current_track[STREAM_SUB];
// One of these was active; they can't be both active.
- assert(!(mpctx->sh_sub && (track && track->sh_sub)));
+ assert(!(mpctx->sh_sub && track && track->sh_sub));
if (mpctx->sh_sub)
sub_switchoff(mpctx->sh_sub, mpctx->osd);
if (track && track->sh_sub)
@@ -576,8 +543,15 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask)
if (mask & INITIALIZED_AO) {
mpctx->initialized_flags &= ~INITIALIZED_AO;
- if (mpctx->mixer.ao)
+ if (mpctx->mixer.ao) {
+ // Normally the mixer remembers volume, but do it even if the
+ // volume is set explicitly with --volume=...
+ if (opts->mixer_init_volume >= 0 && mpctx->mixer.user_set_volume)
+ mixer_getbothvolume(&mpctx->mixer, &opts->mixer_init_volume);
+ if (opts->mixer_init_mute >= 0 && mpctx->mixer.user_set_mute)
+ opts->mixer_init_mute = mixer_getmute(&mpctx->mixer);
mixer_uninit(&mpctx->mixer);
+ }
if (mpctx->ao)
ao_uninit(mpctx->ao, mpctx->stop_play != AT_END_OF_FILE);
mpctx->ao = NULL;
@@ -752,7 +726,8 @@ static int try_load_config(m_config_t *conf, const char *file)
return 1;
}
-static void load_per_file_config(m_config_t *conf, const char * const file)
+static void load_per_file_config(m_config_t *conf, const char * const file,
+ bool search_file_dir)
{
char *confpath;
char cfg[MP_PATH_MAX];
@@ -766,7 +741,7 @@ static void load_per_file_config(m_config_t *conf, const char * const file)
sprintf(cfg, "%s.conf", file);
name = mp_basename(cfg);
- if (use_filedir_conf) {
+ if (search_file_dir) {
char dircfg[MP_PATH_MAX];
strcpy(dircfg, cfg);
strcpy(dircfg + (name - cfg), "mpv.conf");
@@ -935,16 +910,21 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename,
struct ass_track *asst = mp_ass_read_stream(mpctx->ass_library,
filename, sub_cp);
bool is_native_ass = asst;
+ const char *codec = NULL;
if (!asst) {
subd = sub_read_file(filename, fps, &mpctx->opts);
if (subd) {
+ codec = subd->codec;
asst = mp_ass_read_subdata(mpctx->ass_library, opts, subd, fps);
talloc_free(subd);
subd = NULL;
}
}
- if (asst)
+ if (asst) {
sh = sd_ass_create_from_track(asst, is_native_ass, opts);
+ if (codec)
+ sh->gsh->codec = codec;
+ }
#endif
} else
subd = sub_read_file(filename, fps, &mpctx->opts);
@@ -1002,8 +982,8 @@ void init_vo_spudec(struct MPContext *mpctx)
if (vo_spudec != NULL) {
mpctx->initialized_flags |= INITIALIZED_SPUDEC;
- mp_property_do("sub-forced-only", M_PROPERTY_SET, &forced_subs_only,
- mpctx);
+ mp_property_do("sub-forced-only", M_PROPERTY_SET,
+ &mpctx->opts.forced_subs_only, mpctx);
}
}
@@ -1085,7 +1065,7 @@ static void print_status(struct MPContext *mpctx)
char *line = NULL;
// Playback status
- if (mpctx->paused_for_cache) {
+ if (mpctx->paused_for_cache && !opts->pause) {
saddf(&line, "(Buffering) ");
} else if (mpctx->paused) {
saddf(&line, "(Paused) ");
@@ -1131,21 +1111,21 @@ static void print_status(struct MPContext *mpctx)
if (endpos != -1)
position = max(position, (get_current_time(mpctx) - startpos)
/ (endpos - startpos));
- if (play_n_frames_mf)
+ if (opts->play_frames > 0)
position = max(position,
- 1.0 - play_n_frames / (double) play_n_frames_mf);
+ 1.0 - mpctx->max_frames / (double) opts->play_frames);
char lavcbuf[80];
if (encode_lavc_getstatus(mpctx->encode_lavc_ctx, lavcbuf, sizeof(lavcbuf),
position, get_current_time(mpctx) - startpos) >= 0)
{
// encoding stats
- saddf(&line, "%s ", lavcbuf);
+ saddf(&line, " %s", lavcbuf);
} else
#endif
{
// VO stats
- if (sh_video && drop_frame_cnt)
- saddf(&line, " D: %d", drop_frame_cnt);
+ if (sh_video && mpctx->drop_frame_cnt)
+ saddf(&line, " D: %d", mpctx->drop_frame_cnt);
}
int cache = mp_get_cache_percent(mpctx);
@@ -1360,7 +1340,8 @@ void set_osd_bar(struct MPContext *mpctx, int type, const char *name,
if (mpctx->sh_video && opts->term_osd != 1) {
mpctx->osd_visible = (GetTimerMS() + opts->osd_duration) | 1;
mpctx->osd->progbar_type = type;
- mpctx->osd->progbar_value = 256 * (val - min) / (max - min);
+ mpctx->osd->progbar_value = (val - min) / (max - min);
+ mpctx->osd->progbar_num_stops = 0;
vo_osd_changed(OSDTYPE_PROGBAR);
return;
}
@@ -1375,7 +1356,7 @@ static void update_osd_bar(struct MPContext *mpctx, int type,
double min, double max, double val)
{
if (mpctx->osd->progbar_type == type) {
- int new_value = 256 * (val - min) / (max - min);
+ float new_value = (val - min) / (max - min);
if (new_value != mpctx->osd->progbar_value) {
mpctx->osd->progbar_value = new_value;
vo_osd_changed(OSDTYPE_PROGBAR);
@@ -1383,6 +1364,26 @@ static void update_osd_bar(struct MPContext *mpctx, int type,
}
}
+static void set_osd_bar_chapters(struct MPContext *mpctx, int type)
+{
+ struct osd_state *osd = mpctx->osd;
+ osd->progbar_num_stops = 0;
+ if (osd->progbar_type == type) {
+ double len = get_time_length(mpctx);
+ if (len > 0) {
+ int num = get_chapter_count(mpctx);
+ for (int n = 0; n < num; n++) {
+ double time = chapter_start_time(mpctx, n);
+ if (time >= 0) {
+ float pos = time / len;
+ MP_TARRAY_APPEND(osd, osd->progbar_stops,
+ osd->progbar_num_stops, pos);
+ }
+ }
+ }
+ }
+}
+
void set_osd_function(struct MPContext *mpctx, int osd_function)
{
struct MPOpts *opts = &mpctx->opts;
@@ -1428,7 +1429,7 @@ static void sadd_osd_status(char **buffer, struct MPContext *mpctx, bool full)
bool fractions = mpctx->opts.osd_fractions;
int sym = mpctx->osd_function;
if (!sym) {
- if (mpctx->paused_for_cache) {
+ if (mpctx->paused_for_cache && !mpctx->opts.pause) {
sym = OSD_CLOCK;
} else if (mpctx->paused || mpctx->step_frames) {
sym = OSD_PAUSE;
@@ -1462,6 +1463,7 @@ static void add_seek_osd_messages(struct MPContext *mpctx)
if (mpctx->add_osd_seek_info & OSD_SEEK_INFO_BAR) {
set_osd_bar(mpctx, OSD_BAR_SEEK, "Position", 0, 1,
av_clipf(get_current_pos_ratio(mpctx), 0, 1));
+ set_osd_bar_chapters(mpctx, OSD_BAR_SEEK);
}
if (mpctx->add_osd_seek_info & OSD_SEEK_INFO_TEXT) {
mp_osd_msg_t *msg = add_osd_msg(mpctx, OSD_MSG_TEXT, 1,
@@ -1563,7 +1565,7 @@ void reinit_audio_chain(struct MPContext *mpctx)
if (!(mpctx->initialized_flags & INITIALIZED_AO)) {
mpctx->initialized_flags |= INITIALIZED_AO;
mpctx->ao = ao_create(opts, mpctx->input);
- mpctx->ao->samplerate = force_srate;
+ mpctx->ao->samplerate = opts->force_srate;
mpctx->ao->format = opts->audio_output_format;
}
ao = mpctx->ao;
@@ -1607,7 +1609,7 @@ void reinit_audio_chain(struct MPContext *mpctx)
"Couldn't find matching filter/ao format!\n");
goto init_error;
}
- mpctx->mixer.volstep = volstep;
+ mpctx->mixer.volstep = opts->volstep;
mpctx->mixer.softvol = opts->softvol;
mpctx->mixer.softvol_max = opts->softvol_max;
mixer_reinit(&mpctx->mixer, ao);
@@ -1727,7 +1729,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl)
struct demux_stream *d_sub = sh_sub ? sh_sub->ds : NULL;
unsigned char *packet = NULL;
int len;
- int type = sh_sub ? sh_sub->type : '\0';
+ const char *type = sh_sub ? sh_sub->gsh->codec : NULL;
mpctx->osd->sub_offset = mpctx->video_offset;
@@ -1750,7 +1752,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl)
}
// DVD sub:
- if (type == 'v' && !(sh_sub && sh_sub->active)) {
+ if (is_dvd_sub(type) && !(sh_sub && sh_sub->active)) {
int timestamp;
// Get a sub packet from the demuxer (or the vobsub.c thing, which
// should be a demuxer, but isn't).
@@ -1811,7 +1813,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl)
mp_dbg(MSGT_CPLAYER, MSGL_V, "Sub: c_pts=%5.3f s_pts=%5.3f "
"duration=%5.3f len=%d\n", curpts_s, subpts_s, duration,
len);
- if (type == 'm') {
+ if (type && strcmp(type, "mov_text") == 0) {
if (len < 2)
continue;
len = FFMIN(len - 2, AV_RB16(packet));
@@ -1823,7 +1825,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl)
// text sub
if (duration < 0)
sub_clear_text(&mpctx->subs, MP_NOPTS_VALUE);
- if (type == 'a') { // ssa/ass subs without libass => convert to plaintext
+ if (is_ass_sub(type)) { // ssa/ass subs without libass => convert to plaintext
int i;
unsigned char *p = packet;
for (i = 0; i < 8 && *p != '\0'; p++)
@@ -1859,18 +1861,17 @@ static int check_framedrop(struct MPContext *mpctx, double frame_time)
struct MPOpts *opts = &mpctx->opts;
// check for frame-drop:
if (mpctx->sh_audio && !mpctx->ao->untimed && !mpctx->sh_audio->ds->eof) {
- static int dropped_frames;
float delay = opts->playback_speed * ao_get_delay(mpctx->ao);
float d = delay - mpctx->delay;
// we should avoid dropping too many frames in sequence unless we
// are too late. and we allow 100ms A-V delay here:
- if (d < -dropped_frames * frame_time - 0.100 && !mpctx->paused
+ if (d < -mpctx->dropped_frames * frame_time - 0.100 && !mpctx->paused
&& !mpctx->restart_playback) {
- ++drop_frame_cnt;
- ++dropped_frames;
+ mpctx->drop_frame_cnt++;
+ mpctx->dropped_frames++;
return mpctx->opts.frame_dropping;
} else
- dropped_frames = 0;
+ mpctx->dropped_frames = 0;
}
return 0;
}
@@ -1981,7 +1982,7 @@ static void reinit_subs(struct MPContext *mpctx)
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 40, 0)
broken_lavc = true;
#endif
- if (mpctx->sh_sub->type == 'v' && track->demuxer
+ if (is_dvd_sub(mpctx->sh_sub->gsh->codec) && track->demuxer
&& (track->demuxer->type == DEMUXER_TYPE_MPEG_PS || broken_lavc))
init_vo_spudec(mpctx);
else
@@ -2091,6 +2092,8 @@ bool mp_remove_track(struct MPContext *mpctx, struct track *track)
*/
static void adjust_sync(struct MPContext *mpctx, double frame_time)
{
+ struct MPOpts *opts = &mpctx->opts;
+
if (!mpctx->sh_audio || mpctx->syncing_audio)
return;
@@ -2099,11 +2102,11 @@ static void adjust_sync(struct MPContext *mpctx, double frame_time)
double av_delay = a_pts - v_pts;
// Try to sync vo_flip() so it will *finish* at given time
av_delay += mpctx->last_vo_flip_duration;
- av_delay -= audio_delay; // This much pts difference is desired
+ av_delay -= mpctx->audio_delay; // This much pts difference is desired
double change = av_delay * 0.1;
- double max_change = default_max_pts_correction >= 0 ?
- default_max_pts_correction : frame_time * 0.1;
+ double max_change = opts->default_max_pts_correction >= 0 ?
+ opts->default_max_pts_correction : frame_time * 0.1;
if (change < -max_change)
change = -max_change;
else if (change > max_change)
@@ -2157,7 +2160,7 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
ptsdiff = written_pts - mpctx->hrseek_pts;
else
ptsdiff = written_pts - mpctx->sh_video->pts - mpctx->delay
- - audio_delay;
+ - mpctx->audio_delay;
bytes = ptsdiff * bps;
bytes -= bytes % (ao->channels * af_fmt2bits(ao->format) / 8);
@@ -2248,6 +2251,7 @@ static int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
res = audio_start_sync(mpctx, playsize);
else
res = decode_audio(sh_audio, &ao->buffer, playsize);
+
if (res < 0) { // EOF, error or format change
if (res == -2) {
/* The format change isn't handled too gracefully. A more precise
@@ -2265,7 +2269,7 @@ static int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
}
if (endpts != MP_NOPTS_VALUE && modifiable_audio_format) {
- double bytes = (endpts - written_audio_pts(mpctx) + audio_delay)
+ double bytes = (endpts - written_audio_pts(mpctx) + mpctx->audio_delay)
* ao->bps / opts->playback_speed;
if (playsize > bytes) {
playsize = FFMAX(bytes, 0);
@@ -2343,13 +2347,13 @@ int reinit_video_chain(struct MPContext *mpctx)
mpctx->master_demuxer->file_format, mpctx->sh_video->format,
mpctx->sh_video->disp_w, mpctx->sh_video->disp_h,
mpctx->sh_video->fps, mpctx->sh_video->frametime);
- if (force_fps) {
- mpctx->sh_video->fps = force_fps;
+ if (opts->force_fps) {
+ mpctx->sh_video->fps = opts->force_fps;
mpctx->sh_video->frametime = 1.0f / mpctx->sh_video->fps;
}
update_fps(mpctx);
- if (!mpctx->sh_video->fps && !force_fps && !opts->correct_pts) {
+ if (!mpctx->sh_video->fps && !opts->force_fps && !opts->correct_pts) {
mp_tmsg(MSGT_CPLAYER, MSGL_ERR, "FPS not specified in the "
"header or invalid, use the -fps option.\n");
}
@@ -2400,6 +2404,7 @@ int reinit_video_chain(struct MPContext *mpctx)
sh_video->next_frame_time = 0;
mpctx->restart_playback = true;
mpctx->delay = 0;
+ mpctx->vo_pts_history_seek_ts++;
// ========== Init display (sh_video->disp_w*sh_video->disp_h/out_fmt) ============
@@ -2415,14 +2420,48 @@ no_video:
return 0;
}
+static void add_frame_pts(struct MPContext *mpctx, double pts)
+{
+ if (pts == MP_NOPTS_VALUE || mpctx->hrseek_framedrop) {
+ mpctx->vo_pts_history_seek_ts++; // mark discontinuity
+ return;
+ }
+ for (int n = MAX_NUM_VO_PTS - 1; n >= 1; n--) {
+ mpctx->vo_pts_history_seek[n] = mpctx->vo_pts_history_seek[n - 1];
+ mpctx->vo_pts_history_pts[n] = mpctx->vo_pts_history_pts[n - 1];
+ }
+ mpctx->vo_pts_history_seek[0] = mpctx->vo_pts_history_seek_ts;
+ mpctx->vo_pts_history_pts[0] = pts;
+}
+
+static double find_previous_pts(struct MPContext *mpctx, double pts)
+{
+ for (int n = 0; n < MAX_NUM_VO_PTS - 1; n++) {
+ if (pts == mpctx->vo_pts_history_pts[n] &&
+ mpctx->vo_pts_history_seek[n] != 0 &&
+ mpctx->vo_pts_history_seek[n] == mpctx->vo_pts_history_seek[n + 1])
+ {
+ return mpctx->vo_pts_history_pts[n + 1];
+ }
+ }
+ return MP_NOPTS_VALUE;
+}
+
+static double get_last_frame_pts(struct MPContext *mpctx)
+{
+ if (mpctx->vo_pts_history_seek[0] == mpctx->vo_pts_history_seek_ts)
+ return mpctx->vo_pts_history_pts[0];
+ return MP_NOPTS_VALUE;
+}
+
static bool filter_output_queued_frame(struct MPContext *mpctx)
{
struct sh_video *sh_video = mpctx->sh_video;
struct vo *video_out = mpctx->video_out;
struct mp_image *img = vf_chain_output_queued_frame(sh_video->vfilter);
- if (img && video_out->config_ok)
- vo_draw_image(video_out, img);
+ if (img)
+ vo_queue_image(video_out, img);
talloc_free(img);
return !!img;
@@ -2455,19 +2494,22 @@ static double update_video_nocorrect_pts(struct MPContext *mpctx)
int in_size = 0;
while (!in_size)
in_size = video_read_frame(sh_video, &sh_video->next_frame_time,
- &packet, force_fps);
+ &packet, mpctx->opts.force_fps);
if (in_size < 0)
return -1;
- sh_video->timer += frame_time;
if (mpctx->sh_audio)
mpctx->delay -= frame_time;
// video_read_frame can change fps (e.g. for ASF video)
update_fps(mpctx);
int framedrop_type = check_framedrop(mpctx, frame_time);
- void *decoded_frame;
- decoded_frame = decode_video(sh_video, sh_video->ds->current, packet,
- in_size, framedrop_type, sh_video->pts);
+ struct demux_packet pkt = {0};
+ if (sh_video->ds->current)
+ pkt = *sh_video->ds->current;
+ pkt.buffer = packet;
+ pkt.len = in_size;
+ void *decoded_frame = decode_video(sh_video, &pkt, framedrop_type,
+ sh_video->pts);
if (decoded_frame) {
filter_video(mpctx, decoded_frame);
}
@@ -2507,7 +2549,7 @@ static void determine_frame_pts(struct MPContext *mpctx)
sh_video->codec_reordered_pts : sh_video->sorted_pts;
}
-static double update_video(struct MPContext *mpctx)
+static double update_video(struct MPContext *mpctx, double endpts)
{
struct sh_video *sh_video = mpctx->sh_video;
struct vo *video_out = mpctx->video_out;
@@ -2523,8 +2565,6 @@ static double update_video(struct MPContext *mpctx)
break;
if (filter_output_queued_frame(mpctx))
break;
- int in_size = 0;
- unsigned char *buf = NULL;
pts = MP_NOPTS_VALUE;
struct demux_packet *pkt;
while (1) {
@@ -2535,19 +2575,16 @@ static double update_video(struct MPContext *mpctx)
* but to indicate the absence of a frame in formats like AVI
* that must have packets at fixed timecode intervals. */
}
- if (pkt) {
- in_size = pkt->len;
- buf = pkt->buffer;
+ if (pkt)
pts = pkt->pts;
- }
if (pts != MP_NOPTS_VALUE)
pts += mpctx->video_offset;
if (pts >= mpctx->hrseek_pts - .005)
mpctx->hrseek_framedrop = false;
- int framedrop_type = mpctx->hrseek_framedrop ? 1 :
- check_framedrop(mpctx, sh_video->frametime);
+ int framedrop_type = mpctx->hrseek_active && mpctx->hrseek_framedrop ?
+ 1 : check_framedrop(mpctx, sh_video->frametime);
struct mp_image *decoded_frame =
- decode_video(sh_video, pkt, buf, in_size, framedrop_type, pts);
+ decode_video(sh_video, pkt, framedrop_type, pts);
if (decoded_frame) {
determine_frame_pts(mpctx);
filter_video(mpctx, decoded_frame);
@@ -2569,6 +2606,8 @@ static double update_video(struct MPContext *mpctx)
if (pts == MP_NOPTS_VALUE)
pts = sh_video->last_pts;
}
+ if (endpts == MP_NOPTS_VALUE || pts < endpts)
+ add_frame_pts(mpctx, pts);
if (mpctx->hrseek_active && pts < mpctx->hrseek_pts - .005) {
vo_skip_frame(video_out);
return 0;
@@ -2592,7 +2631,6 @@ static double update_video(struct MPContext *mpctx)
}
double frame_time = sh_video->pts - sh_video->last_pts;
sh_video->last_pts = sh_video->pts;
- sh_video->timer += frame_time;
if (mpctx->sh_audio)
mpctx->delay -= frame_time;
return frame_time;
@@ -2600,12 +2638,15 @@ static double update_video(struct MPContext *mpctx)
void pause_player(struct MPContext *mpctx)
{
+ mpctx->opts.pause = 1;
+
if (mpctx->paused)
return;
- mpctx->paused = 1;
+ mpctx->paused = true;
mpctx->step_frames = 0;
mpctx->time_frame -= get_relative_time(mpctx);
mpctx->osd_function = 0;
+ mpctx->paused_for_cache = false;
if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok)
vo_control(mpctx->video_out, VOCTRL_PAUSE, NULL);
@@ -2623,11 +2664,15 @@ void pause_player(struct MPContext *mpctx)
void unpause_player(struct MPContext *mpctx)
{
+ mpctx->opts.pause = 0;
+
if (!mpctx->paused)
return;
- mpctx->paused = 0;
+ // Don't actually unpause while cache is loading.
+ if (mpctx->paused_for_cache)
+ return;
+ mpctx->paused = false;
mpctx->osd_function = 0;
- mpctx->paused_for_cache = false;
if (mpctx->ao && mpctx->sh_audio)
ao_resume(mpctx->ao);
@@ -2657,23 +2702,29 @@ static bool redraw_osd(struct MPContext *mpctx)
return true;
}
-void add_step_frame(struct MPContext *mpctx)
+void add_step_frame(struct MPContext *mpctx, int dir)
{
- mpctx->step_frames++;
- if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok)
- vo_control(mpctx->video_out, VOCTRL_PAUSE, NULL);
- unpause_player(mpctx);
+ if (dir > 0) {
+ mpctx->step_frames += 1;
+ if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok)
+ vo_control(mpctx->video_out, VOCTRL_PAUSE, NULL);
+ unpause_player(mpctx);
+ } else if (dir < 0) {
+ if (!mpctx->backstep_active && !mpctx->hrseek_active) {
+ mpctx->backstep_active = true;
+ mpctx->backstep_start_seek_ts = mpctx->vo_pts_history_seek_ts;
+ pause_player(mpctx);
+ }
+ }
}
static void seek_reset(struct MPContext *mpctx, bool reset_ao, bool reset_ac)
{
if (mpctx->sh_video) {
resync_video_stream(mpctx->sh_video);
- mpctx->sh_video->timer = 0;
vo_seek_reset(mpctx->video_out);
if (mpctx->sh_video->vf_initialized == 1)
vf_chain_seek_reset(mpctx->sh_video->vfilter);
- mpctx->sh_video->timer = 0;
mpctx->sh_video->num_buffered_pts = 0;
mpctx->sh_video->last_pts = MP_NOPTS_VALUE;
mpctx->delay = 0;
@@ -2699,8 +2750,9 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao, bool reset_ac)
mpctx->hrseek_active = false;
mpctx->hrseek_framedrop = false;
mpctx->total_avsync_change = 0;
- mpctx->step_frames = 0;
- drop_frame_cnt = 0;
+ mpctx->drop_frame_cnt = 0;
+ mpctx->dropped_frames = 0;
+ mpctx->playback_pts = MP_NOPTS_VALUE;
#ifdef CONFIG_ENCODING
encode_lavc_discontinuity(mpctx->encode_lavc_ctx);
@@ -2763,6 +2815,7 @@ static int seek(MPContext *mpctx, struct seek_params seek,
bool timeline_fallthrough)
{
struct MPOpts *opts = &mpctx->opts;
+ uint64_t prev_seek_ts = mpctx->vo_pts_history_seek_ts;
if (!mpctx->demuxer)
return -1;
@@ -2771,12 +2824,10 @@ static int seek(MPContext *mpctx, struct seek_params seek,
mpctx->stop_play = KEEP_PLAYING;
bool hr_seek = mpctx->demuxer->accurate_seek && opts->correct_pts;
hr_seek &= seek.exact >= 0 && seek.type != MPSEEK_FACTOR;
- hr_seek &= opts->hr_seek == 0 && seek.type == MPSEEK_ABSOLUTE
- || opts->hr_seek > 0 || seek.exact > 0;
- if (seek.type == MPSEEK_FACTOR
- || seek.type == MPSEEK_ABSOLUTE
- && seek.amount < mpctx->last_chapter_pts
- || seek.amount < 0)
+ hr_seek &= (opts->hr_seek == 0 && seek.type == MPSEEK_ABSOLUTE) ||
+ opts->hr_seek > 0 || seek.exact > 0;
+ if (seek.type == MPSEEK_FACTOR || seek.amount < 0 ||
+ (seek.type == MPSEEK_ABSOLUTE && seek.amount < mpctx->last_chapter_pts))
mpctx->last_chapter_seek = -2;
if (seek.type == MPSEEK_FACTOR) {
double len = get_time_length(mpctx);
@@ -2829,11 +2880,13 @@ static int seek(MPContext *mpctx, struct seek_params seek,
demuxer_style |= SEEK_BACKWARD;
else if (seek.direction > 0)
demuxer_style |= SEEK_FORWARD;
+ if (hr_seek || opts->mkv_subtitle_preroll)
+ demuxer_style |= SEEK_SUBPREROLL;
if (hr_seek)
demuxer_amount -= opts->hr_seek_demuxer_offset;
- int seekresult = demux_seek(mpctx->demuxer, demuxer_amount, audio_delay,
- demuxer_style);
+ int seekresult = demux_seek(mpctx->demuxer, demuxer_amount,
+ mpctx->audio_delay, demuxer_style);
if (seekresult == 0) {
if (need_reset) {
reinit_audio_chain(mpctx);
@@ -2858,7 +2911,7 @@ static int seek(MPContext *mpctx, struct seek_params seek,
for (int type = 0; type < STREAM_TYPE_COUNT; type++) {
struct track *track = mpctx->current_track[type];
if (track && track->is_external && track->demuxer)
- demux_seek(track->demuxer, main_new_pos, audio_delay,
+ demux_seek(track->demuxer, main_new_pos, mpctx->audio_delay,
SEEK_ABSOLUTE);
}
}
@@ -2869,6 +2922,14 @@ static int seek(MPContext *mpctx, struct seek_params seek,
* and resetting could lose audio some decoders produce during init. */
seek_reset(mpctx, !timeline_fallthrough, !need_reset);
+ if (timeline_fallthrough) {
+ // Important if video reinit happens.
+ mpctx->vo_pts_history_seek_ts = prev_seek_ts;
+ } else {
+ mpctx->vo_pts_history_seek_ts++;
+ mpctx->backstep_active = false;
+ }
+
/* Use the target time as "current position" for further relative
* seeks etc until a new video frame has been decoded */
if (seek.type == MPSEEK_ABSOLUTE) {
@@ -2969,16 +3030,8 @@ double get_current_time(struct MPContext *mpctx)
return 0;
if (demuxer->stream_pts != MP_NOPTS_VALUE)
return demuxer->stream_pts;
- if (!mpctx->restart_playback) {
- double apts = playing_audio_pts(mpctx);
- if (apts != MP_NOPTS_VALUE)
- return apts;
- if (mpctx->sh_video) {
- double pts = mpctx->video_pts;
- if (pts != MP_NOPTS_VALUE)
- return pts;
- }
- }
+ if (mpctx->playback_pts != MP_NOPTS_VALUE)
+ return mpctx->playback_pts;
if (mpctx->last_seek_pts != MP_NOPTS_VALUE)
return mpctx->last_seek_pts;
return 0;
@@ -3127,13 +3180,13 @@ static void update_avsync(struct MPContext *mpctx)
double a_pos = playing_audio_pts(mpctx);
- mpctx->last_av_difference = a_pos - mpctx->video_pts - audio_delay;
+ mpctx->last_av_difference = a_pos - mpctx->video_pts - mpctx->audio_delay;
if (mpctx->time_frame > 0)
mpctx->last_av_difference +=
mpctx->time_frame * mpctx->opts.playback_speed;
if (a_pos == MP_NOPTS_VALUE || mpctx->video_pts == MP_NOPTS_VALUE)
mpctx->last_av_difference = MP_NOPTS_VALUE;
- if (mpctx->last_av_difference > 0.5 && drop_frame_cnt > 50
+ if (mpctx->last_av_difference > 0.5 && mpctx->drop_frame_cnt > 50
&& !mpctx->drop_message_shown) {
mp_tmsg(MSGT_AVSYNC, MSGL_WARN, "%s", mp_gtext(av_desync_help_text));
mpctx->drop_message_shown = true;
@@ -3146,12 +3199,17 @@ static void handle_pause_on_low_cache(struct MPContext *mpctx)
int cache = mp_get_cache_percent(mpctx);
bool idle = mp_get_cache_idle(mpctx);
if (mpctx->paused && mpctx->paused_for_cache) {
- if (cache < 0 || cache >= opts->stream_cache_min_percent || idle)
- unpause_player(mpctx);
- } else if (!mpctx->paused) {
+ if (cache < 0 || cache >= opts->stream_cache_min_percent || idle) {
+ mpctx->paused_for_cache = false;
+ if (!opts->pause)
+ unpause_player(mpctx);
+ }
+ } else {
if (cache >= 0 && cache <= opts->stream_cache_pause && !idle) {
+ bool prev_paused_user = opts->pause;
pause_player(mpctx);
mpctx->paused_for_cache = true;
+ opts->pause = prev_paused_user;
}
}
}
@@ -3187,7 +3245,7 @@ static void run_playloop(struct MPContext *mpctx)
bool end_is_chapter = false;
double sleeptime = get_wakeup_period(mpctx);
bool was_restart = mpctx->restart_playback;
- bool new_video_frame_shown = false;
+ bool new_frame_shown = false;
#ifdef CONFIG_ENCODING
if (encode_lavc_didfail(mpctx->encode_lavc_ctx)) {
@@ -3228,7 +3286,7 @@ static void run_playloop(struct MPContext *mpctx)
video_left = vo->hasframe || vo->frame_loaded;
if (!vo->frame_loaded && (!mpctx->paused || mpctx->restart_playback)) {
- double frame_time = update_video(mpctx);
+ double frame_time = update_video(mpctx, endpts);
mp_dbg(MSGT_AVSYNC, MSGL_DBG2, "*** ftime=%5.3f ***\n", frame_time);
if (mpctx->sh_video->vf_initialized < 0) {
mp_tmsg(MSGT_CPLAYER, MSGL_FATAL,
@@ -3258,12 +3316,13 @@ static void run_playloop(struct MPContext *mpctx)
// ================================================================
vo_check_events(vo);
- if (heartbeat_cmd) {
- static unsigned last_heartbeat;
+ if (opts->heartbeat_cmd) {
unsigned now = GetTimerMS();
- if (now - last_heartbeat > 30000) {
- last_heartbeat = now;
- system(heartbeat_cmd);
+ if (now - mpctx->last_heartbeat >
+ (unsigned)(opts->heartbeat_interval * 1000))
+ {
+ mpctx->last_heartbeat = now;
+ system(opts->heartbeat_cmd);
}
}
@@ -3320,6 +3379,7 @@ static void run_playloop(struct MPContext *mpctx)
struct sh_video *sh_video = mpctx->sh_video;
mpctx->video_pts = sh_video->pts;
mpctx->last_vo_pts = mpctx->video_pts;
+ mpctx->playback_pts = mpctx->video_pts;
update_subtitles(mpctx, sh_video->pts);
update_osd_msg(mpctx);
draw_osd(mpctx);
@@ -3371,25 +3431,11 @@ static void run_playloop(struct MPContext *mpctx)
update_avsync(mpctx);
print_status(mpctx);
screenshot_flip(mpctx);
- new_video_frame_shown = true;
+ new_frame_shown = true;
- if (play_n_frames >= 0) {
- --play_n_frames;
- if (play_n_frames <= 0)
- mpctx->stop_play = PT_NEXT_ENTRY;
- }
break;
} // video
- if (mpctx->step_frames > 0 && !mpctx->paused) {
- // If no more video is available, one frame means one playloop iteration.
- // Otherwise, one frame means one video frame.
- if (!video_left || new_video_frame_shown)
- mpctx->step_frames--;
- if (mpctx->step_frames == 0)
- pause_player(mpctx);
- }
-
if (mpctx->sh_audio && (mpctx->restart_playback ? !video_left :
mpctx->ao->untimed && (mpctx->delay <= 0 ||
!video_left))) {
@@ -3415,6 +3461,7 @@ static void run_playloop(struct MPContext *mpctx)
a_pos = (written_audio_pts(mpctx) -
mpctx->opts.playback_speed * buffered_audio);
}
+ mpctx->playback_pts = a_pos;
print_status(mpctx);
if (!mpctx->sh_video)
@@ -3447,7 +3494,40 @@ static void run_playloop(struct MPContext *mpctx)
}, true);
} else
mpctx->stop_play = AT_END_OF_FILE;
- } else if (!mpctx->stop_play) {
+ sleeptime = 0;
+ }
+
+ if (!mpctx->stop_play && !mpctx->restart_playback) {
+
+ // If no more video is available, one frame means one playloop iteration.
+ // Otherwise, one frame means one video frame.
+ if (!video_left)
+ new_frame_shown = true;
+
+ if (opts->playing_msg && !mpctx->playing_msg_shown && new_frame_shown) {
+ mpctx->playing_msg_shown = true;
+ char *msg = mp_property_expand_string(mpctx, opts->playing_msg);
+ mp_msg(MSGT_CPLAYER, MSGL_INFO, "%s\n", msg);
+ talloc_free(msg);
+ }
+
+ if (mpctx->max_frames >= 0) {
+ if (new_frame_shown)
+