Mercurial > mplayer.hg
changeset 21506:8174acbf0633
Speed up ASS subtitles display by detecting changes between two consecutive
rendering results.
author | eugeni |
---|---|
date | Wed, 06 Dec 2006 18:44:26 +0000 |
parents | 47a16f0da01c |
children | fa99b3d31d13 |
files | libass/ass.h libass/ass_mp.h libass/ass_render.c libmpcodecs/vf_ass.c libmpcodecs/vf_vo.c libvo/vo_gl.c |
diffstat | 6 files changed, 114 insertions(+), 17 deletions(-) [+] |
line wrap: on
line diff
--- a/libass/ass.h Wed Dec 06 18:16:02 2006 +0000 +++ b/libass/ass.h Wed Dec 06 18:44:26 2006 +0000 @@ -89,7 +89,7 @@ * \param track subtitle track * \param now video timestamp in milliseconds */ -ass_image_t* ass_render_frame(ass_renderer_t *priv, ass_track_t* track, long long now); +ass_image_t* ass_render_frame(ass_renderer_t *priv, ass_track_t* track, long long now, int* detect_change); // The following functions operate on track objects and do not need an ass_renderer //
--- a/libass/ass_mp.h Wed Dec 06 18:16:02 2006 +0000 +++ b/libass/ass_mp.h Wed Dec 06 18:44:26 2006 +0000 @@ -44,5 +44,10 @@ void ass_configure_fonts(ass_renderer_t* priv); ass_library_t* ass_init(); +typedef struct { + ass_image_t* imgs; + int changed; +} mp_eosd_images_t; + #endif
--- a/libass/ass_render.c Wed Dec 06 18:16:02 2006 +0000 +++ b/libass/ass_render.c Wed Dec 06 18:44:26 2006 +0000 @@ -70,6 +70,7 @@ ass_synth_priv_t* synth_priv; ass_image_t* images_root; // rendering result is stored here + ass_image_t* prev_images_root; }; typedef enum {EF_NONE = 0, EF_KARAOKE, EF_KARAOKE_KF, EF_KARAOKE_KO} effect_t; @@ -372,7 +373,7 @@ } /** - * \brief Render text_info_t struct into ass_images_t list + * \brief Render text_info_t struct into ass_image_t list * Rasterize glyphs and put them in glyph cache. */ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) @@ -1864,10 +1865,25 @@ return 0; } +/** + * \brief deallocate image list + * \param img list pointer + */ +void ass_free_images(ass_image_t* img) +{ + while (img) { + ass_image_t* next = img->next; + free(img); + img = next; + } +} + static void ass_reconfigure(ass_renderer_t* priv) { priv->render_id = ++last_render_id; ass_glyph_cache_reset(); + ass_free_images(priv->prev_images_root); + priv->prev_images_root = 0; } void ass_set_frame_size(ass_renderer_t* priv, int w, int h) @@ -1938,8 +1954,6 @@ */ static int ass_start_frame(ass_renderer_t *priv, ass_track_t* track, long long now) { - ass_image_t* img; - ass_renderer = priv; global_settings = &priv->settings; @@ -1965,12 +1979,7 @@ else frame_context.font_scale_x = ((double)(frame_context.orig_width * track->PlayResY)) / (frame_context.orig_height * track->PlayResX); - img = priv->images_root; - while (img) { - ass_image_t* next = img->next; - free(img); - img = next; - } + priv->prev_images_root = priv->images_root; priv->images_root = 0; return 0; @@ -2134,12 +2143,70 @@ } /** + * \brief compare two images + * \param i1 first image + * \param i2 second image + * \return 0 if identical, 1 if different positions, 2 if different content + */ +int ass_image_compare(ass_image_t *i1, ass_image_t *i2) +{ + if (i1->w != i2->w) return 2; + if (i1->h != i2->h) return 2; + if (i1->stride != i2->stride) return 2; + if (i1->color != i2->color) return 2; + if (i1->bitmap != i2->bitmap) + return 2; + if (i1->dst_x != i2->dst_x) return 1; + if (i1->dst_y != i2->dst_y) return 1; + return 0; +} + +/** + * \brief compare current and previous image list + * \param priv library handle + * \return 0 if identical, 1 if different positions, 2 if different content + */ +int ass_detect_change(ass_renderer_t *priv) +{ + ass_image_t* img, *img2; + int diff; + + img = priv->prev_images_root; + img2 = priv->images_root; + diff = 0; + while (img && diff < 2) { + ass_image_t* next, *next2; + next = img->next; + if (img2) { + int d = ass_image_compare(img, img2); + if (d > diff) diff = d; + next2 = img2->next; + } else { + // previous list is shorter + diff = 2; + break; + } + img = next; + img2 = next2; + } + + // is the previous list longer? + if (img2) + diff = 2; + + return diff; +} + +/** * \brief render a frame * \param priv library handle * \param track track * \param now current video timestamp (ms) + * \param detect_change a value describing how the new images differ from the previous ones will be written here: + * 0 if identical, 1 if different positions, 2 if different content. + * Can be NULL, in that case no detection is performed. */ -ass_image_t* ass_render_frame(ass_renderer_t *priv, ass_track_t* track, long long now) +ass_image_t* ass_render_frame(ass_renderer_t *priv, ass_track_t* track, long long now, int* detect_change) { int i, cnt, rc; event_images_t eimg[MAX_EVENTS]; @@ -2189,7 +2256,14 @@ cur = cur->next; } } + + if (detect_change) + *detect_change = ass_detect_change(priv); + // free the previous image list + ass_free_images(priv->prev_images_root); + priv->prev_images_root = 0; + return ass_renderer->images_root; }
--- a/libmpcodecs/vf_ass.c Wed Dec 06 18:16:02 2006 +0000 +++ b/libmpcodecs/vf_ass.c Wed Dec 06 18:44:26 2006 +0000 @@ -326,7 +326,7 @@ { ass_image_t* images = 0; if (sub_visibility && vf->priv->ass_priv && ass_track && (pts != MP_NOPTS_VALUE)) - images = ass_render_frame(vf->priv->ass_priv, ass_track, (pts+sub_delay) * 1000 + .5); + images = ass_render_frame(vf->priv->ass_priv, ass_track, (pts+sub_delay) * 1000 + .5, NULL); prepare_image(vf, mpi); if (images) render_frame(vf, mpi, images);
--- a/libmpcodecs/vf_vo.c Wed Dec 06 18:16:02 2006 +0000 +++ b/libmpcodecs/vf_vo.c Wed Dec 06 18:44:26 2006 +0000 @@ -26,6 +26,7 @@ vo_functions_t *vo; #ifdef USE_ASS ass_renderer_t* ass_priv; + int prev_visibility; #endif }; #define video_out (vf->priv->vo) @@ -116,11 +117,12 @@ vf->priv->ass_priv = ass_renderer_init((ass_library_t*)data); if (!vf->priv->ass_priv) return CONTROL_FALSE; ass_configure_fonts(vf->priv->ass_priv); + vf->priv->prev_visibility = 0; return CONTROL_TRUE; } case VFCTRL_DRAW_EOSD: { - ass_image_t* images = 0; + mp_eosd_images_t images = {NULL, 2}; double pts = vf->priv->pts; if (!vo_config_count || !vf->priv->ass_priv) return CONTROL_FALSE; if (sub_visibility && vf->priv->ass_priv && ass_track && (pts != MP_NOPTS_VALUE)) { @@ -132,9 +134,14 @@ ass_set_aspect_ratio(vf->priv->ass_priv, (double)res.w / res.h); } - images = ass_render_frame(vf->priv->ass_priv, ass_track, (pts+sub_delay) * 1000 + .5); - } - return (video_out->control(VOCTRL_DRAW_EOSD, images) == VO_TRUE) ? CONTROL_TRUE : CONTROL_FALSE; + images.imgs = ass_render_frame(vf->priv->ass_priv, ass_track, (pts+sub_delay) * 1000 + .5, &images.changed); + if (!vf->priv->prev_visibility) + images.changed = 2; + vf->priv->prev_visibility = 1; + } else + vf->priv->prev_visibility = 0; + vf->priv->prev_visibility = sub_visibility; + return (video_out->control(VOCTRL_DRAW_EOSD, &images) == VO_TRUE) ? CONTROL_TRUE : CONTROL_FALSE; } #endif case VFCTRL_GET_PTS:
--- a/libvo/vo_gl.c Wed Dec 06 18:16:02 2006 +0000 +++ b/libvo/vo_gl.c Wed Dec 06 18:44:26 2006 +0000 @@ -17,6 +17,7 @@ #include "Gui/interface.h" #endif #include "libass/ass.h" +#include "libass/ass_mp.h" static vo_info_t info = { @@ -246,14 +247,21 @@ * \param img image list to create OSD from. * A value of NULL has the same effect as clearEOSD() */ -static void genEOSD(ass_image_t *img) { +static void genEOSD(mp_eosd_images_t *imgs) { int sx, sy; int tinytexcur = 0; int smalltexcur = 0; GLuint *curtex; GLint scale_type = (scaled_osd) ? GL_LINEAR : GL_NEAREST; + ass_image_t *img = imgs->imgs; ass_image_t *i; int cnt; + + if (imgs->changed == 0) // there are elements, but they are unchanged + return; + if (img && imgs->changed == 1) // there are elements, but they just moved + goto skip_upload; + clearEOSD(); if (!img) return; @@ -307,6 +315,7 @@ x, y, i->w, i->h, 0); } eosdDispList = glGenLists(1); +skip_upload: glNewList(eosdDispList, GL_COMPILE); tinytexcur = smalltexcur = 0; for (i = img, curtex = eosdtex; i; i = i->next) { @@ -936,6 +945,8 @@ case VOCTRL_DRAW_IMAGE: return draw_image(data); case VOCTRL_DRAW_EOSD: + if (!data) + return VO_FALSE; genEOSD(data); return VO_TRUE; case VOCTRL_GET_EOSD_RES: