From 083e6e3e1a9bf9ee470f59cfd1c775c8724c5ed9 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Mon, 20 Aug 2012 23:39:31 +0300 Subject: [PATCH] osd: rewrite OSD rendering to use libass Render OSD contents with libass. Delete the old rendering code which used freetype/fontconfig directly and did text layout manually. Compiling without libass enabled is still possible, but now there is no OSD support whatsoever in this case. The "--no-ass" switch still exists, and enables a mode where text is drawn unstyled in a manner similar to old rendering. However, most of the switches controlling old subtitle rendering which do not work with libass rendering (such as --subalign, --subfont-blur etc) now do not work in this mode either. Some of them could be supported by setting suitable libass style attributes or other means. Teletext rendering is not implemented in the new OSD rendering code. I don't have any teletext sources for testing, and since teletext is being phased out world-wide, the need for this is questionable. Note that rendering is inefficient, mostly because the libass output is converted into the strange mplayer OSD format to work with existing VO drawing routines. This could be improved at a later point. Also do some cleanup. Subtitle and OSD related variable declarations were literally all over the place. Move them to sub.h and sub.c, which were hoarding most of these declarations already (proper fix would be to move them to the option struct though). Based on original patches by wm4, with multiple fixes and modifications. --- Makefile | 10 +- README | 6 +- cfg-mplayer.h | 22 - command.c | 11 - configure | 89 --- libmpcodecs/vf_ass.c | 2 - libmpcodecs/vf_vo.c | 2 - libmpdemux/demux_ty.c | 3 +- libvo/vo_corevideo.m | 2 - libvo/vo_direct3d.c | 5 - libvo/vo_gl.c | 9 +- libvo/vo_vdpau.c | 7 - mplayer.c | 88 +-- mplayer.h | 8 - sub/ass_mp.c | 41 +- sub/font_load.c | 351 ---------- sub/font_load.h | 115 ---- sub/font_load_ft.c | 1178 -------------------------------- sub/osd_dummy.c | 35 + sub/osd_font.h | 2 +- sub/osd_libass.c | 362 ++++++++++ sub/sub.c | 1776 ++++++++++++------------------------------------- sub/sub.h | 46 +- sub/sub_cc.c | 2 + sub/subreader.c | 85 +-- sub/subreader.h | 4 - 26 files changed, 899 insertions(+), 3362 deletions(-) delete mode 100644 sub/font_load.c delete mode 100644 sub/font_load.h delete mode 100644 sub/font_load_ft.c create mode 100644 sub/osd_dummy.c create mode 100644 sub/osd_libass.c rewrite sub/sub.c (72%) diff --git a/Makefile b/Makefile index 8b6c140fb3..afbfd3c38b 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,6 @@ include config.mak SRCS_AUDIO_INPUT-$(ALSA) += stream/ai_alsa1x.c SRCS_AUDIO_INPUT-$(OSS) += stream/ai_oss.c SRCS_COMMON-$(AUDIO_INPUT) += $(SRCS_AUDIO_INPUT-yes) -SRCS_COMMON-$(BITMAP_FONT) += sub/font_load.c SRCS_COMMON-$(CDDA) += stream/stream_cdda.c \ stream/cdinfo.c SRCS_COMMON-$(CDDB) += stream/stream_cddb.c @@ -63,7 +62,6 @@ SRCS_COMMON-$(FASTMEMCPY) += libvo/aclib.c SRCS_COMMON-$(FFMPEG_INTERNALS) += libmpcodecs/vf_mcdeint.c \ libmpcodecs/vf_spp.c \ -SRCS_COMMON-$(FREETYPE) += sub/font_load_ft.c SRCS_COMMON-$(FTP) += stream/stream_ftp.c SRCS_COMMON-$(GIF) += libmpdemux/demux_gif.c SRCS_COMMON-$(HAVE_POSIX_SELECT) += libmpcodecs/vf_bmovl.c @@ -73,8 +71,12 @@ SRCS_COMMON-$(LADSPA) += libaf/af_ladspa.c SRCS_COMMON-$(LIBA52) += libmpcodecs/ad_liba52.c SRCS_COMMON-$(LIBASS) += libmpcodecs/vf_ass.c \ sub/ass_mp.c \ + sub/osd_libass.c \ sub/sd_ass.c \ +# compiled if libass is NOT enabled +SRCS_COMMON-NEGATED-$(LIBASS) += sub/osd_dummy.c + SRCS_COMMON-$(LIBBLURAY) += stream/stream_bluray.c SRCS_COMMON-$(LIBBS2B) += libaf/af_bs2b.c SRCS_COMMON-$(LIBDCA) += libmpcodecs/ad_libdca.c @@ -213,6 +215,7 @@ SRCS_COMMON-$(WIN32DLL) += libmpcodecs/ad_acm.c \ SRCS_COMMON-$(XANIM_CODECS) += libmpcodecs/vd_xanim.c SRCS_COMMON-$(XMMS_PLUGINS) += libmpdemux/demux_xmms.c SRCS_COMMON-$(XVID4) += libmpcodecs/vd_xvid4.c + SRCS_COMMON = asxparser.c \ av_log.c \ av_opts.c \ @@ -427,7 +430,8 @@ SRCS_COMMON = asxparser.c \ sub/vobsub.c \ timeline/tl_edl.c \ timeline/tl_matroska.c \ - $(SRCS_COMMON-yes) + $(SRCS_COMMON-yes) \ + $(SRCS_COMMON-NEGATED-no) SRCS_MPLAYER-$(ALSA) += libao2/ao_alsa.c diff --git a/README b/README index c12bf527ae..a71687ea7c 100644 --- a/README +++ b/README @@ -15,10 +15,8 @@ Libraries specific to particular video output methods general: - libasound (ALSA audio output) - various general X development libraries - - libfreetype - - libfontconfig - - libass - - FFmpeg libraries (libavutil libavcodec libavformat libswscale libpostproc) + - libass (subtitle/OSD rendering) + - Libav libraries (libavutil libavcodec libavformat libswscale) Most of the above libraries are available in suitable versions on normal Linux distributions. However FFmpeg is an exception (distro versions may be diff --git a/cfg-mplayer.h b/cfg-mplayer.h index 2d1666db46..0cce261bcd 100644 --- a/cfg-mplayer.h +++ b/cfg-mplayer.h @@ -630,19 +630,6 @@ const m_option_t common_opts[] = { OPT_STRINGLIST("sub", sub_name, 0), OPT_PATHLIST("sub-paths", sub_paths, 0), -#ifdef CONFIG_FRIBIDI - {"fribidi-charset", &fribidi_charset, CONF_TYPE_STRING, 0, 0, 0, NULL}, - {"flip-hebrew", &flip_hebrew, CONF_TYPE_FLAG, 0, 0, 1, NULL}, - {"noflip-hebrew", &flip_hebrew, CONF_TYPE_FLAG, 0, 1, 0, NULL}, - {"flip-hebrew-commas", &fribidi_flip_commas, CONF_TYPE_FLAG, 0, 1, 0, NULL}, - {"noflip-hebrew-commas", &fribidi_flip_commas, CONF_TYPE_FLAG, 0, 0, 1, NULL}, -#else - {"fribidi-charset", "MPlayer was compiled without FriBiDi support.\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL}, - {"flip-hebrew", "MPlayer was compiled without FriBiDi support.\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL}, - {"noflip-hebrew", "MPlayer was compiled without FriBiDi support.\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL}, - {"flip-hebrew-commas", "MPlayer was compiled without FriBiDi support.\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL}, - {"noflip-hebrew-commas", "MPlayer was compiled without FriBiDi support.\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL}, -#endif /* CONFIG_FRIBIDI */ #ifdef CONFIG_ICONV {"subcp", &sub_cp, CONF_TYPE_STRING, 0, 0, 0, NULL}, #endif @@ -674,14 +661,12 @@ const m_option_t common_opts[] = { {"spualign", &spu_alignment, CONF_TYPE_INT, CONF_RANGE, -1, 2, NULL}, {"spuaa", &spu_aamode, CONF_TYPE_INT, CONF_RANGE, 0, 31, NULL}, {"spugauss", &spu_gaussvar, CONF_TYPE_FLOAT, CONF_RANGE, 0.0, 3.0, NULL}, -#ifdef CONFIG_FREETYPE {"subfont-encoding", &subtitle_font_encoding, CONF_TYPE_STRING, 0, 0, 0, NULL}, {"subfont-text-scale", &text_font_scale_factor, CONF_TYPE_FLOAT, CONF_RANGE, 0, 100, NULL}, {"subfont-osd-scale", &osd_font_scale_factor, CONF_TYPE_FLOAT, CONF_RANGE, 0, 100, NULL}, {"subfont-blur", &subtitle_font_radius, CONF_TYPE_FLOAT, CONF_RANGE, 0, 8, NULL}, {"subfont-outline", &subtitle_font_thickness, CONF_TYPE_FLOAT, CONF_RANGE, 0, 8, NULL}, {"subfont-autoscale", &subtitle_autoscale, CONF_TYPE_INT, CONF_RANGE, 0, 3, NULL}, -#endif OPT_START_CONDITIONAL(CONFIG_ASS, "libass"), OPT_MAKE_FLAGS("ass", ass_enabled, 0), OPT_FLOATRANGE("ass-font-scale", ass_font_scale, 0, 0, 100), @@ -697,13 +682,6 @@ const m_option_t common_opts[] = { OPT_STRING("ass-styles", ass_styles_file, 0), OPT_INTRANGE("ass-hinting", ass_hinting, 0, 0, 7), OPT_START_CONDITIONAL(1, ""), -#ifdef CONFIG_FONTCONFIG - {"fontconfig", &font_fontconfig, CONF_TYPE_FLAG, 0, -1, 1, NULL}, - {"nofontconfig", &font_fontconfig, CONF_TYPE_FLAG, 0, 1, -1, NULL}, -#else - {"fontconfig", "MPlayer was compiled without fontconfig support.\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL}, - {"nofontconfig", "MPlayer was compiled without fontconfig support.\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL}, -#endif /* CONFIG_FONTCONFIG */ {NULL, NULL, 0, 0, 0, 0, NULL} }; diff --git a/command.c b/command.c index df249cc4e1..2fd3f1e604 100644 --- a/command.c +++ b/command.c @@ -42,7 +42,6 @@ #include "mp_osd.h" #include "libvo/video_out.h" #include "libvo/csputils.h" -#include "sub/font_load.h" #include "playtree.h" #include "libao2/audio_out.h" #include "mpcommon.h" @@ -2061,7 +2060,6 @@ static int mp_property_sub_forced_only(m_option_t *prop, int action, } -#ifdef CONFIG_FREETYPE /// Subtitle scale (RW) static int mp_property_sub_scale(m_option_t *prop, int action, void *arg, MPContext *mpctx) @@ -2080,7 +2078,6 @@ static int mp_property_sub_scale(m_option_t *prop, int action, void *arg, } #endif text_font_scale_factor = *(float *) arg; - force_load_font = 1; vo_osd_changed(OSDTYPE_SUBTITLE); return M_PROPERTY_OK; case M_PROPERTY_STEP_UP: @@ -2096,7 +2093,6 @@ static int mp_property_sub_scale(m_option_t *prop, int action, void *arg, text_font_scale_factor += (arg ? *(float *) arg : 0.1) * (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0); M_PROPERTY_CLAMP(prop, text_font_scale_factor); - force_load_font = 1; vo_osd_changed(OSDTYPE_SUBTITLE); return M_PROPERTY_OK; default: @@ -2108,7 +2104,6 @@ static int mp_property_sub_scale(m_option_t *prop, int action, void *arg, return m_property_float_ro(prop, action, arg, text_font_scale_factor); } } -#endif #ifdef CONFIG_TV @@ -2377,10 +2372,8 @@ static const m_option_t mp_properties[] = { M_OPT_RANGE, 0, 1, NULL }, { "sub_forced_only", mp_property_sub_forced_only, CONF_TYPE_FLAG, M_OPT_RANGE, 0, 1, NULL }, -#ifdef CONFIG_FREETYPE { "sub_scale", mp_property_sub_scale, CONF_TYPE_FLOAT, M_OPT_RANGE, 0, 100, NULL }, -#endif #ifdef CONFIG_ASS { "ass_use_margins", mp_property_ass_use_margins, CONF_TYPE_FLAG, M_OPT_RANGE, 0, 1, NULL }, @@ -2496,9 +2489,7 @@ static struct property_osd_display { { "sub_delay", 0, OSD_MSG_SUB_DELAY, _("Sub delay: %s") }, { "sub_visibility", 0, -1, _("Subtitles: %s") }, { "sub_forced_only", 0, -1, _("Forced sub only: %s") }, -#ifdef CONFIG_FREETYPE { "sub_scale", 0, -1, _("Sub Scale: %s")}, -#endif { "ass_vsfilter_aspect_compat", 0, -1, _("Subtitle VSFilter aspect compat: %s")}, #ifdef CONFIG_TV @@ -2623,9 +2614,7 @@ static struct { { "sub_delay", MP_CMD_SUB_DELAY, 0}, { "sub_visibility", MP_CMD_SUB_VISIBILITY, 1}, { "sub_forced_only", MP_CMD_SUB_FORCED_ONLY, 1}, -#ifdef CONFIG_FREETYPE { "sub_scale", MP_CMD_SUB_SCALE, 0}, -#endif #ifdef CONFIG_ASS { "ass_use_margins", MP_CMD_ASS_USE_MARGINS, 1}, #endif diff --git a/configure b/configure index a6ba520b62..8637df8de0 100755 --- a/configure +++ b/configure @@ -343,12 +343,8 @@ Optional features: --disable-dvdread-internal disable internal libdvdread [autodetect] --disable-libdvdcss-internal disable internal libdvdcss [autodetect] --disable-cddb disable cddb [autodetect] - --disable-bitmap-font disable bitmap font support [enable] - --disable-freetype disable FreeType 2 font rendering [autodetect] - --disable-fontconfig disable fontconfig font lookup [autodetect] --disable-unrarexec disable using of UnRAR executable [enabled] --disable-sortsub disable subtitle sorting [enabled] - --enable-fribidi enable the FriBiDi libs [autodetect] --disable-enca disable ENCA charset oracle library [autodetect] --enable-macosx-finder enable Mac OS X Finder invocation parameter parsing [disabled] @@ -637,9 +633,6 @@ _libdv=auto _cdda=auto _cddb=auto _big_endian=auto -_bitmap_font=yes -_freetype=auto -_fontconfig=auto _qtx=auto _coreaudio=auto _corevideo=auto @@ -649,7 +642,6 @@ quicktime=auto _macosx_finder=no _macosx_bundle=auto _sortsub=yes -_fribidi=auto _enca=auto _inet6=auto _gethostbyname2=auto @@ -978,12 +970,6 @@ for ac_option do --disable-cddb) _cddb=no ;; --enable-big-endian) _big_endian=yes ;; --disable-big-endian) _big_endian=no ;; - --enable-bitmap-font) _bitmap_font=yes ;; - --disable-bitmap-font) _bitmap_font=no ;; - --enable-freetype) _freetype=yes ;; - --disable-freetype) _freetype=no ;; - --enable-fontconfig) _fontconfig=yes ;; - --disable-fontconfig) _fontconfig=no ;; --enable-unrarexec) _unrar_exec=yes ;; --disable-unrarexec) _unrar_exec=no ;; --enable-ftp) _ftp=yes ;; @@ -1001,9 +987,6 @@ for ac_option do --enable-libpostproc) libpostproc=yes ;; --disable-libpostproc) libpostproc=no ;; - --enable-fribidi) _fribidi=yes ;; - --disable-fribidi) _fribidi=no ;; - --enable-enca) _enca=yes ;; --disable-enca) _enca=no ;; @@ -4648,56 +4631,6 @@ else noinputmodules="cddb $noinputmodules" fi -echocheck "bitmap font support" -if test "$_bitmap_font" = yes ; then - def_bitmap_font="#define CONFIG_BITMAP_FONT 1" -else - def_bitmap_font="#undef CONFIG_BITMAP_FONT" -fi -echores "$_bitmap_font" - - -echocheck "freetype >= 2.0.9" - -# freetype depends on iconv -if test "$_iconv" = no ; then - _freetype=no - res_comment="iconv support needed" -fi - -if test "$_freetype" = auto ; then - if pkg_config_add freetype2 ; then - _freetype=yes - else - die "Unable to find development files for libfreetype. Aborting. If you really mean to compile without FreeType support use --disable-freetype." - fi -fi -if test "$_freetype" = yes ; then - def_freetype='#define CONFIG_FREETYPE 1' -else - def_freetype='#undef CONFIG_FREETYPE' -fi -echores "$_freetype" - -if test "$_freetype" = no ; then - _fontconfig=no - res_comment="FreeType support needed" -fi -echocheck "fontconfig" -if test "$_fontconfig" = auto ; then - if pkg_config_add 'fontconfig >= 2.4.2' ; then - _fontconfig=yes - else - die "Unable to find development files for libfontconfig. Aborting. If you really mean to compile without fontconfig support use --disable-fontconfig." - fi -fi -if test "$_fontconfig" = yes ; then - def_fontconfig='#define CONFIG_FONTCONFIG 1' -else - def_fontconfig='#undef CONFIG_FONTCONFIG' -fi -echores "$_fontconfig" - echocheck "SSA/ASS support" if test "$_ass" = auto ; then @@ -4713,21 +4646,6 @@ fi echores "$_ass" -echocheck "fribidi with charsets" -if test "$_fribidi" = auto ; then - _fribidi=no - if pkg_config_add fribidi ; then - _fribidi=yes - fi -fi -if test "$_fribidi" = yes ; then - def_fribidi='#define CONFIG_FRIBIDI 1' -else - def_fribidi='#undef CONFIG_FRIBIDI' -fi -echores "$_fribidi" - - echocheck "ENCA" if test "$_enca" = auto ; then _enca=no @@ -5782,7 +5700,6 @@ ALSA = $_alsa APPLE_IR = $_apple_ir APPLE_REMOTE = $_apple_remote AUDIO_INPUT = $_audio_input -BITMAP_FONT = $_bitmap_font CACA = $_caca CDDA = $_cdda CDDB = $_cddb @@ -5801,7 +5718,6 @@ DVDREAD_INTERNAL = $_dvdread_internal DXR3 = $_dxr3 FAAD = $_faad FASTMEMCPY = $_fastmemcpy -FREETYPE = $_freetype FTP = $_ftp GIF = $_gif GL = $_gl @@ -6140,12 +6056,7 @@ $def_tv_v4l2 /* font stuff */ $def_ass -$def_bitmap_font $def_enca -$def_fontconfig -$def_freetype -$def_fribidi - /* networking */ $def_closesocket diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index 82351500b3..4b33797013 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -71,8 +71,6 @@ static const struct vf_priv_s { } *line_limits; } vf_priv_dflt; -extern float sub_delay; - static int config(struct vf_instance *vf, int width, int height, int d_width, int d_height, unsigned int flags, unsigned int outfmt) diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c index 0f89d7312f..287fbfe2c2 100644 --- a/libmpcodecs/vf_vo.c +++ b/libmpcodecs/vf_vo.c @@ -33,8 +33,6 @@ #include "sub/ass_mp.h" #include "sub/sub.h" -extern float sub_delay; - struct vf_priv_s { struct vo *vo; #ifdef CONFIG_ASS diff --git a/libmpdemux/demux_ty.c b/libmpdemux/demux_ty.c index cc9bb8f902..527d350bc6 100644 --- a/libmpdemux/demux_ty.c +++ b/libmpdemux/demux_ty.c @@ -50,8 +50,7 @@ #include "parse_es.h" #include "stheader.h" #include "sub/sub_cc.h" - -extern int sub_justify; +#include "sub/sub.h" // 2/c0: audio data // 3/c0: audio packet header (PES header) diff --git a/libvo/vo_corevideo.m b/libvo/vo_corevideo.m index 4c69426e4d..5f5f3a0705 100644 --- a/libvo/vo_corevideo.m +++ b/libvo/vo_corevideo.m @@ -26,7 +26,6 @@ #import "talloc.h" #import "video_out.h" #import "aspect.h" -#import "sub/font_load.h" #import "sub/sub.h" #import "subopt-helper.h" @@ -100,7 +99,6 @@ static void resize(struct vo *vo, int width, int height) gl->MatrixMode(GL_MODELVIEW); gl->LoadIdentity(); - force_load_font = 1; vo_osd_changed(OSDTYPE_OSD); gl->Clear(GL_COLOR_BUFFER_BIT); diff --git a/libvo/vo_direct3d.c b/libvo/vo_direct3d.c index 2fb40d0398..869cfe71e6 100644 --- a/libvo/vo_direct3d.c +++ b/libvo/vo_direct3d.c @@ -30,7 +30,6 @@ #include "aspect.h" #include "w32_common.h" #include "libavutil/common.h" -#include "sub/font_load.h" #include "sub/sub.h" static const vo_info_t info = @@ -505,10 +504,6 @@ static int resize_d3d(void) calc_fs_rect(); -#ifdef CONFIG_FREETYPE - // font needs to be adjusted - force_load_font = 1; -#endif // OSD needs to be drawn fresh for new size vo_osd_changed(OSDTYPE_OSD); diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index 12749426ab..28dc84fff0 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -36,7 +36,6 @@ #include "libmpcodecs/mp_image.h" #include "geometry.h" #include "osd.h" -#include "sub/font_load.h" #include "sub/sub.h" #include "gl_common.h" @@ -173,13 +172,9 @@ static void resize(struct vo *vo, int x, int y) gl->MatrixMode(GL_MODELVIEW); gl->LoadIdentity(); - if (!p->scaled_osd) { -#ifdef CONFIG_FREETYPE - // adjust font size to display size - force_load_font = 1; -#endif + if (!p->scaled_osd) vo_osd_changed(OSDTYPE_OSD); - } + gl->Clear(GL_COLOR_BUFFER_BIT); vo->want_redraw = true; } diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 684776dabc..407ecdff3c 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -50,8 +50,6 @@ #include "libavcodec/vdpau.h" -#include "sub/font_load.h" - #include "libavutil/common.h" #include "libavutil/mathematics.h" @@ -402,11 +400,6 @@ static void resize(struct vo *vo) vc->src_rect_vid.y1 = vc->flip ? src_rect.top : src_rect.bottom; vc->border_x = borders.left; vc->border_y = borders.top; -#ifdef CONFIG_FREETYPE - // adjust font size to display size - force_load_font = 1; -#endif - vo_osd_changed(OSDTYPE_OSD); int flip_offset_ms = vo_fs ? vc->flip_offset_fs : vc->flip_offset_window; vo->flip_queue_offset = flip_offset_ms / 1000.; diff --git a/mplayer.c b/mplayer.c index ff608b0dd6..bf8986c03b 100644 --- a/mplayer.c +++ b/mplayer.c @@ -80,12 +80,12 @@ #include "sub/subreader.h" #include "sub/find_subfiles.h" #include "sub/dec_sub.h" +#include "sub/sub_cc.h" #include "mp_osd.h" #include "libvo/video_out.h" #include "screenshot.h" -#include "sub/font_load.h" #include "sub/sub.h" #include "sub/av_sub.h" #include "libmpcodecs/dec_teletext.h" @@ -321,16 +321,6 @@ int frame_dropping = 0; // option 0=no drop 1= drop vo 2= drop decode static int play_n_frames = -1; static int play_n_frames_mf = -1; -// sub: -char *font_name = NULL; -char *sub_font_name = NULL; -extern int font_fontconfig; -float font_factor = 0.75; -float sub_delay = 0; -float sub_fps = 0; -int subcc_enabled = 0; -int suboverlap_enabled = 1; - #include "sub/ass_mp.h" char *current_module; // for debugging @@ -708,14 +698,6 @@ void exit_player_with_rc(struct MPContext *mpctx, enum exit_reason how, int rc) current_module = "uninit_input"; mp_input_uninit(mpctx->input); -#ifdef CONFIG_FREETYPE - current_module = "uninit_font"; - if (mpctx->osd && mpctx->osd->sub_font != vo_font) - free_font_desc(mpctx->osd->sub_font); - free_font_desc(vo_font); - vo_font = NULL; - done_freetype(); -#endif osd_free(mpctx->osd); #ifdef CONFIG_ASS @@ -1675,7 +1657,6 @@ static void update_osd_msg(struct MPContext *mpctx) struct MPOpts *opts = &mpctx->opts; mp_osd_msg_t *msg; struct osd_state *osd = mpctx->osd; - char osd_text_timer[128]; if (mpctx->add_osd_seek_info) { double percentage = get_percent_pos(mpctx); @@ -1704,6 +1685,7 @@ static void update_osd_msg(struct MPContext *mpctx) if (mpctx->sh_video) { // fallback on the timer + char osd_text_timer[128] = {0}; if (osdlevel >= 2) { int len = get_time_length(mpctx); int percentage = -1; @@ -1745,19 +1727,22 @@ static void update_osd_msg(struct MPContext *mpctx) fractions_text[0] = 0; } + osd_get_function_sym(osd_text_timer, sizeof(osd_text_timer), + mpctx->osd_function); + size_t blen = strlen(osd_text_timer); + if (osdlevel == 3) - snprintf(osd_text_timer, sizeof(osd_text_timer), - "%c %02d:%02d:%02d%s / %02d:%02d:%02d%s", - mpctx->osd_function, pts / 3600, (pts / 60) % 60, pts % 60, - fractions_text, len / 3600, (len / 60) % 60, len % 60, + snprintf(osd_text_timer + blen, sizeof(osd_text_timer) - blen, + " %02d:%02d:%02d%s / %02d:%02d:%02d%s", + pts / 3600, (pts / 60) % 60, pts % 60, fractions_text, + len / 3600, (len / 60) % 60, len % 60, percentage_text); else - snprintf(osd_text_timer, sizeof(osd_text_timer), - "%c %02d:%02d:%02d%s%s", - mpctx->osd_function, pts / 3600, (pts / 60) % 60, - pts % 60, fractions_text, percentage_text); - } else - osd_text_timer[0] = 0; + snprintf(osd_text_timer + blen, sizeof(osd_text_timer) - blen, + " %02d:%02d:%02d%s%s", + pts / 3600, (pts / 60) % 60, pts % 60, fractions_text, + percentage_text); + } if (strcmp(osd->osd_text, osd_text_timer)) { osd_set_text(osd, osd_text_timer); @@ -4109,45 +4094,12 @@ int main(int argc, char *argv[]) //------ load global data first ------ - mpctx->osd = osd_create(); - - // check font -#ifdef CONFIG_FREETYPE - init_freetype(); -#endif -#ifdef CONFIG_FONTCONFIG - if (font_fontconfig <= 0) { -#endif -#ifdef CONFIG_BITMAP_FONT - if (font_name) { - vo_font = read_font_desc(font_name, font_factor, verbose > 1); - if (!vo_font) - mp_tmsg(MSGT_CPLAYER, MSGL_ERR, "Cannot load bitmap font: %s\n", - filename_recode(font_name)); - } else { - // try default: - vo_font = read_font_desc(mem_ptr = get_path("font/font.desc"), - font_factor, verbose > 1); - free(mem_ptr); // release the buffer created by get_path() - if (!vo_font) - vo_font = read_font_desc(MPLAYER_DATADIR "/font/font.desc", - font_factor, verbose > 1); - } - if (sub_font_name) - mpctx->osd->sub_font = read_font_desc(sub_font_name, font_factor, - verbose > 1); - else - mpctx->osd->sub_font = vo_font; -#endif -#ifdef CONFIG_FONTCONFIG -} -#endif - #ifdef CONFIG_ASS mpctx->ass_library = mp_ass_init(opts); - mpctx->osd->ass_library = mpctx->ass_library; #endif + mpctx->osd = osd_create(opts, mpctx->ass_library); + #ifdef HAVE_RTC if (opts->rtc) { char *rtc_device = opts->rtc_device; @@ -4805,11 +4757,7 @@ goto_enable_cache: print_file_properties(mpctx, mpctx->filename); reinit_video_chain(mpctx); - if (mpctx->sh_video) { -#ifdef CONFIG_FREETYPE - force_load_font = 1; -#endif - } else if (!mpctx->sh_audio) + if (!mpctx->sh_video && !mpctx->sh_audio) goto goto_next_file; //================== MAIN: ========================== diff --git a/mplayer.h b/mplayer.h index 267b6501b3..91d4d35f49 100644 --- a/mplayer.h +++ b/mplayer.h @@ -31,16 +31,8 @@ extern char ** video_driver_list; extern char ** audio_driver_list; extern float audio_delay; -extern unsigned int osd_visible; - -extern char * font_name; -extern char * sub_font_name; -extern float font_factor; extern double force_fps; -extern float sub_delay; -extern float sub_fps; - extern int stream_cache_size; extern int frame_dropping; diff --git a/sub/ass_mp.c b/sub/ass_mp.c index 0713248db0..69f9424535 100644 --- a/sub/ass_mp.c +++ b/sub/ass_mp.c @@ -34,22 +34,11 @@ #include "path.h" #include "ass_mp.h" #include "subreader.h" +#include "sub/sub.h" #include "stream/stream.h" #include "options.h" -#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 +#ifndef CONFIG_ICONV static char *sub_cp = 0; #endif @@ -71,10 +60,8 @@ ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts) track->default_style = sid; ASS_Style *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->FontName = sub_font_name ? strdup(sub_font_name) + : font_name ? strdup(font_name) : strdup("Sans"); style->treat_fontname_as_pattern = 1; double fs = track->PlayResY * text_font_scale_factor / 100.; @@ -262,25 +249,19 @@ void mp_ass_configure_fonts(ASS_Renderer *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 (!mp_path_exists(path)) { - free(path); - path = NULL; - } + path = get_path("subfont.ttf"); + if (!mp_path_exists(path)) { + free(path); + path = NULL; } - if (font_fontconfig >= 0 && sub_font_name) + if (sub_font_name) family = strdup(sub_font_name); - else if (font_fontconfig >= 0 && font_name) + else if (font_name) family = strdup(font_name); else family = 0; - ass_set_fonts(priv, path, family, font_fontconfig + 1, NULL, 1); + ass_set_fonts(priv, path, family, 1, NULL, 1); free(dir); free(path); diff --git a/sub/font_load.c b/sub/font_load.c deleted file mode 100644 index d8f9eafe34..0000000000 --- a/sub/font_load.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * 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 MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" - -#include -#include -#include - -#include "osdep/io.h" - -#include "font_load.h" -#include "mp_msg.h" -#include "libavutil/attributes.h" - -raw_file* load_raw(char *name,int verbose){ - int bpp; - raw_file* raw=malloc(sizeof(raw_file)); - unsigned char head[32]; - FILE *f=fopen(name,"rb"); - if(!f) goto err_out; // can't open - if(fread(head,32,1,f)<1) goto err_out; // too small - if(memcmp(head,"mhwanh",6)) goto err_out; // not raw file - raw->w=head[8]*256+head[9]; - raw->h=head[10]*256+head[11]; - raw->c=head[12]*256+head[13]; - if(raw->w == 0) // 2 bytes were not enough for the width... read 4 bytes from the end of the header - raw->w = ((head[28]*0x100 + head[29])*0x100 + head[30])*0x100 + head[31]; - if(raw->c>256) goto err_out; // too many colors!? - mp_msg(MSGT_OSD, MSGL_DBG2, "RAW: %s %d x %d, %d colors\n",name,raw->w,raw->h,raw->c); - if(raw->c){ - raw->pal=malloc(raw->c*3); - fread(raw->pal,3,raw->c,f); - bpp=1; - } else { - raw->pal=NULL; - bpp=3; - } - raw->bmp=malloc(raw->h*raw->w*bpp); - fread(raw->bmp,raw->h*raw->w*bpp,1,f); - fclose(f); - return raw; - -err_out: - if (f) - fclose(f); - free(raw); - return NULL; -} - -extern int sub_unicode; - -font_desc_t* read_font_desc(const char* fname,float factor,int verbose){ -unsigned char sor[1024]; -unsigned char sor2[1024]; -font_desc_t *desc; -FILE *f = NULL; -char *dn; -char section[64]; -int i,j; -int chardb=0; -int fontdb=-1; -int version av_unused; -int first=1; - -desc=malloc(sizeof(font_desc_t));if(!desc) goto fail_out; -memset(desc,0,sizeof(font_desc_t)); - -f=fopen(fname,"rt");if(!f){ mp_msg(MSGT_OSD, MSGL_V, "font: can't open file: %s\n",fname); goto fail_out;} - -i = strlen (fname) - 9; -if ((dn = malloc(i+1))){ - strncpy (dn, fname, i); - dn[i]='\0'; -} - -desc->fpath = dn; // search in the same dir as fonts.desc - - - -// set up some defaults, and erase table -desc->charspace=2; -desc->spacewidth=12; -desc->height=0; -for(i=0;i<65536;i++) desc->start[i]=desc->width[i]=desc->font[i]=-1; - -section[0]=0; - -while(fgets(sor,1020,f)){ - unsigned char* p[8]; - int pdb=0; - unsigned char *s=sor; - unsigned char *d=sor2; - int ec=' '; - int id=0; - sor[1020]=0; - - /* skip files that look like: TTF (0x00, 0x01), PFM (0x00, 0x01), PFB - * (0x80, 0x01), PCF (0x01, 0x66), fon ("MZ"), gzipped (0x1f, 0x8b) */ - - if (first) { - if (!sor[0] || sor[1] == 1 || (sor[0] == 'M' && sor[1] == 'Z') || (sor[0] == 0x1f && sor[1] == 0x8b) || (sor[0] == 1 && sor[1] == 0x66)) { - mp_msg(MSGT_OSD, MSGL_ERR, "%s doesn't look like a bitmap font description, ignoring.\n", fname); - goto fail_out; - } - first = 0; - } - - p[0]=d;++pdb; - while(1){ - int c=*s++; - if(c==0 || c==13 || c==10) break; - if(!id){ - if(c==39 || c==34){ id=c;continue;} // idezojel - if(c==';' || c=='#') break; - if(c==9) c=' '; - if(c==' '){ - if(ec==' ') continue; - *d=0; ++d; - p[pdb]=d;++pdb; - if(pdb>=8) break; - continue; - } - } else { - if(id==c){ id=0;continue;} // idezojel - - } - *d=c;d++; - ec=c; - } - if(d==sor2) continue; // skip empty lines - *d=0; - -// printf("params=%d sor=%s\n",pdb,sor); -// for(i=0;i=16){ mp_msg(MSGT_OSD, MSGL_ERR, "font: Too many bitmaps defined.\n");goto fail_out;} - } - continue; - } - } - - if(strcmp(section,"[fpath]")==0){ - if(pdb==1){ - free (desc->fpath); // release previously allocated memory - desc->fpath=strdup(p[0]); - continue; - } - } else - -#ifdef __AMIGAOS4__ -#define FONT_PATH_SEP "" -#else -//! path seperator for font paths, may not be more than one character -#define FONT_PATH_SEP "/" -#endif - - if(strcmp(section,"[files]")==0){ - char *default_dir=MPLAYER_DATADIR FONT_PATH_SEP "font"; - if(pdb==2 && strcmp(p[0],"alpha")==0){ - char *cp; - if (!(cp=malloc(strlen(desc->fpath)+strlen(p[1])+2))) goto fail_out; - - snprintf(cp,strlen(desc->fpath)+strlen(p[1])+2,"%s" FONT_PATH_SEP "%s", - desc->fpath,p[1]); - if(!((desc->pic_a[fontdb]=load_raw(cp,verbose)))){ - free(cp); - if (!(cp=malloc(strlen(default_dir)+strlen(p[1])+2))) - goto fail_out; - snprintf(cp,strlen(default_dir)+strlen(p[1])+2,"%s" FONT_PATH_SEP "%s", - default_dir,p[1]); - if (!((desc->pic_a[fontdb]=load_raw(cp,verbose)))){ - mp_msg(MSGT_OSD, MSGL_ERR, "Can't load font bitmap: %s\n",p[1]); - free(cp); - goto fail_out; - } - } - free(cp); - continue; - } - if(pdb==2 && strcmp(p[0],"bitmap")==0){ - char *cp; - if (!(cp=malloc(strlen(desc->fpath)+strlen(p[1])+2))) goto fail_out; - - snprintf(cp,strlen(desc->fpath)+strlen(p[1])+2,"%s" FONT_PATH_SEP "%s", - desc->fpath,p[1]); - if(!((desc->pic_b[fontdb]=load_raw(cp,verbose)))){ - free(cp); - if (!(cp=malloc(strlen(default_dir)+strlen(p[1])+2))) - goto fail_out; - snprintf(cp,strlen(default_dir)+strlen(p[1])+2,"%s" FONT_PATH_SEP "%s", - default_dir,p[1]); - if (!((desc->pic_b[fontdb]=load_raw(cp,verbose)))){ - mp_msg(MSGT_OSD, MSGL_ERR, "Can't load font bitmap: %s\n",p[1]); - free(cp); - goto fail_out; - } - } - free(cp); - continue; - } - } else - - if(strcmp(section,"[info]")==0){ - if(pdb==2 && strcmp(p[0],"name")==0){ - desc->name=strdup(p[1]); - continue; - } - if(pdb==2 && strcmp(p[0],"descversion")==0){ - version=atoi(p[1]); - continue; - } - if(pdb==2 && strcmp(p[0],"spacewidth")==0){ - desc->spacewidth=atoi(p[1]); - continue; - } - if(pdb==2 && strcmp(p[0],"charspace")==0){ - desc->charspace=atoi(p[1]); - continue; - } - if(pdb==2 && strcmp(p[0],"height")==0){ - desc->height=atoi(p[1]); - continue; - } - } else - - if(strcmp(section,"[characters]")==0){ - if(pdb==3){ - int chr=p[0][0]; - int start=atoi(p[1]); - int end=atoi(p[2]); - if(sub_unicode && (chr>=0x80)) chr=(chr<<8)+p[0][1]; - else if(strlen(p[0])!=1) chr=strtol(p[0],NULL,0); - if(endstart[chr]=start; - desc->width[chr]=end-start+1; - desc->font[chr]=fontdb; -// printf("char %d '%c' start=%d width=%d\n",chr,chr,desc->start[chr],desc->width[chr]); - ++chardb; - } - continue; - } - } - mp_msg(MSGT_OSD, MSGL_ERR, "Syntax error in font desc: %s",sor); - goto fail_out; - -} -fclose(f); -f = NULL; - - if (first == 1) { - mp_msg(MSGT_OSD, MSGL_ERR, "%s is empty or a directory, ignoring.\n", fname); - goto fail_out; - } - -//printf("font: pos of U = %d\n",desc->start[218]); - -for(i=0;i<=fontdb;i++){ - if(!desc->pic_a[i] || !desc->pic_b[i]){ - mp_msg(MSGT_OSD, MSGL_ERR, "font: Missing bitmap(s) for sub-font #%d\n",i); - goto fail_out; - } - //if(factor!=1.0f) - { - // re-sample alpha - int f=factor*256.0f; - int size=desc->pic_a[i]->w*desc->pic_a[i]->h; - int j; - mp_msg(MSGT_OSD, MSGL_DBG2, "font: resampling alpha by factor %5.3f (%d) ",factor,f);fflush(stdout); - for(j=0;jpic_a[i]->bmp[j]; // alpha - int y=desc->pic_b[i]->bmp[j]; // bitmap - -#ifdef FAST_OSD - x=(x<(255-f))?0:1; -#else - - x=255-((x*f)>>8); // scale - //if(x<0) x=0; else if(x>255) x=255; - //x^=255; // invert - - if(x+y>255) x=255-y; // to avoid overflows - - //x=0; - //x=((x*f*(255-y))>>16); - //x=((x*f*(255-y))>>16)+y; - //x=(x*f)>>8;if(x=252) x=0; -#endif - - desc->pic_a[i]->bmp[j]=x; -// desc->pic_b[i]->bmp[j]=0; // hack - } - mp_msg(MSGT_OSD, MSGL_DBG2, "DONE!\n"); - } - if(!desc->height) desc->height=desc->pic_a[i]->h; -} - -j='_';if(desc->font[j]<0) j='?'; -for(i=0;i<65536;i++) - if(desc->font[i]<0){ - desc->start[i]=desc->start[j]; - desc->width[i]=desc->width[j]; - desc->font[i]=desc->font[j]; - } -desc->font[' ']=-1; -desc->width[' ']=desc->spacewidth; - -mp_msg(MSGT_OSD, MSGL_V, "Bitmap font %s loaded successfully! (%d chars)\n",fname,chardb); - -return desc; - -fail_out: - if (f) - fclose(f); - free(desc->fpath); - free(desc->name); - free(desc); - return NULL; -} - -#ifndef CONFIG_FREETYPE -void render_one_glyph(font_desc_t *desc, int c) {} -int kerning(font_desc_t *desc, int prevc, int c) { return 0; } -#endif diff --git a/sub/font_load.h b/sub/font_load.h deleted file mode 100644 index 7efe067aaf..0000000000 --- a/sub/font_load.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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 MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_FONT_LOAD_H -#define MPLAYER_FONT_LOAD_H - -#include "config.h" - -#ifdef CONFIG_FREETYPE -#include -#include FT_FREETYPE_H -#endif - -typedef struct { - unsigned char *bmp; - unsigned char *pal; - int w,h,c; -#ifdef CONFIG_FREETYPE - int charwidth,charheight,pen,baseline,padding; - int current_count, current_alloc; -#endif -} raw_file; - -typedef struct font_desc { -#ifdef CONFIG_FREETYPE - int dynamic; -#endif - char *name; - char *fpath; - int spacewidth; - int charspace; - int height; -// char *fname_a; -// char *fname_b; - raw_file* pic_a[16]; - raw_file* pic_b[16]; - short font[65536]; - int start[65536]; // short is not enough for unicode fonts - short width[65536]; - int freetype; - -#ifdef CONFIG_FREETYPE - int face_cnt; - - FT_Face faces[16]; - FT_UInt glyph_index[65536]; - - int max_width, max_height; - - struct - { - int g_r; - int o_r; - int g_w; - int o_w; - int o_size; - unsigned volume; - - unsigned *g; - unsigned *gt2; - unsigned *om; - unsigned char *omt; - unsigned short *tmp; - } tables; -#endif - -} font_desc_t; - -extern font_desc_t* vo_font; - -extern char *subtitle_font_encoding; -extern float text_font_scale_factor; -extern float osd_font_scale_factor; -extern float subtitle_font_radius; -extern float subtitle_font_thickness; -extern int subtitle_autoscale; - -extern int vo_image_width; -extern int vo_image_height; - -extern int force_load_font; - -int init_freetype(void); -int done_freetype(void); - -font_desc_t* read_font_desc_ft(const char* fname,int face_index,int movie_width, int movie_height, float font_scale_factor); -void free_font_desc(font_desc_t *desc); - -void render_one_glyph(font_desc_t *desc, int c); -int kerning(font_desc_t *desc, int prevc, int c); - -void load_font_ft(int width, int height, font_desc_t **desc, const char *name, float font_scale_factor); - -void blur(unsigned char *buffer, unsigned short *tmp2, int width, int height, - int stride, int *m2, int r, int mwidth); - -raw_file* load_raw(char *name,int verbose); -font_desc_t* read_font_desc(const char* fname,float factor,int verbose); - -#endif /* MPLAYER_FONT_LOAD_H */ diff --git a/sub/font_load_ft.c b/sub/font_load_ft.c deleted file mode 100644 index eb6d70b657..0000000000 --- a/sub/font_load_ft.c +++ /dev/null @@ -1,1178 +0,0 @@ -/* - * Renders antialiased fonts for mplayer using freetype library. - * Should work with TrueType, Type1 and any other font supported by libfreetype. - * - * Artur Zaprzala - * - * ported inside MPlayer by Jindrich Makovicka - * - * 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 MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" - -#include -#include -#include -#include - -#ifdef CONFIG_ICONV -#include -#endif - -#include -#include FT_FREETYPE_H -#include FT_GLYPH_H - -#ifdef CONFIG_FONTCONFIG -#include -#endif - -#include "libavutil/common.h" -#include "mpbswap.h" -#include "font_load.h" -#include "mp_msg.h" -#include "mplayer.h" -#include "path.h" -#include "osd_font.h" - -#if (FREETYPE_MAJOR > 2) || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 1) -#define HAVE_FREETYPE21 -#endif - -char *subtitle_font_encoding = NULL; -float text_font_scale_factor = 3.5; -float osd_font_scale_factor = 4.0; -float subtitle_font_radius = 2.0; -float subtitle_font_thickness = 2.0; -// 0 = no autoscale -// 1 = video height -// 2 = video width -// 3 = diagonal -int subtitle_autoscale = 3; - -int vo_image_width = 0; -int vo_image_height = 0; -int force_load_font; - -int using_freetype = 0; -#ifdef CONFIG_FONTCONFIG -int font_fontconfig = 1; -#else -int font_fontconfig = -1; -#endif - -//// constants -static unsigned int const colors = 256; -static unsigned int const maxcolor = 255; -static unsigned const base = 256; -static unsigned const first_char = 33; -#define MAX_CHARSET_SIZE 60000 - -static FT_Library library; - -#define OSD_CHARSET_SIZE 15 - -static const FT_ULong osd_charset[OSD_CHARSET_SIZE] = -{ - 0xe001, 0xe002, 0xe003, 0xe004, 0xe005, 0xe006, 0xe007, 0xe008, - 0xe009, 0xe00a, 0xe00b, 0xe010, 0xe011, 0xe012, 0xe013 -}; - -static const FT_ULong osd_charcodes[OSD_CHARSET_SIZE] = -{ - 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, - 0x09,0x0a,0x0b,0x10,0x11,0x12,0x13 -}; - -#define f266ToInt(x) (((x)+32)>>6) // round fractional fixed point number to integer - // coordinates are in 26.6 pixels (i.e. 1/64th of pixels) -#define f266CeilToInt(x) (((x)+63)>>6) // ceiling -#define f266FloorToInt(x) ((x)>>6) // floor -#define f1616ToInt(x) (((x)+0x8000)>>16) // 16.16 -#define floatTof266(x) ((int)((x)*(1<<6)+0.5)) - -#define ALIGN(x) (((x)+7)&~7) // 8 byte align - -#define WARNING(msg, args...) mp_msg(MSGT_OSD, MSGL_WARN, msg "\n", ## args) - -#define DEBUG 0 - -//static double ttime; - - -static void paste_bitmap(unsigned char *bbuffer, FT_Bitmap *bitmap, int x, int y, int width, int height, int bwidth) { - int drow = x+y*width; - int srow = 0; - int sp, dp, w, h; - if (bitmap->pixel_mode==ft_pixel_mode_mono) - for (h = bitmap->rows; h>0 && height > 0; --h, height--, drow+=width, srow+=bitmap->pitch) - for (w = bwidth, sp=dp=0; w>0; --w, ++dp, ++sp) - bbuffer[drow+dp] = (bitmap->buffer[srow+sp/8] & (0x80>>(sp%8))) ? 255:0; - else - for (h = bitmap->rows; h>0 && height > 0; --h, height--, drow+=width, srow+=bitmap->pitch) - for (w = bwidth, sp=dp=0; w>0; --w, ++dp, ++sp) - bbuffer[drow+dp] = bitmap->buffer[srow+sp]; -} - - -static int check_font(font_desc_t *desc, float ppem, int padding, int pic_idx, - int charset_size, const FT_ULong *charset, - const FT_ULong *charcodes, int unicode) -{ - FT_Error error; - FT_Face face = desc->faces[pic_idx]; - int const load_flags = FT_LOAD_DEFAULT; - int ymin = INT_MAX, ymax = INT_MIN; - int space_advance = 20; - int width, height; - unsigned char *bbuffer; - int i, uni_charmap = 1; - - error = FT_Select_Charmap(face, ft_encoding_unicode); -// fprintf(stderr, "select unicode charmap: %d\n", error); - - if (face->charmap==NULL || face->charmap->encoding!=ft_encoding_unicode) { - WARNING("Unicode charmap not available for this font. Very bad!"); - uni_charmap = 0; - error = FT_Set_Charmap(face, face->charmaps[0]); - if (error) WARNING("No charmaps! Strange."); - } - - /* set size */ - if (FT_IS_SCALABLE(face)) { - error = FT_Set_Char_Size(face, 0, floatTof266(ppem), 0, 0); - if (error) WARNING("FT_Set_Char_Size failed."); - } else { - int j = 0; - int jppem = face->available_sizes[0].height; - /* find closest size */ - for (i = 0; inum_fixed_sizes; ++i) { - if (fabs(face->available_sizes[i].height - ppem) < abs(face->available_sizes[i].height - jppem)) { - j = i; - jppem = face->available_sizes[i].height; - } - } - WARNING("Selected font is not scalable. Using ppem=%i.", face->available_sizes[j].height); - error = FT_Set_Pixel_Sizes(face, face->available_sizes[j].width, face->available_sizes[j].height); - if (error) WARNING("FT_Set_Pixel_Sizes failed."); - } - - if (FT_IS_FIXED_WIDTH(face)) - WARNING("Selected font is fixed-width."); - - /* compute space advance */ - error = FT_Load_Char(face, ' ', load_flags); - if (error) WARNING("spacewidth set to default."); - else space_advance = f266ToInt(face->glyph->advance.x); - - if (!desc->spacewidth) desc->spacewidth = 2*padding + space_advance; - if (!desc->charspace) desc->charspace = -2*padding; - if (!desc->height) desc->height = f266ToInt(face->size->metrics.height); - - - for (i= 0; ifont[unicode?character:code] = pic_idx; - // get glyph index - if (character==0) - glyph_index = 0; - else { - glyph_index = FT_Get_Char_Index(face, uni_charmap ? character:code); - if (glyph_index==0) { - WARNING("Glyph for char 0x%02lx|U+%04lX|%c not found.", code, character, - code<' '||code>255 ? '.':(char)code); - desc->font[unicode?character:code] = -1; - continue; - } - } - desc->glyph_index[unicode?character:code] = glyph_index; - } -// fprintf(stderr, "font height: %f\n", (double)(face->bbox.yMax-face->bbox.yMin)/(double)face->units_per_EM*ppem); -// fprintf(stderr, "font width: %f\n", (double)(face->bbox.xMax-face->bbox.xMin)/(double)face->units_per_EM*ppem); - - ymax = (double)(face->bbox.yMax)/(double)face->units_per_EM*ppem+1; - ymin = (double)(face->bbox.yMin)/(double)face->units_per_EM*ppem-1; - - width = ppem*(face->bbox.xMax-face->bbox.xMin)/face->units_per_EM+3+2*padding; - if (desc->max_width < width) desc->max_width = width; - width = ALIGN(width); - desc->pic_b[pic_idx]->charwidth = width; - - if (width <= 0) { - mp_msg(MSGT_OSD, MSGL_ERR, "Wrong bounding box, width <= 0 !\n"); - return -1; - } - - if (ymax<=ymin) { - mp_msg(MSGT_OSD, MSGL_ERR, "Something went wrong. Use the source!\n"); - return -1; - } - - height = ymax - ymin + 2*padding; - if (height <= 0) { - mp_msg(MSGT_OSD, MSGL_ERR, "Wrong bounding box, height <= 0 !\n"); - return -1; - } - - if (desc->max_height < height) desc->max_height = height; - desc->pic_b[pic_idx]->charheight = height; - -// fprintf(stderr, "font height2: %d\n", height); - desc->pic_b[pic_idx]->baseline = ymax + padding; - desc->pic_b[pic_idx]->padding = padding; - desc->pic_b[pic_idx]->current_alloc = 0; - desc->pic_b[pic_idx]->current_count = 0; - - bbuffer = NULL; - - desc->pic_b[pic_idx]->w = width; - desc->pic_b[pic_idx]->h = height; - desc->pic_b[pic_idx]->c = colors; - desc->pic_b[pic_idx]->bmp = bbuffer; - desc->pic_b[pic_idx]->pen = 0; - return 0; -} - -// general outline -static void outline( - unsigned char *s, - unsigned char *t, - int width, - int height, - int stride, - unsigned char *m, - int r, - int mwidth, - int msize) { - - int x, y; - - for (y = 0; y=width ) ? r+width -x : 2*r+1; - const int y2=(y+r>=height) ? r+height-y : 2*r+1; - register unsigned char *dstp= t + (y1+y-r)* stride + x-r; - //register int *mp = m + y1 *mwidth; - register unsigned char *mp= m + msize*src + y1*mwidth; - int my; - - for(my= y1; mymaxcolor ? maxcolor : v; - } - *t++ = *s++; - s += skip; - t += skip; - } - for (x = 0; x>8; - unsigned *m3= m2 + src2*mwidth; - - int mx; - *srcp= 128; - for(mx=r-1; mx>8; - unsigned *m3= m2 + src2*mwidth; - - int mx; - *srcp= 128; - for(mx=0; mx>8; - unsigned *m3= m2 + src2*mwidth; - - int mx; - *srcp= 128; - for(mx=0; mx>8; - } - s+= stride; - t+= width + 1; - } -} - -static void resample_alpha(unsigned char *abuf, unsigned char *bbuf, int width, int height, int stride, float factor) -{ - int f=factor*256.0f; - int i,j; - for (i = 0; i < height; i++) { - unsigned char *a = abuf+i*stride; - unsigned char *b = bbuf+i*stride; - for(j=0;j>8); // scale - if (x+y>255) x=255-y; // to avoid overflows - if (x<1) x=1; else if (x>=252) x=0; - *a=x; - } - } -} - -#define ALLOC_INCR 32 -void render_one_glyph(font_desc_t *desc, int c) -{ - FT_GlyphSlot slot; - FT_UInt glyph_index; - FT_BitmapGlyph glyph; - int width, height, stride, maxw, off; - unsigned char *abuffer, *bbuffer; - - int const load_flags = FT_LOAD_DEFAULT; - int pen_xa; - int font = desc->font[c]; - int error; - -// fprintf(stderr, "render_one_glyph %d\n", c); - - if (!desc->dynamic) return; - if (desc->width[c] != -1) return; - if (desc->font[c] == -1) return; - - glyph_index = desc->glyph_index[c]; - - // load glyph - error = FT_Load_Glyph(desc->faces[font], glyph_index, load_flags); - if (error) { - WARNING("FT_Load_Glyph 0x%02x (char 0x%04x) failed.", glyph_index, c); - desc->font[c] = -1; - return; - } - slot = desc->faces[font]->glyph; - - // render glyph - if (slot->format != ft_glyph_format_bitmap) { - error = FT_Render_Glyph(slot, ft_render_mode_normal); - if (error) { - WARNING("FT_Render_Glyph 0x%04x (char 0x%04x) failed.", glyph_index, c); - desc->font[c] = -1; - return; - } - } - - // extract glyph image - error = FT_Get_Glyph(slot, (FT_Glyph*)&glyph); - if (error) { - WARNING("FT_Get_Glyph 0x%04x (char 0x%04x) failed.", glyph_index, c); - desc->font[c] = -1; - return; - } - -// fprintf(stderr, "glyph generated\n"); - - maxw = desc->pic_b[font]->charwidth; - - if (glyph->bitmap.width > maxw) { - fprintf(stderr, "glyph too wide!\n"); - } - - // allocate new memory, if needed -// fprintf(stderr, "\n%d %d %d\n", desc->pic_b[font]->charwidth, desc->pic_b[font]->charheight, desc->pic_b[font]->current_alloc); - if (desc->pic_b[font]->current_count >= desc->pic_b[font]->current_alloc) { - int newsize = desc->pic_b[font]->charwidth*desc->pic_b[font]->charheight*(desc->pic_b[font]->current_alloc+ALLOC_INCR); - int increment = desc->pic_b[font]->charwidth*desc->pic_b[font]->charheight*ALLOC_INCR; - desc->pic_b[font]->current_alloc += ALLOC_INCR; - -// fprintf(stderr, "\nns = %d inc = %d\n", newsize, increment); - - desc->pic_b[font]->bmp = realloc(desc->pic_b[font]->bmp, newsize); - desc->pic_a[font]->bmp = realloc(desc->pic_a[font]->bmp, newsize); - - off = desc->pic_b[font]->current_count*desc->pic_b[font]->charwidth*desc->pic_b[font]->charheight; - memset(desc->pic_b[font]->bmp+off, 0, increment); - memset(desc->pic_a[font]->bmp+off, 0, increment); - } - - abuffer = desc->pic_a[font]->bmp; - bbuffer = desc->pic_b[font]->bmp; - - off = desc->pic_b[font]->current_count*desc->pic_b[font]->charwidth*desc->pic_b[font]->charheight; - - paste_bitmap(bbuffer+off, - &glyph->bitmap, - desc->pic_b[font]->padding + glyph->left, - desc->pic_b[font]->baseline - glyph->top, - desc->pic_b[font]->charwidth, desc->pic_b[font]->charheight, - glyph->bitmap.width <= maxw ? glyph->bitmap.width : maxw); - -// fprintf(stderr, "glyph pasted\n"); - FT_Done_Glyph((FT_Glyph)glyph); - - /* advance pen */ - pen_xa = f266ToInt(slot->advance.x) + 2*desc->pic_b[font]->padding; - if (pen_xa > maxw) pen_xa = maxw; - - desc->start[c] = off; - width = desc->width[c] = pen_xa; - height = desc->pic_b[font]->charheight; - stride = desc->pic_b[font]->w; - - if (desc->tables.o_r == 0) { - outline0(bbuffer+off, abuffer+off, width, height, stride); - } else if (desc->tables.o_r == 1) { - outline1(bbuffer+off, abuffer+off, width, height, stride); - } else { - outline(bbuffer+off, abuffer+off, width, height, stride, - desc->tables.omt, desc->tables.o_r, desc->tables.o_w, - desc->tables.o_size); - } -// fprintf(stderr, "fg: outline t = %f\n", GetTimer()-t); - - if (desc->tables.g_r) { - blur(abuffer+off, desc->tables.tmp, width, height, stride, - desc->tables.gt2, desc->tables.g_r, - desc->tables.g_w); -// fprintf(stderr, "fg: blur t = %f\n", GetTimer()-t); - } - - resample_alpha(abuffer+off, bbuffer+off, width, height, stride, font_factor); - - desc->pic_b[font]->current_count++; -} - - -static int prepare_font(font_desc_t *desc, FT_Face face, float ppem, - int pic_idx, int charset_size, - const FT_ULong *charset, const FT_ULong *charcodes, - int unicode, double thickness, double radius) -{ - int i, err; - int padding = ceil(radius) + ceil(thickness); - - desc->faces[pic_idx] = face; - - desc->pic_a[pic_idx] = malloc(sizeof(raw_file)); - if (!desc->pic_a[pic_idx]) return -1; - desc->pic_b[pic_idx] = malloc(sizeof(raw_file)); - if (!desc->pic_b[pic_idx]) return -1; - - desc->pic_a[pic_idx]->bmp = NULL; - desc->pic_a[pic_idx]->pal = NULL; - desc->pic_b[pic_idx]->bmp = NULL; - desc->pic_b[pic_idx]->pal = NULL; - - desc->pic_a[pic_idx]->pal = malloc(sizeof(unsigned char)*256*3); - if (!desc->pic_a[pic_idx]->pal) return -1; - for (i = 0; i<768; ++i) desc->pic_a[pic_idx]->pal[i] = i/3; - - desc->pic_b[pic_idx]->pal = malloc(sizeof(unsigned char)*256*3); - if (!desc->pic_b[pic_idx]->pal) return -1; - for (i = 0; i<768; ++i) desc->pic_b[pic_idx]->pal[i] = i/3; - -// ttime = GetTimer(); - err = check_font(desc, ppem, padding, pic_idx, charset_size, charset, charcodes, unicode); -// ttime=GetTimer()-ttime; -// printf("render: %7f us\n",ttime); - if (err) return -1; -// fprintf(stderr, "fg: render t = %f\n", GetTimer()-t); - - desc->pic_a[pic_idx]->w = desc->pic_b[pic_idx]->w; - desc->pic_a[pic_idx]->h = desc->pic_b[pic_idx]->h; - desc->pic_a[pic_idx]->c = colors; - - desc->pic_a[pic_idx]->bmp = NULL; - -// fprintf(stderr, "fg: w = %d, h = %d\n", desc->pic_a[pic_idx]->w, desc->pic_a[pic_idx]->h); - return 0; - -} - -static int generate_tables(font_desc_t *desc, double thickness, double radius) -{ - int width = desc->max_height; - int height = desc->max_width; - - double A = log(1.0/base)/(radius*radius*2); - int mx, my, i; - double volume_diff, volume_factor = 0; - unsigned char *omtp; - - desc->tables.g_r = ceil(radius); - desc->tables.o_r = ceil(thickness); - desc->tables.g_w = 2*desc->tables.g_r+1; - desc->tables.o_w = 2*desc->tables.o_r+1; - desc->tables.o_size = desc->tables.o_w * desc->tables.o_w; - -// fprintf(stderr, "o_r = %d\n", desc->tables.o_r); - - if (desc->tables.g_r) { - desc->tables.g = malloc(desc->tables.g_w * sizeof(unsigned)); - desc->tables.gt2 = malloc(256 * desc->tables.g_w * sizeof(unsigned)); - if (desc->tables.g==NULL || desc->tables.gt2==NULL) { - return -1; - } - } - desc->tables.om = malloc(desc->tables.o_w*desc->tables.o_w * sizeof(unsigned)); - desc->tables.omt = malloc(desc->tables.o_size*256); - - omtp = desc->tables.omt; - desc->tables.tmp = malloc((width+1)*height*sizeof(short)); - - if (desc->tables.om==NULL || desc->tables.omt==NULL || desc->tables.tmp==NULL) { - return -1; - }; - - if (desc->tables.g_r) { - // gaussian curve with volume = 256 - for (volume_diff=10000000; volume_diff>0.0000001; volume_diff*=0.5){ - volume_factor+= volume_diff; - desc->tables.volume=0; - for (i = 0; itables.g_w; ++i) { - desc->tables.g[i] = (unsigned)(exp(A * (i-desc->tables.g_r)*(i-desc->tables.g_r)) * volume_factor + .5); - desc->tables.volume+= desc->tables.g[i]; - } - if(desc->tables.volume>256) volume_factor-= volume_diff; - } - desc->tables.volume=0; - for (i = 0; itables.g_w; ++i) { - desc->tables.g[i] = (unsigned)(exp(A * (i-desc->tables.g_r)*(i-desc->tables.g_r)) * volume_factor + .5); - desc->tables.volume+= desc->tables.g[i]; - } - - // gauss table: - for(mx=0;mxtables.g_w;mx++){ - for(i=0;i<256;i++){ - desc->tables.gt2[mx+i*desc->tables.g_w] = i*desc->tables.g[mx]; - } - } - } - - /* outline matrix */ - for (my = 0; mytables.o_w; ++my) { - for (mx = 0; mxtables.o_w; ++mx) { - // antialiased circle would be perfect here, but this one is good enough - double d = thickness + 1 - sqrt((mx-desc->tables.o_r)*(mx-desc->tables.o_r)+(my-desc->tables.o_r)*(my-desc->tables.o_r)); - desc->tables.om[mx+my*desc->tables.o_w] = d>=1 ? base : d<=0 ? 0 : (d*base + .5); - } - } - - // outline table: - for(i=0;i<256;i++){ - for(mx=0;mxtables.o_size;mx++) *(omtp++) = (i*desc->tables.om[mx] + (base/2))/base; - } - - return 0; -} - -#ifdef CONFIG_ICONV -/* decode from 'encoding' to unicode */ -static FT_ULong decode_char(iconv_t *cd, char c) { - FT_ULong o; - char *inbuf = &c; - char *outbuf = (char*)&o; - size_t inbytesleft = 1; - size_t outbytesleft = sizeof(FT_ULong); - - iconv(*cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); - - /* convert unicode BigEndian -> MachineEndian */ - o = be2me_32(o); - - // if (count==-1) o = 0; // not OK, at least my iconv() returns E2BIG for all - if (outbytesleft!=0) o = 0; - - /* we don't want control characters */ - if (o>=0x7f && o<0xa0) o = 0; - return o; -} - -static int prepare_charset(char *charmap, char *encoding, FT_ULong *charset, FT_ULong *charcodes) { - FT_ULong i; - int count = 0; - int charset_size; - iconv_t cd; - - // check if ucs-4 is available - cd = iconv_open(charmap, charmap); - if (cd==(iconv_t)-1) { - mp_msg(MSGT_OSD, MSGL_ERR, "iconv doesn't know %s encoding. Use the source!\n", charmap); - return -1; - } - - iconv_close(cd); - - cd = iconv_open(charmap, encoding); - if (cd==(iconv_t)-1) { - mp_msg(MSGT_OSD, MSGL_ERR, "Unsupported encoding `%s', use iconv --list to list character sets known on your system.\n", encoding); - return -1; - } - - charset_size = 256 - first_char; - for (i = 0; icharmap==NULL || face->charmap->encoding!=ft_encoding_unicode) { - WARNING("Unicode charmap not available for this font. Very bad!"); - return -1; - } -#ifdef HAVE_FREETYPE21 - i = 0; - charcode = FT_Get_First_Char( face, &gindex ); - while (gindex != 0) { - if (charcode < 65536 && charcode >= 33) { // sanity check - charset[i] = charcode; - charcodes[i] = 0; - i++; - } - charcode = FT_Get_Next_Char( face, charcode, &gindex ); - } -#else - // for FT < 2.1 we have to use brute force enumeration - i = 0; - for (j = 33; j < 65536; j++) { - gindex = FT_Get_Char_Index(face, j); - if (gindex > 0) { - charset[i] = j; - charcodes[i] = 0; - i++; - } - } -#endif - mp_msg(MSGT_OSD, MSGL_V, "Unicode font: %d glyphs.\n", i); - - return i; -} -#endif - -static font_desc_t* init_font_desc(void) -{ - font_desc_t *desc; - - desc = calloc(1, sizeof(*desc)); - if(!desc) return NULL; - - desc->dynamic = 1; - - /* setup sane defaults */ - desc->freetype = 1; - - memset(desc->start, 0xff, sizeof(desc->start)); - memset(desc->width, 0xff, sizeof(desc->width)); - memset(desc->font, 0xff, sizeof(desc->font)); - - return desc; -} - -void free_font_desc(font_desc_t *desc) -{ - int i; - - if (!desc) return; - -// if (!desc->dynamic) return; // some vo_aa crap, better leaking than crashing - - free(desc->name); - free(desc->fpath); - - for(i = 0; i < 16; i++) { - if (desc->pic_a[i]) { - free(desc->pic_a[i]->bmp); - free(desc->pic_a[i]->pal); - free(desc->pic_a[i]); - } - if (desc->pic_b[i]) { - free(desc->pic_b[i]->bmp); - free(desc->pic_b[i]->pal); - free(desc->pic_b[i]); - } - } - - free(desc->tables.g); - free(desc->tables.gt2); - free(desc->tables.om); - free(desc->tables.omt); - free(desc->tables.tmp); - - for(i = 0; i < desc->face_cnt; i++) { - FT_Done_Face(desc->faces[i]); - } - - free(desc); -} - -static int load_sub_face(const char *name, int face_index, FT_Face *face) -{ - int err = -1; - - if (name) err = FT_New_Face(library, name, face_index, face); - - if (err) { - char *font_file = get_path("subfont.ttf"); - err = FT_New_Face(library, font_file, 0, face); - free(font_file); - if (err) { - err = FT_New_Face(library, MPLAYER_DATADIR "/subfont.ttf", 0, face); - if (err) { - mp_tmsg(MSGT_OSD, MSGL_ERR, "New_Face failed. Maybe the font path is wrong.\nPlease supply the text font file (~/.mplayer/subfont.ttf).\n"); - return -1; - } - } - } - return err; -} - -static int load_osd_face(FT_Face *face) -{ - if ( FT_New_Memory_Face(library, osd_font_pfb, sizeof(osd_font_pfb), 0, face) ) { - mp_tmsg(MSGT_OSD, MSGL_ERR, "New_Memory_Face failed..\n"); - return -1; - } - return 0; -} - -int kerning(font_desc_t *desc, int prevc, int c) -{ - FT_Vector kern; - - if (!desc->dynamic) return 0; - if (prevc < 0 || c < 0) return 0; - if (desc->font[prevc] != desc->font[c]) return 0; - if (desc->font[prevc] == -1 || desc->font[c] == -1) return 0; - FT_Get_Kerning(desc->faces[desc->font[c]], - desc->glyph_index[prevc], desc->glyph_index[c], - ft_kerning_default, &kern); - -// fprintf(stderr, "kern: %c %c %d\n", prevc, c, f266ToInt(kern.x)); - - return f266ToInt(kern.x); -} - -font_desc_t* read_font_desc_ft(const char *fname, int face_index, int movie_width, int movie_height, float font_scale_factor) -{ - font_desc_t *desc = NULL; - - FT_Face face; - - FT_ULong *my_charset = malloc(MAX_CHARSET_SIZE * sizeof(FT_ULong)); /* characters we want to render; Unicode */ - FT_ULong *my_charcodes = malloc(MAX_CHARSET_SIZE * sizeof(FT_ULong)); /* character codes in 'encoding' */ - - char *charmap = "ucs-4"; - int err; - int charset_size; - int i, j; - int unicode; - - float movie_size; - - float subtitle_font_ppem; - float osd_font_ppem; - - if (my_charset == NULL || my_charcodes == NULL) { - mp_msg(MSGT_OSD, MSGL_ERR, "subtitle font: malloc failed.\n"); - goto err_out; - } - - switch (subtitle_autoscale) { - case 1: - movie_size = movie_height; - break; - case 2: - movie_size = movie_width; - break; - case 3: - movie_size = sqrt(movie_height*movie_height+movie_width*movie_width); - break; - default: - movie_size = 100; - break; - } - - subtitle_font_ppem = movie_size*font_scale_factor/100.0; - osd_font_ppem = movie_size*(font_scale_factor+1)/100.0; - - if (subtitle_font_ppem < 5) subtitle_font_ppem = 5; - if (osd_font_ppem < 5) osd_font_ppem = 5; - - if (subtitle_font_ppem > 128) subtitle_font_ppem = 128; - if (osd_font_ppem > 128) osd_font_ppem = 128; - - if ((subtitle_font_encoding == NULL) - || (strcasecmp(subtitle_font_encoding, "unicode") == 0)) { - unicode = 1; - } else { - unicode = 0; - } - - desc = init_font_desc(); - if(!desc) goto err_out; - -// t=GetTimer(); - - /* generate the subtitle font */ - err = load_sub_face(fname, face_index, &face); - if (err) { - mp_tmsg(MSGT_OSD, MSGL_WARN, "subtitle font: load_sub_face failed.\n"); - goto gen_osd; - } - desc->face_cnt++; - -#ifdef CONFIG_ICONV - if (unicode) { - charset_size = prepare_charset_unicode(face, my_charset, my_charcodes); - } else { - if (subtitle_font_encoding) { - charset_size = prepare_charset(charmap, subtitle_font_encoding, my_charset, my_charcodes); - } else { - charset_size = prepare_charset(charmap, "iso-8859-1", my_charset, my_charcodes); - } - } - - if (charset_size < 0) { - mp_tmsg(MSGT_OSD, MSGL_ERR, "subtitle font: prepare_charset failed.\n"); - goto err_out; - } -#else - goto err_out; -#endif - -// fprintf(stderr, "fg: prepare t = %f\n", GetTimer()-t); - - err = prepare_font(desc, face, subtitle_font_ppem, desc->face_cnt-1, - charset_size, my_charset, my_charcodes, unicode, - subtitle_font_thickness, subtitle_font_radius); - - if (err) { - mp_tmsg(MSGT_OSD, MSGL_ERR, "Cannot prepare subtitle font.\n"); - goto err_out; - } - -gen_osd: - - /* generate the OSD font */ - err = load_osd_face(&face); - if (err) { - goto err_out; - } - desc->face_cnt++; - - err = prepare_font(desc, face, osd_font_ppem, desc->face_cnt-1, - OSD_CHARSET_SIZE, osd_charset, osd_charcodes, 0, - subtitle_font_thickness, subtitle_font_radius); - - if (err) { - mp_tmsg(MSGT_OSD, MSGL_ERR, "Cannot prepare OSD font.\n"); - goto err_out; - } - - err = generate_tables(desc, subtitle_font_thickness, subtitle_font_radius); - - if (err) { - mp_tmsg(MSGT_OSD, MSGL_ERR, "Cannot generate tables.\n"); - goto err_out; - } - - // final cleanup - desc->font[' ']=-1; - desc->width[' ']=desc->spacewidth; - - j = '_'; - if (desc->font[j] < 0) j = '?'; - if (desc->font[j] < 0) j = ' '; - render_one_glyph(desc, j); - for(i = 0; i < 65536; i++) { - if (desc->font[i] < 0 && i != ' ') { - desc->start[i] = desc->start[j]; - desc->width[i] = desc->width[j]; - desc->font[i] = desc->font[j]; - } - } - free(my_charset); - free(my_charcodes); - return desc; - -err_out: - if (desc) - free_font_desc(desc); - free(my_charset); - free(my_charcodes); - return NULL; -} - -int init_freetype(void) -{ - int err; - - /* initialize freetype */ - err = FT_Init_FreeType(&library); - if (err) { - mp_msg(MSGT_OSD, MSGL_ERR, "Init_FreeType failed.\n"); - return -1; - } - mp_msg(MSGT_OSD, MSGL_V, "init_freetype\n"); - using_freetype = 1; - return 0; -} - -int done_freetype(void) -{ - int err; - - if (!using_freetype) - return 0; - - err = FT_Done_FreeType(library); - if (err) { - mp_tmsg(MSGT_OSD, MSGL_ERR, "FT_Done_FreeType failed.\n"); - return -1; - } - - return 0; -} - -void load_font_ft(int width, int height, font_desc_t** fontp, const char *font_name, float font_scale_factor) -{ -#ifdef CONFIG_FONTCONFIG - FcPattern *fc_pattern; - FcPattern *fc_pattern2; - FcChar8 *s; - int face_index; - FcBool scalable; - FcResult result; -#endif - font_desc_t *vo_font = *fontp; - vo_image_width = width; - vo_image_height = height; - - // protection against vo_aa font hacks - if (vo_font && !vo_font->dynamic) return; - - if (vo_font) free_font_desc(vo_font); - -#ifdef CONFIG_FONTCONFIG - if (font_fontconfig > 0) - { - FcInit(); - fc_pattern = FcNameParse(font_name ? font_name : "sans-serif"); - FcConfigSubstitute(0, fc_pattern, FcMatchPattern); - FcDefaultSubstitute(fc_pattern); - fc_pattern2 = fc_pattern; - fc_pattern = FcFontMatch(0, fc_pattern, &result); - if (fc_pattern) { - FcPatternDestroy(fc_pattern2); - FcPatternGetBool(fc_pattern, FC_SCALABLE, 0, &scalable); - if (scalable != FcTrue) { - FcPatternDestroy(fc_pattern); - fc_pattern = FcNameParse("sans-serif"); - FcConfigSubstitute(0, fc_pattern, FcMatchPattern); - FcDefaultSubstitute(fc_pattern); - fc_pattern2 = fc_pattern; - fc_pattern = FcFontMatch(0, fc_pattern, &result); - FcPatternDestroy(fc_pattern2); - } - // s doesn't need to be freed according to fontconfig docs - FcPatternGetString(fc_pattern, FC_FILE, 0, &s); - FcPatternGetInteger(fc_pattern, FC_INDEX, 0, &face_index); - *fontp=read_font_desc_ft(s, face_index, width, height, font_scale_factor); - FcPatternDestroy(fc_pattern); - return; - } - mp_tmsg(MSGT_OSD, MSGL_ERR, "Fontconfig failed to select a font. " - "Trying without fontconfig...\n"); - } -#endif - *fontp=read_font_desc_ft(font_name, 0, width, height, font_scale_factor); -} diff --git a/sub/osd_dummy.c b/sub/osd_dummy.c new file mode 100644 index 0000000000..51824c6fb7 --- /dev/null +++ b/sub/osd_dummy.c @@ -0,0 +1,35 @@ +#include +#include +#include + +#include "config.h" +#include "talloc.h" +#include "sub.h" + +void vo_update_text_osd(struct osd_state *osd, mp_osd_obj_t *obj) +{ +} + +void vo_update_text_teletext(struct osd_state *osd, mp_osd_obj_t *obj) +{ +} + +void vo_update_text_progbar(struct osd_state *osd, mp_osd_obj_t *obj) +{ +} + +void vo_update_text_sub(struct osd_state *osd, mp_osd_obj_t *obj) +{ +} + +void osd_init_backend(struct osd_state *osd) +{ +} + +void osd_destroy_backend(struct osd_state *osd) +{ +} + +void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function) +{ +} diff --git a/sub/osd_font.h b/sub/osd_font.h index 6be45bc1fa..616c27d155 100644 --- a/sub/osd_font.h +++ b/sub/osd_font.h @@ -19,7 +19,7 @@ #ifndef MPLAYER_OSD_FONT_H #define MPLAYER_OSD_FONT_H -const unsigned char osd_font_pfb[] = { +static const unsigned char osd_font_pfb[] = { 0x80,0x01,0x02,0x17,0x00,0x00,0x25,0x21,0x50,0x53,0x2d,0x41,0x64,0x6f,0x62,0x65, 0x46,0x6f,0x6e,0x74,0x2d,0x31,0x2e,0x30,0x3a,0x20,0x4f,0x53,0x44,0x20,0x31,0x2e, 0x30,0x30,0x0a,0x25,0x25,0x43,0x72,0x65,0x61,0x74,0x69,0x6f,0x6e,0x44,0x61,0x74, diff --git a/sub/osd_libass.c b/sub/osd_libass.c new file mode 100644 index 0000000000..9679c75c0b --- /dev/null +++ b/sub/osd_libass.c @@ -0,0 +1,362 @@ +/* + * This file is part of mplayer2. + * + * mplayer2 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. + * + * mplayer2 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 mplayer2. If not, see . + */ + +#include +#include +#include +#include + +#include "config.h" + +#include "talloc.h" +#include "mp_msg.h" +#include "sub.h" +#include "libavutil/common.h" + +#include "sub/osd_font.h" + +#include "sub/ass_mp.h" +#include "mp_core.h" + + +// Map OSD symbols (e.g. OSD_PLAY) to the glyphs in osd_font_pfb[]. +#define OSD_CODEPOINTS 0xE000 + +void osd_init_backend(struct osd_state *osd) +{ + /* The player adds file-specific embedded fonts with ass_add_font() + * and clears them later with ass_clear_fonts(). Since these + * operations affect the whole library, this would lose the OSD font. + * So we use a separate ass_library instance for OSD rendering. + */ + osd->osd_ass_library = mp_ass_init(osd->opts); + ass_add_font(osd->osd_ass_library, "OSD", (void *)osd_font_pfb, + sizeof(osd_font_pfb)); + + osd->osd_render = ass_renderer_init(osd->osd_ass_library); + mp_ass_configure_fonts(osd->osd_render); + ass_set_aspect_ratio(osd->osd_render, 1.0, 1.0); +} + +void osd_destroy_backend(struct osd_state *osd) +{ + if (osd) { + if (osd->osd_render) + ass_renderer_done(osd->osd_render); + osd->osd_render = NULL; + ass_library_done(osd->osd_ass_library); + osd->osd_ass_library = NULL; + } +} + +static void eosd_draw_alpha_a8i8(unsigned char *src, + int src_w, int src_h, + int src_stride, + unsigned char *dst_a, + unsigned char *dst_i, + size_t dst_stride, + int dst_x, int dst_y, + uint32_t color) +{ + const unsigned int r = (color >> 24) & 0xff; + const unsigned int g = (color >> 16) & 0xff; + const unsigned int b = (color >> 8) & 0xff; + const unsigned int a = 0xff - (color & 0xff); + + int gray = (r + g + b) / 3; // not correct + + dst_a += dst_y * dst_stride + dst_x; + dst_i += dst_y * dst_stride + dst_x; + + for (int y = 0; y < src_h; y++) { + for (int x = 0; x < src_w; x++) { + unsigned char as = ((*src) * a + 255) >> 8; + unsigned char bs = (gray * as + 255) >> 8; + /* In the old mplayer OSD format, alpha=0 means transparency, + * but alpha=1..255 is opaque..transparent. */ + *dst_i = (*dst_i * (255-as) >> 8) + bs; + unsigned char old_transparency = *dst_a - 1; + *dst_a = (old_transparency * (255-as) + 255 >> 8) + 1; + + dst_a++; + dst_i++; + src++; + } + dst_a += dst_stride - src_w; + dst_i += dst_stride - src_w; + src += src_stride - src_w; + } +} + +static void eosd_render_a8i8(unsigned char *a, unsigned char *i, size_t stride, + int x, int y, ASS_Image *imgs) +{ + for (ASS_Image *p = imgs; p; p = p->next) { + eosd_draw_alpha_a8i8(p->bitmap, p->w, p->h, p->stride, a, i, stride, + x + p->dst_x, y + p->dst_y, p->color); + } +} + +static bool ass_bb(ASS_Image *imgs, int *x1, int *y1, int *x2, int *y2) +{ + *x1 = *y1 = INT_MAX; + *x2 = *y2 = INT_MIN; + for (ASS_Image *p = imgs; p; p = p->next) { + *x1 = FFMIN(*x1, p->dst_x); + *y1 = FFMIN(*y1, p->dst_y); + *x2 = FFMAX(*x2, p->dst_x + p->w); + *y2 = FFMAX(*y2, p->dst_y + p->h); + } + return *x1 < *x2 && *y1 < *y2; +} + +static void draw_ass_osd(struct osd_state *osd, mp_osd_obj_t *obj) +{ + ass_set_frame_size(osd->osd_render, osd->w, osd->h); + + ASS_Image *imgs = ass_render_frame(osd->osd_render, obj->osd_track, 0, + NULL); + + int x1, y1, x2, y2; + if (!ass_bb(imgs, &x1, &y1, &x2, &y2)) { + obj->flags &= ~OSDFLAG_VISIBLE; + return; + } + + obj->bbox.x1 = x1; + obj->bbox.y1 = y1; + obj->bbox.x2 = x2; + obj->bbox.y2 = y2; + obj->flags |= OSDFLAG_BBOX; + osd_alloc_buf(obj); + + eosd_render_a8i8(obj->alpha_buffer, obj->bitmap_buffer, obj->stride, + -x1, -y1, imgs); +} + + +static void update_font_scale(ASS_Track *track, ASS_Style *style, double factor) +{ + // duplicated from ass_mp.c + double fs = track->PlayResY * factor / 100.; + /* The font size is always proportional to video height only; + * real -subfont-autoscale behavior is not implemented. + * Apply a correction that corresponds to about 4:3 aspect ratio + * video to get a size somewhat closer to what non-libass rendering + * would produce with the same text_font_scale_factor + * and subtitle_autoscale. + */ + if (subtitle_autoscale == 2) + fs *= 1.3; + else if (subtitle_autoscale == 3) + fs *= 1.7; + style->FontSize = fs; + style->Outline = style->FontSize / 16; +} + + +static ASS_Track *create_osd_ass_track(struct osd_state *osd) +{ + ASS_Track *track = mp_ass_default_track(osd->osd_ass_library, osd->opts); + ASS_Style *style = track->styles + track->default_style; + + track->PlayResX = track->PlayResY * 1.33333; + + update_font_scale(track, style, osd_font_scale_factor); + + style->Alignment = 5; + + free(style->FontName); + style->FontName = strdup(font_name ? font_name : "Sans"); + + return track; +} + +static ASS_Event *get_osd_ass_event(ASS_Track *track) +{ + ass_flush_events(track); + ass_alloc_event(track); + ASS_Event *event = track->events + 0; + event->Start = 0; + event->Duration = 100; + event->Style = track->default_style; + return event; +} + +static char *append_utf8_buffer(char *buffer, uint32_t codepoint) +{ + char data[8]; + uint8_t tmp; + char *output = data; + PUT_UTF8(codepoint, tmp, *output++ = tmp;); + return talloc_strndup_append_buffer(buffer, data, output - data); +} + +void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function) +{ + // 0xFF is never valid UTF-8, so we can use it to escape OSD symbols. + snprintf(buffer, buffer_size, "\xFF%c", osd_function); +} + +static char *mangle_ass(const char *in) +{ + char *res = talloc_strdup(NULL, ""); + while (*in) { + // As used by osd_get_function_sym(). + if (in[0] == '\xFF' && in[1]) { + /* The special play/pause etc symbols are taller than normal + * letters, and do not look very good when libass renders them + * with the base of the letters at the same level. Scale + * the symbols down to 70% size so they're closer to the + * letter sizes in usual fonts. */ + res = talloc_strdup_append_buffer(res, "{\\fnOSD\\fscx70\\fscy70}"); + res = append_utf8_buffer(res, OSD_CODEPOINTS + in[1]); + res = talloc_strdup_append_buffer(res, "{\\r}"); + in += 2; + continue; + } + if (*in == '{') + res = talloc_strdup_append_buffer(res, "\\"); + res = talloc_strndup_append_buffer(res, in, 1); + /* Libass has a couple of escapes like "\n" and "\{", but only + * those specific cases are recognized, and there is no escape + * for "\" itself. This makes it impossible to quote strings + * like "\n"; for example, "\\n" would be interpreted as a + * literal "\" followed by "\n" escape for linefeed. Work around + * this by adding the ZERO WIDTH NO-BREAK SPACE character after + * each "\". This ensures it will not be interpreted as an escape + * and should not change visible output. + */ + if (*in == '\\') + res = append_utf8_buffer(res, 0xfeff); + in++; + } + return res; +} + +void vo_update_text_osd(struct osd_state *osd, mp_osd_obj_t* obj) +{ + if (!obj->osd_track) + obj->osd_track = create_osd_ass_track(osd); + ASS_Event *event = get_osd_ass_event(obj->osd_track); + event->Text = mangle_ass(osd->osd_text); + draw_ass_osd(osd, obj); + talloc_free(event->Text); + event->Text = NULL; +} + +#define OSDBAR_ELEMS 46 + +void vo_update_text_progbar(struct osd_state *osd, mp_osd_obj_t* obj) +{ + obj->flags |= OSDFLAG_CHANGED | OSDFLAG_VISIBLE; + + if (vo_osd_progbar_type < 0) { + obj->flags &= ~OSDFLAG_VISIBLE; + return; + } + + if (!obj->osd_track) + obj->osd_track = create_osd_ass_track(osd); + + ASS_Style *style = obj->osd_track->styles + obj->osd_track->default_style; + + style->Alignment = 10; + style->MarginL = style->MarginR = style->MarginV = 0; + + // We need a fixed font size with respect to the OSD width. + // Assume the OSD bar takes 2/3 of the OSD width at PlayResY=288 and + // FontSize=17 with an OSD aspect ratio of 16:9. Rescale as needed. + // xxx can fail when unknown fonts are involved + double asp = (double)osd->w / osd->h; + double scale = (asp / 1.77777) * (obj->osd_track->PlayResY / 288.0); + style->ScaleX = style->ScaleY = scale; + style->FontSize = 17.0; + style->Outline = style->FontSize / 16 * scale; + + int active = (vo_osd_progbar_value * OSDBAR_ELEMS + 255) / 256; + active = FFMIN(OSDBAR_ELEMS, FFMAX(active, 0)); + + char *text = talloc_strdup(NULL, "{\\q2}"); + + if (vo_osd_progbar_type >= 32) { + text = append_utf8_buffer(text, vo_osd_progbar_type); + } else if (vo_osd_progbar_type > 0) { + text = talloc_strdup_append_buffer(text, "{\\fnOSD}"); + text = append_utf8_buffer(text, OSD_CODEPOINTS + vo_osd_progbar_type); + text = talloc_strdup_append_buffer(text, "{\\r}"); + } + + //xxx space in normal font, because OSD font doesn't have a space + text = talloc_strdup_append_buffer(text, "\\h"); + text = talloc_strdup_append_buffer(text, "{\\fnOSD}"); + + text = append_utf8_buffer(text, OSD_CODEPOINTS + OSD_PB_START); + for (int n = 0; n < active; n++) + text = append_utf8_buffer(text, OSD_CODEPOINTS + OSD_PB_0); + for (int n = 0; n < OSDBAR_ELEMS - active; n++) + text = append_utf8_buffer(text, OSD_CODEPOINTS + OSD_PB_1); + text = append_utf8_buffer(text, OSD_CODEPOINTS + OSD_PB_END); + + ASS_Event *event = get_osd_ass_event(obj->osd_track); + event->Text = text; + draw_ass_osd(osd, obj); + event->Text = NULL; + + talloc_free(text); +} + +void vo_update_text_sub(struct osd_state *osd, mp_osd_obj_t* obj) +{ + obj->flags |= OSDFLAG_CHANGED | OSDFLAG_VISIBLE; + + if (!vo_sub || !sub_visibility) { + obj->flags &= ~OSDFLAG_VISIBLE; + return; + } + + if (!obj->osd_track) + obj->osd_track = mp_ass_default_track(osd->osd_ass_library, osd->opts); + + ASS_Style *style = obj->osd_track->styles + obj->osd_track->default_style; + + style->MarginV = obj->osd_track->PlayResY * ((100 - sub_pos)/110.0); + update_font_scale(obj->osd_track, style, text_font_scale_factor); + + char *text = talloc_strdup(NULL, ""); + + for (int n = 0; n < vo_sub->lines; n++) + text = talloc_asprintf_append_buffer(text, "%s\n", vo_sub->text[n]); + + ASS_Event *event = get_osd_ass_event(obj->osd_track); + event->Text = mangle_ass(text); + draw_ass_osd(osd, obj); + talloc_free(event->Text); + event->Text = NULL; + + talloc_free(text); +} + +// Unimplemented. +void vo_update_text_teletext(struct osd_state *osd, mp_osd_obj_t *obj) +{ + obj->flags |= OSDFLAG_CHANGED; + obj->flags &= ~OSDFLAG_VISIBLE; + if (!vo_osd_teletext_page || !vo_osd_teletext_mode) + return; + mp_msg(MSGT_OSD, MSGL_ERR, "OSD: teletext rendering not implemented\n"); +} diff --git a/sub/sub.c b/sub/sub.c dissimilarity index 72% index efe648948c..0ab97e7ba6 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -1,1355 +1,421 @@ -/* - * 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 MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include - -#include "config.h" -#if HAVE_MALLOC_H -#include -#endif - -#include "stream/stream.h" -#include "stream/stream_dvdnav.h" -#define OSD_NAV_BOX_ALPHA 0x7f - -#include "libmpcodecs/dec_teletext.h" -#include "osdep/timer.h" - -#include "talloc.h" -#include "mplayer.h" -#include "mp_msg.h" -#include "libvo/video_out.h" -#include "font_load.h" -#include "sub.h" -#include "spudec.h" -#include "libavutil/common.h" - -#define NEW_SPLITTING - - -// Structures needed for the new splitting algorithm. -// osd_text_t contains the single subtitle word. -// osd_text_p is used to mark the lines of subtitles -struct osd_text_t { - int osd_kerning, //kerning with the previous word - osd_length, //orizontal length inside the bbox - text_length, //number of characters - *text; //characters - struct osd_text_t *prev, - *next; -}; - -struct osd_text_p { - int value; - struct osd_text_t *ott; - struct osd_text_p *prev, - *next; -}; -//^ - -char * const sub_osd_names[]={ - _("Seekbar"), - _("Play"), - _("Pause"), - _("Stop"), - _("Rewind"), - _("Forward"), - _("Clock"), - _("Contrast"), - _("Saturation"), - _("Volume"), - _("Brightness"), - _("Hue"), - _("Balance") -}; -char * const sub_osd_names_short[] ={ "", "|>", "||", "[]", "<<" , ">>", "", "", "", "", "", "", "" }; - -//static int vo_font_loaded=-1; -font_desc_t* vo_font=NULL; - -void* vo_osd_teletext_page=NULL; -int vo_osd_teletext_half = 0; -int vo_osd_teletext_mode=0; -int vo_osd_teletext_format=0; -int vo_osd_teletext_scale=0; -int sub_unicode=0; -int sub_utf8=0; -int sub_pos=100; -int sub_width_p=100; -int sub_alignment=2; /* 0=top, 1=center, 2=bottom */ -int sub_visibility=1; -int sub_bg_color=0; /* subtitles background color */ -int sub_bg_alpha=0; -int sub_justify=0; -#ifdef CONFIG_DVDNAV -static nav_highlight_t nav_hl; -#endif - -// return the real height of a char: -static inline int get_height(int c,int h){ - int font; - if ((font=vo_font->font[c])>=0) - if(hpic_a[font]->h) h=vo_font->pic_a[font]->h; - return h; -} - -// renders char to a big per-object buffer where alpha and bitmap are separated -static void draw_alpha_buf(mp_osd_obj_t* obj, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride) -{ - int dststride = obj->stride; - int dstskip = obj->stride-w; - int srcskip = stride-w; - int i, j; - unsigned char *b = obj->bitmap_buffer + (y0-obj->bbox.y1)*dststride + (x0-obj->bbox.x1); - unsigned char *a = obj->alpha_buffer + (y0-obj->bbox.y1)*dststride + (x0-obj->bbox.x1); - unsigned char *bs = src; - unsigned char *as = srca; - - if (x0 < obj->bbox.x1 || x0+w > obj->bbox.x2 || y0 < obj->bbox.y1 || y0+h > obj->bbox.y2) { - fprintf(stderr, "osd text out of range: bbox [%d %d %d %d], txt [%d %d %d %d]\n", - obj->bbox.x1, obj->bbox.x2, obj->bbox.y1, obj->bbox.y2, - x0, x0+w, y0, y0+h); - return; - } - - for (i = 0; i < h; i++) { - for (j = 0; j < w; j++, b++, a++, bs++, as++) { - if (*b < *bs) *b = *bs; - if (*as) { - if (*a == 0 || *a > *as) *a = *as; - } - } - b+= dstskip; - a+= dstskip; - bs+= srcskip; - as+= srcskip; - } -} - -// allocates/enlarges the alpha/bitmap buffer -static void alloc_buf(mp_osd_obj_t* obj) -{ - int len; - if (obj->bbox.x2 < obj->bbox.x1) obj->bbox.x2 = obj->bbox.x1; - if (obj->bbox.y2 < obj->bbox.y1) obj->bbox.y2 = obj->bbox.y1; - obj->stride = ((obj->bbox.x2-obj->bbox.x1)+7)&(~7); - len = obj->stride*(obj->bbox.y2-obj->bbox.y1); - if (obj->allocatedallocated = len; - free(obj->bitmap_buffer); - free(obj->alpha_buffer); - obj->bitmap_buffer = memalign(16, len); - obj->alpha_buffer = memalign(16, len); - } - memset(obj->bitmap_buffer, sub_bg_color, len); - memset(obj->alpha_buffer, sub_bg_alpha, len); -} - -// renders the buffer -inline static void vo_draw_text_from_buffer(mp_osd_obj_t* obj,void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx) -{ - if (obj->allocated > 0) { - draw_alpha(ctx, - obj->bbox.x1,obj->bbox.y1, - obj->bbox.x2-obj->bbox.x1, - obj->bbox.y2-obj->bbox.y1, - obj->bitmap_buffer, - obj->alpha_buffer, - obj->stride); - } -} - -unsigned utf8_get_char(const char **str) { - const uint8_t *strp = (const uint8_t *)*str; - unsigned c; - GET_UTF8(c, *strp++, goto no_utf8;); - *str = (const char *)strp; - return c; - -no_utf8: - strp = (const uint8_t *)*str; - c = *strp++; - *str = (const char *)strp; - return c; -} - -inline static void vo_update_text_osd(struct osd_state *osd, mp_osd_obj_t* obj, - int dxs, int dys) -{ - const char *cp = osd->osd_text; - int x=20; - int h=0; - int font; - - obj->bbox.x1=obj->x=x; - obj->bbox.y1=obj->y=10; - - while (*cp){ - uint16_t c=utf8_get_char(&cp); - render_one_glyph(vo_font, c); - x+=vo_font->width[c]+vo_font->charspace; - h=get_height(c,h); - } - - obj->bbox.x2=x-vo_font->charspace; - obj->bbox.y2=obj->bbox.y1+h; - obj->flags|=OSDFLAG_BBOX; - - alloc_buf(obj); - - cp = osd->osd_text; - x = obj->x; - while (*cp){ - uint16_t c=utf8_get_char(&cp); - if ((font=vo_font->font[c])>=0) - draw_alpha_buf(obj,x,obj->y, - vo_font->width[c], - vo_font->pic_a[font]->h, - vo_font->pic_b[font]->bmp+vo_font->start[c], - vo_font->pic_a[font]->bmp+vo_font->start[c], - vo_font->pic_a[font]->w); - x+=vo_font->width[c]+vo_font->charspace; - } -} - -#ifdef CONFIG_DVDNAV -void osd_set_nav_box (uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey) { - nav_hl.sx = sx; - nav_hl.sy = sy; - nav_hl.ex = ex; - nav_hl.ey = ey; -} - -inline static void vo_update_nav (mp_osd_obj_t *obj, int dxs, int dys, int left_border, int top_border, - int right_border, int bottom_border, int orig_w, int orig_h) { - int len; - int sx = nav_hl.sx, sy = nav_hl.sy; - int ex = nav_hl.ex, ey = nav_hl.ey; - int scaled_w = dxs - left_border - right_border; - int scaled_h = dys - top_border - bottom_border; - if (scaled_w != orig_w) { - sx = sx * scaled_w / orig_w; - ex = ex * scaled_w / orig_w; - } - if (scaled_h != orig_h) { - sy = sy * scaled_h / orig_h; - ey = ey * scaled_h / orig_h; - } - sx += left_border; ex += left_border; - sy += top_border; ey += top_border; - sx = FFMIN(FFMAX(sx, 0), dxs); - ex = FFMIN(FFMAX(ex, 0), dxs); - sy = FFMIN(FFMAX(sy, 0), dys); - ey = FFMIN(FFMAX(ey, 0), dys); - - obj->bbox.x1 = obj->x = sx; - obj->bbox.y1 = obj->y = sy; - obj->bbox.x2 = ex; - obj->bbox.y2 = ey; - - alloc_buf (obj); - len = obj->stride * (obj->bbox.y2 - obj->bbox.y1); - memset (obj->bitmap_buffer, OSD_NAV_BOX_ALPHA, len); - memset (obj->alpha_buffer, OSD_NAV_BOX_ALPHA, len); - obj->flags |= OSDFLAG_BBOX | OSDFLAG_CHANGED; - if (obj->bbox.y2 > obj->bbox.y1 && obj->bbox.x2 > obj->bbox.x1) - obj->flags |= OSDFLAG_VISIBLE; -} -#endif - -// renders char to a big per-object buffer where alpha and bitmap are separated -static void tt_draw_alpha_buf(mp_osd_obj_t* obj, int x0,int y0, int w,int h, unsigned char* src, int stride,int fg,int bg,int alpha) -{ - int dststride = obj->stride; - int dstskip = obj->stride-w; - int srcskip = stride-w; - int i, j; - unsigned char *b = obj->bitmap_buffer + (y0-obj->bbox.y1)*dststride + (x0-obj->bbox.x1); - unsigned char *a = obj->alpha_buffer + (y0-obj->bbox.y1)*dststride + (x0-obj->bbox.x1); - unsigned char *bs = src; - if (x0 < obj->bbox.x1 || x0+w > obj->bbox.x2 || y0 < obj->bbox.y1 || y0+h > obj->bbox.y2) { - mp_msg(MSGT_OSD,MSGL_ERR,"tt osd text out of range: bbox [%d %d %d %d], txt [%d %d %d %d]\n", - obj->bbox.x1, obj->bbox.x2, obj->bbox.y1, obj->bbox.y2, - x0, x0+w, y0, y0+h); - return; - } - for (i = 0; i < h; i++) { - for (j = 0; j < w; j++, b++, a++, bs++) { - *b=(fg-bg)*(*bs)/255+bg; - *a=alpha; - } - b+= dstskip; - a+= dstskip; - bs+= srcskip; - } -} -inline static void vo_update_text_teletext(mp_osd_obj_t *obj, int dxs, int dys) -{ - int h=0,w=0,i,j,font,flashon; - int wm,hm; - int color; - int x,y,x0,y0; - int cols,rows; - int wm12; - int hm13; - int hm23; - int start_row,max_rows; - int b,ax[6],ay[6],aw[6],ah[6]; - tt_char tc; - tt_char* tdp=vo_osd_teletext_page; - static const uint8_t colors[8]={1,85,150,226,70,105,179,254}; - unsigned char* buf[9]; - - obj->flags|=OSDFLAG_CHANGED|OSDFLAG_VISIBLE; - if (!tdp || !vo_osd_teletext_mode) { - obj->flags&=~OSDFLAG_VISIBLE; - return; - } - flashon=(GetTimer()/1000000)%2; - switch(vo_osd_teletext_half){ - case TT_ZOOM_TOP_HALF: - start_row=0; - max_rows=VBI_ROWS/2; - break; - case TT_ZOOM_BOTTOM_HALF: - start_row=VBI_ROWS/2; - max_rows=VBI_ROWS/2; - break; - default: - start_row=0; - max_rows=VBI_ROWS; - break; - } - wm=0; - for(i=start_row;iwidth[tc.unicode]) - wm=vo_font->width[tc.unicode]; - } - } - } - - hm=vo_font->height+1; - wm=dxs*hm*max_rows/(dys*VBI_COLUMNS); - -#ifdef CONFIG_FREETYPE - //very simple teletext font auto scaling - if(!vo_osd_teletext_scale && hm*(max_rows+1)>dys){ - osd_font_scale_factor*=1.0*(dys)/((max_rows+1)*hm); - force_load_font=1; - vo_osd_teletext_scale=osd_font_scale_factor; - obj->flags&=~OSDFLAG_VISIBLE; - return; - } -#endif - - cols=dxs/wm; - rows=dys/hm; - - if(cols>VBI_COLUMNS) - cols=VBI_COLUMNS; - if(rows>max_rows) - rows=max_rows; - w=cols*wm-vo_font->charspace; - h=rows*hm-vo_font->charspace; - - if(w>1; - hm13=(hm+1)/3; - hm23=hm13<<1; - - for(i=0;i<6;i+=2){ - ax[i+0]=0; - aw[i+0]=wm12; - - ax[i+1]=wm12; - aw[i+1]=wm-wm12; - } - - for(i=0;i<2;i++){ - ay[i+0]=0; - ah[i+0]=hm13; - - ay[i+2]=hm13; - ah[i+2]=hm-hm23; - - ay[i+4]=hm-hm13; - ah[i+4]=hm13; - } - - obj->x = 0; - obj->y = 0; - obj->bbox.x1 = x0; - obj->bbox.y1 = y0; - obj->bbox.x2 = x0+w; - obj->bbox.y2 = y0+h; - obj->flags |= OSDFLAG_BBOX; - alloc_buf(obj); - - for(i=0;i<9;i++) - buf[i]=malloc(wm*hm); - - //alpha - if(vo_osd_teletext_format==TT_FORMAT_OPAQUE ||vo_osd_teletext_format==TT_FORMAT_OPAQUE_INV) - color=1; - else - color=200; - memset(buf[8],color,wm*hm); - //colors - if(vo_osd_teletext_format==TT_FORMAT_OPAQUE ||vo_osd_teletext_format==TT_FORMAT_TRANSPARENT){ - for(i=0;i<8;i++){ - memset(buf[i],(unsigned char)(1.0*(255-color)*colors[i]/255),wm*hm); - } - }else{ - for(i=0;i<8;i++) - memset(buf[i],(unsigned char)(1.0*(255-color)*colors[7-i]/255),wm*hm); - } - - y=y0; - for(i=0;ifont[tc.unicode])>=0 && y+hmwidth[tc.unicode],vo_font->height, - vo_font->pic_b[font]->bmp+vo_font->start[tc.unicode]-vo_font->charspace*vo_font->pic_a[font]->w, - vo_font->pic_b[font]->w, - buf[tc.fg][0],buf[tc.bg][0],buf[8][0]); - } - }else{ -/* -Rendering one graphics character -TODO: support for separated graphics symbols (where six rectangles does not touch each other) - - +--+ +--+ 87654321 - |01| |12| -------- - |10| <= |34| <= 00100110 <= 0x26 - |01| |56| - +--+ +--+ - -(0:wm/2) (wm/2:wm-wm/2) - -********** *********** (0:hm/3) -*** **** **** **** -*** 1 **** **** 2 **** -*** **** **** **** -********** *********** -********** *********** - -********** *********** (hm/3:hm-2*hm/3) -********** *********** -*** **** **** **** -*** 3 **** **** 4 **** -*** **** **** **** -********** *********** -********** *********** -********** *********** - -********** *********** (hm-hm/3:hm/3) -*** **** **** **** -*** 5 **** **** 6 **** -*** **** **** **** -********** *********** -********** *********** - -*/ - if(tc.gfx>1){ //separated gfx - for(b=0;b<6;b++){ - color=(tc.unicode>>b)&1?tc.fg:tc.bg; - draw_alpha_buf(obj,x+ax[b]+1,y+ay[b]+1,aw[b]-2,ah[b]-2,buf[color],buf[8],wm); - } - //separated gfx (background borders) - //vertical - draw_alpha_buf(obj,x ,y,1,hm,buf[tc.bg],buf[8],wm); - draw_alpha_buf(obj,x+ax[1]-1,y,2,hm,buf[tc.bg],buf[8],wm); - draw_alpha_buf(obj,x+ax[1]+aw[1]-1,y,wm-ax[1]-aw[1]+1,hm,buf[tc.bg],buf[8],wm); - //horizontal - draw_alpha_buf(obj,x,y ,wm,1,buf[tc.bg],buf[8],wm); - draw_alpha_buf(obj,x,y+ay[0]+ah[0]-1,wm,2,buf[tc.bg],buf[8],wm); - draw_alpha_buf(obj,x,y+ay[2]+ah[2]-1,wm,2,buf[tc.bg],buf[8],wm); - draw_alpha_buf(obj,x,y+ay[4]+ah[4]-1,wm,hm-ay[4]-ah[4]+1,buf[tc.bg],buf[8],wm); - }else{ - for(b=0;b<6;b++){ - color=(tc.unicode>>b)&1?tc.fg:tc.bg; - draw_alpha_buf(obj,x+ax[b],y+ay[b],aw[b],ah[b],buf[color],buf[8],wm); - } - } - } - x+=wm; - } - y+=hm; - } - for(i=0;i<9;i++) - free(buf[i]); -} - -int vo_osd_progbar_type=-1; -int vo_osd_progbar_value=100; // 0..256 - -// if we have n=256 bars then OSD progbar looks like below -// -// 0 1 2 3 ... 256 <= vo_osd_progbar_value -// | | | | | -// [ === === === ... === ] -// -// the above schema is rescalled to n=elems bars - -inline static void vo_update_text_progbar(mp_osd_obj_t* obj,int dxs,int dys){ - - obj->flags|=OSDFLAG_CHANGED|OSDFLAG_VISIBLE; - - if(vo_osd_progbar_type<0 || !vo_font){ - obj->flags&=~OSDFLAG_VISIBLE; - return; - } - - render_one_glyph(vo_font, OSD_PB_START); - render_one_glyph(vo_font, OSD_PB_END); - render_one_glyph(vo_font, OSD_PB_0); - render_one_glyph(vo_font, OSD_PB_1); - render_one_glyph(vo_font, vo_osd_progbar_type); - - // calculate bbox corners: - { int h=0; - int y=(dys-vo_font->height)/2; - int delimw=vo_font->width[OSD_PB_START] - +vo_font->width[OSD_PB_END] - +vo_font->charspace; - int width=(2*dxs-3*delimw)/3; - int charw=vo_font->width[OSD_PB_0]+vo_font->charspace; - int elems=width/charw; - int x=(dxs-elems*charw-delimw)/2; - int delta = 0; - h=get_height(OSD_PB_START,h); - h=get_height(OSD_PB_END,h); - h=get_height(OSD_PB_0,h); - h=get_height(OSD_PB_1,h); - if (vo_osd_progbar_type>0 && vo_font->font[vo_osd_progbar_type]>=0){ - delta = vo_font->width[vo_osd_progbar_type]+vo_font->spacewidth; - delta = (x-delta > 0) ? delta : x; - h=get_height(vo_osd_progbar_type,h); - } - obj->bbox.x1=obj->x=x; - obj->bbox.y1=obj->y=y; - obj->bbox.x2=x+width+delimw; - obj->bbox.y2=y+h; //vo_font->height; - obj->flags|=OSDFLAG_BBOX; - obj->params.progbar.elems=elems; - obj->bbox.x1-=delta; // space for an icon - } - - alloc_buf(obj); - - { - int minw = vo_font->width[OSD_PB_START]+vo_font->width[OSD_PB_END]+vo_font->width[OSD_PB_0]; - if (vo_osd_progbar_type>0 && vo_font->font[vo_osd_progbar_type]>=0){ - minw += vo_font->width[vo_osd_progbar_type]+vo_font->charspace+vo_font->spacewidth; - } - if (obj->bbox.x2 - obj->bbox.x1 < minw) return; // space too small, don't render anything - } - - // render it: - { unsigned char *s; - unsigned char *sa; - int i,w,h,st,mark; - int x=obj->x; - int y=obj->y; - int c,font; - int charw=vo_font->width[OSD_PB_0]+vo_font->charspace; - int elems=obj->params.progbar.elems; - - if (vo_osd_progbar_value<=0) - mark=0; - else { - int ev=vo_osd_progbar_value*elems; - mark=ev>>8; - if (ev & 0xFF) mark++; - if (mark>elems) mark=elems; - } - - -// printf("osd.progbar width=%d xpos=%d\n",width,x); - - c=vo_osd_progbar_type; - if(vo_osd_progbar_type>0 && (font=vo_font->font[c])>=0) { - int xp=x-vo_font->width[c]-vo_font->spacewidth; - draw_alpha_buf(obj,(xp<0?0:xp),y, - vo_font->width[c], - vo_font->pic_a[font]->h, - vo_font->pic_b[font]->bmp+vo_font->start[c], - vo_font->pic_a[font]->bmp+vo_font->start[c], - vo_font->pic_a[font]->w); - } - - c=OSD_PB_START; - if ((font=vo_font->font[c])>=0) - draw_alpha_buf(obj,x,y, - vo_font->width[c], - vo_font->pic_a[font]->h, - vo_font->pic_b[font]->bmp+vo_font->start[c], - vo_font->pic_a[font]->bmp+vo_font->start[c], - vo_font->pic_a[font]->w); - x+=vo_font->width[c]+vo_font->charspace; - - c=OSD_PB_0; - if ((font=vo_font->font[c])>=0){ - w=vo_font->width[c]; - h=vo_font->pic_a[font]->h; - s=vo_font->pic_b[font]->bmp+vo_font->start[c]; - sa=vo_font->pic_a[font]->bmp+vo_font->start[c]; - st=vo_font->pic_a[font]->w; - if ((i=mark)) do { - draw_alpha_buf(obj,x,y,w,h,s,sa,st); - x+=charw; - } while(--i); - } - - c=OSD_PB_1; - if ((font=vo_font->font[c])>=0){ - w=vo_font->width[c]; - h=vo_font->pic_a[font]->h; - s =vo_font->pic_b[font]->bmp+vo_font->start[c]; - sa=vo_font->pic_a[font]->bmp+vo_font->start[c]; - st=vo_font->pic_a[font]->w; - if ((i=elems-mark)) do { - draw_alpha_buf(obj,x,y,w,h,s,sa,st); - x+=charw; - } while(--i); - } - - c=OSD_PB_END; - if ((font=vo_font->font[c])>=0) - draw_alpha_buf(obj,x,y, - vo_font->width[c], - vo_font->pic_a[font]->h, - vo_font->pic_b[font]->bmp+vo_font->start[c], - vo_font->pic_a[font]->bmp+vo_font->start[c], - vo_font->pic_a[font]->w); -// x+=vo_font->width[c]+vo_font->charspace; - - } -// vo_osd_progbar_value=(vo_osd_progbar_value+1)&0xFF; - -} - -subtitle* vo_sub=NULL; - -inline static void vo_update_text_sub(struct osd_state *osd, mp_osd_obj_t* obj,int dxs,int dys){ - unsigned char *t; - int c,i,j,l,x,y,font,prevc,counter; - int k; - int xsize; - int xmin=dxs,xmax=0; - int h,lasth; - int xtblc, utblc; - struct font_desc *sub_font = osd->sub_font; - - obj->flags|=OSDFLAG_CHANGED|OSDFLAG_VISIBLE; - - if(!vo_sub || !osd->sub_font || !sub_visibility || (sub_font->font[40]<0)){ - obj->flags&=~OSDFLAG_VISIBLE; - return; - } - - obj->bbox.y2=obj->y=dys; - obj->params.subtitle.lines=0; - - // too long lines divide into a smaller ones - i=k=lasth=0; - h=sub_font->height; - l=vo_sub->lines; - - { - struct osd_text_t *osl, *cp_ott, *tmp_ott, *tmp; - struct osd_text_p *otp_sub = NULL, *otp_sub_tmp = NULL, // these are used to store the whole sub text osd - *otp, *tmp_otp, *pmt; // these are used to manage sub text osd coming from a single sub line - int *char_seq, char_position, xlimit = dxs * sub_width_p / 100, counter; - - while (l) { - xsize = -sub_font->charspace; - l--; - t=vo_sub->text[i++]; - char_position = 0; - char_seq = calloc(strlen(t), sizeof(int)); - - prevc = -1; - - otp = NULL; - osl = NULL; - x = 1; - - // reading the subtitle words from vo_sub->text[] - while (*t) { - if (sub_utf8) - c = utf8_get_char((const char **)&t); - else if ((c = *t++) >= 0x80 && sub_unicode) - c = (c<<8) + *t++; - if (k==MAX_UCS){ - t += strlen(t); // end here - mp_msg(MSGT_OSD,MSGL_WARN,"\nMAX_UCS exceeded!\n"); - } - if (!c) c++; // avoid UCS 0 - render_one_glyph(sub_font, c); - - if (c == ' ') { - struct osd_text_t *tmp_ott = calloc(1, sizeof(struct osd_text_t)); - - if (osl == NULL) { - osl = cp_ott = tmp_ott; - } else { - tmp_ott->prev = cp_ott; - cp_ott->next = tmp_ott; - tmp_ott->osd_kerning = - sub_font->charspace + sub_font->width[' ']; - cp_ott = tmp_ott; - } - tmp_ott->osd_length = xsize; - tmp_ott->text_length = char_position; - tmp_ott->text = malloc(char_position * sizeof(int)); - for (counter = 0; counter < char_position; ++counter) - tmp_ott->text[counter] = char_seq[counter]; - char_position = 0; - xsize = 0; - prevc = c; - } else { - int delta_xsize = sub_font->width[c] + sub_font->charspace + kerning(sub_font, prevc, c); - - if (xsize + delta_xsize <= dxs) { - if (!x) x = 1; - prevc = c; - char_seq[char_position++] = c; - xsize += delta_xsize; - if ((!suboverlap_enabled) && ((font = sub_font->font[c]) >= 0)) { - if (sub_font->pic_a[font]->h > h) { - h = sub_font->pic_a[font]->h; - } - } - } else { - if (x) { - mp_msg(MSGT_OSD, MSGL_WARN, "\nSubtitle word '%s' too long!\n", t); - x = 0; - } - } - } - }// for len (all words from subtitle line read) - - // osl holds an ordered (as they appear in the lines) chain of the subtitle words - { - struct osd_text_t *tmp_ott = calloc(1, sizeof(struct osd_text_t)); - - if (osl == NULL) { - osl = cp_ott = tmp_ott; - } else { - tmp_ott->prev = cp_ott; - cp_ott->next = tmp_ott; - tmp_ott->osd_kerning = - sub_font->charspace + sub_font->width[' ']; - cp_ott = tmp_ott; - } - tmp_ott->osd_length = xsize; - tmp_ott->text_length = char_position; - tmp_ott->text = malloc(char_position * sizeof(int)); - for (counter = 0; counter < char_position; ++counter) - tmp_ott->text[counter] = char_seq[counter]; - char_position = 0; - xsize = -sub_font->charspace; - } - free(char_seq); - - if (osl != NULL) { - int value = 0, exit = 0, minimum = 0; - - // otp will contain the chain of the osd subtitle lines coming from the single vo_sub line. - otp = tmp_otp = calloc(1, sizeof(struct osd_text_p)); - tmp_otp->ott = osl; - for (tmp_ott = tmp_otp->ott; exit == 0; ) { - do { - value += tmp_ott->osd_kerning + tmp_ott->osd_length; - tmp_ott = tmp_ott->next; - } while ((tmp_ott != NULL) && (value + tmp_ott->osd_kerning + tmp_ott->osd_length <= xlimit)); - if (tmp_ott != NULL) { - struct osd_text_p *tmp = calloc(1, sizeof(struct osd_text_p)); - - tmp_otp->value = value; - tmp_otp->next = tmp; - tmp->prev = tmp_otp; - tmp_otp = tmp; - tmp_otp->ott = tmp_ott; - value = -2 * sub_font->charspace - sub_font->width[' ']; - } else { - tmp_otp->value = value; - exit = 1; - } - } - - -#ifdef NEW_SPLITTING - // minimum holds the 'sum of the differences in length among the lines', - // a measure of the evenness of the lengths of the lines - for (tmp_otp = otp; tmp_otp->next != NULL; tmp_otp = tmp_otp->next) { - pmt = tmp_otp->next; - while (pmt != NULL) { - minimum += abs(tmp_otp->value - pmt->value); - pmt = pmt->next; - } - } - - if (otp->next != NULL) { - int mem1, mem2; - struct osd_text_p *mem, *hold; - - exit = 0; - // until the last word of a line can be moved to the beginning of following line - // reducing the 'sum of the differences in length among the lines', it is done - while (exit == 0) { - hold = NULL; - exit = 1; - for (tmp_otp = otp; tmp_otp->next != NULL; tmp_otp = tmp_otp->next) { - pmt = tmp_otp->next; - for (tmp = tmp_otp->ott; tmp->next != pmt->ott; tmp = tmp->next); - if (pmt->value + tmp->osd_length + pmt->ott->osd_kerning <= xlimit) { - mem1 = tmp_otp->value; - mem2 = pmt->value; - tmp_otp->value = mem1 - tmp->osd_length - tmp->osd_kerning; - pmt->value = mem2 + tmp->osd_length + pmt->ott->osd_kerning; - - value = 0; - for (mem = otp; mem->next != NULL; mem = mem->next) { - pmt = mem->next; - while (pmt != NULL) { - value += abs(mem->value - pmt->value); - pmt = pmt->next; - } - } - if (value < minimum) { - minimum = value; - hold = tmp_otp; - exit = 0; - } - tmp_otp->value = mem1; - tmp_otp->next->value = mem2; - } - } - // merging - if (exit == 0) { - tmp_otp = hold; - pmt = tmp_otp->next; - for (tmp = tmp_otp->ott; tmp->next != pmt->ott; tmp = tmp->next); - mem1 = tmp_otp->value; - mem2 = pmt->value; - tmp_otp->value = mem1 - tmp->osd_length - tmp->osd_kerning; - pmt->value = mem2 + tmp->osd_length + pmt->ott->osd_kerning; - pmt->ott = tmp; - }//~merging - }//~while(exit == 0) - }//~if(otp->next!=NULL) -#endif - - // adding otp (containing splitted lines) to otp chain - if (otp_sub == NULL) { - otp_sub = otp; - for (otp_sub_tmp = otp_sub; otp_sub_tmp->next != NULL; otp_sub_tmp = otp_sub_tmp->next); - } else { - //updating ott chain - tmp = otp_sub->ott; - while (tmp->next != NULL) tmp = tmp->next; - tmp->next = otp->ott; - otp->ott->prev = tmp; - //attaching new subtitle line at the end - otp_sub_tmp->next = otp; - otp->prev = otp_sub_tmp; - do - otp_sub_tmp = otp_sub_tmp->next; - while (otp_sub_tmp->next != NULL); - } - }//~ if(osl != NULL) - } // while - - // write lines into utbl - xtblc = 0; - utblc = 0; - obj->y = dys; - obj->params.subtitle.lines = 0; - for (tmp_otp = otp_sub; tmp_otp != NULL; tmp_otp = tmp_otp->next) { - - if ((obj->params.subtitle.lines++) >= MAX_UCSLINES) - break; - - if (h > obj->y) { // out of the screen so end parsing - obj->y -= lasth - sub_font->height; // correct the y position - break; - } - xsize = tmp_otp->value; - obj->params.subtitle.xtbl[xtblc++] = (dxs - xsize) / 2; - if (xmin > (dxs - xsize) / 2) - xmin = (dxs - xsize) / 2; - if (xmax < (dxs + xsize) / 2) - xmax = (dxs + xsize) / 2; - - tmp = (tmp_otp->next == NULL) ? NULL : tmp_otp->next->ott; - for (tmp_ott = tmp_otp->ott; tmp_ott != tmp; tmp_ott = tmp_ott->next) { - for (counter = 0; counter < tmp_ott->text_length; ++counter) { - if (utblc > MAX_UCS) { - break; - } - c = tmp_ott->text[counter]; - render_one_glyph(sub_font, c); - obj->params.subtitle.utbl[utblc++] = c; - k++; - } - obj->params.subtitle.utbl[utblc++] = ' '; - } - obj->params.subtitle.utbl[utblc - 1] = 0; - obj->y -= sub_font->height; - } - if(obj->params.subtitle.lines) - obj->y = dys - ((obj->params.subtitle.lines - 1) * sub_font->height + sub_font->pic_a[sub_font->font[40]]->h); - - // free memory - if (otp_sub != NULL) { - for (tmp = otp_sub->ott; tmp->next != NULL; free(tmp->prev)) { - free(tmp->text); - tmp = tmp->next; - } - free(tmp->text); - free(tmp); - - for(pmt = otp_sub; pmt->next != NULL; free(pmt->prev)) { - pmt = pmt->next; - } - free(pmt); - } - - } - /// vertical alignment - h = dys - obj->y; - if (sub_alignment == 2) - obj->y = dys * sub_pos / 100 - h; - else if (sub_alignment == 1) - obj->y = dys * sub_pos / 100 - h / 2; - else - obj->y = dys * sub_pos / 100; - - if (obj->y < 0) - obj->y = 0; - if (obj->y > dys - h) - obj->y = dys - h; - - obj->bbox.y2 = obj->y + h; - - // calculate bbox: - if (sub_justify) xmin = 10; - obj->bbox.x1=xmin; - obj->bbox.x2=xmax; - obj->bbox.y1=obj->y; -// obj->bbox.y2=obj->y+obj->params.subtitle.lines*sub_font->height; - obj->flags|=OSDFLAG_BBOX; - - alloc_buf(obj); - - y = obj->y; - - obj->alignment = 0; - switch(vo_sub->alignment) { - case SUB_ALIGNMENT_BOTTOMLEFT: - case SUB_ALIGNMENT_MIDDLELEFT: - case SUB_ALIGNMENT_TOPLEFT: - obj->alignment |= 0x1; - break; - case SUB_ALIGNMENT_BOTTOMRIGHT: - case SUB_ALIGNMENT_MIDDLERIGHT: - case SUB_ALIGNMENT_TOPRIGHT: - obj->alignment |= 0x2; - break; - case SUB_ALIGNMENT_BOTTOMCENTER: - case SUB_ALIGNMENT_MIDDLECENTER: - case SUB_ALIGNMENT_TOPCENTER: - default: - obj->alignment |= 0x0; - } - - i=j=0; - if ((l = obj->params.subtitle.lines)) { - for(counter = dxs; i < l; ++i) - if (obj->params.subtitle.xtbl[i] < counter) counter = obj->params.subtitle.xtbl[i]; - for (i = 0; i < l; ++i) { - switch (obj->alignment&0x3) { - case 1: - // left - x = counter; - break; - case 2: - // right - x = 2 * obj->params.subtitle.xtbl[i] - counter - ((obj->params.subtitle.xtbl[i] == counter) ? 0 : 1); - break; - default: - //center - x = obj->params.subtitle.xtbl[i]; - } - prevc = -1; - while ((c=obj->params.subtitle.utbl[j++])){ - x += kerning(sub_font,prevc,c); - if ((font=sub_font->font[c])>=0) - draw_alpha_buf(obj,x,y, - sub_font->width[c], - sub_font->pic_a[font]->h+ydys ? sub_font->pic_a[font]->h : obj->dys-y, - sub_font->pic_b[font]->bmp+sub_font->start[c], - sub_font->pic_a[font]->bmp+sub_font->start[c], - sub_font->pic_a[font]->w); - x+=sub_font->width[c]+sub_font->charspace; - prevc = c; - } - y+=sub_font->height; - } - } - -} - -inline static void vo_update_spudec_sub(mp_osd_obj_t* obj, int dxs, int dys) -{ - unsigned int bbox[4]; - spudec_calc_bbox(vo_spudec, dxs, dys, bbox); - obj->bbox.x1 = bbox[0]; - obj->bbox.x2 = bbox[1]; - obj->bbox.y1 = bbox[2]; - obj->bbox.y2 = bbox[3]; - obj->flags |= OSDFLAG_BBOX; -} - -inline static void vo_draw_spudec_sub(mp_osd_obj_t* obj, void (*draw_alpha)(void *ctx, int x0, int y0, int w, int h, unsigned char* src, unsigned char* srca, int stride), void *ctx) -{ - spudec_draw_scaled(vo_spudec, obj->dxs, obj->dys, draw_alpha, ctx); -} - -void *vo_spudec=NULL; -void *vo_vobsub=NULL; - -static int draw_alpha_init_flag=0; - -void vo_draw_alpha_init(void); - - mp_osd_obj_t* vo_osd_list=NULL; - -static mp_osd_obj_t* new_osd_obj(int type){ - mp_osd_obj_t* osd=malloc(sizeof(mp_osd_obj_t)); - memset(osd,0,sizeof(mp_osd_obj_t)); - osd->next=vo_osd_list; - vo_osd_list=osd; - osd->type=type; - osd->alpha_buffer = NULL; - osd->bitmap_buffer = NULL; - osd->allocated = -1; - return osd; -} - -void osd_free(struct osd_state *osd) -{ - mp_osd_obj_t* obj=vo_osd_list; - while(obj){ - mp_osd_obj_t* next=obj->next; - free(obj->alpha_buffer); - free(obj->bitmap_buffer); - free(obj); - obj=next; - } - vo_osd_list=NULL; - talloc_free(osd); -} - -#define FONT_LOAD_DEFER 6 - -static int osd_update_ext(struct osd_state *osd, int dxs, int dys, - int left_border, int top_border, int right_border, - int bottom_border, int orig_w, int orig_h) -{ - mp_osd_obj_t* obj=vo_osd_list; - int chg=0; -#ifdef CONFIG_FREETYPE - static int defer_counter = 0, prev_dxs = 0, prev_dys = 0; -#endif - -#ifdef CONFIG_FREETYPE - // here is the right place to get screen dimensions - if (((dxs != vo_image_width) - && (subtitle_autoscale == 2 || subtitle_autoscale == 3)) - || ((dys != vo_image_height) - && (subtitle_autoscale == 1 || subtitle_autoscale == 3))) - { - // screen dimensions changed - // wait a while to avoid useless reloading of the font - if (dxs == prev_dxs || dys == prev_dys) { - defer_counter++; - } else { - prev_dxs = dxs; - prev_dys = dys; - defer_counter = 0; - } - if (defer_counter >= FONT_LOAD_DEFER) force_load_font = 1; - } - - if (force_load_font) { - force_load_font = 0; - load_font_ft(dxs, dys, &vo_font, font_name, osd_font_scale_factor); - if (sub_font_name) - load_font_ft(dxs, dys, &osd->sub_font, sub_font_name, text_font_scale_factor); - else - load_font_ft(dxs, dys, &osd->sub_font, font_name, text_font_scale_factor); - prev_dxs = dxs; - prev_dys = dys; - defer_counter = 0; - } else { - if (!vo_font) - load_font_ft(dxs, dys, &vo_font, font_name, osd_font_scale_factor); - if (!osd->sub_font) { - if (sub_font_name) - load_font_ft(dxs, dys, &osd->sub_font, sub_font_name, text_font_scale_factor); - else - load_font_ft(dxs, dys, &osd->sub_font, font_name, text_font_scale_factor); - } - } -#endif - - while(obj){ - if(dxs!=obj->dxs || dys!=obj->dys || obj->flags&OSDFLAG_FORCE_UPDATE){ - int vis=obj->flags&OSDFLAG_VISIBLE; - obj->flags&=~OSDFLAG_BBOX; - switch(obj->type){ -#ifdef CONFIG_DVDNAV - case OSDTYPE_DVDNAV: - vo_update_nav(obj,dxs,dys, left_border, top_border, right_border, bottom_border, orig_w, orig_h); - break; -#endif - case OSDTYPE_SUBTITLE: - vo_update_text_sub(osd, obj,dxs,dys); - break; - case OSDTYPE_TELETEXT: - vo_update_text_teletext(obj,dxs,dys); - break; - case OSDTYPE_PROGBAR: - vo_update_text_progbar(obj,dxs,dys); - break; - case OSDTYPE_SPU: - if(sub_visibility && vo_spudec && spudec_visible(vo_spudec)){ - vo_update_spudec_sub(obj, dxs, dys); - obj->flags|=OSDFLAG_VISIBLE|OSDFLAG_CHANGED; - } - else - obj->flags&=~OSDFLAG_VISIBLE; - break; - case OSDTYPE_OSD: - if(vo_font && osd->osd_text[0]){ - vo_update_text_osd(osd, obj, dxs, dys); // update bbox - obj->flags|=OSDFLAG_VISIBLE|OSDFLAG_CHANGED; - } else - obj->flags&=~OSDFLAG_VISIBLE; - break; - } - // check bbox: - if(!(obj->flags&OSDFLAG_BBOX)){ - // we don't know, so assume the whole screen changed :( - obj->bbox.x1=obj->bbox.y1=0; - obj->bbox.x2=dxs; - obj->bbox.y2=dys; - obj->flags|=OSDFLAG_BBOX; - } else { - // check bbox, reduce it if it's out of bounds (corners): - if(obj->bbox.x1<0) obj->bbox.x1=0; - if(obj->bbox.y1<0) obj->bbox.y1=0; - if(obj->bbox.x2>dxs) obj->bbox.x2=dxs; - if(obj->bbox.y2>dys) obj->bbox.y2=dys; - if(obj->flags&OSDFLAG_VISIBLE) - // debug: - mp_msg(MSGT_OSD,MSGL_DBG2,"OSD update: %d;%d %dx%d \n", - obj->bbox.x1,obj->bbox.y1,obj->bbox.x2-obj->bbox.x1, - obj->bbox.y2-obj->bbox.y1); - } - // check if visibility changed: - if(vis != (obj->flags&OSDFLAG_VISIBLE) ) obj->flags|=OSDFLAG_CHANGED; - // remove the cause of automatic update: - obj->dxs=dxs; obj->dys=dys; - obj->flags&=~OSDFLAG_FORCE_UPDATE; - } - if(obj->flags&OSDFLAG_CHANGED){ - chg|=1<type; - mp_msg(MSGT_OSD,MSGL_DBG2,"OSD chg: %d V: %s pb:%d \n",obj->type,(obj->flags&OSDFLAG_VISIBLE)?"yes":"no",vo_osd_progbar_type); - } - obj=obj->next; - } - return chg; -} - -int osd_update(struct osd_state *osd, int dxs, int dys) -{ - return osd_update_ext(osd, dxs, dys, 0, 0, 0, 0, dxs, dys); -} - -struct osd_state *osd_create(void) -{ - struct osd_state *osd = talloc_zero(NULL, struct osd_state); - *osd = (struct osd_state){ - }; - if(!draw_alpha_init_flag){ - draw_alpha_init_flag=1; - vo_draw_alpha_init(); - } - // temp hack, should be moved to mplayer later - new_osd_obj(OSDTYPE_OSD); - new_osd_obj(OSDTYPE_SUBTITLE); - new_osd_obj(OSDTYPE_PROGBAR); - new_osd_obj(OSDTYPE_SPU); -#ifdef CONFIG_DVDNAV - new_osd_obj(OSDTYPE_DVDNAV); -#endif - new_osd_obj(OSDTYPE_TELETEXT); -#ifdef CONFIG_FREETYPE - force_load_font = 1; -#endif - osd_set_text(osd, NULL); - return osd; -} - -void osd_set_text(struct osd_state *osd, const char *text) { - talloc_free(osd->osd_text); - //osd->text must never be NULL - if (!text) - text = ""; - osd->osd_text = talloc_strdup(osd, text); -} - -int vo_osd_changed_flag=0; - -void osd_remove_text(struct osd_state *osd, int dxs, int dys, - void (*remove)(int x0, int y0, int w, int h)) -{ - mp_osd_obj_t* obj=vo_osd_list; - osd_update(osd, dxs, dys); - while(obj){ - if(((obj->flags&OSDFLAG_CHANGED) || (obj->flags&OSDFLAG_VISIBLE)) && - (obj->flags&OSDFLAG_OLD_BBOX)){ - int w=obj->old_bbox.x2-obj->old_bbox.x1; - int h=obj->old_bbox.y2-obj->old_bbox.y1; - if(w>0 && h>0){ - vo_osd_changed_flag=obj->flags&OSDFLAG_CHANGED; // temp hack - remove(obj->old_bbox.x1,obj->old_bbox.y1,w,h); - } -// obj->flags&=~OSDFLAG_OLD_BBOX; - } - obj=obj->next; - } -} - -void osd_draw_text_ext(struct osd_state *osd, int dxs, int dys, - int left_border, int top_border, int right_border, - int bottom_border, int orig_w, int orig_h, - void (*draw_alpha)(void *ctx, int x0, int y0, int w, - int h, unsigned char* src, - unsigned char *srca, - int stride), - void *ctx) -{ - mp_osd_obj_t* obj=vo_osd_list; - osd_update_ext(osd, dxs, dys, left_border, top_border, right_border, - bottom_border, orig_w, orig_h); - while(obj){ - if(obj->flags&OSDFLAG_VISIBLE){ - vo_osd_changed_flag=obj->flags&OSDFLAG_CHANGED; // temp hack - switch(obj->type){ - case OSDTYPE_SPU: - vo_draw_spudec_sub(obj, draw_alpha, ctx); // FIXME - break; -#ifdef CONFIG_DVDNAV - case OSDTYPE_DVDNAV: -#endif - case OSDTYPE_TELETEXT: - case OSDTYPE_OSD: - case OSDTYPE_SUBTITLE: - case OSDTYPE_PROGBAR: - vo_draw_text_from_buffer(obj, draw_alpha, ctx); - break; - } - obj->old_bbox=obj->bbox; - obj->flags|=OSDFLAG_OLD_BBOX; - } - obj->flags&=~OSDFLAG_CHANGED; - obj=obj->next; - } -} - -void osd_draw_text(struct osd_state *osd, int dxs, int dys, - void (*draw_alpha)(void *ctx, int x0, int y0, int w, int h, - unsigned char* src, unsigned char *srca, - int stride), - void *ctx) -{ - osd_draw_text_ext(osd, dxs, dys, 0, 0, 0, 0, dxs, dys, draw_alpha, ctx); -} - -static int vo_osd_changed_status = 0; - -int vo_osd_changed(int new_value) -{ - mp_osd_obj_t* obj=vo_osd_list; - int ret = vo_osd_changed_status; - vo_osd_changed_status = new_value; - - while(obj){ - if(obj->type==new_value) obj->flags|=OSDFLAG_FORCE_UPDATE; - obj=obj->next; - } - - return ret; -} - -// BBBBBBBBBBBB AAAAAAAAAAAAA BBBBBBBBBBB -// BBBBBBBBBBBB BBBBBBBBBBBBB -// BBBBBBB - -// return TRUE if we have osd in the specified rectangular area: -int vo_osd_check_range_update(int x1,int y1,int x2,int y2){ - mp_osd_obj_t* obj=vo_osd_list; - while(obj){ - if(obj->flags&OSDFLAG_VISIBLE){ - if( (obj->bbox.x1<=x2 && obj->bbox.x2>=x1) && - (obj->bbox.y1<=y2 && obj->bbox.y2>=y1) && - obj->bbox.y2 > obj->bbox.y1 && obj->bbox.x2 > obj->bbox.x1 - ) return 1; - } - obj=obj->next; - } - return 0; -} +/* + * 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 MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +#include "config.h" +#if HAVE_MALLOC_H +#include +#endif + +#include "stream/stream.h" +#include "stream/stream_dvdnav.h" +#define OSD_NAV_BOX_ALPHA 0x7f + +#include "libmpcodecs/dec_teletext.h" +#include "osdep/timer.h" + +#include "talloc.h" +#include "mplayer.h" +#include "mp_msg.h" +#include "libvo/video_out.h" +#include "sub.h" +#include "sub/ass_mp.h" +#include "spudec.h" +#include "libavutil/common.h" + + +char * const sub_osd_names[]={ + _("Seekbar"), + _("Play"), + _("Pause"), + _("Stop"), + _("Rewind"), + _("Forward"), + _("Clock"), + _("Contrast"), + _("Saturation"), + _("Volume"), + _("Brightness"), + _("Hue"), + _("Balance") +}; +char * const sub_osd_names_short[] ={ "", "|>", "||", "[]", "<<" , ">>", "", "", "", "", "", "", "" }; + +void* vo_osd_teletext_page=NULL; +int vo_osd_teletext_half = 0; +int vo_osd_teletext_mode=0; +int vo_osd_teletext_format=0; +int sub_unicode=0; +int sub_utf8=0; +int sub_pos=100; +int sub_width_p=100; +int sub_alignment=2; /* 0=top, 1=center, 2=bottom */ +int sub_visibility=1; +int sub_bg_color=0; /* subtitles background color */ +int sub_bg_alpha=0; +int sub_justify=0; +#ifdef CONFIG_DVDNAV +static nav_highlight_t nav_hl; +#endif + +int vo_osd_progbar_type=-1; +int vo_osd_progbar_value=100; // 0..256 +subtitle* vo_sub=NULL; +char *subtitle_font_encoding = NULL; +float text_font_scale_factor = 3.5; +float osd_font_scale_factor = 4.0; +float subtitle_font_radius = 2.0; +float subtitle_font_thickness = 2.0; +// 0 = no autoscale +// 1 = video height +// 2 = video width +// 3 = diagonal +int subtitle_autoscale = 3; + +char *font_name = NULL; +char *sub_font_name = NULL; +float font_factor = 0.75; +float sub_delay = 0; +float sub_fps = 0; + +// allocates/enlarges the alpha/bitmap buffer +void osd_alloc_buf(mp_osd_obj_t* obj) +{ + int len; + if (obj->bbox.x2 < obj->bbox.x1) obj->bbox.x2 = obj->bbox.x1; + if (obj->bbox.y2 < obj->bbox.y1) obj->bbox.y2 = obj->bbox.y1; + obj->stride = ((obj->bbox.x2-obj->bbox.x1)+7)&(~7); + len = obj->stride*(obj->bbox.y2-obj->bbox.y1); + if (obj->allocatedallocated = len; + free(obj->bitmap_buffer); + free(obj->alpha_buffer); + obj->bitmap_buffer = memalign(16, len); + obj->alpha_buffer = memalign(16, len); + } + memset(obj->bitmap_buffer, sub_bg_color, len); + memset(obj->alpha_buffer, sub_bg_alpha, len); +} + +// renders the buffer +static void vo_draw_text_from_buffer(mp_osd_obj_t* obj,void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx) +{ + if (obj->allocated > 0) { + draw_alpha(ctx, + obj->bbox.x1,obj->bbox.y1, + obj->bbox.x2-obj->bbox.x1, + obj->bbox.y2-obj->bbox.y1, + obj->bitmap_buffer, + obj->alpha_buffer, + obj->stride); + } +} + +#ifdef CONFIG_DVDNAV +void osd_set_nav_box (uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey) { + nav_hl.sx = sx; + nav_hl.sy = sy; + nav_hl.ex = ex; + nav_hl.ey = ey; +} + +inline static void vo_update_nav (mp_osd_obj_t *obj, int dxs, int dys, int left_border, int top_border, + int right_border, int bottom_border, int orig_w, int orig_h) { + int len; + int sx = nav_hl.sx, sy = nav_hl.sy; + int ex = nav_hl.ex, ey = nav_hl.ey; + int scaled_w = dxs - left_border - right_border; + int scaled_h = dys - top_border - bottom_border; + if (scaled_w != orig_w) { + sx = sx * scaled_w / orig_w; + ex = ex * scaled_w / orig_w; + } + if (scaled_h != orig_h) { + sy = sy * scaled_h / orig_h; + ey = ey * scaled_h / orig_h; + } + sx += left_border; ex += left_border; + sy += top_border; ey += top_border; + sx = FFMIN(FFMAX(sx, 0), dxs); + ex = FFMIN(FFMAX(ex, 0), dxs); + sy = FFMIN(FFMAX(sy, 0), dys); + ey = FFMIN(FFMAX(ey, 0), dys); + + obj->bbox.x1 = obj->x = sx; + obj->bbox.y1 = obj->y = sy; + obj->bbox.x2 = ex; + obj->bbox.y2 = ey; + + osd_alloc_buf (obj); + len = obj->stride * (obj->bbox.y2 - obj->bbox.y1); + memset (obj->bitmap_buffer, OSD_NAV_BOX_ALPHA, len); + memset (obj->alpha_buffer, OSD_NAV_BOX_ALPHA, len); + obj->flags |= OSDFLAG_BBOX | OSDFLAG_CHANGED; + if (obj->bbox.y2 > obj->bbox.y1 && obj->bbox.x2 > obj->bbox.x1) + obj->flags |= OSDFLAG_VISIBLE; +} +#endif + + +inline static void vo_update_spudec_sub(struct osd_state *osd, mp_osd_obj_t* obj) +{ + unsigned int bbox[4]; + spudec_calc_bbox(vo_spudec, osd->w, osd->h, bbox); + obj->bbox.x1 = bbox[0]; + obj->bbox.x2 = bbox[1]; + obj->bbox.y1 = bbox[2]; + obj->bbox.y2 = bbox[3]; + obj->flags |= OSDFLAG_BBOX; +} + +inline static void vo_draw_spudec_sub(mp_osd_obj_t* obj, void (*draw_alpha)(void *ctx, int x0, int y0, int w, int h, unsigned char* src, unsigned char* srca, int stride), void *ctx) +{ + spudec_draw_scaled(vo_spudec, obj->dxs, obj->dys, draw_alpha, ctx); +} + +void *vo_spudec=NULL; +void *vo_vobsub=NULL; + +static int draw_alpha_init_flag=0; + +void vo_draw_alpha_init(void); + + mp_osd_obj_t* vo_osd_list=NULL; + +static mp_osd_obj_t* new_osd_obj(int type){ + mp_osd_obj_t* osd=malloc(sizeof(mp_osd_obj_t)); + memset(osd,0,sizeof(mp_osd_obj_t)); + osd->next=vo_osd_list; + vo_osd_list=osd; + osd->type=type; + osd->alpha_buffer = NULL; + osd->bitmap_buffer = NULL; + osd->allocated = -1; + return osd; +} + +void osd_free(struct osd_state *osd) +{ + osd_destroy_backend(osd); + mp_osd_obj_t* obj=vo_osd_list; + while(obj){ + mp_osd_obj_t* next=obj->next; + free(obj->alpha_buffer); + free(obj->bitmap_buffer); + free(obj); + obj=next; + } + vo_osd_list=NULL; + talloc_free(osd); +} + +static int osd_update_ext(struct osd_state *osd, int dxs, int dys, + int left_border, int top_border, int right_border, + int bottom_border, int orig_w, int orig_h) +{ + mp_osd_obj_t* obj=vo_osd_list; + int chg=0; + + osd->w = dxs; + osd->h = dys; + + while(obj){ + if(dxs!=obj->dxs || dys!=obj->dys || obj->flags&OSDFLAG_FORCE_UPDATE){ + int vis=obj->flags&OSDFLAG_VISIBLE; + obj->flags&=~OSDFLAG_BBOX; + switch(obj->type){ +#ifdef CONFIG_DVDNAV + case OSDTYPE_DVDNAV: + vo_update_nav(obj,dxs,dys, left_border, top_border, right_border, bottom_border, orig_w, orig_h); + break; +#endif + case OSDTYPE_SUBTITLE: + vo_update_text_sub(osd, obj); + break; + case OSDTYPE_TELETEXT: + vo_update_text_teletext(osd, obj); + break; + case OSDTYPE_PROGBAR: + vo_update_text_progbar(osd, obj); + break; + case OSDTYPE_SPU: + if(sub_visibility && vo_spudec && spudec_visible(vo_spudec)){ + vo_update_spudec_sub(osd, obj); + obj->flags|=OSDFLAG_VISIBLE|OSDFLAG_CHANGED; + } + else + obj->flags&=~OSDFLAG_VISIBLE; + break; + case OSDTYPE_OSD: + if(osd->osd_text[0]){ + vo_update_text_osd(osd, obj); + obj->flags|=OSDFLAG_VISIBLE|OSDFLAG_CHANGED; + } else + obj->flags&=~OSDFLAG_VISIBLE; + break; + } + // check bbox: + if(!(obj->flags&OSDFLAG_BBOX)){ + // we don't know, so assume the whole screen changed :( + obj->bbox.x1=obj->bbox.y1=0; + obj->bbox.x2=dxs; + obj->bbox.y2=dys; + obj->flags|=OSDFLAG_BBOX; + } else { + // check bbox, reduce it if it's out of bounds (corners): + if(obj->bbox.x1<0) obj->bbox.x1=0; + if(obj->bbox.y1<0) obj->bbox.y1=0; + if(obj->bbox.x2>dxs) obj->bbox.x2=dxs; + if(obj->bbox.y2>dys) obj->bbox.y2=dys; + if(obj->flags&OSDFLAG_VISIBLE) + // debug: + mp_msg(MSGT_OSD,MSGL_DBG2,"OSD update: %d;%d %dx%d \n", + obj->bbox.x1,obj->bbox.y1,obj->bbox.x2-obj->bbox.x1, + obj->bbox.y2-obj->bbox.y1); + } + // check if visibility changed: + if(vis != (obj->flags&OSDFLAG_VISIBLE) ) obj->flags|=OSDFLAG_CHANGED; + // remove the cause of automatic update: + obj->dxs=dxs; obj->dys=dys; + obj->flags&=~OSDFLAG_FORCE_UPDATE; + } + if(obj->flags&OSDFLAG_CHANGED){ + chg|=1<type; + mp_msg(MSGT_OSD,MSGL_DBG2,"OSD chg: %d V: %s pb:%d \n",obj->type,(obj->flags&OSDFLAG_VISIBLE)?"yes":"no",vo_osd_progbar_type); + } + obj=obj->next; + } + return chg; +} + +int osd_update(struct osd_state *osd, int dxs, int dys) +{ + return osd_update_ext(osd, dxs, dys, 0, 0, 0, 0, dxs, dys); +} + +struct osd_state *osd_create(struct MPOpts *opts, struct ass_library *asslib) +{ + struct osd_state *osd = talloc_zero(NULL, struct osd_state); + *osd = (struct osd_state){ + .opts = opts, + .ass_library = asslib, + }; + if(!draw_alpha_init_flag){ + draw_alpha_init_flag=1; + vo_draw_alpha_init(); + } + // temp hack, should be moved to mplayer later + new_osd_obj(OSDTYPE_OSD); + new_osd_obj(OSDTYPE_SUBTITLE); + new_osd_obj(OSDTYPE_PROGBAR); + new_osd_obj(OSDTYPE_SPU); +#ifdef CONFIG_DVDNAV + new_osd_obj(OSDTYPE_DVDNAV); +#endif + new_osd_obj(OSDTYPE_TELETEXT); + osd_set_text(osd, NULL); + osd_init_backend(osd); + return osd; +} + +void osd_set_text(struct osd_state *osd, const char *text) { + talloc_free(osd->osd_text); + //osd->text must never be NULL + if (!text) + text = ""; + osd->osd_text = talloc_strdup(osd, text); +} + +void osd_draw_text_ext(struct osd_state *osd, int dxs, int dys, + int left_border, int top_border, int right_border, + int bottom_border, int orig_w, int orig_h, + void (*draw_alpha)(void *ctx, int x0, int y0, int w, + int h, unsigned char* src, + unsigned char *srca, + int stride), + void *ctx) +{ + mp_osd_obj_t* obj=vo_osd_list; + osd_update_ext(osd, dxs, dys, left_border, top_border, right_border, + bottom_border, orig_w, orig_h); + while(obj){ + if(obj->flags&OSDFLAG_VISIBLE){ + switch(obj->type){ + case OSDTYPE_SPU: + vo_draw_spudec_sub(obj, draw_alpha, ctx); // FIXME + break; +#ifdef CONFIG_DVDNAV + case OSDTYPE_DVDNAV: +#endif + case OSDTYPE_TELETEXT: + case OSDTYPE_OSD: + case OSDTYPE_SUBTITLE: + case OSDTYPE_PROGBAR: + vo_draw_text_from_buffer(obj, draw_alpha, ctx); + break; + } + obj->old_bbox=obj->bbox; + obj->flags|=OSDFLAG_OLD_BBOX; + } + obj->flags&=~OSDFLAG_CHANGED; + obj=obj->next; + } +} + +void osd_draw_text(struct osd_state *osd, int dxs, int dys, + void (*draw_alpha)(void *ctx, int x0, int y0, int w, int h, + unsigned char* src, unsigned char *srca, + int stride), + void *ctx) +{ + osd_draw_text_ext(osd, dxs, dys, 0, 0, 0, 0, dxs, dys, draw_alpha, ctx); +} + +static int vo_osd_changed_status = 0; + +int vo_osd_changed(int new_value) +{ + mp_osd_obj_t* obj=vo_osd_list; + int ret = vo_osd_changed_status; + vo_osd_changed_status = new_value; + + while(obj){ + if(obj->type==new_value) obj->flags|=OSDFLAG_FORCE_UPDATE; + obj=obj->next; + } + + return ret; +} + +// return TRUE if we have osd in the specified rectangular area: +int vo_osd_check_range_update(int x1,int y1,int x2,int y2){ + mp_osd_obj_t* obj=vo_osd_list; + while(obj){ + if(obj->flags&OSDFLAG_VISIBLE){ + if( (obj->bbox.x1<=x2 && obj->bbox.x2>=x1) && + (obj->bbox.y1<=y2 && obj->bbox.y2>=y1) && + obj->bbox.y2 > obj->bbox.y1 && obj->bbox.x2 > obj->bbox.x1 + ) return 1; + } + obj=obj->next; + } + return 0; +} diff --git a/sub/sub.h b/sub/sub.h index 081834e3bb..5359701403 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -66,19 +66,26 @@ typedef struct mp_osd_obj_s { int allocated; unsigned char *alpha_buffer; unsigned char *bitmap_buffer; + + struct ass_track *osd_track; } mp_osd_obj_t; struct osd_state { struct ass_library *ass_library; // flag to signal reinitialization due to ass-related option changes bool ass_force_reload; + int w, h; char *osd_text; - struct font_desc *sub_font; struct ass_track *ass_track; double pts; double sub_offset; bool ass_track_changed; bool vsfilter_aspect; + + struct ass_renderer *osd_render; + struct ass_library *osd_ass_library; + + struct MPOpts *opts; }; #include "subreader.h" @@ -133,6 +140,21 @@ extern int spu_alignment; extern int spu_aamode; extern float spu_gaussvar; +extern char *subtitle_font_encoding; +extern float text_font_scale_factor; +extern float osd_font_scale_factor; +extern float subtitle_font_radius; +extern float subtitle_font_thickness; +extern int subtitle_autoscale; + +extern char *font_name; +extern char *sub_font_name; +extern float font_factor; +extern float sub_delay; +extern float sub_fps; + +extern int sub_justify; + void osd_draw_text(struct osd_state *osd, int dxs, int dys, void (*draw_alpha)(void *ctx, int x0, int y0, int w, int h, unsigned char* src, unsigned char *srca, @@ -146,28 +168,30 @@ void osd_draw_text_ext(struct osd_state *osd, int dxs, int dys, unsigned char *srca, int stride), void *ctx); -void osd_remove_text(struct osd_state *osd, int dxs, int dys, - void (*remove)(int x0, int y0, int w, int h)); -struct osd_state *osd_create(void); +struct osd_state *osd_create(struct MPOpts *opts, struct ass_library *asslib); void osd_set_text(struct osd_state *osd, const char *text); int osd_update(struct osd_state *osd, int dxs, int dys); int vo_osd_changed(int new_value); int vo_osd_check_range_update(int,int,int,int); void osd_free(struct osd_state *osd); -extern int vo_osd_changed_flag; - -unsigned utf8_get_char(const char **str); - #ifdef CONFIG_DVDNAV #include void osd_set_nav_box (uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey); #endif -#ifdef IS_OLD_VO -#define vo_remove_text(...) osd_remove_text(global_osd, __VA_ARGS__) -#endif +// used only by osd_libass.c +void osd_alloc_buf(mp_osd_obj_t* obj); + +// defined in osd_libass.c or osd_dummy.c +void vo_update_text_osd(struct osd_state *osd, mp_osd_obj_t *obj); +void vo_update_text_teletext(struct osd_state *osd, mp_osd_obj_t *obj); +void vo_update_text_progbar(struct osd_state *osd, mp_osd_obj_t *obj); +void vo_update_text_sub(struct osd_state *osd, mp_osd_obj_t *obj); +void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function); +void osd_init_backend(struct osd_state *osd); +void osd_destroy_backend(struct osd_state *osd); #endif /* MPLAYER_SUB_H */ diff --git a/sub/sub_cc.c b/sub/sub_cc.c index f18fa28c54..8919ce84f4 100644 --- a/sub/sub_cc.c +++ b/sub/sub_cc.c @@ -58,6 +58,8 @@ static int initialized=0; static int cc_mode=CC_ROLLON; static int cc_lines=4; ///< number of visible rows in CC roll-up mode, not used in CC roll-on mode +int subcc_enabled = 0; + static void build_char_table(void) { int i; diff --git a/sub/subreader.c b/sub/subreader.c index f694f57a7c..68c4ecbaf3 100644 --- a/sub/subreader.c +++ b/sub/subreader.c @@ -47,12 +47,8 @@ #include char *sub_cp=NULL; #endif -#ifdef CONFIG_FRIBIDI -#include -char *fribidi_charset = NULL; ///character set that will be passed to FriBiDi -int flip_hebrew = 1; ///flip subtitles using fribidi -int fribidi_flip_commas = 0; ///flip comma when fribidi is used -#endif + +int suboverlap_enabled = 1; // Parameter struct for the format-specific readline functions struct readline_args { @@ -1274,71 +1270,6 @@ subtitle* subcp_recode (subtitle *sub) } #endif -#ifdef CONFIG_FRIBIDI -/** - * Do conversion necessary for right-to-left language support via fribidi. - * @param sub subtitle to convert - * @param sub_utf8 whether the subtitle is encoded in UTF-8 - * @param from first new subtitle, all lines before this are assumed to be already converted - */ -static subtitle* sub_fribidi (subtitle *sub, int sub_utf8, int from) -{ - FriBidiChar logical[LINE_LEN+1], visual[LINE_LEN+1]; // Hopefully these two won't smash the stack - char *ip = NULL, *op = NULL; - size_t len,orig_len; - int l=sub->lines; - int char_set_num; - fribidi_boolean log2vis; - if (!flip_hebrew) - return sub; - fribidi_set_mirroring(1); - fribidi_set_reorder_nsm(0); - - if( sub_utf8 == 0 ) { - char_set_num = fribidi_parse_charset (fribidi_charset?fribidi_charset:"ISO8859-8"); - }else { - char_set_num = fribidi_parse_charset ("UTF-8"); - } - while (l > from) { - ip = sub->text[--l]; - orig_len = len = strlen( ip ); // We assume that we don't use full unicode, only UTF-8 or ISO8859-x - if(len > LINE_LEN) { - mp_msg(MSGT_SUBREADER,MSGL_WARN,"SUB: sub->text is longer than LINE_LEN.\n"); - l++; - break; - } - len = fribidi_charset_to_unicode (char_set_num, ip, len, logical); -#if FRIBIDI_INTERFACE_VERSION < 3 - FriBidiCharType base = fribidi_flip_commas?FRIBIDI_TYPE_ON:FRIBIDI_TYPE_L; -#else - FriBidiParType base = fribidi_flip_commas?FRIBIDI_TYPE_ON:FRIBIDI_TYPE_L; -#endif - log2vis = fribidi_log2vis (logical, len, &base, - /* output */ - visual, NULL, NULL, NULL); - if(log2vis) { - len = fribidi_remove_bidi_marks (visual, len, NULL, NULL, - NULL); - if((op = malloc((FFMAX(2*orig_len,2*len) + 1))) == NULL) { - mp_msg(MSGT_SUBREADER,MSGL_WARN,"SUB: error allocating mem.\n"); - l++; - break; - } - fribidi_unicode_to_charset ( char_set_num, visual, len,op); - free (ip); - sub->text[l] = op; - } - } - if (!from && l){ - for (l = sub->lines; l;) - free (sub->text[--l]); - return ERR; - } - return sub; -} - -#endif - static void adjust_subs_time(subtitle* sub, float subtime, float fps, int block, int sub_num, int sub_uses_time) { int n,m; @@ -1557,12 +1488,6 @@ sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts) #ifdef CONFIG_ICONV if ((sub!=ERR) && sub_utf8 == 2) sub=subcp_recode(sub); #endif -#ifdef CONFIG_FRIBIDI - /* Libass has its own BiDi handling now, and running this before - * giving the subtitle to libass would only break things. */ - if (sub != ERR && !opts->ass_enabled) - sub = sub_fribidi(sub, sub_utf8, 0); -#endif if ( sub == ERR ) { #ifdef CONFIG_ICONV @@ -2149,9 +2074,6 @@ void sub_add_text(subtitle *sub, const char *txt, int len, double endpts) { int double_newline = 1; // ignore newlines at the beginning int i, pos; char *buf; -#ifdef CONFIG_FRIBIDI - int orig_lines = sub->lines; -#endif if (sub->lines >= SUB_MAX_TEXT) return; pos = 0; buf = malloc(MAX_SUBLINE + 1); @@ -2196,9 +2118,6 @@ void sub_add_text(subtitle *sub, const char *txt, int len, double endpts) { if (sub->lines < SUB_MAX_TEXT && strlen(sub->text[sub->lines])) sub->lines++; -#ifdef CONFIG_FRIBIDI - sub = sub_fribidi(sub, sub_utf8, orig_lines); -#endif } /** diff --git a/sub/subreader.h b/sub/subreader.h index 079238a6c3..a6d0831413 100644 --- a/sub/subreader.h +++ b/sub/subreader.h @@ -79,10 +79,6 @@ typedef struct sub_data { int sub_errs; } sub_data; -extern char *fribidi_charset; -extern int flip_hebrew; -extern int fribidi_flip_commas; - struct MPOpts; sub_data* sub_read_file (char *filename, float pts, struct MPOpts *opts); subtitle* subcp_recode (subtitle *sub); -- 2.11.4.GIT