>From a8013803c3a6763ae2a2a97b5398e580487998a4 Mon Sep 17 00:00:00 2001 From: Grigori Goronzy Date: Tue, 21 Jul 2009 23:05:40 +0200 Subject: [PATCH] Support standalone libass. --- Makefile | 10 +-- ass_mp.c | 296 ++++++++++++++++++++++++++++++++++++++++++++++++ ass_mp.h | 60 ++++++++++ command.c | 3 +- configure | 32 ++---- libmpcodecs/vf_ass.c | 7 +- libmpcodecs/vf_vo.c | 11 ++- libmpdemux/demux_mkv.c | 3 +- libmpdemux/demuxer.c | 3 +- libvo/vo_gl.c | 23 +++- libvo/vo_vdpau.c | 26 ++++- mencoder.c | 3 +- mpcommon.c | 3 +- mplayer.c | 3 +- 14 files changed, 424 insertions(+), 59 deletions(-) create mode 100644 ass_mp.c create mode 100644 ass_mp.h diff --git a/Makefile b/Makefile index cacc837..575ea28 100644 --- a/Makefile +++ b/Makefile @@ -125,15 +125,7 @@ SRCS_COMMON-$(LIBA52_INTERNAL) += liba52/crc.c \ liba52/imdct.c \ liba52/parse.c \ -SRCS_COMMON-$(LIBASS) += libass/ass.c \ - libass/ass_bitmap.c \ - libass/ass_cache.c \ - libass/ass_font.c \ - libass/ass_fontconfig.c \ - libass/ass_library.c \ - libass/ass_mp.c \ - libass/ass_render.c \ - libass/ass_utils.c \ +SRCS_COMMON-$(LIBASS) += ass_mp.c \ libmpcodecs/vf_ass.c \ SRCS_COMMON-$(LIBAVCODEC) += av_opts.c \ diff --git a/ass_mp.c b/ass_mp.c new file mode 100644 index 0000000..d957e0c --- /dev/null +++ b/ass_mp.c @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2006 Evgeniy Stepanov + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with libass; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +#include "mp_msg.h" +#include "get_path.h" + +#include "subreader.h" +#include +#include + +#ifdef CONFIG_FONTCONFIG +#include +#endif + +// libass-related command line options +ass_library_t *ass_library; +int ass_enabled = 0; +float ass_font_scale = 1.; +float ass_line_spacing = 0.; +int ass_top_margin = 0; +int ass_bottom_margin = 0; +#if defined(FC_VERSION) && (FC_VERSION >= 20402) +int extract_embedded_fonts = 1; +#else +int extract_embedded_fonts = 0; +#endif +char **ass_force_style_list = NULL; +int ass_use_margins = 0; +char *ass_color = NULL; +char *ass_border_color = NULL; +char *ass_styles_file = NULL; +int ass_hinting = ASS_HINTING_NATIVE + 4; // native hinting for unscaled osd + +#ifdef CONFIG_FONTCONFIG +extern int font_fontconfig; +#else +static int font_fontconfig = -1; +#endif +extern char *font_name; +extern char *sub_font_name; +extern float text_font_scale_factor; +extern int subtitle_autoscale; + +#ifdef CONFIG_ICONV +extern char *sub_cp; +#else +static char *sub_cp = 0; +#endif + +void process_force_style(ass_track_t *track); + +ass_track_t *ass_default_track(ass_library_t *library) +{ + ass_track_t *track = ass_new_track(library); + + track->track_type = TRACK_TYPE_ASS; + track->Timer = 100.; + track->PlayResY = 288; + track->WrapStyle = 0; + + if (ass_styles_file) + ass_read_styles(track, ass_styles_file, sub_cp); + + if (track->n_styles == 0) { + ass_style_t *style; + int sid; + double fs; + uint32_t c1, c2; + + sid = ass_alloc_style(track); + style = track->styles + sid; + style->Name = strdup("Default"); + style->FontName = (font_fontconfig >= 0 + && sub_font_name) ? strdup(sub_font_name) + : (font_fontconfig >= 0 + && font_name) ? strdup(font_name) : strdup("Sans"); + style->treat_fontname_as_pattern = 1; + + fs = track->PlayResY * text_font_scale_factor / 100.; + // approximate autoscale coefficients + if (subtitle_autoscale == 2) + fs *= 1.3; + else if (subtitle_autoscale == 3) + fs *= 1.4; + style->FontSize = fs; + + if (ass_color) + c1 = strtoll(ass_color, NULL, 16); + else + c1 = 0xFFFF0000; + if (ass_border_color) + c2 = strtoll(ass_border_color, NULL, 16); + else + c2 = 0x00000000; + + style->PrimaryColour = c1; + style->SecondaryColour = c1; + style->OutlineColour = c2; + style->BackColour = 0x00000000; + style->BorderStyle = 1; + style->Alignment = 2; + style->Outline = 2; + style->MarginL = 10; + style->MarginR = 10; + style->MarginV = 5; + style->ScaleX = 1.; + style->ScaleY = 1.; + } + + ass_process_force_style(track); + return track; +} + +static int check_duplicate_plaintext_event(ass_track_t *track) +{ + int i; + ass_event_t *evt = track->events + track->n_events - 1; + + for (i = 0; i < track->n_events - 1; ++i) // ignoring last event, it is the one we are comparing with + if (track->events[i].Start == evt->Start && + track->events[i].Duration == evt->Duration && + strcmp(track->events[i].Text, evt->Text) == 0) + return 1; + return 0; +} + +/** + * \brief Convert subtitle to ass_event_t for the given track + * \param ass_track_t track + * \param sub subtitle to convert + * \return event id + * note: assumes that subtitle is _not_ fps-based; caller must manually correct + * Start and Duration in other case. + **/ +int ass_process_subtitle(ass_track_t *track, subtitle *sub) +{ + int eid; + ass_event_t *event; + int len = 0, j; + char *p; + char *end; + + eid = ass_alloc_event(track); + event = track->events + eid; + + event->Start = sub->start * 10; + event->Duration = (sub->end - sub->start) * 10; + event->Style = 0; + + for (j = 0; j < sub->lines; ++j) + len += sub->text[j] ? strlen(sub->text[j]) : 0; + + len += 2 * sub->lines; // '\N', including the one after the last line + len += 6; // {\anX} + len += 1; // '\0' + + event->Text = malloc(len); + end = event->Text + len; + p = event->Text; + + if (sub->alignment) + p += snprintf(p, end - p, "{\\an%d}", sub->alignment); + + for (j = 0; j < sub->lines; ++j) + p += snprintf(p, end - p, "%s\\N", sub->text[j]); + + if (sub->lines > 0) + p -= 2; // remove last "\N" + *p = 0; + + if (check_duplicate_plaintext_event(track)) { + ass_free_event(track, eid); + track->n_events--; + return -1; + } + + mp_msg(MSGT_ASS, MSGL_V, + "plaintext event at %" PRId64 ", +%" PRId64 ": %s \n", + (int64_t) event->Start, (int64_t) event->Duration, event->Text); + + return eid; +} + + +/** + * \brief Convert subdata to ass_track + * \param subdata subtitles struct from subreader + * \param fps video framerate + * \return newly allocated ass_track, filled with subtitles from subdata + */ +ass_track_t *ass_read_subdata(ass_library_t *library, sub_data *subdata, + double fps) +{ + ass_track_t *track; + int i; + + track = ass_default_track(library); + track->name = subdata->filename ? strdup(subdata->filename) : 0; + + for (i = 0; i < subdata->sub_num; ++i) { + int eid = ass_process_subtitle(track, subdata->subtitles + i); + if (eid < 0) + continue; + if (!subdata->sub_uses_time) { + track->events[eid].Start *= 100. / fps; + track->events[eid].Duration *= 100. / fps; + } + } + return track; +} + +void ass_configure(ass_renderer_t *priv, int w, int h, int unscaled) +{ + int hinting; + ass_set_frame_size(priv, w, h); + ass_set_margins(priv, ass_top_margin, ass_bottom_margin, 0, 0); + ass_set_use_margins(priv, ass_use_margins); + ass_set_font_scale(priv, ass_font_scale); + if (!unscaled && (ass_hinting & 4)) + hinting = 0; + else + hinting = ass_hinting & 3; + ass_set_hinting(priv, hinting); + ass_set_line_spacing(priv, ass_line_spacing); +} + +void ass_configure_fonts(ass_renderer_t *priv) +{ + char *dir, *path, *family; + dir = get_path("fonts"); + if (font_fontconfig < 0 && sub_font_name) + path = strdup(sub_font_name); + else if (font_fontconfig < 0 && font_name) + path = strdup(font_name); + else + path = get_path("subfont.ttf"); + if (font_fontconfig >= 0 && sub_font_name) + family = strdup(sub_font_name); + else if (font_fontconfig >= 0 && font_name) + family = strdup(font_name); + else + family = 0; + + ass_set_fonts(priv, path, family, font_fontconfig + 1, NULL, 1); + + free(dir); + free(path); + free(family); +} + +ass_library_t *ass_init(void) +{ + ass_library_t *priv; + char *path = get_path("fonts"); + priv = ass_library_init(); + ass_set_fonts_dir(priv, path); + ass_set_extract_fonts(priv, extract_embedded_fonts); + ass_set_style_overrides(priv, ass_force_style_list); + free(path); + return priv; +} + +int ass_force_reload = 0; // flag set if global ass-related settings were changed + +ass_image_t *ass_mp_render_frame(ass_renderer_t *priv, ass_track_t *track, + long long now, int *detect_change) +{ + if (ass_force_reload) { + ass_set_margins(priv, ass_top_margin, ass_bottom_margin, 0, 0); + ass_set_use_margins(priv, ass_use_margins); + ass_set_font_scale(priv, ass_font_scale); + ass_force_reload = 0; + } + return ass_render_frame(priv, track, now, detect_change); +} diff --git a/ass_mp.h b/ass_mp.h new file mode 100644 index 0000000..eb8be19 --- /dev/null +++ b/ass_mp.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2006 Evgeniy Stepanov + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with libass; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef LIBASS_MP_H +#define LIBASS_MP_H + +#include "subreader.h" +#include +#include + +extern ass_library_t *ass_library; +extern int ass_enabled; +extern float ass_font_scale; +extern float ass_line_spacing; +extern int ass_top_margin; +extern int ass_bottom_margin; +extern int extract_embedded_fonts; +extern char **ass_force_style_list; +extern int ass_use_margins; +extern char *ass_color; +extern char *ass_border_color; +extern char *ass_styles_file; +extern int ass_hinting; + +ass_track_t *ass_default_track(ass_library_t *library); +int ass_process_subtitle(ass_track_t *track, subtitle *sub); +ass_track_t *ass_read_subdata(ass_library_t *library, sub_data *subdata, + double fps); + +void ass_configure(ass_renderer_t *priv, int w, int h, int hinting); +void ass_configure_fonts(ass_renderer_t *priv); +ass_library_t *ass_init(void); + +typedef struct { + ass_image_t *imgs; + int changed; +} mp_eosd_images_t; + +extern int ass_force_reload; +ass_image_t *ass_mp_render_frame(ass_renderer_t *priv, ass_track_t *track, + long long now, int *detect_change); + +#endif /* LIBASS_MP_H */ diff --git a/command.c b/command.c index ff36cd8..981f7e4 100644 --- a/command.c +++ b/command.c @@ -47,8 +47,7 @@ #include "stream/stream_dvdnav.h" #endif #ifdef CONFIG_ASS -#include "libass/ass.h" -#include "libass/ass_mp.h" +#include "ass_mp.h" #endif #ifdef CONFIG_MENU #include "m_struct.h" diff --git a/configure b/configure index 41cc989..8382c19 100755 --- a/configure +++ b/configure @@ -6077,28 +6077,16 @@ echores "$_fontconfig" echocheck "SSA/ASS support" # libass depends on FreeType -if test "$_freetype" = no ; then - _ass=no - _res_comment="FreeType support needed" -fi - -if test "$_ass" = auto ; then - cat > $TMPC << EOF -#include -#include FT_FREETYPE_H -#if ((FREETYPE_MAJOR < 2) || (FREETYPE_MINOR < 1) || ((FREETYPE_MINOR == 1) && (FREETYPE_PATCH < 8))) -#error "Need FreeType 2.1.8 or newer" -#endif -int main(void) { return 0; } -EOF - _ass=no - cc_check $($_freetypeconfig --cflags) $($_freetypeconfig --libs) && tmp_run && _ass=yes - if test "$_ass" = no ; then - _res_comment="FreeType >= 2.1.8 needed" - fi -fi -if test "$_ass" = yes ; then - def_ass='#define CONFIG_ASS' +if test "$_ass" = auto -o "$_ass" = yes ; then + if $_pkg_config libass; then + _ass=yes + def_ass='#define CONFIG_ASS' + extra_ldflags="$extra_ldflags $($_pkg_config --libs libass)" + extra_cflags="$extra_cflags $($_pkg_config --cflags libass)" + else + _ass=no + def_ass='#undef CONFIG_ASS' + fi else def_ass='#undef CONFIG_ASS' fi diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index 2068383..c1e6e8e 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -41,8 +41,7 @@ #include "m_option.h" #include "m_struct.h" -#include "libass/ass.h" -#include "libass/ass_mp.h" +#include "ass_mp.h" #define _r(c) ((c)>>24) #define _g(c) (((c)>>16)&0xFF) @@ -94,8 +93,9 @@ static int config(struct vf_instance_s* vf, vf->priv->dirty_rows = malloc(vf->priv->outh); if (vf->priv->ass_priv) { + double aspect = (double) d_width / d_height; ass_configure(vf->priv->ass_priv, vf->priv->outw, vf->priv->outh, 0); - ass_set_aspect_ratio(vf->priv->ass_priv, ((double)d_width) / d_height); + ass_set_aspect_ratio(vf->priv->ass_priv, aspect, aspect); } return vf_next_config(vf, vf->priv->outw, vf->priv->outh, d_width, d_height, flags, outfmt); @@ -431,4 +431,3 @@ const vf_info_t vf_info_ass = { open, &vf_opts }; - diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c index affffa6..bd7b003 100644 --- a/libmpcodecs/vf_vo.c +++ b/libmpcodecs/vf_vo.c @@ -11,8 +11,7 @@ #include "libvo/video_out.h" #ifdef CONFIG_ASS -#include "libass/ass.h" -#include "libass/ass_mp.h" +#include "ass_mp.h" extern ass_track_t* ass_track; #endif @@ -27,6 +26,7 @@ struct vf_priv_s { #ifdef CONFIG_ASS ass_renderer_t* ass_priv; int prev_visibility; + int d_width, d_height; #endif }; #define video_out (vf->priv->vo) @@ -68,6 +68,9 @@ static int config(struct vf_instance_s* vf, return 0; #ifdef CONFIG_ASS + vf->priv->d_width = d_width; + vf->priv->d_height = d_height; + if (vf->priv->ass_priv) ass_configure(vf->priv->ass_priv, width, height, !!(vf->default_caps & VFCAP_EOSD_UNSCALED)); #endif @@ -133,7 +136,9 @@ static int control(struct vf_instance_s* vf, int request, void* data) if (video_out->control(VOCTRL_GET_EOSD_RES, &res) == VO_TRUE) { ass_set_frame_size(vf->priv->ass_priv, res.w, res.h); ass_set_margins(vf->priv->ass_priv, res.mt, res.mb, res.ml, res.mr); - ass_set_aspect_ratio(vf->priv->ass_priv, (double)res.w / res.h); + ass_set_aspect_ratio(vf->priv->ass_priv, + (double) vf->priv->d_width / vf->priv->d_height, + (double) vf->w / vf->h); } images.imgs = ass_mp_render_frame(vf->priv->ass_priv, ass_track, (pts+sub_delay) * 1000 + .5, &images.changed); diff --git a/libmpdemux/demux_mkv.c b/libmpdemux/demux_mkv.c index cb4d971..5532421 100644 --- a/libmpdemux/demux_mkv.c +++ b/libmpdemux/demux_mkv.c @@ -41,8 +41,7 @@ #include "subreader.h" #include "libvo/sub.h" -#include "libass/ass.h" -#include "libass/ass_mp.h" +#include "ass_mp.h" #include "libavutil/common.h" diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c index c46ba9d..4eed80d 100644 --- a/libmpdemux/demuxer.c +++ b/libmpdemux/demuxer.c @@ -41,8 +41,7 @@ #include "libaf/af_format.h" #ifdef CONFIG_ASS -#include "libass/ass.h" -#include "libass/ass_mp.h" +#include "ass_mp.h" #endif #ifdef CONFIG_LIBAVCODEC diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index 4cc3ebc..9397d7d 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -35,8 +35,9 @@ #include "gui/interface.h" #endif #include "fastmemcpy.h" -#include "libass/ass.h" -#include "libass/ass_mp.h" +#ifdef CONFIG_ASS +#include "ass_mp.h" +#endif static const vo_info_t info = { @@ -277,6 +278,9 @@ static void clearOSD(void) { osdtexCnt = 0; } +static void do_render_osd(int); + +#ifdef CONFIG_ASS /** * \brief remove textures, display list and free memory used by EOSD */ @@ -291,8 +295,6 @@ static void clearEOSD(void) { eosdtex = NULL; } -static void do_render_osd(int); - static inline int is_tinytex(ass_image_t *i, int tinytexcur) { return i->w < TINYTEX_SIZE && i->h < TINYTEX_SIZE && tinytexcur < TINYTEX_MAX; } @@ -408,6 +410,7 @@ skip_upload: glEndList(); BindTexture(gl_target, 0); } +#endif /** * \brief uninitialize OpenGL context, freeing textures, buffers etc. @@ -423,10 +426,12 @@ static void uninitGl(void) { glDeleteTextures(i, default_texs); default_texs[0] = 0; clearOSD(); +#ifdef CONFIG_ASS clearEOSD(); if (largeeosdtex[0]) glDeleteTextures(2, largeeosdtex); largeeosdtex[0] = 0; +#endif if (DeleteBuffers && gl_buffer) DeleteBuffers(1, &gl_buffer); gl_buffer = 0; gl_buffersize = 0; @@ -944,8 +949,12 @@ query_format(uint32_t format) int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE; - if (use_osd) - caps |= VFCAP_OSD | VFCAP_EOSD | (scaled_osd ? 0 : VFCAP_EOSD_UNSCALED); + if (use_osd) { + caps |= VFCAP_OSD; +#ifdef CONFIG_ASS + caps |= VFCAP_EOSD | (scaled_osd ? 0 : VFCAP_EOSD_UNSCALED); +#endif + } if (format == IMGFMT_RGB24 || format == IMGFMT_RGBA) return caps; if (use_yuv && format == IMGFMT_YV12) @@ -1136,6 +1145,7 @@ static int control(uint32_t request, void *data, ...) return get_image(data); case VOCTRL_DRAW_IMAGE: return draw_image(data); +#ifdef CONFIG_ASS case VOCTRL_DRAW_EOSD: if (!data) return VO_FALSE; @@ -1156,6 +1166,7 @@ static int control(uint32_t request, void *data, ...) } } return VO_TRUE; +#endif case VOCTRL_GUISUPPORT: return VO_TRUE; case VOCTRL_ONTOP: diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index fffb1b0..2567856 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -51,8 +51,9 @@ #include "libavutil/common.h" #include "libavutil/mathematics.h" -#include "libass/ass.h" -#include "libass/ass_mp.h" +#ifdef CONFIG_ASS +#include "ass_mp.h" +#endif static vo_info_t info = { "VDPAU with X11", @@ -182,6 +183,7 @@ static unsigned char *index_data; static int index_data_size; static uint32_t palette[PALETTE_SIZE]; +#ifdef CONFIG_ASS // EOSD // Pool of surfaces struct { @@ -201,6 +203,7 @@ struct { static int eosd_render_count; static int eosd_surface_count; +#endif // Video equalizer static VdpProcamp procamp; @@ -211,7 +214,9 @@ static VdpProcamp procamp; static int visible_buf; static int int_pause; +#ifdef CONFIG_ASS static void draw_eosd(void); +#endif static void push_deint_surface(VdpVideoSurface surface) { @@ -235,7 +240,9 @@ static void video_to_output_surface(void) int field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; VdpOutputSurface output_surface; if (i) { +#ifdef CONFIG_ASS draw_eosd(); +#endif draw_osd(); flip_page(); } @@ -713,6 +720,7 @@ static void draw_osd_I8A8(int x0,int y0, int w,int h, unsigned char *src, CHECK_ST_WARNING("Error when calling vdp_output_surface_render_output_surface") } +#ifdef CONFIG_ASS static void draw_eosd(void) { VdpStatus vdp_st; VdpOutputSurface output_surface = output_surfaces[surface_num]; @@ -826,6 +834,7 @@ eosd_skip_upload: eosd_render_count++; } } +#endif static void draw_osd(void) { @@ -951,7 +960,10 @@ static uint32_t get_image(mp_image_t *mpi) static int query_format(uint32_t format) { - int default_flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_EOSD | VFCAP_EOSD_UNSCALED; + int default_flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD; +#ifdef CONFIG_ASS + default_flags |= VFCAP_EOSD | VFCAP_EOSD_UNSCALED; +#endif switch (format) { case IMGFMT_YV12: case IMGFMT_I420: @@ -989,6 +1001,7 @@ static void DestroyVdpauObjects(void) CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy") } +#ifdef CONFIG_ASS for (i = 0; i