diff options
-rw-r--r-- | libass/ass.h | 2 | ||||
-rw-r--r-- | libass/ass_mp.h | 5 | ||||
-rw-r--r-- | libass/ass_render.c | 94 | ||||
-rw-r--r-- | libmpcodecs/vf_ass.c | 2 | ||||
-rw-r--r-- | libmpcodecs/vf_vo.c | 15 | ||||
-rw-r--r-- | libvo/vo_gl.c | 13 |
6 files changed, 114 insertions, 17 deletions
diff --git a/libass/ass.h b/libass/ass.h index ba9a41104b..7cba671ffd 100644 --- a/libass/ass.h +++ b/libass/ass.h @@ -89,7 +89,7 @@ int ass_set_fonts(ass_renderer_t* priv, const char* default_font, const char* d * \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 // diff --git a/libass/ass_mp.h b/libass/ass_mp.h index 28c83b6a02..ac9bacc0bd 100644 --- a/libass/ass_mp.h +++ b/libass/ass_mp.h @@ -44,5 +44,10 @@ void ass_configure(ass_renderer_t* priv, int w, int h); 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 diff --git a/libass/ass_render.c b/libass/ass_render.c index 60189d1d1d..25db5164d9 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -70,6 +70,7 @@ struct ass_renderer_s { 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 @@ static ass_image_t** render_glyph(bitmap_t* bm, int dst_x, int dst_y, uint32_t c } /** - * \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 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images) 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 @@ int ass_set_fonts(ass_renderer_t* priv, const char* default_font, const char* de */ 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 @@ static int ass_start_frame(ass_renderer_t *priv, ass_track_t* track, long long n 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 @@ static void fix_collisions(event_images_t* imgs, int cnt) } /** + * \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 @@ ass_image_t* ass_render_frame(ass_renderer_t *priv, ass_track_t* track, long lon 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; } diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index 88fbd2eab5..04f131d4cb 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -326,7 +326,7 @@ static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts) { 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); diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c index 8d9b8e97d2..bb4d1bb87d 100644 --- a/libmpcodecs/vf_vo.c +++ b/libmpcodecs/vf_vo.c @@ -26,6 +26,7 @@ struct vf_priv_s { 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 @@ static int control(struct vf_instance_s* vf, int request, void* data) 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 @@ static int control(struct vf_instance_s* vf, int request, void* data) 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: diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index 4f0fff99fa..4657363765 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -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 @@ static void clearEOSD(void) { * \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 @@ static void genEOSD(ass_image_t *img) { 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 @@ static int control(uint32_t request, void *data, ...) 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: |