summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Barbato <lu_zero@gentoo.org>2015-10-20 13:42:51 +0200
committerLuca Barbato <lu_zero@gentoo.org>2015-10-20 16:40:04 +0200
commit4e12e196868b8162c8fee41647a0ce409f56601d (patch)
tree19dd72914fe24dfc04bf435776ab324121a727e0
parentfe2b5632e0933394c28406e61097c6f28a1b6506 (diff)
wip
-rw-r--r--libavscale/avscale.c206
-rw-r--r--libavscale/avscale.h123
-rw-r--r--libavscale/internal.h80
3 files changed, 409 insertions, 0 deletions
diff --git a/libavscale/avscale.c b/libavscale/avscale.c
index e69de29bb2..f6d1bb1e2d 100644
--- a/libavscale/avscale.c
+++ b/libavscale/avscale.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2015 Kostya Shishkov
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.GPLv3. If not see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "libavutil/mem.h"
+#include "internal.h"
+
+static int prepare_next_stage(AVScaleContext *ctx, AVScaleFilterStage **stage,
+ const char *name)
+{
+ int ret;
+ AVScaleFilterStage *s;
+ int i;
+
+ s = av_mallocz(sizeof(*s));
+ if (!s)
+ return AVERROR(ENOMEM);
+
+ if (!ctx->head)
+ ctx->head = s;
+
+ for (i = 0; i < AVSCALE_MAX_COMPONENTS; i++) {
+ s->w[i] = ctx->cur_w >> ctx->cur_fmt.component_desc[i].h_sub_log;
+ s->h[i] = ctx->cur_h >> ctx->cur_fmt.component_desc[i].v_sub_log;
+ }
+
+ if ((ret = avscale_apply_kernel(ctx, name, s)) < 0)
+ goto err;
+
+ if (*stage)
+ (*stage)->next = s;
+ *stage = s;
+ return 0;
+err:
+ if (s->deinit)
+ s->deinit(s);
+ av_free(s);
+ return ret;
+}
+
+
+// FIXME: proof of a concept
+int avscale_build_chain(AVScaleContext *ctx, AVFrame *src, AVFrame *dst)
+{
+ AVScaleFilterStage *stage = 0;
+ int ret;
+
+ ctx->src_fmt = src->pixfmt;
+ ctx->dst_fmt = dst->pixfmt;
+ ctx->cur_w = src->width;
+ ctx->cur_h = src->height;
+ ctx->dst_w = dst->width;
+ ctx->dst_h = dst->height;
+ ctx->cur_fmt = *ctx->src_fmt;
+
+ if (ctx->src_fmt->colourspace == ctx->dst_fmt->colourspace) {
+ if ( ctx->src_fmt->component_desc[0].packed &&
+ !ctx->dst_fmt->component_desc[0].packed) {
+ if ((ret = prepare_next_stage(ctx, &stage, "rgbunp")) < 0)
+ return ret;
+ } else if (ctx->src_fmt->entry_size != ctx->dst_fmt->entry_size) {
+ if ((ret = prepare_next_stage(ctx, &stage, "rgbunp")) < 0)
+ return ret;
+ if (ctx->cur_w != ctx->dst_w || ctx->cur_h != ctx->dst_h)
+ if ((ret = prepare_next_stage(ctx, &stage, "scale")) < 0)
+ return ret;
+ if ((ret = prepare_next_stage(ctx, &stage, "rgbpck")) < 0)
+ return ret;
+ } else {
+ if ((ret = prepare_next_stage(ctx, &stage, "murder")) < 0)
+ return ret;
+ }
+ } else if (ctx->src_fmt->colourspace == AVS_RGB &&
+ ctx->dst_fmt->colourspace == AVS_YUV) {
+ if ((ret = prepare_next_stage(ctx, &stage, "rgbunp")) < 0)
+ return ret;
+ if (ctx->cur_w != ctx->dst_w || ctx->cur_h != ctx->dst_h) {
+ if ((ret = prepare_next_stage(ctx, &stage, "scale")) < 0)
+ return ret;
+ }
+ if ((ret = prepare_next_stage(ctx, &stage, "rgb2yuv")) < 0)
+ return ret;
+ } else
+ return AVERROR(ENOSYS);
+
+ ctx->tail = stage;
+
+ return 0;
+}
+
+uint8_t *avscale_get_component_ptr(AVFrame *src, int component_id)
+{ // currently a simple hack - it has to be extended for e.g. NV12
+ if (component_id >= src->pixfmt->components)
+ return 0;
+ if (!src->pixfmt->component_desc[component_id].packed)
+ return src->data[src->pixfmt->component_desc[component_id].plane];
+ else
+ return src->data[0] + src->pixfmt->component_desc[component_id].off;
+}
+
+int avscale_get_component_stride(AVFrame *src, int component_id)
+{
+ if (src->linesize[component_id])
+ return src->linesize[component_id];
+ else
+ return src->linesize[0];
+}
+
+int avscale_process_frame(AVScaleContext *ctx, AVFrame *srcf, AVFrame *dstf)
+{
+ int ret;
+ const AVScaleFilterStage *stage;
+
+ int i;
+
+ uint8_t *src[AVSCALE_MAX_COMPONENTS];
+ int sstride[AVSCALE_MAX_COMPONENTS];
+ uint8_t *dst[AVSCALE_MAX_COMPONENTS];
+ int dstride[AVSCALE_MAX_COMPONENTS];
+ int w[AVSCALE_MAX_COMPONENTS], h[AVSCALE_MAX_COMPONENTS];
+ uint8_t *src2[AVSCALE_MAX_COMPONENTS];
+ uint8_t *dst2[AVSCALE_MAX_COMPONENTS];
+
+ if (!ctx->head) {
+ if ((ret = avscale_build_chain(ctx, srcf, dstf)) < 0)
+ return ret;
+ av_log(ctx, AV_LOG_VERBOSE, "build chain ret = %d\n",
+ ret);
+ }
+
+ stage = ctx->head;
+
+ for (i = 0; i < AVSCALE_MAX_COMPONENTS; i++) {
+ src[i] = avscale_get_component_ptr(srcf, i);
+ sstride[i] = avscale_get_component_stride(srcf, i);
+ }
+
+ while (stage) {
+ for (i = 0; i < AVSCALE_MAX_COMPONENTS; i++) {
+ if (stage->src[i]) {
+ src[i] = stage->src[i];
+ sstride[i] = stage->src_stride[i];
+ }
+ if (stage->dst[i]) {
+ dst[i] = stage->dst[i];
+ dstride[i] = stage->dst_stride[i];
+ } else {
+ dst[i] = avscale_get_component_ptr(dstf, i);
+ dstride[i] = avscale_get_component_stride(dstf, i);
+ }
+ }
+ memcpy(src2, src, sizeof(src2));
+ memcpy(dst2, dst, sizeof(dst2));
+ if (stage->do_common)
+ stage->do_common(stage->do_common_ctx,
+ src2, sstride, dst2, dstride,
+ stage->w[0], stage->h[0]);
+ for (i = 0; i < AVSCALE_MAX_COMPONENTS; i++)
+ if (stage->do_component[i])
+ stage->do_component[i](stage->do_component_ctx[i],
+ src2[i], sstride[i],
+ dst2[i], dstride[i],
+ stage->w[i], stage->h[i]);
+
+ // this stage output buffers are likely to be next stage input
+ for (i = 0; i < AVSCALE_MAX_COMPONENTS; i++) {
+ src[i] = dst[i];
+ sstride[i] = dstride[i];
+ }
+ stage = stage->next;
+ }
+}
+
+void avscale_free_context(AVScaleContext *ctx)
+{
+ AVScaleFilterStage *s, *next;
+
+ if (!ctx)
+ return;
+
+ s = ctx->head;
+
+ while (s) {
+ next = s->next;
+ if (s->deinit)
+ s->deinit(s);
+ av_free(s);
+ s = next;
+ }
+ ctx->head = ctx->tail = 0;
+}
+
diff --git a/libavscale/avscale.h b/libavscale/avscale.h
new file mode 100644
index 0000000000..66f235ef6e
--- /dev/null
+++ b/libavscale/avscale.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2015 Kostya Shishkov
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.GPLv3. If not see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef AVSCALE_AVSCALE_H
+#define AVSCALE_AVSCALE_H
+
+#include <stdint.h>
+
+#include "libavutil/frame.h"
+#include "libavutil/pixdesc.h"
+
+#define AVSCALE_MAX_COMPONENTS 5
+
+typedef struct AVChromaton {
+ int plane;
+ int h_sub_log, v_sub_log; ///< subsampling information
+ int off; ///< offset to the starting element - e.g. 0 for Y, 1 for U and 3 for V in YUYV
+ int shift; ///< component shift for packed, e.g. for RGB565 it will be 11,5,0
+ int bpp; ///< bits per component, e.g. for packed RGB565 you'll have 5,6,5
+ int packed; ///< if component is packed with others (e.g. RGB24 - 1,1,1, NV12 - 0,1,1)
+ int next; ///< offset to the next element - e.g. 2 for Y and 4 for U and V in YUYV
+} AVChromaton;
+
+typedef struct AVPixelFormaton {
+ const char *name;
+
+ unsigned flags; // has alpha, uses BE order, uses palette etc
+ int entry_size; // might serve useful for packed formats - e.g. 4 or 2 bytes per entry
+
+ enum AVColorRange range;
+ enum AVColorPrimaries primaries;
+ enum AVColorTransferCharacteristic trc;
+ enum AVColorSpace colorspace;
+ enum AVChromaLocation chroma_location;
+
+ int nb_components;
+ AVChromaton component_desc[AVSCALE_MAX_COMPONENTS];
+} AVPixelFormaton;
+
+typedef struct AVScaleContext AVScaleContext;
+
+/**
+ * Allocate an empty AVScaleContext.
+ *
+ * This can be configured using AVOption and passed to avscale_init_context()
+ * or to avscale_build_chain() to initialize it early,
+ * or used as-is directly in avscale_process_frame().
+ *
+ * For filling see AVOptions, options.c.
+ *
+ * @return NULL on failure or a pointer to a newly allocated AVScaleContext
+ *
+ * @see avscale_init_context
+ * @see avscale_build_chain
+ * @see avscale_process_frame
+ * @see avscale_free_context
+ */
+AVScaleContext *avscale_alloc_context(void);
+
+/**
+ * Initialize the avscaler context by allocating the pixel format conversion
+ * chain and the scaling kernel.
+ *
+ * @param ctx The context to initialize.
+ *
+ * @return zero or positive value on success, a negative value on error
+ * @see avscale_build_chain
+ * @see avscale_process_frame
+ */
+int avscale_init_context(AVScaleContext *ctx);
+
+/**
+ * Free the avscaler context AVScaleContext.
+ * If AVScaleContext is NULL, then does nothing.
+ *
+ * @param ctx The context to free.
+ */
+void avscale_free_context(AVScaleContext *ctx);
+
+/**
+ * Build a conversion chain using the information contained in the
+ * source and destination AVFrame.
+ *
+ * @param ctx The config to configure
+ * @param src The source frame
+ * @param dst The destination frame
+ */
+int avscale_build_chain(AVScaleContext *ctx, AVFrame *src, AVFrame *dst);
+
+/**
+ * Scale the image provided by an AVFrame in src and put the result
+ * in dst.
+ *
+ * If the scaling context is already configured (e.g. by calling
+ * avscale_init_context()) or the frame pixel format and dimensions
+ * do not match the current context the function would reconfigure
+ * it before scaling.
+ *
+ * @param c The scaling context previously created
+ * with avscale_alloc_context()
+ * @param dst The destination frame
+ * @param src The source frame
+ * @return 0 on successo or AVERROR
+ */
+int avscale_process_frame(AVScaleContext *c, AVFrame *dst, AVFrame *src);
+
+#endif /* AVSCALE_AVSCALE_H */
+
diff --git a/libavscale/internal.h b/libavscale/internal.h
new file mode 100644
index 0000000000..4e8e47266e
--- /dev/null
+++ b/libavscale/internal.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015 Kostya Shishkov
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.GPLv3. If not see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef AVSCALE_INTERNAL_H
+#define AVSCALE_INTERNAL_H
+
+#include "libavutil/dict.h"
+#include "libavutil/log.h"
+
+#include "avscale.h"
+
+typedef struct AVScaleFilterStage {
+ void (*deinit)(struct AVScaleFilterStage *stage);
+ void (*do_common)(void *ctx,
+ uint8_t *src[AVSCALE_MAX_COMPONENTS],
+ int sstrides[AVSCALE_MAX_COMPONENTS],
+ uint8_t *dst[AVSCALE_MAX_COMPONENTS],
+ int dstrides[AVSCALE_MAX_COMPONENTS],
+ int w, int h);
+ void (*do_component[AVSCALE_MAX_COMPONENTS])(void *ctx,
+ uint8_t *src, int sstride,
+ uint8_t *dst, int dstride,
+ int w, int h);
+
+ void *do_common_ctx;
+ void *do_component_ctx[AVSCALE_MAX_COMPONENTS];
+
+ uint8_t *src[AVSCALE_MAX_COMPONENTS]; // null if current input should be used
+ int src_stride[AVSCALE_MAX_COMPONENTS];
+ uint8_t *dst[AVSCALE_MAX_COMPONENTS]; // null if default output should be used
+ int dst_stride[AVSCALE_MAX_COMPONENTS];
+ int w[AVSCALE_MAX_COMPONENTS], h[AVSCALE_MAX_COMPONENTS];
+
+ struct AVScaleFilterStage *next;
+} AVScaleFilterStage;
+
+struct AVScaleContext {
+ const AVClass *av_class;
+ const AVPixelFormaton *src_fmt, *dst_fmt;
+ AVPixelFormaton cur_fmt;
+ int cur_w, cur_h;
+ int dst_w, dst_h;
+ AVScaleFilterStage *head, *tail;
+};
+
+typedef struct AVScaleKernel {
+ const char *name; // for convenience
+
+ // init worker-specific contexts and set working functions
+ // e.g. for YUV2RGB it will init do_common_ctx with YUV2RGB tables
+ // and set do_common = convert_yuv2rgb
+ int (*kernel_init)(AVScaleContext *ctx, const struct AVScaleKernel *kern,
+ AVScaleFilterStage *stage,
+ AVDictionary *opts);
+} AVScaleKernel;
+
+const AVScaleKernel *avscale_find_kernel(const char *name);
+int avscale_apply_kernel(AVScaleContext *ctx, const char *name, AVScaleFilterStage *stage);
+
+uint8_t *avscale_get_component_ptr(AVFrame *src, int component_id);
+int avscale_get_component_stride(AVFrame *src, int component_id);
+
+
+
+#endif /* AVSCALE_INTERNAL_H */