mirror of
https://github.com/mpv-player/mpv
synced 2024-12-28 10:02:17 +00:00
mplayer: fix idle mode regressions
Commit 89a17bcda6
simplified the idle loop to run any commands
mplayer receives, not just playlist related commands. Unfortunately, it
turns out many slave commands always assume the presence of a demuxer.
MPContext->demuxer is assumed not to be NULL. This made the player
crash when receiving slave commands like pause/unpause, chapter
control, subtitle selection.
We want mplayer being able to handle this. Any slave command or
property, as long as it's backed by a persistent setting, should be run
successfully, even if no file is being played. If the slave command
doesn't make sense in this state, it shouldn't crash the player.
Insert some NULL checks when accessing demuxers. If sh_video or
sh_audio are not NULL, assume demuxer can't be NULL.
(There actually aren't that many properties which need to be changed. If
it gets too complicated, we could employ alternative mechanisms instead,
such as explicitly marking safe properties with a flag.)
This commit is contained in:
parent
c0abc94a4b
commit
a4f7a3df50
37
command.c
37
command.c
@ -155,6 +155,12 @@ static void update_global_sub_size(MPContext *mpctx)
|
||||
int i;
|
||||
int cnt = 0;
|
||||
|
||||
if (!mpctx->demuxer) {
|
||||
mpctx->global_sub_size = -1;
|
||||
mpctx->global_sub_pos = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// update number of demuxer sub streams
|
||||
for (i = 0; i < MAX_S_STREAMS; i++)
|
||||
if (mpctx->d_sub->demuxer->s_streams[i])
|
||||
@ -1042,6 +1048,9 @@ static int mp_property_program(m_option_t *prop, int action, void *arg,
|
||||
{
|
||||
demux_program_t prog;
|
||||
|
||||
if (!mpctx->demuxer)
|
||||
return M_PROPERTY_UNAVAILABLE;
|
||||
|
||||
switch (action) {
|
||||
case M_PROPERTY_STEP_UP:
|
||||
case M_PROPERTY_SET:
|
||||
@ -2041,6 +2050,8 @@ static int mp_property_tv_color(m_option_t *prop, int action, void *arg,
|
||||
MPContext *mpctx)
|
||||
{
|
||||
int r, val;
|
||||
if (!mpctx->demuxer)
|
||||
return M_PROPERTY_UNAVAILABLE;
|
||||
tvi_handle_t *tvh = mpctx->demuxer->priv;
|
||||
if (mpctx->demuxer->type != DEMUXER_TYPE_TV || !tvh)
|
||||
return M_PROPERTY_UNAVAILABLE;
|
||||
@ -3005,7 +3016,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
|
||||
#ifdef CONFIG_RADIO
|
||||
case MP_CMD_RADIO_STEP_CHANNEL:
|
||||
if (mpctx->demuxer->stream->type == STREAMTYPE_RADIO) {
|
||||
if (mpctx->demuxer && mpctx->demuxer->stream->type == STREAMTYPE_RADIO) {
|
||||
int v = cmd->args[0].v.i;
|
||||
if (v > 0)
|
||||
radio_step_channel(mpctx->demuxer->stream,
|
||||
@ -3022,7 +3033,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
break;
|
||||
|
||||
case MP_CMD_RADIO_SET_CHANNEL:
|
||||
if (mpctx->demuxer->stream->type == STREAMTYPE_RADIO) {
|
||||
if (mpctx->demuxer && mpctx->demuxer->stream->type == STREAMTYPE_RADIO) {
|
||||
radio_set_channel(mpctx->demuxer->stream, cmd->args[0].v.s);
|
||||
if (radio_get_channel_name(mpctx->demuxer->stream)) {
|
||||
set_osd_tmsg(OSD_MSG_RADIO_CHANNEL, 1, osd_duration,
|
||||
@ -3033,23 +3044,23 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
break;
|
||||
|
||||
case MP_CMD_RADIO_SET_FREQ:
|
||||
if (mpctx->demuxer->stream->type == STREAMTYPE_RADIO)
|
||||
if (mpctx->demuxer && mpctx->demuxer->stream->type == STREAMTYPE_RADIO)
|
||||
radio_set_freq(mpctx->demuxer->stream, cmd->args[0].v.f);
|
||||
break;
|
||||
|
||||
case MP_CMD_RADIO_STEP_FREQ:
|
||||
if (mpctx->demuxer->stream->type == STREAMTYPE_RADIO)
|
||||
if (mpctx->demuxer && mpctx->demuxer->stream->type == STREAMTYPE_RADIO)
|
||||
radio_step_freq(mpctx->demuxer->stream, cmd->args[0].v.f);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TV
|
||||
case MP_CMD_TV_START_SCAN:
|
||||
if (mpctx->file_format == DEMUXER_TYPE_TV)
|
||||
if (mpctx->demuxer && mpctx->file_format == DEMUXER_TYPE_TV)
|
||||
tv_start_scan((tvi_handle_t *) (mpctx->demuxer->priv), 1);
|
||||
break;
|
||||
case MP_CMD_TV_SET_FREQ:
|
||||
if (mpctx->file_format == DEMUXER_TYPE_TV)
|
||||
if (mpctx->demuxer && mpctx->file_format == DEMUXER_TYPE_TV)
|
||||
tv_set_freq((tvi_handle_t *) (mpctx->demuxer->priv),
|
||||
cmd->args[0].v.f * 16.0);
|
||||
#ifdef CONFIG_PVR
|
||||
@ -3063,7 +3074,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
break;
|
||||
|
||||
case MP_CMD_TV_STEP_FREQ:
|
||||
if (mpctx->file_format == DEMUXER_TYPE_TV)
|
||||
if (mpctx->demuxer && mpctx->file_format == DEMUXER_TYPE_TV)
|
||||
tv_step_freq((tvi_handle_t *) (mpctx->demuxer->priv),
|
||||
cmd->args[0].v.f * 16.0);
|
||||
#ifdef CONFIG_PVR
|
||||
@ -3077,13 +3088,13 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
break;
|
||||
|
||||
case MP_CMD_TV_SET_NORM:
|
||||
if (mpctx->file_format == DEMUXER_TYPE_TV)
|
||||
if (mpctx->demuxer && mpctx->file_format == DEMUXER_TYPE_TV)
|
||||
tv_set_norm((tvi_handle_t *) (mpctx->demuxer->priv),
|
||||
cmd->args[0].v.s);
|
||||
break;
|
||||
|
||||
case MP_CMD_TV_STEP_CHANNEL:
|
||||
if (mpctx->file_format == DEMUXER_TYPE_TV) {
|
||||
if (mpctx->demuxer && mpctx->file_format == DEMUXER_TYPE_TV) {
|
||||
int v = cmd->args[0].v.i;
|
||||
if (v > 0) {
|
||||
tv_step_channel((tvi_handle_t *) (mpctx->
|
||||
@ -3130,7 +3141,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
break;
|
||||
|
||||
case MP_CMD_TV_SET_CHANNEL:
|
||||
if (mpctx->file_format == DEMUXER_TYPE_TV) {
|
||||
if (mpctx->demuxer && mpctx->file_format == DEMUXER_TYPE_TV) {
|
||||
tv_set_channel((tvi_handle_t *) (mpctx->demuxer->priv),
|
||||
cmd->args[0].v.s);
|
||||
if (tv_channel_list) {
|
||||
@ -3164,7 +3175,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
#endif /* CONFIG_DVBIN */
|
||||
|
||||
case MP_CMD_TV_LAST_CHANNEL:
|
||||
if (mpctx->file_format == DEMUXER_TYPE_TV) {
|
||||
if (mpctx->demuxer && mpctx->file_format == DEMUXER_TYPE_TV) {
|
||||
tv_last_channel((tvi_handle_t *) (mpctx->demuxer->priv));
|
||||
if (tv_channel_list) {
|
||||
set_osd_tmsg(OSD_MSG_TV_CHANNEL, 1, osd_duration,
|
||||
@ -3183,12 +3194,12 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
break;
|
||||
|
||||
case MP_CMD_TV_STEP_NORM:
|
||||
if (mpctx->file_format == DEMUXER_TYPE_TV)
|
||||
if (mpctx->demuxer && mpctx->file_format == DEMUXER_TYPE_TV)
|
||||
tv_step_norm((tvi_handle_t *) (mpctx->demuxer->priv));
|
||||
break;
|
||||
|
||||
case MP_CMD_TV_STEP_CHANNEL_LIST:
|
||||
if (mpctx->file_format == DEMUXER_TYPE_TV)
|
||||
if (mpctx->demuxer && mpctx->file_format == DEMUXER_TYPE_TV)
|
||||
tv_step_chanlist((tvi_handle_t *) (mpctx->demuxer->priv));
|
||||
break;
|
||||
#endif /* CONFIG_TV */
|
||||
|
@ -104,6 +104,8 @@ typedef struct MPContext {
|
||||
struct timeline_part *timeline;
|
||||
int num_timeline_parts;
|
||||
int timeline_part;
|
||||
// NOTE: even if num_chapters==0, chapters being not NULL signifies presence
|
||||
// of chapter metadata
|
||||
struct chapter *chapters;
|
||||
int num_chapters;
|
||||
double video_offset;
|
||||
|
81
mplayer.c
81
mplayer.c
@ -448,7 +448,8 @@ static void print_file_properties(struct MPContext *mpctx, const char *filename)
|
||||
double video_start_pts = MP_NOPTS_VALUE;
|
||||
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_FILENAME=%s\n",
|
||||
filename);
|
||||
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DEMUXER=%s\n",
|
||||
if (mpctx->demuxer)
|
||||
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DEMUXER=%s\n",
|
||||
mpctx->demuxer->desc->name);
|
||||
if (mpctx->sh_video) {
|
||||
/* Assume FOURCC if all bytes >= 0x20 (' ') */
|
||||
@ -516,9 +517,9 @@ static void print_file_properties(struct MPContext *mpctx, const char *filename)
|
||||
talloc_free(name);
|
||||
}
|
||||
}
|
||||
for (int n = 0; n < mpctx->demuxer->num_streams; n++)
|
||||
print_stream(mpctx, mpctx->demuxer->streams[n]);
|
||||
}
|
||||
for (int n = 0; n < mpctx->demuxer->num_streams; n++)
|
||||
print_stream(mpctx, mpctx->demuxer->streams[n]);
|
||||
}
|
||||
|
||||
/// step size of mixer changes
|
||||
@ -2551,7 +2552,9 @@ void pause_player(struct MPContext *mpctx)
|
||||
if (mpctx->ao && mpctx->sh_audio)
|
||||
ao_pause(mpctx->ao); // pause audio, keep data if possible
|
||||
|
||||
print_status(mpctx, MP_NOPTS_VALUE, false);
|
||||
// Only print status if there's actually a file being played.
|
||||
if (mpctx->demuxer)
|
||||
print_status(mpctx, MP_NOPTS_VALUE, false);
|
||||
|
||||
if (!mpctx->opts.quiet)
|
||||
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_PAUSED\n");
|
||||
@ -2683,6 +2686,9 @@ static int seek(MPContext *mpctx, struct seek_params seek,
|
||||
{
|
||||
struct MPOpts *opts = &mpctx->opts;
|
||||
|
||||
if (!mpctx->demuxer)
|
||||
return -1;
|
||||
|
||||
if (mpctx->stop_play == AT_END_OF_FILE)
|
||||
mpctx->stop_play = KEEP_PLAYING;
|
||||
bool hr_seek = mpctx->demuxer->accurate_seek && opts->correct_pts;
|
||||
@ -2816,10 +2822,13 @@ void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
|
||||
|
||||
double get_time_length(struct MPContext *mpctx)
|
||||
{
|
||||
struct demuxer *demuxer = mpctx->demuxer;
|
||||
if (!demuxer)
|
||||
return 0;
|
||||
|
||||
if (mpctx->timeline)
|
||||
return mpctx->timeline[mpctx->num_timeline_parts].start;
|
||||
|
||||
struct demuxer *demuxer = mpctx->demuxer;
|
||||
double get_time_ans;
|
||||
// <= 0 means DEMUXER_CTRL_NOTIMPL or DEMUXER_CTRL_DONTKNOW
|
||||
if (demux_control(demuxer, DEMUXER_CTRL_GET_TIME_LENGTH,
|
||||
@ -2846,6 +2855,8 @@ double get_time_length(struct MPContext *mpctx)
|
||||
double get_current_time(struct MPContext *mpctx)
|
||||
{
|
||||
struct demuxer *demuxer = mpctx->demuxer;
|
||||
if (!demuxer)
|
||||
return 0;
|
||||
if (demuxer->stream_pts != MP_NOPTS_VALUE)
|
||||
return demuxer->stream_pts;
|
||||
if (mpctx->sh_video) {
|
||||
@ -2862,6 +2873,8 @@ double get_current_time(struct MPContext *mpctx)
|
||||
int get_percent_pos(struct MPContext *mpctx)
|
||||
{
|
||||
struct demuxer *demuxer = mpctx->demuxer;
|
||||
if (!demuxer)
|
||||
return 0;
|
||||
int ans = 0;
|
||||
if (mpctx->timeline)
|
||||
ans = get_current_time(mpctx) * 100 /
|
||||
@ -2888,15 +2901,17 @@ int get_percent_pos(struct MPContext *mpctx)
|
||||
int get_current_chapter(struct MPContext *mpctx)
|
||||
{
|
||||
double current_pts = get_current_time(mpctx);
|
||||
if (!mpctx->chapters)
|
||||
if (mpctx->chapters) {
|
||||
int i;
|
||||
for (i = 1; i < mpctx->num_chapters; i++)
|
||||
if (current_pts < mpctx->chapters[i].start)
|
||||
break;
|
||||
return FFMAX(mpctx->last_chapter_seek, i - 1);
|
||||
}
|
||||
if (mpctx->demuxer)
|
||||
return FFMAX(mpctx->last_chapter_seek,
|
||||
demuxer_get_current_chapter(mpctx->demuxer, current_pts));
|
||||
|
||||
int i;
|
||||
for (i = 1; i < mpctx->num_chapters; i++)
|
||||
if (current_pts < mpctx->chapters[i].start)
|
||||
break;
|
||||
return FFMAX(mpctx->last_chapter_seek, i - 1);
|
||||
return -2;
|
||||
}
|
||||
|
||||
char *chapter_display_name(struct MPContext *mpctx, int chapter)
|
||||
@ -2918,30 +2933,46 @@ char *chapter_display_name(struct MPContext *mpctx, int chapter)
|
||||
// returns NULL if chapter name unavailable
|
||||
char *chapter_name(struct MPContext *mpctx, int chapter)
|
||||
{
|
||||
if (!mpctx->chapters)
|
||||
if (mpctx->chapters)
|
||||
return talloc_strdup(NULL, mpctx->chapters[chapter].name);
|
||||
if (mpctx->demuxer)
|
||||
return demuxer_chapter_name(mpctx->demuxer, chapter);
|
||||
return talloc_strdup(NULL, mpctx->chapters[chapter].name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// returns the start of the chapter in seconds
|
||||
// returns the start of the chapter in seconds (-1 if unavailable)
|
||||
double chapter_start_time(struct MPContext *mpctx, int chapter)
|
||||
{
|
||||
if (!mpctx->chapters)
|
||||
if (mpctx->chapters)
|
||||
return mpctx->chapters[chapter].start;
|
||||
if (mpctx->demuxer)
|
||||
return demuxer_chapter_time(mpctx->demuxer, chapter, NULL);
|
||||
return mpctx->chapters[chapter].start;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int get_chapter_count(struct MPContext *mpctx)
|
||||
{
|
||||
if (!mpctx->chapters)
|
||||
if (mpctx->chapters)
|
||||
return mpctx->num_chapters;
|
||||
if (mpctx->demuxer)
|
||||
return demuxer_chapter_count(mpctx->demuxer);
|
||||
return mpctx->num_chapters;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int seek_chapter(struct MPContext *mpctx, int chapter, double *seek_pts)
|
||||
{
|
||||
mpctx->last_chapter_seek = -2;
|
||||
if (!mpctx->chapters) {
|
||||
if (mpctx->chapters) {
|
||||
if (chapter >= mpctx->num_chapters)
|
||||
return -1;
|
||||
if (chapter < 0)
|
||||
chapter = 0;
|
||||
*seek_pts = mpctx->chapters[chapter].start;
|
||||
mpctx->last_chapter_seek = chapter;
|
||||
mpctx->last_chapter_pts = *seek_pts;
|
||||
return chapter;
|
||||
}
|
||||
if (mpctx->demuxer) {
|
||||
int res = demuxer_seek_chapter(mpctx->demuxer, chapter, seek_pts);
|
||||
if (res >= 0) {
|
||||
if (*seek_pts == -1)
|
||||
@ -2953,15 +2984,7 @@ int seek_chapter(struct MPContext *mpctx, int chapter, double *seek_pts)
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
if (chapter >= mpctx->num_chapters)
|
||||
return -1;
|
||||
if (chapter < 0)
|
||||
chapter = 0;
|
||||
*seek_pts = mpctx->chapters[chapter].start;
|
||||
mpctx->last_chapter_seek = chapter;
|
||||
mpctx->last_chapter_pts = *seek_pts;
|
||||
return chapter;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user