summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libass/ass.h2
-rw-r--r--libass/ass_mp.h5
-rw-r--r--libass/ass_render.c94
-rw-r--r--libmpcodecs/vf_ass.c2
-rw-r--r--libmpcodecs/vf_vo.c15
-rw-r--r--libvo/vo_gl.c13
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: