mirror of
https://github.com/mpv-player/mpv
synced 2024-10-02 16:25:33 +02:00
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 track subtitle track
|
||||||
* \param now video timestamp in milliseconds
|
* \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 //
|
// 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);
|
void ass_configure_fonts(ass_renderer_t* priv);
|
||||||
ass_library_t* ass_init();
|
ass_library_t* ass_init();
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ass_image_t* imgs;
|
||||||
|
int changed;
|
||||||
|
} mp_eosd_images_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ struct ass_renderer_s {
|
|||||||
ass_synth_priv_t* synth_priv;
|
ass_synth_priv_t* synth_priv;
|
||||||
|
|
||||||
ass_image_t* images_root; // rendering result is stored here
|
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;
|
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.
|
* 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)
|
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;
|
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)
|
static void ass_reconfigure(ass_renderer_t* priv)
|
||||||
{
|
{
|
||||||
priv->render_id = ++last_render_id;
|
priv->render_id = ++last_render_id;
|
||||||
ass_glyph_cache_reset();
|
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)
|
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)
|
static int ass_start_frame(ass_renderer_t *priv, ass_track_t* track, long long now)
|
||||||
{
|
{
|
||||||
ass_image_t* img;
|
|
||||||
|
|
||||||
ass_renderer = priv;
|
ass_renderer = priv;
|
||||||
global_settings = &priv->settings;
|
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
|
else
|
||||||
frame_context.font_scale_x = ((double)(frame_context.orig_width * track->PlayResY)) / (frame_context.orig_height * track->PlayResX);
|
frame_context.font_scale_x = ((double)(frame_context.orig_width * track->PlayResY)) / (frame_context.orig_height * track->PlayResX);
|
||||||
|
|
||||||
img = priv->images_root;
|
priv->prev_images_root = priv->images_root;
|
||||||
while (img) {
|
|
||||||
ass_image_t* next = img->next;
|
|
||||||
free(img);
|
|
||||||
img = next;
|
|
||||||
}
|
|
||||||
priv->images_root = 0;
|
priv->images_root = 0;
|
||||||
|
|
||||||
return 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
|
* \brief render a frame
|
||||||
* \param priv library handle
|
* \param priv library handle
|
||||||
* \param track track
|
* \param track track
|
||||||
* \param now current video timestamp (ms)
|
* \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;
|
int i, cnt, rc;
|
||||||
event_images_t eimg[MAX_EVENTS];
|
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;
|
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;
|
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;
|
ass_image_t* images = 0;
|
||||||
if (sub_visibility && vf->priv->ass_priv && ass_track && (pts != MP_NOPTS_VALUE))
|
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);
|
prepare_image(vf, mpi);
|
||||||
if (images) render_frame(vf, mpi, images);
|
if (images) render_frame(vf, mpi, images);
|
||||||
|
@ -26,6 +26,7 @@ struct vf_priv_s {
|
|||||||
vo_functions_t *vo;
|
vo_functions_t *vo;
|
||||||
#ifdef USE_ASS
|
#ifdef USE_ASS
|
||||||
ass_renderer_t* ass_priv;
|
ass_renderer_t* ass_priv;
|
||||||
|
int prev_visibility;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
#define video_out (vf->priv->vo)
|
#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);
|
vf->priv->ass_priv = ass_renderer_init((ass_library_t*)data);
|
||||||
if (!vf->priv->ass_priv) return CONTROL_FALSE;
|
if (!vf->priv->ass_priv) return CONTROL_FALSE;
|
||||||
ass_configure_fonts(vf->priv->ass_priv);
|
ass_configure_fonts(vf->priv->ass_priv);
|
||||||
|
vf->priv->prev_visibility = 0;
|
||||||
return CONTROL_TRUE;
|
return CONTROL_TRUE;
|
||||||
}
|
}
|
||||||
case VFCTRL_DRAW_EOSD:
|
case VFCTRL_DRAW_EOSD:
|
||||||
{
|
{
|
||||||
ass_image_t* images = 0;
|
mp_eosd_images_t images = {NULL, 2};
|
||||||
double pts = vf->priv->pts;
|
double pts = vf->priv->pts;
|
||||||
if (!vo_config_count || !vf->priv->ass_priv) return CONTROL_FALSE;
|
if (!vo_config_count || !vf->priv->ass_priv) return CONTROL_FALSE;
|
||||||
if (sub_visibility && vf->priv->ass_priv && ass_track && (pts != MP_NOPTS_VALUE)) {
|
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);
|
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);
|
images.imgs = ass_render_frame(vf->priv->ass_priv, ass_track, (pts+sub_delay) * 1000 + .5, &images.changed);
|
||||||
}
|
if (!vf->priv->prev_visibility)
|
||||||
return (video_out->control(VOCTRL_DRAW_EOSD, images) == VO_TRUE) ? CONTROL_TRUE : CONTROL_FALSE;
|
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
|
#endif
|
||||||
case VFCTRL_GET_PTS:
|
case VFCTRL_GET_PTS:
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "Gui/interface.h"
|
#include "Gui/interface.h"
|
||||||
#endif
|
#endif
|
||||||
#include "libass/ass.h"
|
#include "libass/ass.h"
|
||||||
|
#include "libass/ass_mp.h"
|
||||||
|
|
||||||
static vo_info_t info =
|
static vo_info_t info =
|
||||||
{
|
{
|
||||||
@ -246,14 +247,21 @@ static void clearEOSD(void) {
|
|||||||
* \param img image list to create OSD from.
|
* \param img image list to create OSD from.
|
||||||
* A value of NULL has the same effect as clearEOSD()
|
* 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 sx, sy;
|
||||||
int tinytexcur = 0;
|
int tinytexcur = 0;
|
||||||
int smalltexcur = 0;
|
int smalltexcur = 0;
|
||||||
GLuint *curtex;
|
GLuint *curtex;
|
||||||
GLint scale_type = (scaled_osd) ? GL_LINEAR : GL_NEAREST;
|
GLint scale_type = (scaled_osd) ? GL_LINEAR : GL_NEAREST;
|
||||||
|
ass_image_t *img = imgs->imgs;
|
||||||
ass_image_t *i;
|
ass_image_t *i;
|
||||||
int cnt;
|
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();
|
clearEOSD();
|
||||||
if (!img)
|
if (!img)
|
||||||
return;
|
return;
|
||||||
@ -307,6 +315,7 @@ static void genEOSD(ass_image_t *img) {
|
|||||||
x, y, i->w, i->h, 0);
|
x, y, i->w, i->h, 0);
|
||||||
}
|
}
|
||||||
eosdDispList = glGenLists(1);
|
eosdDispList = glGenLists(1);
|
||||||
|
skip_upload:
|
||||||
glNewList(eosdDispList, GL_COMPILE);
|
glNewList(eosdDispList, GL_COMPILE);
|
||||||
tinytexcur = smalltexcur = 0;
|
tinytexcur = smalltexcur = 0;
|
||||||
for (i = img, curtex = eosdtex; i; i = i->next) {
|
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:
|
case VOCTRL_DRAW_IMAGE:
|
||||||
return draw_image(data);
|
return draw_image(data);
|
||||||
case VOCTRL_DRAW_EOSD:
|
case VOCTRL_DRAW_EOSD:
|
||||||
|
if (!data)
|
||||||
|
return VO_FALSE;
|
||||||
genEOSD(data);
|
genEOSD(data);
|
||||||
return VO_TRUE;
|
return VO_TRUE;
|
||||||
case VOCTRL_GET_EOSD_RES:
|
case VOCTRL_GET_EOSD_RES:
|
||||||
|
Loading…
Reference in New Issue
Block a user