player: make decoding cover art more robust

When showing cover art, the decoding logic pretends that the source has
an infinite number of frames. This slightly simplifies dealing with
filter data flow. It was done by feeding the same packet repeatedly to
the decoder (each decode run produces new output).

Change this by decoding once at the video initialization. This is easier
to follow, and increases robustness in case of broken images. Usually,
we try to tolerate decoding errors, so decoding normally continues, but
in this case it would just burn the CPU for no reason.

Fixes #2056.
This commit is contained in:
wm4 2015-06-18 18:39:46 +02:00
parent a87b18aa5a
commit e00e9d651b
3 changed files with 21 additions and 3 deletions

View File

@ -76,6 +76,8 @@ static const char av_desync_help_text[] =
" with --no-video, --no-audio, or --no-sub.\n" " with --no-video, --no-audio, or --no-sub.\n"
"If none of this helps you, file a bug report.\n\n"; "If none of this helps you, file a bug report.\n\n";
static bool decode_coverart(struct dec_video *d_video);
static void set_allowed_vo_formats(struct vf_chain *c, struct vo *vo) static void set_allowed_vo_formats(struct vf_chain *c, struct vo *vo)
{ {
vo_query_formats(vo, c->allowed_output_formats); vo_query_formats(vo, c->allowed_output_formats);
@ -301,6 +303,9 @@ int reinit_video_chain(struct MPContext *mpctx)
if (!video_init_best_codec(d_video, opts->video_decoders)) if (!video_init_best_codec(d_video, opts->video_decoders))
goto err_out; goto err_out;
if (!decode_coverart(d_video))
goto err_out;
bool saver_state = opts->pause || !opts->stop_screensaver; bool saver_state = opts->pause || !opts->stop_screensaver;
vo_control(mpctx->video_out, saver_state ? VOCTRL_RESTORE_SCREENSAVER vo_control(mpctx->video_out, saver_state ? VOCTRL_RESTORE_SCREENSAVER
: VOCTRL_KILL_SCREENSAVER, NULL); : VOCTRL_KILL_SCREENSAVER, NULL);
@ -362,6 +367,17 @@ static int check_framedrop(struct MPContext *mpctx)
return 0; return 0;
} }
static bool decode_coverart(struct dec_video *d_video)
{
d_video->cover_art_mpi =
video_decode(d_video, d_video->header->attached_picture, 0);
// Might need flush.
if (!d_video->cover_art_mpi)
d_video->cover_art_mpi = video_decode(d_video, NULL, 0);
return !!d_video->cover_art_mpi;
}
// Read a packet, store decoded image into d_video->waiting_decoded_mpi // Read a packet, store decoded image into d_video->waiting_decoded_mpi
// returns VD_* code // returns VD_* code
static int decode_image(struct MPContext *mpctx) static int decode_image(struct MPContext *mpctx)
@ -369,9 +385,8 @@ static int decode_image(struct MPContext *mpctx)
struct dec_video *d_video = mpctx->d_video; struct dec_video *d_video = mpctx->d_video;
if (d_video->header->attached_picture) { if (d_video->header->attached_picture) {
d_video->waiting_decoded_mpi = d_video->waiting_decoded_mpi = mp_image_new_ref(d_video->cover_art_mpi);
video_decode(d_video, d_video->header->attached_picture, 0); return VD_EOF;
return d_video->waiting_decoded_mpi ? VD_EOF : VD_PROGRESS;
} }
struct demux_packet *pkt; struct demux_packet *pkt;

View File

@ -117,6 +117,7 @@ int video_get_colors(struct dec_video *d_video, const char *item, int *value)
void video_uninit(struct dec_video *d_video) void video_uninit(struct dec_video *d_video)
{ {
mp_image_unrefp(&d_video->waiting_decoded_mpi); mp_image_unrefp(&d_video->waiting_decoded_mpi);
mp_image_unrefp(&d_video->cover_art_mpi);
if (d_video->vd_driver) { if (d_video->vd_driver) {
MP_VERBOSE(d_video, "Uninit video.\n"); MP_VERBOSE(d_video, "Uninit video.\n");
d_video->vd_driver->uninit(d_video); d_video->vd_driver->uninit(d_video);

View File

@ -43,6 +43,8 @@ struct dec_video {
struct mp_image *waiting_decoded_mpi; struct mp_image *waiting_decoded_mpi;
struct mp_image_params decoder_output; // last output of the decoder struct mp_image_params decoder_output; // last output of the decoder
struct mp_image *cover_art_mpi;
void *priv; // for free use by vd_driver void *priv; // for free use by vd_driver
// Last PTS from decoder (set with each vd_driver->decode() call) // Last PTS from decoder (set with each vd_driver->decode() call)