From ffb7a2fe17af204635db6694b5b49b6368be91e6 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 28 Sep 2012 21:19:36 +0200 Subject: sub: create sub_bitmap array even when using libass One sub_bitmaps struct could contain either a libass ASS_Image list, or a mplayer native list of sub-bitmaps. This caused code duplication in vo_vdpau.c and bitmap_packer.c. Avoid this by creating such a sub_bitmap array even with libass. This basically copies the list and recreates it in mplayer's native format. It gets rid of the code duplication, and will make implementing extended subtitle and OSD rendering in other VOs easier. Also do some cosmetic changes and other preparations for the following commits. --- libmpcodecs/vfcap.h | 1 - 1 file changed, 1 deletion(-) (limited to 'libmpcodecs') diff --git a/libmpcodecs/vfcap.h b/libmpcodecs/vfcap.h index aef75840ae..0bb255b3cd 100644 --- a/libmpcodecs/vfcap.h +++ b/libmpcodecs/vfcap.h @@ -46,7 +46,6 @@ #define VFCAP_EOSD_UNSCALED 0x4000 // used by libvo and vf_vo, indicates the VO does not support draw_slice for this format #define VOCAP_NOSLICES 0x8000 -#define VFCAP_OSD_FILTER 0x10000 // OSD is drawn in filter chain #define VFCAP_EOSD_FILTER 0x20000 // EOSD is drawn in filter chain #define VFCAP_EOSD_RGBA 0x40000 -- cgit v1.2.3 From 8f8f6e6d9d27eef37640b363214a775647a0f2f4 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 3 Oct 2012 17:00:37 +0200 Subject: sub: remove logic for disabling hinting on scaled EOSD This was an extremely obscure setting, as it was used only with vo_gl if its scaled-osd suboption was used. If you really want this, you can set the desired ass-hinting value directly, and there will be literally no loss in functionality. Note that this didn't actually test whether the EOSD was scaled. Basically, it only checked whether vo_gl had the scaled-osd suboption set. --- libmpcodecs/vf_vo.c | 1 - libmpcodecs/vfcap.h | 2 -- 2 files changed, 3 deletions(-) (limited to 'libmpcodecs') diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c index 862cd63492..49668d4640 100644 --- a/libmpcodecs/vf_vo.c +++ b/libmpcodecs/vf_vo.c @@ -126,7 +126,6 @@ static int control(struct vf_instance *vf, int request, void *data) return CONTROL_FALSE; osd->normal_scale = 1; osd->vsfilter_scale = vf->priv->scale_ratio; - osd->unscaled = vf->default_caps & VFCAP_EOSD_UNSCALED; struct sub_bitmaps images; sub_get_bitmaps(osd, &images); return vo_control(video_out, VOCTRL_DRAW_EOSD, &images) == VO_TRUE; diff --git a/libmpcodecs/vfcap.h b/libmpcodecs/vfcap.h index 0bb255b3cd..0fb73f5a51 100644 --- a/libmpcodecs/vfcap.h +++ b/libmpcodecs/vfcap.h @@ -42,8 +42,6 @@ #define VFCAP_POSTPROC 0x800 // filter can draw EOSD #define VFCAP_EOSD 0x2000 -// filter will draw EOSD at screen resolution (without scaling) -#define VFCAP_EOSD_UNSCALED 0x4000 // used by libvo and vf_vo, indicates the VO does not support draw_slice for this format #define VOCAP_NOSLICES 0x8000 #define VFCAP_EOSD_FILTER 0x20000 // EOSD is drawn in filter chain -- cgit v1.2.3 From 17f5019b468d5269408b7dae53a24e17426de7d5 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 4 Oct 2012 17:16:32 +0200 Subject: sub: always go through sub.c for OSD rendering Before this commit, vf_vo.c and vf_ass.c were manually calling the subtitle decoder to retrieve images to render. In particular, this circumvented the sub-bitmap conversion & caching layer in sub.c. Change this so that subtitle decoding isn't special anymore, and draws all subtitles with the normal OSD drawing API. This is also a step towards removing the need for vf_ass auto-insertion. In fact, if auto-insertion would be disabled now, VOs with "old" OSD rendering could still render ASS subtitles in monochrome, because there is still ASS -> old-OSD bitmap conversion in the sub.c mechanism. The code is written with the assumption that the subtitle rendering filter (vf_ass) can render all subtitle formats. Since vf_ass knows the ASS format only, rendering image subs (i.e. RGBA subs) with it simply fails. This means that with vo_xv (vf_ass auto-inserted), image subs wouldn't be rendered. Use a dumb hack to disable rendering subs with a filter, if we detect that the subs are not in ASS format. (Trying to render the subs first would probably result in purging the conversion cache on every frame.) --- libmpcodecs/vf.h | 3 +-- libmpcodecs/vf_ass.c | 30 ++++++++++++++---------------- libmpcodecs/vf_vo.c | 16 ---------------- 3 files changed, 15 insertions(+), 34 deletions(-) (limited to 'libmpcodecs') diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h index ec8144b22f..8b18470e62 100644 --- a/libmpcodecs/vf.h +++ b/libmpcodecs/vf.h @@ -104,8 +104,7 @@ struct vf_ctrl_screenshot { #define VFCTRL_SKIP_NEXT_FRAME 12 // For encoding - drop the next frame that passes thru #define VFCTRL_FLUSH_FRAMES 13 // For encoding - flush delayed frames #define VFCTRL_SCREENSHOT 14 // Take screenshot, arg is vf_ctrl_screenshot -#define VFCTRL_INIT_EOSD 15 // Select EOSD renderer -#define VFCTRL_DRAW_EOSD 16 // Render EOSD */ +#define VFCTRL_INIT_OSD 15 // Filter OSD renderer present? #define VFCTRL_SET_DEINTERLACE 18 // Set deinterlacing status #define VFCTRL_GET_DEINTERLACE 19 // Get deinterlacing status /* Hack to make the OSD state object available to vf_expand and vf_ass which diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index f0b2e6ab77..937912313b 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -355,23 +355,23 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) struct vf_priv_s *priv = vf->priv; struct MPOpts *opts = vf->opts; struct osd_state *osd = priv->osd; - ASS_Image *images = 0; + struct sub_bitmaps imgs = (struct sub_bitmaps) {0}; if (pts != MP_NOPTS_VALUE) { - osd->dim = (struct mp_eosd_res){ .w = vf->priv->outw, - .h = vf->priv->outh, - .mt = opts->ass_top_margin, - .mb = opts->ass_bottom_margin }; - osd->normal_scale = vf->priv->aspect_correction; - osd->vsfilter_scale = 1; - osd->sub_pts = pts - osd->sub_offset; - osd->support_rgba = false; - struct sub_bitmaps b; - sub_get_bitmaps(osd, &b); - images = b.imgs; + struct sub_render_params subparams = { + .pts = pts, + .dim = { .w = vf->priv->outw, + .h = vf->priv->outh, + .mt = opts->ass_top_margin, + .mb = opts->ass_bottom_margin }, + .normal_scale = vf->priv->aspect_correction, + .vsfilter_scale = 1, + }; + bool formats[SUBBITMAP_COUNT] = {[SUBBITMAP_LIBASS] = true}; + osd_draw_sub(osd, &imgs, &subparams, formats); } prepare_image(vf, mpi); - render_frame(vf, mpi, images); + render_frame(vf, mpi, imgs.imgs); return vf_next_put_image(vf, vf->dmpi, pts); } @@ -393,9 +393,7 @@ static int control(vf_instance_t *vf, int request, void *data) case VFCTRL_SET_OSD_OBJ: vf->priv->osd = data; break; - case VFCTRL_INIT_EOSD: - return CONTROL_TRUE; - case VFCTRL_DRAW_EOSD: + case VFCTRL_INIT_OSD: return CONTROL_TRUE; } return vf_next_control(vf, request, data); diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c index 49668d4640..998b4b6dfa 100644 --- a/libmpcodecs/vf_vo.c +++ b/libmpcodecs/vf_vo.c @@ -34,7 +34,6 @@ struct vf_priv_s { struct vo *vo; - double scale_ratio; }; #define video_out (vf->priv->vo) @@ -74,8 +73,6 @@ static int config(struct vf_instance *vf, if (vo_config(video_out, width, height, d_width, d_height, flags, outfmt)) return 0; - vf->priv->scale_ratio = (double) d_width / d_height * height / width; - return 1; } @@ -117,19 +114,6 @@ static int control(struct vf_instance *vf, int request, void *data) }; return vo_control(video_out, VOCTRL_GET_EQUALIZER, ¶m) == VO_TRUE; } - case VFCTRL_DRAW_EOSD: { - struct osd_state *osd = data; - osd->support_rgba = vf->default_caps & VFCAP_EOSD_RGBA; - osd->dim = (struct mp_eosd_res){0}; - if (!video_out->config_ok || - vo_control(video_out, VOCTRL_GET_EOSD_RES, &osd->dim) != true) - return CONTROL_FALSE; - osd->normal_scale = 1; - osd->vsfilter_scale = vf->priv->scale_ratio; - struct sub_bitmaps images; - sub_get_bitmaps(osd, &images); - return vo_control(video_out, VOCTRL_DRAW_EOSD, &images) == VO_TRUE; - } } return CONTROL_UNKNOWN; } -- cgit v1.2.3 From cc05910f16a5ccd8e3dca26a89e9c3835cbdb645 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 4 Oct 2012 17:16:40 +0200 Subject: sub: cosmetics: move things around Move sub-bitmap definitions from dec_sub.h to sub.h. While it's a bit odd that OSD data structures are in a file named sub.h, it's definitely way too strange to have them in a file about subtitle decoding. (Maybe sub.h/.c and the sub/ directory should be split out and renamed "osd" at a later point.) Remove including ass_mp.h (and the libass headers) where possible. Remove typedefs for mp_eosd_res and sub_bitmaps structs. Store a mp_eosd_res struct in osd_state instead of just w/h. Note that sbtitles might be rendered using different sizes/margins when filters are involved (the subtitle renderer is not supposed to use the OSD res directly, and the "dim" member removed in the previous commit is something different). --- libmpcodecs/vf_ass.c | 1 + 1 file changed, 1 insertion(+) (limited to 'libmpcodecs') diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index 937912313b..77248b49c0 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -35,6 +35,7 @@ #include "mp_image.h" #include "vf.h" #include "sub/sub.h" +#include "sub/dec_sub.h" #include "libvo/fastmemcpy.h" -- cgit v1.2.3 From 64ac38c4d30e30783032a4b65f34f4fb50761c7b Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Wed, 24 Oct 2012 19:00:49 +0200 Subject: libmpcodecs: move vf_scale.c swscale helper functions to sws_utils.c Extracted/rebased by wm4 from commits 93978f17b76d..13211ef5fc20. Actual mp_image_swscale is added in a later commit. --- libmpcodecs/sws_utils.c | 134 ++++++++++++++++++++++++++++++++++++++++++++ libmpcodecs/sws_utils.h | 27 +++++++++ libmpcodecs/vf_scale.c | 83 +-------------------------- libmpcodecs/vf_scale.h | 28 --------- libmpcodecs/vf_screenshot.c | 2 +- 5 files changed, 163 insertions(+), 111 deletions(-) create mode 100644 libmpcodecs/sws_utils.c create mode 100644 libmpcodecs/sws_utils.h delete mode 100644 libmpcodecs/vf_scale.h (limited to 'libmpcodecs') diff --git a/libmpcodecs/sws_utils.c b/libmpcodecs/sws_utils.c new file mode 100644 index 0000000000..438db4a13a --- /dev/null +++ b/libmpcodecs/sws_utils.c @@ -0,0 +1,134 @@ +/* + * 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 "libmpcodecs/sws_utils.h" + +#include "libmpcodecs/mp_image.h" +#include "libmpcodecs/img_format.h" +#include "fmt-conversion.h" +#include "libvo/csputils.h" +#include "mp_msg.h" + +//global sws_flags from the command line +int sws_flags = 2; + +float sws_lum_gblur = 0.0; +float sws_chr_gblur = 0.0; +int sws_chr_vshift = 0; +int sws_chr_hshift = 0; +float sws_chr_sharpen = 0.0; +float sws_lum_sharpen = 0.0; + +//global srcFilter +static SwsFilter *src_filter = NULL; + +void sws_getFlagsAndFilterFromCmdLine(int *flags, SwsFilter **srcFilterParam, + SwsFilter **dstFilterParam) +{ + static int firstTime = 1; + *flags = 0; + + if (firstTime) { + firstTime = 0; + *flags = SWS_PRINT_INFO; + } else if (mp_msg_test(MSGT_VFILTER, MSGL_DBG2)) + *flags = SWS_PRINT_INFO; + + if (src_filter) + sws_freeFilter(src_filter); + + src_filter = sws_getDefaultFilter( + sws_lum_gblur, sws_chr_gblur, + sws_lum_sharpen, sws_chr_sharpen, + sws_chr_hshift, sws_chr_vshift, verbose > 1); + + switch (sws_flags) { + case 0: *flags |= SWS_FAST_BILINEAR; + break; + case 1: *flags |= SWS_BILINEAR; + break; + case 2: *flags |= SWS_BICUBIC; + break; + case 3: *flags |= SWS_X; + break; + case 4: *flags |= SWS_POINT; + break; + case 5: *flags |= SWS_AREA; + break; + case 6: *flags |= SWS_BICUBLIN; + break; + case 7: *flags |= SWS_GAUSS; + break; + case 8: *flags |= SWS_SINC; + break; + case 9: *flags |= SWS_LANCZOS; + break; + case 10: *flags |= SWS_SPLINE; + break; + default: *flags |= SWS_BILINEAR; + break; + } + + *srcFilterParam = src_filter; + *dstFilterParam = NULL; +} + +// will use sws_flags & src_filter (from cmd line) +static struct SwsContext *sws_getContextFromCmdLine2(int srcW, int srcH, + int srcFormat, int dstW, + int dstH, int dstFormat, + int extraflags) +{ + int flags; + SwsFilter *dstFilterParam, *srcFilterParam; + enum PixelFormat dfmt, sfmt; + + dfmt = imgfmt2pixfmt(dstFormat); + sfmt = imgfmt2pixfmt(srcFormat); + if (srcFormat == IMGFMT_RGB8 || srcFormat == IMGFMT_BGR8) + sfmt = PIX_FMT_PAL8; + sws_getFlagsAndFilterFromCmdLine(&flags, &srcFilterParam, &dstFilterParam); + + return sws_getContext(srcW, srcH, sfmt, dstW, dstH, dfmt, flags | + extraflags, srcFilterParam, dstFilterParam, + NULL); +} + +struct SwsContext *sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, + int dstW, int dstH, + int dstFormat) +{ + return sws_getContextFromCmdLine2(srcW, srcH, srcFormat, dstW, dstH, + dstFormat, + 0); +} + +struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, + int srcFormat, int dstW, + int dstH, + int dstFormat) +{ + return sws_getContextFromCmdLine2( + srcW, srcH, srcFormat, dstW, dstH, dstFormat, + SWS_FULL_CHR_H_INT | SWS_FULL_CHR_H_INP | + SWS_ACCURATE_RND | SWS_BITEXACT); +} + +// vim: ts=4 sw=4 et tw=80 diff --git a/libmpcodecs/sws_utils.h b/libmpcodecs/sws_utils.h new file mode 100644 index 0000000000..a8dc970d08 --- /dev/null +++ b/libmpcodecs/sws_utils.h @@ -0,0 +1,27 @@ +#ifndef MPLAYER_SWS_UTILS_H +#define MPLAYER_SWS_UTILS_H + +#include + +struct mp_image; +struct mp_csp_details; + +// libswscale currently requires 16 bytes alignment for row pointers and +// strides. Otherwise, it will print warnings and use slow codepaths. +// Guaranteed to be a power of 2 and > 1. +#define SWS_MIN_BYTE_ALIGN 16 + +void sws_getFlagsAndFilterFromCmdLine(int *flags, SwsFilter **srcFilterParam, + SwsFilter **dstFilterParam); +struct SwsContext *sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, + int dstW, int dstH, + int dstFormat); +struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, + int srcFormat, int dstW, + int dstH, + int dstFormat); +int mp_sws_set_colorspace(struct SwsContext *sws, struct mp_csp_details *csp); + +#endif /* MP_SWS_UTILS_H */ + +// vim: ts=4 sw=4 et tw=80 diff --git a/libmpcodecs/vf_scale.c b/libmpcodecs/vf_scale.c index 71428685ac..5ea62bacbd 100644 --- a/libmpcodecs/vf_scale.c +++ b/libmpcodecs/vf_scale.c @@ -32,8 +32,7 @@ #include "fmt-conversion.h" #include "mpbswap.h" -#include "libswscale/swscale.h" -#include "vf_scale.h" +#include "libmpcodecs/sws_utils.h" #include "libvo/csputils.h" // VOFLAG_SWSCALE @@ -68,8 +67,6 @@ static struct vf_priv_s { //===========================================================================// -void sws_getFlagsAndFilterFromCmdLine(int *flags, SwsFilter **srcFilterParam, SwsFilter **dstFilterParam); - static const unsigned int outfmt_list[]={ // YUV: IMGFMT_444P, @@ -647,84 +644,6 @@ static int vf_open(vf_instance_t *vf, char *args){ return 1; } -//global sws_flags from the command line -int sws_flags=2; - -//global srcFilter -static SwsFilter *src_filter= NULL; - -float sws_lum_gblur= 0.0; -float sws_chr_gblur= 0.0; -int sws_chr_vshift= 0; -int sws_chr_hshift= 0; -float sws_chr_sharpen= 0.0; -float sws_lum_sharpen= 0.0; - -void sws_getFlagsAndFilterFromCmdLine(int *flags, SwsFilter **srcFilterParam, SwsFilter **dstFilterParam) -{ - static int firstTime=1; - *flags=0; - - if(firstTime) - { - firstTime=0; - *flags= SWS_PRINT_INFO; - } - else if( mp_msg_test(MSGT_VFILTER,MSGL_DBG2) ) *flags= SWS_PRINT_INFO; - - if(src_filter) sws_freeFilter(src_filter); - - src_filter= sws_getDefaultFilter( - sws_lum_gblur, sws_chr_gblur, - sws_lum_sharpen, sws_chr_sharpen, - sws_chr_hshift, sws_chr_vshift, verbose>1); - - switch(sws_flags) - { - case 0: *flags|= SWS_FAST_BILINEAR; break; - case 1: *flags|= SWS_BILINEAR; break; - case 2: *flags|= SWS_BICUBIC; break; - case 3: *flags|= SWS_X; break; - case 4: *flags|= SWS_POINT; break; - case 5: *flags|= SWS_AREA; break; - case 6: *flags|= SWS_BICUBLIN; break; - case 7: *flags|= SWS_GAUSS; break; - case 8: *flags|= SWS_SINC; break; - case 9: *flags|= SWS_LANCZOS; break; - case 10:*flags|= SWS_SPLINE; break; - default:*flags|= SWS_BILINEAR; break; - } - - *srcFilterParam= src_filter; - *dstFilterParam= NULL; -} - -// will use sws_flags & src_filter (from cmd line) -static struct SwsContext *sws_getContextFromCmdLine2(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat, int extraflags) -{ - int flags; - SwsFilter *dstFilterParam, *srcFilterParam; - enum PixelFormat dfmt, sfmt; - - dfmt = imgfmt2pixfmt(dstFormat); - sfmt = imgfmt2pixfmt(srcFormat); - if (srcFormat == IMGFMT_RGB8 || srcFormat == IMGFMT_BGR8) sfmt = PIX_FMT_PAL8; - sws_getFlagsAndFilterFromCmdLine(&flags, &srcFilterParam, &dstFilterParam); - - return sws_getContext(srcW, srcH, sfmt, dstW, dstH, dfmt, flags | extraflags, srcFilterParam, dstFilterParam, NULL); -} - -struct SwsContext *sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat) -{ - return sws_getContextFromCmdLine2(srcW, srcH, srcFormat, dstW, dstH, dstFormat, 0); -} - -struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat) -{ - return sws_getContextFromCmdLine2(srcW, srcH, srcFormat, dstW, dstH, dstFormat, - SWS_FULL_CHR_H_INT | SWS_FULL_CHR_H_INP | SWS_ACCURATE_RND | SWS_BITEXACT); -} - /// An example of presets usage static const struct size_preset { char* name; diff --git a/libmpcodecs/vf_scale.h b/libmpcodecs/vf_scale.h deleted file mode 100644 index 575d4f3640..0000000000 --- a/libmpcodecs/vf_scale.h +++ /dev/null @@ -1,28 +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_VF_SCALE_H -#define MPLAYER_VF_SCALE_H - -struct SwsContext *sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat); -struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat); - -struct mp_csp_details; -int mp_sws_set_colorspace(struct SwsContext *sws, struct mp_csp_details *csp); - -#endif /* MPLAYER_VF_SCALE_H */ diff --git a/libmpcodecs/vf_screenshot.c b/libmpcodecs/vf_screenshot.c index eb961d8118..013525694a 100644 --- a/libmpcodecs/vf_screenshot.c +++ b/libmpcodecs/vf_screenshot.c @@ -27,7 +27,7 @@ #include "img_format.h" #include "mp_image.h" #include "vf.h" -#include "vf_scale.h" +#include "libmpcodecs/sws_utils.h" #include "fmt-conversion.h" #include "libvo/fastmemcpy.h" -- cgit v1.2.3 From 1282f9d79e09160af67ec13c05c0eed1ae02bd46 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Wed, 24 Oct 2012 19:05:49 +0200 Subject: mp_image: fix copy_mpi() with 16 bit formats, add helper macros Merged by wm4. copy_mpi() assumed that planar YUV formats always used 1 byte per component, which is not true for 9/10/16 bit YUV formats. --- libmpcodecs/mp_image.c | 12 +++++++----- libmpcodecs/mp_image.h | 10 ++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'libmpcodecs') diff --git a/libmpcodecs/mp_image.c b/libmpcodecs/mp_image.c index 006b0bf4f3..28472d092c 100644 --- a/libmpcodecs/mp_image.c +++ b/libmpcodecs/mp_image.c @@ -40,7 +40,9 @@ void mp_image_alloc_planes(mp_image_t *mpi) { if (!mpi->planes[0]) abort(); //out of memory if (mpi->flags&MP_IMGFLAG_PLANAR) { - int bpp = IMGFMT_IS_YUVP16(mpi->imgfmt)? 2 : 1; + // FIXME this code only supports same bpp for all planes, and bpp divisible + // by 8. Currently the case for all planar formats. + int bpp = MP_IMAGE_PLANAR_BITS_PER_PIXEL_ON_PLANE(mpi, 0) / 8; // YV12/I420/YVU9/IF09. feel free to add other planar formats here... mpi->stride[0]=mpi->stride[3]=bpp*mpi->width; if(mpi->num_planes > 2){ @@ -82,15 +84,15 @@ mp_image_t* alloc_mpi(int w, int h, unsigned long int fmt) { void copy_mpi(mp_image_t *dmpi, mp_image_t *mpi) { if(mpi->flags&MP_IMGFLAG_PLANAR){ - memcpy_pic(dmpi->planes[0],mpi->planes[0], mpi->w, mpi->h, + memcpy_pic(dmpi->planes[0],mpi->planes[0], MP_IMAGE_BYTES_PER_ROW_ON_PLANE(mpi, 0), mpi->h, dmpi->stride[0],mpi->stride[0]); - memcpy_pic(dmpi->planes[1],mpi->planes[1], mpi->chroma_width, mpi->chroma_height, + memcpy_pic(dmpi->planes[1],mpi->planes[1], MP_IMAGE_BYTES_PER_ROW_ON_PLANE(mpi, 1), mpi->chroma_height, dmpi->stride[1],mpi->stride[1]); - memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->chroma_width, mpi->chroma_height, + memcpy_pic(dmpi->planes[2], mpi->planes[2], MP_IMAGE_BYTES_PER_ROW_ON_PLANE(mpi, 2), mpi->chroma_height, dmpi->stride[2],mpi->stride[2]); } else { memcpy_pic(dmpi->planes[0],mpi->planes[0], - mpi->w*(dmpi->bpp/8), mpi->h, + MP_IMAGE_BYTES_PER_ROW_ON_PLANE(mpi, 0), mpi->h, dmpi->stride[0],mpi->stride[0]); } } diff --git a/libmpcodecs/mp_image.h b/libmpcodecs/mp_image.h index 6dbe3bfe02..e1cbe7d2cf 100644 --- a/libmpcodecs/mp_image.h +++ b/libmpcodecs/mp_image.h @@ -130,4 +130,14 @@ mp_image_t* alloc_mpi(int w, int h, unsigned long int fmt); void mp_image_alloc_planes(mp_image_t *mpi); void copy_mpi(mp_image_t *dmpi, mp_image_t *mpi); +// this macro requires img_format.h to be included too: +#define MP_IMAGE_PLANAR_BITS_PER_PIXEL_ON_PLANE(mpi, p) \ + (IMGFMT_IS_YUVP16((mpi)->imgfmt) ? 16 : 8) +#define MP_IMAGE_BITS_PER_PIXEL_ON_PLANE(mpi, p) \ + (((mpi)->flags & MP_IMGFLAG_PLANAR) \ + ? MP_IMAGE_PLANAR_BITS_PER_PIXEL_ON_PLANE(mpi, p) \ + : (mpi)->bpp) +#define MP_IMAGE_BYTES_PER_ROW_ON_PLANE(mpi, p) \ + ((MP_IMAGE_BITS_PER_PIXEL_ON_PLANE(mpi, p) * ((mpi)->w >> (p ? mpi->chroma_x_shift : 0)) + 7) / 8) + #endif /* MPLAYER_MP_IMAGE_H */ -- cgit v1.2.3 From aa1047a35a98606c972cc35e566178703b1f2bff Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Wed, 24 Oct 2012 19:11:42 +0200 Subject: sub: add helper to draw sub-bitmaps into an image Merged by wm4 from commits 93978f17b76d..13211ef5fc20. Changed copyright header in draw_bmp.c to "mpv", and removed the one in draw_bmp.h. --- libmpcodecs/sws_utils.c | 24 ++++++++++++++++++++++++ libmpcodecs/sws_utils.h | 3 +++ 2 files changed, 27 insertions(+) (limited to 'libmpcodecs') diff --git a/libmpcodecs/sws_utils.c b/libmpcodecs/sws_utils.c index 438db4a13a..65b079dd84 100644 --- a/libmpcodecs/sws_utils.c +++ b/libmpcodecs/sws_utils.c @@ -131,4 +131,28 @@ struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, SWS_ACCURATE_RND | SWS_BITEXACT); } +void mp_image_swscale(struct mp_image *dst, + const struct mp_image *src, + struct mp_csp_details *csp, + int my_sws_flags) +{ + enum PixelFormat dfmt, sfmt; + dfmt = imgfmt2pixfmt(dst->imgfmt); + sfmt = imgfmt2pixfmt(src->imgfmt); + if (src->imgfmt == IMGFMT_RGB8 || src->imgfmt == IMGFMT_BGR8) + sfmt = PIX_FMT_PAL8; + + struct SwsContext *sws = + sws_getContext(src->w, src->h, sfmt, dst->w, dst->h, dfmt, + my_sws_flags, NULL, NULL, NULL); + struct mp_csp_details mycsp = MP_CSP_DETAILS_DEFAULTS; + if (csp) + mycsp = *csp; + mp_sws_set_colorspace(sws, &mycsp); + sws_scale(sws, (const unsigned char *const *) src->planes, src->stride, + 0, src->h, + dst->planes, dst->stride); + sws_freeContext(sws); +} + // vim: ts=4 sw=4 et tw=80 diff --git a/libmpcodecs/sws_utils.h b/libmpcodecs/sws_utils.h index a8dc970d08..b2c55eb407 100644 --- a/libmpcodecs/sws_utils.h +++ b/libmpcodecs/sws_utils.h @@ -22,6 +22,9 @@ struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, int dstFormat); int mp_sws_set_colorspace(struct SwsContext *sws, struct mp_csp_details *csp); +void mp_image_swscale(struct mp_image *dst, const struct mp_image *src, + struct mp_csp_details *csp, int my_sws_flags); + #endif /* MP_SWS_UTILS_H */ // vim: ts=4 sw=4 et tw=80 -- cgit v1.2.3 From 73f18ace91fb040f7016df28e66ebe5ce7177e66 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 17 Oct 2012 13:46:46 +0200 Subject: mp_image: hack to fix alignment for certain image formats This is to get rid of swscale alignment warnings with the new OSD code. Only image formats used by it are fixed. Solving this generally would require some more effort. (Possibly by using libav's allocation functions plus lots of testing.) --- libmpcodecs/mp_image.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'libmpcodecs') diff --git a/libmpcodecs/mp_image.c b/libmpcodecs/mp_image.c index 28472d092c..1ba9e8e753 100644 --- a/libmpcodecs/mp_image.c +++ b/libmpcodecs/mp_image.c @@ -26,11 +26,30 @@ #include "libmpcodecs/img_format.h" #include "libmpcodecs/mp_image.h" +#include "libmpcodecs/sws_utils.h" #include "libvo/fastmemcpy.h" #include "libavutil/mem.h" +#include "libavutil/common.h" void mp_image_alloc_planes(mp_image_t *mpi) { + if (mpi->imgfmt == IMGFMT_BGRA) { + mpi->stride[0]=FFALIGN(mpi->width*4,SWS_MIN_BYTE_ALIGN); + mpi->planes[0]=av_malloc(mpi->stride[0]*mpi->height); + mpi->flags|=MP_IMGFLAG_ALLOCATED; + return; + } + if (mpi->imgfmt == IMGFMT_444P16 || mpi->imgfmt == IMGFMT_444P) { + int bp = mpi->imgfmt == IMGFMT_444P16 ? 2 : 1; + mpi->stride[0]=FFALIGN(mpi->width*bp,SWS_MIN_BYTE_ALIGN); + mpi->stride[1]=mpi->stride[2]=mpi->stride[0]; + int imgsize = mpi->stride[0] * mpi->height; + mpi->planes[0]=av_malloc(imgsize*3); + mpi->planes[1]=mpi->planes[0]+imgsize; + mpi->planes[2]=mpi->planes[1]+imgsize; + mpi->flags|=MP_IMGFLAG_ALLOCATED; + return; + } // IF09 - allocate space for 4. plane delta info - unused if (mpi->imgfmt == IMGFMT_IF09) { mpi->planes[0]=av_malloc(mpi->bpp*mpi->width*(mpi->height+2)/8+ -- cgit v1.2.3 From 98f74335d509320f19db2da8786273f95cad2a69 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 18 Oct 2012 17:31:00 +0200 Subject: sub: fix text subtitle aspect ratio with vo_xv and vo_lavc, refactor This fixes that vo_xv didn't display text subtitles correctly when using anamorphic video. It didn't pass the aspect information to the subtitle renderer. Also, try to render OSD correctly with respect to aspect ratio settings: on vo_xv, the OSD is rendered into the video, and needs to be "stretched" too when playing anamorphic video. When the -monitorpixelaspect option is used, even with VOs such as vo_opengl the OSD has to be rendered with that aspect ratio. As preparation for future commits, replace the weird vsfilter_scale value with a somewhat more sensible video_par member. Also, struct mp_eosd_res is a better place for the aspect ratio parameters, as OSD needs this too. Use osd_draw_on_image() directly in vo_lavc, which fixes aspect ratio issues as well. --- libmpcodecs/vf_ass.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'libmpcodecs') diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index 77248b49c0..167ebd6e15 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -63,7 +63,7 @@ static const struct vf_priv_s { int auto_insert; struct osd_state *osd; - double aspect_correction; + struct mp_eosd_res dim; unsigned char *planes[3]; struct line_limits { @@ -92,7 +92,17 @@ static int config(struct vf_instance *vf, vf->priv->planes[2] = malloc(vf->priv->outw * vf->priv->outh); vf->priv->line_limits = malloc((vf->priv->outh + 1) / 2 * sizeof(*vf->priv->line_limits)); - vf->priv->aspect_correction = (double)width / height * d_height / d_width; + double dar = (double)d_width / d_height; + double sar = (double)width / height; + + vf->priv->dim = (struct mp_eosd_res) { + .w = vf->priv->outw, + .h = vf->priv->outh, + .mt = opts->ass_top_margin, + .mb = opts->ass_bottom_margin, + .display_par = sar / dar, + .video_par = dar / sar, + }; return vf_next_config(vf, vf->priv->outw, vf->priv->outh, d_width, d_height, flags, outfmt); @@ -354,18 +364,12 @@ static int render_frame(struct vf_instance *vf, mp_image_t *mpi, static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) { struct vf_priv_s *priv = vf->priv; - struct MPOpts *opts = vf->opts; struct osd_state *osd = priv->osd; struct sub_bitmaps imgs = (struct sub_bitmaps) {0}; if (pts != MP_NOPTS_VALUE) { struct sub_render_params subparams = { .pts = pts, - .dim = { .w = vf->priv->outw, - .h = vf->priv->outh, - .mt = opts->ass_top_margin, - .mb = opts->ass_bottom_margin }, - .normal_scale = vf->priv->aspect_correction, - .vsfilter_scale = 1, + .dim = priv->dim, }; bool formats[SUBBITMAP_COUNT] = {[SUBBITMAP_LIBASS] = true}; osd_draw_sub(osd, &imgs, &subparams, formats); -- cgit v1.2.3 From 97c6425140aecc3910a622fb0ad7d79916cfebbe Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 19 Oct 2012 19:11:08 +0200 Subject: sub, vf_ass: allow rendering RGBA subs, replace old vf_ass rendering Do this by replacing all the old vf_ass drawing code by draw_bmp.c. Change sub.c to always use osd_draw() for the other OSD drawing routines, and simplify the code a bit. spudec.c subtitles (i.e. DVD subs) are now considered subtitles, and are rendered by vf_ass, if that filter is inserted. --- libmpcodecs/vf_ass.c | 171 +++++---------------------------------------------- 1 file changed, 15 insertions(+), 156 deletions(-) (limited to 'libmpcodecs') diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index 167ebd6e15..9695ecfdfc 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -38,25 +38,16 @@ #include "sub/dec_sub.h" #include "libvo/fastmemcpy.h" +#include "libvo/csputils.h" #include "m_option.h" #include "m_struct.h" -#include "sub/ass_mp.h" - -#define _r(c) ((c)>>24) -#define _g(c) (((c)>>16)&0xFF) -#define _b(c) (((c)>>8)&0xFF) -#define _a(c) ((c)&0xFF) -#define rgba2y(c) ( (( 263*_r(c) + 516*_g(c) + 100*_b(c)) >> 10) + 16 ) -#define rgba2u(c) ( ((-152*_r(c) - 298*_g(c) + 450*_b(c)) >> 10) + 128 ) -#define rgba2v(c) ( (( 450*_r(c) - 376*_g(c) - 73*_b(c)) >> 10) + 128 ) - - static const struct vf_priv_s { int outh, outw; unsigned int outfmt; + struct mp_csp_details csp; // 1 = auto-added filter: insert only if chain does not support EOSD already // 0 = insert always @@ -64,13 +55,9 @@ static const struct vf_priv_s { struct osd_state *osd; struct mp_eosd_res dim; - - unsigned char *planes[3]; - struct line_limits { - uint16_t start; - uint16_t end; - } *line_limits; -} vf_priv_dflt; +} vf_priv_dflt = { + .csp = MP_CSP_DETAILS_DEFAULTS, +}; static int config(struct vf_instance *vf, int width, int height, int d_width, int d_height, @@ -88,10 +75,6 @@ static int config(struct vf_instance *vf, d_height = d_height * vf->priv->outh / height; } - vf->priv->planes[1] = malloc(vf->priv->outw * vf->priv->outh); - vf->priv->planes[2] = malloc(vf->priv->outw * vf->priv->outh); - vf->priv->line_limits = malloc((vf->priv->outh + 1) / 2 * sizeof(*vf->priv->line_limits)); - double dar = (double)d_width / d_height; double sar = (double)width / height; @@ -236,148 +219,22 @@ static int prepare_image(struct vf_instance *vf, mp_image_t *mpi) return 0; } -static void update_limits(struct vf_instance *vf, int starty, int endy, - int startx, int endx) -{ - starty >>= 1; - endy = (endy + 1) >> 1; - startx >>= 1; - endx = (endx + 1) >> 1; - for (int i = starty; i < endy; i++) { - struct line_limits *ll = vf->priv->line_limits + i; - if (startx < ll->start) - ll->start = startx; - if (endx > ll->end) - ll->end = endx; - } -} - -/** - * \brief Copy specified rows from render_context.dmpi to render_context.planes, upsampling to 4:4:4 - */ -static void copy_from_image(struct vf_instance *vf) -{ - int pl; - - for (pl = 1; pl < 3; ++pl) { - int dst_stride = vf->priv->outw; - int src_stride = vf->dmpi->stride[pl]; - - unsigned char *src = vf->dmpi->planes[pl]; - unsigned char *dst = vf->priv->planes[pl]; - for (int i = 0; i < (vf->priv->outh + 1) / 2; i++) { - struct line_limits *ll = vf->priv->line_limits + i; - unsigned char *dst_next = dst + dst_stride; - for (int j = ll->start; j < ll->end; j++) { - unsigned char val = src[j]; - dst[j << 1] = val; - dst[(j << 1) + 1] = val; - dst_next[j << 1] = val; - dst_next[(j << 1) + 1] = val; - } - src += src_stride; - dst = dst_next + dst_stride; - } - } -} - -/** - * \brief Copy all previously copied rows back to render_context.dmpi - */ -static void copy_to_image(struct vf_instance *vf) -{ - int pl; - int i, j; - for (pl = 1; pl < 3; ++pl) { - int dst_stride = vf->dmpi->stride[pl]; - int src_stride = vf->priv->outw; - - unsigned char *dst = vf->dmpi->planes[pl]; - unsigned char *src = vf->priv->planes[pl]; - unsigned char *src_next = vf->priv->planes[pl] + src_stride; - for (i = 0; i < vf->priv->outh / 2; ++i) { - for (j = vf->priv->line_limits[i].start; j < vf->priv->line_limits[i].end; j++) { - unsigned val = 0; - val += src[j << 1]; - val += src[(j << 1) + 1]; - val += src_next[j << 1]; - val += src_next[(j << 1) + 1]; - dst[j] = val >> 2; - } - dst += dst_stride; - src = src_next + src_stride; - src_next = src + src_stride; - } - } -} - -static void my_draw_bitmap(struct vf_instance *vf, unsigned char *bitmap, - int bitmap_w, int bitmap_h, int stride, - int dst_x, int dst_y, unsigned color) -{ - unsigned char y = rgba2y(color); - unsigned char u = rgba2u(color); - unsigned char v = rgba2v(color); - unsigned char opacity = 255 - _a(color); - unsigned char *src, *dsty, *dstu, *dstv; - int i, j; - mp_image_t *dmpi = vf->dmpi; - - src = bitmap; - dsty = dmpi->planes[0] + dst_x + dst_y * dmpi->stride[0]; - dstu = vf->priv->planes[1] + dst_x + dst_y * vf->priv->outw; - dstv = vf->priv->planes[2] + dst_x + dst_y * vf->priv->outw; - for (i = 0; i < bitmap_h; ++i) { - for (j = 0; j < bitmap_w; ++j) { - unsigned k = (src[j] * opacity + 255) >> 8; - dsty[j] = (k * y + (255 - k) * dsty[j] + 255) >> 8; - dstu[j] = (k * u + (255 - k) * dstu[j] + 255) >> 8; - dstv[j] = (k * v + (255 - k) * dstv[j] + 255) >> 8; - } - src += stride; - dsty += dmpi->stride[0]; - dstu += vf->priv->outw; - dstv += vf->priv->outw; - } -} - -static int render_frame(struct vf_instance *vf, mp_image_t *mpi, - const ASS_Image *img) -{ - if (img) { - for (int i = 0; i < (vf->priv->outh + 1) / 2; i++) - vf->priv->line_limits[i] = (struct line_limits){65535, 0}; - for (const ASS_Image *im = img; im; im = im->next) - update_limits(vf, im->dst_y, im->dst_y + im->h, - im->dst_x, im->dst_x + im->w); - copy_from_image(vf); - while (img) { - my_draw_bitmap(vf, img->bitmap, img->w, img->h, img->stride, - img->dst_x, img->dst_y, img->color); - img = img->next; - } - copy_to_image(vf); - } - return 0; -} - static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) { struct vf_priv_s *priv = vf->priv; struct osd_state *osd = priv->osd; - struct sub_bitmaps imgs = (struct sub_bitmaps) {0}; + + prepare_image(vf, mpi); + if (pts != MP_NOPTS_VALUE) { struct sub_render_params subparams = { .pts = pts, .dim = priv->dim, }; - bool formats[SUBBITMAP_COUNT] = {[SUBBITMAP_LIBASS] = true}; - osd_draw_sub(osd, &imgs, &subparams, formats); + osd_draw_on_image(osd, &subparams, OSD_DRAW_SUB_FILTER, vf->dmpi, + &priv->csp); } - prepare_image(vf, mpi); - render_frame(vf, mpi, imgs.imgs); - return vf_next_put_image(vf, vf->dmpi, pts); } @@ -400,15 +257,17 @@ static int control(vf_instance_t *vf, int request, void *data) break; case VFCTRL_INIT_OSD: return CONTROL_TRUE; + case VFCTRL_SET_YUV_COLORSPACE: { + struct mp_csp_details colorspace = *(struct mp_csp_details *)data; + vf->priv->csp = colorspace; + break; + } } return vf_next_control(vf, request, data); } static void uninit(struct vf_instance *vf) { - free(vf->priv->planes[1]); - free(vf->priv->planes[2]); - free(vf->priv->line_limits); free(vf->priv); } -- cgit v1.2.3 From a4f9077f6c1a897120616cc70c1ca37c6a247be2 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 19 Oct 2012 19:11:58 +0200 Subject: draw_bmp: don't try to call swscale if image format not supported If that happens, we silently fail. --- libmpcodecs/sws_utils.c | 8 ++++++++ libmpcodecs/sws_utils.h | 9 +++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'libmpcodecs') diff --git a/libmpcodecs/sws_utils.c b/libmpcodecs/sws_utils.c index 65b079dd84..d7500efe2e 100644 --- a/libmpcodecs/sws_utils.c +++ b/libmpcodecs/sws_utils.c @@ -131,6 +131,14 @@ struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, SWS_ACCURATE_RND | SWS_BITEXACT); } +bool mp_sws_supported_format(int imgfmt) +{ + enum PixelFormat av_format = imgfmt2pixfmt(imgfmt); + + return av_format != PIX_FMT_NONE && sws_isSupportedInput(av_format) + && sws_isSupportedOutput(av_format); +} + void mp_image_swscale(struct mp_image *dst, const struct mp_image *src, struct mp_csp_details *csp, diff --git a/libmpcodecs/sws_utils.h b/libmpcodecs/sws_utils.h index b2c55eb407..70b7d0b7fb 100644 --- a/libmpcodecs/sws_utils.h +++ b/libmpcodecs/sws_utils.h @@ -1,6 +1,7 @@ #ifndef MPLAYER_SWS_UTILS_H #define MPLAYER_SWS_UTILS_H +#include #include struct mp_image; @@ -22,8 +23,12 @@ struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, int dstFormat); int mp_sws_set_colorspace(struct SwsContext *sws, struct mp_csp_details *csp); -void mp_image_swscale(struct mp_image *dst, const struct mp_image *src, - struct mp_csp_details *csp, int my_sws_flags); +bool mp_sws_supported_format(int imgfmt); + +void mp_image_swscale(struct mp_image *dst, + const struct mp_image *src, + struct mp_csp_details *csp, + int my_sws_flags); #endif /* MP_SWS_UTILS_H */ -- cgit v1.2.3 From 4d11f32162b08e3b48ae382e2ed0a151035f8aea Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 19 Oct 2012 19:25:18 +0200 Subject: VO, sub: refactor Remove VFCTRL_DRAW_OSD, VFCAP_EOSD_FILTER, VFCAP_EOSD_RGBA, VFCAP_EOSD, VOCTRL_DRAW_EOSD, VOCTRL_GET_EOSD_RES, VOCTRL_QUERY_EOSD_FORMAT. Remove draw_osd_with_eosd(), which rendered the OSD by calling VOCTRL_DRAW_EOSD. Change VOs to call osd_draw() directly, which takes a callback as argument. (This basically works like the old OSD API, except multiple OSD bitmap formats are supported and caching is possible.) Remove all mentions of "eosd". It's simply "osd" now. Make OSD size per-OSD-object, as they can be different when using vf_sub. Include display_par/video_par in resolution change detection. Fix the issue with margin borders in vo_corevideo. --- libmpcodecs/vf.h | 1 - libmpcodecs/vf_ass.c | 16 ++++++---------- libmpcodecs/vf_vo.c | 5 ----- libmpcodecs/vfcap.h | 4 ---- 4 files changed, 6 insertions(+), 20 deletions(-) (limited to 'libmpcodecs') diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h index 8b18470e62..7db9bd5808 100644 --- a/libmpcodecs/vf.h +++ b/libmpcodecs/vf.h @@ -99,7 +99,6 @@ struct vf_ctrl_screenshot { #define VFCTRL_SET_PP_LEVEL 5 // set postprocessing level #define VFCTRL_SET_EQUALIZER 6 // set color options (brightness,contrast etc) #define VFCTRL_GET_EQUALIZER 8 // get color options (brightness,contrast etc) -#define VFCTRL_DRAW_OSD 7 #define VFCTRL_DUPLICATE_FRAME 11 // For encoding - encode zero-change frame #define VFCTRL_SKIP_NEXT_FRAME 12 // For encoding - drop the next frame that passes thru #define VFCTRL_FLUSH_FRAMES 13 // For encoding - flush delayed frames diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index 9695ecfdfc..1da0b03b44 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -49,12 +49,12 @@ static const struct vf_priv_s { unsigned int outfmt; struct mp_csp_details csp; - // 1 = auto-added filter: insert only if chain does not support EOSD already + // 1 = auto-added filter: insert only if chain does not support OSD already // 0 = insert always int auto_insert; struct osd_state *osd; - struct mp_eosd_res dim; + struct mp_osd_res dim; } vf_priv_dflt = { .csp = MP_CSP_DETAILS_DEFAULTS, }; @@ -78,7 +78,7 @@ static int config(struct vf_instance *vf, double dar = (double)d_width / d_height; double sar = (double)width / height; - vf->priv->dim = (struct mp_eosd_res) { + vf->priv->dim = (struct mp_osd_res) { .w = vf->priv->outw, .h = vf->priv->outh, .mt = opts->ass_top_margin, @@ -227,11 +227,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) prepare_image(vf, mpi); if (pts != MP_NOPTS_VALUE) { - struct sub_render_params subparams = { - .pts = pts, - .dim = priv->dim, - }; - osd_draw_on_image(osd, &subparams, OSD_DRAW_SUB_FILTER, vf->dmpi, + osd_draw_on_image(osd, priv->dim, pts, OSD_DRAW_SUB_FILTER, vf->dmpi, &priv->csp); } @@ -287,7 +283,7 @@ static int vf_open(vf_instance_t *vf, char *args) if (!vf->priv->outfmt) { uninit(vf); return 0; - } else if (vf->priv->auto_insert && flags & VFCAP_EOSD) { + } else if (vf->priv->auto_insert && flags & VFCAP_OSD) { uninit(vf); return -1; } @@ -301,7 +297,7 @@ static int vf_open(vf_instance_t *vf, char *args) vf->control = control; vf->get_image = get_image; vf->put_image = put_image; - vf->default_caps = VFCAP_EOSD | VFCAP_EOSD_FILTER; + vf->default_caps = VFCAP_OSD; return 1; } diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c index 998b4b6dfa..16d10f0cdc 100644 --- a/libmpcodecs/vf_vo.c +++ b/libmpcodecs/vf_vo.c @@ -91,11 +91,6 @@ static int control(struct vf_instance *vf, int request, void *data) return vo_control(video_out, VOCTRL_GET_YUV_COLORSPACE, data) == true; case VFCTRL_SET_YUV_COLORSPACE: return vo_control(video_out, VOCTRL_SET_YUV_COLORSPACE, data) == true; - case VFCTRL_DRAW_OSD: - if (!video_out->config_ok) - return CONTROL_FALSE; // vo not configured? - vo_draw_osd(video_out, data); - return CONTROL_TRUE; case VFCTRL_SET_EQUALIZER: { vf_equalizer_t *eq = data; if (!video_out->config_ok) diff --git a/libmpcodecs/vfcap.h b/libmpcodecs/vfcap.h index 0fb73f5a51..acc7ce31c6 100644 --- a/libmpcodecs/vfcap.h +++ b/libmpcodecs/vfcap.h @@ -40,11 +40,7 @@ #define VFCAP_ACCEPT_STRIDE 0x400 // filter does postprocessing (so you shouldn't scale/filter image before it) #define VFCAP_POSTPROC 0x800 -// filter can draw EOSD -#define VFCAP_EOSD 0x2000 // used by libvo and vf_vo, indicates the VO does not support draw_slice for this format #define VOCAP_NOSLICES 0x8000 -#define VFCAP_EOSD_FILTER 0x20000 // EOSD is drawn in filter chain -#define VFCAP_EOSD_RGBA 0x40000 #endif /* MPLAYER_VFCAP_H */ -- cgit v1.2.3 From f80a32a8ebd1573f1578d707416b07880c1a08c1 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 21 Oct 2012 15:54:22 +0200 Subject: core: do not try to redraw OSD if VO doesn't support OSD This fixes awkward framestepping when seeking with -vo null while paused (caused because seeking by default draws an OSD bar, and mplayer trying to redraw the OSD in that case; this logic is actually needed with vo_xv). It would have been simpler to just check vo->driver->draw_osd (and leave that callback to NULL for VOs which don't support OSD), but for now try to retain the capability to let VOs decide based on the image format whether to support OSD or not. --- libmpcodecs/vf_vo.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'libmpcodecs') diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c index 16d10f0cdc..d11724f881 100644 --- a/libmpcodecs/vf_vo.c +++ b/libmpcodecs/vf_vo.c @@ -37,7 +37,6 @@ struct vf_priv_s { }; #define video_out (vf->priv->vo) -static int query_format(struct vf_instance *vf, unsigned int fmt); static void draw_slice(struct vf_instance *vf, unsigned char **src, int *stride, int w, int h, int x, int y); @@ -66,13 +65,13 @@ static int config(struct vf_instance *vf, if (info->comment && strlen(info->comment) > 0) mp_msg(MSGT_CPLAYER, MSGL_V, "VO: Comment: %s\n", info->comment); - // save vo's stride capability for the wanted colorspace: - vf->default_caps = query_format(vf, outfmt); - vf->draw_slice = (vf->default_caps & VOCAP_NOSLICES) ? NULL : draw_slice; - if (vo_config(video_out, width, height, d_width, d_height, flags, outfmt)) return 0; + // save vo's stride capability for the wanted colorspace: + vf->default_caps = video_out->default_caps; + vf->draw_slice = (vf->default_caps & VOCAP_NOSLICES) ? NULL : draw_slice; + return 1; } -- cgit v1.2.3 From 4b4e4b56909a07f1738d75c0f3fc1739990adfc9 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 21 Oct 2012 17:08:54 +0200 Subject: draw_bmp: fix for yuy2 format mp_get_chroma_shift() modifies its argument even if it fails, so we have to restore that. mp_image didn't set chroma shifts for yuy2. --- libmpcodecs/mp_image.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'libmpcodecs') diff --git a/libmpcodecs/mp_image.c b/libmpcodecs/mp_image.c index 1ba9e8e753..f01e416b01 100644 --- a/libmpcodecs/mp_image.c +++ b/libmpcodecs/mp_image.c @@ -196,6 +196,9 @@ void mp_image_setfmt(mp_image_t* mpi,unsigned int out_fmt){ mpi->flags|=MP_IMGFLAG_SWAPPED; case IMGFMT_YUY2: mpi->chroma_x_shift = 1; + mpi->chroma_y_shift = 1; + mpi->chroma_width=(mpi->width>>1); + mpi->chroma_height=(mpi->height>>1); mpi->bpp=16; mpi->num_planes=1; return; -- cgit v1.2.3 From 773668b6e85d4da4d252cb4ad8abd50448d70c7c Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 21 Oct 2012 18:31:34 +0200 Subject: VF: rename vf_ass to vf_sub This reflects the fact that this filter now renders all types of subtitles, not just ASS subtitles. Always compile this filter, not just on CONFIG_ASS. Note that --no-ass still disables auto-inserting this filter. It's the only way to disable auto-insertion, so keep it even though it's not really ASS specific anymore. --no-ass also disables using libass for rendering text subs directly. --- libmpcodecs/vf.c | 6 +- libmpcodecs/vf.h | 2 +- libmpcodecs/vf_ass.c | 324 --------------------------------------------------- libmpcodecs/vf_sub.c | 324 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 327 insertions(+), 329 deletions(-) delete mode 100644 libmpcodecs/vf_ass.c create mode 100644 libmpcodecs/vf_sub.c (limited to 'libmpcodecs') diff --git a/libmpcodecs/vf.c b/libmpcodecs/vf.c index 5ec7d19570..9ea17f978c 100644 --- a/libmpcodecs/vf.c +++ b/libmpcodecs/vf.c @@ -64,7 +64,7 @@ extern const vf_info_t vf_info_divtc; extern const vf_info_t vf_info_softskip; extern const vf_info_t vf_info_screenshot; extern const vf_info_t vf_info_screenshot_force; -extern const vf_info_t vf_info_ass; +extern const vf_info_t vf_info_sub; extern const vf_info_t vf_info_yadif; extern const vf_info_t vf_info_stereo3d; extern const vf_info_t vf_info_dlopen; @@ -102,9 +102,7 @@ static const vf_info_t *const filter_list[] = { &vf_info_delogo, &vf_info_phase, &vf_info_divtc, -#ifdef CONFIG_ASS - &vf_info_ass, -#endif + &vf_info_sub, &vf_info_yadif, &vf_info_stereo3d, &vf_info_dlopen, diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h index 7db9bd5808..4c50f0e9cc 100644 --- a/libmpcodecs/vf.h +++ b/libmpcodecs/vf.h @@ -106,7 +106,7 @@ struct vf_ctrl_screenshot { #define VFCTRL_INIT_OSD 15 // Filter OSD renderer present? #define VFCTRL_SET_DEINTERLACE 18 // Set deinterlacing status #define VFCTRL_GET_DEINTERLACE 19 // Get deinterlacing status -/* Hack to make the OSD state object available to vf_expand and vf_ass which +/* Hack to make the OSD state object available to vf_sub which * access OSD/subtitle state outside of normal OSD draw time. */ #define VFCTRL_SET_OSD_OBJ 20 #define VFCTRL_SET_YUV_COLORSPACE 22 // arg is struct mp_csp_details* diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c deleted file mode 100644 index 1da0b03b44..0000000000 --- a/libmpcodecs/vf_ass.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with 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 -#include -#include - -#include "config.h" -#include "mp_msg.h" -#include "options.h" - -#include "img_format.h" -#include "mp_image.h" -#include "vf.h" -#include "sub/sub.h" -#include "sub/dec_sub.h" - -#include "libvo/fastmemcpy.h" -#include "libvo/csputils.h" - -#include "m_option.h" -#include "m_struct.h" - -static const struct vf_priv_s { - int outh, outw; - - unsigned int outfmt; - struct mp_csp_details csp; - - // 1 = auto-added filter: insert only if chain does not support OSD already - // 0 = insert always - int auto_insert; - - struct osd_state *osd; - struct mp_osd_res dim; -} vf_priv_dflt = { - .csp = MP_CSP_DETAILS_DEFAULTS, -}; - -static int config(struct vf_instance *vf, - int width, int height, int d_width, int d_height, - unsigned int flags, unsigned int outfmt) -{ - struct MPOpts *opts = vf->opts; - if (outfmt == IMGFMT_IF09) - return 0; - - vf->priv->outh = height + opts->ass_top_margin + opts->ass_bottom_margin; - vf->priv->outw = width; - - if (!opts->screen_size_x && !opts->screen_size_y) { - d_width = d_width * vf->priv->outw / width; - d_height = d_height * vf->priv->outh / height; - } - - double dar = (double)d_width / d_height; - double sar = (double)width / height; - - vf->priv->dim = (struct mp_osd_res) { - .w = vf->priv->outw, - .h = vf->priv->outh, - .mt = opts->ass_top_margin, - .mb = opts->ass_bottom_margin, - .display_par = sar / dar, - .video_par = dar / sar, - }; - - return vf_next_config(vf, vf->priv->outw, vf->priv->outh, d_width, - d_height, flags, outfmt); -} - -static void get_image(struct vf_instance *vf, mp_image_t *mpi) -{ - if (mpi->type == MP_IMGTYPE_IPB) - return; - if (mpi->flags & MP_IMGFLAG_PRESERVE) - return; - if (mpi->imgfmt != vf->priv->outfmt) - return; // colorspace differ - - // width never changes, always try full DR - mpi->priv = vf->dmpi = vf_get_image(vf->next, mpi->imgfmt, mpi->type, - mpi->flags | MP_IMGFLAG_READABLE, - FFMAX(mpi->width, vf->priv->outw), - FFMAX(mpi->height, vf->priv->outh)); - - if ((vf->dmpi->flags & MP_IMGFLAG_DRAW_CALLBACK) && - !(vf->dmpi->flags & MP_IMGFLAG_DIRECT)) { - mp_tmsg(MSGT_ASS, MSGL_INFO, "Full DR not possible, trying SLICES instead!\n"); - return; - } - - int tmargin = vf->opts->ass_top_margin; - // set up mpi as a cropped-down image of dmpi: - if (mpi->flags & MP_IMGFLAG_PLANAR) { - mpi->planes[0] = vf->dmpi->planes[0] + tmargin * vf->dmpi->stride[0]; - mpi->planes[1] = vf->dmpi->planes[1] + (tmargin >> mpi->chroma_y_shift) * vf->dmpi->stride[1]; - mpi->planes[2] = vf->dmpi->planes[2] + (tmargin >> mpi->chroma_y_shift) * vf->dmpi->stride[2]; - mpi->stride[1] = vf->dmpi->stride[1]; - mpi->stride[2] = vf->dmpi->stride[2]; - } else { - mpi->planes[0] = vf->dmpi->planes[0] + tmargin * vf->dmpi->stride[0]; - } - mpi->stride[0] = vf->dmpi->stride[0]; - mpi->width = vf->dmpi->width; - mpi->flags |= MP_IMGFLAG_DIRECT; - mpi->flags &= ~MP_IMGFLAG_DRAW_CALLBACK; -// vf->dmpi->flags&=~MP_IMGFLAG_DRAW_CALLBACK; -} - -static void blank(mp_image_t *mpi, int y1, int y2) -{ - int color[3] = {16, 128, 128}; // black (YUV) - int y; - unsigned char *dst; - int chroma_rows = (y2 - y1) >> mpi->chroma_y_shift; - - dst = mpi->planes[0] + y1 * mpi->stride[0]; - for (y = 0; y < y2 - y1; ++y) { - memset(dst, color[0], mpi->w); - dst += mpi->stride[0]; - } - dst = mpi->planes[1] + (y1 >> mpi->chroma_y_shift) * mpi->stride[1]; - for (y = 0; y < chroma_rows; ++y) { - memset(dst, color[1], mpi->chroma_width); - dst += mpi->stride[1]; - } - dst = mpi->planes[2] + (y1 >> mpi->chroma_y_shift) * mpi->stride[2]; - for (y = 0; y < chroma_rows; ++y) { - memset(dst, color[2], mpi->chroma_width); - dst += mpi->stride[2]; - } -} - -static int prepare_image(struct vf_instance *vf, mp_image_t *mpi) -{ - struct MPOpts *opts = vf->opts; - int tmargin = opts->ass_top_margin; - if (mpi->flags & MP_IMGFLAG_DIRECT - || mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) { - vf->dmpi = mpi->priv; - if (!vf->dmpi) { - mp_tmsg(MSGT_ASS, MSGL_WARN, "Why do we get NULL??\n"); - return 0; - } - mpi->priv = NULL; - // we've used DR, so we're ready... - if (tmargin) - blank(vf->dmpi, 0, tmargin); - if (opts->ass_bottom_margin) - blank(vf->dmpi, vf->priv->outh - opts->ass_bottom_margin, - vf->priv->outh); - if (!(mpi->flags & MP_IMGFLAG_PLANAR)) - vf->dmpi->planes[1] = mpi->planes[1]; // passthrough rgb8 palette - return 0; - } - - // hope we'll get DR buffer: - vf->dmpi = vf_get_image(vf->next, vf->priv->outfmt, MP_IMGTYPE_TEMP, - MP_IMGFLAG_ACCEPT_STRIDE | MP_IMGFLAG_READABLE, - vf->priv->outw, vf->priv->outh); - - // copy mpi->dmpi... - if (mpi->flags & MP_IMGFLAG_PLANAR) { - memcpy_pic(vf->dmpi->planes[0] + tmargin * vf->dmpi->stride[0], - mpi->planes[0], - mpi->w, - mpi->h, - vf->dmpi->stride[0], - mpi->stride[0]); - memcpy_pic(vf->dmpi->planes[1] + (tmargin >> mpi->chroma_y_shift) * vf->dmpi->stride[1], - mpi->planes[1], - mpi->w >> mpi->chroma_x_shift, - mpi->h >> mpi->chroma_y_shift, - vf->dmpi->stride[1], - mpi->stride[1]); - memcpy_pic(vf->dmpi->planes[2] + (tmargin >> mpi->chroma_y_shift) * vf->dmpi->stride[2], - mpi->planes[2], - mpi->w >> mpi->chroma_x_shift, - mpi->h >> mpi->chroma_y_shift, - vf->dmpi->stride[2], - mpi->stride[2]); - } else { - memcpy_pic(vf->dmpi->planes[0] + tmargin * vf->dmpi->stride[0], - mpi->planes[0], - mpi->w * (vf->dmpi->bpp / 8), - mpi->h, - vf->dmpi->stride[0], - mpi->stride[0]); - vf->dmpi->planes[1] = mpi->planes[1]; // passthrough rgb8 palette - } - if (tmargin) - blank(vf->dmpi, 0, tmargin); - if (opts->ass_bottom_margin) - blank(vf->dmpi, vf->priv->outh - opts->ass_bottom_margin, - vf->priv->outh); - return 0; -} - -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) -{ - struct vf_priv_s *priv = vf->priv; - struct osd_state *osd = priv->osd; - - prepare_image(vf, mpi); - - if (pts != MP_NOPTS_VALUE) { - osd_draw_on_image(osd, priv->dim, pts, OSD_DRAW_SUB_FILTER, vf->dmpi, - &priv->csp); - } - - return vf_next_put_image(vf, vf->dmpi, pts); -} - -static int query_format(struct vf_instance *vf, unsigned int fmt) -{ - switch (fmt) { - case IMGFMT_YV12: - case IMGFMT_I420: - case IMGFMT_IYUV: - return vf_next_query_format(vf, vf->priv->outfmt); - } - return 0; -} - -static int control(vf_instance_t *vf, int request, void *data) -{ - switch (request) { - case VFCTRL_SET_OSD_OBJ: - vf->priv->osd = data; - break; - case VFCTRL_INIT_OSD: - return CONTROL_TRUE; - case VFCTRL_SET_YUV_COLORSPACE: { - struct mp_csp_details colorspace = *(struct mp_csp_details *)data; - vf->priv->csp = colorspace; - break; - } - } - return vf_next_control(vf, request, data); -} - -static void uninit(struct vf_instance *vf) -{ - free(vf->priv); -} - -static const unsigned int fmt_list[] = { - IMGFMT_YV12, - IMGFMT_I420, - IMGFMT_IYUV, - 0 -}; - -static int vf_open(vf_instance_t *vf, char *args) -{ - int flags; - vf->priv->outfmt = vf_match_csp(&vf->next, fmt_list, IMGFMT_YV12); - if (vf->priv->outfmt) - flags = vf_next_query_format(vf, vf->priv->outfmt); - if (!vf->priv->outfmt) { - uninit(vf); - return 0; - } else if (vf->priv->auto_insert && flags & VFCAP_OSD) { - uninit(vf); - return -1; - } - - if (vf->priv->auto_insert) - mp_msg(MSGT_ASS, MSGL_INFO, "[ass] auto-open\n"); - - vf->config = config; - vf->query_format = query_format; - vf->uninit = uninit; - vf->control = control; - vf->get_image = get_image; - vf->put_image = put_image; - vf->default_caps = VFCAP_OSD; - return 1; -} - -#define ST_OFF(f) M_ST_OFF(struct vf_priv_s, f) -static const m_option_t vf_opts_fields[] = { - {"auto", ST_OFF(auto_insert), CONF_TYPE_FLAG, 0, 0, 1, NULL}, - {NULL, NULL, 0, 0, 0, 0, NULL} -}; - -static const m_struct_t vf_opts = { - "ass", - sizeof(struct vf_priv_s), - &vf_priv_dflt, - vf_opts_fields -}; - -const vf_info_t vf_info_ass = { - "Render ASS/SSA subtitles", - "ass", - "Evgeniy Stepanov", - "", - vf_open, - &vf_opts -}; diff --git a/libmpcodecs/vf_sub.c b/libmpcodecs/vf_sub.c new file mode 100644 index 0000000000..e377d589c5 --- /dev/null +++ b/libmpcodecs/vf_sub.c @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2006 Evgeniy Stepanov + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with 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 +#include +#include + +#include "config.h" +#include "mp_msg.h" +#include "options.h" + +#include "img_format.h" +#include "mp_image.h" +#include "vf.h" +#include "sub/sub.h" +#include "sub/dec_sub.h" + +#include "libvo/fastmemcpy.h" +#include "libvo/csputils.h" + +#include "m_option.h" +#include "m_struct.h" + +static const struct vf_priv_s { + int outh, outw; + + unsigned int outfmt; + struct mp_csp_details csp; + + // 1 = auto-added filter: insert only if chain does not support OSD already + // 0 = insert always + int auto_insert; + + struct osd_state *osd; + struct mp_osd_res dim; +} vf_priv_dflt = { + .csp = MP_CSP_DETAILS_DEFAULTS, +}; + +static int config(