summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/client-api-changes.rst2
-rw-r--r--libmpv/client.h39
-rw-r--r--player/audio.c1
-rw-r--r--player/client.c5
-rw-r--r--player/core.h3
-rw-r--r--player/loadfile.c55
-rw-r--r--player/misc.c7
-rw-r--r--player/video.c5
8 files changed, 92 insertions, 25 deletions
diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst
index b6b5dbc6ca..e868d554d3 100644
--- a/DOCS/client-api-changes.rst
+++ b/DOCS/client-api-changes.rst
@@ -26,6 +26,8 @@ API changes
::
1.9 - add enum mpv_end_file_reason for mpv_event_end_file.reason
+ - add MPV_END_FILE_REASON_ERROR and the mpv_event_end_file.error field
+ for slightly better error reporting on playback failure
1.8 - add qthelper.hpp
1.7 - add mpv_command_node(), mpv_command_node_async()
1.6 - modify "core-idle" property behavior
diff --git a/libmpv/client.h b/libmpv/client.h
index ed99715857..bc594cee6a 100644
--- a/libmpv/client.h
+++ b/libmpv/client.h
@@ -246,7 +246,30 @@ typedef enum mpv_error {
/**
* General error when running a command with mpv_command and similar.
*/
- MPV_ERROR_COMMAND = -12
+ MPV_ERROR_COMMAND = -12,
+ /**
+ * Generic error on loading (used with mpv_event_end_file.error).
+ */
+ MPV_ERROR_LOADING_FAILED = -13,
+ /**
+ * Initializing the audio output failed.
+ */
+ MPV_ERROR_AO_INIT_FAILED = -14,
+ /**
+ * Initializing the video output failed.
+ */
+ MPV_ERROR_VO_INIT_FAILED = -15,
+ /**
+ * There was no audio or video data to play. This also happens if the
+ * file was recognized, but did not contain any audio or video streams,
+ * or no streams were selected.
+ */
+ MPV_ERROR_NOTHING_TO_PLAY = -16,
+ /**
+ * When trying to load the file, the file format could not be determined,
+ * or the file was too broken to open it.
+ */
+ MPV_ERROR_UNKNOWN_FORMAT = -17
} mpv_error;
/**
@@ -1131,6 +1154,14 @@ typedef enum mpv_end_file_reason {
* Playback was stopped by the quit command or player shutdown.
*/
MPV_END_FILE_REASON_QUIT = 3,
+ /**
+ * Some kind of error happened that lead to playback abort. Does not
+ * necessarily happen on incomplete or broken files (in these cases, both
+ * MPV_END_FILE_REASON_ERROR or MPV_END_FILE_REASON_EOF are possible).
+ *
+ * mpv_event_end_file.error will be set.
+ */
+ MPV_END_FILE_REASON_ERROR = 4,
} mpv_end_file_reason;
typedef struct mpv_event_end_file {
@@ -1141,6 +1172,12 @@ typedef struct mpv_event_end_file {
* Unknown values should be treated as unknown.
*/
int reason;
+ /**
+ * If reason==MPV_END_FILE_REASON_ERROR, this contains a mpv error code
+ * (one of MPV_ERROR_...) giving an approximate reason why playback
+ * failed. In other cases, this field is 0 (no error).
+ */
+ int error;
} mpv_event_end_file;
typedef struct mpv_event_script_input_dispatch {
diff --git a/player/audio.c b/player/audio.c
index 6774d415c3..8274399f67 100644
--- a/player/audio.c
+++ b/player/audio.c
@@ -255,6 +255,7 @@ void reinit_audio_chain(struct MPContext *mpctx)
struct ao *ao = mpctx->ao;
if (!ao) {
MP_ERR(mpctx, "Could not open/initialize audio device -> no sound.\n");
+ mpctx->error_playing = MPV_ERROR_AO_INIT_FAILED;
goto init_error;
}
diff --git a/player/client.c b/player/client.c
index 8376756a9a..2308555a1e 100644
--- a/player/client.c
+++ b/player/client.c
@@ -1479,6 +1479,11 @@ static const char *const err_table[] = {
[-MPV_ERROR_PROPERTY_UNAVAILABLE] = "property unavailable",
[-MPV_ERROR_PROPERTY_ERROR] = "error accessing property",
[-MPV_ERROR_COMMAND] = "error running command",
+ [-MPV_ERROR_LOADING_FAILED] = "loading failed",
+ [-MPV_ERROR_AO_INIT_FAILED] = "audio output initialization failed",
+ [-MPV_ERROR_VO_INIT_FAILED] = "audio output initialization failed",
+ [-MPV_ERROR_NOTHING_TO_PLAY] = "the file has no audio or video data",
+ [-MPV_ERROR_UNKNOWN_FORMAT] = "unrecognized file format",
};
const char *mpv_error_string(int error)
diff --git a/player/core.h b/player/core.h
index 9b9873e610..32c6b45db6 100644
--- a/player/core.h
+++ b/player/core.h
@@ -38,6 +38,7 @@ enum stop_play_reason {
PT_STOP, // stop playback, clear playlist
PT_RELOAD_DEMUXER, // restart playback, but keep stream open
PT_QUIT, // stop playback, quit player
+ PT_ERROR, // play next playlist entry (due to an error)
};
enum exit_reason {
@@ -186,7 +187,7 @@ typedef struct MPContext {
enum exit_reason quit_player_rc;
int quit_custom_rc;
bool has_quit_custom_rc;
- bool error_playing;
+ int error_playing;
char **resume_defaults;
int64_t shown_vframes, shown_aframes;
diff --git a/player/loadfile.c b/player/loadfile.c
index 58b9cf9f68..46f41644c1 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -877,6 +877,7 @@ static void play_current_file(struct MPContext *mpctx)
mp_cancel_reset(mpctx->playback_abort);
+ mpctx->error_playing = MPV_ERROR_LOADING_FAILED;
mpctx->stop_play = 0;
mpctx->filename = NULL;
mpctx->shown_aframes = 0;
@@ -973,6 +974,7 @@ goto_reopen_demuxer: ;
mpctx->demuxer = open_demux_async(mpctx, mpctx->stream);
if (!mpctx->demuxer) {
MP_ERR(mpctx, "Failed to recognize file format.\n");
+ mpctx->error_playing = MPV_ERROR_UNKNOWN_FORMAT;
goto terminate_playback;
}
mpctx->master_demuxer = mpctx->demuxer;
@@ -987,6 +989,7 @@ goto_reopen_demuxer: ;
for (struct playlist_entry *e = pl->first; e; e = e->next)
e->stream_flags |= entry_stream_flags;
transfer_playlist(mpctx, pl);
+ mpctx->error_playing = 0;
goto terminate_playback;
}
@@ -1092,6 +1095,7 @@ goto_reopen_demuxer: ;
if (demux_stream_control(d, STREAM_CTRL_DVB_STEP_CHANNEL, &dir) > 0)
mpctx->stop_play = PT_RELOAD_DEMUXER;
}
+ mpctx->error_playing = MPV_ERROR_NOTHING_TO_PLAY;
goto terminate_playback;
}
@@ -1099,6 +1103,7 @@ goto_reopen_demuxer: ;
if (mpctx->max_frames == 0) {
mpctx->stop_play = PT_NEXT_ENTRY;
+ mpctx->error_playing = 0;
goto terminate_playback;
}
@@ -1124,7 +1129,7 @@ goto_reopen_demuxer: ;
mp_notify(mpctx, MPV_EVENT_FILE_LOADED, NULL);
playback_start = mp_time_sec();
- mpctx->error_playing = false;
+ mpctx->error_playing = 0;
while (!mpctx->stop_play)
run_playloop(mpctx);
@@ -1173,18 +1178,33 @@ terminate_playback:
mpctx->playback_initialized = false;
- if (mpctx->playing && mpctx->stop_play == AT_END_OF_FILE) {
- // Played/paused for longer than 1 second -> ok
- mpctx->playing->playback_short =
- playback_start < 0 || mp_time_sec() - playback_start < 1.0;
- mpctx->playing->init_failed =
- mpctx->shown_aframes == 0 && mpctx->shown_vframes == 0;
- }
-
mp_notify(mpctx, MPV_EVENT_TRACKS_CHANGED, NULL);
struct mpv_event_end_file end_event = {0};
switch (mpctx->stop_play) {
- case AT_END_OF_FILE: end_event.reason = MPV_END_FILE_REASON_EOF; break;
+ case PT_ERROR:
+ case AT_END_OF_FILE:
+ {
+ if (mpctx->error_playing >= 0 &&
+ mpctx->shown_aframes == 0 && mpctx->shown_vframes == 0)
+ {
+ mpctx->error_playing = MPV_ERROR_NOTHING_TO_PLAY;
+ }
+ end_event.error = mpctx->error_playing;
+ if (end_event.error < 0) {
+ end_event.reason = MPV_END_FILE_REASON_ERROR;
+ } else {
+ end_event.reason = MPV_END_FILE_REASON_EOF;
+ }
+ if (mpctx->playing) {
+ // Played/paused for longer than 1 second -> ok
+ mpctx->playing->playback_short =
+ playback_start < 0 || mp_time_sec() - playback_start < 1.0;
+ mpctx->playing->init_failed =
+ end_event.error == MPV_ERROR_NOTHING_TO_PLAY;
+ }
+ break;
+ }
+ // Note that error_playing is meaningless in these cases.
case PT_NEXT_ENTRY:
case PT_CURRENT_ENTRY:
case PT_STOP: end_event.reason = MPV_END_FILE_REASON_STOP; break;
@@ -1259,9 +1279,8 @@ void mp_play_files(struct MPContext *mpctx)
if (mpctx->stop_play == PT_QUIT)
break;
- mpctx->error_playing = true;
play_current_file(mpctx);
- if (mpctx->error_playing) {
+ if (mpctx->error_playing < 0) {
if (!mpctx->quit_player_rc) {
mpctx->quit_player_rc = EXIT_NOTPLAYED;
} else if (mpctx->quit_player_rc == EXIT_PLAYED) {
@@ -1275,15 +1294,11 @@ void mp_play_files(struct MPContext *mpctx)
if (mpctx->stop_play == PT_QUIT)
break;
- if (!mpctx->stop_play || mpctx->stop_play == AT_END_OF_FILE)
- mpctx->stop_play = PT_NEXT_ENTRY;
-
- struct playlist_entry *new_entry = NULL;
-
- if (mpctx->stop_play == PT_NEXT_ENTRY) {
+ struct playlist_entry *new_entry = mpctx->playlist->current;
+ if (mpctx->stop_play == PT_NEXT_ENTRY || mpctx->stop_play == PT_ERROR ||
+ mpctx->stop_play == AT_END_OF_FILE || !mpctx->stop_play)
+ {
new_entry = mp_next_file(mpctx, +1, false);
- } else {
- new_entry = mpctx->playlist->current;
}
mpctx->playlist->current = new_entry;
diff --git a/player/misc.c b/player/misc.c
index 5355e23f41..c178ec7b39 100644
--- a/player/misc.c
+++ b/player/misc.c
@@ -191,8 +191,11 @@ void error_on_track(struct MPContext *mpctx, struct track *track)
MP_INFO(mpctx, "Video: no video\n");
if (!mpctx->current_track[0][STREAM_AUDIO] &&
!mpctx->current_track[0][STREAM_VIDEO])
- mpctx->stop_play = PT_NEXT_ENTRY;
- mpctx->error_playing = true;
+ {
+ mpctx->stop_play = PT_ERROR;
+ if (mpctx->error_playing >= 0)
+ mpctx->error_playing = MPV_ERROR_NOTHING_TO_PLAY;
+ }
mpctx->sleeptime = 0;
}
}
diff --git a/player/video.c b/player/video.c
index db33406d63..7e4de2482f 100644
--- a/player/video.c
+++ b/player/video.c
@@ -273,6 +273,7 @@ int reinit_video_chain(struct MPContext *mpctx)
if (!mpctx->video_out) {
MP_FATAL(mpctx, "Error opening/initializing "
"the selected video_out (-vo) device.\n");
+ mpctx->error_playing = MPV_ERROR_VO_INIT_FAILED;
goto err_out;
}
mpctx->mouse_cursor_visible = true;
@@ -766,8 +767,10 @@ void write_video(struct MPContext *mpctx, double endpts)
MP_VERBOSE(mpctx, "VO: Description: %s\n", info->description);
int vo_r = vo_reconfig(vo, &p, 0);
- if (vo_r < 0)
+ if (vo_r < 0) {
+ mpctx->error_playing = MPV_ERROR_VO_INIT_FAILED;
goto error;
+ }
init_vo(mpctx);
mpctx->time_frame = 0; // display immediately
}