# HG changeset patch # User cigaes # Date 1286702831 0 # Node ID b4c3659d16b120aa2ba15d3211fe65d31f26df90 # Parent b33aed46ecda4359c5bd8b876c0825f964a278f3 Use a dynamic list for the sources of EOSD elements. diff -r b33aed46ecda -r b4c3659d16b1 ass_mp.c --- a/ass_mp.c Sat Oct 09 17:52:35 2010 +0000 +++ b/ass_mp.c Sun Oct 10 09:27:11 2010 +0000 @@ -28,6 +28,9 @@ #include "subreader.h" #include "ass_mp.h" +#include "eosd.h" +#include "mpcommon.h" +#include "libvo/sub.h" #include "help_mp.h" #include "libvo/font_load.h" #include "stream/stream.h" @@ -313,3 +316,63 @@ } return ass_render_frame(priv, track, now, detect_change); } + +/* EOSD source for ASS subtitles. */ + +static ASS_Renderer *ass_renderer; +static int prev_visibility; + +static void eosd_ass_update(struct mp_eosd_source *src, const struct mp_eosd_settings *res, double ts) +{ + long long ts_ms = (ts + sub_delay) * 1000 + .5; + ASS_Image *aimg; + struct mp_eosd_image *img; + if (res->changed) { + double dar = (double) (res->w - res->ml - res->mr) / (res->h - res->mt - res->mb); + ass_configure(ass_renderer, res->w, res->h, res->unscaled); + ass_set_margins(ass_renderer, res->mt, res->mb, res->ml, res->mr); + ass_set_aspect_ratio(ass_renderer, dar, (double)res->srcw / res->srch); + } + aimg = sub_visibility && ass_track && ts != MP_NOPTS_VALUE ? + ass_mp_render_frame(ass_renderer, ass_track, ts_ms, &src->changed) : + NULL; + if (!aimg != !src->images) + src->changed = 2; + if (src->changed) { + eosd_image_remove_all(src); + while (aimg) { + img = eosd_image_alloc(); + img->w = aimg->w; + img->h = aimg->h; + img->bitmap = aimg->bitmap; + img->stride = aimg->stride; + img->color = aimg->color; + img->dst_x = aimg->dst_x; + img->dst_y = aimg->dst_y; + eosd_image_append(src, img); + aimg = aimg->next; + } + } + prev_visibility = sub_visibility; +} + +static void eosd_ass_uninit(struct mp_eosd_source *src) +{ + eosd_image_remove_all(src); + ass_renderer_done(ass_renderer); +} + +static struct mp_eosd_source eosd_ass = { + .uninit = eosd_ass_uninit, + .update = eosd_ass_update, + .z_index = 10, +}; + +void eosd_ass_init(ASS_Library *ass_library) +{ + ass_renderer = ass_renderer_init(ass_library); + if (!ass_renderer) + return; + ass_configure_fonts(ass_renderer); + eosd_register(&eosd_ass); +} diff -r b33aed46ecda -r b4c3659d16b1 ass_mp.h --- a/ass_mp.h Sat Oct 09 17:52:35 2010 +0000 +++ b/ass_mp.h Sun Oct 10 09:27:11 2010 +0000 @@ -62,4 +62,9 @@ extern int ass_force_reload; ASS_Image* ass_mp_render_frame(ASS_Renderer *priv, ASS_Track* track, long long now, int* detect_change); +/** + * Initialize the use of EOSD for ASS subtitles rendering. + */ +void eosd_ass_init(ASS_Library *library); + #endif /* MPLAYER_ASS_MP_H */ diff -r b33aed46ecda -r b4c3659d16b1 eosd.c --- a/eosd.c Sat Oct 09 17:52:35 2010 +0000 +++ b/eosd.c Sun Oct 10 09:27:11 2010 +0000 @@ -26,54 +26,134 @@ #include "ass_mp.h" #include "eosd.h" -#ifdef CONFIG_ASS -static ASS_Renderer *ass_renderer; -int prev_visibility; - -void eosd_ass_init(ASS_Library *ass_library) -{ - ass_renderer = ass_renderer_init(ass_library); - if (!ass_renderer) - return; - ass_configure_fonts(ass_renderer); -} -#endif +static struct mp_eosd_source *sources; +static struct mp_eosd_settings settings; +static struct mp_eosd_image *image_pool; void eosd_init(vf_instance_t *vf) { vf->control(vf, VFCTRL_INIT_EOSD, NULL); } -void eosd_configure(mp_eosd_res_t *res, int hinting) +void eosd_register(struct mp_eosd_source *src) { -#ifdef CONFIG_ASS - double dar = (double) (res->w - res->ml - res->mr) / (res->h - res->mt - res->mb); - if (ass_renderer) { - ass_configure(ass_renderer, res->w, res->h, hinting); - ass_set_margins(ass_renderer, res->mt, res->mb, res->ml, res->mr); - ass_set_aspect_ratio(ass_renderer, dar, (double)res->srcw/res->srch); - } -#endif + struct mp_eosd_source *p, **prev = &sources; + for (p = sources; p && p->z_index < src->z_index; p = p->priv_next) + prev = &p->priv_next; + src->priv_next = p; + *prev = src; } -ASS_Image *eosd_render_frame(double ts, int *changed) +void eosd_configure(struct mp_eosd_settings *res) { - ASS_Image *r = NULL; -#ifdef CONFIG_ASS - if (sub_visibility && ass_renderer && ass_track && ts != MP_NOPTS_VALUE) { - r = ass_mp_render_frame(ass_renderer, ass_track, (ts+sub_delay) * 1000 + .5, changed); - if (!prev_visibility && changed) - *changed = 2; + if (res->w != settings.w || + res->h != settings.h || + res->srcw != settings.srcw || + res->srch != settings.srch || + res->mt != settings.mt || + res->mt != settings.mb || + res->mt != settings.ml || + res->mt != settings.mr || + res->unscaled != settings.unscaled) { + settings = *res; + settings.changed = 1; } - prev_visibility = sub_visibility; -#endif - return r; +} + +void eosd_render_frame(double ts, struct mp_eosd_image_list *images) +{ + struct mp_eosd_source *src; + int changed = 0; + for (src = sources; src; src = src->priv_next) { + if (src->update) + src->update(src, &settings, ts); + changed |= src->changed; + src->changed = 0; + } + settings.changed = 0; + images->first_source = sources; + images->changed = changed; } void eosd_uninit(void) { -#ifdef CONFIG_ASS - if (ass_renderer) - ass_renderer_done(ass_renderer); -#endif + struct mp_eosd_source *src; + for (src = sources; src; src = src->priv_next) + if (src->uninit) + src->uninit(src); +} + +struct mp_eosd_image *eosd_image_alloc(void) +{ + struct mp_eosd_image *r; + if (!image_pool) { + const unsigned n_alloc = 127; /* arbitrary */ + unsigned i; + image_pool = calloc(n_alloc, sizeof(*image_pool)); + for (i = 0; i < n_alloc - 1; i++) + image_pool[i].next = image_pool + i + 1; + image_pool[i].next = NULL; + } + r = image_pool; + image_pool = image_pool->next; + return r; +} + +void eosd_image_free(struct mp_eosd_image *image) +{ + image->next = image_pool; + image_pool = image; +} + +void eosd_image_append(struct mp_eosd_source *source, + struct mp_eosd_image *image) +{ + image->next = NULL; + *source->images_tail = image; + source->images_tail = &image->next; } + +void eosd_image_remove(struct mp_eosd_source *source, + struct mp_eosd_image *image, + struct mp_eosd_image **prev) +{ + *prev = image->next; + if (!*prev) + source->images_tail = prev; + eosd_image_free(image); +} + +void eosd_image_remove_all(struct mp_eosd_source *source) +{ + struct mp_eosd_image *image; + + while (source->images) { + image = source->images; + source->images = source->images->next; + eosd_image_free(image); + } + source->images_tail = &source->images; +} + +static void next_image_in_sources(struct mp_eosd_image_list *images, + struct mp_eosd_source *src) +{ + images->source = src; + while (images->source && !images->source->images) + images->source = images->source->priv_next; + images->image = images->source ? images->source->images : NULL; +} + +struct mp_eosd_image *eosd_image_first(struct mp_eosd_image_list *images) +{ + next_image_in_sources(images, images->first_source); + return images->image; +} + +struct mp_eosd_image *eosd_image_next(struct mp_eosd_image_list *images) +{ + images->image = images->image->next; + if (!images->image) + next_image_in_sources(images, images->source->priv_next); + return images->image; +} diff -r b33aed46ecda -r b4c3659d16b1 eosd.h --- a/eosd.h Sat Oct 09 17:52:35 2010 +0000 +++ b/eosd.h Sun Oct 10 09:27:11 2010 +0000 @@ -22,9 +22,84 @@ #ifndef MPLAYER_EOSD_H #define MPLAYER_EOSD_H +#include #include "libmpcodecs/vf.h" -#include "libvo/video_out.h" -#include "ass_mp.h" + +enum { + EOSD_CHANGED_LAYOUT = 0x1, + EOSD_CHANGED_BITMAP = 0x2, +}; + +struct mp_eosd_settings { + int w, h; ///< screen dimensions, including black borders + int srcw, srch; ///< unscaled source dimensions + int mt, mb, ml, mr; ///< borders (top, bottom, left, right) + int unscaled; ///< EOSD objects are rendered at native resolution + int changed; ///< settings have changed since last update +}; + +struct mp_eosd_image { + struct mp_eosd_image *next; ///< Next image, or NULL + uint8_t *bitmap; ///< 1bpp stride*h alpha buffer + void *opaque; ///< Arbitrary value for the client's use + int w, h; ///< Bitmap width, height + int stride; ///< Bitmap stride + uint32_t color; ///< Bitmap color and transparency, RGBT + /// T is the complement of A (alpha=opacity). + int dst_x, dst_y; ///< Bitmap placement inside the video frame +}; + +struct mp_eosd_source { + + /** + * Linked list of images element. + * The client is responsible for initializing and maintaining this list. + * It can alter it at any time in the main MPlayer thread. + */ + struct mp_eosd_image *images; + + /** + * Pointer to the next field of the last image, or to images if the list + * is empty. + * The client is not required to handle this field, but list + * manipulation functions (see below) use it. + */ + struct mp_eosd_image **images_tail; + + /** + * Callback to update the images. Can be NULL. + */ + void (*update)(struct mp_eosd_source *, const struct mp_eosd_settings *, + double); + + /** + * Callback to uninit the source. Can be NULL. + */ + void (*uninit)(struct mp_eosd_source *); + + /** + * Changed flags of the images. + * The client must set it to a combination of EOSD_CHANGED_* whenever + * the images are altered. + * The core EOSD system resets it. + */ + int changed; + + /** + * Z-index of the images. + * Images with a higher Z-index are rendered on top. + */ + int z_index; + + struct mp_eosd_source *priv_next; +}; + +struct mp_eosd_image_list { + struct mp_eosd_source *first_source; + struct mp_eosd_source *source; + struct mp_eosd_image *image; + int changed; +}; /** * Initialize the EOSD subsystem. @@ -39,22 +114,22 @@ * settings change. * * @param res resolution and margins of the rendering area. - * @param hinting nonzero if hinting is useful. */ -void eosd_configure(mp_eosd_res_t *res, int hinting); +void eosd_configure(struct mp_eosd_settings *res); /** * Renders the EOSD elements for the current frame. * Should be called by the rendering engine when it is about to do or * prepare the rendering. * - * @param ts presentation timestamp of the frame. - * @param changed if not NULL, will be set to 0 if the elements are - * identical since the last call, 1 if they have changed - * only in coordinates, and 2 if they have really changed. - * @return a linked list of EOSD elements. + * @param[in] ts presentation timestamp of the frame. + * @param[out] images list of images to render. + * The list and list elements are only valid until any + * client alter them. + * The renderer should therefore not call anything that + * may alter the EOSD elements. */ -struct ass_image *eosd_render_frame(double ts, int *changed); +void eosd_render_frame(double ts, struct mp_eosd_image_list *images); /** * Shut down the EOSD subsystem and free the associated resources. @@ -62,8 +137,56 @@ void eosd_uninit(void); /** - * Initialize the use of EOSD for ASS subtitles rendering. + * Register a source of EOSD images. + */ +void eosd_register(struct mp_eosd_source *source); + +/** + * Allocate a structure for an EOSD image. + */ +struct mp_eosd_image *eosd_image_alloc(void); + +/** + * Free a previously allocated structure. + */ +void eosd_image_free(struct mp_eosd_image *image); + +/** + * Append an image to the list of images associated to a source. + * This function requires that the images_tail pointer is correctly set. */ -void eosd_ass_init(ASS_Library *ass_library); +void eosd_image_append(struct mp_eosd_source *source, + struct mp_eosd_image *image); + +/** + * Remove an image from the list of images associated to a source. + * The image structure is freed using eosd_image_free. + * + * @param source source where the image is. + * @param image image to remove. + * @param prev pointeur to the prev field of the previous image, + * or to source->images if this is the first image. + */ +void eosd_image_remove(struct mp_eosd_source *source, + struct mp_eosd_image *image, + struct mp_eosd_image **prev); + +/** + * Remove all images associated to a source and free the corresponding + * structures. + * This function also resets the images_tail pointer. + */ +void eosd_image_remove_all(struct mp_eosd_source *source); + +/** + * Reset the cursor of an image list and get the first image. + */ +struct mp_eosd_image *eosd_image_first(struct mp_eosd_image_list *images); + +/** + * Get the next image in an image list. + * The renderer must NOT use the next field in the image structure. + */ +struct mp_eosd_image *eosd_image_next(struct mp_eosd_image_list *images); #endif /* MPLAYER_EOSD_H */ diff -r b33aed46ecda -r b4c3659d16b1 libmpcodecs/vf_ass.c --- a/libmpcodecs/vf_ass.c Sat Oct 09 17:52:35 2010 +0000 +++ b/libmpcodecs/vf_ass.c Sun Oct 10 09:27:11 2010 +0000 @@ -37,7 +37,6 @@ #include "libvo/fastmemcpy.h" #include "libvo/sub.h" -#include "libvo/video_out.h" #include "m_option.h" #include "m_struct.h" @@ -71,7 +70,7 @@ int width, int height, int d_width, int d_height, unsigned int flags, unsigned int outfmt) { - mp_eosd_res_t res = { 0 }; + struct mp_eosd_settings res = {0}; if (outfmt == IMGFMT_IF09) return 0; @@ -94,7 +93,7 @@ res.srch = height; res.mt = ass_top_margin; res.mb = ass_bottom_margin; - eosd_configure(&res, 0); + eosd_configure(&res); return vf_next_config(vf, vf->priv->outw, vf->priv->outh, d_width, d_height, flags, outfmt); @@ -334,29 +333,29 @@ } } -static int render_frame(struct vf_instance *vf, mp_image_t *mpi, - const ASS_Image *img) +static void render_frame(struct vf_instance *vf, mp_image_t *mpi, + struct mp_eosd_image_list *images) { - if (img) { + struct mp_eosd_image *img; + img = eosd_image_first(images); + if (!img) + return; memset(vf->priv->dirty_rows, 0, vf->priv->outh); // reset dirty rows while (img) { copy_from_image(vf, img->dst_y, img->dst_y + img->h); my_draw_bitmap(vf, img->bitmap, img->w, img->h, img->stride, img->dst_x, img->dst_y, img->color); - img = img->next; + img = eosd_image_next(images); } copy_to_image(vf); - } - return 0; } static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) { - ASS_Image *images = eosd_render_frame(pts, NULL); + struct mp_eosd_image_list images; + eosd_render_frame(pts, &images); prepare_image(vf, mpi); - if (images) - render_frame(vf, mpi, images); - + render_frame(vf, mpi, &images); return vf_next_put_image(vf, vf->dmpi, pts); } diff -r b33aed46ecda -r b4c3659d16b1 libmpcodecs/vf_vo.c --- a/libmpcodecs/vf_vo.c Sat Oct 09 17:52:35 2010 +0000 +++ b/libmpcodecs/vf_vo.c Sun Oct 10 09:27:11 2010 +0000 @@ -28,6 +28,7 @@ #include "libvo/sub.h" #include "libvo/video_out.h" +#include "eosd.h" #include "eosd.h" @@ -123,13 +124,14 @@ } case VFCTRL_DRAW_EOSD: { - EOSD_ImageList images = {NULL, 2}; - mp_eosd_res_t res = {0}; + struct mp_eosd_image_list images; + struct mp_eosd_settings res = {0}; double pts = vf->priv->pts; if (!vo_config_count) return CONTROL_FALSE; + res.unscaled = !!(vf->default_caps & VFCAP_EOSD_UNSCALED); if (video_out->control(VOCTRL_GET_EOSD_RES, &res) == VO_TRUE) - eosd_configure(&res, !!(vf->default_caps & VFCAP_EOSD_UNSCALED)); - images.imgs = eosd_render_frame(pts, &images.changed); + eosd_configure(&res); + eosd_render_frame(pts, &images); return (video_out->control(VOCTRL_DRAW_EOSD, &images) == VO_TRUE) ? CONTROL_TRUE : CONTROL_FALSE; } #endif diff -r b33aed46ecda -r b4c3659d16b1 libvo/video_out.h --- a/libvo/video_out.h Sat Oct 09 17:52:35 2010 +0000 +++ b/libvo/video_out.h Sun Oct 10 09:27:11 2010 +0000 @@ -74,11 +74,6 @@ #define VOCTRL_BORDER 27 #define VOCTRL_DRAW_EOSD 28 #define VOCTRL_GET_EOSD_RES 29 -typedef struct { - int w, h; // screen dimensions, including black borders - int srcw, srch; // unscaled source dimensions - int mt, mb, ml, mr; // borders (top, bottom, left, right) -} mp_eosd_res_t; #define VOCTRL_SET_DEINTERLACE 30 #define VOCTRL_GET_DEINTERLACE 31 diff -r b33aed46ecda -r b4c3659d16b1 libvo/vo_gl.c --- a/libvo/vo_gl.c Sat Oct 09 17:52:35 2010 +0000 +++ b/libvo/vo_gl.c Sun Oct 10 09:27:11 2010 +0000 @@ -38,6 +38,7 @@ #include "gl_common.h" #include "aspect.h" #include "fastmemcpy.h" +#include "eosd.h" #ifdef CONFIG_GL_SDL #ifdef CONFIG_SDL_SDL_H @@ -313,11 +314,11 @@ eosdtex = NULL; } -static inline int is_tinytex(ASS_Image *i, int tinytexcur) { +static inline int is_tinytex(struct mp_eosd_image *i, int tinytexcur) { return i->w < TINYTEX_SIZE && i->h < TINYTEX_SIZE && tinytexcur < TINYTEX_MAX; } -static inline int is_smalltex(ASS_Image *i, int smalltexcur) { +static inline int is_smalltex(struct mp_eosd_image *i, int smalltexcur) { return i->w < SMALLTEX_SIZE && i->h < SMALLTEX_SIZE && smalltexcur < SMALLTEX_MAX; } @@ -336,14 +337,14 @@ * \param img image list to create OSD from. * A value of NULL has the same effect as clearEOSD() */ -static void genEOSD(EOSD_ImageList *imgs) { +static void genEOSD(struct mp_eosd_image_list *imgs) { int sx, sy; int tinytexcur = 0; int smalltexcur = 0; GLuint *curtex; GLint scale_type = scaled_osd ? GL_LINEAR : GL_NEAREST; - ASS_Image *img = imgs->imgs; - ASS_Image *i; + struct mp_eosd_image *img = eosd_image_first(imgs); + struct mp_eosd_image *i; if (imgs->changed == 0) // there are elements, but they are unchanged return; @@ -360,7 +361,7 @@ mpglBindTexture(gl_target, largeeosdtex[1]); glCreateClearTex(gl_target, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, scale_type, LARGE_EOSD_TEX_SIZE, LARGE_EOSD_TEX_SIZE, 0); } - for (i = img; i; i = i->next) + for (i = img; i; i = eosd_image_next(imgs)) { if (i->w <= 0 || i->h <= 0 || i->stride < i->w) continue; @@ -378,7 +379,7 @@ mpglGenTextures(eosdtexCnt, eosdtex); } tinytexcur = smalltexcur = 0; - for (i = img, curtex = eosdtex; i; i = i->next) { + for (i = eosd_image_first(imgs), curtex = eosdtex; i; i = eosd_image_next(imgs)) { int x = 0, y = 0; if (i->w <= 0 || i->h <= 0 || i->stride < i->w) { mp_msg(MSGT_VO, MSGL_V, "Invalid dimensions OSD for part!\n"); @@ -404,7 +405,7 @@ skip_upload: mpglNewList(eosdDispList, GL_COMPILE); tinytexcur = smalltexcur = 0; - for (i = img, curtex = eosdtex; i; i = i->next) { + for (i = eosd_image_first(imgs), curtex = eosdtex; i; i = eosd_image_next(imgs)) { int x = 0, y = 0; if (i->w <= 0 || i->h <= 0 || i->stride < i->w) continue; @@ -1323,7 +1324,7 @@ return VO_TRUE; case VOCTRL_GET_EOSD_RES: { - mp_eosd_res_t *r = data; + struct mp_eosd_settings *r = data; r->w = vo_dwidth; r->h = vo_dheight; r->srcw = image_width; r->srch = image_height; r->mt = r->mb = r->ml = r->mr = 0; diff -r b33aed46ecda -r b4c3659d16b1 libvo/vo_vdpau.c --- a/libvo/vo_vdpau.c Sat Oct 09 17:52:35 2010 +0000 +++ b/libvo/vo_vdpau.c Sun Oct 10 09:27:11 2010 +0000 @@ -43,6 +43,7 @@ #include "aspect.h" #include "font_load.h" #include "sub.h" +#include "eosd.h" #include "subopt-helper.h" #include "libavcodec/vdpau.h" @@ -854,13 +855,13 @@ } } -static void generate_eosd(EOSD_ImageList *imgs) +static void generate_eosd(struct mp_eosd_image_list *imgs) { VdpStatus vdp_st; VdpRect destRect; int j, found; - ASS_Image *img = imgs->imgs; - ASS_Image *i; + struct mp_eosd_image *img = eosd_image_first(imgs); + struct mp_eosd_image *i; // Nothing changed, no need to redraw if (imgs->changed == 0) @@ -876,7 +877,7 @@ for (j = 0; j < eosd_surface_count; j++) eosd_surfaces[j].in_use = 0; - for (i = img; i; i = i->next) { + for (i = img; i; i = eosd_image_next(imgs)) { // Try to reuse a suitable surface found = -1; for (j = 0; j < eosd_surface_count; j++) { @@ -927,7 +928,7 @@ eosd_skip_upload: eosd_render_count = 0; - for (i = img; i; i = i->next) { + for (i = eosd_image_first(imgs); i; i = eosd_image_next(imgs)) { // Render dest, color, etc. eosd_targets[eosd_render_count].color.alpha = 1.0 - ((i->color >> 0) & 0xff) / 255.0; eosd_targets[eosd_render_count].color.blue = ((i->color >> 8) & 0xff) / 255.0; @@ -1400,7 +1401,7 @@ draw_eosd(); return VO_TRUE; case VOCTRL_GET_EOSD_RES: { - mp_eosd_res_t *r = data; + struct mp_eosd_settings *r = data; r->mt = r->mb = r->ml = r->mr = 0; r->srcw = vid_width; r->srch = vid_height; if (vo_fs) {