mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
video-converter: add support for src/dest regions
Add support for cropping the source and placing the converted image into a rectangle in the destination frame. Add an option to add a border and border color.
This commit is contained in:
parent
a16cd5d2a5
commit
ce2d4d40a1
2 changed files with 207 additions and 31 deletions
|
@ -62,10 +62,18 @@ struct _GstVideoConverter
|
|||
GstVideoInfo in_info;
|
||||
GstVideoInfo out_info;
|
||||
|
||||
gint in_x;
|
||||
gint in_y;
|
||||
gint in_width;
|
||||
gint in_height;
|
||||
gint in_maxwidth;
|
||||
gint in_maxheight;
|
||||
gint out_x;
|
||||
gint out_y;
|
||||
gint out_width;
|
||||
gint out_height;
|
||||
gint out_maxwidth;
|
||||
gint out_maxheight;
|
||||
gint v_scale_width;
|
||||
|
||||
gint in_bits;
|
||||
|
@ -85,6 +93,10 @@ struct _GstVideoConverter
|
|||
guint16 *errline;
|
||||
guint tmplines_idx;
|
||||
|
||||
gboolean fill_border;
|
||||
guint16 *borderline;
|
||||
guint32 border_argb;
|
||||
|
||||
GstVideoChromaResample *upsample;
|
||||
guint up_n_lines;
|
||||
gint up_offset;
|
||||
|
@ -265,17 +277,20 @@ alloc_tmplines (GstVideoConverter * convert, guint lines, gint width)
|
|||
|
||||
convert->n_tmplines = lines;
|
||||
convert->tmplines = g_malloc (lines * sizeof (gpointer));
|
||||
for (i = 0; i < lines; i++)
|
||||
for (i = 0; i < lines; i++) {
|
||||
convert->tmplines[i] = g_malloc (sizeof (guint16) * (width + 8) * 4);
|
||||
if (convert->borderline)
|
||||
memcpy (convert->tmplines[i], convert->borderline, width * 8);
|
||||
}
|
||||
convert->tmplines_idx = 0;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
get_temp_line (GstVideoConverter * convert)
|
||||
get_temp_line (GstVideoConverter * convert, gint offset)
|
||||
{
|
||||
gpointer tmpline;
|
||||
|
||||
tmpline = convert->tmplines[convert->tmplines_idx];
|
||||
tmpline = (guint32 *) convert->tmplines[convert->tmplines_idx] + offset;
|
||||
convert->tmplines_idx = (convert->tmplines_idx + 1) % convert->n_tmplines;
|
||||
|
||||
return tmpline;
|
||||
|
@ -374,6 +389,33 @@ chain_pack (GstVideoConverter * convert, GstLineCacheNeedLineFunc need_line)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static gint
|
||||
get_opt_int (GstVideoConverter * convert, const gchar * opt, gint def)
|
||||
{
|
||||
gint res;
|
||||
if (!gst_structure_get_int (convert->config, opt, &res))
|
||||
res = def;
|
||||
return res;
|
||||
}
|
||||
|
||||
static guint
|
||||
get_opt_uint (GstVideoConverter * convert, const gchar * opt, guint def)
|
||||
{
|
||||
guint res;
|
||||
if (!gst_structure_get_uint (convert->config, opt, &res))
|
||||
res = def;
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_opt_bool (GstVideoConverter * convert, const gchar * opt, gboolean def)
|
||||
{
|
||||
gboolean res;
|
||||
if (!gst_structure_get_boolean (convert->config, opt, &res))
|
||||
res = def;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_video_converter_new:
|
||||
* @in_info: a #GstVideoInfo
|
||||
|
@ -410,17 +452,36 @@ gst_video_converter_new (GstVideoInfo * in_info, GstVideoInfo * out_info,
|
|||
convert->in_info = *in_info;
|
||||
convert->out_info = *out_info;
|
||||
|
||||
convert->in_width = GST_VIDEO_INFO_WIDTH (in_info);
|
||||
convert->in_height = GST_VIDEO_INFO_HEIGHT (in_info);
|
||||
convert->out_width = GST_VIDEO_INFO_WIDTH (out_info);
|
||||
convert->out_height = GST_VIDEO_INFO_HEIGHT (out_info);
|
||||
|
||||
/* default config */
|
||||
convert->config = gst_structure_new ("GstVideoConverter",
|
||||
"dither", GST_TYPE_VIDEO_DITHER_METHOD, GST_VIDEO_DITHER_NONE, NULL);
|
||||
if (config)
|
||||
gst_video_converter_set_config (convert, config);
|
||||
|
||||
convert->in_maxwidth = GST_VIDEO_INFO_WIDTH (in_info);
|
||||
convert->in_maxheight = GST_VIDEO_INFO_HEIGHT (in_info);
|
||||
convert->out_maxwidth = GST_VIDEO_INFO_WIDTH (out_info);
|
||||
convert->out_maxheight = GST_VIDEO_INFO_HEIGHT (out_info);
|
||||
|
||||
convert->in_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_X, 0);
|
||||
convert->in_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_Y, 0);
|
||||
convert->in_width = get_opt_int (convert,
|
||||
GST_VIDEO_CONVERTER_OPT_SRC_WIDTH, convert->in_maxwidth);
|
||||
convert->in_height = get_opt_int (convert,
|
||||
GST_VIDEO_CONVERTER_OPT_SRC_HEIGHT, convert->in_maxheight);
|
||||
|
||||
convert->out_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_X, 0);
|
||||
convert->out_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_Y, 0);
|
||||
convert->out_width = get_opt_int (convert,
|
||||
GST_VIDEO_CONVERTER_OPT_DEST_WIDTH, convert->out_maxwidth);
|
||||
convert->out_height = get_opt_int (convert,
|
||||
GST_VIDEO_CONVERTER_OPT_DEST_HEIGHT, convert->out_maxheight);
|
||||
|
||||
convert->fill_border = get_opt_bool (convert,
|
||||
GST_VIDEO_CONVERTER_OPT_FILL_BORDER, TRUE);
|
||||
convert->border_argb = get_opt_uint (convert,
|
||||
GST_VIDEO_CONVERTER_OPT_BORDER_ARGB, 0x00000000);
|
||||
|
||||
if (video_converter_lookup_fastpath (convert))
|
||||
goto done;
|
||||
|
||||
|
@ -486,8 +547,17 @@ gst_video_converter_new (GstVideoInfo * in_info, GstVideoInfo * out_info,
|
|||
need_line = chain_pack (convert, need_line);
|
||||
|
||||
convert->lines = out_info->finfo->pack_lines;
|
||||
width = MAX (convert->in_width, convert->out_width);
|
||||
width = MAX (convert->in_maxwidth, convert->out_maxwidth);
|
||||
convert->errline = g_malloc0 (sizeof (guint16) * width * 4);
|
||||
|
||||
if (convert->fill_border && (convert->out_height < convert->out_maxheight ||
|
||||
convert->out_width < convert->out_maxwidth)) {
|
||||
convert->borderline = g_malloc0 (sizeof (guint16) * width * 4);
|
||||
memset (convert->borderline, convert->border_argb, width * 8);
|
||||
} else {
|
||||
convert->borderline = NULL;
|
||||
}
|
||||
|
||||
/* FIXME */
|
||||
alloc_tmplines (convert, 64, width);
|
||||
|
||||
|
@ -552,6 +622,7 @@ gst_video_converter_free (GstVideoConverter * convert)
|
|||
g_free (convert->tmplines[i]);
|
||||
g_free (convert->tmplines);
|
||||
g_free (convert->errline);
|
||||
g_free (convert->borderline);
|
||||
|
||||
if (convert->config)
|
||||
gst_structure_free (convert->config);
|
||||
|
@ -1087,32 +1158,36 @@ convert_to8 (gpointer line, gint width)
|
|||
line8[i] = line16[i] >> 8;
|
||||
}
|
||||
|
||||
#define UNPACK_FRAME(frame,dest,line,width) \
|
||||
#define UNPACK_FRAME(frame,dest,line,x,width) \
|
||||
frame->info.finfo->unpack_func (frame->info.finfo, \
|
||||
(GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
|
||||
GST_VIDEO_PACK_FLAG_INTERLACED : \
|
||||
GST_VIDEO_PACK_FLAG_NONE), \
|
||||
dest, frame->data, frame->info.stride, 0, \
|
||||
dest, frame->data, frame->info.stride, x, \
|
||||
line, width)
|
||||
#define PACK_FRAME(frame,dest,line,width) \
|
||||
#define PACK_FRAME(frame,src,line,width) \
|
||||
frame->info.finfo->pack_func (frame->info.finfo, \
|
||||
(GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
|
||||
GST_VIDEO_PACK_FLAG_INTERLACED : \
|
||||
GST_VIDEO_PACK_FLAG_NONE), \
|
||||
dest, 0, frame->data, frame->info.stride, \
|
||||
src, 0, frame->data, frame->info.stride, \
|
||||
frame->info.chroma_site, line, width);
|
||||
|
||||
static gboolean
|
||||
do_unpack_lines (GstLineCache * cache, gint line, GstVideoConverter * convert)
|
||||
{
|
||||
gpointer tmpline;
|
||||
guint cline;;
|
||||
guint cline;
|
||||
|
||||
cline = CLAMP (line, 0, convert->in_height - 1);
|
||||
cline = CLAMP (line + convert->in_y, 0, convert->in_maxheight);
|
||||
|
||||
/* FIXME we should be able to use the input line without unpack if the
|
||||
* format is already suitable. When we do this, we should be careful not to
|
||||
* do in-place modifications. */
|
||||
GST_DEBUG ("unpack line %d (%u)", line, cline);
|
||||
tmpline = get_temp_line (convert);
|
||||
UNPACK_FRAME (convert->src, tmpline, cline, convert->in_width);
|
||||
tmpline = get_temp_line (convert, convert->out_x);
|
||||
|
||||
UNPACK_FRAME (convert->src, tmpline, cline, convert->in_x, convert->in_width);
|
||||
|
||||
gst_line_cache_add_line (cache, line, tmpline);
|
||||
|
||||
|
@ -1150,7 +1225,7 @@ do_hscale_lines (GstLineCache * cache, gint line, GstVideoConverter * convert)
|
|||
|
||||
lines = gst_line_cache_get_lines (convert->hscale_lines, line, 1);
|
||||
|
||||
destline = get_temp_line (convert);
|
||||
destline = get_temp_line (convert, convert->out_x);
|
||||
|
||||
GST_DEBUG ("hresample line %d", line);
|
||||
gst_video_scaler_horizontal (convert->h_scaler, GST_VIDEO_FORMAT_AYUV,
|
||||
|
@ -1170,8 +1245,10 @@ do_vscale_lines (GstLineCache * cache, gint line, GstVideoConverter * convert)
|
|||
gst_video_scaler_get_coeff (convert->v_scaler, line, &sline, &n_lines);
|
||||
lines = gst_line_cache_get_lines (convert->vscale_lines, sline, n_lines);
|
||||
|
||||
destline = get_temp_line (convert);
|
||||
destline = get_temp_line (convert, convert->out_x);
|
||||
|
||||
/* FIXME with 1-tap (nearest), we can simply copy the input line. We need
|
||||
* to be careful to not do in-place modifications later */
|
||||
GST_DEBUG ("vresample line %d %d-%d", line, sline, sline + n_lines - 1);
|
||||
gst_video_scaler_vertical (convert->v_scaler, GST_VIDEO_FORMAT_AYUV,
|
||||
lines, destline, line, convert->v_scale_width);
|
||||
|
@ -1248,26 +1325,58 @@ video_converter_generic (GstVideoConverter * convert, const GstVideoFrame * src,
|
|||
GstVideoFrame * dest)
|
||||
{
|
||||
gint i;
|
||||
gint out_width, out_height;
|
||||
gint out_maxwidth, out_maxheight;
|
||||
gint out_x, out_y, out_height;
|
||||
gint pack_lines;
|
||||
gint r_border, out_width;
|
||||
|
||||
out_width = convert->out_width;
|
||||
out_height = convert->out_height;
|
||||
out_maxwidth = convert->out_maxwidth;
|
||||
out_maxheight = convert->out_maxheight;
|
||||
|
||||
out_x = convert->out_x;
|
||||
out_y = convert->out_y;
|
||||
|
||||
r_border = out_x + out_width;
|
||||
|
||||
convert->src = src;
|
||||
convert->dest = dest;
|
||||
|
||||
pack_lines = convert->lines; /* only 1 for now */
|
||||
|
||||
if (convert->borderline) {
|
||||
/* FIXME we should try to avoid PACK_FRAME */
|
||||
for (i = 0; i < out_y; i++)
|
||||
PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
|
||||
}
|
||||
|
||||
for (i = 0; i < out_height; i += pack_lines) {
|
||||
gpointer *lines;
|
||||
guint32 *l;
|
||||
|
||||
/* load the lines needed to pack */
|
||||
lines = gst_line_cache_get_lines (convert->pack_lines, i, pack_lines);
|
||||
|
||||
/* take away the border */
|
||||
l = ((guint32 *) lines[0]) - out_x;
|
||||
|
||||
if (convert->borderline) {
|
||||
/* FIXME this can be optimized if we make separate temp lines with
|
||||
* border for the output lines */
|
||||
memcpy (l, convert->borderline, out_x * 4);
|
||||
memcpy (l + r_border, convert->borderline, (out_maxwidth - r_border) * 4);
|
||||
}
|
||||
/* and pack into destination */
|
||||
GST_DEBUG ("pack line %d", i);
|
||||
PACK_FRAME (dest, lines[0], i, out_width);
|
||||
/* FIXME, we should be able to convert directly into the destination line
|
||||
* when the output format is in the right format */
|
||||
GST_DEBUG ("pack line %d", i + out_y);
|
||||
PACK_FRAME (dest, l, i + out_y, out_maxwidth);
|
||||
}
|
||||
|
||||
if (convert->borderline) {
|
||||
for (i = out_y + out_height; i < out_maxheight; i++)
|
||||
PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1331,7 +1440,7 @@ convert_I420_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
|
|||
|
||||
/* now handle last line */
|
||||
if (height & 1) {
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, width);
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, convert->in_x, width);
|
||||
PACK_FRAME (dest, convert->tmplines[0], height - 1, width);
|
||||
}
|
||||
}
|
||||
|
@ -1359,7 +1468,7 @@ convert_I420_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
|
|||
|
||||
/* now handle last line */
|
||||
if (height & 1) {
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, width);
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, convert->in_x, width);
|
||||
PACK_FRAME (dest, convert->tmplines[0], height - 1, width);
|
||||
}
|
||||
}
|
||||
|
@ -1386,7 +1495,7 @@ convert_I420_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
|
|||
|
||||
/* now handle last line */
|
||||
if (height & 1) {
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, width);
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, convert->in_x, width);
|
||||
PACK_FRAME (dest, convert->tmplines[0], height - 1, width);
|
||||
}
|
||||
}
|
||||
|
@ -1436,7 +1545,7 @@ convert_I420_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
|
|||
|
||||
/* now handle last line */
|
||||
if (height & 1) {
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, width);
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, convert->in_x, width);
|
||||
PACK_FRAME (dest, convert->tmplines[0], height - 1, width);
|
||||
}
|
||||
}
|
||||
|
@ -1463,7 +1572,7 @@ convert_YUY2_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
|
|||
|
||||
/* now handle last line */
|
||||
if (height & 1) {
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, width);
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, convert->in_x, width);
|
||||
PACK_FRAME (dest, convert->tmplines[0], height - 1, width);
|
||||
}
|
||||
}
|
||||
|
@ -1531,7 +1640,7 @@ convert_UYVY_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
|
|||
|
||||
/* now handle last line */
|
||||
if (height & 1) {
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, width);
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, convert->in_x, width);
|
||||
PACK_FRAME (dest, convert->tmplines[0], height - 1, width);
|
||||
}
|
||||
}
|
||||
|
@ -1683,7 +1792,7 @@ convert_Y42B_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
|
|||
|
||||
/* now handle last line */
|
||||
if (height & 1) {
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, width);
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, convert->in_x, width);
|
||||
PACK_FRAME (dest, convert->tmplines[0], height - 1, width);
|
||||
}
|
||||
}
|
||||
|
@ -1774,7 +1883,7 @@ convert_Y444_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
|
|||
|
||||
/* now handle last line */
|
||||
if (height & 1) {
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, width);
|
||||
UNPACK_FRAME (src, convert->tmplines[0], height - 1, convert->in_x, width);
|
||||
PACK_FRAME (dest, convert->tmplines[0], height - 1, width);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ typedef enum {
|
|||
*
|
||||
* #GST_TYPE_RESAMPLER_METHOD, The resampler method to use for
|
||||
* resampling. Other options for the resampler can be used, see
|
||||
* the #GstResampler. Default is #GST_RESAMPLER_METHOD_LINEAR.
|
||||
* the #GstResampler. Default is #GST_RESAMPLER_METHOD_CUBIC
|
||||
*/
|
||||
#define GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD "GstVideoConverter.resampler-method"
|
||||
/**
|
||||
|
@ -64,6 +64,73 @@ typedef enum {
|
|||
*/
|
||||
#define GST_VIDEO_CONVERTER_OPT_DITHER_METHOD "GstVideoConverter.dither-method"
|
||||
|
||||
/**
|
||||
* GST_VIDEO_CONVERTER_OPT_SRC_X:
|
||||
*
|
||||
* #G_TYPE_INT, source x position to start conversion, default 0
|
||||
*/
|
||||
#define GST_VIDEO_CONVERTER_OPT_SRC_X "GstVideoConverter.src-x"
|
||||
/**
|
||||
* GST_VIDEO_CONVERTER_OPT_SRC_Y:
|
||||
*
|
||||
* #G_TYPE_INT, source y position to start conversion, default 0
|
||||
*/
|
||||
#define GST_VIDEO_CONVERTER_OPT_SRC_Y "GstVideoConverter.src-y"
|
||||
/**
|
||||
* GST_VIDEO_CONVERTER_OPT_SRC_WIDTH:
|
||||
*
|
||||
* #G_TYPE_INT, source width to convert, default source width
|
||||
*/
|
||||
#define GST_VIDEO_CONVERTER_OPT_SRC_WIDTH "GstVideoConverter.src-width"
|
||||
/**
|
||||
* GST_VIDEO_CONVERTER_OPT_SRC_HEIGHT:
|
||||
*
|
||||
* #G_TYPE_INT, source height to convert, default source height
|
||||
*/
|
||||
#define GST_VIDEO_CONVERTER_OPT_SRC_HEIGHT "GstVideoConverter.src-height"
|
||||
|
||||
/**
|
||||
* GST_VIDEO_CONVERTER_OPT_DEST_X:
|
||||
*
|
||||
* #G_TYPE_INT, x position in the destination frame, default 0
|
||||
*/
|
||||
#define GST_VIDEO_CONVERTER_OPT_DEST_X "GstVideoConverter.dest-x"
|
||||
/**
|
||||
* GST_VIDEO_CONVERTER_OPT_DEST_Y:
|
||||
*
|
||||
* #G_TYPE_INT, y position in the destination frame, default 0
|
||||
*/
|
||||
#define GST_VIDEO_CONVERTER_OPT_DEST_Y "GstVideoConverter.dest-y"
|
||||
/**
|
||||
* GST_VIDEO_CONVERTER_OPT_DEST_WIDTH:
|
||||
*
|
||||
* #G_TYPE_INT, width in the destination frame, default destination width
|
||||
*/
|
||||
#define GST_VIDEO_CONVERTER_OPT_DEST_WIDTH "GstVideoConverter.dest-width"
|
||||
/**
|
||||
* GST_VIDEO_CONVERTER_OPT_DEST_HEIGHT:
|
||||
*
|
||||
* #G_TYPE_INT, height in the destination frame, default destination height
|
||||
*/
|
||||
#define GST_VIDEO_CONVERTER_OPT_DEST_HEIGHT "GstVideoConverter.dest-height"
|
||||
|
||||
/**
|
||||
* GST_VIDEO_CONVERTER_OPT_FILL_BORDER:
|
||||
*
|
||||
* #G_TYPE_BOOLEAN, if the destination rectangle does not fill the complete
|
||||
* destination image, render a border with
|
||||
* #GST_VIDEO_CONVERTER_OPT_BORDER_ARGB. Otherwise the unusded pixels in the
|
||||
* destination are untouched. Default %TRUE.
|
||||
*/
|
||||
#define GST_VIDEO_CONVERTER_OPT_FILL_BORDER "GstVideoConverter.fill-border"
|
||||
/**
|
||||
* GST_VIDEO_CONVERTER_OPT_BORDER_ARGB:
|
||||
*
|
||||
* #G_TYPE_UINT, the border color to use if #GST_VIDEO_CONVERTER_OPT_FILL_BORDER
|
||||
* is set to %TRUE. Default 0x00000000
|
||||
*/
|
||||
#define GST_VIDEO_CONVERTER_OPT_BORDER_ARGB "GstVideoConverter.border-argb"
|
||||
|
||||
|
||||
typedef struct _GstVideoConverter GstVideoConverter;
|
||||
|
||||
|
|
Loading…
Reference in a new issue