mirror of
https://github.com/nyanmisaka/ffmpeg-rockchip.git
synced 2026-01-23 23:21:06 +01:00
lavf/rkrga: add RKRGA scale, vpp and overlay filter
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
This commit is contained in:
parent
570a2a53d8
commit
78421570bf
7 changed files with 2164 additions and 0 deletions
10
configure
vendored
10
configure
vendored
|
|
@ -346,6 +346,7 @@ External library support:
|
|||
--enable-omx enable OpenMAX IL code [no]
|
||||
--enable-omx-rpi enable OpenMAX IL code for Raspberry Pi [no]
|
||||
--enable-rkmpp enable Rockchip Media Process Platform code [no]
|
||||
--enable-rkrga enable Rockchip 2D Raster Graphic Acceleration code [no]
|
||||
--disable-v4l2-m2m disable V4L2 mem2mem code [autodetect]
|
||||
--disable-vaapi disable Video Acceleration API (mainly Unix/Intel) code [autodetect]
|
||||
--disable-vdpau disable Nvidia Video Decode and Presentation API for Unix code [autodetect]
|
||||
|
|
@ -1824,6 +1825,7 @@ EXTERNAL_LIBRARY_VERSION3_LIST="
|
|||
libvo_amrwbenc
|
||||
mbedtls
|
||||
rkmpp
|
||||
rkrga
|
||||
"
|
||||
|
||||
EXTERNAL_LIBRARY_GPLV3_LIST="
|
||||
|
|
@ -3765,6 +3767,7 @@ overlay_qsv_filter_deps="libmfx"
|
|||
overlay_qsv_filter_select="qsvvpp"
|
||||
overlay_vaapi_filter_deps="vaapi VAProcPipelineCaps_blend_flags"
|
||||
overlay_vulkan_filter_deps="vulkan spirv_compiler"
|
||||
overlay_rkrga_filter_deps="rkrga"
|
||||
owdenoise_filter_deps="gpl"
|
||||
pad_opencl_filter_deps="opencl"
|
||||
pan_filter_deps="swresample"
|
||||
|
|
@ -3786,6 +3789,7 @@ scale2ref_filter_deps="swscale"
|
|||
scale_filter_deps="swscale"
|
||||
scale_qsv_filter_deps="libmfx"
|
||||
scale_qsv_filter_select="qsvvpp"
|
||||
scale_rkrga_filter_deps="rkrga"
|
||||
scdet_filter_select="scene_sad"
|
||||
select_filter_select="scene_sad"
|
||||
sharpness_vaapi_filter_deps="vaapi"
|
||||
|
|
@ -3829,6 +3833,7 @@ scale_vt_filter_deps="videotoolbox"
|
|||
scale_vulkan_filter_deps="vulkan spirv_compiler"
|
||||
vpp_qsv_filter_deps="libmfx"
|
||||
vpp_qsv_filter_select="qsvvpp"
|
||||
vpp_rkrga_filter_deps="rkrga"
|
||||
xfade_opencl_filter_deps="opencl"
|
||||
xfade_vulkan_filter_deps="vulkan spirv_compiler"
|
||||
yadif_cuda_filter_deps="ffnvcodec"
|
||||
|
|
@ -6908,6 +6913,11 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/rk
|
|||
{ enabled libdrm ||
|
||||
die "ERROR: rkmpp requires --enable-libdrm"; }
|
||||
}
|
||||
enabled rkrga && require rkrga rga/RgaApi.h c_RkRgaBlit -lrga &&
|
||||
{ require rkrga rga/im2d.h querystring -lrga &&
|
||||
{ enabled rkmpp ||
|
||||
die "ERROR: rkrga requires --enable-rkmpp"; }
|
||||
}
|
||||
enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ OBJS-$(HAVE_THREADS) += pthread.o
|
|||
|
||||
# subsystems
|
||||
OBJS-$(CONFIG_QSVVPP) += qsvvpp.o
|
||||
OBJS-$(CONFIG_RKRGA) += rkrga_common.o
|
||||
OBJS-$(CONFIG_SCENE_SAD) += scene_sad.o
|
||||
OBJS-$(CONFIG_DNN) += dnn_filter_common.o
|
||||
include $(SRC_PATH)/libavfilter/dnn/Makefile
|
||||
|
|
@ -412,6 +413,7 @@ OBJS-$(CONFIG_OVERLAY_OPENCL_FILTER) += vf_overlay_opencl.o opencl.o \
|
|||
OBJS-$(CONFIG_OVERLAY_QSV_FILTER) += vf_overlay_qsv.o framesync.o
|
||||
OBJS-$(CONFIG_OVERLAY_VAAPI_FILTER) += vf_overlay_vaapi.o framesync.o vaapi_vpp.o
|
||||
OBJS-$(CONFIG_OVERLAY_VULKAN_FILTER) += vf_overlay_vulkan.o vulkan.o vulkan_filter.o
|
||||
OBJS-$(CONFIG_OVERLAY_RKRGA_FILTER) += vf_overlay_rkrga.o framesync.o
|
||||
OBJS-$(CONFIG_OWDENOISE_FILTER) += vf_owdenoise.o
|
||||
OBJS-$(CONFIG_PAD_FILTER) += vf_pad.o
|
||||
OBJS-$(CONFIG_PAD_OPENCL_FILTER) += vf_pad_opencl.o opencl.o opencl/pad.o
|
||||
|
|
@ -461,6 +463,7 @@ OBJS-$(CONFIG_SCALE_QSV_FILTER) += vf_vpp_qsv.o
|
|||
OBJS-$(CONFIG_SCALE_VAAPI_FILTER) += vf_scale_vaapi.o scale_eval.o vaapi_vpp.o
|
||||
OBJS-$(CONFIG_SCALE_VT_FILTER) += vf_scale_vt.o scale_eval.o
|
||||
OBJS-$(CONFIG_SCALE_VULKAN_FILTER) += vf_scale_vulkan.o vulkan.o vulkan_filter.o
|
||||
OBJS-$(CONFIG_SCALE_RKRGA_FILTER) += vf_vpp_rkrga.o scale_eval.o
|
||||
OBJS-$(CONFIG_SCALE2REF_FILTER) += vf_scale.o scale_eval.o
|
||||
OBJS-$(CONFIG_SCALE2REF_NPP_FILTER) += vf_scale_npp.o scale_eval.o
|
||||
OBJS-$(CONFIG_SCDET_FILTER) += vf_scdet.o
|
||||
|
|
@ -550,6 +553,7 @@ OBJS-$(CONFIG_VIF_FILTER) += vf_vif.o framesync.o
|
|||
OBJS-$(CONFIG_VIGNETTE_FILTER) += vf_vignette.o
|
||||
OBJS-$(CONFIG_VMAFMOTION_FILTER) += vf_vmafmotion.o framesync.o
|
||||
OBJS-$(CONFIG_VPP_QSV_FILTER) += vf_vpp_qsv.o
|
||||
OBJS-$(CONFIG_VPP_RKRGA_FILTER) += vf_vpp_rkrga.o scale_eval.o
|
||||
OBJS-$(CONFIG_VSTACK_FILTER) += vf_stack.o framesync.o
|
||||
OBJS-$(CONFIG_W3FDIF_FILTER) += vf_w3fdif.o
|
||||
OBJS-$(CONFIG_WAVEFORM_FILTER) += vf_waveform.o
|
||||
|
|
@ -648,6 +652,7 @@ SKIPHEADERS-$(CONFIG_LCMS2) += fflcms2.h
|
|||
SKIPHEADERS-$(CONFIG_LIBVIDSTAB) += vidstabutils.h
|
||||
|
||||
SKIPHEADERS-$(CONFIG_QSVVPP) += qsvvpp.h stack_internal.h
|
||||
SKIPHEADERS-$(CONFIG_RKRGA) += rkrga_common.h
|
||||
SKIPHEADERS-$(CONFIG_OPENCL) += opencl.h
|
||||
SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_vpp.h stack_internal.h
|
||||
SKIPHEADERS-$(CONFIG_VULKAN) += vulkan.h vulkan_filter.h
|
||||
|
|
|
|||
|
|
@ -387,6 +387,7 @@ extern const AVFilter ff_vf_overlay_qsv;
|
|||
extern const AVFilter ff_vf_overlay_vaapi;
|
||||
extern const AVFilter ff_vf_overlay_vulkan;
|
||||
extern const AVFilter ff_vf_overlay_cuda;
|
||||
extern const AVFilter ff_vf_overlay_rkrga;
|
||||
extern const AVFilter ff_vf_owdenoise;
|
||||
extern const AVFilter ff_vf_pad;
|
||||
extern const AVFilter ff_vf_pad_opencl;
|
||||
|
|
@ -432,6 +433,7 @@ extern const AVFilter ff_vf_scale_qsv;
|
|||
extern const AVFilter ff_vf_scale_vaapi;
|
||||
extern const AVFilter ff_vf_scale_vt;
|
||||
extern const AVFilter ff_vf_scale_vulkan;
|
||||
extern const AVFilter ff_vf_scale_rkrga;
|
||||
extern const AVFilter ff_vf_scale2ref;
|
||||
extern const AVFilter ff_vf_scale2ref_npp;
|
||||
extern const AVFilter ff_vf_scdet;
|
||||
|
|
@ -517,6 +519,7 @@ extern const AVFilter ff_vf_vif;
|
|||
extern const AVFilter ff_vf_vignette;
|
||||
extern const AVFilter ff_vf_vmafmotion;
|
||||
extern const AVFilter ff_vf_vpp_qsv;
|
||||
extern const AVFilter ff_vf_vpp_rkrga;
|
||||
extern const AVFilter ff_vf_vstack;
|
||||
extern const AVFilter ff_vf_w3fdif;
|
||||
extern const AVFilter ff_vf_waveform;
|
||||
|
|
|
|||
1179
libavfilter/rkrga_common.c
Normal file
1179
libavfilter/rkrga_common.c
Normal file
File diff suppressed because it is too large
Load diff
127
libavfilter/rkrga_common.h
Normal file
127
libavfilter/rkrga_common.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2023 NyanMisaka
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Rockchip RGA (2D Raster Graphic Acceleration) base function
|
||||
*/
|
||||
|
||||
#ifndef AVFILTER_RKRGA_COMMON_H
|
||||
#define AVFILTER_RKRGA_COMMON_H
|
||||
|
||||
#include <rga/RgaApi.h>
|
||||
#include <rga/im2d.h>
|
||||
|
||||
#include "avfilter.h"
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/hwcontext.h"
|
||||
#include "libavutil/hwcontext_rkmpp.h"
|
||||
|
||||
#define ALIGN_DOWN(a, b) ((a) & ~((b)-1))
|
||||
#define RK_RGA_YUV_ALIGN 2
|
||||
#define RK_RGA_AFBC_STRIDE_ALIGN 16
|
||||
|
||||
#define FF_INLINK_IDX(link) ((int)((link)->dstpad - (link)->dst->input_pads))
|
||||
#define FF_OUTLINK_IDX(link) ((int)((link)->srcpad - (link)->src->output_pads))
|
||||
|
||||
typedef struct RGAFrame {
|
||||
AVFrame *frame;
|
||||
rga_info_t info;
|
||||
struct RGAFrame *next;
|
||||
int queued;
|
||||
int locked;
|
||||
} RGAFrame;
|
||||
|
||||
typedef struct RGAFrameInfo {
|
||||
enum _Rga_SURF_FORMAT rga_fmt;
|
||||
enum AVPixelFormat pix_fmt;
|
||||
const AVPixFmtDescriptor *pix_desc;
|
||||
float bytes_pp;
|
||||
int act_x;
|
||||
int act_y;
|
||||
int act_w;
|
||||
int act_h;
|
||||
int uncompact_10b_msb;
|
||||
int rotate_mode;
|
||||
int blend_mode;
|
||||
int crop;
|
||||
int scheduler_core;
|
||||
int overlay_x;
|
||||
int overlay_y;
|
||||
} RGAFrameInfo;
|
||||
|
||||
typedef struct RKRGAContext {
|
||||
const AVClass *class;
|
||||
|
||||
int (*filter_frame) (AVFilterLink *outlink, AVFrame *frame);
|
||||
enum AVPixelFormat out_sw_format;
|
||||
|
||||
RGAFrame *src_frame_list;
|
||||
RGAFrame *dst_frame_list;
|
||||
RGAFrame *pat_frame_list;
|
||||
|
||||
AVBufferRef *pat_preproc_hwframes_ctx;
|
||||
RGAFrame *pat_preproc_frame_list;
|
||||
|
||||
RGAFrameInfo *in_rga_frame_infos;
|
||||
RGAFrameInfo out_rga_frame_info;
|
||||
|
||||
int scheduler_core;
|
||||
int async_depth;
|
||||
int afbc_out;
|
||||
|
||||
int has_rga2;
|
||||
int has_rga2l;
|
||||
int has_rga2e;
|
||||
int has_rga3;
|
||||
int is_rga2_used;
|
||||
int is_overlay_offset_valid;
|
||||
|
||||
int eof;
|
||||
int got_frame;
|
||||
|
||||
AVFifo *async_fifo;
|
||||
} RKRGAContext;
|
||||
|
||||
typedef struct RKRGAParam {
|
||||
int (*filter_frame)(AVFilterLink *outlink, AVFrame *frame);
|
||||
|
||||
enum AVPixelFormat out_sw_format;
|
||||
|
||||
int in_rotate_mode;
|
||||
int in_global_alpha;
|
||||
|
||||
int in_crop;
|
||||
int in_crop_x;
|
||||
int in_crop_y;
|
||||
int in_crop_w;
|
||||
int in_crop_h;
|
||||
|
||||
int overlay_x;
|
||||
int overlay_y;
|
||||
} RKRGAParam;
|
||||
|
||||
int ff_rkrga_init(AVFilterContext *avctx, RKRGAParam *param);
|
||||
int ff_rkrga_close(AVFilterContext *avctx);
|
||||
int ff_rkrga_filter_frame(RKRGAContext *r,
|
||||
AVFilterLink *inlink_src, AVFrame *picref_src,
|
||||
AVFilterLink *inlink_pat, AVFrame *picref_pat);
|
||||
|
||||
#endif /* AVFILTER_RKRGA_COMMON_H */
|
||||
363
libavfilter/vf_overlay_rkrga.c
Normal file
363
libavfilter/vf_overlay_rkrga.c
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* Copyright (c) 2023 NyanMisaka
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Rockchip RGA (2D Raster Graphic Acceleration) video compositor
|
||||
*/
|
||||
|
||||
#include "libavutil/common.h"
|
||||
#include "libavutil/eval.h"
|
||||
#include "libavutil/internal.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavutil/pixdesc.h"
|
||||
|
||||
#include "filters.h"
|
||||
#include "framesync.h"
|
||||
|
||||
#include "rkrga_common.h"
|
||||
|
||||
enum var_name {
|
||||
VAR_MAIN_W, VAR_MW,
|
||||
VAR_MAIN_H, VAR_MH,
|
||||
VAR_OVERLAY_W, VAR_OW,
|
||||
VAR_OVERLAY_H, VAR_OH,
|
||||
VAR_OVERLAY_X, VAR_OX,
|
||||
VAR_OVERLAY_Y, VAR_OY,
|
||||
VAR_VARS_NB
|
||||
};
|
||||
|
||||
typedef struct RGAOverlayContext {
|
||||
RKRGAContext rga;
|
||||
|
||||
FFFrameSync fs;
|
||||
|
||||
double var_values[VAR_VARS_NB];
|
||||
char *overlay_ox, *overlay_oy;
|
||||
int global_alpha;
|
||||
enum AVPixelFormat format;
|
||||
} RGAOverlayContext;
|
||||
|
||||
static const char *const var_names[] = {
|
||||
"main_w", "W", /* input width of the main layer */
|
||||
"main_h", "H", /* input height of the main layer */
|
||||
"overlay_w", "w", /* input width of the overlay layer */
|
||||
"overlay_h", "h", /* input height of the overlay layer */
|
||||
"overlay_x", "x", /* x position of the overlay layer inside of main */
|
||||
"overlay_y", "y", /* y position of the overlay layer inside of main */
|
||||
NULL
|
||||
};
|
||||
|
||||
static int eval_expr(AVFilterContext *ctx)
|
||||
{
|
||||
RGAOverlayContext *r = ctx->priv;
|
||||
double *var_values = r->var_values;
|
||||
int ret = 0;
|
||||
AVExpr *ox_expr = NULL, *oy_expr = NULL;
|
||||
AVExpr *ow_expr = NULL, *oh_expr = NULL;
|
||||
|
||||
#define PASS_EXPR(e, s) {\
|
||||
ret = av_expr_parse(&e, s, var_names, NULL, NULL, NULL, NULL, 0, ctx); \
|
||||
if (ret < 0) {\
|
||||
av_log(ctx, AV_LOG_ERROR, "Error when passing '%s'.\n", s);\
|
||||
goto release;\
|
||||
}\
|
||||
}
|
||||
PASS_EXPR(ox_expr, r->overlay_ox);
|
||||
PASS_EXPR(oy_expr, r->overlay_oy);
|
||||
PASS_EXPR(ow_expr, "overlay_w");
|
||||
PASS_EXPR(oh_expr, "overlay_h");
|
||||
#undef PASS_EXPR
|
||||
|
||||
var_values[VAR_OVERLAY_W] =
|
||||
var_values[VAR_OW] = av_expr_eval(ow_expr, var_values, NULL);
|
||||
var_values[VAR_OVERLAY_H] =
|
||||
var_values[VAR_OH] = av_expr_eval(oh_expr, var_values, NULL);
|
||||
|
||||
/* calc again in case ow is relative to oh */
|
||||
var_values[VAR_OVERLAY_W] =
|
||||
var_values[VAR_OW] = av_expr_eval(ow_expr, var_values, NULL);
|
||||
|
||||
var_values[VAR_OVERLAY_X] =
|
||||
var_values[VAR_OX] = av_expr_eval(ox_expr, var_values, NULL);
|
||||
var_values[VAR_OVERLAY_Y] =
|
||||
var_values[VAR_OY] = av_expr_eval(oy_expr, var_values, NULL);
|
||||
|
||||
/* calc again in case ox is relative to oy */
|
||||
var_values[VAR_OVERLAY_X] =
|
||||
var_values[VAR_OX] = av_expr_eval(ox_expr, var_values, NULL);
|
||||
|
||||
release:
|
||||
av_expr_free(ox_expr);
|
||||
av_expr_free(oy_expr);
|
||||
av_expr_free(ow_expr);
|
||||
av_expr_free(oh_expr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static av_cold int set_size_info(AVFilterContext *ctx,
|
||||
AVFilterLink *inlink_main,
|
||||
AVFilterLink *inlink_overlay,
|
||||
AVFilterLink *outlink)
|
||||
{
|
||||
RGAOverlayContext *r = ctx->priv;
|
||||
int ret;
|
||||
|
||||
if (inlink_main->w < 2 || inlink_main->w > 8192 ||
|
||||
inlink_main->h < 2 || inlink_main->h > 8192 ||
|
||||
inlink_overlay->w < 2 || inlink_overlay->w > 8192 ||
|
||||
inlink_overlay->h < 2 || inlink_overlay->h > 8192) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Supported input size is range from 2x2 ~ 8192x8192\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
r->var_values[VAR_MAIN_W] =
|
||||
r->var_values[VAR_MW] = inlink_main->w;
|
||||
r->var_values[VAR_MAIN_H] =
|
||||
r->var_values[VAR_MH] = inlink_main->h;
|
||||
|
||||
r->var_values[VAR_OVERLAY_W] = inlink_overlay->w;
|
||||
r->var_values[VAR_OVERLAY_H] = inlink_overlay->h;
|
||||
|
||||
if ((ret = eval_expr(ctx)) < 0)
|
||||
return ret;
|
||||
|
||||
outlink->w = r->var_values[VAR_MW];
|
||||
outlink->h = r->var_values[VAR_MH];
|
||||
if (outlink->w < 2 || outlink->w > 8128 ||
|
||||
outlink->h < 2 || outlink->h > 8128) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Supported output size is range from 2x2 ~ 8128x8128\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if (inlink_main->sample_aspect_ratio.num)
|
||||
outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink_main->w,
|
||||
outlink->w * inlink_main->h},
|
||||
inlink_main->sample_aspect_ratio);
|
||||
else
|
||||
outlink->sample_aspect_ratio = inlink_main->sample_aspect_ratio;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static av_cold int rgaoverlay_config_props(AVFilterLink *outlink)
|
||||
{
|
||||
AVFilterContext *ctx = outlink->src;
|
||||
RGAOverlayContext *r = ctx->priv;
|
||||
AVFilterLink *inlink_main = ctx->inputs[0];
|
||||
AVFilterLink *inlink_overlay = ctx->inputs[1];
|
||||
AVHWFramesContext *frames_ctx_main;
|
||||
AVHWFramesContext *frames_ctx_overlay;
|
||||
enum AVPixelFormat in_format_main;
|
||||
enum AVPixelFormat in_format_overlay;
|
||||
enum AVPixelFormat out_format;
|
||||
int ret;
|
||||
|
||||
RKRGAParam param = { NULL };
|
||||
|
||||
if (!inlink_main->hw_frames_ctx) {
|
||||
av_log(ctx, AV_LOG_ERROR, "No hw context provided on main input\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
frames_ctx_main = (AVHWFramesContext *)inlink_main->hw_frames_ctx->data;
|
||||
in_format_main = frames_ctx_main->sw_format;
|
||||
out_format = (r->format == AV_PIX_FMT_NONE) ? in_format_main : r->format;
|
||||
|
||||
if (!inlink_overlay->hw_frames_ctx) {
|
||||
av_log(ctx, AV_LOG_ERROR, "No hw context provided on overlay input\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
frames_ctx_overlay = (AVHWFramesContext *)inlink_overlay->hw_frames_ctx->data;
|
||||
in_format_overlay = frames_ctx_overlay->sw_format;
|
||||
|
||||
ret = set_size_info(ctx, inlink_main, inlink_overlay, outlink);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
param.filter_frame = NULL;
|
||||
param.out_sw_format = out_format;
|
||||
param.in_global_alpha = r->global_alpha;
|
||||
param.overlay_x = r->var_values[VAR_OX];
|
||||
param.overlay_y = r->var_values[VAR_OY];
|
||||
|
||||
ret = ff_rkrga_init(ctx, ¶m);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s + w:%d h:%d fmt:%s (x:%d y:%d) -> w:%d h:%d fmt:%s\n",
|
||||
inlink_main->w, inlink_main->h, av_get_pix_fmt_name(in_format_main),
|
||||
inlink_overlay->w, inlink_overlay->h, av_get_pix_fmt_name(in_format_overlay),
|
||||
param.overlay_x, param.overlay_y, outlink->w, outlink->h, av_get_pix_fmt_name(out_format));
|
||||
|
||||
ret = ff_framesync_init_dualinput(&r->fs, ctx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
r->fs.time_base = outlink->time_base = inlink_main->time_base;
|
||||
|
||||
ret = ff_framesync_configure(&r->fs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rgaoverlay_on_event(FFFrameSync *fs)
|
||||
{
|
||||
AVFilterContext *ctx = fs->parent;
|
||||
AVFilterLink *inlink_main = ctx->inputs[0];
|
||||
AVFilterLink *inlink_overlay = ctx->inputs[1];
|
||||
AVFrame *in_main = NULL, *in_overlay = NULL;
|
||||
int ret;
|
||||
|
||||
RGAOverlayContext *r = ctx->priv;
|
||||
|
||||
ret = ff_framesync_get_frame(fs, 0, &in_main, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = ff_framesync_get_frame(fs, 1, &in_overlay, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!in_main)
|
||||
return AVERROR_BUG;
|
||||
|
||||
return ff_rkrga_filter_frame(&r->rga,
|
||||
inlink_main, in_main,
|
||||
inlink_overlay, in_overlay);
|
||||
}
|
||||
|
||||
static av_cold int rgaoverlay_init(AVFilterContext *ctx)
|
||||
{
|
||||
RGAOverlayContext *r = ctx->priv;
|
||||
|
||||
r->fs.on_event = &rgaoverlay_on_event;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static av_cold void rgaoverlay_uninit(AVFilterContext *ctx)
|
||||
{
|
||||
RGAOverlayContext *r = ctx->priv;
|
||||
|
||||
ff_framesync_uninit(&r->fs);
|
||||
|
||||
ff_rkrga_close(ctx);
|
||||
}
|
||||
|
||||
static int rgaoverlay_activate(AVFilterContext *ctx)
|
||||
{
|
||||
RGAOverlayContext *r = ctx->priv;
|
||||
AVFilterLink *inlink_main = ctx->inputs[0];
|
||||
AVFilterLink *inlink_overlay = ctx->inputs[1];
|
||||
AVFilterLink *outlink = ctx->outputs[0];
|
||||
int i, ret;
|
||||
|
||||
ret = ff_framesync_activate(&r->fs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (r->fs.eof) {
|
||||
r->rga.eof = 1;
|
||||
goto eof;
|
||||
}
|
||||
|
||||
if (!r->rga.got_frame) {
|
||||
for (i = 0; i < ctx->nb_inputs; i++) {
|
||||
if (!ff_inlink_check_available_frame(ctx->inputs[i])) {
|
||||
FF_FILTER_FORWARD_WANTED(outlink, ctx->inputs[i]);
|
||||
}
|
||||
}
|
||||
return FFERROR_NOT_READY;
|
||||
} else
|
||||
r->rga.got_frame = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
eof:
|
||||
ff_rkrga_filter_frame(&r->rga,
|
||||
inlink_main, NULL,
|
||||
inlink_overlay, NULL);
|
||||
ff_outlink_set_status(outlink, AVERROR_EOF, AV_NOPTS_VALUE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define OFFSET(x) offsetof(RGAOverlayContext, x)
|
||||
#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
|
||||
|
||||
static const AVOption rgaoverlay_options[] = {
|
||||
{ "x", "Overlay x position", OFFSET(overlay_ox), AV_OPT_TYPE_STRING, { .str = "0" }, 0, 0, .flags = FLAGS },
|
||||
{ "y", "Overlay y position", OFFSET(overlay_oy), AV_OPT_TYPE_STRING, { .str = "0" }, 0, 0, .flags = FLAGS },
|
||||
{ "alpha", "Overlay global alpha", OFFSET(global_alpha), AV_OPT_TYPE_INT, { .i64 = 255 }, 0, 255, .flags = FLAGS },
|
||||
{ "format", "Output video pixel format", OFFSET(format), AV_OPT_TYPE_PIXEL_FMT, { .i64 = AV_PIX_FMT_NONE }, INT_MIN, INT_MAX, .flags = FLAGS },
|
||||
{ "eof_action", "Action to take when encountering EOF from secondary input ",
|
||||
OFFSET(fs.opt_eof_action), AV_OPT_TYPE_INT, { .i64 = EOF_ACTION_REPEAT },
|
||||
EOF_ACTION_REPEAT, EOF_ACTION_PASS, .flags = FLAGS, "eof_action" },
|
||||
{ "repeat", "Repeat the previous frame.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_REPEAT }, .flags = FLAGS, "eof_action" },
|
||||
{ "endall", "End both streams.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_ENDALL }, .flags = FLAGS, "eof_action" },
|
||||
{ "pass", "Pass through the main input.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_PASS }, .flags = FLAGS, "eof_action" },
|
||||
{ "shortest", "Force termination when the shortest input terminates", OFFSET(fs.opt_shortest), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
|
||||
{ "repeatlast", "Repeat overlay of the last overlay frame", OFFSET(fs.opt_repeatlast), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
|
||||
{ "core", "Set multicore RGA scheduler core [use with caution]", OFFSET(rga.scheduler_core), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, 0, INT_MAX, FLAGS, "core" },
|
||||
{ "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, "core" },
|
||||
{ "rga3_core0", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, "core" }, /* RGA3_SCHEDULER_CORE0 */
|
||||
{ "rga3_core1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, FLAGS, "core" }, /* RGA3_SCHEDULER_CORE1 */
|
||||
{ "rga2_core0", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 4 }, 0, 0, FLAGS, "core" }, /* RGA2_SCHEDULER_CORE0 */
|
||||
{ "async_depth", "Set the internal parallelization depth", OFFSET(rga.async_depth), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 4, .flags = FLAGS },
|
||||
{ "afbc", "Enable AFBC (Arm Frame Buffer Compression) to save bandwidth", OFFSET(rga.afbc_out), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = FLAGS },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
FRAMESYNC_DEFINE_CLASS(rgaoverlay, RGAOverlayContext, fs);
|
||||
|
||||
static const AVFilterPad rgaoverlay_inputs[] = {
|
||||
{
|
||||
.name = "main",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
},
|
||||
{
|
||||
.name = "overlay",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
},
|
||||
};
|
||||
|
||||
static const AVFilterPad rgaoverlay_outputs[] = {
|
||||
{
|
||||
.name = "default",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
.config_props = rgaoverlay_config_props,
|
||||
},
|
||||
};
|
||||
|
||||
const AVFilter ff_vf_overlay_rkrga = {
|
||||
.name = "overlay_rkrga",
|
||||
.description = NULL_IF_CONFIG_SMALL("Rockchip RGA (2D Raster Graphic Acceleration) video compositor"),
|
||||
.priv_size = sizeof(RGAOverlayContext),
|
||||
.priv_class = &rgaoverlay_class,
|
||||
.init = rgaoverlay_init,
|
||||
.uninit = rgaoverlay_uninit,
|
||||
.activate = rgaoverlay_activate,
|
||||
FILTER_INPUTS(rgaoverlay_inputs),
|
||||
FILTER_OUTPUTS(rgaoverlay_outputs),
|
||||
FILTER_SINGLE_PIXFMT(AV_PIX_FMT_DRM_PRIME),
|
||||
.preinit = rgaoverlay_framesync_preinit,
|
||||
.flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
|
||||
};
|
||||
477
libavfilter/vf_vpp_rkrga.c
Normal file
477
libavfilter/vf_vpp_rkrga.c
Normal file
|
|
@ -0,0 +1,477 @@
|
|||
/*
|
||||
* Copyright (c) 2023 NyanMisaka
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Rockchip RGA (2D Raster Graphic Acceleration) video post-process (scale/crop/transpose)
|
||||
*/
|
||||
|
||||
#include "config_components.h"
|
||||
|
||||
#include "libavutil/common.h"
|
||||
#include "libavutil/eval.h"
|
||||
#include "libavutil/internal.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavutil/pixdesc.h"
|
||||
|
||||
#include "filters.h"
|
||||
#include "scale_eval.h"
|
||||
#include "transpose.h"
|
||||
|
||||
#include "rkrga_common.h"
|
||||
|
||||
typedef struct RGAVppContext {
|
||||
RKRGAContext rga;
|
||||
|
||||
enum AVPixelFormat format;
|
||||
int transpose;
|
||||
int force_original_aspect_ratio;
|
||||
int force_divisible_by;
|
||||
int scheduler_core;
|
||||
|
||||
int in_rotate_mode;
|
||||
|
||||
char *ow, *oh;
|
||||
char *cx, *cy, *cw, *ch;
|
||||
int crop;
|
||||
|
||||
int act_x, act_y;
|
||||
int act_w, act_h;
|
||||
} RGAVppContext;
|
||||
|
||||
static const char *const var_names[] = {
|
||||
"iw", "in_w",
|
||||
"ih", "in_h",
|
||||
"ow", "out_w", "w",
|
||||
"oh", "out_h", "h",
|
||||
"cw",
|
||||
"ch",
|
||||
"cx",
|
||||
"cy",
|
||||
"a", "dar",
|
||||
"sar",
|
||||
NULL
|
||||
};
|
||||
|
||||
enum var_name {
|
||||
VAR_IW, VAR_IN_W,
|
||||
VAR_IH, VAR_IN_H,
|
||||
VAR_OW, VAR_OUT_W, VAR_W,
|
||||
VAR_OH, VAR_OUT_H, VAR_H,
|
||||
VAR_CW,
|
||||
VAR_CH,
|
||||
VAR_CX,
|
||||
VAR_CY,
|
||||
VAR_A, VAR_DAR,
|
||||
VAR_SAR,
|
||||
VAR_VARS_NB
|
||||
};
|
||||
|
||||
static av_cold int eval_expr(AVFilterContext *ctx,
|
||||
int *ret_w, int *ret_h,
|
||||
int *ret_cx, int *ret_cy,
|
||||
int *ret_cw, int *ret_ch)
|
||||
{
|
||||
#define PASS_EXPR(e, s) {\
|
||||
if (s) {\
|
||||
ret = av_expr_parse(&e, s, var_names, NULL, NULL, NULL, NULL, 0, ctx); \
|
||||
if (ret < 0) { \
|
||||
av_log(ctx, AV_LOG_ERROR, "Error when passing '%s'.\n", s); \
|
||||
goto release; \
|
||||
} \
|
||||
}\
|
||||
}
|
||||
#define CALC_EXPR(e, v, i, d) {\
|
||||
if (e)\
|
||||
i = v = av_expr_eval(e, var_values, NULL); \
|
||||
else\
|
||||
i = v = d;\
|
||||
}
|
||||
RGAVppContext *r = ctx->priv;
|
||||
double var_values[VAR_VARS_NB] = { NAN };
|
||||
AVExpr *w_expr = NULL, *h_expr = NULL;
|
||||
AVExpr *cw_expr = NULL, *ch_expr = NULL;
|
||||
AVExpr *cx_expr = NULL, *cy_expr = NULL;
|
||||
int ret = 0;
|
||||
|
||||
PASS_EXPR(cw_expr, r->cw);
|
||||
PASS_EXPR(ch_expr, r->ch);
|
||||
|
||||
PASS_EXPR(w_expr, r->ow);
|
||||
PASS_EXPR(h_expr, r->oh);
|
||||
|
||||
PASS_EXPR(cx_expr, r->cx);
|
||||
PASS_EXPR(cy_expr, r->cy);
|
||||
|
||||
var_values[VAR_IW] =
|
||||
var_values[VAR_IN_W] = ctx->inputs[0]->w;
|
||||
|
||||
var_values[VAR_IH] =
|
||||
var_values[VAR_IN_H] = ctx->inputs[0]->h;
|
||||
|
||||
var_values[VAR_A] = (double)var_values[VAR_IN_W] / var_values[VAR_IN_H];
|
||||
var_values[VAR_SAR] = ctx->inputs[0]->sample_aspect_ratio.num ?
|
||||
(double)ctx->inputs[0]->sample_aspect_ratio.num / ctx->inputs[0]->sample_aspect_ratio.den : 1;
|
||||
var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR];
|
||||
|
||||
/* crop params */
|
||||
CALC_EXPR(cw_expr, var_values[VAR_CW], *ret_cw, var_values[VAR_IW]);
|
||||
CALC_EXPR(ch_expr, var_values[VAR_CH], *ret_ch, var_values[VAR_IH]);
|
||||
|
||||
/* calc again in case cw is relative to ch */
|
||||
CALC_EXPR(cw_expr, var_values[VAR_CW], *ret_cw, var_values[VAR_IW]);
|
||||
|
||||
CALC_EXPR(w_expr,
|
||||
var_values[VAR_OUT_W] = var_values[VAR_OW] = var_values[VAR_W],
|
||||
*ret_w, var_values[VAR_CW]);
|
||||
CALC_EXPR(h_expr,
|
||||
var_values[VAR_OUT_H] = var_values[VAR_OH] = var_values[VAR_H],
|
||||
*ret_h, var_values[VAR_CH]);
|
||||
|
||||
/* calc again in case ow is relative to oh */
|
||||
CALC_EXPR(w_expr,
|
||||
var_values[VAR_OUT_W] = var_values[VAR_OW] = var_values[VAR_W],
|
||||
*ret_w, var_values[VAR_CW]);
|
||||
|
||||
CALC_EXPR(cx_expr, var_values[VAR_CX], *ret_cx, (var_values[VAR_IW] - var_values[VAR_OW]) / 2);
|
||||
CALC_EXPR(cy_expr, var_values[VAR_CY], *ret_cy, (var_values[VAR_IH] - var_values[VAR_OH]) / 2);
|
||||
|
||||
/* calc again in case cx is relative to cy */
|
||||
CALC_EXPR(cx_expr, var_values[VAR_CX], *ret_cx, (var_values[VAR_IW] - var_values[VAR_OW]) / 2);
|
||||
|
||||
r->crop = (*ret_cw != var_values[VAR_IW]) || (*ret_ch != var_values[VAR_IH]);
|
||||
|
||||
release:
|
||||
av_expr_free(w_expr);
|
||||
av_expr_free(h_expr);
|
||||
av_expr_free(cw_expr);
|
||||
av_expr_free(ch_expr);
|
||||
av_expr_free(cx_expr);
|
||||
av_expr_free(cy_expr);
|
||||
#undef PASS_EXPR
|
||||
#undef CALC_EXPR
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static av_cold int set_size_info(AVFilterContext *ctx,
|
||||
AVFilterLink *inlink,
|
||||
AVFilterLink *outlink)
|
||||
{
|
||||
RGAVppContext *r = ctx->priv;
|
||||
int w, h, ret;
|
||||
|
||||
if (inlink->w < 2 || inlink->w > 8192 ||
|
||||
inlink->h < 2 || inlink->h > 8192) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Supported input size is range from 2x2 ~ 8192x8192\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if ((ret = eval_expr(ctx, &w, &h, &r->act_x, &r->act_y, &r->act_w, &r->act_h)) < 0)
|
||||
return ret;
|
||||
|
||||
r->act_x = FFMAX(FFMIN(r->act_x, inlink->w), 0);
|
||||
r->act_y = FFMAX(FFMIN(r->act_y, inlink->h), 0);
|
||||
r->act_w = FFMAX(FFMIN(r->act_w, inlink->w), 0);
|
||||
r->act_h = FFMAX(FFMIN(r->act_h, inlink->h), 0);
|
||||
|
||||
r->act_x = FFMIN(r->act_x, inlink->w - r->act_w);
|
||||
r->act_y = FFMIN(r->act_y, inlink->h - r->act_h);
|
||||
r->act_w = FFMIN(r->act_w, inlink->w - r->act_x);
|
||||
r->act_h = FFMIN(r->act_h, inlink->h - r->act_y);
|
||||
|
||||
ff_scale_adjust_dimensions(inlink, &w, &h,
|
||||
r->force_original_aspect_ratio, r->force_divisible_by);
|
||||
|
||||
if (((int64_t)h * inlink->w) > INT_MAX ||
|
||||
((int64_t)w * inlink->h) > INT_MAX) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
outlink->w = w;
|
||||
outlink->h = h;
|
||||
if (outlink->w < 2 || outlink->w > 8128 ||
|
||||
outlink->h < 2 || outlink->h > 8128) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Supported output size is range from 2x2 ~ 8128x8128\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if (inlink->sample_aspect_ratio.num)
|
||||
outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink->w,
|
||||
outlink->w * inlink->h},
|
||||
inlink->sample_aspect_ratio);
|
||||
else
|
||||
outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
|
||||
|
||||
if (r->transpose >= 0) {
|
||||
switch (r->transpose) {
|
||||
case TRANSPOSE_CCLOCK_FLIP:
|
||||
r->in_rotate_mode = 0x07 | (0x01 << 4); /* HAL_TRANSFORM_ROT_270 | (HAL_TRANSFORM_FLIP_H << 4) */
|
||||
FFSWAP(int, outlink->w, outlink->h);
|
||||
FFSWAP(int, outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den);
|
||||
break;
|
||||
case TRANSPOSE_CLOCK:
|
||||
r->in_rotate_mode = 0x04; /* HAL_TRANSFORM_ROT_90 */
|
||||
FFSWAP(int, outlink->w, outlink->h);
|
||||
FFSWAP(int, outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den);
|
||||
break;
|
||||
case TRANSPOSE_CCLOCK:
|
||||
r->in_rotate_mode = 0x07; /* HAL_TRANSFORM_ROT_270 */
|
||||
FFSWAP(int, outlink->w, outlink->h);
|
||||
FFSWAP(int, outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den);
|
||||
break;
|
||||
case TRANSPOSE_CLOCK_FLIP:
|
||||
r->in_rotate_mode = 0x04 | (0x01 << 4); /* HAL_TRANSFORM_ROT_90 | (HAL_TRANSFORM_FLIP_H << 4) */
|
||||
FFSWAP(int, outlink->w, outlink->h);
|
||||
FFSWAP(int, outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den);
|
||||
break;
|
||||
case TRANSPOSE_REVERSAL:
|
||||
r->in_rotate_mode = 0x03; /* HAL_TRANSFORM_ROT_180 */
|
||||
break;
|
||||
case TRANSPOSE_HFLIP:
|
||||
r->in_rotate_mode = 0x01; /* HAL_TRANSFORM_FLIP_H */
|
||||
break;
|
||||
case TRANSPOSE_VFLIP:
|
||||
r->in_rotate_mode = 0x02; /* HAL_TRANSFORM_FLIP_V */
|
||||
break;
|
||||
default:
|
||||
av_log(ctx, AV_LOG_ERROR, "Failed to set transpose mode to %d\n", r->transpose);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static av_cold int rgavpp_config_props(AVFilterLink *outlink)
|
||||
{
|
||||
AVFilterContext *ctx = outlink->src;
|
||||
RGAVppContext *r = ctx->priv;
|
||||
AVFilterLink *inlink = ctx->inputs[0];
|
||||
AVHWFramesContext *in_frames_ctx;
|
||||
enum AVPixelFormat in_format;
|
||||
enum AVPixelFormat out_format;
|
||||
RKRGAParam param = { NULL };
|
||||
int ret;
|
||||
|
||||
if (!inlink->hw_frames_ctx) {
|
||||
av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
in_frames_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
|
||||
in_format = in_frames_ctx->sw_format;
|
||||
out_format = (r->format == AV_PIX_FMT_NONE) ? in_format : r->format;
|
||||
|
||||
ret = set_size_info(ctx, inlink, outlink);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
param.filter_frame = NULL;
|
||||
param.out_sw_format = out_format;
|
||||
param.in_rotate_mode = r->in_rotate_mode;
|
||||
param.in_crop = r->crop;
|
||||
param.in_crop_x = r->act_x;
|
||||
param.in_crop_y = r->act_y;
|
||||
param.in_crop_w = r->act_w;
|
||||
param.in_crop_h = r->act_h;
|
||||
|
||||
ret = ff_rkrga_init(ctx, ¶m);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s -> w:%d h:%d fmt:%s\n",
|
||||
inlink->w, inlink->h, av_get_pix_fmt_name(in_format),
|
||||
outlink->w, outlink->h, av_get_pix_fmt_name(out_format));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rgavpp_activate(AVFilterContext *ctx)
|
||||
{
|
||||
AVFilterLink *inlink = ctx->inputs[0];
|
||||
AVFilterLink *outlink = ctx->outputs[0];
|
||||
RGAVppContext *r = ctx->priv;
|
||||
AVFrame *in = NULL;
|
||||
int ret, status = 0;
|
||||
int64_t pts = AV_NOPTS_VALUE;
|
||||
|
||||
FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
|
||||
|
||||
if (!r->rga.eof) {
|
||||
ret = ff_inlink_consume_frame(inlink, &in);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {
|
||||
if (status == AVERROR_EOF) {
|
||||
r->rga.eof = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (in || r->rga.eof) {
|
||||
ret = ff_rkrga_filter_frame(&r->rga, inlink, in, NULL, NULL);
|
||||
av_frame_free(&in);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (!r->rga.got_frame)
|
||||
goto not_ready;
|
||||
|
||||
if (r->rga.eof)
|
||||
goto eof;
|
||||
|
||||
if (r->rga.got_frame) {
|
||||
r->rga.got_frame = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
not_ready:
|
||||
if (r->rga.eof)
|
||||
goto eof;
|
||||
|
||||
FF_FILTER_FORWARD_WANTED(outlink, inlink);
|
||||
return FFERROR_NOT_READY;
|
||||
|
||||
eof:
|
||||
pts = av_rescale_q(pts, inlink->time_base, outlink->time_base);
|
||||
ff_outlink_set_status(outlink, status, pts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static av_cold int rgavpp_init(AVFilterContext *ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static av_cold void rgavpp_uninit(AVFilterContext *ctx)
|
||||
{
|
||||
ff_rkrga_close(ctx);
|
||||
}
|
||||
|
||||
#define OFFSET(x) offsetof(RGAVppContext, x)
|
||||
#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
|
||||
|
||||
#define RKRGA_VPP_COMMON_OPTS \
|
||||
{ "force_original_aspect_ratio", "Decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 2, FLAGS, "force_oar" }, \
|
||||
{ "disable", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, "force_oar" }, \
|
||||
{ "decrease", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, "force_oar" }, \
|
||||
{ "increase", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, FLAGS, "force_oar" }, \
|
||||
{ "force_divisible_by", "Enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, 256, FLAGS }, \
|
||||
{ "core", "Set multicore RGA scheduler core [use with caution]", OFFSET(rga.scheduler_core), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, 0, INT_MAX, FLAGS, "core" }, \
|
||||
{ "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, "core" }, \
|
||||
{ "rga3_core0", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, "core" }, /* RGA3_SCHEDULER_CORE0 */ \
|
||||
{ "rga3_core1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, FLAGS, "core" }, /* RGA3_SCHEDULER_CORE1 */ \
|
||||
{ "rga2_core0", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 4 }, 0, 0, FLAGS, "core" }, /* RGA2_SCHEDULER_CORE0 */ \
|
||||
{ "async_depth", "Set the internal parallelization depth", OFFSET(rga.async_depth), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 4, .flags = FLAGS }, \
|
||||
{ "afbc", "Enable AFBC (Arm Frame Buffer Compression) to save bandwidth", OFFSET(rga.afbc_out), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = FLAGS },
|
||||
|
||||
static const AVFilterPad rgavpp_inputs[] = {
|
||||
{
|
||||
.name = "default",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
},
|
||||
};
|
||||
|
||||
static const AVFilterPad rgavpp_outputs[] = {
|
||||
{
|
||||
.name = "default",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
.config_props = rgavpp_config_props,
|
||||
},
|
||||
};
|
||||
|
||||
#if CONFIG_SCALE_RKRGA_FILTER
|
||||
|
||||
static const AVOption rgascale_options[] = {
|
||||
{ "w", "Output video width", OFFSET(ow), AV_OPT_TYPE_STRING, { .str = "iw" }, 0, 0, FLAGS },
|
||||
{ "h", "Output video height", OFFSET(oh), AV_OPT_TYPE_STRING, { .str = "ih" }, 0, 0, FLAGS },
|
||||
{ "format", "Output video pixel format", OFFSET(format), AV_OPT_TYPE_PIXEL_FMT, { .i64 = AV_PIX_FMT_NONE }, INT_MIN, INT_MAX, .flags = FLAGS },
|
||||
RKRGA_VPP_COMMON_OPTS
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static av_cold int rgascale_preinit(AVFilterContext *ctx)
|
||||
{
|
||||
RGAVppContext *r = ctx->priv;
|
||||
|
||||
r->transpose = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVFILTER_DEFINE_CLASS(rgascale);
|
||||
|
||||
const AVFilter ff_vf_scale_rkrga = {
|
||||
.name = "scale_rkrga",
|
||||
.description = NULL_IF_CONFIG_SMALL("Rockchip RGA (2D Raster Graphic Acceleration) video resizer and format converter"),
|
||||
.priv_size = sizeof(RGAVppContext),
|
||||
.priv_class = &rgascale_class,
|
||||
.preinit = rgascale_preinit,
|
||||
.init = rgavpp_init,
|
||||
.uninit = rgavpp_uninit,
|
||||
FILTER_INPUTS(rgavpp_inputs),
|
||||
FILTER_OUTPUTS(rgavpp_outputs),
|
||||
FILTER_SINGLE_PIXFMT(AV_PIX_FMT_DRM_PRIME),
|
||||
.activate = rgavpp_activate,
|
||||
.flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if CONFIG_VPP_RKRGA_FILTER
|
||||
|
||||
static const AVOption rgavpp_options[] = {
|
||||
{ "w", "Output video width", OFFSET(ow), AV_OPT_TYPE_STRING, { .str = "cw" }, 0, 0, FLAGS },
|
||||
{ "h", "Output video height", OFFSET(oh), AV_OPT_TYPE_STRING, { .str = "w*ch/cw" }, 0, 0, FLAGS },
|
||||
{ "cw", "Set the width crop area expression", OFFSET(cw), AV_OPT_TYPE_STRING, { .str = "iw" }, 0, 0, FLAGS },
|
||||
{ "ch", "Set the height crop area expression", OFFSET(ch), AV_OPT_TYPE_STRING, { .str = "ih" }, 0, 0, FLAGS },
|
||||
{ "cx", "Set the x crop area expression", OFFSET(cx), AV_OPT_TYPE_STRING, { .str = "(in_w-out_w)/2" }, 0, 0, FLAGS },
|
||||
{ "cy", "Set the y crop area expression", OFFSET(cy), AV_OPT_TYPE_STRING, { .str = "(in_h-out_h)/2" }, 0, 0, FLAGS },
|
||||
{ "format", "Output video pixel format", OFFSET(format), AV_OPT_TYPE_PIXEL_FMT, { .i64 = AV_PIX_FMT_NONE }, INT_MIN, INT_MAX, .flags = FLAGS },
|
||||
{ "transpose", "Set transpose direction", OFFSET(transpose), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 6, FLAGS, "transpose" },
|
||||
{ "cclock_hflip", "Rotate counter-clockwise with horizontal flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK_FLIP }, 0, 0, FLAGS, "transpose" },
|
||||
{ "clock", "Rotate clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK }, 0, 0, FLAGS, "transpose" },
|
||||
{ "cclock", "Rotate counter-clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK }, 0, 0, FLAGS, "transpose" },
|
||||
{ "clock_hflip", "Rotate clockwise with horizontal flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK_FLIP }, 0, 0, FLAGS, "transpose" },
|
||||
{ "reversal", "Rotate by half-turn", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_REVERSAL }, 0, 0, FLAGS, "transpose" },
|
||||
{ "hflip", "Flip horizontally", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_HFLIP }, 0, 0, FLAGS, "transpose" },
|
||||
{ "vflip", "Flip vertically", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_VFLIP }, 0, 0, FLAGS, "transpose" },
|
||||
RKRGA_VPP_COMMON_OPTS
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
AVFILTER_DEFINE_CLASS(rgavpp);
|
||||
|
||||
const AVFilter ff_vf_vpp_rkrga = {
|
||||
.name = "vpp_rkrga",
|
||||
.description = NULL_IF_CONFIG_SMALL("Rockchip RGA (2D Raster Graphic Acceleration) video post-process (scale/crop/transpose)"),
|
||||
.priv_size = sizeof(RGAVppContext),
|
||||
.priv_class = &rgavpp_class,
|
||||
.init = rgavpp_init,
|
||||
.uninit = rgavpp_uninit,
|
||||
FILTER_INPUTS(rgavpp_inputs),
|
||||
FILTER_OUTPUTS(rgavpp_outputs),
|
||||
FILTER_SINGLE_PIXFMT(AV_PIX_FMT_DRM_PRIME),
|
||||
.activate = rgavpp_activate,
|
||||
.flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue