diff options
Diffstat (limited to 'libavcodec/imgconvert.c')
-rw-r--r-- | libavcodec/imgconvert.c | 628 |
1 files changed, 288 insertions, 340 deletions
diff --git a/libavcodec/imgconvert.c b/libavcodec/imgconvert.c index fd30dc4..4846172 100644 --- a/libavcodec/imgconvert.c +++ b/libavcodec/imgconvert.c @@ -2,20 +2,20 @@ * Misc image conversion routines * Copyright (c) 2001, 2002, 2003 Fabrice Bellard * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg 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.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg 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 Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -47,10 +47,6 @@ #define FF_COLOR_YUV 2 /**< YUV color space. 16 <= Y <= 235, 16 <= U, V <= 240 */ #define FF_COLOR_YUV_JPEG 3 /**< YUV color space. 0 <= Y <= 255, 0 <= U, V <= 255 */ -#define FF_PIXEL_PLANAR 0 /**< each channel has one component in AVPicture */ -#define FF_PIXEL_PACKED 1 /**< only one components containing all the channels */ -#define FF_PIXEL_PALETTE 2 /**< one components containing indexes for a palette */ - #if HAVE_MMX_EXTERNAL #define deinterlace_line_inplace ff_deinterlace_line_inplace_mmx #define deinterlace_line ff_deinterlace_line_mmx @@ -59,352 +55,336 @@ #define deinterlace_line deinterlace_line_c #endif +#define pixdesc_has_alpha(pixdesc) \ + ((pixdesc)->nb_components == 2 || (pixdesc)->nb_components == 4 || (pixdesc)->flags & PIX_FMT_PAL) + typedef struct PixFmtInfo { - uint8_t nb_channels; /**< number of channels (including alpha) */ uint8_t color_type; /**< color type (see FF_COLOR_xxx constants) */ - uint8_t pixel_type; /**< pixel storage type (see FF_PIXEL_xxx constants) */ - uint8_t is_alpha : 1; /**< true if alpha can be specified */ - uint8_t depth; /**< bit depth of the color components */ + uint8_t padded_size; /**< padded size in bits if different from the non-padded size */ } PixFmtInfo; /* this table gives more information about formats */ static const PixFmtInfo pix_fmt_info[AV_PIX_FMT_NB] = { /* YUV formats */ [AV_PIX_FMT_YUV420P] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, }, [AV_PIX_FMT_YUV422P] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, }, [AV_PIX_FMT_YUV444P] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, }, [AV_PIX_FMT_YUYV422] = { - .nb_channels = 1, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PACKED, - .depth = 8, }, [AV_PIX_FMT_UYVY422] = { - .nb_channels = 1, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PACKED, - .depth = 8, }, [AV_PIX_FMT_YUV410P] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, }, [AV_PIX_FMT_YUV411P] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, }, [AV_PIX_FMT_YUV440P] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, + }, + [AV_PIX_FMT_YUV420P9LE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV422P9LE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV444P9LE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV420P9BE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV422P9BE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV444P9BE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV420P10LE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV422P10LE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV444P10LE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV420P10BE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV422P10BE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV444P10BE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV420P12LE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV422P12LE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV444P12LE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV420P12BE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV422P12BE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV444P12BE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV420P14LE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV422P14LE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV444P14LE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV420P14BE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV422P14BE] = { + .color_type = FF_COLOR_YUV, + }, + [AV_PIX_FMT_YUV444P14BE] = { + .color_type = FF_COLOR_YUV, }, [AV_PIX_FMT_YUV420P16LE] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 16, }, [AV_PIX_FMT_YUV422P16LE] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 16, }, [AV_PIX_FMT_YUV444P16LE] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 16, }, [AV_PIX_FMT_YUV420P16BE] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 16, }, [AV_PIX_FMT_YUV422P16BE] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 16, }, [AV_PIX_FMT_YUV444P16BE] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 16, }, - /* YUV formats with alpha plane */ [AV_PIX_FMT_YUVA420P] = { - .nb_channels = 4, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, + }, + + [AV_PIX_FMT_YUVA422P] = { + .color_type = FF_COLOR_YUV, + }, + + [AV_PIX_FMT_YUVA444P] = { + .color_type = FF_COLOR_YUV, }, /* JPEG YUV */ [AV_PIX_FMT_YUVJ420P] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV_JPEG, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, }, [AV_PIX_FMT_YUVJ422P] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV_JPEG, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, }, [AV_PIX_FMT_YUVJ444P] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV_JPEG, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, }, [AV_PIX_FMT_YUVJ440P] = { - .nb_channels = 3, .color_type = FF_COLOR_YUV_JPEG, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, }, /* RGB formats */ [AV_PIX_FMT_RGB24] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 8, }, [AV_PIX_FMT_BGR24] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 8, }, [AV_PIX_FMT_ARGB] = { - .nb_channels = 4, .is_alpha = 1, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 8, }, [AV_PIX_FMT_RGB48BE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 16, }, [AV_PIX_FMT_RGB48LE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 16, + }, + [AV_PIX_FMT_RGBA64BE] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_RGBA64LE] = { + .color_type = FF_COLOR_RGB, }, [AV_PIX_FMT_RGB565BE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 5, }, [AV_PIX_FMT_RGB565LE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 5, }, [AV_PIX_FMT_RGB555BE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 5, + .padded_size = 16, }, [AV_PIX_FMT_RGB555LE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 5, + .padded_size = 16, }, [AV_PIX_FMT_RGB444BE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 4, + .padded_size = 16, }, [AV_PIX_FMT_RGB444LE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 4, + .padded_size = 16, }, /* gray / mono formats */ [AV_PIX_FMT_GRAY16BE] = { - .nb_channels = 1, .color_type = FF_COLOR_GRAY, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 16, }, [AV_PIX_FMT_GRAY16LE] = { - .nb_channels = 1, .color_type = FF_COLOR_GRAY, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 16, }, [AV_PIX_FMT_GRAY8] = { - .nb_channels = 1, .color_type = FF_COLOR_GRAY, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, + }, + [AV_PIX_FMT_GRAY8A] = { + .color_type = FF_COLOR_GRAY, }, [AV_PIX_FMT_MONOWHITE] = { - .nb_channels = 1, .color_type = FF_COLOR_GRAY, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 1, }, [AV_PIX_FMT_MONOBLACK] = { - .nb_channels = 1, .color_type = FF_COLOR_GRAY, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 1, }, /* paletted formats */ [AV_PIX_FMT_PAL8] = { - .nb_channels = 4, .is_alpha = 1, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PALETTE, - .depth = 8, }, [AV_PIX_FMT_UYYVYY411] = { - .nb_channels = 1, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PACKED, - .depth = 8, }, [AV_PIX_FMT_ABGR] = { - .nb_channels = 4, .is_alpha = 1, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 8, + }, + [AV_PIX_FMT_BGR48BE] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_BGR48LE] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_BGRA64BE] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_BGRA64LE] = { + .color_type = FF_COLOR_RGB, }, [AV_PIX_FMT_BGR565BE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 5, + .padded_size = 16, }, [AV_PIX_FMT_BGR565LE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 5, + .padded_size = 16, }, [AV_PIX_FMT_BGR555BE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 5, + .padded_size = 16, }, [AV_PIX_FMT_BGR555LE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 5, + .padded_size = 16, }, [AV_PIX_FMT_BGR444BE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 4, + .padded_size = 16, }, [AV_PIX_FMT_BGR444LE] = { - .nb_channels = 3, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 4, + .padded_size = 16, }, [AV_PIX_FMT_RGB8] = { - .nb_channels = 1, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 8, }, [AV_PIX_FMT_RGB4] = { - .nb_channels = 1, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 4, }, [AV_PIX_FMT_RGB4_BYTE] = { - .nb_channels = 1, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 8, + .padded_size = 8, }, [AV_PIX_FMT_BGR8] = { - .nb_channels = 1, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 8, }, [AV_PIX_FMT_BGR4] = { - .nb_channels = 1, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 4, }, [AV_PIX_FMT_BGR4_BYTE] = { - .nb_channels = 1, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 8, + .padded_size = 8, }, [AV_PIX_FMT_NV12] = { - .nb_channels = 2, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, }, [AV_PIX_FMT_NV21] = { - .nb_channels = 2, .color_type = FF_COLOR_YUV, - .pixel_type = FF_PIXEL_PLANAR, - .depth = 8, }, [AV_PIX_FMT_BGRA] = { - .nb_channels = 4, .is_alpha = 1, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 8, }, [AV_PIX_FMT_RGBA] = { - .nb_channels = 4, .is_alpha = 1, .color_type = FF_COLOR_RGB, - .pixel_type = FF_PIXEL_PACKED, - .depth = 8, + }, + + [AV_PIX_FMT_GBRP] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_GBRP9BE] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_GBRP9LE] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_GBRP10BE] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_GBRP10LE] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_GBRP12BE] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_GBRP12LE] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_GBRP14BE] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_GBRP14LE] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_GBRP16BE] = { + .color_type = FF_COLOR_RGB, + }, + [AV_PIX_FMT_GBRP16LE] = { + .color_type = FF_COLOR_RGB, }, }; @@ -424,61 +404,39 @@ int ff_is_hwaccel_pix_fmt(enum AVPixelFormat pix_fmt) int avpicture_fill(AVPicture *picture, uint8_t *ptr, enum AVPixelFormat pix_fmt, int width, int height) { - int ret; - - if ((ret = av_image_check_size(width, height, 0, NULL)) < 0) - return ret; - - if ((ret = av_image_fill_linesizes(picture->linesize, pix_fmt, width)) < 0) - return ret; - - return av_image_fill_pointers(picture->data, pix_fmt, height, ptr, picture->linesize); + return av_image_fill_arrays(picture->data, picture->linesize, + ptr, pix_fmt, width, height, 1); } int avpicture_layout(const AVPicture* src, enum AVPixelFormat pix_fmt, int width, int height, unsigned char *dest, int dest_size) { - int i, j, nb_planes = 0, linesizes[4]; - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); - int size = avpicture_get_size(pix_fmt, width, height); - - if (size > dest_size || size < 0) - return AVERROR(EINVAL); - - for (i = 0; i < desc->nb_components; i++) - nb_planes = FFMAX(desc->comp[i].plane, nb_planes); - nb_planes++; - - av_image_fill_linesizes(linesizes, pix_fmt, width); - for (i = 0; i < nb_planes; i++) { - int h, shift = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; - const unsigned char *s = src->data[i]; - h = (height + (1 << shift) - 1) >> shift; - - for (j = 0; j < h; j++) { - memcpy(dest, s, linesizes[i]); - dest += linesizes[i]; - s += src->linesize[i]; - } - } - - if (desc->flags & PIX_FMT_PAL) - memcpy((unsigned char *)(((size_t)dest + 3) & ~3), src->data[1], 256 * 4); - - return size; + return av_image_copy_to_buffer(dest, dest_size, + (const uint8_t * const*)src->data, src->linesize, + pix_fmt, width, height, 1); } int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height) { - AVPicture dummy_pict; + return av_image_get_buffer_size(pix_fmt, width, height, 1); +} + +static int get_pix_fmt_depth(int *min, int *max, enum AVPixelFormat pix_fmt) +{ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int i; - if(av_image_check_size(width, height, 0, NULL)) - return -1; - if (desc->flags & PIX_FMT_PSEUDOPAL) - // do not include palette for these pseudo-paletted formats - return width * height; - return avpicture_fill(&dummy_pict, NULL, pix_fmt, width, height); + if (!desc || !desc->nb_components) { + *min = *max = 0; + return AVERROR(EINVAL); + } + + *min = INT_MAX, *max = -INT_MAX; + for (i = 0; i < desc->nb_components; i++) { + *min = FFMIN(desc->comp[i].depth_minus1+1, *min); + *max = FFMAX(desc->comp[i].depth_minus1+1, *max); + } + return 0; } int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, enum AVPixelFormat src_pix_fmt, @@ -487,22 +445,29 @@ int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, enum AVPixelFormat const PixFmtInfo *pf, *ps; const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(src_pix_fmt); const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(dst_pix_fmt); - int loss; + int src_min_depth, src_max_depth, dst_min_depth, dst_max_depth; + int ret, loss; + + if (dst_pix_fmt >= AV_PIX_FMT_NB || dst_pix_fmt <= AV_PIX_FMT_NONE) + return ~0; ps = &pix_fmt_info[src_pix_fmt]; /* compute loss */ loss = 0; - pf = &pix_fmt_info[dst_pix_fmt]; - if (pf->depth < ps->depth || - ((dst_pix_fmt == AV_PIX_FMT_RGB555BE || dst_pix_fmt == AV_PIX_FMT_RGB555LE || - dst_pix_fmt == AV_PIX_FMT_BGR555BE || dst_pix_fmt == AV_PIX_FMT_BGR555LE) && - (src_pix_fmt == AV_PIX_FMT_RGB565BE || src_pix_fmt == AV_PIX_FMT_RGB565LE || - src_pix_fmt == AV_PIX_FMT_BGR565BE || src_pix_fmt == AV_PIX_FMT_BGR565LE))) + + if ((ret = get_pix_fmt_depth(&src_min_depth, &src_max_depth, src_pix_fmt)) < 0) + return ret; + if ((ret = get_pix_fmt_depth(&dst_min_depth, &dst_max_depth, dst_pix_fmt)) < 0) + return ret; + if (dst_min_depth < src_min_depth || + dst_max_depth < src_max_depth) loss |= FF_LOSS_DEPTH; if (dst_desc->log2_chroma_w > src_desc->log2_chroma_w || dst_desc->log2_chroma_h > src_desc->log2_chroma_h) loss |= FF_LOSS_RESOLUTION; + + pf = &pix_fmt_info[dst_pix_fmt]; switch(pf->color_type) { case FF_COLOR_RGB: if (ps->color_type != FF_COLOR_RGB && @@ -532,156 +497,116 @@ int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, enum AVPixelFormat 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)) + if (!pixdesc_has_alpha(dst_desc) && (pixdesc_has_alpha(src_desc) && 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)) + if (dst_pix_fmt == AV_PIX_FMT_PAL8 && + (src_pix_fmt != AV_PIX_FMT_PAL8 && (ps->color_type != FF_COLOR_GRAY || (pixdesc_has_alpha(src_desc) && has_alpha)))) loss |= FF_LOSS_COLORQUANT; + return loss; } static int avg_bits_per_pixel(enum AVPixelFormat pix_fmt) { - int bits; - const PixFmtInfo *pf; + const PixFmtInfo *info = &pix_fmt_info[pix_fmt]; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); - pf = &pix_fmt_info[pix_fmt]; - switch(pf->pixel_type) { - case FF_PIXEL_PACKED: - switch(pix_fmt) { - case AV_PIX_FMT_YUYV422: - case AV_PIX_FMT_UYVY422: - case AV_PIX_FMT_RGB565BE: - case AV_PIX_FMT_RGB565LE: - case AV_PIX_FMT_RGB555BE: - case AV_PIX_FMT_RGB555LE: - case AV_PIX_FMT_RGB444BE: - case AV_PIX_FMT_RGB444LE: - case AV_PIX_FMT_BGR565BE: - case AV_PIX_FMT_BGR565LE: - case AV_PIX_FMT_BGR555BE: - case AV_PIX_FMT_BGR555LE: - case AV_PIX_FMT_BGR444BE: - case AV_PIX_FMT_BGR444LE: - bits = 16; - break; - case AV_PIX_FMT_UYYVYY411: - bits = 12; - break; - default: - bits = pf->depth * pf->nb_channels; - break; - } - break; - case FF_PIXEL_PLANAR: - if (desc->log2_chroma_w == 0 && desc->log2_chroma_h == 0) { - bits = pf->depth * pf->nb_channels; - } else { - bits = pf->depth + ((2 * pf->depth) >> - (desc->log2_chroma_w + desc->log2_chroma_h)); - } - break; - case FF_PIXEL_PALETTE: - bits = 8; - break; - default: - bits = -1; - break; - } - return bits; -} - -static enum AVPixelFormat avcodec_find_best_pix_fmt1(enum AVPixelFormat *pix_fmt_list, - enum AVPixelFormat src_pix_fmt, - int has_alpha, - int loss_mask) -{ - int dist, i, loss, min_dist; - enum AVPixelFormat dst_pix_fmt; - - /* find exact color match with smallest size */ - dst_pix_fmt = AV_PIX_FMT_NONE; - min_dist = 0x7fffffff; - i = 0; - while (pix_fmt_list[i] != AV_PIX_FMT_NONE) { - enum AVPixelFormat pix_fmt = pix_fmt_list[i]; - - if (i > AV_PIX_FMT_NB) { - av_log(NULL, AV_LOG_ERROR, "Pixel format list longer than expected, " - "it is either not properly terminated or contains duplicates\n"); - return AV_PIX_FMT_NONE; - } - - loss = avcodec_get_pix_fmt_loss(pix_fmt, src_pix_fmt, has_alpha) & loss_mask; - if (loss == 0) { - dist = avg_bits_per_pixel(pix_fmt); - if (dist < min_dist) { - min_dist = dist; - dst_pix_fmt = pix_fmt; - } - } - i++; - } - return dst_pix_fmt; + return info->padded_size ? + info->padded_size : av_get_bits_per_pixel(desc); } #if FF_API_FIND_BEST_PIX_FMT enum AVPixelFormat avcodec_find_best_pix_fmt(int64_t pix_fmt_mask, enum AVPixelFormat src_pix_fmt, - int has_alpha, int *loss_ptr) + int has_alpha, int *loss_ptr) { - enum AVPixelFormat list[64]; - int i, j = 0; + enum AVPixelFormat dst_pix_fmt; + int i; + + if (loss_ptr) /* all losses count (for backward compatibility) */ + *loss_ptr = 0; - // test only the first 64 pixel formats to avoid undefined behaviour - for (i = 0; i < 64; i++) { + dst_pix_fmt = AV_PIX_FMT_NONE; /* so first iteration doesn't have to be treated special */ + for(i = 0; i< FFMIN(AV_PIX_FMT_NB, 64); i++){ if (pix_fmt_mask & (1ULL << i)) - list[j++] = i; + dst_pix_fmt = avcodec_find_best_pix_fmt_of_2(dst_pix_fmt, i, src_pix_fmt, has_alpha, loss_ptr); } - list[j] = AV_PIX_FMT_NONE; - - return avcodec_find_best_pix_fmt2(list, src_pix_fmt, has_alpha, loss_ptr); + return dst_pix_fmt; } #endif /* FF_API_FIND_BEST_PIX_FMT */ -enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat *pix_fmt_list, - enum AVPixelFormat src_pix_fmt, - int has_alpha, int *loss_ptr) +enum AVPixelFormat avcodec_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr) { enum AVPixelFormat dst_pix_fmt; - int loss_mask, i; + int loss1, loss2, loss_order1, loss_order2, i, loss_mask; static const int loss_mask_order[] = { ~0, /* no loss first */ ~FF_LOSS_ALPHA, ~FF_LOSS_RESOLUTION, + ~FF_LOSS_COLORSPACE, ~(FF_LOSS_COLORSPACE | FF_LOSS_RESOLUTION), ~FF_LOSS_COLORQUANT, ~FF_LOSS_DEPTH, + ~(FF_LOSS_DEPTH|FF_LOSS_COLORSPACE), + ~(FF_LOSS_RESOLUTION | FF_LOSS_DEPTH | FF_LOSS_COLORSPACE | FF_LOSS_ALPHA | + FF_LOSS_COLORQUANT | FF_LOSS_CHROMA), + 0x80000, //non zero entry that combines all loss variants including future additions 0, }; + loss_mask= loss_ptr?~*loss_ptr:~0; /* use loss mask if provided */ + dst_pix_fmt = AV_PIX_FMT_NONE; + loss1 = avcodec_get_pix_fmt_loss(dst_pix_fmt1, src_pix_fmt, has_alpha) & loss_mask; + loss2 = avcodec_get_pix_fmt_loss(dst_pix_fmt2, src_pix_fmt, has_alpha) & loss_mask; + /* try with successive loss */ - i = 0; - for(;;) { - loss_mask = loss_mask_order[i++]; - dst_pix_fmt = avcodec_find_best_pix_fmt1(pix_fmt_list, src_pix_fmt, - has_alpha, loss_mask); - if (dst_pix_fmt >= 0) - goto found; - if (loss_mask == 0) - break; + for(i = 0;loss_mask_order[i] != 0 && dst_pix_fmt == AV_PIX_FMT_NONE;i++) { + loss_order1 = loss1 & loss_mask_order[i]; + loss_order2 = loss2 & loss_mask_order[i]; + + if (loss_order1 == 0 && loss_order2 == 0){ /* use format with smallest depth */ + dst_pix_fmt = avg_bits_per_pixel(dst_pix_fmt2) < avg_bits_per_pixel(dst_pix_fmt1) ? dst_pix_fmt2 : dst_pix_fmt1; + } else if (loss_order1 == 0 || loss_order2 == 0) { /* use format with no loss */ + dst_pix_fmt = loss_order2 ? dst_pix_fmt1 : dst_pix_fmt2; + } } - return AV_PIX_FMT_NONE; - found: + if (loss_ptr) *loss_ptr = avcodec_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha); return dst_pix_fmt; } +#if AV_HAVE_INCOMPATIBLE_FORK_ABI +enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat *pix_fmt_list, + enum AVPixelFormat src_pix_fmt, + int has_alpha, int *loss_ptr){ + return avcodec_find_best_pix_fmt_of_list(pix_fmt_list, src_pix_fmt, has_alpha, loss_ptr); +} +#else +enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr) +{ + return avcodec_find_best_pix_fmt_of_2(dst_pix_fmt1, dst_pix_fmt2, src_pix_fmt, has_alpha, loss_ptr); +} +#endif + +enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(enum AVPixelFormat *pix_fmt_list, + enum AVPixelFormat src_pix_fmt, + int has_alpha, int *loss_ptr){ + int i; + + enum AVPixelFormat best = AV_PIX_FMT_NONE; + + for(i=0; pix_fmt_list[i] != AV_PIX_FMT_NONE; i++) + best = avcodec_find_best_pix_fmt_of_2(best, pix_fmt_list[i], src_pix_fmt, has_alpha, loss_ptr); + + return best; +} + void av_picture_copy(AVPicture *dst, const AVPicture *src, enum AVPixelFormat pix_fmt, int width, int height) { - av_image_copy(dst->data, dst->linesize, src->data, + av_image_copy(dst->data, dst->linesize, (const uint8_t **)src->data, src->linesize, pix_fmt, width, height); } @@ -791,11 +716,26 @@ void avpicture_free(AVPicture *picture) } /* return true if yuv planar */ -static inline int is_yuv_planar(const PixFmtInfo *ps) +static inline int is_yuv_planar(enum AVPixelFormat fmt) { - return (ps->color_type == FF_COLOR_YUV || - ps->color_type == FF_COLOR_YUV_JPEG) && - ps->pixel_type == FF_PIXEL_PLANAR; + const PixFmtInfo *info = &pix_fmt_info[fmt]; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + int i; + int planes[4] = { 0 }; + + if (info->color_type != FF_COLOR_YUV && + info->color_type != FF_COLOR_YUV_JPEG) + return 0; + + /* set the used planes */ + for (i = 0; i < desc->nb_components; i++) + planes[desc->comp[i].plane] = 1; + + /* if there is an unused plane, the format is not planar */ + for (i = 0; i < desc->nb_components; i++) + if (!planes[i]) + return 0; + return 1; } int av_picture_crop(AVPicture *dst, const AVPicture *src, @@ -805,15 +745,23 @@ int av_picture_crop(AVPicture *dst, const AVPicture *src, int y_shift; int x_shift; - if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB || !is_yuv_planar(&pix_fmt_info[pix_fmt])) + if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB) return -1; y_shift = desc->log2_chroma_h; x_shift = desc->log2_chroma_w; + if (is_yuv_planar(pix_fmt)) { dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + left_band; dst->data[1] = src->data[1] + ((top_band >> y_shift) * src->linesize[1]) + (left_band >> x_shift); dst->data[2] = src->data[2] + ((top_band >> y_shift) * src->linesize[2]) + (left_band >> x_shift); + } else{ + if(top_band % (1<<y_shift) || left_band % (1<<x_shift)) + return -1; + if(left_band) //FIXME add support for this too + return -1; + dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + left_band; + } dst->linesize[0] = src->linesize[0]; dst->linesize[1] = src->linesize[1]; @@ -833,7 +781,7 @@ int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width, int i, y; if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB || - !is_yuv_planar(&pix_fmt_info[pix_fmt])) return -1; + !is_yuv_planar(pix_fmt)) return -1; for (i = 0; i < 3; i++) { x_shift = i ? desc->log2_chroma_w : 0; |