mirror of https://github.com/mpv-player/mpv
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:
parent
89e3a7b845
commit
e15d11c89e
|
@ -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 //
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
@ -2190,6 +2257,13 @@ ass_image_t* ass_render_frame(ass_renderer_t *priv, ass_track_t* track, long lon
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue