diff --git a/demux/packet.c b/demux/packet.c index 93f64e844a..c78ad49026 100644 --- a/demux/packet.c +++ b/demux/packet.c @@ -64,6 +64,7 @@ static struct demux_packet *packet_create(void) .end = MP_NOPTS_VALUE, .stream = -1, .avpacket = av_packet_alloc(), + .animated = -1, }; MP_HANDLE_OOM(dp->avpacket); return dp; diff --git a/demux/packet.h b/demux/packet.h index 8087216355..6a0423fe8f 100644 --- a/demux/packet.h +++ b/demux/packet.h @@ -59,7 +59,7 @@ typedef struct demux_packet { double start, end; // set to non-NOPTS iff segmented is set // subtitles only - bool animated; + int animated; // -1 is unknown bool seen; int seen_pos; double sub_duration; diff --git a/player/sub.c b/player/sub.c index 65e5732e23..bdd19540b0 100644 --- a/player/sub.c +++ b/player/sub.c @@ -106,6 +106,15 @@ static bool update_subtitle(struct MPContext *mpctx, double video_pts, sub_control(dec_sub, SD_CTRL_SET_VIDEO_PARAMS, ¶ms); } + // Checking if packets have special animations is relatively expensive. + // This is only needed if we are rendering ASS subtitles with no video + // being played. + bool still_image = mpctx->video_out && ((mpctx->video_status == STATUS_EOF && + mpctx->opts->subs_rend->sub_past_video_end) || + !mpctx->current_track[0][STREAM_VIDEO] || + mpctx->current_track[0][STREAM_VIDEO]->image); + sub_control(dec_sub, SD_CTRL_SET_ANIMATED_CHECK, &still_image); + if (track->demuxer->fully_read && sub_can_preload(dec_sub)) { // Assume fully_read implies no interleaved audio/video streams. // (Reading packets will change the demuxer position.) @@ -136,10 +145,7 @@ static bool update_subtitle(struct MPContext *mpctx, double video_pts, // Handle displaying subtitles on VO with no video being played. This is // quite different, because normally subtitles are redrawn on new video // frames, using the video frames' timestamps. - if (mpctx->video_out && mpctx->video_status == STATUS_EOF && - (mpctx->opts->subs_rend->sub_past_video_end || - !mpctx->current_track[0][STREAM_VIDEO] || - mpctx->current_track[0][STREAM_VIDEO]->image)) { + if (still_image) { if (osd_pts != video_pts) { osd_set_force_video_pts(mpctx->osd, video_pts); osd_query_and_reset_want_redraw(mpctx->osd); diff --git a/sub/dec_sub.c b/sub/dec_sub.c index c03393a007..ce51fdf8c8 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -319,7 +319,7 @@ static bool update_pkt_cache(struct dec_sub *sub, double video_pts) return true; } - if (pkt && pkt->animated) + if (pkt && pkt->animated == 1) return true; return false; diff --git a/sub/dec_sub.h b/sub/dec_sub.h index a40aa9bbfd..476e83a3f5 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -16,6 +16,7 @@ struct sd; enum sd_ctrl { SD_CTRL_SUB_STEP, + SD_CTRL_SET_ANIMATED_CHECK, SD_CTRL_SET_VIDEO_PARAMS, SD_CTRL_SET_VIDEO_DEF_FPS, SD_CTRL_UPDATE_OPTS, diff --git a/sub/sd_ass.c b/sub/sd_ass.c index 82e39b6f54..e9f091682a 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -57,8 +57,9 @@ struct sd_ass_priv { struct mp_osd_res osd; struct seen_packet *seen_packets; int num_seen_packets; - bool *packets_animated; + int *packets_animated; int num_packets_animated; + bool check_animated; bool duration_unknown; }; @@ -351,19 +352,32 @@ static void filter_and_add(struct sd *sd, struct demux_packet *pkt) llrint(pkt->pts * 1000), llrint(pkt->duration * 1000)); - // This bookkeeping is only ever needed for ASS subs + // This bookkeeping only has any practical use for ASS subs + // over a VO with no video. if (!ctx->is_converted) { if (!pkt->seen) { for (int n = track->n_events - 1; n >= 0; n--) { - if (n + 1 == old_n_events || pkt->animated) + if (n + 1 == old_n_events || pkt->animated == 1) break; ASS_Event *event = &track->events[n]; - pkt->animated = (event->Effect && event->Effect[0]) || - is_animated(event->Text); + // Might as well mark pkt->animated here with effects if we can. + pkt->animated = (event->Effect && event->Effect[0]) ? 1 : -1; + if (ctx->check_animated && pkt->animated != 1) + pkt->animated = is_animated(event->Text); } MP_TARRAY_APPEND(ctx, ctx->packets_animated, ctx->num_packets_animated, pkt->animated); } else { - pkt->animated = ctx->packets_animated[pkt->seen_pos]; + if (ctx->check_animated && ctx->packets_animated[pkt->seen_pos] == -1) { + for (int n = track->n_events - 1; n >= 0; n--) { + if (n + 1 == old_n_events || pkt->animated == 1) + break; + ASS_Event *event = &track->events[n]; + ctx->packets_animated[pkt->seen_pos] = is_animated(event->Text); + pkt->animated = ctx->packets_animated[pkt->seen_pos]; + } + } else { + pkt->animated = ctx->packets_animated[pkt->seen_pos]; + } } } @@ -952,6 +966,9 @@ static int control(struct sd *sd, enum sd_ctrl cmd, void *arg) a[0] += res / 1000.0 + SUB_SEEK_OFFSET; return true; } + case SD_CTRL_SET_ANIMATED_CHECK: + ctx->check_animated = *(bool *)arg; + return CONTROL_OK; case SD_CTRL_SET_VIDEO_PARAMS: ctx->video_params = *(struct mp_image_params *)arg; return CONTROL_OK;