[FFmpeg-devel] [PATCH v2 7/8] avfilter/spliter: Add VPE spliter filter
Zhang, Guiyong
Guiyong.Zhang at verisilicon.com
Sun May 31 09:29:50 EEST 2020
This filter splite one input to multi output with different picture data.
Signed-off-by: Qin.Wang <Qin.Wang at verisilicon.com>
---
configure | 1 +
libavfilter/Makefile | 1 +
libavfilter/allfilters.c | 1 +
libavfilter/vf_spliter_vpe.c | 319 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 322 insertions(+)
create mode 100755 libavfilter/vf_spliter_vpe.c
diff --git a/configure b/configure
index 0522f21..6146954 100755
--- a/configure
+++ b/configure
@@ -3642,6 +3642,7 @@ vpp_qsv_filter_select="qsvvpp"
xfade_opencl_filter_deps="opencl"
yadif_cuda_filter_deps="ffnvcodec"
yadif_cuda_filter_deps_any="cuda_nvcc cuda_llvm"
+spliter_vpe_filter_deps="vpe"
# examples
avio_list_dir_deps="avformat avutil"
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 5123540..104ec0c 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -466,6 +466,7 @@ OBJS-$(CONFIG_YAEPBLUR_FILTER) += vf_yaepblur.o
OBJS-$(CONFIG_ZMQ_FILTER) += f_zmq.o
OBJS-$(CONFIG_ZOOMPAN_FILTER) += vf_zoompan.o
OBJS-$(CONFIG_ZSCALE_FILTER) += vf_zscale.o
+OBJS-$(CONFIG_SPLITER_VPE_FILTER) += vf_spliter_vpe.o
OBJS-$(CONFIG_ALLRGB_FILTER) += vsrc_testsrc.o
OBJS-$(CONFIG_ALLYUV_FILTER) += vsrc_testsrc.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 1183e40..353a3ca 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -444,6 +444,7 @@ extern AVFilter ff_vf_yaepblur;
extern AVFilter ff_vf_zmq;
extern AVFilter ff_vf_zoompan;
extern AVFilter ff_vf_zscale;
+extern AVFilter ff_vf_spliter_vpe;
extern AVFilter ff_vsrc_allrgb;
extern AVFilter ff_vsrc_allyuv;
diff --git a/libavfilter/vf_spliter_vpe.c b/libavfilter/vf_spliter_vpe.c
new file mode 100755
index 0000000..0be2b09
--- /dev/null
+++ b/libavfilter/vf_spliter_vpe.c
@@ -0,0 +1,319 @@
+/*
+ * Verisilicon VPE H264 Decoder
+ *
+ * This file is part of FFmpeg.
+ *
+ * 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.
+ *
+ * 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <vpe/vpi_types.h>
+
+#include "avfilter.h"
+#include "filters.h"
+#include "internal.h"
+#include "libavutil/mem.h"
+#include "libavutil/opt.h"
+#include "libavutil/frame.h"
+#include "libavutil/buffer.h"
+#include "libavutil/internal.h"
+#include "libavutil/hwcontext.h"
+#include "libavutil/hwcontext_vpe.h"
+
+typedef struct SpliterVpeContext {
+ const AVClass *class;
+ int nb_outputs;
+ struct {
+ int enabled;
+ int out_index;
+ int flag;
+ int width;
+ int height;
+ struct {
+ int enabled;
+ int x;
+ int y;
+ int w;
+ int h;
+ } crop;
+ struct {
+ int enabled;
+ int w;
+ int h;
+ } scale;
+ } pic_info[PIC_INDEX_MAX_NUMBER];
+} SpliterVpeContext;
+
+static int spliter_vpe_out_config_props(AVFilterLink *outlink);
+
+static av_cold int spliter_vpe_init(AVFilterContext *ctx)
+{
+ SpliterVpeContext *s = ctx->priv;
+ int i, ret;
+
+ for (i = 0; i < s->nb_outputs; i++) {
+ char name[32];
+ AVFilterPad pad = { 0 };
+
+ snprintf(name, sizeof(name), "output%d", i);
+ pad.type = AVMEDIA_TYPE_VIDEO;
+ pad.name = av_strdup(name);
+ if (!pad.name) {
+ return AVERROR(ENOMEM);
+ }
+ pad.config_props = spliter_vpe_out_config_props;
+
+ if ((ret = ff_insert_outpad(ctx, i, &pad)) < 0) {
+ av_freep(&pad.name);
+ return ret;
+ }
+ }
+
+ for (i = 0; i < PIC_INDEX_MAX_NUMBER; i++) {
+ s->pic_info[i].out_index = -1;
+ }
+
+ return 0;
+}
+
+static av_cold void spliter_vpe_uninit(AVFilterContext *ctx)
+{
+ int i;
+
+ for (i = 0; i < ctx->nb_outputs; i++) {
+ av_freep(&ctx->output_pads[i].name);
+ }
+}
+
+static int spliter_vpe_config_props(AVFilterLink *inlink)
+{
+ AVHWFramesContext *hwframe_ctx;
+ AVVpeFramesContext *vpeframe_ctx;
+ VpiFrame *frame_hwctx;
+ AVFilterContext *dst = inlink->dst;
+ SpliterVpeContext *s = dst->priv;
+ int i;
+
+ hwframe_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
+ vpeframe_ctx = (AVVpeFramesContext *)hwframe_ctx->hwctx;
+ frame_hwctx = vpeframe_ctx->frame;
+
+ for (i = 0; i < PIC_INDEX_MAX_NUMBER; i++) {
+ s->pic_info[i].enabled = frame_hwctx->pic_info[i].enabled;
+ s->pic_info[i].flag = frame_hwctx->pic_info[i].flag;
+ s->pic_info[i].width = frame_hwctx->pic_info[i].width;
+ s->pic_info[i].height = frame_hwctx->pic_info[i].height;
+ }
+ s->pic_info[0].crop.enabled = frame_hwctx->pic_info[0].crop.enabled;
+ s->pic_info[0].crop.x = frame_hwctx->pic_info[0].crop.x;
+ s->pic_info[0].crop.y = frame_hwctx->pic_info[0].crop.y;
+ s->pic_info[0].crop.w = frame_hwctx->pic_info[0].crop.w;
+ s->pic_info[0].crop.h = frame_hwctx->pic_info[0].crop.h;
+
+ return 0;
+}
+
+static int spliter_vpe_out_config_props(AVFilterLink *outlink)
+{
+ AVFilterContext *src = outlink->src;
+ SpliterVpeContext *s = src->priv;
+ int out_index, pp_index, j;
+ AVHWFramesContext *hwframe_ctx;
+ AVVpeFramesContext *vpeframe_ctx;
+ VpiFrame *frame_hwctx;
+
+ if (!src->inputs[0]->hw_frames_ctx) {
+ // for ffplay
+ return 0;
+ }
+
+ outlink->hw_frames_ctx = av_buffer_ref(src->inputs[0]->hw_frames_ctx);
+ hwframe_ctx = (AVHWFramesContext *)outlink->hw_frames_ctx->data;
+ vpeframe_ctx = (AVVpeFramesContext *)hwframe_ctx->hwctx;
+ frame_hwctx = vpeframe_ctx->frame;
+ frame_hwctx->nb_outputs = s->nb_outputs;
+
+ for (out_index = 0; out_index < src->nb_outputs; out_index++) {
+ if (outlink == src->outputs[out_index]) {
+ break;
+ }
+ }
+ if (out_index == src->nb_outputs) {
+ av_log(src, AV_LOG_ERROR, "can't find output\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (pp_index = PIC_INDEX_MAX_NUMBER - 1; pp_index >= 0; pp_index--) {
+ if (s->pic_info[pp_index].enabled && !s->pic_info[pp_index].flag &&
+ s->pic_info[pp_index].out_index == -1) {
+ break;
+ }
+ }
+
+ for (j = 0; j < PIC_INDEX_MAX_NUMBER; j++) {
+ if (j == pp_index) {
+ continue;
+ }
+ if (frame_hwctx->pic_info[j].flag) {
+ continue;
+ }
+ frame_hwctx->pic_info[j].enabled = 0;
+ }
+
+ outlink->w = s->pic_info[pp_index].width;
+ outlink->h = s->pic_info[pp_index].height;
+ s->pic_info[pp_index].out_index = out_index;
+
+ return 0;
+}
+
+static int spliter_vpe_query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *fmts_list;
+ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_VPE,
+ AV_PIX_FMT_NONE };
+
+ fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list) {
+ return AVERROR(ENOMEM);
+ }
+
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int spliter_vpe_filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVHWFramesContext *hwframe_ctx;
+ AVVpeFramesContext *vpeframe_ctx;
+ AVFilterContext *ctx = inlink->dst;
+ SpliterVpeContext *s = ctx->priv;
+ int i, j, pp_index, ret = AVERROR_UNKNOWN;
+ VpiPicInfo *pic_info;
+ VpiFrame *vpi_frame;
+
+ hwframe_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
+ vpeframe_ctx = (AVVpeFramesContext *)hwframe_ctx->hwctx;
+
+ pp_index = 0;
+ for (i = 0; i < ctx->nb_outputs; i++) {
+ AVFrame *buf_out;
+
+ if (ff_outlink_get_status(ctx->outputs[i])) {
+ continue;
+ }
+
+ if (ctx->inputs[0]->hw_frames_ctx) {
+ for (pp_index = 0; pp_index < PIC_INDEX_MAX_NUMBER; pp_index++) {
+ if (i == s->pic_info[pp_index].out_index) {
+ break;
+ }
+ }
+ if (pp_index == PIC_INDEX_MAX_NUMBER) {
+ av_log(ctx, AV_LOG_ERROR, "can't find pp_index\n");
+ ret = AVERROR_UNKNOWN;
+ goto err_exit;
+ }
+ }
+
+ if (i > 0) {
+ buf_out = av_frame_alloc();
+ if (!buf_out) {
+ ret = AVERROR(ENOMEM);
+ goto err_exit;
+ }
+ ret = av_frame_ref(buf_out, frame);
+ if (ret < 0) {
+ goto err_exit;
+ }
+
+ for (j = 1; j < PIC_INDEX_MAX_NUMBER; j++) {
+ if (buf_out->buf[j]) {
+ av_buffer_unref(&buf_out->buf[j]);
+ }
+ }
+ for (j = 1; j < PIC_INDEX_MAX_NUMBER; j++) {
+ buf_out->buf[j] =
+ av_buffer_alloc(sizeof(vpeframe_ctx->pic_info_size));
+ if (buf_out->buf[j] == NULL) {
+ goto err_exit;
+ }
+ }
+
+ } else {
+ buf_out = frame;
+ }
+
+ for (j = 1; j < PIC_INDEX_MAX_NUMBER; j++) {
+ if (buf_out->buf[j] == NULL || buf_out->buf[j]->data == NULL)
+ continue;
+ pic_info = (VpiPicInfo *)buf_out->buf[j]->data;
+ if (j == pp_index) {
+ pic_info->enabled = 1;
+ } else {
+ pic_info->enabled = 0;
+ }
+ }
+
+ vpi_frame = (VpiFrame *)buf_out->data[0];
+ if (!vpi_frame)
+ goto err_exit;
+
+ vpi_frame->nb_outputs = s->nb_outputs;
+ ret = ff_filter_frame(ctx->outputs[i], buf_out);
+ if (ret < 0) {
+ goto err_exit;
+ }
+ }
+
+err_exit:
+ return ret;
+}
+
+#define OFFSET(x) offsetof(SpliterVpeContext, x)
+#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM)
+static const AVOption spliter_vpe_options[] = { { "outputs",
+ "set number of outputs",
+ OFFSET(nb_outputs),
+ AV_OPT_TYPE_INT,
+ { .i64 = 1 },
+ 1,
+ 4,
+ FLAGS },
+ { NULL } };
+
+AVFILTER_DEFINE_CLASS(spliter_vpe);
+
+static const AVFilterPad spliter_vpe_inputs[] =
+ { {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = spliter_vpe_config_props,
+ .filter_frame = spliter_vpe_filter_frame,
+ },
+ { NULL } };
+
+AVFilter ff_vf_spliter_vpe = {
+ .name = "spliter_vpe",
+ .description = NULL_IF_CONFIG_SMALL("Filter to split pictures generated by "
+ "vpe"),
+ .priv_size = sizeof(SpliterVpeContext),
+ .priv_class = &spliter_vpe_class,
+ .init = spliter_vpe_init,
+ .uninit = spliter_vpe_uninit,
+ .query_formats = spliter_vpe_query_formats,
+ .inputs = spliter_vpe_inputs,
+ .outputs = NULL,
+ .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
+ .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
+};
--
1.8.3.1
More information about the ffmpeg-devel
mailing list