gstreamer/gst/ffmpegcolorspace/imgconvert.c
Sebastian Dröge 1469453cb9 ffmpegcolorspace: Fix IYU1 support
Fix conversions to IYU1, they allocated infinite amounts of memory before
because no conversion to IYU1 was actually implemented and it was running
into an infinite loop trying to find suitable intermediate formats.

Also fix the stride and sizes used for IYU1.
2010-11-03 10:49:35 +01:00

4126 lines
108 KiB
C

/*
* Misc image convertion routines
* Copyright (c) 2001, 2002, 2003 Fabrice Bellard.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* @file imgconvert.c
* Misc image convertion routines.
*/
/* TODO:
* - write 'ffimg' program to test all the image related stuff
* - move all api to slice based system
* - integrate deinterlacing, postprocessing and scaling in the conversion process
*/
#include "avcodec.h"
#include "dsputil.h"
#include "gstffmpegcodecmap.h"
#include <string.h>
#include <stdlib.h>
GST_DEBUG_CATEGORY_EXTERN (ffmpegcolorspace_performance);
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
/* this table gives more information about formats */
/* FIXME, this table is also in ffmpegcodecmap */
static PixFmtInfo pix_fmt_info[PIX_FMT_NB] = {
/* YUV formats */
/* [PIX_FMT_YUV420P] = */ {
/* .format = */ PIX_FMT_YUV420P,
/* .name = */ "yuv420p",
/* .nb_channels = */ 3,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 1,
/* .y_chroma_shift = */ 1,
/* .depth = */ 8,
},
/* [PIX_FMT_YVU420P] = */ {
/* .format = */ PIX_FMT_YVU420P,
/* .name = */ "yvu420p",
/* .nb_channels = */ 3,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 1,
/* .y_chroma_shift = */ 1,
/* .depth = */ 8,
},
/* [PIX_FMT_NV12] = */ {
/* .format = */ PIX_FMT_NV12,
/* .name = */ "nv12",
/* .nb_channels = */ 2,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 1,
/* .y_chroma_shift = */ 1,
/* .depth = */ 8,
},
/* [PIX_FMT_NV21] = */ {
/* .format = */ PIX_FMT_NV21,
/* .name = */ "nv21",
/* .nb_channels = */ 2,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 1,
/* .y_chroma_shift = */ 1,
/* .depth = */ 8,
},
/* [PIX_FMT_YUV422P] = */ {
/* .format = */ PIX_FMT_YUV422P,
/* .name = */ "yuv422p",
/* .nb_channels = */ 3,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 1,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_YUV444P] = */ {
/* .format = */ PIX_FMT_YUV444P,
/* .name = */ "yuv444p",
/* .nb_channels = */ 3,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_YUV422] = */ {
/* .format = */ PIX_FMT_YUV422,
/* .name = */ "yuv422",
/* .nb_channels = */ 1,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 1,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_UYVY422] = */ {
/* .format = */ PIX_FMT_UYVY422,
/* .name = */ "uyvy422",
/* .nb_channels = */ 1,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 1,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_YVYU422] = */ {
/* .format = */ PIX_FMT_YVYU422,
/* .name = */ "yvyu422",
/* .nb_channels = */ 1,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 1,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_V308] = */ {
/* .format = */ PIX_FMT_V308,
/* .name = */ "v308",
/* .nb_channels = */ 1,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_YUV410P] = */ {
/* .format = */ PIX_FMT_YUV410P,
/* .name = */ "yuv410p",
/* .nb_channels = */ 3,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 2,
/* .y_chroma_shift = */ 2,
/* .depth = */ 8,
},
/* [PIX_FMT_YVU410P] = */ {
/* .format = */ PIX_FMT_YVU410P,
/* .name = */ "yvu410p",
/* .nb_channels = */ 3,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 2,
/* .y_chroma_shift = */ 2,
/* .depth = */ 8,
},
/* [PIX_FMT_YUV411P] = */ {
/* .format = */ PIX_FMT_YUV411P,
/* .name = */ "yuv411p",
/* .nb_channels = */ 3,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 2,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_Y800] = */ {
/* .format = */ PIX_FMT_Y800,
/* .name = */ "y800",
/* .nb_channels = */ 1,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_Y16] = */ {
/* .format = */ PIX_FMT_Y16,
/* .name = */ "y16",
/* .nb_channels = */ 1,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 16,
},
/* JPEG YUV */
/* [PIX_FMT_YUVJ420P] = */ {
/* .format = */ PIX_FMT_YUVJ420P,
/* .name = */ "yuvj420p",
/* .nb_channels = */ 3,
/* .color_type = */ FF_COLOR_YUV_JPEG,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 1,
/* .y_chroma_shift = */ 1,
/* .depth = */ 8,
},
/* [PIX_FMT_YUVJ422P] = */ {
/* .format = */ PIX_FMT_YUVJ422P,
/* .name = */ "yuvj422p",
/* .nb_channels = */ 3,
/* .color_type = */ FF_COLOR_YUV_JPEG,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 1,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_YUVJ444P] = */ {
/* .format = */ PIX_FMT_YUVJ444P,
/* .name = */ "yuvj444p",
/* .nb_channels = */ 3,
/* .color_type = */ FF_COLOR_YUV_JPEG,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* RGB formats */
/* [PIX_FMT_RGB24] = */ {
/* .format = */ PIX_FMT_RGB24,
/* .name = */ "rgb24",
/* .nb_channels = */ 3,
/* .color_type = */ FF_COLOR_RGB,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_BGR24] = */ {
/* .format = */ PIX_FMT_BGR24,
/* .name = */ "bgr24",
/* .nb_channels = */ 3,
/* .color_type = */ FF_COLOR_RGB,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_RGB32] = */ {
/* .format = */ PIX_FMT_RGB32,
/* .name = */ "rgb32",
/* .nb_channels = */ 4,
/* .color_type = */ FF_COLOR_RGB,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_BGR32] = */ {
/* .format = */ PIX_FMT_BGR32,
/* .name = */ "bgr32",
/* .nb_channels = */ 4,
/* .color_type = */ FF_COLOR_RGB,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_RGB32] = */ {
/* .format = */ PIX_FMT_xRGB32,
/* .name = */ "xrgb32",
/* .nb_channels = */ 4,
/* .color_type = */ FF_COLOR_RGB,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_BGR32] = */ {
/* .format = */ PIX_FMT_BGRx32,
/* .name = */ "bgrx32",
/* .nb_channels = */ 4,
/* .color_type = */ FF_COLOR_RGB,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_RGBA32] = */ {
/* .format = */ PIX_FMT_RGBA32,
/* .name = */ "rgba32",
/* .nb_channels = */ 4,
/* .color_type = */ FF_COLOR_RGB,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 1,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_BGRA32] = */ {
/* .format = */ PIX_FMT_BGRA32,
/* .name = */ "bgra32",
/* .nb_channels = */ 4,
/* .color_type = */ FF_COLOR_RGB,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 1,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_ARGB32] = */ {
/* .format = */ PIX_FMT_ARGB32,
/* .name = */ "argb32",
/* .nb_channels = */ 4,
/* .color_type = */ FF_COLOR_RGB,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 1,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_ABGR32] = */ {
/* .format = */ PIX_FMT_ABGR32,
/* .name = */ "abgr32",
/* .nb_channels = */ 4,
/* .color_type = */ FF_COLOR_RGB,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 1,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_RGB565] = */ {
/* .format = */ PIX_FMT_RGB565,
/* .name = */ "rgb565",
/* .nb_channels = */ 3,
/* .color_type = */ FF_COLOR_RGB,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 5,
},
/* [PIX_FMT_RGB555] = */ {
/* .format = */ PIX_FMT_RGB555,
/* .name = */ "rgb555",
/* .nb_channels = */ 4,
/* .color_type = */ FF_COLOR_RGB,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 1,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 5,
},
/* gray / mono formats */
/* [PIX_FMT_GRAY8] = */ {
/* .format = */ PIX_FMT_GRAY8,
/* .name = */ "gray",
/* .nb_channels = */ 1,
/* .color_type = */ FF_COLOR_GRAY,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_GRAY16_L] = */ {
/* .format = */ PIX_FMT_GRAY16_L,
/* .name = */ "gray",
/* .nb_channels = */ 1,
/* .color_type = */ FF_COLOR_GRAY,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 16,
},
/* [PIX_FMT_GRAY16_B] = */ {
/* .format = */ PIX_FMT_GRAY16_B,
/* .name = */ "gray",
/* .nb_channels = */ 1,
/* .color_type = */ FF_COLOR_GRAY,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 16,
},
/* [PIX_FMT_MONOWHITE] = */ {
/* .format = */ PIX_FMT_MONOWHITE,
/* .name = */ "monow",
/* .nb_channels = */ 1,
/* .color_type = */ FF_COLOR_GRAY,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 1,
},
/* [PIX_FMT_MONOBLACK] = */ {
/* .format = */ PIX_FMT_MONOBLACK,
/* .name = */ "monob",
/* .nb_channels = */ 1,
/* .color_type = */ FF_COLOR_GRAY,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 1,
},
/* paletted formats */
/* [PIX_FMT_PAL8] = */ {
/* .format = */ PIX_FMT_PAL8,
/* .name = */ "pal8",
/* .nb_channels = */ 4,
/* .color_type = */ FF_COLOR_RGB,
/* .pixel_type = */ FF_PIXEL_PALETTE,
/* .is_alpha = */ 1,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_XVMC_MPEG2_MC] = */ {
/* .format = */ PIX_FMT_XVMC_MPEG2_MC,
/* .name = */ "xvmcmc",
},
/* [PIX_FMT_XVMC_MPEG2_IDCT] = */ {
/* .format = */ PIX_FMT_XVMC_MPEG2_IDCT,
/* .name = */ "xvmcidct",
},
/* [PIX_FMT_UYVY411] = */ {
/* .format = */ PIX_FMT_UYVY411,
/* .name = */ "uyvy411",
/* .nb_channels = */ 1,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 0,
/* .x_chroma_shift = */ 2,
/* .y_chroma_shift = */ 0,
/* .depth = */ 8,
},
/* [PIX_FMT_AYUV4444] = */ {
/* .format = */ PIX_FMT_AYUV4444,
/* .name = */ "ayuv4444",
/* .nb_channels = */ 1,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PACKED,
/* .is_alpha = */ 1,
/* .x_chroma_shift = */ 0,
/* .y_chroma_shift = */ 0,
/*.depth = */ 8
},
/* [PIX_FMT_YUVA420P] = */ {
/* .format = */ PIX_FMT_YUVA420P,
/* .name = */ "yuva420p",
/* .nb_channels = */ 4,
/* .color_type = */ FF_COLOR_YUV,
/* .pixel_type = */ FF_PIXEL_PLANAR,
/* .is_alpha = */ 1,
/* .x_chroma_shift = */ 1,
/* .y_chroma_shift = */ 1,
/* .depth = */ 8,
}
};
/* returns NULL if not found */
/* undid static since this is also used in gstffmpegcodecmap.c */
PixFmtInfo *
get_pix_fmt_info (enum PixelFormat format)
{
int i;
for (i = 0; i < sizeof (pix_fmt_info) / sizeof (pix_fmt_info[0]); i++) {
if (pix_fmt_info[i].format == format) {
return pix_fmt_info + i;
}
}
/* since this doesn't get checked *anywhere*, we might as well warn
here if we return NULL so you have *some* idea what's going on */
g_warning
("Could not find info for pixel format %d out of %d known pixel formats. One segfault coming up",
format, PIX_FMT_NB);
return NULL;
}
void
avcodec_get_chroma_sub_sample (int pix_fmt, int *h_shift, int *v_shift)
{
*h_shift = get_pix_fmt_info (pix_fmt)->x_chroma_shift;
*v_shift = get_pix_fmt_info (pix_fmt)->y_chroma_shift;
}
const char *
avcodec_get_pix_fmt_name (int pix_fmt)
{
if (pix_fmt < 0 || pix_fmt >= PIX_FMT_NB)
return "???";
else
return get_pix_fmt_info (pix_fmt)->name;
}
enum PixelFormat
avcodec_get_pix_fmt (const char *name)
{
int i;
for (i = 0; i < PIX_FMT_NB; i++)
if (!strcmp (pix_fmt_info[i].name, name))
break;
return pix_fmt_info[i].format;
}
#if 0
static int
avpicture_layout (const AVPicture * src, int pix_fmt, int width, int height,
unsigned char *dest, int dest_size)
{
PixFmtInfo *pf = get_pix_fmt_info (pix_fmt);
int i, j, w, h, data_planes;
const unsigned char *s;
int size = avpicture_get_size (pix_fmt, width, height);
if (size > dest_size)
return -1;
if (pf->pixel_type == FF_PIXEL_PACKED || pf->pixel_type == FF_PIXEL_PALETTE) {
if (pix_fmt == PIX_FMT_YUV422 ||
pix_fmt == PIX_FMT_UYVY422 ||
pix_fmt == PIX_FMT_RGB565 || pix_fmt == PIX_FMT_RGB555)
w = width * 2;
else if (pix_fmt == PIX_FMT_UYVY411)
w = width + width / 2;
else if (pix_fmt == PIX_FMT_PAL8)
w = width;
else
w = width * (pf->depth * pf->nb_channels / 8);
data_planes = 1;
h = height;
} else {
data_planes = pf->nb_channels;
w = (width * pf->depth + 7) / 8;
h = height;
}
for (i = 0; i < data_planes; i++) {
if (i == 1) {
w = width >> pf->x_chroma_shift;
h = height >> pf->y_chroma_shift;
}
s = src->data[i];
for (j = 0; j < h; j++) {
memcpy (dest, s, w);
dest += w;
s += src->linesize[i];
}
}
if (pf->pixel_type == FF_PIXEL_PALETTE)
memcpy ((unsigned char *) (((size_t) dest + 3) & ~3), src->data[1],
256 * 4);
return size;
}
#endif
int
avpicture_get_size (int pix_fmt, int width, int height)
{
AVPicture dummy_pict;
return gst_ffmpegcsp_avpicture_fill (&dummy_pict, NULL, pix_fmt, width,
height, FALSE);
}
/**
* compute the loss when converting from a pixel format to another
*/
int
avcodec_get_pix_fmt_loss (int dst_pix_fmt, int src_pix_fmt, int has_alpha)
{
const PixFmtInfo *pf, *ps;
int loss;
ps = get_pix_fmt_info (src_pix_fmt);
pf = get_pix_fmt_info (dst_pix_fmt);
/* compute loss */
loss = 0;
if (pf->depth < ps->depth ||
(dst_pix_fmt == PIX_FMT_RGB555 && src_pix_fmt == PIX_FMT_RGB565))
loss |= FF_LOSS_DEPTH;
if (pf->x_chroma_shift > ps->x_chroma_shift ||
pf->y_chroma_shift > ps->y_chroma_shift)
loss |= FF_LOSS_RESOLUTION;
switch (pf->color_type) {
case FF_COLOR_RGB:
if (ps->color_type != FF_COLOR_RGB && ps->color_type != FF_COLOR_GRAY)
loss |= FF_LOSS_COLORSPACE;
break;
case FF_COLOR_GRAY:
if (ps->color_type != FF_COLOR_GRAY)
loss |= FF_LOSS_COLORSPACE;
break;
case FF_COLOR_YUV:
if (ps->color_type != FF_COLOR_YUV)
loss |= FF_LOSS_COLORSPACE;
break;
case FF_COLOR_YUV_JPEG:
if (ps->color_type != FF_COLOR_YUV_JPEG &&
ps->color_type != FF_COLOR_YUV && ps->color_type != FF_COLOR_GRAY)
loss |= FF_LOSS_COLORSPACE;
break;
default:
/* fail safe test */
if (ps->color_type != pf->color_type)
loss |= FF_LOSS_COLORSPACE;
break;
}
if (pf->color_type == FF_COLOR_GRAY && ps->color_type != FF_COLOR_GRAY)
loss |= FF_LOSS_CHROMA;
if (!pf->is_alpha && (ps->is_alpha && has_alpha))
loss |= FF_LOSS_ALPHA;
if (pf->pixel_type == FF_PIXEL_PALETTE &&
(ps->pixel_type != FF_PIXEL_PALETTE && ps->color_type != FF_COLOR_GRAY))
loss |= FF_LOSS_COLORQUANT;
return loss;
}
static int
avg_bits_per_pixel (int pix_fmt)
{
int bits;
const PixFmtInfo *pf;
pf = get_pix_fmt_info (pix_fmt);
switch (pf->pixel_type) {
case FF_PIXEL_PACKED:
switch (pix_fmt) {
case PIX_FMT_YUV422:
case PIX_FMT_UYVY422:
case PIX_FMT_YVYU422:
case PIX_FMT_RGB565:
case PIX_FMT_RGB555:
bits = 16;
break;
case PIX_FMT_UYVY411:
bits = 12;
break;
default:
bits = pf->depth * pf->nb_channels;
break;
}
break;
case FF_PIXEL_PLANAR:
if (pf->x_chroma_shift == 0 && pf->y_chroma_shift == 0) {
bits = pf->depth * pf->nb_channels;
} else {
bits = pf->depth + ((2 * pf->depth) >>
(pf->x_chroma_shift + pf->y_chroma_shift));
}
break;
case FF_PIXEL_PALETTE:
bits = 8;
break;
default:
bits = -1;
break;
}
return bits;
}
static int
avcodec_find_best_pix_fmt1 (int pix_fmt_mask,
int src_pix_fmt, int has_alpha, int loss_mask)
{
int dist, i, loss, min_dist, dst_pix_fmt;
/* find exact color match with smallest size */
dst_pix_fmt = -1;
min_dist = 0x7fffffff;
for (i = 0; i < PIX_FMT_NB; i++) {
if (pix_fmt_mask & (1 << i)) {
loss = avcodec_get_pix_fmt_loss (i, src_pix_fmt, has_alpha) & loss_mask;
if (loss == 0) {
dist = avg_bits_per_pixel (i);
if (dist < min_dist) {
min_dist = dist;
dst_pix_fmt = i;
}
}
}
}
return dst_pix_fmt;
}
/**
* find best pixel format to convert to. Return -1 if none found
*/
int
avcodec_find_best_pix_fmt (int pix_fmt_mask, int src_pix_fmt,
int has_alpha, int *loss_ptr)
{
int dst_pix_fmt, loss_mask, i;
static const int loss_mask_order[] = {
~0, /* no loss first */
~FF_LOSS_ALPHA,
~FF_LOSS_RESOLUTION,
~(FF_LOSS_COLORSPACE | FF_LOSS_RESOLUTION),
~FF_LOSS_COLORQUANT,
~FF_LOSS_DEPTH,
0,
};
/* try with successive loss */
i = 0;
for (;;) {
loss_mask = loss_mask_order[i++];
dst_pix_fmt = avcodec_find_best_pix_fmt1 (pix_fmt_mask, src_pix_fmt,
has_alpha, loss_mask);
if (dst_pix_fmt >= 0)
goto found;
if (loss_mask == 0)
break;
}
return -1;
found:
if (loss_ptr)
*loss_ptr = avcodec_get_pix_fmt_loss (dst_pix_fmt, src_pix_fmt, has_alpha);
return dst_pix_fmt;
}
static void
img_copy_plane (uint8_t * dst, int dst_wrap,
const uint8_t * src, int src_wrap, int width, int height)
{
for (; height > 0; height--) {
memcpy (dst, src, width);
dst += dst_wrap;
src += src_wrap;
}
}
/**
* Copy image 'src' to 'dst'.
*/
static void
img_copy (AVPicture * dst, const AVPicture * src,
int pix_fmt, int width, int height)
{
int bwidth, bits, i;
const PixFmtInfo *pf;
pf = get_pix_fmt_info (pix_fmt);
switch (pf->pixel_type) {
case FF_PIXEL_PACKED:
switch (pix_fmt) {
case PIX_FMT_YUV422:
case PIX_FMT_UYVY422:
case PIX_FMT_YVYU422:
case PIX_FMT_RGB565:
case PIX_FMT_RGB555:
bits = 16;
break;
case PIX_FMT_UYVY411:
bits = 12;
break;
default:
bits = pf->depth * pf->nb_channels;
break;
}
bwidth = (width * bits + 7) >> 3;
img_copy_plane (dst->data[0], dst->linesize[0],
src->data[0], src->linesize[0], bwidth, height);
break;
case FF_PIXEL_PLANAR:
for (i = 0; i < pf->nb_channels; i++) {
int w, h;
w = width;
h = height;
if (i == 1 || i == 2) {
w >>= pf->x_chroma_shift;
h >>= pf->y_chroma_shift;
}
bwidth = (w * pf->depth + 7) >> 3;
img_copy_plane (dst->data[i], dst->linesize[i],
src->data[i], src->linesize[i], bwidth, h);
}
break;
case FF_PIXEL_PALETTE:
img_copy_plane (dst->data[0], dst->linesize[0],
src->data[0], src->linesize[0], width, height);
/* copy the palette */
img_copy_plane (dst->data[1], dst->linesize[1],
src->data[1], src->linesize[1], 4, 256);
break;
}
}
/* XXX: totally non optimized */
static void
yuv422_to_yuv420p (AVPicture * dst, const AVPicture * src,
int width, int height)
{
const uint8_t *p, *p1;
uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
int w;
p1 = src->data[0];
lum1 = dst->data[0];
cb1 = dst->data[1];
cr1 = dst->data[2];
for (; height >= 1; height -= 2) {
p = p1;
lum = lum1;
cb = cb1;
cr = cr1;
for (w = width; w >= 2; w -= 2) {
lum[0] = p[0];
cb[0] = p[1];
lum[1] = p[2];
cr[0] = p[3];
p += 4;
lum += 2;
cb++;
cr++;
}
if (w) {
lum[0] = p[0];
cb[0] = p[1];
cr[0] = p[3];
}
p1 += src->linesize[0];
lum1 += dst->linesize[0];
if (height > 1) {
p = p1;
lum = lum1;
for (w = width; w >= 2; w -= 2) {
lum[0] = p[0];
lum[1] = p[2];
p += 4;
lum += 2;
}
if (w) {
lum[0] = p[0];
}
p1 += src->linesize[0];
lum1 += dst->linesize[0];
}
cb1 += dst->linesize[1];
cr1 += dst->linesize[2];
}
}
static void
uyvy422_to_gray (AVPicture * dst, const AVPicture * src, int width, int height)
{
const uint8_t *p, *p1;
uint8_t *lum, *lum1;
int w;
p1 = src->data[0];
lum1 = dst->data[0];
for (; height > 0; height--) {
p = p1;
lum = lum1;
for (w = width; w >= 2; w -= 2) {
lum[0] = p[1];
lum[1] = p[3];
p += 4;
lum += 2;
}
if (w)
lum[0] = p[1];
p1 += src->linesize[0];
lum1 += dst->linesize[0];
}
}
static void
uyvy422_to_yuv420p (AVPicture * dst, const AVPicture * src,
int width, int height)
{
const uint8_t *p, *p1;
uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
int w;
p1 = src->data[0];
lum1 = dst->data[0];
cb1 = dst->data[1];
cr1 = dst->data[2];
for (; height >= 1; height -= 2) {
p = p1;
lum = lum1;
cb = cb1;
cr = cr1;
for (w = width; w >= 2; w -= 2) {
lum[0] = p[1];
cb[0] = p[0];
lum[1] = p[3];
cr[0] = p[2];
p += 4;
lum += 2;
cb++;
cr++;
}
if (w) {
lum[0] = p[1];
cb[0] = p[0];
cr[0] = p[2];
}
p1 += src->linesize[0];
lum1 += dst->linesize[0];
if (height > 1) {
p = p1;
lum = lum1;
for (w = width; w >= 2; w -= 2) {
lum[0] = p[1];
lum[1] = p[3];
p += 4;
lum += 2;
}
if (w) {
lum[0] = p[1];
}
p1 += src->linesize[0];
lum1 += dst->linesize[0];
}
cb1 += dst->linesize[1];
cr1 += dst->linesize[2];
}
}
static void
uyvy422_to_yuv422p (AVPicture * dst, const AVPicture * src,
int width, int height)
{
const uint8_t *p, *p1;
uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
int w;
p1 = src->data[0];
lum1 = dst->data[0];
cb1 = dst->data[1];
cr1 = dst->data[2];
for (; height > 0; height--) {
p = p1;
lum = lum1;
cb = cb1;
cr = cr1;
for (w = width; w >= 2; w -= 2) {
lum[0] = p[1];
cb[0] = p[0];
lum[1] = p[3];
cr[0] = p[2];
p += 4;
lum += 2;
cb++;
cr++;
}
if (w) {
lum[0] = p[1];
cb[0] = p[0];
cr[0] = p[2];
}
p1 += src->linesize[0];
lum1 += dst->linesize[0];
cb1 += dst->linesize[1];
cr1 += dst->linesize[2];
}
}
static void
yvyu422_to_gray (AVPicture * dst, const AVPicture * src, int width, int height)
{
const uint8_t *p, *p1;
uint8_t *lum, *lum1;
int w;
p1 = src->data[0];
lum1 = dst->data[0];
for (; height > 0; height--) {
p = p1;
lum = lum1;
for (w = width; w >= 2; w -= 2) {
lum[0] = p[0];
lum[1] = p[2];
p += 4;
lum += 2;
}
if (w)
lum[0] = p[0];
p1 += src->linesize[0];
lum1 += dst->linesize[0];
}
}
static void
yvyu422_to_yuv420p (AVPicture * dst, const AVPicture * src,
int width, int height)
{
const uint8_t *p, *p1;
uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
int w;
p1 = src->data[0];
lum1 = dst->data[0];
cb1 = dst->data[1];
cr1 = dst->data[2];
for (; height >= 1; height -= 2) {
p = p1;
lum = lum1;
cb = cb1;
cr = cr1;
for (w = width; w >= 2; w -= 2) {
lum[0] = p[0];
cb[0] = p[3];
lum[1] = p[2];
cr[0] = p[1];
p += 4;
lum += 2;
cb++;
cr++;
}
if (w) {
lum[0] = p[0];
cb[0] = p[3];
cr[0] = p[1];
}
p1 += src->linesize[0];
lum1 += dst->linesize[0];
if (height > 1) {
p = p1;
lum = lum1;
for (w = width; w >= 2; w -= 2) {
lum[0] = p[0];
lum[1] = p[2];
p += 4;
lum += 2;
}
if (w) {
lum[0] = p[0];
}
p1 += src->linesize[0];
lum1 += dst->linesize[0];
}
cb1 += dst->linesize[1];
cr1 += dst->linesize[2];
}
}
static void
yvyu422_to_yuv422p (AVPicture * dst, const AVPicture * src,
int width, int height)
{
const uint8_t *p, *p1;
uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
int w;
p1 = src->data[0];
lum1 = dst->data[0];
cb1 = dst->data[1];
cr1 = dst->data[2];
for (; height > 0; height--) {
p = p1;
lum = lum1;
cb = cb1;
cr = cr1;
for (w = width; w >= 2; w -= 2) {
lum[0] = p[0];
cb[0] = p[3];
lum[1] = p[2];
cr[0] = p[1];
p += 4;
lum += 2;
cb++;
cr++;
}
if (w) {
lum[0] = p[0];
cb[0] = p[3];
cr[0] = p[1];
}
p1 += src->linesize[0];
lum1 += dst->linesize[0];
cb1 += dst->linesize[1];
cr1 += dst->linesize[2];
}
}
static void
yuv422_to_yuv422p (AVPicture * dst, const AVPicture * src,
int width, int height)
{
const uint8_t *p, *p1;
uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
int w;
p1 = src->data[0];
lum1 = dst->data[0];
cb1 = dst->data[1];
cr1 = dst->data[2];
for (; height > 0; height--) {
p = p1;
lum = lum1;
cb = cb1;
cr = cr1;
for (w = width; w >= 2; w -= 2) {
lum[0] = p[0];
cb[0] = p[1];
lum[1] = p[2];
cr[0] = p[3];
p += 4;
lum += 2;
cb++;
cr++;
}
if (w) {
lum[0] = p[0];
cb[0] = p[1];
cr[0] = p[3];
}
p1 += src->linesize[0];
lum1 += dst->linesize[0];
cb1 += dst->linesize[1];
cr1 += dst->linesize[2];
}
}
static void
yuv422p_to_yuv422 (AVPicture * dst, const AVPicture * src,
int width, int height)
{
uint8_t *p, *p1;
const uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
int w;
p1 = dst->data[0];
lum1 = src->data[0];
cb1 = src->data[1];
cr1 = src->data[2];
for (; height > 0; height--) {
p = p1;
lum = lum1;
cb = cb1;
cr = cr1;
for (w = width; w >= 2; w -= 2) {
p[0] = lum[0];
p[1] = cb[0];
p[2] = lum[1];
p[3] = cr[0];
p += 4;
lum += 2;
cb++;
cr++;
}
if (w) {
p[0] = lum[0];
p[1] = cb[0];
p[3] = cr[0];
}
p1 += dst->linesize[0];
lum1 += src->linesize[0];
cb1 += src->linesize[1];
cr1 += src->linesize[2];
}
}
static void
yuv422p_to_uyvy422 (AVPicture * dst, const AVPicture * src,
int width, int height)
{
uint8_t *p, *p1;
const uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
int w;
p1 = dst->data[0];
lum1 = src->data[0];
cb1 = src->data[1];
cr1 = src->data[2];
for (; height > 0; height--) {
p = p1;
lum = lum1;
cb = cb1;
cr = cr1;
for (w = width; w >= 2; w -= 2) {
p[1] = lum[0];
p[0] = cb[0];
p[3] = lum[1];
p[2] = cr[0];
p += 4;
lum += 2;
cb++;
cr++;
}
if (w) {
p[1] = lum[0];
p[0] = cb[0];
p[2] = cr[0];
}
p1 += dst->linesize[0];
lum1 += src->linesize[0];
cb1 += src->linesize[1];
cr1 += src->linesize[2];
}
}
static void
yuv422p_to_yvyu422 (AVPicture * dst, const AVPicture * src,
int width, int height)
{
uint8_t *p, *p1;
const uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
int w;
p1 = dst->data[0];
lum1 = src->data[0];
cb1 = src->data[1];
cr1 = src->data[2];
for (; height > 0; height--) {
p = p1;
lum = lum1;
cb = cb1;
cr = cr1;
for (w = width; w >= 2; w -= 2) {
p[0] = lum[0];
p[3] = cb[0];
p[2] = lum[1];
p[1] = cr[0];
p += 4;
lum += 2;
cb++;
cr++;
}
if (w) {
p[0] = lum[0];
p[3] = cb[0];
p[1] = cr[0];
}
p1 += dst->linesize[0];
lum1 += src->linesize[0];
cb1 += src->linesize[1];
cr1 += src->linesize[2];
}
}
static void
uyvy411_to_yuv411p (AVPicture * dst, const AVPicture * src,
int width, int height)
{
const uint8_t *p, *p1;
uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
int w;
p1 = src->data[0];
lum1 = dst->data[0];
cb1 = dst->data[1];
cr1 = dst->data[2];
for (; height > 0; height--) {
p = p1;
lum = lum1;
cb = cb1;
cr = cr1;
for (w = width; w >= 4; w -= 4) {
cb[0] = p[0];
lum[0] = p[1];
lum[1] = p[2];
cr[0] = p[3];
lum[2] = p[4];
lum[3] = p[5];
p += 6;
lum += 4;
cb++;
cr++;
}
p1 += src->linesize[0];
lum1 += dst->linesize[0];
cb1 += dst->linesize[1];
cr1 += dst->linesize[2];
}
}
static void
yuv411p_to_uyvy411 (AVPicture * dst, const AVPicture * src,
int width, int height)
{
uint8_t *p, *p1;
const uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
int w;
p1 = dst->data[0];
lum1 = src->data[0];
cb1 = src->data[1];
cr1 = src->data[2];
for (; height > 0; height--) {
p = p1;
lum = lum1;
cb = cb1;
cr = cr1;
for (w = width; w >= 4; w -= 4) {
p[0] = cb[0];
p[1] = lum[0];
p[2] = lum[1];
p[3] = cr[0];
p[4] = lum[2];
p[5] = lum[3];
p += 6;
lum += 4;
cb++;
cr++;
}
p1 += dst->linesize[0];
lum1 += src->linesize[0];
cb1 += src->linesize[1];
cr1 += src->linesize[2];
}
}
static void
yuv420p_to_yuv422 (AVPicture * dst, const AVPicture * src,
int width, int height)
{
int w, h;
uint8_t *line1, *line2, *linesrc = dst->data[0];
uint8_t *lum1, *lum2, *lumsrc = src->data[0];
uint8_t *cb1, *cb2 = src->data[1];
uint8_t *cr1, *cr2 = src->data[2];
for (h = height / 2; h--;) {
line1 = linesrc;
line2 = linesrc + dst->linesize[0];
lum1 = lumsrc;
lum2 = lumsrc + src->linesize[0];
cb1 = cb2;
cr1 = cr2;
for (w = width / 2; w--;) {
*line1++ = *lum1++;
*line2++ = *lum2++;
*line1++ = *line2++ = *cb1++;
*line1++ = *lum1++;
*line2++ = *lum2++;
*line1++ = *line2++ = *cr1++;
}
/* odd width */
if (width % 2 != 0) {
*line1++ = *lum1++;
*line2++ = *lum2++;
*line1++ = *line2++ = *cb1++;
}
linesrc += dst->linesize[0] * 2;
lumsrc += src->linesize[0] * 2;
cb2 += src->linesize[1];
cr2 += src->linesize[2];
}
/* odd height */
if (height % 2 != 0) {
line1 = linesrc;
lum1 = lumsrc;
cb1 = cb2;
cr1 = cr2;
for (w = width / 2; w--;) {
*line1++ = *lum1++;
*line1++ = *cb1++;
*line1++ = *lum1++;
*line1++ = *cr1++;
}
/* odd width */
if (width % 2 != 0) {
*line1++ = *lum1++;
*line1++ = *cb1++;
}
}
}
static void
nv12_to_nv21 (AVPicture * dst, const AVPicture * src, int width, int height)
{
const uint8_t *s_c_ptr;
uint8_t *d_c_ptr;
int w, c_wrap;
memcpy (dst->data[0], src->data[0], src->linesize[0] * height);
s_c_ptr = src->data[1];
d_c_ptr = dst->data[1];
c_wrap = src->linesize[1] - ((width + 1) & ~0x01);
for (; height >= 2; height -= 2) {
for (w = width; w >= 2; w -= 2) {
d_c_ptr[0] = s_c_ptr[1];
d_c_ptr[1] = s_c_ptr[0];
s_c_ptr += 2;
d_c_ptr += 2;
}
/* handle odd width */
if (w) {
d_c_ptr[0] = s_c_ptr[1];
d_c_ptr[1] = s_c_ptr[0];
s_c_ptr += 2;
d_c_ptr += 2;
}
s_c_ptr += c_wrap;
d_c_ptr += c_wrap;
}
/* handle odd height */
if (height) {
for (w = width; w >= 2; w -= 2) {
d_c_ptr[0] = s_c_ptr[1];
d_c_ptr[1] = s_c_ptr[0];
s_c_ptr += 2;
d_c_ptr += 2;
}
/* handle odd width */
if (w) {
d_c_ptr[0] = s_c_ptr[1];
d_c_ptr[1] = s_c_ptr[0];
s_c_ptr += 2;
d_c_ptr += 2;
}
}
}
static void
nv12_to_yuv444p (AVPicture * dst, const AVPicture * src, int width, int height)
{
int w, h;
uint8_t *dst_lum1, *dst_lum2, *dst_line = dst->data[0];
uint8_t *dst_cb1, *dst_cb2, *dst_cb_line = dst->data[1];
uint8_t *dst_cr1, *dst_cr2, *dst_cr_line = dst->data[2];
uint8_t *lum1, *lum2, *src_lum_line = src->data[0];
uint8_t *src_c1, *src_c_line = src->data[1];
uint8_t cb, cr;
for (h = height / 2; h--;) {
dst_lum1 = dst_line;
dst_lum2 = dst_line + dst->linesize[0];
dst_cb1 = dst_cb_line;
dst_cb2 = dst_cb_line + dst->linesize[1];
dst_cr1 = dst_cr_line;
dst_cr2 = dst_cr_line + dst->linesize[2];
lum1 = src_lum_line;
lum2 = src_lum_line + src->linesize[0];
src_c1 = src_c_line;
for (w = width / 2; w--;) {
cb = *src_c1++;
cr = *src_c1++;
*dst_lum1++ = *lum1++;
*dst_lum2++ = *lum2++;
*dst_cb1++ = *dst_cb2++ = cb;
*dst_cr1++ = *dst_cr2++ = cr;
*dst_lum1++ = *lum1++;
*dst_lum2++ = *lum2++;
*dst_cb1++ = *dst_cb2++ = cb;
*dst_cr1++ = *dst_cr2++ = cr;
}
/* odd width */
if (width % 2 != 0) {
cb = *src_c1++;
cr = *src_c1++;
*dst_lum1++ = *lum1++;
*dst_lum2++ = *lum2++;
*dst_cb1++ = *dst_cb2++ = *src_c1++;
*dst_cr1++ = *dst_cr2++ = *src_c1++;
}
dst_line += dst->linesize[0] * 2;
dst_cb_line += dst->linesize[1] * 2;
dst_cr_line += dst->linesize[2] * 2;
src_lum_line += src->linesize[0] * 2;
src_c_line += src->linesize[1];
}
/* odd height */
if (height % 2 != 0) {
dst_lum1 = dst_line;
lum1 = src_lum_line;
src_c1 = src_c_line;
dst_cb1 = dst_cb_line;
dst_cr1 = dst_cr_line;
for (w = width / 2; w--;) {
cb = *src_c1++;
cr = *src_c1++;
*dst_lum1++ = *lum1++;
*dst_cb1++ = cb;
*dst_cr1++ = cr;
*dst_lum1++ = *lum1++;
*dst_cb1++ = cb;
*dst_cr1++ = cr;
}
/* odd width */
if (width % 2 != 0) {
cb = *src_c1++;
cr = *src_c1++;
*dst_lum1++ = *lum1++;
*dst_cb1++ = cb;
*dst_cr1++ = cr;
}
}
}
#define nv21_to_nv12 nv12_to_nv21
static void
nv21_to_yuv444p (AVPicture * dst, const AVPicture * src, int width, int height)
{
int w, h;
uint8_t *dst_lum1, *dst_lum2, *dst_line = dst->data[0];
uint8_t *dst_cb1, *dst_cb2, *dst_cb_line = dst->data[1];
uint8_t *dst_cr1, *dst_cr2, *dst_cr_line = dst->data[2];
uint8_t *lum1, *lum2, *src_lum_line = src->data[0];
uint8_t *src_c1, *src_c_line = src->data[1];
uint8_t cb, cr;
for (h = height / 2; h--;) {
dst_lum1 = dst_line;
dst_lum2 = dst_line + dst->linesize[0];
dst_cb1 = dst_cb_line;
dst_cb2 = dst_cb_line + dst->linesize[1];
dst_cr1 = dst_cr_line;
dst_cr2 = dst_cr_line + dst->linesize[2];
lum1 = src_lum_line;
lum2 = src_lum_line + src->linesize[0];
src_c1 = src_c_line;
for (w = width / 2; w--;) {
cr = *src_c1++;
cb = *src_c1++;
*dst_lum1++ = *lum1++;
*dst_lum2++ = *lum2++;
*dst_cb1++ = *dst_cb2++ = cb;
*dst_cr1++ = *dst_cr2++ = cr;
*dst_lum1++ = *lum1++;
*dst_lum2++ = *lum2++;
*dst_cb1++ = *dst_cb2++ = cb;
*dst_cr1++ = *dst_cr2++ = cr;
}
/* odd width */
if (width % 2 != 0) {
cr = *src_c1++;
cb = *src_c1++;
*dst_lum1++ = *lum1++;
*dst_lum2++ = *lum2++;
*dst_cb1++ = *dst_cb2++ = *src_c1++;
*dst_cr1++ = *dst_cr2++ = *src_c1++;
}
dst_line += dst->linesize[0] * 2;
dst_cb_line += dst->linesize[1] * 2;
dst_cr_line += dst->linesize[2] * 2;
src_lum_line += src->linesize[0] * 2;
src_c_line += src->linesize[1];
}
/* odd height */
if (height % 2 != 0) {
dst_lum1 = dst_line;
lum1 = src_lum_line;
src_c1 = src_c_line;
dst_cb1 = dst_cb_line;
dst_cr1 = dst_cr_line;
for (w = width / 2; w--;) {
cr = *src_c1++;
cb = *src_c1++;
*dst_lum1++ = *lum1++;
*dst_cb1++ = cb;
*dst_cr1++ = cr;
*dst_lum1++ = *lum1++;
*dst_cb1++ = cb;
*dst_cr1++ = cr;
}
/* odd width */
if (width % 2 != 0) {
cr = *src_c1++;
cb = *src_c1++;
*dst_lum1++ = *lum1++;
*dst_cb1++ = cb;
*dst_cr1++ = cr;
}
}
}
static void
yuva420p_to_yuv420p (AVPicture * dst, const AVPicture * src, int width,
int height)
{
memcpy (dst->data[0], src->data[0], dst->linesize[0] * height);
memcpy (dst->data[1], src->data[1], dst->linesize[1] * ((height + 1) / 2));
memcpy (dst->data[2], src->data[2], dst->linesize[2] * ((height + 1) / 2));
}
static void
yuva420p_to_yuv422 (AVPicture * dst, const AVPicture * src,
int width, int height)
{
int w, h;
uint8_t *line1, *line2, *linesrc = dst->data[0];
uint8_t *lum1, *lum2, *lumsrc = src->data[0];
uint8_t *cb1, *cb2 = src->data[1];
uint8_t *cr1, *cr2 = src->data[2];
for (h = height / 2; h--;) {
line1 = linesrc;
line2 = linesrc + dst->linesize[0];
lum1 = lumsrc;
lum2 = lumsrc + src->linesize[0];
cb1 = cb2;
cr1 = cr2;
for (w = width / 2; w--;) {
*line1++ = *lum1++;
*line2++ = *lum2++;
*line1++ = *line2++ = *cb1++;
*line1++ = *lum1++;
*line2++ = *lum2++;
*line1++ = *line2++ = *cr1++;
}
/* odd width */
if (width % 2 != 0) {
*line1++ = *lum1++;
*line2++ = *lum2++;
*line1++ = *line2++ = *cb1++;
}
linesrc += dst->linesize[0] * 2;
lumsrc += src->linesize[0] * 2;
cb2 += src->linesize[1];
cr2 += src->linesize[2];
}
/* odd height */
if (height % 2 != 0) {
line1 = linesrc;
lum1 = lumsrc;
cb1 = cb2;
cr1 = cr2;
for (w = width / 2; w--;) {
*line1++ = *lum1++;
*line1++ = *cb1++;
*line1++ = *lum1++;
*line1++ = *cr1++;
}
/* odd width */
if (width % 2 != 0) {
*line1++ = *lum1++;
*line1++ = *cb1++;
}
}
}
#define SCALEBITS 10
#define ONE_HALF (1 << (SCALEBITS - 1))
#define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
#define YUV_TO_RGB1_CCIR(cb1, cr1)\
{\
cb = (cb1) - 128;\
cr = (cr1) - 128;\
r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;\
g_add = - FIX(0.34414*255.0/224.0) * cb - FIX(0.71414*255.0/224.0) * cr + \
ONE_HALF;\
b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;\
}
#define YUV_TO_RGB2_CCIR(r, g, b, y1)\
{\
y = ((y1) - 16) * FIX(255.0/219.0);\
r = cm[(y + r_add) >> SCALEBITS];\
g = cm[(y + g_add) >> SCALEBITS];\
b = cm[(y + b_add) >> SCALEBITS];\
}
#define YUV_TO_RGB1(cb1, cr1)\
{\
cb = (cb1) - 128;\
cr = (cr1) - 128;\
r_add = FIX(1.40200) * cr + ONE_HALF;\
g_add = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;\
b_add = FIX(1.77200) * cb + ONE_HALF;\
}
#define YUV_TO_RGB2(r, g, b, y1)\
{\
y = (y1) << SCALEBITS;\
r = cm[(y + r_add) >> SCALEBITS];\
g = cm[(y + g_add) >> SCALEBITS];\
b = cm[(y + b_add) >> SCALEBITS];\
}
#define Y_CCIR_TO_JPEG(y)\
cm[((y) * FIX(255.0/219.0) + (ONE_HALF - 16 * FIX(255.0/219.0))) >> SCALEBITS]
#define Y_JPEG_TO_CCIR(y)\
(((y) * FIX(219.0/255.0) + (ONE_HALF + (16 << SCALEBITS))) >> SCALEBITS)
#define C_CCIR_TO_JPEG(y)\
cm[(((y) - 128) * FIX(127.0/112.0) + (ONE_HALF + (128 << SCALEBITS))) >> SCALEBITS]
/* NOTE: the clamp is really necessary! */
static inline int
C_JPEG_TO_CCIR (int y)
{
y = (((y - 128) * FIX (112.0 / 127.0) + (ONE_HALF +
(128 << SCALEBITS))) >> SCALEBITS);
if (y < 16)
y = 16;
return y;
}
#define RGB_TO_Y(r, g, b) \
((FIX(0.29900) * (r) + FIX(0.58700) * (g) + \
FIX(0.11400) * (b) + ONE_HALF) >> SCALEBITS)
#define RGB_TO_U(r1, g1, b1, shift)\
(((- FIX(0.16874) * r1 - FIX(0.33126) * g1 + \
FIX(0.50000) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128)
#define RGB_TO_V(r1, g1, b1, shift)\
(((FIX(0.50000) * r1 - FIX(0.41869) * g1 - \
FIX(0.08131) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128)
#define RGB_TO_Y_CCIR(r, g, b) \
((FIX(0.29900*219.0/255.0) * (r) + FIX(0.58700*219.0/255.0) * (g) + \
FIX(0.11400*219.0/255.0) * (b) + (ONE_HALF + (16 << SCALEBITS))) >> SCALEBITS)
#define RGB_TO_U_CCIR(r1, g1, b1, shift)\
(((- FIX(0.16874*224.0/255.0) * r1 - FIX(0.33126*224.0/255.0) * g1 + \
FIX(0.50000*224.0/255.0) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128)
#define RGB_TO_V_CCIR(r1, g1, b1, shift)\
(((FIX(0.50000*224.0/255.0) * r1 - FIX(0.41869*224.0/255.0) * g1 - \
FIX(0.08131*224.0/255.0) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128)
static uint8_t y_ccir_to_jpeg[256];
static uint8_t y_jpeg_to_ccir[256];
static uint8_t c_ccir_to_jpeg[256];
static uint8_t c_jpeg_to_ccir[256];
/* init various conversion tables */
static void
img_convert_init (void)
{
int i;
uint8_t *cm = cropTbl + MAX_NEG_CROP;
for (i = 0; i < 256; i++) {
y_ccir_to_jpeg[i] = Y_CCIR_TO_JPEG (i);
y_jpeg_to_ccir[i] = Y_JPEG_TO_CCIR (i);
c_ccir_to_jpeg[i] = C_CCIR_TO_JPEG (i);
c_jpeg_to_ccir[i] = C_JPEG_TO_CCIR (i);
}
}
/* apply to each pixel the given table */
static void
img_apply_table (uint8_t * dst, int dst_wrap,
const uint8_t * src, int src_wrap,
int width, int height, const uint8_t * table1)
{
int n;
const uint8_t *s;
uint8_t *d;
const uint8_t *table;
table = table1;
for (; height > 0; height--) {
s = src;
d = dst;
n = width;
while (n >= 4) {
d[0] = table[s[0]];
d[1] = table[s[1]];
d[2] = table[s[2]];
d[3] = table[s[3]];
d += 4;
s += 4;
n -= 4;
}
while (n > 0) {
d[0] = table[s[0]];
d++;
s++;
n--;
}
dst += dst_wrap;
src += src_wrap;
}
}
/* XXX: use generic filter ? */
/* XXX: in most cases, the sampling position is incorrect */
static void
img_copy_plane_resize (uint8_t * dst, int dst_wrap, int dst_width,
int dst_height, const uint8_t * src, int src_wrap, int src_width,
int src_height)
{
img_copy_plane (dst, dst_wrap, src, src_wrap, dst_width, dst_height);
}
/* 4x1 -> 1x1 */
static void
shrink41 (uint8_t * dst, int dst_wrap, int dst_width, int dst_height,
const uint8_t * src, int src_wrap, int src_width, int src_height)
{
int w, s_w;
const uint8_t *s;
uint8_t *d;
for (; dst_height > 0; dst_height--) {
s = src;
d = dst;
for (s_w = src_width, w = dst_width; w > 0 && s_w > 3; w--, s_w -= 4) {
d[0] = (s[0] + s[1] + s[2] + s[3] + 2) >> 2;
s += 4;
d++;
}
if (w) {
if (s_w == 3)
d[0] = (s[0] + s[1] + s[2]) / 3;
else if (s_w == 2)
d[0] = (s[0] + s[1]) / 2;
else /* s_w == 1 */
d[0] = s[0];
}
src += src_wrap;
dst += dst_wrap;
}
}
/* 2x1 -> 1x1 */
static void
shrink21 (uint8_t * dst, int dst_wrap, int dst_width, int dst_height,
const uint8_t * src, int src_wrap, int src_width, int src_height)
{
int w, s_w;
const uint8_t *s;
uint8_t *d;
for (; dst_height > 0; dst_height--) {
s = src;
d = dst;
for (s_w = src_width, w = dst_width; w > 0 && s_w > 1; w--, s_w -= 2) {
d[0] = (s[0] + s[1]) >> 1;
s += 2;
d++;
}
if (w) /* s_w == 1 */
d[0] = s[0];
src += src_wrap;
dst += dst_wrap;
}
}
/* 1x2 -> 1x1 */
static void
shrink12 (uint8_t * dst, int dst_wrap, int dst_width, int dst_height,
const uint8_t * src, int src_wrap, int src_width, int src_height)
{
int w;
uint8_t *d;
const uint8_t *s1, *s2;
for (; dst_height > 0; dst_height--, src_height -= 2) {
s1 = src;
s2 = s1 + (src_height > 1 ? src_wrap : 0);
d = dst;
for (w = dst_width; w >= 4; w -= 4) {
d[0] = (s1[0] + s2[0]) >> 1;
d[1] = (s1[1] + s2[1]) >> 1;
d[2] = (s1[2] + s2[2]) >> 1;
d[3] = (s1[3] + s2[3]) >> 1;
s1 += 4;
s2 += 4;
d += 4;
}
for (; w > 0; w--) {
d[0] = (s1[0] + s2[0]) >> 1;
s1++;
s2++;
d++;
}
src += 2 * src_wrap;
dst += dst_wrap;
}
}
/* 2x2 -> 1x1 */
static void
shrink22 (uint8_t * dst, int dst_wrap, int dst_width, int dst_height,
const uint8_t * src, int src_wrap, int src_width, int src_height)
{
int w, s_w;
const uint8_t *s1, *s2;
uint8_t *d;
for (; dst_height > 0; dst_height--, src_height -= 2) {
s1 = src;
s2 = s1 + (src_height > 1 ? src_wrap : 0);
d = dst;
for (s_w = src_width, w = dst_width; w >= 4; w -= 4, s_w -= 8) {
d[0] = (s1[0] + s1[1] + s2[0] + s2[1] + 2) >> 2;
d[1] = (s1[2] + s1[3] + s2[2] + s2[3] + 2) >> 2;
d[2] = (s1[4] + s1[5] + s2[4] + s2[5] + 2) >> 2;
d[3] = (s1[6] + s1[7] + s2[6] + s2[7] + 2) >> 2;
s1 += 8;
s2 += 8;
d += 4;
}
for (; w > 0 && s_w > 1; w--, s_w -= 2) {
d[0] = (s1[0] + s1[1] + s2[0] + s2[1] + 2) >> 2;
s1 += 2;
s2 += 2;
d++;
}
if (w)
d[0] = (s1[0] + s2[0] + 1) >> 1;
src += 2 * src_wrap;
dst += dst_wrap;
}
}
/* 4x4 -> 1x1 */
static void
shrink44 (uint8_t * dst, int dst_wrap, int dst_width, int dst_height,
const uint8_t * src, int src_wrap, int src_width, int src_height)
{
int s_w, w;
const uint8_t *s1, *s2, *s3, *s4;
uint8_t *d;
for (; dst_height > 0; dst_height--, src_height -= 4) {
s1 = src;
s2 = s1 + (src_height > 1 ? src_wrap : 0);
s3 = s2 + (src_height > 2 ? src_wrap : 0);
s4 = s3 + (src_height > 3 ? src_wrap : 0);
d = dst;
for (s_w = src_width, w = dst_width; s_w > 3 && w > 0; w--, s_w -= 4) {
d[0] = (s1[0] + s1[1] + s1[2] + s1[3] +
s2[0] + s2[1] + s2[2] + s2[3] +
s3[0] + s3[1] + s3[2] + s3[3] +
s4[0] + s4[1] + s4[2] + s4[3] + 8) >> 4;
s1 += 4;
s2 += 4;
s3 += 4;
s4 += 4;
d++;
}
if (w) {
if (s_w == 3)
d[0] = (s1[0] + s1[1] + s1[2] +
s2[0] + s2[1] + s2[2] +
s3[0] + s3[1] + s3[2] + s4[0] + s4[1] + s4[2]) / 12;
else if (s_w == 2)
d[0] = (s1[0] + s1[1] +
s2[0] + s2[1] + s3[0] + s3[1] + s4[0] + s4[1]) / 8;
else /* s_w == 1 */
d[0] = (s1[0] + s2[0] + s3[0] + s4[0]) / 4;
}
src += 4 * src_wrap;
dst += dst_wrap;
}
}
static void
grow21_line (uint8_t * dst, const uint8_t * src, int width)
{
int w;
const uint8_t *s1;
uint8_t *d;
s1 = src;
d = dst;
for (w = width; w >= 4; w -= 4) {
d[1] = d[0] = s1[0];
d[3] = d[2] = s1[1];
s1 += 2;
d += 4;
}
for (; w >= 2; w -= 2) {
d[1] = d[0] = s1[0];
s1++;
d += 2;
}
/* only needed if width is not a multiple of two */
if (w) {
d[0] = s1[0];
}
}
static void
grow41_line (uint8_t * dst, const uint8_t * src, int width)
{
int w, v;
const uint8_t *s1;
uint8_t *d;
s1 = src;
d = dst;
for (w = width; w >= 4; w -= 4) {
v = s1[0];
d[0] = v;
d[1] = v;
d[2] = v;
d[3] = v;
s1++;
d += 4;
}
for (; w > 0; w--) {
d[0] = s1[0];
d++;
}
}
/* 1x1 -> 2x1 */
static void
grow21 (uint8_t * dst, int dst_wrap, int dst_width, int dst_height,
const uint8_t * src, int src_wrap, int src_width, int src_height)
{
for (; dst_height > 0; dst_height--) {
grow21_line (dst, src, dst_width);
src += src_wrap;
dst += dst_wrap;
}
}
/* 1x1 -> 2x2 */
static void
grow22 (uint8_t * dst, int dst_wrap, int dst_width, int dst_height,
const uint8_t * src, int src_wrap, int src_width, int src_height)
{
for (; dst_height > 0; dst_height--) {
grow21_line (dst, src, dst_width);
if (dst_height % 2)
src += src_wrap;
dst += dst_wrap;
}
}
/* 1x1 -> 4x1 */
static void
grow41 (uint8_t * dst, int dst_wrap, int dst_width, int dst_height,
const uint8_t * src, int src_wrap, int src_width, int src_height)
{
for (; dst_height > 0; dst_height--) {
grow41_line (dst, src, dst_width);
src += src_wrap;
dst += dst_wrap;
}
}
/* 1x1 -> 4x4 */
static void
grow44 (uint8_t * dst, int dst_wrap, int dst_width, int dst_height,
const uint8_t * src, int src_wrap, int src_width, int src_height)
{
for (; dst_height > 0; dst_height--) {
grow41_line (dst, src, dst_width);
if ((dst_height & 3) == 1)
src += src_wrap;
dst += dst_wrap;
}
}
/* 1x2 -> 2x1 */
static void
conv411 (uint8_t * dst, int dst_wrap, int dst_width, int dst_height,
const uint8_t * src, int src_wrap, int src_width, int src_height)
{
int w, c;
const uint8_t *s1, *s2;
uint8_t *d;
for (; dst_height > 0; dst_height--, src_height -= 2) {
s1 = src;
s2 = src + (src_height > 1 ? src_wrap : 0);
d = dst;
for (w = dst_width; w > 1; w -= 2) {
c = (s1[0] + s2[0]) >> 1;
d[0] = c;
d[1] = c;
s1++;
s2++;
d += 2;
}
if (w) {
d[0] = (s1[0] + s2[0]) >> 1;
}
src += src_wrap * 2;
dst += dst_wrap;
}
}
/* XXX: add jpeg quantize code */
#define TRANSP_INDEX (6*6*6)
/* this is maybe slow, but allows for extensions */
static inline unsigned char
gif_clut_index (uint8_t r, uint8_t g, uint8_t b)
{
return ((((r) / 47) % 6) * 6 * 6 + (((g) / 47) % 6) * 6 + (((b) / 47) % 6));
}
static void
build_rgb_palette (uint8_t * palette, int has_alpha)
{
uint32_t *pal;
static const uint8_t pal_value[6] = { 0x00, 0x33, 0x66, 0x99, 0xcc, 0xff };
int i, r, g, b;
pal = (uint32_t *) palette;
i = 0;
for (r = 0; r < 6; r++) {
for (g = 0; g < 6; g++) {
for (b = 0; b < 6; b++) {
pal[i++] = (0xffU << 24) | (pal_value[r] << 16) |
(pal_value[g] << 8) | pal_value[b];
}
}
}
if (has_alpha)
pal[i++] = 0;
while (i < 256)
pal[i++] = 0xff000000;
}
/* copy bit n to bits 0 ... n - 1 */
static inline unsigned int
bitcopy_n (unsigned int a, int n)
{
int mask;
mask = (1 << n) - 1;
return (a & (0xff & ~mask)) | ((-((a >> n) & 1)) & mask);
}
/* rgb555 handling */
#define RGB_NAME rgb555
#define RGB_IN(r, g, b, s)\
{\
unsigned int v = ((const uint16_t *)(s))[0];\
r = bitcopy_n(v >> (10 - 3), 3);\
g = bitcopy_n(v >> (5 - 3), 3);\
b = bitcopy_n(v << 3, 3);\
}
#define RGBA_IN(r, g, b, a, s)\
{\
unsigned int v = ((const uint16_t *)(s))[0];\
r = bitcopy_n(v >> (10 - 3), 3);\
g = bitcopy_n(v >> (5 - 3), 3);\
b = bitcopy_n(v << 3, 3);\
a = (-(v >> 15)) & 0xff;\
}
#define RGBA_OUT(d, r, g, b, a)\
{\
((uint16_t *)(d))[0] = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3) | \
((a << 8) & 0x8000);\
}
#define BPP 2
#include "imgconvert_template.h"
/* rgb565 handling */
#define RGB_NAME rgb565
#define RGB_IN(r, g, b, s)\
{\
unsigned int v = ((const uint16_t *)(s))[0];\
r = bitcopy_n(v >> (11 - 3), 3);\
g = bitcopy_n(v >> (5 - 2), 2);\
b = bitcopy_n(v << 3, 3);\
}
#define RGB_OUT(d, r, g, b)\
{\
((uint16_t *)(d))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);\
}
#define BPP 2
#include "imgconvert_template.h"
/* bgr24 handling */
#define RGB_NAME bgr24
#define RGB_IN(r, g, b, s)\
{\
b = (s)[0];\
g = (s)[1];\
r = (s)[2];\
}
#define RGB_OUT(d, r, g, b)\
{\
(d)[0] = b;\
(d)[1] = g;\
(d)[2] = r;\
}
#define BPP 3
#include "imgconvert_template.h"
#undef RGB_IN
#undef RGB_OUT
#undef BPP
/* rgb24 handling */
#define RGB_NAME rgb24
#define FMT_RGB24
#define RGB_IN(r, g, b, s)\
{\
r = (s)[0];\
g = (s)[1];\
b = (s)[2];\
}
#define RGB_OUT(d, r, g, b)\
{\
(d)[0] = r;\
(d)[1] = g;\
(d)[2] = b;\
}
#define BPP 3
#include "imgconvert_template.h"
/* rgb32 handling */
#define RGB_NAME rgb32
#define FMT_RGBA32
#define RGB_IN(r, g, b, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
r = (v >> 16) & 0xff;\
g = (v >> 8) & 0xff;\
b = v & 0xff;\
}
#define RGBA_IN(r, g, b, a, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
a = 0xff;\
r = (v >> 16) & 0xff;\
g = (v >> 8) & 0xff;\
b = v & 0xff;\
}
#define RGBA_OUT(d, r, g, b, a)\
{\
((uint32_t *)(d))[0] = (a << 24) | (r << 16) | (g << 8) | b;\
}
#define BPP 4
#include "imgconvert_template.h"
/* bgr32 handling */
#define RGB_NAME bgr32
#define RGB_IN(r, g, b, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
r = (v >> 8) & 0xff;\
g = (v >> 16) & 0xff;\
b = (v >> 24) & 0xff;\
}
#define RGBA_IN(r, g, b, a, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
a = 0xff;\
r = (v >> 8) & 0xff;\
g = (v >> 16) & 0xff;\
b = (v >> 24) & 0xff;\
}
#define RGBA_OUT(d, r, g, b, a)\
{\
((uint32_t *)(d))[0] = a | (r << 8) | (g << 16) | (b << 24);\
}
#define BPP 4
#include "imgconvert_template.h"
/* xrgb32 handling */
#define RGB_NAME xrgb32
#define FMT_RGBA32
#define RGB_IN(r, g, b, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
r = (v >> 24) & 0xff;\
g = (v >> 16) & 0xff;\
b = (v >> 8) & 0xff;\
}
#define RGBA_IN(r, g, b, a, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
a = 0xff;\
r = (v >> 24) & 0xff;\
g = (v >> 16) & 0xff;\
b = (v >> 8) & 0xff;\
}
#define RGBA_OUT(d, r, g, b, a)\
{\
((uint32_t *)(d))[0] = (r << 24) | (g << 16) | (b << 8) | a;\
}
#define BPP 4
#include "imgconvert_template.h"
/* bgrx32 handling */
#define RGB_NAME bgrx32
#define RGB_IN(r, g, b, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
r = (v) & 0xff;\
g = (v >> 8) & 0xff;\
b = (v >> 16) & 0xff;\
}
#define RGBA_IN(r, g, b, a, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
a = 0xff;\
r = (v) & 0xff;\
g = (v >> 8) & 0xff;\
b = (v >> 16) & 0xff;\
}
#define RGBA_OUT(d, r, g, b, a)\
{\
((uint32_t *)(d))[0] = r | (g << 8) | (b << 16) | (a << 24);\
}
#define BPP 4
#include "imgconvert_template.h"
/* rgba32 handling */
#define RGB_NAME rgba32
#define FMT_RGBA32
#define RGB_IN(r, g, b, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
r = (v >> 16) & 0xff;\
g = (v >> 8) & 0xff;\
b = v & 0xff;\
}
#define RGBA_IN(r, g, b, a, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
a = (v >> 24) & 0xff;\
r = (v >> 16) & 0xff;\
g = (v >> 8) & 0xff;\
b = v & 0xff;\
}
#define RGBA_OUT(d, r, g, b, a)\
{\
((uint32_t *)(d))[0] = (a << 24) | (r << 16) | (g << 8) | b;\
}
#define BPP 4
#include "imgconvert_template.h"
/* bgra32 handling */
#define RGB_NAME bgra32
#define FMT_BGRA32
#define RGB_IN(r, g, b, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
r = (v >> 8) & 0xff;\
g = (v >> 16) & 0xff;\
b = (v >> 24) & 0xff;\
}
#define RGBA_IN(r, g, b, a, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
a = v & 0xff;\
r = (v >> 8) & 0xff;\
g = (v >> 16) & 0xff;\
b = (v >> 24) & 0xff;\
}
#define RGBA_OUT(d, r, g, b, a)\
{\
((uint32_t *)(d))[0] = a | (r << 8) | (g << 16) | (b << 24 );\
}
#define BPP 4
#include "imgconvert_template.h"
/* argb32 handling */
#define RGB_NAME argb32
#define FMT_ARGB32
#define RGB_IN(r, g, b, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
r = (v >> 24) & 0xff;\
g = (v >> 16) & 0xff;\
b = (v >> 8) & 0xff;\
}
#define RGBA_IN(r, g, b, a, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
r = (v >> 24) & 0xff;\
g = (v >> 16) & 0xff;\
b = (v >> 8) & 0xff;\
a = v & 0xff;\
}
#define RGBA_OUT(d, r, g, b, a)\
{\
((uint32_t *)(d))[0] = (r << 24) | (g << 16) | (b << 8) | a;\
}
#define BPP 4
#include "imgconvert_template.h"
/* abgr32 handling */
#define RGB_NAME abgr32
#define FMT_ABGR32
#define RGB_IN(r, g, b, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
r = v & 0xff;\
g = (v >> 8) & 0xff;\
b = (v >> 16) & 0xff;\
}
#define RGBA_IN(r, g, b, a, s)\
{\
unsigned int v = ((const uint32_t *)(s))[0];\
r = v & 0xff;\
g = (v >> 8) & 0xff;\
b = (v >> 16) & 0xff;\
a = (v >> 24) & 0xff;\
}
#define RGBA_OUT(d, r, g, b, a)\
{\
((uint32_t *)(d))[0] = r | (g << 8) | (b << 16) | (a << 24 );\
}
#define BPP 4
#include "imgconvert_template.h"
static void
gray_to_gray16_l (AVPicture * dst, const AVPicture * src, int width, int height)
{
const unsigned char *p;
unsigned char *q;
int dst_wrap, src_wrap;
int x, y;
p = src->data[0];
src_wrap = src->linesize[0] - width;
q = dst->data[0];
dst_wrap = dst->linesize[0] - 2 * width;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
GST_WRITE_UINT16_LE (q, (*p << 8));
q += 2;
p++;
}
p += src_wrap;
q += dst_wrap;
}
}
static void
gray_to_gray16_b (AVPicture * dst, const AVPicture * src, int width, int height)
{
const unsigned char *p;
unsigned char *q;
int dst_wrap, src_wrap;
int x, y;
p = src->data[0];
src_wrap = src->linesize[0] - width;
q = dst->data[0];
dst_wrap = dst->linesize[0] - 2 * width;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
GST_WRITE_UINT16_BE (q, (*p << 8));
q += 2;
p++;
}
p += src_wrap;
q += dst_wrap;
}
}
static void
gray16_l_to_gray (AVPicture * dst, const AVPicture * src, int width, int height)
{
const unsigned char *p;
unsigned char *q;
int dst_wrap, src_wrap;
int x, y;
p = src->data[0];
src_wrap = src->linesize[0] - 2 * width;
q = dst->data[0];
dst_wrap = dst->linesize[0] - width;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
q[0] = GST_READ_UINT16_LE (p) >> 8;
q++;
p += 2;
}
p += src_wrap;
q += dst_wrap;
}
}
static void
gray16_b_to_gray (AVPicture * dst, const AVPicture * src, int width, int height)
{
const unsigned char *p;
unsigned char *q;
int dst_wrap, src_wrap;
int x, y;
p = src->data[0];
src_wrap = src->linesize[0] - 2 * width;
q = dst->data[0];
dst_wrap = dst->linesize[0] - width;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
q[0] = GST_READ_UINT16_BE (p) >> 8;
q++;
p += 2;
}
p += src_wrap;
q += dst_wrap;
}
}
static void
gray16_b_to_gray16_l (AVPicture * dst, const AVPicture * src,
int width, int height)
{
const unsigned char *p;
unsigned char *q;
int dst_wrap, src_wrap;
int x, y;
p = src->data[0];
src_wrap = src->linesize[0] - 2 * width;
q = dst->data[0];
dst_wrap = dst->linesize[0] - 2 * width;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
q[0] = p[1];
q[1] = p[0];
q += 2;
p += 2;
}
p += src_wrap;
q += dst_wrap;
}
}
static void
mono_to_gray (AVPicture * dst, const AVPicture * src,
int width, int height, int xor_mask)
{
const unsigned char *p;
unsigned char *q;
int v, dst_wrap, src_wrap;
int y, w;
p = src->data[0];
src_wrap = src->linesize[0] - ((width + 7) >> 3);
q = dst->data[0];
dst_wrap = dst->linesize[0] - width;
for (y = 0; y < height; y++) {
w = width;
while (w >= 8) {
v = *p++ ^ xor_mask;
q[0] = -(v >> 7);
q[1] = -((v >> 6) & 1);
q[2] = -((v >> 5) & 1);
q[3] = -((v >> 4) & 1);
q[4] = -((v >> 3) & 1);
q[5] = -((v >> 2) & 1);
q[6] = -((v >> 1) & 1);
q[7] = -((v >> 0) & 1);
w -= 8;
q += 8;
}
if (w > 0) {
v = *p++ ^ xor_mask;
do {
q[0] = -((v >> 7) & 1);
q++;
v <<= 1;
} while (--w);
}
p += src_wrap;
q += dst_wrap;
}
}
static void
monowhite_to_gray (AVPicture * dst, const AVPicture * src,
int width, int height)
{
mono_to_gray (dst, src, width, height, 0xff);
}
static void
monoblack_to_gray (AVPicture * dst, const AVPicture * src,
int width, int height)
{
mono_to_gray (dst, src, width, height, 0x00);
}
static void
gray_to_mono (AVPicture * dst, const AVPicture * src,
int width, int height, int xor_mask)
{
int n;
const uint8_t *s;
uint8_t *d;
int j, b, v, n1, src_wrap, dst_wrap, y;
s = src->data[0];
src_wrap = src->linesize[0] - width;
d = dst->data[0];
dst_wrap = dst->linesize[0] - ((width + 7) >> 3);
for (y = 0; y < height; y++) {
n = width;
while (n >= 8) {
v = 0;
for (j = 0; j < 8; j++) {
b = s[0];
s++;
v = (v << 1) | (b >> 7);
}
d[0] = v ^ xor_mask;
d++;
n -= 8;
}
if (n > 0) {
n1 = n;
v = 0;
while (n > 0) {
b = s[0];
s++;
v = (v << 1) | (b >> 7);
n--;
}
d[0] = (v << (8 - (n1 & 7))) ^ xor_mask;
d++;
}
s += src_wrap;
d += dst_wrap;
}
}
static void
gray_to_monowhite (AVPicture * dst, const AVPicture * src,
int width, int height)
{
gray_to_mono (dst, src, width, height, 0xff);
}
static void
gray_to_monoblack (AVPicture * dst, const AVPicture * src,
int width, int height)
{
gray_to_mono (dst, src, width, height, 0x00);
}
static void
y800_to_y16 (AVPicture * dst, const AVPicture * src, int width, int height)
{
const unsigned char *p;
unsigned char *q;
int dst_wrap, src_wrap;
int x, y;
p = src->data[0];
src_wrap = src->linesize[0] - width;
q = dst->data[0];
dst_wrap = dst->linesize[0] - 2 * width;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
GST_WRITE_UINT16_LE (q, (*p << 8));
q += 2;
p++;
}
p += src_wrap;
q += dst_wrap;
}
}
static void
y16_to_y800 (AVPicture * dst, const AVPicture * src, int width, int height)
{
const unsigned char *p;
unsigned char *q;
int dst_wrap, src_wrap;
int x, y;
p = src->data[0];
src_wrap = src->linesize[0] - 2 * width;
q = dst->data[0];
dst_wrap = dst->linesize[0] - width;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
q[0] = GST_READ_UINT16_LE (p) >> 8;
q++;
p += 2;
}
p += src_wrap;
q += dst_wrap;
}
}
static void
yuva420p_to_ayuv4444 (AVPicture * dst, const AVPicture * src,
int width, int height)
{
const uint8_t *y1_ptr, *y2_ptr, *cb_ptr, *cr_ptr, *a1_ptr, *a2_ptr;
uint8_t *d, *d1, *d2;
int w, width2;
d = dst->data[0];
y1_ptr = src->data[0];
cb_ptr = src->data[1];
cr_ptr = src->data[2];
a1_ptr = src->data[3];
width2 = (width + 1) >> 1;
for (; height >= 2; height -= 2) {
d1 = d;
d2 = d + dst->linesize[0];
y2_ptr = y1_ptr + src->linesize[0];
a2_ptr = a1_ptr + src->linesize[3];
for (w = width; w >= 2; w -= 2) {
d1[0] = a1_ptr[0];
d1[1] = y1_ptr[0];
d1[2] = cb_ptr[0];
d1[3] = cr_ptr[0];
d1[4 + 0] = a1_ptr[1];
d1[4 + 1] = y1_ptr[1];
d1[4 + 2] = cb_ptr[0];
d1[4 + 3] = cr_ptr[0];
d2[0] = a2_ptr[0];
d2[1] = y2_ptr[0];
d2[2] = cb_ptr[0];
d2[3] = cr_ptr[0];
d2[4 + 0] = a2_ptr[1];
d2[4 + 1] = y2_ptr[1];
d2[4 + 2] = cb_ptr[0];
d2[4 + 3] = cr_ptr[0];
d1 += 2 * 4;
d2 += 2 * 4;
y1_ptr += 2;
y2_ptr += 2;
cb_ptr++;
cr_ptr++;
a1_ptr += 2;
a2_ptr += 2;
}
/* handle odd width */
if (w) {
d1[0] = a1_ptr[0];
d1[1] = y1_ptr[0];
d1[2] = cb_ptr[0];
d1[3] = cr_ptr[0];
d2[0] = a2_ptr[0];
d2[1] = y2_ptr[0];
d2[2] = cb_ptr[0];
d2[3] = cr_ptr[0];
d1 += 4;
d2 += 4;
y1_ptr++;
y2_ptr++;
cb_ptr++;
cr_ptr++;
a1_ptr++;
a2_ptr++;
}
d += 2 * dst->linesize[0];
y1_ptr += 2 * src->linesize[0] - width;
cb_ptr += src->linesize[1] - width2;
cr_ptr += src->linesize[2] - width2;
a1_ptr += 2 * src->linesize[3] - width;
}
/* handle odd height */
if (height) {
d1 = d;
for (w = width; w >= 2; w -= 2) {
d1[0] = a1_ptr[0];
d1[1] = y1_ptr[0];
d1[2] = cb_ptr[0];
d1[3] = cr_ptr[0];
d1[4 + 0] = a1_ptr[1];
d1[4 + 1] = y1_ptr[1];
d1[4 + 2] = cb_ptr[0];
d1[4 + 3] = cr_ptr[0];
d1 += 2 * 4;
y1_ptr += 2;
cb_ptr++;
cr_ptr++;
a1_ptr += 2;
}
/* handle width */
if (w) {
d1[0] = a1_ptr[0];
d1[1] = y1_ptr[0];
d1[2] = cb_ptr[0];
d1[3] = cr_ptr[0];
d1 += 4;
y1_ptr++;
cb_ptr++;
cr_ptr++;
a1_ptr++;
}
}
}
static void
ayuv4444_to_yuva420p (AVPicture * dst,
const AVPicture * src, int width, int height)
{
int wrap, wrap3, width2;
int u1, v1, w;
uint8_t *lum, *cb, *cr, *a;
const uint8_t *p;
lum = dst->data[0];
cb = dst->data[1];
cr = dst->data[2];
a = dst->data[3];
width2 = (width + 1) >> 1;
wrap = dst->linesize[0];
wrap3 = src->linesize[0];
p = src->data[0];
for (; height >= 2; height -= 2) {
for (w = width; w >= 2; w -= 2) {
a[0] = p[0];
lum[0] = p[1];
u1 = p[2];
v1 = p[3];
a[1] = p[4 + 0];
lum[1] = p[4 + 1];
u1 += p[4 + 2];
v1 += p[4 + 3];
p += wrap3;
lum += wrap;
a += wrap;
a[0] = p[0];
lum[0] = p[1];
u1 += p[2];
v1 += p[3];
a[1] = p[4 + 0];
lum[1] = p[4 + 1];
u1 += p[4 + 2];
v1 += p[4 + 3];
cb[0] = u1 >> 2;
cr[0] = v1 >> 2;
cb++;
cr++;
p += -wrap3 + 2 * 4;
lum += -wrap + 2;
a += -wrap + 2;
}
if (w) {
a[0] = p[0];
lum[0] = p[1];
u1 = p[2];
v1 = p[3];
p += wrap3;
lum += wrap;
a += wrap;
a[0] = p[0];
lum[0] = p[1];
u1 += p[2];
v1 += p[3];
cb[0] = u1 >> 1;
cr[0] = v1 >> 1;
cb++;
cr++;
p += -wrap3 + 4;
lum += -wrap + 1;
a += -wrap + 1;
}
p += wrap3 + (wrap3 - width * 4);
lum += wrap + (wrap - width);
a += wrap + (wrap - width);
cb += dst->linesize[1] - width2;
cr += dst->linesize[2] - width2;
}
/* handle odd height */
if (height) {
for (w = width; w >= 2; w -= 2) {
a[0] = p[0];
lum[0] = p[1];
u1 = p[2];
v1 = p[3];
a[1] = p[4 + 0];
lum[1] = p[4 + 1];
u1 += p[4 + 2];
v1 += p[4 + 3];
cb[0] = u1 >> 1;
cr[0] = v1 >> 1;
cb++;
cr++;
p += 2 * 4;
lum += 2;
a += 2;
}
if (w) {
a[0] = p[0];
lum[0] = p[1];
cb[0] = p[2];
cr[0] = p[3];
}
}
}
typedef struct ConvertEntry
{
enum PixelFormat src;
enum PixelFormat dest;
void (*convert) (AVPicture * dst,
const AVPicture * src, int width, int height);
} ConvertEntry;
/* Add each new convertion function in this table. In order to be able
to convert from any format to any format, the following constraints
must be satisfied:
- all FF_COLOR_RGB formats must convert to and from PIX_FMT_RGB24
- all FF_COLOR_GRAY formats must convert to and from PIX_FMT_GRAY8
- all FF_COLOR_RGB formats with alpha must convert to and from PIX_FMT_RGBA32
- PIX_FMT_YUV444P and PIX_FMT_YUVJ444P must convert to and from
PIX_FMT_RGB24.
- PIX_FMT_422 must convert to and from PIX_FMT_422P.
The other conversion functions are just optimisations for common cases.
*/
static ConvertEntry convert_table[] = {
{PIX_FMT_YUV420P, PIX_FMT_YUV422, yuv420p_to_yuv422},
{PIX_FMT_YUV420P, PIX_FMT_RGB555, yuv420p_to_rgb555},
{PIX_FMT_YUV420P, PIX_FMT_RGB565, yuv420p_to_rgb565},
{PIX_FMT_YUV420P, PIX_FMT_BGR24, yuv420p_to_bgr24},
{PIX_FMT_YUV420P, PIX_FMT_RGB24, yuv420p_to_rgb24},
{PIX_FMT_YUV420P, PIX_FMT_RGB32, yuv420p_to_rgb32},
{PIX_FMT_YUV420P, PIX_FMT_BGR32, yuv420p_to_bgr32},
{PIX_FMT_YUV420P, PIX_FMT_xRGB32, yuv420p_to_xrgb32},
{PIX_FMT_YUV420P, PIX_FMT_BGRx32, yuv420p_to_bgrx32},
{PIX_FMT_YUV420P, PIX_FMT_RGBA32, yuv420p_to_rgba32},
{PIX_FMT_YUV420P, PIX_FMT_BGRA32, yuv420p_to_bgra32},
{PIX_FMT_YUV420P, PIX_FMT_ARGB32, yuv420p_to_argb32},
{PIX_FMT_YUV420P, PIX_FMT_ABGR32, yuv420p_to_abgr32},
{PIX_FMT_NV12, PIX_FMT_RGB555, nv12_to_rgb555},
{PIX_FMT_NV12, PIX_FMT_RGB565, nv12_to_rgb565},
{PIX_FMT_NV12, PIX_FMT_BGR24, nv12_to_bgr24},
{PIX_FMT_NV12, PIX_FMT_RGB24, nv12_to_rgb24},
{PIX_FMT_NV12, PIX_FMT_RGB32, nv12_to_rgb32},
{PIX_FMT_NV12, PIX_FMT_BGR32, nv12_to_bgr32},
{PIX_FMT_NV12, PIX_FMT_xRGB32, nv12_to_xrgb32},
{PIX_FMT_NV12, PIX_FMT_BGRx32, nv12_to_bgrx32},
{PIX_FMT_NV12, PIX_FMT_RGBA32, nv12_to_rgba32},
{PIX_FMT_NV12, PIX_FMT_BGRA32, nv12_to_bgra32},
{PIX_FMT_NV12, PIX_FMT_ARGB32, nv12_to_argb32},
{PIX_FMT_NV12, PIX_FMT_ABGR32, nv12_to_abgr32},
{PIX_FMT_NV12, PIX_FMT_NV21, nv12_to_nv21},
{PIX_FMT_NV12, PIX_FMT_YUV444P, nv12_to_yuv444p},
{PIX_FMT_NV21, PIX_FMT_RGB555, nv21_to_rgb555},
{PIX_FMT_NV21, PIX_FMT_RGB565, nv21_to_rgb565},
{PIX_FMT_NV21, PIX_FMT_BGR24, nv21_to_bgr24},
{PIX_FMT_NV21, PIX_FMT_RGB24, nv21_to_rgb24},
{PIX_FMT_NV21, PIX_FMT_RGB32, nv21_to_rgb32},
{PIX_FMT_NV21, PIX_FMT_BGR32, nv21_to_bgr32},
{PIX_FMT_NV21, PIX_FMT_xRGB32, nv21_to_xrgb32},
{PIX_FMT_NV21, PIX_FMT_BGRx32, nv21_to_bgrx32},
{PIX_FMT_NV21, PIX_FMT_RGBA32, nv21_to_rgba32},
{PIX_FMT_NV21, PIX_FMT_BGRA32, nv21_to_bgra32},
{PIX_FMT_NV21, PIX_FMT_ARGB32, nv21_to_argb32},
{PIX_FMT_NV21, PIX_FMT_ABGR32, nv21_to_abgr32},
{PIX_FMT_NV21, PIX_FMT_YUV444P, nv21_to_yuv444p},
{PIX_FMT_NV21, PIX_FMT_NV12, nv21_to_nv12},
{PIX_FMT_YUV422P, PIX_FMT_YUV422, yuv422p_to_yuv422},
{PIX_FMT_YUV422P, PIX_FMT_UYVY422, yuv422p_to_uyvy422},
{PIX_FMT_YUV422P, PIX_FMT_YVYU422, yuv422p_to_yvyu422},
{PIX_FMT_YUV444P, PIX_FMT_RGB24, yuv444p_to_rgb24},
{PIX_FMT_YUVJ420P, PIX_FMT_RGB555, yuvj420p_to_rgb555},
{PIX_FMT_YUVJ420P, PIX_FMT_RGB565, yuvj420p_to_rgb565},
{PIX_FMT_YUVJ420P, PIX_FMT_BGR24, yuvj420p_to_bgr24},
{PIX_FMT_YUVJ420P, PIX_FMT_RGB24, yuvj420p_to_rgb24},
{PIX_FMT_YUVJ420P, PIX_FMT_RGB32, yuvj420p_to_rgb32},
{PIX_FMT_YUVJ420P, PIX_FMT_BGR32, yuvj420p_to_bgr32},
{PIX_FMT_YUVJ420P, PIX_FMT_RGB32, yuvj420p_to_xrgb32},
{PIX_FMT_YUVJ420P, PIX_FMT_BGR32, yuvj420p_to_bgrx32},
{PIX_FMT_YUVJ420P, PIX_FMT_RGBA32, yuvj420p_to_rgba32},
{PIX_FMT_YUVJ420P, PIX_FMT_BGRA32, yuvj420p_to_bgra32},
{PIX_FMT_YUVJ420P, PIX_FMT_ARGB32, yuvj420p_to_argb32},
{PIX_FMT_YUVJ420P, PIX_FMT_ABGR32, yuvj420p_to_abgr32},
{PIX_FMT_YUVJ444P, PIX_FMT_RGB24, yuvj444p_to_rgb24},
{PIX_FMT_YUV422, PIX_FMT_YUV420P, yuv422_to_yuv420p},
{PIX_FMT_YUV422, PIX_FMT_YUV422P, yuv422_to_yuv422p},
{PIX_FMT_YUV422, PIX_FMT_GRAY8, yvyu422_to_gray},
{PIX_FMT_YUV422, PIX_FMT_RGB555, yuv422_to_rgb555},
{PIX_FMT_YUV422, PIX_FMT_RGB565, yuv422_to_rgb565},
{PIX_FMT_YUV422, PIX_FMT_BGR24, yuv422_to_bgr24},
{PIX_FMT_YUV422, PIX_FMT_RGB24, yuv422_to_rgb24},
{PIX_FMT_YUV422, PIX_FMT_BGR32, yuv422_to_bgr32},
{PIX_FMT_YUV422, PIX_FMT_RGB32, yuv422_to_rgb32},
{PIX_FMT_YUV422, PIX_FMT_xRGB32, yuv422_to_xrgb32},
{PIX_FMT_YUV422, PIX_FMT_BGRx32, yuv422_to_bgrx32},
{PIX_FMT_YUV422, PIX_FMT_BGRA32, yuv422_to_bgra32},
{PIX_FMT_YUV422, PIX_FMT_RGBA32, yuv422_to_rgba32},
{PIX_FMT_YUV422, PIX_FMT_ABGR32, yuv422_to_abgr32},
{PIX_FMT_YUV422, PIX_FMT_ARGB32, yuv422_to_argb32},
{PIX_FMT_UYVY422, PIX_FMT_YUV420P, uyvy422_to_yuv420p},
{PIX_FMT_UYVY422, PIX_FMT_YUV422P, uyvy422_to_yuv422p},
{PIX_FMT_UYVY422, PIX_FMT_GRAY8, uyvy422_to_gray},
{PIX_FMT_UYVY422, PIX_FMT_RGB555, uyvy422_to_rgb555},
{PIX_FMT_UYVY422, PIX_FMT_RGB565, uyvy422_to_rgb565},
{PIX_FMT_UYVY422, PIX_FMT_BGR24, uyvy422_to_bgr24},
{PIX_FMT_UYVY422, PIX_FMT_RGB24, uyvy422_to_rgb24},
{PIX_FMT_UYVY422, PIX_FMT_RGB32, uyvy422_to_rgb32},
{PIX_FMT_UYVY422, PIX_FMT_BGR32, uyvy422_to_bgr32},
{PIX_FMT_UYVY422, PIX_FMT_xRGB32, uyvy422_to_xrgb32},
{PIX_FMT_UYVY422, PIX_FMT_BGRx32, uyvy422_to_bgrx32},
{PIX_FMT_UYVY422, PIX_FMT_RGBA32, uyvy422_to_rgba32},
{PIX_FMT_UYVY422, PIX_FMT_BGRA32, uyvy422_to_bgra32},
{PIX_FMT_UYVY422, PIX_FMT_ARGB32, uyvy422_to_argb32},
{PIX_FMT_UYVY422, PIX_FMT_ABGR32, uyvy422_to_abgr32},
{PIX_FMT_YVYU422, PIX_FMT_YUV420P, yvyu422_to_yuv420p},
{PIX_FMT_YVYU422, PIX_FMT_YUV422P, yvyu422_to_yuv422p},
{PIX_FMT_YVYU422, PIX_FMT_GRAY8, yvyu422_to_gray},
{PIX_FMT_YVYU422, PIX_FMT_RGB555, yvyu422_to_rgb555},
{PIX_FMT_YVYU422, PIX_FMT_RGB565, yvyu422_to_rgb565},
{PIX_FMT_YVYU422, PIX_FMT_BGR24, yvyu422_to_bgr24},
{PIX_FMT_YVYU422, PIX_FMT_RGB24, yvyu422_to_rgb24},
{PIX_FMT_YVYU422, PIX_FMT_BGR32, yvyu422_to_bgr32},
{PIX_FMT_YVYU422, PIX_FMT_RGB32, yvyu422_to_rgb32},
{PIX_FMT_YVYU422, PIX_FMT_xRGB32, yvyu422_to_xrgb32},
{PIX_FMT_YVYU422, PIX_FMT_BGRx32, yvyu422_to_bgrx32},
{PIX_FMT_YVYU422, PIX_FMT_BGRA32, yvyu422_to_bgra32},
{PIX_FMT_YVYU422, PIX_FMT_RGBA32, yvyu422_to_rgba32},
{PIX_FMT_YVYU422, PIX_FMT_ABGR32, yvyu422_to_abgr32},
{PIX_FMT_YVYU422, PIX_FMT_ARGB32, yvyu422_to_argb32},
{PIX_FMT_RGB24, PIX_FMT_YUV420P, rgb24_to_yuv420p},
{PIX_FMT_RGB24, PIX_FMT_YUVA420P, rgb24_to_yuva420p},
{PIX_FMT_RGB24, PIX_FMT_NV12, rgb24_to_nv12},
{PIX_FMT_RGB24, PIX_FMT_NV21, rgb24_to_nv21},
{PIX_FMT_RGB24, PIX_FMT_RGB565, rgb24_to_rgb565},
{PIX_FMT_RGB24, PIX_FMT_RGB555, rgb24_to_rgb555},
{PIX_FMT_RGB24, PIX_FMT_RGB32, rgb24_to_rgb32},
{PIX_FMT_RGB24, PIX_FMT_BGR32, rgb24_to_bgr32},
{PIX_FMT_RGB24, PIX_FMT_xRGB32, rgb24_to_xrgb32},
{PIX_FMT_RGB24, PIX_FMT_BGRx32, rgb24_to_bgrx32},
{PIX_FMT_RGB24, PIX_FMT_RGBA32, rgb24_to_rgba32},
{PIX_FMT_RGB24, PIX_FMT_BGR24, rgb24_to_bgr24},
{PIX_FMT_RGB24, PIX_FMT_BGRA32, rgb24_to_bgra32},
{PIX_FMT_RGB24, PIX_FMT_ARGB32, rgb24_to_argb32},
{PIX_FMT_RGB24, PIX_FMT_ABGR32, rgb24_to_abgr32},
{PIX_FMT_RGB24, PIX_FMT_Y800, rgb24_to_y800},
{PIX_FMT_RGB24, PIX_FMT_Y16, rgb24_to_y16},
{PIX_FMT_RGB24, PIX_FMT_GRAY8, rgb24_to_gray},
{PIX_FMT_RGB24, PIX_FMT_GRAY16_L, rgb24_to_gray16_l},
{PIX_FMT_RGB24, PIX_FMT_GRAY16_B, rgb24_to_gray16_b},
{PIX_FMT_RGB24, PIX_FMT_PAL8, rgb24_to_pal8},
{PIX_FMT_RGB24, PIX_FMT_YUV444P, rgb24_to_yuv444p},
{PIX_FMT_RGB24, PIX_FMT_YUVJ420P, rgb24_to_yuvj420p},
{PIX_FMT_RGB24, PIX_FMT_YUVJ444P, rgb24_to_yuvj444p},
{PIX_FMT_RGB24, PIX_FMT_AYUV4444, rgb24_to_ayuv4444},
{PIX_FMT_RGB24, PIX_FMT_V308, rgb24_to_v308},
{PIX_FMT_RGB32, PIX_FMT_RGB24, rgb32_to_rgb24},
{PIX_FMT_RGB32, PIX_FMT_RGB555, rgba32_to_rgb555},
{PIX_FMT_RGB32, PIX_FMT_PAL8, rgb32_to_pal8},
{PIX_FMT_RGB32, PIX_FMT_YUV420P, rgb32_to_yuv420p},
{PIX_FMT_RGB32, PIX_FMT_YUVA420P, rgb32_to_yuva420p},
{PIX_FMT_RGB32, PIX_FMT_NV12, rgb32_to_nv12},
{PIX_FMT_RGB32, PIX_FMT_NV21, rgb32_to_nv21},
{PIX_FMT_RGB32, PIX_FMT_Y800, rgb32_to_y800},
{PIX_FMT_RGB32, PIX_FMT_Y16, rgb32_to_y16},
{PIX_FMT_RGB32, PIX_FMT_GRAY8, rgb32_to_gray},
{PIX_FMT_RGB32, PIX_FMT_GRAY16_L, rgb32_to_gray16_l},
{PIX_FMT_RGB32, PIX_FMT_GRAY16_B, rgb32_to_gray16_b},
{PIX_FMT_xRGB32, PIX_FMT_RGB24, xrgb32_to_rgb24},
{PIX_FMT_xRGB32, PIX_FMT_PAL8, xrgb32_to_pal8},
{PIX_FMT_xRGB32, PIX_FMT_YUV420P, xrgb32_to_yuv420p},
{PIX_FMT_xRGB32, PIX_FMT_YUVA420P, xrgb32_to_yuva420p},
{PIX_FMT_xRGB32, PIX_FMT_NV12, xrgb32_to_nv12},
{PIX_FMT_xRGB32, PIX_FMT_NV21, xrgb32_to_nv21},
{PIX_FMT_xRGB32, PIX_FMT_Y800, xrgb32_to_y800},
{PIX_FMT_xRGB32, PIX_FMT_Y16, xrgb32_to_y16},
{PIX_FMT_xRGB32, PIX_FMT_GRAY8, xrgb32_to_gray},
{PIX_FMT_xRGB32, PIX_FMT_GRAY16_L, xrgb32_to_gray16_l},
{PIX_FMT_xRGB32, PIX_FMT_GRAY16_B, xrgb32_to_gray16_b},
{PIX_FMT_RGBA32, PIX_FMT_BGRA32, rgba32_to_bgra32},
{PIX_FMT_RGBA32, PIX_FMT_ABGR32, rgba32_to_abgr32},
{PIX_FMT_RGBA32, PIX_FMT_ARGB32, rgba32_to_argb32},
{PIX_FMT_RGBA32, PIX_FMT_BGR32, rgba32_to_bgr32},
{PIX_FMT_RGBA32, PIX_FMT_BGRx32, rgba32_to_bgrx32},
{PIX_FMT_RGBA32, PIX_FMT_ABGR32, rgba32_to_abgr32},
{PIX_FMT_RGBA32, PIX_FMT_RGB24, rgba32_to_rgb24},
{PIX_FMT_RGBA32, PIX_FMT_RGB555, rgba32_to_rgb555},
{PIX_FMT_RGBA32, PIX_FMT_PAL8, rgba32_to_pal8},
{PIX_FMT_RGBA32, PIX_FMT_YUV420P, rgba32_to_yuv420p},
{PIX_FMT_RGBA32, PIX_FMT_YUVA420P, rgba32_to_yuva420p},
{PIX_FMT_RGBA32, PIX_FMT_NV12, rgba32_to_nv12},
{PIX_FMT_RGBA32, PIX_FMT_NV21, rgba32_to_nv21},
{PIX_FMT_RGBA32, PIX_FMT_Y800, rgba32_to_y800},
{PIX_FMT_RGBA32, PIX_FMT_Y16, rgba32_to_y16},
{PIX_FMT_RGBA32, PIX_FMT_GRAY8, rgba32_to_gray},
{PIX_FMT_RGBA32, PIX_FMT_GRAY16_L, rgba32_to_gray16_l},
{PIX_FMT_RGBA32, PIX_FMT_GRAY16_B, rgba32_to_gray16_b},
{PIX_FMT_RGBA32, PIX_FMT_AYUV4444, rgba32_to_ayuv4444},
{PIX_FMT_BGR24, PIX_FMT_RGB24, bgr24_to_rgb24},
{PIX_FMT_BGR24, PIX_FMT_YUV420P, bgr24_to_yuv420p},
{PIX_FMT_BGR24, PIX_FMT_YUVA420P, bgr24_to_yuva420p},
{PIX_FMT_BGR24, PIX_FMT_NV12, bgr24_to_nv12},
{PIX_FMT_BGR24, PIX_FMT_NV21, bgr24_to_nv21},
{PIX_FMT_BGR24, PIX_FMT_Y800, bgr24_to_y800},
{PIX_FMT_BGR24, PIX_FMT_Y16, bgr24_to_y16},
{PIX_FMT_BGR24, PIX_FMT_GRAY8, bgr24_to_gray},
{PIX_FMT_BGR24, PIX_FMT_GRAY16_L, bgr24_to_gray16_l},
{PIX_FMT_BGR24, PIX_FMT_GRAY16_B, bgr24_to_gray16_b},
{PIX_FMT_BGR32, PIX_FMT_RGB24, bgr32_to_rgb24},
{PIX_FMT_BGR32, PIX_FMT_RGBA32, bgr32_to_rgba32},
{PIX_FMT_BGR32, PIX_FMT_YUV420P, bgr32_to_yuv420p},
{PIX_FMT_BGR32, PIX_FMT_YUVA420P, bgr32_to_yuva420p},
{PIX_FMT_BGR32, PIX_FMT_NV12, bgr32_to_nv12},
{PIX_FMT_BGR32, PIX_FMT_NV21, bgr32_to_nv21},
{PIX_FMT_BGR32, PIX_FMT_Y800, bgr32_to_y800},
{PIX_FMT_BGR32, PIX_FMT_Y16, bgr32_to_y16},
{PIX_FMT_BGR32, PIX_FMT_GRAY8, bgr32_to_gray},
{PIX_FMT_BGR32, PIX_FMT_GRAY16_L, bgr32_to_gray16_l},
{PIX_FMT_BGR32, PIX_FMT_GRAY16_B, bgr32_to_gray16_b},
{PIX_FMT_BGRx32, PIX_FMT_RGB24, bgrx32_to_rgb24},
{PIX_FMT_BGRx32, PIX_FMT_RGBA32, bgrx32_to_rgba32},
{PIX_FMT_BGRx32, PIX_FMT_YUV420P, bgrx32_to_yuv420p},
{PIX_FMT_BGRx32, PIX_FMT_YUVA420P, bgrx32_to_yuva420p},
{PIX_FMT_BGRx32, PIX_FMT_NV12, bgrx32_to_nv12},
{PIX_FMT_BGRx32, PIX_FMT_NV21, bgrx32_to_nv21},
{PIX_FMT_BGRx32, PIX_FMT_Y800, bgrx32_to_y800},
{PIX_FMT_BGRx32, PIX_FMT_Y16, bgrx32_to_y16},
{PIX_FMT_BGRx32, PIX_FMT_GRAY8, bgrx32_to_gray},
{PIX_FMT_BGRx32, PIX_FMT_GRAY16_L, bgrx32_to_gray16_l},
{PIX_FMT_BGRx32, PIX_FMT_GRAY16_B, bgrx32_to_gray16_b},
{PIX_FMT_BGRA32, PIX_FMT_RGB24, bgra32_to_rgb24},
{PIX_FMT_BGRA32, PIX_FMT_RGBA32, bgra32_to_rgba32},
{PIX_FMT_BGRA32, PIX_FMT_YUV420P, bgra32_to_yuv420p},
{PIX_FMT_BGRA32, PIX_FMT_YUVA420P, bgra32_to_yuva420p},
{PIX_FMT_BGRA32, PIX_FMT_NV12, bgra32_to_nv12},
{PIX_FMT_BGRA32, PIX_FMT_NV21, bgra32_to_nv21},
{PIX_FMT_BGRA32, PIX_FMT_Y800, bgra32_to_y800},
{PIX_FMT_BGRA32, PIX_FMT_Y16, bgra32_to_y16},
{PIX_FMT_BGRA32, PIX_FMT_GRAY8, bgra32_to_gray},
{PIX_FMT_BGRA32, PIX_FMT_GRAY16_L, bgra32_to_gray16_l},
{PIX_FMT_BGRA32, PIX_FMT_GRAY16_B, bgra32_to_gray16_b},
{PIX_FMT_BGRA32, PIX_FMT_AYUV4444, bgra32_to_ayuv4444},
{PIX_FMT_ABGR32, PIX_FMT_RGB24, abgr32_to_rgb24},
{PIX_FMT_ABGR32, PIX_FMT_RGBA32, abgr32_to_rgba32},
{PIX_FMT_ABGR32, PIX_FMT_YUV420P, abgr32_to_yuv420p},
{PIX_FMT_ABGR32, PIX_FMT_YUVA420P, abgr32_to_yuva420p},
{PIX_FMT_ABGR32, PIX_FMT_NV12, abgr32_to_nv12},
{PIX_FMT_ABGR32, PIX_FMT_NV21, abgr32_to_nv21},
{PIX_FMT_ABGR32, PIX_FMT_Y800, abgr32_to_y800},
{PIX_FMT_ABGR32, PIX_FMT_Y16, abgr32_to_y16},
{PIX_FMT_ABGR32, PIX_FMT_GRAY8, abgr32_to_gray},
{PIX_FMT_ABGR32, PIX_FMT_GRAY16_L, abgr32_to_gray16_l},
{PIX_FMT_ABGR32, PIX_FMT_GRAY16_B, abgr32_to_gray16_b},
{PIX_FMT_ABGR32, PIX_FMT_AYUV4444, abgr32_to_ayuv4444},
{PIX_FMT_ARGB32, PIX_FMT_RGB24, argb32_to_rgb24},
{PIX_FMT_ARGB32, PIX_FMT_RGBA32, argb32_to_rgba32},
{PIX_FMT_ARGB32, PIX_FMT_YUV420P, argb32_to_yuv420p},
{PIX_FMT_ARGB32, PIX_FMT_YUVA420P, argb32_to_yuva420p},
{PIX_FMT_ARGB32, PIX_FMT_NV12, argb32_to_nv12},
{PIX_FMT_ARGB32, PIX_FMT_NV21, argb32_to_nv21},
{PIX_FMT_ARGB32, PIX_FMT_Y800, argb32_to_y800},
{PIX_FMT_ARGB32, PIX_FMT_Y16, argb32_to_y16},
{PIX_FMT_ARGB32, PIX_FMT_GRAY8, argb32_to_gray},
{PIX_FMT_ARGB32, PIX_FMT_GRAY16_L, argb32_to_gray16_l},
{PIX_FMT_ARGB32, PIX_FMT_GRAY16_B, argb32_to_gray16_b},
{PIX_FMT_ARGB32, PIX_FMT_AYUV4444, argb32_to_ayuv4444},
{PIX_FMT_RGB555, PIX_FMT_RGB24, rgb555_to_rgb24},
{PIX_FMT_RGB555, PIX_FMT_RGB32, rgb555_to_rgba32},
{PIX_FMT_RGB555, PIX_FMT_RGBA32, rgb555_to_rgba32},
{PIX_FMT_RGB555, PIX_FMT_YUV420P, rgb555_to_yuv420p},
{PIX_FMT_RGB555, PIX_FMT_YUVA420P, rgb555_to_yuva420p},
{PIX_FMT_RGB555, PIX_FMT_NV12, rgb555_to_nv12},
{PIX_FMT_RGB555, PIX_FMT_NV21, rgb555_to_nv21},
{PIX_FMT_RGB555, PIX_FMT_Y800, rgb555_to_y800},
{PIX_FMT_RGB555, PIX_FMT_Y16, rgb555_to_y16},
{PIX_FMT_RGB555, PIX_FMT_GRAY8, rgb555_to_gray},
{PIX_FMT_RGB555, PIX_FMT_GRAY16_L, rgb555_to_gray16_l},
{PIX_FMT_RGB555, PIX_FMT_GRAY16_B, rgb555_to_gray16_b},
{PIX_FMT_RGB565, PIX_FMT_RGB24, rgb565_to_rgb24},
{PIX_FMT_RGB565, PIX_FMT_YUV420P, rgb565_to_yuv420p},
{PIX_FMT_RGB565, PIX_FMT_YUVA420P, rgb565_to_yuva420p},
{PIX_FMT_RGB565, PIX_FMT_NV12, rgb565_to_nv12},
{PIX_FMT_RGB565, PIX_FMT_NV21, rgb565_to_nv21},
{PIX_FMT_RGB565, PIX_FMT_Y800, rgb565_to_y800},
{PIX_FMT_RGB565, PIX_FMT_Y16, rgb565_to_y16},
{PIX_FMT_RGB565, PIX_FMT_GRAY8, rgb565_to_gray},
{PIX_FMT_RGB565, PIX_FMT_GRAY16_L, rgb565_to_gray16_l},
{PIX_FMT_RGB565, PIX_FMT_GRAY16_B, rgb565_to_gray16_b},
{PIX_FMT_Y800, PIX_FMT_RGB555, y800_to_rgb555},
{PIX_FMT_Y800, PIX_FMT_RGB565, y800_to_rgb565},
{PIX_FMT_Y800, PIX_FMT_BGR24, y800_to_bgr24},
{PIX_FMT_Y800, PIX_FMT_RGB24, y800_to_rgb24},
{PIX_FMT_Y800, PIX_FMT_RGB32, y800_to_rgb32},
{PIX_FMT_Y800, PIX_FMT_BGR32, y800_to_bgr32},
{PIX_FMT_Y800, PIX_FMT_RGB32, y800_to_xrgb32},
{PIX_FMT_Y800, PIX_FMT_BGR32, y800_to_bgrx32},
{PIX_FMT_Y800, PIX_FMT_RGBA32, y800_to_rgba32},
{PIX_FMT_Y800, PIX_FMT_BGRA32, y800_to_bgra32},
{PIX_FMT_Y800, PIX_FMT_ARGB32, y800_to_argb32},
{PIX_FMT_Y800, PIX_FMT_ABGR32, y800_to_abgr32},
{PIX_FMT_Y800, PIX_FMT_Y16, y800_to_y16},
{PIX_FMT_Y16, PIX_FMT_RGB555, y16_to_rgb555},
{PIX_FMT_Y16, PIX_FMT_RGB565, y16_to_rgb565},
{PIX_FMT_Y16, PIX_FMT_BGR24, y16_to_bgr24},
{PIX_FMT_Y16, PIX_FMT_RGB24, y16_to_rgb24},
{PIX_FMT_Y16, PIX_FMT_RGB32, y16_to_rgb32},
{PIX_FMT_Y16, PIX_FMT_BGR32, y16_to_bgr32},
{PIX_FMT_Y16, PIX_FMT_RGB32, y16_to_xrgb32},
{PIX_FMT_Y16, PIX_FMT_BGR32, y16_to_bgrx32},
{PIX_FMT_Y16, PIX_FMT_RGBA32, y16_to_rgba32},
{PIX_FMT_Y16, PIX_FMT_BGRA32, y16_to_bgra32},
{PIX_FMT_Y16, PIX_FMT_ARGB32, y16_to_argb32},
{PIX_FMT_Y16, PIX_FMT_ABGR32, y16_to_abgr32},
{PIX_FMT_Y16, PIX_FMT_Y800, y16_to_y800},
{PIX_FMT_GRAY8, PIX_FMT_RGB555, gray_to_rgb555},
{PIX_FMT_GRAY8, PIX_FMT_RGB565, gray_to_rgb565},
{PIX_FMT_GRAY8, PIX_FMT_RGB24, gray_to_rgb24},
{PIX_FMT_GRAY8, PIX_FMT_BGR24, gray_to_bgr24},
{PIX_FMT_GRAY8, PIX_FMT_RGB32, gray_to_rgb32},
{PIX_FMT_GRAY8, PIX_FMT_BGR32, gray_to_bgr32},
{PIX_FMT_GRAY8, PIX_FMT_xRGB32, gray_to_xrgb32},
{PIX_FMT_GRAY8, PIX_FMT_BGRx32, gray_to_bgrx32},
{PIX_FMT_GRAY8, PIX_FMT_RGBA32, gray_to_rgba32},
{PIX_FMT_GRAY8, PIX_FMT_BGRA32, gray_to_bgra32},
{PIX_FMT_GRAY8, PIX_FMT_ARGB32, gray_to_argb32},
{PIX_FMT_GRAY8, PIX_FMT_ABGR32, gray_to_abgr32},
{PIX_FMT_GRAY8, PIX_FMT_MONOWHITE, gray_to_monowhite},
{PIX_FMT_GRAY8, PIX_FMT_MONOBLACK, gray_to_monoblack},
{PIX_FMT_GRAY8, PIX_FMT_GRAY16_L, gray_to_gray16_l},
{PIX_FMT_GRAY8, PIX_FMT_GRAY16_B, gray_to_gray16_b},
{PIX_FMT_MONOWHITE, PIX_FMT_GRAY8, monowhite_to_gray},
{PIX_FMT_MONOBLACK, PIX_FMT_GRAY8, monoblack_to_gray},
{PIX_FMT_GRAY16_L, PIX_FMT_GRAY8, gray16_l_to_gray},
{PIX_FMT_GRAY16_L, PIX_FMT_RGB555, gray16_l_to_rgb555},
{PIX_FMT_GRAY16_L, PIX_FMT_RGB565, gray16_l_to_rgb565},
{PIX_FMT_GRAY16_L, PIX_FMT_BGR24, gray16_l_to_bgr24},
{PIX_FMT_GRAY16_L, PIX_FMT_RGB24, gray16_l_to_rgb24},
{PIX_FMT_GRAY16_L, PIX_FMT_BGR32, gray16_l_to_bgr32},
{PIX_FMT_GRAY16_L, PIX_FMT_RGB32, gray16_l_to_rgb32},
{PIX_FMT_GRAY16_L, PIX_FMT_xRGB32, gray16_l_to_xrgb32},
{PIX_FMT_GRAY16_L, PIX_FMT_BGRx32, gray16_l_to_bgrx32},
{PIX_FMT_GRAY16_L, PIX_FMT_ABGR32, gray16_l_to_abgr32},
{PIX_FMT_GRAY16_L, PIX_FMT_ARGB32, gray16_l_to_argb32},
{PIX_FMT_GRAY16_L, PIX_FMT_BGRA32, gray16_l_to_bgra32},
{PIX_FMT_GRAY16_L, PIX_FMT_RGBA32, gray16_l_to_rgba32},
{PIX_FMT_GRAY16_L, PIX_FMT_GRAY16_B, gray16_b_to_gray16_l},
{PIX_FMT_GRAY16_B, PIX_FMT_GRAY8, gray16_b_to_gray},
{PIX_FMT_GRAY16_B, PIX_FMT_RGB555, gray16_b_to_rgb555},
{PIX_FMT_GRAY16_B, PIX_FMT_RGB565, gray16_b_to_rgb565},
{PIX_FMT_GRAY16_B, PIX_FMT_BGR24, gray16_b_to_bgr24},
{PIX_FMT_GRAY16_B, PIX_FMT_RGB24, gray16_b_to_rgb24},
{PIX_FMT_GRAY16_B, PIX_FMT_BGR32, gray16_b_to_bgr32},
{PIX_FMT_GRAY16_B, PIX_FMT_RGB32, gray16_b_to_rgb32},
{PIX_FMT_GRAY16_B, PIX_FMT_xRGB32, gray16_b_to_xrgb32},
{PIX_FMT_GRAY16_B, PIX_FMT_BGRx32, gray16_b_to_bgrx32},
{PIX_FMT_GRAY16_B, PIX_FMT_ABGR32, gray16_b_to_abgr32},
{PIX_FMT_GRAY16_B, PIX_FMT_ARGB32, gray16_b_to_argb32},
{PIX_FMT_GRAY16_B, PIX_FMT_BGRA32, gray16_b_to_bgra32},
{PIX_FMT_GRAY16_B, PIX_FMT_RGBA32, gray16_b_to_rgba32},
{PIX_FMT_GRAY16_B, PIX_FMT_GRAY16_L, gray16_b_to_gray16_l},
{PIX_FMT_PAL8, PIX_FMT_RGB555, pal8_to_rgb555},
{PIX_FMT_PAL8, PIX_FMT_RGB565, pal8_to_rgb565},
{PIX_FMT_PAL8, PIX_FMT_BGR24, pal8_to_bgr24},
{PIX_FMT_PAL8, PIX_FMT_RGB24, pal8_to_rgb24},
{PIX_FMT_PAL8, PIX_FMT_RGB32, pal8_to_rgb32},
{PIX_FMT_PAL8, PIX_FMT_BGR32, pal8_to_bgr32},
{PIX_FMT_PAL8, PIX_FMT_xRGB32, pal8_to_xrgb32},
{PIX_FMT_PAL8, PIX_FMT_BGRx32, pal8_to_bgrx32},
{PIX_FMT_PAL8, PIX_FMT_RGBA32, pal8_to_rgba32},
{PIX_FMT_PAL8, PIX_FMT_BGRA32, pal8_to_bgra32},
{PIX_FMT_PAL8, PIX_FMT_ARGB32, pal8_to_argb32},
{PIX_FMT_PAL8, PIX_FMT_ABGR32, pal8_to_abgr32},
{PIX_FMT_UYVY411, PIX_FMT_YUV411P, uyvy411_to_yuv411p},
{PIX_FMT_YUV411P, PIX_FMT_UYVY411, yuv411p_to_uyvy411},
{PIX_FMT_V308, PIX_FMT_RGB24, v308_to_rgb24},
{PIX_FMT_AYUV4444, PIX_FMT_RGBA32, ayuv4444_to_rgba32},
{PIX_FMT_AYUV4444, PIX_FMT_ARGB32, ayuv4444_to_argb32},
{PIX_FMT_AYUV4444, PIX_FMT_BGRA32, ayuv4444_to_bgra32},
{PIX_FMT_AYUV4444, PIX_FMT_ABGR32, ayuv4444_to_abgr32},
{PIX_FMT_AYUV4444, PIX_FMT_RGB24, ayuv4444_to_rgb24},
{PIX_FMT_AYUV4444, PIX_FMT_YUVA420P, ayuv4444_to_yuva420p},
{PIX_FMT_YUVA420P, PIX_FMT_YUV420P, yuva420p_to_yuv420p},
{PIX_FMT_YUVA420P, PIX_FMT_YUV422, yuva420p_to_yuv422},
{PIX_FMT_YUVA420P, PIX_FMT_AYUV4444, yuva420p_to_ayuv4444},
{PIX_FMT_YUVA420P, PIX_FMT_RGB555, yuva420p_to_rgb555},
{PIX_FMT_YUVA420P, PIX_FMT_RGB565, yuva420p_to_rgb565},
{PIX_FMT_YUVA420P, PIX_FMT_BGR24, yuva420p_to_bgr24},
{PIX_FMT_YUVA420P, PIX_FMT_RGB24, yuva420p_to_rgb24},
{PIX_FMT_YUVA420P, PIX_FMT_RGB32, yuva420p_to_rgb32},
{PIX_FMT_YUVA420P, PIX_FMT_BGR32, yuva420p_to_bgr32},
{PIX_FMT_YUVA420P, PIX_FMT_xRGB32, yuva420p_to_xrgb32},
{PIX_FMT_YUVA420P, PIX_FMT_BGRx32, yuva420p_to_bgrx32},
{PIX_FMT_YUVA420P, PIX_FMT_RGBA32, yuva420p_to_rgba32},
{PIX_FMT_YUVA420P, PIX_FMT_BGRA32, yuva420p_to_bgra32},
{PIX_FMT_YUVA420P, PIX_FMT_ARGB32, yuva420p_to_argb32},
{PIX_FMT_YUVA420P, PIX_FMT_ABGR32, yuva420p_to_abgr32},
};
static ConvertEntry *
get_convert_table_entry (int src_pix_fmt, int dst_pix_fmt)
{
int i;
for (i = 0; i < sizeof (convert_table) / sizeof (convert_table[0]); i++) {
if (convert_table[i].src == src_pix_fmt &&
convert_table[i].dest == dst_pix_fmt) {
return convert_table + i;
}
}
return NULL;
}
static int
avpicture_alloc (AVPicture * picture, int pix_fmt, int width, int height,
int interlaced)
{
unsigned int size;
void *ptr;
size = avpicture_get_size (pix_fmt, width, height);
ptr = av_malloc (size);
if (!ptr)
goto fail;
gst_ffmpegcsp_avpicture_fill (picture, ptr, pix_fmt, width, height,
interlaced);
return 0;
fail:
memset (picture, 0, sizeof (AVPicture));
return -1;
}
static void
avpicture_free (AVPicture * picture)
{
av_free (picture->data[0]);
}
/* return true if yuv planar */
static inline int
is_yuv_planar (PixFmtInfo * ps)
{
return (ps->color_type == FF_COLOR_YUV ||
ps->color_type == FF_COLOR_YUV_JPEG) && ps->pixel_type == FF_PIXEL_PLANAR;
}
/* XXX: always use linesize. Return -1 if not supported */
int
img_convert (AVPicture * dst, int dst_pix_fmt,
const AVPicture * src, int src_pix_fmt, int src_width, int src_height)
{
static int inited;
int i, ret, dst_width, dst_height, int_pix_fmt;
PixFmtInfo *src_pix, *dst_pix;
ConvertEntry *ce;
AVPicture tmp1, *tmp = &tmp1;
if (G_UNLIKELY (src_width <= 0 || src_height <= 0))
return 0;
if (G_UNLIKELY (!inited)) {
inited = 1;
img_convert_init ();
}
dst_width = src_width;
dst_height = src_height;
dst_pix = get_pix_fmt_info (dst_pix_fmt);
src_pix = get_pix_fmt_info (src_pix_fmt);
if (G_UNLIKELY (src_pix_fmt == dst_pix_fmt)) {
/* no conversion needed: just copy */
img_copy (dst, src, dst_pix_fmt, dst_width, dst_height);
return 0;
}
ce = get_convert_table_entry (src_pix_fmt, dst_pix_fmt);
if (ce && ce->convert) {
/* specific conversion routine */
ce->convert (dst, src, dst_width, dst_height);
return 0;
}
/* gray to YUV */
if (is_yuv_planar (dst_pix) && dst_pix_fmt != PIX_FMT_Y16
&& src_pix_fmt == PIX_FMT_GRAY8) {
int w, h, y;
uint8_t *d;
if (dst_pix->color_type == FF_COLOR_YUV_JPEG) {
img_copy_plane (dst->data[0], dst->linesize[0],
src->data[0], src->linesize[0], dst_width, dst_height);
} else {
img_apply_table (dst->data[0], dst->linesize[0],
src->data[0], src->linesize[0],
dst_width, dst_height, y_jpeg_to_ccir);
}
/* fill U and V with 128 */
w = dst_width;
h = dst_height;
w >>= dst_pix->x_chroma_shift;
h >>= dst_pix->y_chroma_shift;
for (i = 1; i <= 2; i++) {
d = dst->data[i];
if (!d)
continue;
for (y = 0; y < h; y++) {
memset (d, 128, w);
d += dst->linesize[i];
}
}
return 0;
}
/* YUV to gray */
if (is_yuv_planar (src_pix) && src_pix_fmt != PIX_FMT_Y16
&& dst_pix_fmt == PIX_FMT_GRAY8) {
if (src_pix->color_type == FF_COLOR_YUV_JPEG) {
img_copy_plane (dst->data[0], dst->linesize[0],
src->data[0], src->linesize[0], dst_width, dst_height);
} else {
img_apply_table (dst->data[0], dst->linesize[0],
src->data[0], src->linesize[0],
dst_width, dst_height, y_ccir_to_jpeg);
}
return 0;
}
/* YUV to YUV planar */
if (is_yuv_planar (dst_pix) && is_yuv_planar (src_pix) &&
dst_pix->depth == src_pix->depth) {
int x_shift, y_shift, xy_shift;
void (*resize_func) (uint8_t * dst, int dst_wrap, int dst_width,
int dst_height, const uint8_t * src, int src_wrap, int src_width,
int src_height);
x_shift = (dst_pix->x_chroma_shift - src_pix->x_chroma_shift);
y_shift = (dst_pix->y_chroma_shift - src_pix->y_chroma_shift);
xy_shift = ((x_shift & 0xf) << 4) | (y_shift & 0xf);
/* there must be filters for conversion at least from and to
YUV444 format */
switch (xy_shift) {
case 0x00:
resize_func = img_copy_plane_resize;
break;
case 0x10:
resize_func = shrink21;
break;
case 0x20:
resize_func = shrink41;
break;
case 0x01:
resize_func = shrink12;
break;
case 0x11:
resize_func = shrink22;
break;
case 0x22:
resize_func = shrink44;
break;
case 0xf0:
resize_func = grow21;
break;
case 0xe0:
resize_func = grow41;
break;
case 0xff:
resize_func = grow22;
break;
case 0xee:
resize_func = grow44;
break;
case 0xf1:
resize_func = conv411;
break;
default:
/* currently not handled */
goto no_chroma_filter;
}
img_copy_plane (dst->data[0], dst->linesize[0],
src->data[0], src->linesize[0], dst_width, dst_height);
#define GEN_MASK(x) ((1<<(x))-1)
#define DIV_ROUND_UP_X(v,x) (((v) + GEN_MASK(x)) >> (x))
for (i = 1; i <= 2; i++) {
gint w, h;
gint s_w, s_h;
w = DIV_ROUND_UP_X (dst_width, dst_pix->x_chroma_shift);
h = DIV_ROUND_UP_X (dst_height, dst_pix->y_chroma_shift);
s_w = DIV_ROUND_UP_X (src_width, src_pix->x_chroma_shift);
s_h = DIV_ROUND_UP_X (src_height, src_pix->y_chroma_shift);
if (src->data[i] != NULL && dst->data[i] != NULL) {
resize_func (dst->data[i], dst->linesize[i], w, h,
src->data[i], src->linesize[i], s_w, s_h);
} else if (dst->data[i] != NULL) {
memset (dst->data[i], 128, dst->linesize[i] * h);
}
}
/* if yuv color space conversion is needed, we do it here on
the destination image */
if (dst_pix->color_type != src_pix->color_type) {
const uint8_t *y_table, *c_table;
if (dst_pix->color_type == FF_COLOR_YUV) {
y_table = y_jpeg_to_ccir;
c_table = c_jpeg_to_ccir;
} else {
y_table = y_ccir_to_jpeg;
c_table = c_ccir_to_jpeg;
}
img_apply_table (dst->data[0], dst->linesize[0],
dst->data[0], dst->linesize[0], dst_width, dst_height, y_table);
for (i = 1; i <= 2; i++)
img_apply_table (dst->data[i], dst->linesize[i],
dst->data[i], dst->linesize[i],
dst_width >> dst_pix->x_chroma_shift,
dst_height >> dst_pix->y_chroma_shift, c_table);
}
return 0;
}
no_chroma_filter:
GST_CAT_INFO (ffmpegcolorspace_performance,
"no direct path to convert colorspace from %s -> %s", src_pix->name,
dst_pix->name);
/* try to use an intermediate format */
if (src_pix_fmt == PIX_FMT_YUV422 || dst_pix_fmt == PIX_FMT_YUV422) {
/* specific case: convert to YUV422P first */
int_pix_fmt = PIX_FMT_YUV422P;
} else if (src_pix_fmt == PIX_FMT_UYVY422 || dst_pix_fmt == PIX_FMT_UYVY422 ||
src_pix_fmt == PIX_FMT_YVYU422 || dst_pix_fmt == PIX_FMT_YVYU422) {
/* specific case: convert to YUV422P first */
int_pix_fmt = PIX_FMT_YUV422P;
} else if (src_pix_fmt == PIX_FMT_UYVY411 || dst_pix_fmt == PIX_FMT_UYVY411) {
/* specific case: convert to YUV411P first */
int_pix_fmt = PIX_FMT_YUV411P;
} else if ((src_pix->color_type == FF_COLOR_GRAY &&
src_pix_fmt != PIX_FMT_GRAY8) ||
(dst_pix->color_type == FF_COLOR_GRAY && dst_pix_fmt != PIX_FMT_GRAY8)) {
/* gray8 is the normalized format */
int_pix_fmt = PIX_FMT_GRAY8;
} else if (src_pix_fmt == PIX_FMT_Y16 || dst_pix_fmt == PIX_FMT_Y16) {
/* y800 is the normalized format */
int_pix_fmt = PIX_FMT_Y800;
} else if ((is_yuv_planar (src_pix) &&
src_pix_fmt != PIX_FMT_YUV444P && src_pix_fmt != PIX_FMT_YUVJ444P)) {
/* yuv444 is the normalized format */
if (src_pix->color_type == FF_COLOR_YUV_JPEG)
int_pix_fmt = PIX_FMT_YUVJ444P;
else
int_pix_fmt = PIX_FMT_YUV444P;
} else if ((is_yuv_planar (dst_pix) &&
dst_pix_fmt != PIX_FMT_YUV444P && dst_pix_fmt != PIX_FMT_YUVJ444P)) {
/* yuv444 is the normalized format */
if (dst_pix->color_type == FF_COLOR_YUV_JPEG)
int_pix_fmt = PIX_FMT_YUVJ444P;
else
int_pix_fmt = PIX_FMT_YUV444P;
} else {
/* the two formats are rgb or gray8 or yuv[j]444p */
if (src_pix->is_alpha && dst_pix->is_alpha)
int_pix_fmt = PIX_FMT_RGBA32;
else
int_pix_fmt = PIX_FMT_RGB24;
}
if (avpicture_alloc (tmp, int_pix_fmt, dst_width, dst_height,
dst->interlaced) < 0)
return -1;
ret = -1;
if (img_convert (tmp, int_pix_fmt,
src, src_pix_fmt, src_width, src_height) < 0)
goto fail1;
if (img_convert (dst, dst_pix_fmt,
tmp, int_pix_fmt, dst_width, dst_height) < 0)
goto fail1;
ret = 0;
fail1:
avpicture_free (tmp);
return ret;
}
/* NOTE: we scan all the pixels to have an exact information */
static int
get_alpha_info_pal8 (const AVPicture * src, int width, int height)
{
const unsigned char *p;
int src_wrap, ret, x, y;
unsigned int a;
uint32_t *palette = (uint32_t *) src->data[1];
p = src->data[0];
src_wrap = src->linesize[0] - width;
ret = 0;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
a = palette[p[0]] >> 24;
if (a == 0x00) {
ret |= FF_ALPHA_TRANSP;
} else if (a != 0xff) {
ret |= FF_ALPHA_SEMI_TRANSP;
}
p++;
}
p += src_wrap;
}
return ret;
}
/**
* Tell if an image really has transparent alpha values.
* @return ored mask of FF_ALPHA_xxx constants
*/
int
img_get_alpha_info (const AVPicture * src, int pix_fmt, int width, int height)
{
const PixFmtInfo *pf;
int ret;
pf = get_pix_fmt_info (pix_fmt);
/* no alpha can be represented in format */
if (!pf->is_alpha)
return 0;
switch (pix_fmt) {
case PIX_FMT_RGB32:
ret = get_alpha_info_rgb32 (src, width, height);
break;
case PIX_FMT_BGR32:
ret = get_alpha_info_bgr32 (src, width, height);
break;
case PIX_FMT_xRGB32:
ret = get_alpha_info_xrgb32 (src, width, height);
break;
case PIX_FMT_BGRx32:
ret = get_alpha_info_bgrx32 (src, width, height);
break;
case PIX_FMT_RGBA32:
ret = get_alpha_info_rgba32 (src, width, height);
break;
case PIX_FMT_BGRA32:
ret = get_alpha_info_bgra32 (src, width, height);
break;
case PIX_FMT_ARGB32:
ret = get_alpha_info_argb32 (src, width, height);
break;
case PIX_FMT_ABGR32:
ret = get_alpha_info_abgr32 (src, width, height);
break;
case PIX_FMT_RGB555:
ret = get_alpha_info_rgb555 (src, width, height);
break;
case PIX_FMT_PAL8:
ret = get_alpha_info_pal8 (src, width, height);
break;
default:
/* we do not know, so everything is indicated */
ret = FF_ALPHA_TRANSP | FF_ALPHA_SEMI_TRANSP;
break;
}
return ret;
}
#ifdef HAVE_MMX
#define DEINT_INPLACE_LINE_LUM \
movd_m2r(lum_m4[0],mm0);\
movd_m2r(lum_m3[0],mm1);\
movd_m2r(lum_m2[0],mm2);\
movd_m2r(lum_m1[0],mm3);\
movd_m2r(lum[0],mm4);\
punpcklbw_r2r(mm7,mm0);\
movd_r2m(mm2,lum_m4[0]);\
punpcklbw_r2r(mm7,mm1);\
punpcklbw_r2r(mm7,mm2);\
punpcklbw_r2r(mm7,mm3);\
punpcklbw_r2r(mm7,mm4);\
paddw_r2r(mm3,mm1);\
psllw_i2r(1,mm2);\
paddw_r2r(mm4,mm0);\
psllw_i2r(2,mm1);\
paddw_r2r(mm6,mm2);\
paddw_r2r(mm2,mm1);\
psubusw_r2r(mm0,mm1);\
psrlw_i2r(3,mm1);\
packuswb_r2r(mm7,mm1);\
movd_r2m(mm1,lum_m2[0]);
#define DEINT_LINE_LUM \
movd_m2r(lum_m4[0],mm0);\
movd_m2r(lum_m3[0],mm1);\
movd_m2r(lum_m2[0],mm2);\
movd_m2r(lum_m1[0],mm3);\
movd_m2r(lum[0],mm4);\
punpcklbw_r2r(mm7,mm0);\
punpcklbw_r2r(mm7,mm1);\
punpcklbw_r2r(mm7,mm2);\
punpcklbw_r2r(mm7,mm3);\
punpcklbw_r2r(mm7,mm4);\
paddw_r2r(mm3,mm1);\
psllw_i2r(1,mm2);\
paddw_r2r(mm4,mm0);\
psllw_i2r(2,mm1);\
paddw_r2r(mm6,mm2);\
paddw_r2r(mm2,mm1);\
psubusw_r2r(mm0,mm1);\
psrlw_i2r(3,mm1);\
packuswb_r2r(mm7,mm1);\
movd_r2m(mm1,dst[0]);
#endif
/* filter parameters: [-1 4 2 4 -1] // 8 */
#if 0
static void
deinterlace_line (uint8_t * dst,
const uint8_t * lum_m4, const uint8_t * lum_m3,
const uint8_t * lum_m2, const uint8_t * lum_m1,
const uint8_t * lum, int size)
{
#ifndef HAVE_MMX
uint8_t *cm = cropTbl + MAX_NEG_CROP;
int sum;
for (; size > 0; size--) {
sum = -lum_m4[0];
sum += lum_m3[0] << 2;
sum += lum_m2[0] << 1;
sum += lum_m1[0] << 2;
sum += -lum[0];
dst[0] = cm[(sum + 4) >> 3];
lum_m4++;
lum_m3++;
lum_m2++;
lum_m1++;
lum++;
dst++;
}
#else
{
mmx_t rounder;
rounder.uw[0] = 4;
rounder.uw[1] = 4;
rounder.uw[2] = 4;
rounder.uw[3] = 4;
pxor_r2r (mm7, mm7);
movq_m2r (rounder, mm6);
}
for (; size > 3; size -= 4) {
DEINT_LINE_LUM lum_m4 += 4;
lum_m3 += 4;
lum_m2 += 4;
lum_m1 += 4;
lum += 4;
dst += 4;
}
#endif
}
static void
deinterlace_line_inplace (uint8_t * lum_m4, uint8_t * lum_m3, uint8_t * lum_m2,
uint8_t * lum_m1, uint8_t * lum, int size)
{
#ifndef HAVE_MMX
uint8_t *cm = cropTbl + MAX_NEG_CROP;
int sum;
for (; size > 0; size--) {
sum = -lum_m4[0];
sum += lum_m3[0] << 2;
sum += lum_m2[0] << 1;
lum_m4[0] = lum_m2[0];
sum += lum_m1[0] << 2;
sum += -lum[0];
lum_m2[0] = cm[(sum + 4) >> 3];
lum_m4++;
lum_m3++;
lum_m2++;
lum_m1++;
lum++;
}
#else
{
mmx_t rounder;
rounder.uw[0] = 4;
rounder.uw[1] = 4;
rounder.uw[2] = 4;
rounder.uw[3] = 4;
pxor_r2r (mm7, mm7);
movq_m2r (rounder, mm6);
}
for (; size > 3; size -= 4) {
DEINT_INPLACE_LINE_LUM lum_m4 += 4;
lum_m3 += 4;
lum_m2 += 4;
lum_m1 += 4;
lum += 4;
}
#endif
}
#endif
/* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
top field is copied as is, but the bottom field is deinterlaced
against the top field. */
#if 0
static void
deinterlace_bottom_field (uint8_t * dst, int dst_wrap,
const uint8_t * src1, int src_wrap, int width, int height)
{
const uint8_t *src_m2, *src_m1, *src_0, *src_p1, *src_p2;
int y;
src_m2 = src1;
src_m1 = src1;
src_0 = &src_m1[src_wrap];
src_p1 = &src_0[src_wrap];
src_p2 = &src_p1[src_wrap];
for (y = 0; y < (height - 2); y += 2) {
memcpy (dst, src_m1, width);
dst += dst_wrap;
deinterlace_line (dst, src_m2, src_m1, src_0, src_p1, src_p2, width);
src_m2 = src_0;
src_m1 = src_p1;
src_0 = src_p2;
src_p1 += 2 * src_wrap;
src_p2 += 2 * src_wrap;
dst += dst_wrap;
}
memcpy (dst, src_m1, width);
dst += dst_wrap;
/* do last line */
deinterlace_line (dst, src_m2, src_m1, src_0, src_0, src_0, width);
}
static void
deinterlace_bottom_field_inplace (uint8_t * src1, int src_wrap,
int width, int height)
{
uint8_t *src_m1, *src_0, *src_p1, *src_p2;
int y;
uint8_t *buf;
buf = (uint8_t *) av_malloc (width);
src_m1 = src1;
memcpy (buf, src_m1, width);
src_0 = &src_m1[src_wrap];
src_p1 = &src_0[src_wrap];
src_p2 = &src_p1[src_wrap];
for (y = 0; y < (height - 2); y += 2) {
deinterlace_line_inplace (buf, src_m1, src_0, src_p1, src_p2, width);
src_m1 = src_p1;
src_0 = src_p2;
src_p1 += 2 * src_wrap;
src_p2 += 2 * src_wrap;
}
/* do last line */
deinterlace_line_inplace (buf, src_m1, src_0, src_0, src_0, width);
av_free (buf);
}
#endif
/* deinterlace - if not supported return -1 */
#if 0
static int
avpicture_deinterlace (AVPicture * dst, const AVPicture * src,
int pix_fmt, int width, int height)
{
int i;
if (pix_fmt != PIX_FMT_YUV420P &&
pix_fmt != PIX_FMT_YUV422P &&
pix_fmt != PIX_FMT_YUV444P && pix_fmt != PIX_FMT_YUV411P)
return -1;
if ((width & 3) != 0 || (height & 3) != 0)
return -1;
for (i = 0; i < 3; i++) {
if (i == 1) {
switch (pix_fmt) {
case PIX_FMT_YUV420P:
width >>= 1;
height >>= 1;
break;
case PIX_FMT_YUV422P:
width >>= 1;
break;
case PIX_FMT_YUV411P:
width >>= 2;
break;
default:
break;
}
}
if (src == dst) {
deinterlace_bottom_field_inplace (dst->data[i], dst->linesize[i],
width, height);
} else {
deinterlace_bottom_field (dst->data[i], dst->linesize[i],
src->data[i], src->linesize[i], width, height);
}
}
#ifdef HAVE_MMX
emms ();
#endif
return 0;
}
#endif
#undef FIX