summaryrefslogtreecommitdiff
path: root/libavfilter/drawutils.c
diff options
context:
space:
mode:
authorNicolas George <nicolas.george@normalesup.org>2012-02-23 11:07:01 +0100
committerNicolas George <nicolas.george@normalesup.org>2012-03-21 15:52:45 +0100
commit8ec0832743d73c5de4c4978ea5f65b54cfa07625 (patch)
tree6579fe38f1ca0bf247a428895a980d0ee0110dc9 /libavfilter/drawutils.c
parent87a72b9122e49f209c89fc83af2d51f5cdf44ce2 (diff)
drawutils: new API.
This new API stores useful data in a dedicated structure and has clearly delimited init functions. Hopefully, uses of the old API can be replaced quickly.
Diffstat (limited to 'libavfilter/drawutils.c')
-rw-r--r--libavfilter/drawutils.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/libavfilter/drawutils.c b/libavfilter/drawutils.c
index bf308a1c5c..0243a17a11 100644
--- a/libavfilter/drawutils.c
+++ b/libavfilter/drawutils.c
@@ -26,11 +26,15 @@ enum { RED = 0, GREEN, BLUE, ALPHA };
int ff_fill_rgba_map(uint8_t *rgba_map, enum PixelFormat pix_fmt)
{
switch (pix_fmt) {
+ case PIX_FMT_0RGB:
case PIX_FMT_ARGB: rgba_map[ALPHA] = 0; rgba_map[RED ] = 1; rgba_map[GREEN] = 2; rgba_map[BLUE ] = 3; break;
+ case PIX_FMT_0BGR:
case PIX_FMT_ABGR: rgba_map[ALPHA] = 0; rgba_map[BLUE ] = 1; rgba_map[GREEN] = 2; rgba_map[RED ] = 3; break;
+ case PIX_FMT_RGB0:
case PIX_FMT_RGBA:
case PIX_FMT_RGB24: rgba_map[RED ] = 0; rgba_map[GREEN] = 1; rgba_map[BLUE ] = 2; rgba_map[ALPHA] = 3; break;
case PIX_FMT_BGRA:
+ case PIX_FMT_BGR0:
case PIX_FMT_BGR24: rgba_map[BLUE ] = 0; rgba_map[GREEN] = 1; rgba_map[RED ] = 2; rgba_map[ALPHA] = 3; break;
default: /* unsupported */
return AVERROR(EINVAL);
@@ -120,3 +124,189 @@ void ff_copy_rectangle(uint8_t *dst[4], int dst_linesize[4],
}
}
}
+
+int ff_draw_init(FFDrawContext *draw, enum PixelFormat format, unsigned flags)
+{
+ const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[format];
+ const AVComponentDescriptor *c;
+ unsigned i, nb_planes = 0;
+ int pixelstep[MAX_PLANES] = { 0 };
+
+ if (desc->flags & ~(PIX_FMT_PLANAR | PIX_FMT_RGB))
+ return AVERROR(ENOSYS);
+ for (i = 0; i < desc->nb_components; i++) {
+ c = &desc->comp[i];
+ /* for now, only 8-bits formats */
+ if (c->depth_minus1 != 8 - 1)
+ return AVERROR(ENOSYS);
+ if (c->plane >= MAX_PLANES)
+ return AVERROR(ENOSYS);
+ /* strange interleaving */
+ if (pixelstep[c->plane] != 0 &&
+ pixelstep[c->plane] != c->step_minus1 + 1)
+ return AVERROR(ENOSYS);
+ pixelstep[c->plane] = c->step_minus1 + 1;
+ nb_planes = FFMAX(nb_planes, c->plane + 1);
+ }
+ if ((desc->log2_chroma_w || desc->log2_chroma_h) && nb_planes < 3)
+ return AVERROR(ENOSYS); /* exclude NV12 and NV21 */
+ memset(draw, 0, sizeof(*draw));
+ draw->desc = desc;
+ draw->format = format;
+ draw->nb_planes = nb_planes;
+ memcpy(draw->pixelstep, pixelstep, sizeof(draw->pixelstep));
+ if (nb_planes >= 3 && !(desc->flags & PIX_FMT_RGB)) {
+ draw->hsub[1] = draw->hsub[2] = draw->hsub_max = desc->log2_chroma_w;
+ draw->vsub[1] = draw->vsub[2] = draw->vsub_max = desc->log2_chroma_h;
+ }
+ return 0;
+}
+
+void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, uint8_t rgba[4])
+{
+ unsigned i;
+ uint8_t rgba_map[4];
+
+ if ((draw->desc->flags & PIX_FMT_RGB) && draw->nb_planes == 1 &&
+ ff_fill_rgba_map(rgba_map, draw->format) >= 0) {
+ for (i = 0; i < 4; i++)
+ color->comp[0].u8[rgba_map[i]] = rgba[i];
+ } else if (draw->nb_planes == 3 || draw->nb_planes == 4) {
+ /* assume YUV */
+ color->comp[0].u8[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
+ color->comp[1].u8[0] = RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0);
+ color->comp[2].u8[0] = RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0);
+ color->comp[3].u8[0] = rgba[3];
+ } else if (draw->format == PIX_FMT_GRAY8 || draw->format == PIX_FMT_GRAY8A) {
+ color->comp[0].u8[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
+ color->comp[1].u8[0] = rgba[3];
+ } else {
+ av_log(NULL, AV_LOG_WARNING,
+ "Color conversion not implemented for %s\n", draw->desc->name);
+ memset(color, 128, sizeof(*color));
+ }
+}
+
+static uint8_t *pointer_at(FFDrawContext *draw, uint8_t *data[], int linesize[],
+ int plane, int x, int y)
+{
+ return data[plane] +
+ (y >> draw->vsub[plane]) * linesize[plane] +
+ (x >> draw->hsub[plane]) * draw->pixelstep[plane];
+}
+
+void ff_copy_rectangle2(FFDrawContext *draw,
+ uint8_t *dst[], int dst_linesize[],
+ uint8_t *src[], int src_linesize[],
+ int dst_x, int dst_y, int src_x, int src_y,
+ int w, int h)
+{
+ int plane, y, wp, hp;
+ uint8_t *p, *q;
+
+ for (plane = 0; plane < draw->nb_planes; plane++) {
+ p = pointer_at(draw, src, src_linesize, plane, src_x, src_y);
+ q = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
+ wp = (w >> draw->hsub[plane]) * draw->pixelstep[plane];
+ hp = (h >> draw->vsub[plane]);
+ for (y = 0; y < hp; y++) {
+ memcpy(q, p, wp);
+ p += src_linesize[plane];
+ q += dst_linesize[plane];
+ }
+ }
+}
+
+void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color,
+ uint8_t *dst[], int dst_linesize[],
+ int dst_x, int dst_y, int w, int h)
+{
+ int plane, x, y, wp, hp;
+ uint8_t *p0, *p;
+
+ for (plane = 0; plane < draw->nb_planes; plane++) {
+ p0 = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
+ wp = (w >> draw->hsub[plane]);
+ hp = (h >> draw->vsub[plane]);
+ if (!hp)
+ return;
+ p = p0;
+ /* copy first line from color */
+ for (x = 0; x < wp; x++) {
+ memcpy(p, color->comp[plane].u8, draw->pixelstep[plane]);
+ p += draw->pixelstep[plane];
+ }
+ wp *= draw->pixelstep[plane];
+ /* copy next lines from first line */
+ p = p0 + dst_linesize[plane];
+ for (y = 1; y < hp; y++) {
+ memcpy(p, p0, wp);
+ p += dst_linesize[plane];
+ }
+ }
+}
+
+int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir,
+ int value)
+{
+ unsigned shift = sub_dir ? draw->vsub_max : draw->hsub_max;
+
+ if (!shift)
+ return value;
+ if (round_dir >= 0)
+ value += round_dir ? (1 << shift) - 1 : 1 << (shift - 1);
+ return (value >> shift) << shift;
+}
+
+AVFilterFormats *ff_draw_supported_pixel_formats(unsigned flags)
+{
+ enum PixelFormat i, pix_fmts[PIX_FMT_NB + 1];
+ unsigned n = 0;
+ FFDrawContext draw;
+
+ for (i = 0; i < PIX_FMT_NB; i++)
+ if (ff_draw_init(&draw, i, flags) >= 0)
+ pix_fmts[n++] = i;
+ pix_fmts[n++] = PIX_FMT_NONE;
+ return avfilter_make_format_list(pix_fmts);
+}
+
+#ifdef TEST
+
+#undef printf
+
+int main(void)
+{
+ enum PixelFormat f;
+ const AVPixFmtDescriptor *desc;
+ FFDrawContext draw;
+ FFDrawColor color;
+ int r, i;
+
+ for (f = 0; f < PIX_FMT_NB; f++) {
+ desc = &av_pix_fmt_descriptors[f];
+ if (!desc->name)
+ continue;
+ printf("Testing %s...%*s", desc->name,
+ (int)(16 - strlen(desc->name)), "");
+ r = ff_draw_init(&draw, f, 0);
+ if (r < 0) {
+ char buf[128];
+ av_strerror(r, buf, sizeof(buf));
+ printf("no: %s\n", buf);
+ continue;
+ }
+ ff_draw_color(&draw, &color, (uint8_t[]) { 1, 0, 0, 1 });
+ for (i = 0; i < sizeof(color); i++)
+ if (((uint8_t *)&color)[i] != 128)
+ break;
+ if (i == sizeof(color)) {
+ printf("fallback color\n");
+ continue;
+ }
+ printf("ok\n");
+ }
+ return 0;
+}
+
+#endif