4e5d996c3a3f74a7308aee53614c2b94c71daebc added this as part of a series of patches written to avoid wasteful sub redraws when playing a still image with subs. The is_animated special case was specifically for ASS subtitles that have animations/effects and would need repeated redraws in the still image case. This check was done unconditionally for all ASS subtitles, but for very big ASS subtitles, this text parsing can get a bit expensive. Because this function call is only ever needed for the weird edge case of ASS subtitles over a still image, some additional logic can be added to avoid calling is_animated in the vast majority of cases. The animated field in demux_packet can be changed to a tristate instead where -1 indicates "unknown" (the default state). In update_subtitle, we can look at the current state of the video tracks and decide whether or not it is neccesary to perform is_animated and pass that knowledge to sd_ass before any subtitle packets are decoded and thus save us from doing this potentially expensive call.
Unified · Split
| @@ -64,6 +64,7 @@ static struct demux_packet *packet_create(void) · 63 unmodified lines | |||
| 64 | .end = MP_NOPTS_VALUE, | 64 | .end = MP_NOPTS_VALUE, |
| 65 | .stream = -1, | 65 | .stream = -1, |
| 66 | .avpacket = av_packet_alloc(), | 66 | .avpacket = av_packet_alloc(), |
| 67 | .animated = -1, | ||
| 67 | }; | 68 | }; |
| 68 | MP_HANDLE_OOM(dp->avpacket); | 69 | MP_HANDLE_OOM(dp->avpacket); |
| 69 | return dp; | 70 | return dp; |
| @@ -59,7 +59,7 @@ typedef struct demux_packet { · 58 unmodified lines | |||
| 59 | double start, end; // set to non-NOPTS iff segmented is set | 59 | double start, end; // set to non-NOPTS iff segmented is set |
| 60 | 60 | ||
| 61 | // subtitles only | 61 | // subtitles only |
| 62 | bool animated; | 62 | int animated; // -1 is unknown |
| 63 | bool seen; | 63 | bool seen; |
| 64 | int seen_pos; | 64 | int seen_pos; |
| 65 | double sub_duration; | 65 | double sub_duration; |
| @@ -106,6 +106,15 @@ static bool update_subtitle(struct MPContext *mpctx, double video_pts, · 105 unmodified lines | |||
| 106 | sub_control(dec_sub, SD_CTRL_SET_VIDEO_PARAMS, ¶ms); | 106 | sub_control(dec_sub, SD_CTRL_SET_VIDEO_PARAMS, ¶ms); |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | // Checking if packets have special animations is relatively expensive. | ||
| 110 | // This is only needed if we are rendering ASS subtitles with no video | ||
| 111 | // being played. | ||
| 112 | bool still_image = mpctx->video_out && ((mpctx->video_status == STATUS_EOF && | ||
| 113 | mpctx->opts->subs_rend->sub_past_video_end) || | ||
| 114 | !mpctx->current_track[0][STREAM_VIDEO] || | ||
| 115 | mpctx->current_track[0][STREAM_VIDEO]->image); | ||
| 116 | sub_control(dec_sub, SD_CTRL_SET_ANIMATED_CHECK, &still_image); | ||
| 117 | |||
| 109 | if (track->demuxer->fully_read && sub_can_preload(dec_sub)) { | 118 | if (track->demuxer->fully_read && sub_can_preload(dec_sub)) { |
| 110 | // Assume fully_read implies no interleaved audio/video streams. | 119 | // Assume fully_read implies no interleaved audio/video streams. |
| 111 | // (Reading packets will change the demuxer position.) | 120 | // (Reading packets will change the demuxer position.) |
| @@ -136,10 +145,7 @@ static bool update_subtitle(struct MPContext *mpctx, double video_pts, · 24 unmodified lines | |||
| 136 | // Handle displaying subtitles on VO with no video being played. This is | 145 | // Handle displaying subtitles on VO with no video being played. This is |
| 137 | // quite different, because normally subtitles are redrawn on new video | 146 | // quite different, because normally subtitles are redrawn on new video |
| 138 | // frames, using the video frames' timestamps. | 147 | // frames, using the video frames' timestamps. |
| 139 | if (mpctx->video_out && mpctx->video_status == STATUS_EOF && | 148 | if (still_image) { |
| 140 | (mpctx->opts->subs_rend->sub_past_video_end || | ||
| 141 | !mpctx->current_track[0][STREAM_VIDEO] || | ||
| 142 | mpctx->current_track[0][STREAM_VIDEO]->image)) { | ||
| 143 | if (osd_pts != video_pts) { | 149 | if (osd_pts != video_pts) { |
| 144 | osd_set_force_video_pts(mpctx->osd, video_pts); | 150 | osd_set_force_video_pts(mpctx->osd, video_pts); |
| 145 | osd_query_and_reset_want_redraw(mpctx->osd); | 151 | osd_query_and_reset_want_redraw(mpctx->osd); |
| @@ -319,7 +319,7 @@ static bool update_pkt_cache(struct dec_sub *sub, double video_pts) · 318 unmodified lines | |||
| 319 | return true; | 319 | return true; |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | if (pkt && pkt->animated) | 322 | if (pkt && pkt->animated == 1) |
| 323 | return true; | 323 | return true; |
| 324 | 324 | ||
| 325 | return false; | 325 | return false; |
| @@ -16,6 +16,7 @@ struct sd; · 15 unmodified lines | |||
| 16 | 16 | ||
| 17 | enum sd_ctrl { | 17 | enum sd_ctrl { |
| 18 | SD_CTRL_SUB_STEP, | 18 | SD_CTRL_SUB_STEP, |
| 19 | SD_CTRL_SET_ANIMATED_CHECK, | ||
| 19 | SD_CTRL_SET_VIDEO_PARAMS, | 20 | SD_CTRL_SET_VIDEO_PARAMS, |
| 20 | SD_CTRL_SET_VIDEO_DEF_FPS, | 21 | SD_CTRL_SET_VIDEO_DEF_FPS, |
| 21 | SD_CTRL_UPDATE_OPTS, | 22 | SD_CTRL_UPDATE_OPTS, |
| @@ -57,8 +57,9 @@ struct sd_ass_priv { · 56 unmodified lines | |||
| 57 | struct mp_osd_res osd; | 57 | struct mp_osd_res osd; |
| 58 | struct seen_packet *seen_packets; | 58 | struct seen_packet *seen_packets; |
| 59 | int num_seen_packets; | 59 | int num_seen_packets; |
| 60 | bool *packets_animated; | 60 | int *packets_animated; |
| 61 | int num_packets_animated; | 61 | int num_packets_animated; |
| 62 | bool check_animated; | ||
| 62 | bool duration_unknown; | 63 | bool duration_unknown; |
| 63 | }; | 64 | }; |
| 64 | 65 | ||
| @@ -351,19 +352,32 @@ static void filter_and_add(struct sd *sd, struct demux_packet *pkt) · 286 unmodified lines | |||
| 351 | llrint(pkt->pts * 1000), | 352 | llrint(pkt->pts * 1000), |
| 352 | llrint(pkt->duration * 1000)); | 353 | llrint(pkt->duration * 1000)); |
| 353 | 354 | ||
| 354 | // This bookkeeping is only ever needed for ASS subs | 355 | // This bookkeeping only has any practical use for ASS subs |
| 356 | // over a VO with no video. | ||
| 355 | if (!ctx->is_converted) { | 357 | if (!ctx->is_converted) { |
| 356 | if (!pkt->seen) { | 358 | if (!pkt->seen) { |
| 357 | for (int n = track->n_events - 1; n >= 0; n--) { | 359 | for (int n = track->n_events - 1; n >= 0; n--) { |
| 358 | if (n + 1 == old_n_events || pkt->animated) | 360 | if (n + 1 == old_n_events || pkt->animated == 1) |
| 359 | break; | 361 | break; |
| 360 | ASS_Event *event = &track->events[n]; | 362 | ASS_Event *event = &track->events[n]; |
| 361 | pkt->animated = (event->Effect && event->Effect[0]) || | 363 | // Might as well mark pkt->animated here with effects if we can. |
| 362 | is_animated(event->Text); | 364 | pkt->animated = (event->Effect && event->Effect[0]) ? 1 : -1; |
| 365 | if (ctx->check_animated && pkt->animated != 1) | ||
| 366 | pkt->animated = is_animated(event->Text); | ||
| 363 | } | 367 | } |
| 364 | MP_TARRAY_APPEND(ctx, ctx->packets_animated, ctx->num_packets_animated, pkt->animated); | 368 | MP_TARRAY_APPEND(ctx, ctx->packets_animated, ctx->num_packets_animated, pkt->animated); |
| 365 | } else { | 369 | } else { |
| 366 | pkt->animated = ctx->packets_animated[pkt->seen_pos]; | 370 | if (ctx->check_animated && ctx->packets_animated[pkt->seen_pos] == -1) { |
| 371 | for (int n = track->n_events - 1; n >= 0; n--) { | ||
| 372 | if (n + 1 == old_n_events || pkt->animated == 1) | ||
| 373 | break; | ||
| 374 | ASS_Event *event = &track->events[n]; | ||
| 375 | ctx->packets_animated[pkt->seen_pos] = is_animated(event->Text); | ||
| 376 | pkt->animated = ctx->packets_animated[pkt->seen_pos]; | ||
| 377 | } | ||
| 378 | } else { | ||
| 379 | pkt->animated = ctx->packets_animated[pkt->seen_pos]; | ||
| 380 | } | ||
| 367 | } | 381 | } |
| 368 | } | 382 | } |
| 369 | 383 | ||
| @@ -952,6 +966,9 @@ static int control(struct sd *sd, enum sd_ctrl cmd, void *arg) · 582 unmodified lines | |||
| 952 | a[0] += res / 1000.0 + SUB_SEEK_OFFSET; | 966 | a[0] += res / 1000.0 + SUB_SEEK_OFFSET; |
| 953 | return true; | 967 | return true; |
| 954 | } | 968 | } |
| 969 | case SD_CTRL_SET_ANIMATED_CHECK: | ||
| 970 | ctx->check_animated = *(bool *)arg; | ||
| 971 | return CONTROL_OK; | ||
| 955 | case SD_CTRL_SET_VIDEO_PARAMS: | 972 | case SD_CTRL_SET_VIDEO_PARAMS: |
| 956 | ctx->video_params = *(struct mp_image_params *)arg; | 973 | ctx->video_params = *(struct mp_image_params *)arg; |
| 957 | return CONTROL_OK; | 974 | return CONTROL_OK; |