2006-10-01 17:09:04 +00:00
|
|
|
/*
|
2008-05-13 10:16:20 +00:00
|
|
|
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2006-10-01 17:09:04 +00:00
|
|
|
|
2006-07-07 18:26:51 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2007-09-18 09:30:42 +00:00
|
|
|
#include <inttypes.h>
|
2006-07-07 18:26:51 +00:00
|
|
|
#include <assert.h>
|
2012-05-25 20:31:10 +00:00
|
|
|
#include <libavutil/common.h>
|
2006-07-07 18:26:51 +00:00
|
|
|
|
|
|
|
#include "config.h"
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/msg.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/options.h"
|
2006-07-07 18:26:51 +00:00
|
|
|
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "video/img_format.h"
|
|
|
|
#include "video/mp_image.h"
|
2006-07-07 18:26:51 +00:00
|
|
|
#include "vf.h"
|
2013-11-24 11:58:06 +00:00
|
|
|
#include "sub/osd.h"
|
2012-10-04 15:16:40 +00:00
|
|
|
#include "sub/dec_sub.h"
|
2006-07-07 18:26:51 +00:00
|
|
|
|
2012-12-25 21:45:20 +00:00
|
|
|
#include "video/sws_utils.h"
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "video/memcpy_pic.h"
|
2006-07-07 18:26:51 +00:00
|
|
|
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/m_option.h"
|
2006-07-07 18:26:51 +00:00
|
|
|
|
2013-12-05 21:55:09 +00:00
|
|
|
struct vf_priv_s {
|
2012-12-12 22:35:01 +00:00
|
|
|
int opt_top_margin, opt_bottom_margin;
|
2012-12-25 21:45:20 +00:00
|
|
|
|
2010-10-30 19:15:15 +00:00
|
|
|
int outh, outw;
|
2006-07-07 18:26:51 +00:00
|
|
|
|
2011-01-12 13:15:02 +00:00
|
|
|
struct osd_state *osd;
|
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.
2012-10-19 17:25:18 +00:00
|
|
|
struct mp_osd_res dim;
|
2012-10-19 17:11:08 +00:00
|
|
|
};
|
2006-07-07 18:26:51 +00:00
|
|
|
|
2010-05-29 14:15:55 +00:00
|
|
|
static int config(struct vf_instance *vf,
|
2010-10-30 19:15:15 +00:00
|
|
|
int width, int height, int d_width, int d_height,
|
|
|
|
unsigned int flags, unsigned int outfmt)
|
2006-07-07 18:26:51 +00:00
|
|
|
{
|
2012-12-12 22:35:01 +00:00
|
|
|
vf->priv->outh = height + vf->priv->opt_top_margin +
|
|
|
|
vf->priv->opt_bottom_margin;
|
2010-10-30 19:15:15 +00:00
|
|
|
vf->priv->outw = width;
|
2006-07-07 18:26:51 +00:00
|
|
|
|
2012-11-08 01:57:42 +00:00
|
|
|
double dar = (double)d_width / d_height;
|
|
|
|
double sar = (double)width / height;
|
|
|
|
|
2013-01-22 12:28:31 +00:00
|
|
|
vf_rescale_dsize(&d_width, &d_height, width, height,
|
2012-12-25 21:45:20 +00:00
|
|
|
vf->priv->outw, vf->priv->outh);
|
2006-07-07 18:26:51 +00:00
|
|
|
|
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.
2012-10-19 17:25:18 +00:00
|
|
|
vf->priv->dim = (struct mp_osd_res) {
|
2012-10-18 15:31:00 +00:00
|
|
|
.w = vf->priv->outw,
|
|
|
|
.h = vf->priv->outh,
|
2012-12-12 22:35:01 +00:00
|
|
|
.mt = vf->priv->opt_top_margin,
|
|
|
|
.mb = vf->priv->opt_bottom_margin,
|
2012-10-18 15:31:00 +00:00
|
|
|
.display_par = sar / dar,
|
|
|
|
};
|
2006-07-07 18:26:51 +00:00
|
|
|
|
2010-10-30 19:15:15 +00:00
|
|
|
return vf_next_config(vf, vf->priv->outw, vf->priv->outh, d_width,
|
|
|
|
d_height, flags, outfmt);
|
2006-07-07 18:26:51 +00:00
|
|
|
}
|
|
|
|
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
static void prepare_image(struct vf_instance *vf, struct mp_image *dmpi,
|
|
|
|
struct mp_image *mpi)
|
2006-07-07 18:26:51 +00:00
|
|
|
{
|
2012-12-25 21:45:20 +00:00
|
|
|
int y1 = MP_ALIGN_DOWN(vf->priv->opt_top_margin, mpi->fmt.align_y);
|
|
|
|
int y2 = MP_ALIGN_DOWN(y1 + mpi->h, mpi->fmt.align_y);
|
|
|
|
struct mp_image cropped = *dmpi;
|
|
|
|
mp_image_crop(&cropped, 0, y1, mpi->w, y1 + mpi->h);
|
|
|
|
mp_image_copy(&cropped, mpi);
|
|
|
|
mp_image_clear(dmpi, 0, 0, dmpi->w, y1);
|
|
|
|
mp_image_clear(dmpi, 0, y2, dmpi->w, vf->priv->outh);
|
2006-07-07 18:26:51 +00:00
|
|
|
}
|
|
|
|
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
static struct mp_image *filter(struct vf_instance *vf, struct mp_image *mpi)
|
2006-07-07 18:26:51 +00:00
|
|
|
{
|
2012-08-25 18:22:39 +00:00
|
|
|
struct vf_priv_s *priv = vf->priv;
|
|
|
|
struct osd_state *osd = priv->osd;
|
2012-10-19 17:11:08 +00:00
|
|
|
|
sub: do not copy the target image if there is no OSD/subs
It's not easy to tell whether the OSD/subs are empty, or if something is
drawn. In general you have to use osd_draw() with a custom callback. If
nothing is visible, the callback is never invoked. (The actual reason
why this is so "hard" is the implementation of osd_libass.c, which
doesn't allow separating rendering and drawing of OSD elements, because
all OSD elements share the same ASS_Renderer.)
To simplify avoiding copies, make osd_draw_on_image() instead of the
caller use mp_image_make_writeable(). Introduce osd_draw_on_image_p(),
which works like osd_draw_on_image(), but gets the new image allocation
from an image pool. This is supposed to be an optimization, because it
reduces the frequency of large allocations/deallocations for image data.
The result of this is that the frequency of copies needed in conjunction
with vf_sub, screenshots, and vo_lavc (encoding) should be reduced.
vf_sub now always does true pass-through if no subs are shown.
Drop the pts check from vf_sub. This didn't make much sense.
2012-12-22 16:17:43 +00:00
|
|
|
if (vf->priv->opt_top_margin || vf->priv->opt_bottom_margin) {
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
struct mp_image *dmpi = vf_alloc_out_image(vf);
|
|
|
|
mp_image_copy_attributes(dmpi, mpi);
|
|
|
|
prepare_image(vf, dmpi, mpi);
|
|
|
|
talloc_free(mpi);
|
|
|
|
mpi = dmpi;
|
|
|
|
}
|
|
|
|
|
sub: do not copy the target image if there is no OSD/subs
It's not easy to tell whether the OSD/subs are empty, or if something is
drawn. In general you have to use osd_draw() with a custom callback. If
nothing is visible, the callback is never invoked. (The actual reason
why this is so "hard" is the implementation of osd_libass.c, which
doesn't allow separating rendering and drawing of OSD elements, because
all OSD elements share the same ASS_Renderer.)
To simplify avoiding copies, make osd_draw_on_image() instead of the
caller use mp_image_make_writeable(). Introduce osd_draw_on_image_p(),
which works like osd_draw_on_image(), but gets the new image allocation
from an image pool. This is supposed to be an optimization, because it
reduces the frequency of large allocations/deallocations for image data.
The result of this is that the frequency of copies needed in conjunction
with vf_sub, screenshots, and vo_lavc (encoding) should be reduced.
vf_sub now always does true pass-through if no subs are shown.
Drop the pts check from vf_sub. This didn't make much sense.
2012-12-22 16:17:43 +00:00
|
|
|
osd_draw_on_image_p(osd, priv->dim, mpi->pts, OSD_DRAW_SUB_FILTER,
|
|
|
|
vf->out_pool, mpi);
|
2009-07-06 23:26:13 +00:00
|
|
|
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
return mpi;
|
2006-07-07 18:26:51 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 14:15:55 +00:00
|
|
|
static int query_format(struct vf_instance *vf, unsigned int fmt)
|
2006-07-07 18:26:51 +00:00
|
|
|
{
|
2012-12-25 21:45:20 +00:00
|
|
|
if (!mp_sws_supported_format(fmt))
|
|
|
|
return 0;
|
|
|
|
return vf_next_query_format(vf, fmt);
|
2006-07-07 18:26:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int control(vf_instance_t *vf, int request, void *data)
|
|
|
|
{
|
2010-10-30 19:15:15 +00:00
|
|
|
switch (request) {
|
2011-01-12 13:15:02 +00:00
|
|
|
case VFCTRL_SET_OSD_OBJ:
|
|
|
|
vf->priv->osd = data;
|
2013-12-07 18:33:38 +00:00
|
|
|
return CONTROL_TRUE;
|
2012-10-04 15:16:32 +00:00
|
|
|
case VFCTRL_INIT_OSD:
|
2012-08-25 14:47:50 +00:00
|
|
|
return CONTROL_TRUE;
|
2010-10-30 19:15:15 +00:00
|
|
|
}
|
2013-12-07 18:33:38 +00:00
|
|
|
return CONTROL_UNKNOWN;
|
2006-07-07 18:26:51 +00:00
|
|
|
}
|
|
|
|
|
2013-12-03 23:01:38 +00:00
|
|
|
static int vf_open(vf_instance_t *vf)
|
2006-07-07 18:26:51 +00:00
|
|
|
{
|
2010-10-30 19:15:15 +00:00
|
|
|
vf->config = config;
|
|
|
|
vf->query_format = query_format;
|
|
|
|
vf->control = control;
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
vf->filter = filter;
|
2010-10-30 19:15:15 +00:00
|
|
|
return 1;
|
2006-07-07 18:26:51 +00:00
|
|
|
}
|
|
|
|
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
#define OPT_BASE_STRUCT struct vf_priv_s
|
2007-11-09 06:58:32 +00:00
|
|
|
static const m_option_t vf_opts_fields[] = {
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
OPT_INTRANGE("bottom-margin", opt_bottom_margin, 0, 0, 2000),
|
|
|
|
OPT_INTRANGE("top-margin", opt_top_margin, 0, 0, 2000),
|
|
|
|
{0}
|
2006-07-07 18:26:51 +00:00
|
|
|
};
|
|
|
|
|
2012-10-21 16:31:34 +00:00
|
|
|
const vf_info_t vf_info_sub = {
|
2013-10-23 17:06:42 +00:00
|
|
|
.description = "Render subtitles",
|
|
|
|
.name = "sub",
|
|
|
|
.open = vf_open,
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
.priv_size = sizeof(struct vf_priv_s),
|
|
|
|
.options = vf_opts_fields,
|
2006-07-07 18:26:51 +00:00
|
|
|
};
|