Speed up ASS subtitles display by detecting changes between two consecutive

rendering results.


git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@21522 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
eugeni 2006-12-06 18:44:26 +00:00
parent 89e3a7b845
commit e15d11c89e
6 changed files with 114 additions and 17 deletions

View File

@ -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 //

View File

@ -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

View File

@ -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;
@ -2133,13 +2142,71 @@ 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;
}

View File

@ -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);

View File

@ -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:

View File

@ -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: