diff options
author | Luca Barbato <lu_zero@gentoo.org> | 2015-10-20 13:42:51 +0200 |
---|---|---|
committer | Luca Barbato <lu_zero@gentoo.org> | 2015-10-20 16:40:04 +0200 |
commit | 4e12e196868b8162c8fee41647a0ce409f56601d (patch) | |
tree | 19dd72914fe24dfc04bf435776ab324121a727e0 | |
parent | fe2b5632e0933394c28406e61097c6f28a1b6506 (diff) |
wip
-rw-r--r-- | libavscale/avscale.c | 206 | ||||
-rw-r--r-- | libavscale/avscale.h | 123 | ||||
-rw-r--r-- | libavscale/internal.h | 80 |
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 */ |