ap手表是什么牌子| 低钾血症吃什么食补| 阳历八月份是什么星座| 奥氮平片是什么药| 六娃的能力是什么| 漏尿是什么原因造成的| 伴侣是什么意思| 拔罐痒是什么原因| 甘少一横读什么| 左室舒张功能减低是什么意思| 办护照需要什么条件| 身上红痣多是什么原因| 19朵玫瑰代表什么意思| 大熊猫属于什么科| 毛主席什么时候死的| 检查妇科清洁度三是什么意思| 男人结扎对身体有什么影响| 姨妈发黑量少什么原因| mt是什么意思| 晚上8点是什么时辰| 弢是什么意思| 乙肝两对半挂什么科| 上不下要念什么| ls是什么牌子| 小苏打和柠檬酸反应产生什么| au999是什么意思| 抗凝是什么意思| 牙龈萎缩吃什么药见效快| 6月24是什么日子| 吃酒酿有什么好处| 什么是结缔组织病| 养肝吃什么食物| 勾芡用什么淀粉| 甲减是什么意思| 低血压去药店买什么药| 临床试验是什么意思| 体检胸透主要检查什么| 子宫偏小有什么影响| 猝死是什么意思| 置之死地而后生是什么意思| 两个山念什么| 小孩子晚上睡觉磨牙是什么原因| 曜字五行属什么| 血儿茶酚胺是查什么的| 铁观音什么季节喝最好| 甲状腺炎有什么症状表现| jdk是什么| 头发染什么颜色显皮肤白显年轻| 老汉推车什么意思| 属兔适合佩戴什么饰品| 烧心是什么意思| 梅毒早期什么症状| cd是什么元素| psa升高代表什么| 14年属什么| 大便粘稠吃什么药| 98年什么命| 蜂蜡有什么用| 晚来天欲雪能饮一杯无什么意思| 蛇的天敌是什么| 死库水是什么意思| 刷存在感是什么意思| 乳晕是什么意思| 动爻是什么意思| 羊水暗区是什么意思| 降压药的原理是什么| 瓜田李下什么意思| 李白字什么| 嬉皮士是什么意思| abc是什么药| 烹调是什么意思| 雪花鱼是什么鱼| 两肺结节是什么意思| 环切是什么意思| 吃什么润肺养肺最快| 八月十四是什么星座| 保险子是什么| 卡针是什么| td代表什么意思| 腋下检查挂什么科| 滚床单是什么意思| 卡路里什么意思| 肚脐下三寸是什么位置| 商人是什么意思| 态度是什么| 天乙是什么意思| 老年人吃什么水果对身体好| 载脂蛋白b偏低是什么意思| 扁桃体化脓是什么原因引起的| 观音菩萨的坐骑是什么| 不为良相便为良医是什么意思| 扁桃体结石有什么症状| 胆在什么位置| 火牙是什么原因引起的| 副处级干部是什么级别| 钧字五行属什么| rop是什么意思| 胃疼喝什么药| 伯父是什么关系| 红楼梦是一部什么小说| 查生育能力挂什么科| 前列腺炎吃什么药效果好见效快| 甲亢挂什么科| 无后为大是什么意思| 窦性心律室性早搏是什么意思| 增加白细胞吃什么食物最好| 周杰伦英文名叫什么| 凉拌菜用什么醋好| 嗓子干疼吃什么药| 急性肠胃炎吃什么药好| 曼字五行属什么| 85年属于什么生肖| 痤疮是什么意思| 乳房是什么| 心绪是什么意思| 点痣后需要注意什么事项| 异卵双胞胎是什么意思| 酉时是什么时间| 瑞五行属什么| 金刚菩提是什么植物的种子| 宝宝拉肚子能吃什么| 维生素b2吃多了有什么副作用| 铲垃圾的工具叫什么| cet什么意思| 画龙点睛是什么生肖| 出栏是什么意思| 梦到蛇是什么征兆| 鬼佬是什么意思| 咳嗽喉咙痒吃什么药| 不一般是什么意思| 右侧附件区囊性回声是什么意思| 例假推迟是什么原因引起的| 血小板偏高是什么原因| 月经期间喝红糖水有什么好处| 夏至是什么| 孕妇什么东西不能吃| 右佐匹克隆是什么药| 白斑有什么症状图片| 马赛克什么意思| 心什么什么什么| 额头长痘痘什么原因| 钯金和铂金有什么区别| 睾丸炎吃什么药最有效| 宫颈柱状上皮外移是什么意思| 肺炎是什么症状| acg文化是什么意思| 为什么喜欢你| 做试管前需要检查什么项目| 什么的梦想| 坐落是什么意思| 三手烟是什么| 为什么叫中国| 自助餐是什么意思| 金牛座与什么星座最配| 樱花什么时候开花| 肠道肿瘤有什么症状| ana医学上是什么意思| 令加瓦读什么| 儿童诺如病毒吃什么药| 手脚肿胀是什么原因| 肾积水挂什么科| 定坤丹适合什么人吃| 甲胎蛋白什么意思| 纯水是什么| 为什么不能打死飞蛾| 甲鱼和什么一起炖最好| 端午节吃什么菜呢| 申时属什么| 摆子是什么意思| 反流性食管炎吃什么中药| 室性早搏是什么意思| 上热下寒吃什么中成药| 优思悦是什么药| 爱是个什么东西| 巴图是什么意思| 宝宝吃益生菌有什么好处和坏处| 吃什么通血管| 孕早期适合吃什么水果| 吃什么治疗便秘| 一个口一个者念什么| 牙根发黑是什么原因| 艺考是什么| 耳朵疼吃什么药| 什么的尾巴有什么作用| 头发热是什么原因| 性格开朗是什么意思| 痔疮手术后吃什么| 优生优育检查什么项目| 尿频挂什么科| 冲动是什么意思| 冲锋衣是什么意思| 踢馆什么意思| 地钱是什么植物| 缺锌会有什么症状| 阴道里面有个肉球是什么| 春天开什么花| 饱的偏旁叫什么| 尿次数多是什么原因| 颈部出汗是什么原因| 百香果有什么好处| 梦到父母离婚是什么意思| 一路繁花的意思是什么| 晚上喝牛奶有什么好处| 重庆有什么美食| 专科是什么意思| 什么地看| 纹身有什么讲究和忌讳| 活动性肺结核是什么意思| 龙珠是什么| 肚脐左侧是什么器官| 小丫头是什么意思| 幽门螺旋杆菌感染有什么症状| 什么是取保候审| 什么是虫草| 什么时候上环是最佳时期| 为什么吃鸽子刀口长得快| 像什么似的| 庙祝是什么意思| 兰州人为什么要戴头巾| 国家的实质是什么| 卵泡刺激素是什么意思| 什么是码率| 护士长是什么级别| 柔顺和拉直有什么区别| 芒果跟什么不能一起吃| 猪肝可以钓什么鱼| 机器灵砍菜刀是什么意思| 1966年属马的是什么命| 12点半是什么时辰| 什么是血浆| 什么胆什么心| 三岁看小七岁看老是什么意思| 什么是破伤风| 7.14号是什么节日| 舀水是什么意思| 顶针什么意思| 甲状腺功能减退是什么意思| newbee什么意思| 马赛克什么意思| 什么是人生| 来大姨妈吃什么水果好| 美团和美团外卖有什么区别| 心脏呈逆钟向转位什么意思| 羊与什么生肖相合| 为什么今年有两个六月| 什么的手| miniso是什么意思| 甘露是什么| 中央候补委员是什么级别| 看指甲挂什么科| 吃饱就犯困是什么原因| 早泄什么意思| 吉人天相好福气指什么生肖| 邓超属什么生肖| 老年人心慌是什么原因| 孔子孟子什么关系| 月经结束一周后又出血是什么原因| 内向是什么意思| 梅毒和艾滋病有什么区别| 梦见蚯蚓是什么预兆| 35属什么生肖| 添堵是什么意思| 左手麻是什么原因| neu是什么意思| 百度

国道317线(西藏境内)丁青至斜拉山公路整治改建


Directory: ../../../ffmpeg/
File: src/libavfilter/vf_xfade.c
Date: 2025-08-04 00:43:16
Exec Total Coverage
Lines: 0 371 0.0%
Functions: 0 139 0.0%
Branches: 0 1256 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2020 Paul B Mahol
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "libavutil/eval.h"
22 #include "libavutil/opt.h"
23 #include "libavutil/pixdesc.h"
24 #include "libavutil/pixfmt.h"
25 #include "avfilter.h"
26 #include "filters.h"
27 #include "video.h"
28
29 enum XFadeTransitions {
30 CUSTOM = -1,
31 FADE,
32 WIPELEFT,
33 WIPERIGHT,
34 WIPEUP,
35 WIPEDOWN,
36 SLIDELEFT,
37 SLIDERIGHT,
38 SLIDEUP,
39 SLIDEDOWN,
40 CIRCLECROP,
41 RECTCROP,
42 DISTANCE,
43 FADEBLACK,
44 FADEWHITE,
45 RADIAL,
46 SMOOTHLEFT,
47 SMOOTHRIGHT,
48 SMOOTHUP,
49 SMOOTHDOWN,
50 CIRCLEOPEN,
51 CIRCLECLOSE,
52 VERTOPEN,
53 VERTCLOSE,
54 HORZOPEN,
55 HORZCLOSE,
56 DISSOLVE,
57 PIXELIZE,
58 DIAGTL,
59 DIAGTR,
60 DIAGBL,
61 DIAGBR,
62 HLSLICE,
63 HRSLICE,
64 VUSLICE,
65 VDSLICE,
66 HBLUR,
67 FADEGRAYS,
68 WIPETL,
69 WIPETR,
70 WIPEBL,
71 WIPEBR,
72 SQUEEZEH,
73 SQUEEZEV,
74 ZOOMIN,
75 FADEFAST,
76 FADESLOW,
77 HLWIND,
78 HRWIND,
79 VUWIND,
80 VDWIND,
81 COVERLEFT,
82 COVERRIGHT,
83 COVERUP,
84 COVERDOWN,
85 REVEALLEFT,
86 REVEALRIGHT,
87 REVEALUP,
88 REVEALDOWN,
89 NB_TRANSITIONS,
90 };
91
92 typedef struct XFadeContext {
93 const AVClass *class;
94
95 int transition;
96 int64_t duration;
97 int64_t offset;
98 char *custom_str;
99
100 int nb_planes;
101 int depth;
102 int is_rgb;
103
104 // PTS when the fade should start (in first inputs timebase)
105 int64_t start_pts;
106
107 // PTS offset between first and second input
108 int64_t inputs_offset_pts;
109
110 // Duration of the transition
111 int64_t duration_pts;
112
113 // Current PTS of the first input
114 int64_t pts;
115
116 // If frames are currently just passed through unmodified,
117 // like before and after the actual transition.
118 int passthrough;
119
120 int status[2];
121 AVFrame *xf[2];
122 int max_value;
123 uint16_t black[4];
124 uint16_t white[4];
125
126 void (*transitionf)(AVFilterContext *ctx, const AVFrame *a, const AVFrame *b, AVFrame *out, float progress,
127 int slice_start, int slice_end, int jobnr);
128
129 AVExpr *e;
130 } XFadeContext;
131
132 static const char *const var_names[] = { "X", "Y", "W", "H", "A", "B", "PLANE", "P", NULL };
133 enum { VAR_X, VAR_Y, VAR_W, VAR_H, VAR_A, VAR_B, VAR_PLANE, VAR_PROGRESS, VAR_VARS_NB };
134
135 typedef struct ThreadData {
136 const AVFrame *xf[2];
137 AVFrame *out;
138 float progress;
139 } ThreadData;
140
141 static const enum AVPixelFormat pix_fmts[] = {
142 AV_PIX_FMT_YUVA444P,
143 AV_PIX_FMT_YUVJ444P,
144 AV_PIX_FMT_YUV444P,
145 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY8,
146 AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_GBRP9,
147 AV_PIX_FMT_YUV444P10,
148 AV_PIX_FMT_YUVA444P10,
149 AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GRAY10,
150 AV_PIX_FMT_YUV444P12,
151 AV_PIX_FMT_YUVA444P12,
152 AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GRAY12,
153 AV_PIX_FMT_YUV444P14, AV_PIX_FMT_GBRP14,
154 AV_PIX_FMT_YUV444P16,
155 AV_PIX_FMT_YUVA444P16,
156 AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_GRAY16,
157 AV_PIX_FMT_NONE
158 };
159
160 static av_cold void uninit(AVFilterContext *ctx)
161 {
162 XFadeContext *s = ctx->priv;
163
164 av_expr_free(s->e);
165 }
166
167 #define OFFSET(x) offsetof(XFadeContext, x)
168 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
169
170 static const AVOption xfade_options[] = {
171 { "transition", "set cross fade transition", OFFSET(transition), AV_OPT_TYPE_INT, {.i64=FADE}, -1, NB_TRANSITIONS-1, FLAGS, .unit = "transition" },
172 { "custom", "custom transition", 0, AV_OPT_TYPE_CONST, {.i64=CUSTOM}, 0, 0, FLAGS, .unit = "transition" },
173 { "fade", "fade transition", 0, AV_OPT_TYPE_CONST, {.i64=FADE}, 0, 0, FLAGS, .unit = "transition" },
174 { "wipeleft", "wipe left transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPELEFT}, 0, 0, FLAGS, .unit = "transition" },
175 { "wiperight", "wipe right transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPERIGHT}, 0, 0, FLAGS, .unit = "transition" },
176 { "wipeup", "wipe up transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPEUP}, 0, 0, FLAGS, .unit = "transition" },
177 { "wipedown", "wipe down transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPEDOWN}, 0, 0, FLAGS, .unit = "transition" },
178 { "slideleft", "slide left transition", 0, AV_OPT_TYPE_CONST, {.i64=SLIDELEFT}, 0, 0, FLAGS, .unit = "transition" },
179 { "slideright", "slide right transition", 0, AV_OPT_TYPE_CONST, {.i64=SLIDERIGHT}, 0, 0, FLAGS, .unit = "transition" },
180 { "slideup", "slide up transition", 0, AV_OPT_TYPE_CONST, {.i64=SLIDEUP}, 0, 0, FLAGS, .unit = "transition" },
181 { "slidedown", "slide down transition", 0, AV_OPT_TYPE_CONST, {.i64=SLIDEDOWN}, 0, 0, FLAGS, .unit = "transition" },
182 { "circlecrop", "circle crop transition", 0, AV_OPT_TYPE_CONST, {.i64=CIRCLECROP}, 0, 0, FLAGS, .unit = "transition" },
183 { "rectcrop", "rect crop transition", 0, AV_OPT_TYPE_CONST, {.i64=RECTCROP}, 0, 0, FLAGS, .unit = "transition" },
184 { "distance", "distance transition", 0, AV_OPT_TYPE_CONST, {.i64=DISTANCE}, 0, 0, FLAGS, .unit = "transition" },
185 { "fadeblack", "fadeblack transition", 0, AV_OPT_TYPE_CONST, {.i64=FADEBLACK}, 0, 0, FLAGS, .unit = "transition" },
186 { "fadewhite", "fadewhite transition", 0, AV_OPT_TYPE_CONST, {.i64=FADEWHITE}, 0, 0, FLAGS, .unit = "transition" },
187 { "radial", "radial transition", 0, AV_OPT_TYPE_CONST, {.i64=RADIAL}, 0, 0, FLAGS, .unit = "transition" },
188 { "smoothleft", "smoothleft transition", 0, AV_OPT_TYPE_CONST, {.i64=SMOOTHLEFT}, 0, 0, FLAGS, .unit = "transition" },
189 { "smoothright","smoothright transition", 0, AV_OPT_TYPE_CONST, {.i64=SMOOTHRIGHT},0, 0, FLAGS, .unit = "transition" },
190 { "smoothup", "smoothup transition", 0, AV_OPT_TYPE_CONST, {.i64=SMOOTHUP}, 0, 0, FLAGS, .unit = "transition" },
191 { "smoothdown", "smoothdown transition", 0, AV_OPT_TYPE_CONST, {.i64=SMOOTHDOWN}, 0, 0, FLAGS, .unit = "transition" },
192 { "circleopen", "circleopen transition", 0, AV_OPT_TYPE_CONST, {.i64=CIRCLEOPEN}, 0, 0, FLAGS, .unit = "transition" },
193 { "circleclose","circleclose transition", 0, AV_OPT_TYPE_CONST, {.i64=CIRCLECLOSE},0, 0, FLAGS, .unit = "transition" },
194 { "vertopen", "vert open transition", 0, AV_OPT_TYPE_CONST, {.i64=VERTOPEN}, 0, 0, FLAGS, .unit = "transition" },
195 { "vertclose", "vert close transition", 0, AV_OPT_TYPE_CONST, {.i64=VERTCLOSE}, 0, 0, FLAGS, .unit = "transition" },
196 { "horzopen", "horz open transition", 0, AV_OPT_TYPE_CONST, {.i64=HORZOPEN}, 0, 0, FLAGS, .unit = "transition" },
197 { "horzclose", "horz close transition", 0, AV_OPT_TYPE_CONST, {.i64=HORZCLOSE}, 0, 0, FLAGS, .unit = "transition" },
198 { "dissolve", "dissolve transition", 0, AV_OPT_TYPE_CONST, {.i64=DISSOLVE}, 0, 0, FLAGS, .unit = "transition" },
199 { "pixelize", "pixelize transition", 0, AV_OPT_TYPE_CONST, {.i64=PIXELIZE}, 0, 0, FLAGS, .unit = "transition" },
200 { "diagtl", "diag tl transition", 0, AV_OPT_TYPE_CONST, {.i64=DIAGTL}, 0, 0, FLAGS, .unit = "transition" },
201 { "diagtr", "diag tr transition", 0, AV_OPT_TYPE_CONST, {.i64=DIAGTR}, 0, 0, FLAGS, .unit = "transition" },
202 { "diagbl", "diag bl transition", 0, AV_OPT_TYPE_CONST, {.i64=DIAGBL}, 0, 0, FLAGS, .unit = "transition" },
203 { "diagbr", "diag br transition", 0, AV_OPT_TYPE_CONST, {.i64=DIAGBR}, 0, 0, FLAGS, .unit = "transition" },
204 { "hlslice", "hl slice transition", 0, AV_OPT_TYPE_CONST, {.i64=HLSLICE}, 0, 0, FLAGS, .unit = "transition" },
205 { "hrslice", "hr slice transition", 0, AV_OPT_TYPE_CONST, {.i64=HRSLICE}, 0, 0, FLAGS, .unit = "transition" },
206 { "vuslice", "vu slice transition", 0, AV_OPT_TYPE_CONST, {.i64=VUSLICE}, 0, 0, FLAGS, .unit = "transition" },
207 { "vdslice", "vd slice transition", 0, AV_OPT_TYPE_CONST, {.i64=VDSLICE}, 0, 0, FLAGS, .unit = "transition" },
208 { "hblur", "hblur transition", 0, AV_OPT_TYPE_CONST, {.i64=HBLUR}, 0, 0, FLAGS, .unit = "transition" },
209 { "fadegrays", "fadegrays transition", 0, AV_OPT_TYPE_CONST, {.i64=FADEGRAYS}, 0, 0, FLAGS, .unit = "transition" },
210 { "wipetl", "wipe tl transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPETL}, 0, 0, FLAGS, .unit = "transition" },
211 { "wipetr", "wipe tr transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPETR}, 0, 0, FLAGS, .unit = "transition" },
212 { "wipebl", "wipe bl transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPEBL}, 0, 0, FLAGS, .unit = "transition" },
213 { "wipebr", "wipe br transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPEBR}, 0, 0, FLAGS, .unit = "transition" },
214 { "squeezeh", "squeeze h transition", 0, AV_OPT_TYPE_CONST, {.i64=SQUEEZEH}, 0, 0, FLAGS, .unit = "transition" },
215 { "squeezev", "squeeze v transition", 0, AV_OPT_TYPE_CONST, {.i64=SQUEEZEV}, 0, 0, FLAGS, .unit = "transition" },
216 { "zoomin", "zoom in transition", 0, AV_OPT_TYPE_CONST, {.i64=ZOOMIN}, 0, 0, FLAGS, .unit = "transition" },
217 { "fadefast", "fast fade transition", 0, AV_OPT_TYPE_CONST, {.i64=FADEFAST}, 0, 0, FLAGS, .unit = "transition" },
218 { "fadeslow", "slow fade transition", 0, AV_OPT_TYPE_CONST, {.i64=FADESLOW}, 0, 0, FLAGS, .unit = "transition" },
219 { "hlwind", "hl wind transition", 0, AV_OPT_TYPE_CONST, {.i64=HLWIND}, 0, 0, FLAGS, .unit = "transition" },
220 { "hrwind", "hr wind transition", 0, AV_OPT_TYPE_CONST, {.i64=HRWIND}, 0, 0, FLAGS, .unit = "transition" },
221 { "vuwind", "vu wind transition", 0, AV_OPT_TYPE_CONST, {.i64=VUWIND}, 0, 0, FLAGS, .unit = "transition" },
222 { "vdwind", "vd wind transition", 0, AV_OPT_TYPE_CONST, {.i64=VDWIND}, 0, 0, FLAGS, .unit = "transition" },
223 { "coverleft", "cover left transition", 0, AV_OPT_TYPE_CONST, {.i64=COVERLEFT}, 0, 0, FLAGS, .unit = "transition" },
224 { "coverright", "cover right transition", 0, AV_OPT_TYPE_CONST, {.i64=COVERRIGHT}, 0, 0, FLAGS, .unit = "transition" },
225 { "coverup", "cover up transition", 0, AV_OPT_TYPE_CONST, {.i64=COVERUP}, 0, 0, FLAGS, .unit = "transition" },
226 { "coverdown", "cover down transition", 0, AV_OPT_TYPE_CONST, {.i64=COVERDOWN}, 0, 0, FLAGS, .unit = "transition" },
227 { "revealleft", "reveal left transition", 0, AV_OPT_TYPE_CONST, {.i64=REVEALLEFT}, 0, 0, FLAGS, .unit = "transition" },
228 { "revealright","reveal right transition",0, AV_OPT_TYPE_CONST, {.i64=REVEALRIGHT},0, 0, FLAGS, .unit = "transition" },
229 { "revealup", "reveal up transition", 0, AV_OPT_TYPE_CONST, {.i64=REVEALUP}, 0, 0, FLAGS, .unit = "transition" },
230 { "revealdown", "reveal down transition", 0, AV_OPT_TYPE_CONST, {.i64=REVEALDOWN}, 0, 0, FLAGS, .unit = "transition" },
231 { "duration", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=1000000}, 0, 60000000, FLAGS },
232 { "offset", "set cross fade start relative to first input stream", OFFSET(offset), AV_OPT_TYPE_DURATION, {.i64=0}, INT64_MIN, INT64_MAX, FLAGS },
233 { "expr", "set expression for custom transition", OFFSET(custom_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
234 { NULL }
235 };
236
237 AVFILTER_DEFINE_CLASS(xfade);
238
239 #define CUSTOM_TRANSITION(name, type, div) \
240 static void custom##name##_transition(AVFilterContext *ctx, \
241 const AVFrame *a, const AVFrame *b, AVFrame *out, \
242 float progress, \
243 int slice_start, int slice_end, int jobnr) \
244 { \
245 XFadeContext *s = ctx->priv; \
246 const int height = slice_end - slice_start; \
247 const int width = out->width; \
248 \
249 double values[VAR_VARS_NB]; \
250 values[VAR_W] = width; \
251 values[VAR_H] = out->height; \
252 values[VAR_PROGRESS] = progress; \
253 \
254 for (int p = 0; p < s->nb_planes; p++) { \
255 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
256 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
257 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
258 \
259 values[VAR_PLANE] = p; \
260 \
261 for (int y = 0; y < height; y++) { \
262 values[VAR_Y] = slice_start + y; \
263 for (int x = 0; x < width; x++) { \
264 values[VAR_X] = x; \
265 values[VAR_A] = xf0[x]; \
266 values[VAR_B] = xf1[x]; \
267 dst[x] = av_expr_eval(s->e, values, s); \
268 } \
269 \
270 dst += out->linesize[p] / div; \
271 xf0 += a->linesize[p] / div; \
272 xf1 += b->linesize[p] / div; \
273 } \
274 } \
275 }
276
277 CUSTOM_TRANSITION(8, uint8_t, 1)
278 CUSTOM_TRANSITION(16, uint16_t, 2)
279
280 static inline float mix(float a, float b, float mix)
281 {
282 return a * mix + b * (1.f - mix);
283 }
284
285 static inline float fract(float a)
286 {
287 return a - floorf(a);
288 }
289
290 static inline float smoothstep(float edge0, float edge1, float x)
291 {
292 float t;
293
294 t = av_clipf((x - edge0) / (edge1 - edge0), 0.f, 1.f);
295
296 return t * t * (3.f - 2.f * t);
297 }
298
299 #define FADE_TRANSITION(name, type, div) \
300 static void fade##name##_transition(AVFilterContext *ctx, \
301 const AVFrame *a, const AVFrame *b, AVFrame *out, \
302 float progress, \
303 int slice_start, int slice_end, int jobnr) \
304 { \
305 XFadeContext *s = ctx->priv; \
306 const int height = slice_end - slice_start; \
307 const int width = out->width; \
308 \
309 for (int p = 0; p < s->nb_planes; p++) { \
310 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
311 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
312 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
313 \
314 for (int y = 0; y < height; y++) { \
315 for (int x = 0; x < width; x++) { \
316 dst[x] = mix(xf0[x], xf1[x], progress); \
317 } \
318 \
319 dst += out->linesize[p] / div; \
320 xf0 += a->linesize[p] / div; \
321 xf1 += b->linesize[p] / div; \
322 } \
323 } \
324 }
325
326 FADE_TRANSITION(8, uint8_t, 1)
327 FADE_TRANSITION(16, uint16_t, 2)
328
329 #define WIPELEFT_TRANSITION(name, type, div) \
330 static void wipeleft##name##_transition(AVFilterContext *ctx, \
331 const AVFrame *a, const AVFrame *b, AVFrame *out, \
332 float progress, \
333 int slice_start, int slice_end, int jobnr) \
334 { \
335 XFadeContext *s = ctx->priv; \
336 const int height = slice_end - slice_start; \
337 const int width = out->width; \
338 const int z = width * progress; \
339 \
340 for (int p = 0; p < s->nb_planes; p++) { \
341 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
342 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
343 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
344 \
345 for (int y = 0; y < height; y++) { \
346 for (int x = 0; x < width; x++) { \
347 dst[x] = x > z ? xf1[x] : xf0[x]; \
348 } \
349 \
350 dst += out->linesize[p] / div; \
351 xf0 += a->linesize[p] / div; \
352 xf1 += b->linesize[p] / div; \
353 } \
354 } \
355 }
356
357 WIPELEFT_TRANSITION(8, uint8_t, 1)
358 WIPELEFT_TRANSITION(16, uint16_t, 2)
359
360 #define WIPERIGHT_TRANSITION(name, type, div) \
361 static void wiperight##name##_transition(AVFilterContext *ctx, \
362 const AVFrame *a, const AVFrame *b, AVFrame *out, \
363 float progress, \
364 int slice_start, int slice_end, int jobnr) \
365 { \
366 XFadeContext *s = ctx->priv; \
367 const int height = slice_end - slice_start; \
368 const int width = out->width; \
369 const int z = width * (1.f - progress); \
370 \
371 for (int p = 0; p < s->nb_planes; p++) { \
372 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
373 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
374 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
375 \
376 for (int y = 0; y < height; y++) { \
377 for (int x = 0; x < width; x++) { \
378 dst[x] = x > z ? xf0[x] : xf1[x]; \
379 } \
380 \
381 dst += out->linesize[p] / div; \
382 xf0 += a->linesize[p] / div; \
383 xf1 += b->linesize[p] / div; \
384 } \
385 } \
386 }
387
388 WIPERIGHT_TRANSITION(8, uint8_t, 1)
389 WIPERIGHT_TRANSITION(16, uint16_t, 2)
390
391 #define WIPEUP_TRANSITION(name, type, div) \
392 static void wipeup##name##_transition(AVFilterContext *ctx, \
393 const AVFrame *a, const AVFrame *b, AVFrame *out, \
394 float progress, \
395 int slice_start, int slice_end, int jobnr) \
396 { \
397 XFadeContext *s = ctx->priv; \
398 const int height = slice_end - slice_start; \
399 const int width = out->width; \
400 const int z = out->height * progress; \
401 \
402 for (int p = 0; p < s->nb_planes; p++) { \
403 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
404 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
405 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
406 \
407 for (int y = 0; y < height; y++) { \
408 for (int x = 0; x < width; x++) { \
409 dst[x] = slice_start + y > z ? xf1[x] : xf0[x]; \
410 } \
411 \
412 dst += out->linesize[p] / div; \
413 xf0 += a->linesize[p] / div; \
414 xf1 += b->linesize[p] / div; \
415 } \
416 } \
417 }
418
419 WIPEUP_TRANSITION(8, uint8_t, 1)
420 WIPEUP_TRANSITION(16, uint16_t, 2)
421
422 #define WIPEDOWN_TRANSITION(name, type, div) \
423 static void wipedown##name##_transition(AVFilterContext *ctx, \
424 const AVFrame *a, const AVFrame *b, AVFrame *out, \
425 float progress, \
426 int slice_start, int slice_end, int jobnr) \
427 { \
428 XFadeContext *s = ctx->priv; \
429 const int height = slice_end - slice_start; \
430 const int width = out->width; \
431 const int z = out->height * (1.f - progress); \
432 \
433 for (int p = 0; p < s->nb_planes; p++) { \
434 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
435 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
436 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
437 \
438 for (int y = 0; y < height; y++) { \
439 for (int x = 0; x < width; x++) { \
440 dst[x] = slice_start + y > z ? xf0[x] : xf1[x]; \
441 } \
442 \
443 dst += out->linesize[p] / div; \
444 xf0 += a->linesize[p] / div; \
445 xf1 += b->linesize[p] / div; \
446 } \
447 } \
448 }
449
450 WIPEDOWN_TRANSITION(8, uint8_t, 1)
451 WIPEDOWN_TRANSITION(16, uint16_t, 2)
452
453 #define SLIDELEFT_TRANSITION(name, type, div) \
454 static void slideleft##name##_transition(AVFilterContext *ctx, \
455 const AVFrame *a, const AVFrame *b, AVFrame *out, \
456 float progress, \
457 int slice_start, int slice_end, int jobnr) \
458 { \
459 XFadeContext *s = ctx->priv; \
460 const int height = slice_end - slice_start; \
461 const int width = out->width; \
462 const int z = -progress * width; \
463 \
464 for (int p = 0; p < s->nb_planes; p++) { \
465 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
466 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
467 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
468 \
469 for (int y = 0; y < height; y++) { \
470 for (int x = 0; x < width; x++) { \
471 const int zx = z + x; \
472 const int zz = zx % width + width * (zx < 0); \
473 dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[zz]; \
474 } \
475 \
476 dst += out->linesize[p] / div; \
477 xf0 += a->linesize[p] / div; \
478 xf1 += b->linesize[p] / div; \
479 } \
480 } \
481 }
482
483 SLIDELEFT_TRANSITION(8, uint8_t, 1)
484 SLIDELEFT_TRANSITION(16, uint16_t, 2)
485
486 #define SLIDERIGHT_TRANSITION(name, type, div) \
487 static void slideright##name##_transition(AVFilterContext *ctx, \
488 const AVFrame *a, const AVFrame *b, AVFrame *out, \
489 float progress, \
490 int slice_start, int slice_end, int jobnr) \
491 { \
492 XFadeContext *s = ctx->priv; \
493 const int height = slice_end - slice_start; \
494 const int width = out->width; \
495 const int z = progress * width; \
496 \
497 for (int p = 0; p < s->nb_planes; p++) { \
498 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
499 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
500 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
501 \
502 for (int y = 0; y < height; y++) { \
503 for (int x = 0; x < width; x++) { \
504 const int zx = z + x; \
505 const int zz = zx % width + width * (zx < 0); \
506 dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[zz]; \
507 } \
508 \
509 dst += out->linesize[p] / div; \
510 xf0 += a->linesize[p] / div; \
511 xf1 += b->linesize[p] / div; \
512 } \
513 } \
514 }
515
516 SLIDERIGHT_TRANSITION(8, uint8_t, 1)
517 SLIDERIGHT_TRANSITION(16, uint16_t, 2)
518
519 #define SLIDEUP_TRANSITION(name, type, div) \
520 static void slideup##name##_transition(AVFilterContext *ctx, \
521 const AVFrame *a, const AVFrame *b, AVFrame *out, \
522 float progress, \
523 int slice_start, int slice_end, int jobnr) \
524 { \
525 XFadeContext *s = ctx->priv; \
526 const int height = out->height; \
527 const int width = out->width; \
528 const int z = -progress * height; \
529 \
530 for (int p = 0; p < s->nb_planes; p++) { \
531 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
532 \
533 for (int y = slice_start; y < slice_end; y++) { \
534 const int zy = z + y; \
535 const int zz = zy % height + height * (zy < 0); \
536 const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \
537 const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]); \
538 \
539 for (int x = 0; x < width; x++) { \
540 dst[x] = (zy >= 0) && (zy < height) ? xf1[x] : xf0[x]; \
541 } \
542 \
543 dst += out->linesize[p] / div; \
544 } \
545 } \
546 }
547
548 SLIDEUP_TRANSITION(8, uint8_t, 1)
549 SLIDEUP_TRANSITION(16, uint16_t, 2)
550
551 #define SLIDEDOWN_TRANSITION(name, type, div) \
552 static void slidedown##name##_transition(AVFilterContext *ctx, \
553 const AVFrame *a, const AVFrame *b, AVFrame *out, \
554 float progress, \
555 int slice_start, int slice_end, int jobnr) \
556 { \
557 XFadeContext *s = ctx->priv; \
558 const int height = out->height; \
559 const int width = out->width; \
560 const int z = progress * height; \
561 \
562 for (int p = 0; p < s->nb_planes; p++) { \
563 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
564 \
565 for (int y = slice_start; y < slice_end; y++) { \
566 const int zy = z + y; \
567 const int zz = zy % height + height * (zy < 0); \
568 const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \
569 const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]); \
570 \
571 for (int x = 0; x < width; x++) { \
572 dst[x] = (zy >= 0) && (zy < height) ? xf1[x] : xf0[x]; \
573 } \
574 \
575 dst += out->linesize[p] / div; \
576 } \
577 } \
578 }
579
580 SLIDEDOWN_TRANSITION(8, uint8_t, 1)
581 SLIDEDOWN_TRANSITION(16, uint16_t, 2)
582
583 #define CIRCLECROP_TRANSITION(name, type, div) \
584 static void circlecrop##name##_transition(AVFilterContext *ctx, \
585 const AVFrame *a, const AVFrame *b, AVFrame *out, \
586 float progress, \
587 int slice_start, int slice_end, int jobnr) \
588 { \
589 XFadeContext *s = ctx->priv; \
590 const int width = out->width; \
591 const int height = out->height; \
592 float z = powf(2.f * fabsf(progress - 0.5f), 3.f) * hypotf(width/2, height/2); \
593 \
594 for (int p = 0; p < s->nb_planes; p++) { \
595 const int bg = s->black[p]; \
596 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
597 \
598 for (int y = slice_start; y < slice_end; y++) { \
599 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
600 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
601 \
602 for (int x = 0; x < width; x++) { \
603 float dist = hypotf(x - width / 2, y - height / 2); \
604 int val = progress < 0.5f ? xf1[x] : xf0[x]; \
605 dst[x] = (z < dist) ? bg : val; \
606 } \
607 \
608 dst += out->linesize[p] / div; \
609 } \
610 } \
611 }
612
613 CIRCLECROP_TRANSITION(8, uint8_t, 1)
614 CIRCLECROP_TRANSITION(16, uint16_t, 2)
615
616 #define RECTCROP_TRANSITION(name, type, div) \
617 static void rectcrop##name##_transition(AVFilterContext *ctx, \
618 const AVFrame *a, const AVFrame *b, AVFrame *out, \
619 float progress, \
620 int slice_start, int slice_end, int jobnr) \
621 { \
622 XFadeContext *s = ctx->priv; \
623 const int width = out->width; \
624 const int height = out->height; \
625 int zh = fabsf(progress - 0.5f) * height; \
626 int zw = fabsf(progress - 0.5f) * width; \
627 \
628 for (int p = 0; p < s->nb_planes; p++) { \
629 const int bg = s->black[p]; \
630 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
631 \
632 for (int y = slice_start; y < slice_end; y++) { \
633 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
634 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
635 \
636 for (int x = 0; x < width; x++) { \
637 int dist = FFABS(x - width / 2) < zw && \
638 FFABS(y - height / 2) < zh; \
639 int val = progress < 0.5f ? xf1[x] : xf0[x]; \
640 dst[x] = !dist ? bg : val; \
641 } \
642 \
643 dst += out->linesize[p] / div; \
644 } \
645 } \
646 }
647
648 RECTCROP_TRANSITION(8, uint8_t, 1)
649 RECTCROP_TRANSITION(16, uint16_t, 2)
650
651 #define DISTANCE_TRANSITION(name, type, div) \
652 static void distance##name##_transition(AVFilterContext *ctx, \
653 const AVFrame *a, const AVFrame *b, AVFrame *out, \
654 float progress, \
655 int slice_start, int slice_end, int jobnr) \
656 { \
657 XFadeContext *s = ctx->priv; \
658 const int width = out->width; \
659 const float max = s->max_value; \
660 \
661 for (int y = slice_start; y < slice_end; y++) { \
662 for (int x = 0; x < width; x++) { \
663 float dist = 0.f; \
664 for (int p = 0; p < s->nb_planes; p++) { \
665 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
666 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
667 \
668 dist += (xf0[x] / max - xf1[x] / max) * \
669 (xf0[x] / max - xf1[x] / max); \
670 } \
671 \
672 dist = sqrtf(dist) <= progress; \
673 for (int p = 0; p < s->nb_planes; p++) { \
674 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
675 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
676 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
677 dst[x] = mix(mix(xf0[x], xf1[x], dist), xf1[x], progress); \
678 } \
679 } \
680 } \
681 }
682
683 DISTANCE_TRANSITION(8, uint8_t, 1)
684 DISTANCE_TRANSITION(16, uint16_t, 2)
685
686 #define FADEBLACK_TRANSITION(name, type, div) \
687 static void fadeblack##name##_transition(AVFilterContext *ctx, \
688 const AVFrame *a, const AVFrame *b, AVFrame *out, \
689 float progress, \
690 int slice_start, int slice_end, int jobnr) \
691 { \
692 XFadeContext *s = ctx->priv; \
693 const int height = slice_end - slice_start; \
694 const int width = out->width; \
695 const float phase = 0.2f; \
696 \
697 for (int p = 0; p < s->nb_planes; p++) { \
698 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
699 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
700 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
701 const int bg = s->black[p]; \
702 \
703 for (int y = 0; y < height; y++) { \
704 for (int x = 0; x < width; x++) { \
705 dst[x] = mix(mix(xf0[x], bg, smoothstep(1.f-phase, 1.f, progress)), \
706 mix(bg, xf1[x], smoothstep(phase, 1.f, progress)), \
707 progress); \
708 } \
709 \
710 dst += out->linesize[p] / div; \
711 xf0 += a->linesize[p] / div; \
712 xf1 += b->linesize[p] / div; \
713 } \
714 } \
715 }
716
717 FADEBLACK_TRANSITION(8, uint8_t, 1)
718 FADEBLACK_TRANSITION(16, uint16_t, 2)
719
720 #define FADEWHITE_TRANSITION(name, type, div) \
721 static void fadewhite##name##_transition(AVFilterContext *ctx, \
722 const AVFrame *a, const AVFrame *b, AVFrame *out, \
723 float progress, \
724 int slice_start, int slice_end, int jobnr) \
725 { \
726 XFadeContext *s = ctx->priv; \
727 const int height = slice_end - slice_start; \
728 const int width = out->width; \
729 const float phase = 0.2f; \
730 \
731 for (int p = 0; p < s->nb_planes; p++) { \
732 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
733 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
734 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
735 const int bg = s->white[p]; \
736 \
737 for (int y = 0; y < height; y++) { \
738 for (int x = 0; x < width; x++) { \
739 dst[x] = mix(mix(xf0[x], bg, smoothstep(1.f-phase, 1.f, progress)), \
740 mix(bg, xf1[x], smoothstep(phase, 1.f, progress)), \
741 progress); \
742 } \
743 \
744 dst += out->linesize[p] / div; \
745 xf0 += a->linesize[p] / div; \
746 xf1 += b->linesize[p] / div; \
747 } \
748 } \
749 }
750
751 FADEWHITE_TRANSITION(8, uint8_t, 1)
752 FADEWHITE_TRANSITION(16, uint16_t, 2)
753
754 #define RADIAL_TRANSITION(name, type, div) \
755 static void radial##name##_transition(AVFilterContext *ctx, \
756 const AVFrame *a, const AVFrame *b, AVFrame *out, \
757 float progress, \
758 int slice_start, int slice_end, int jobnr) \
759 { \
760 XFadeContext *s = ctx->priv; \
761 const int width = out->width; \
762 const int height = out->height; \
763 \
764 for (int y = slice_start; y < slice_end; y++) { \
765 for (int x = 0; x < width; x++) { \
766 const float smooth = atan2f(x - width / 2, y - height / 2) - \
767 (progress - 0.5f) * (M_PI * 2.5f); \
768 for (int p = 0; p < s->nb_planes; p++) { \
769 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
770 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
771 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
772 \
773 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
774 } \
775 } \
776 } \
777 }
778
779 RADIAL_TRANSITION(8, uint8_t, 1)
780 RADIAL_TRANSITION(16, uint16_t, 2)
781
782 #define SMOOTHLEFT_TRANSITION(name, type, div) \
783 static void smoothleft##name##_transition(AVFilterContext *ctx, \
784 const AVFrame *a, const AVFrame *b, AVFrame *out, \
785 float progress, \
786 int slice_start, int slice_end, int jobnr) \
787 { \
788 XFadeContext *s = ctx->priv; \
789 const int width = out->width; \
790 const float w = width; \
791 \
792 for (int y = slice_start; y < slice_end; y++) { \
793 for (int x = 0; x < width; x++) { \
794 const float smooth = 1.f + x / w - progress * 2.f; \
795 \
796 for (int p = 0; p < s->nb_planes; p++) { \
797 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
798 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
799 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
800 \
801 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
802 } \
803 } \
804 } \
805 }
806
807 SMOOTHLEFT_TRANSITION(8, uint8_t, 1)
808 SMOOTHLEFT_TRANSITION(16, uint16_t, 2)
809
810 #define SMOOTHRIGHT_TRANSITION(name, type, div) \
811 static void smoothright##name##_transition(AVFilterContext *ctx, \
812 const AVFrame *a, const AVFrame *b, AVFrame *out, \
813 float progress, \
814 int slice_start, int slice_end, int jobnr) \
815 { \
816 XFadeContext *s = ctx->priv; \
817 const int width = out->width; \
818 const float w = width; \
819 \
820 for (int y = slice_start; y < slice_end; y++) { \
821 for (int x = 0; x < width; x++) { \
822 const float smooth = 1.f + (w - 1 - x) / w - progress * 2.f; \
823 \
824 for (int p = 0; p < s->nb_planes; p++) { \
825 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
826 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
827 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
828 \
829 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
830 } \
831 } \
832 } \
833 }
834
835 SMOOTHRIGHT_TRANSITION(8, uint8_t, 1)
836 SMOOTHRIGHT_TRANSITION(16, uint16_t, 2)
837
838 #define SMOOTHUP_TRANSITION(name, type, div) \
839 static void smoothup##name##_transition(AVFilterContext *ctx, \
840 const AVFrame *a, const AVFrame *b, AVFrame *out, \
841 float progress, \
842 int slice_start, int slice_end, int jobnr) \
843 { \
844 XFadeContext *s = ctx->priv; \
845 const int width = out->width; \
846 const float h = out->height; \
847 \
848 for (int y = slice_start; y < slice_end; y++) { \
849 const float smooth = 1.f + y / h - progress * 2.f; \
850 for (int x = 0; x < width; x++) { \
851 for (int p = 0; p < s->nb_planes; p++) { \
852 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
853 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
854 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
855 \
856 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
857 } \
858 } \
859 } \
860 }
861
862 SMOOTHUP_TRANSITION(8, uint8_t, 1)
863 SMOOTHUP_TRANSITION(16, uint16_t, 2)
864
865 #define SMOOTHDOWN_TRANSITION(name, type, div) \
866 static void smoothdown##name##_transition(AVFilterContext *ctx, \
867 const AVFrame *a, const AVFrame *b, AVFrame *out, \
868 float progress, \
869 int slice_start, int slice_end, int jobnr) \
870 { \
871 XFadeContext *s = ctx->priv; \
872 const int width = out->width; \
873 const float h = out->height; \
874 \
875 for (int y = slice_start; y < slice_end; y++) { \
876 const float smooth = 1.f + (h - 1 - y) / h - progress * 2.f; \
877 for (int x = 0; x < width; x++) { \
878 for (int p = 0; p < s->nb_planes; p++) { \
879 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
880 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
881 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
882 \
883 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
884 } \
885 } \
886 } \
887 }
888
889 SMOOTHDOWN_TRANSITION(8, uint8_t, 1)
890 SMOOTHDOWN_TRANSITION(16, uint16_t, 2)
891
892 #define CIRCLEOPEN_TRANSITION(name, type, div) \
893 static void circleopen##name##_transition(AVFilterContext *ctx, \
894 const AVFrame *a, const AVFrame *b, AVFrame *out, \
895 float progress, \
896 int slice_start, int slice_end, int jobnr) \
897 { \
898 XFadeContext *s = ctx->priv; \
899 const int width = out->width; \
900 const int height = out->height; \
901 const float z = hypotf(width / 2, height / 2); \
902 const float p = (progress - 0.5f) * 3.f; \
903 \
904 for (int y = slice_start; y < slice_end; y++) { \
905 for (int x = 0; x < width; x++) { \
906 const float smooth = hypotf(x - width / 2, y - height / 2) / z + p; \
907 for (int p = 0; p < s->nb_planes; p++) { \
908 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
909 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
910 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
911 \
912 dst[x] = mix(xf0[x], xf1[x], smoothstep(0.f, 1.f, smooth)); \
913 } \
914 } \
915 } \
916 }
917
918 CIRCLEOPEN_TRANSITION(8, uint8_t, 1)
919 CIRCLEOPEN_TRANSITION(16, uint16_t, 2)
920
921 #define CIRCLECLOSE_TRANSITION(name, type, div) \
922 static void circleclose##name##_transition(AVFilterContext *ctx, \
923 const AVFrame *a, const AVFrame *b, AVFrame *out, \
924 float progress, \
925 int slice_start, int slice_end, int jobnr) \
926 { \
927 XFadeContext *s = ctx->priv; \
928 const int width = out->width; \
929 const int height = out->height; \
930 const float z = hypotf(width / 2, height / 2); \
931 const float p = (1.f - progress - 0.5f) * 3.f; \
932 \
933 for (int y = slice_start; y < slice_end; y++) { \
934 for (int x = 0; x < width; x++) { \
935 const float smooth = hypotf(x - width / 2, y - height / 2) / z + p; \
936 for (int p = 0; p < s->nb_planes; p++) { \
937 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
938 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
939 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
940 \
941 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
942 } \
943 } \
944 } \
945 }
946
947 CIRCLECLOSE_TRANSITION(8, uint8_t, 1)
948 CIRCLECLOSE_TRANSITION(16, uint16_t, 2)
949
950 #define VERTOPEN_TRANSITION(name, type, div) \
951 static void vertopen##name##_transition(AVFilterContext *ctx, \
952 const AVFrame *a, const AVFrame *b, AVFrame *out, \
953 float progress, \
954 int slice_start, int slice_end, int jobnr) \
955 { \
956 XFadeContext *s = ctx->priv; \
957 const int width = out->width; \
958 const float w2 = out->width / 2.0; \
959 \
960 for (int y = slice_start; y < slice_end; y++) { \
961 for (int x = 0; x < width; x++) { \
962 const float smooth = 2.f - fabsf((x - w2) / w2) - progress * 2.f; \
963 for (int p = 0; p < s->nb_planes; p++) { \
964 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
965 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
966 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
967 \
968 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
969 } \
970 } \
971 } \
972 }
973
974 VERTOPEN_TRANSITION(8, uint8_t, 1)
975 VERTOPEN_TRANSITION(16, uint16_t, 2)
976
977 #define VERTCLOSE_TRANSITION(name, type, div) \
978 static void vertclose##name##_transition(AVFilterContext *ctx, \
979 const AVFrame *a, const AVFrame *b, AVFrame *out, \
980 float progress, \
981 int slice_start, int slice_end, int jobnr) \
982 { \
983 XFadeContext *s = ctx->priv; \
984 const int nb_planes = s->nb_planes; \
985 const int width = out->width; \
986 const float w2 = out->width / 2.0; \
987 \
988 for (int y = slice_start; y < slice_end; y++) { \
989 for (int x = 0; x < width; x++) { \
990 const float smooth = 1.f + fabsf((x - w2) / w2) - progress * 2.f; \
991 for (int p = 0; p < nb_planes; p++) { \
992 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
993 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
994 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
995 \
996 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
997 } \
998 } \
999 } \
1000 }
1001
1002 VERTCLOSE_TRANSITION(8, uint8_t, 1)
1003 VERTCLOSE_TRANSITION(16, uint16_t, 2)
1004
1005 #define HORZOPEN_TRANSITION(name, type, div) \
1006 static void horzopen##name##_transition(AVFilterContext *ctx, \
1007 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1008 float progress, \
1009 int slice_start, int slice_end, int jobnr) \
1010 { \
1011 XFadeContext *s = ctx->priv; \
1012 const int nb_planes = s->nb_planes; \
1013 const int width = out->width; \
1014 const float h2 = out->height / 2.0; \
1015 \
1016 for (int y = slice_start; y < slice_end; y++) { \
1017 const float smooth = 2.f - fabsf((y - h2) / h2) - progress * 2.f; \
1018 for (int x = 0; x < width; x++) { \
1019 for (int p = 0; p < nb_planes; p++) { \
1020 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1021 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1022 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1023 \
1024 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1025 } \
1026 } \
1027 } \
1028 }
1029
1030 HORZOPEN_TRANSITION(8, uint8_t, 1)
1031 HORZOPEN_TRANSITION(16, uint16_t, 2)
1032
1033 #define HORZCLOSE_TRANSITION(name, type, div) \
1034 static void horzclose##name##_transition(AVFilterContext *ctx, \
1035 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1036 float progress, \
1037 int slice_start, int slice_end, int jobnr) \
1038 { \
1039 XFadeContext *s = ctx->priv; \
1040 const int nb_planes = s->nb_planes; \
1041 const int width = out->width; \
1042 const float h2 = out->height / 2.0; \
1043 \
1044 for (int y = slice_start; y < slice_end; y++) { \
1045 const float smooth = 1.f + fabsf((y - h2) / h2) - progress * 2.f; \
1046 for (int x = 0; x < width; x++) { \
1047 for (int p = 0; p < nb_planes; p++) { \
1048 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1049 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1050 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1051 \
1052 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1053 } \
1054 } \
1055 } \
1056 }
1057
1058 HORZCLOSE_TRANSITION(8, uint8_t, 1)
1059 HORZCLOSE_TRANSITION(16, uint16_t, 2)
1060
1061 static float frand(int x, int y)
1062 {
1063 const float r = sinf(x * 12.9898f + y * 78.233f) * 43758.545f;
1064
1065 return r - floorf(r);
1066 }
1067
1068 #define DISSOLVE_TRANSITION(name, type, div) \
1069 static void dissolve##name##_transition(AVFilterContext *ctx, \
1070 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1071 float progress, \
1072 int slice_start, int slice_end, int jobnr) \
1073 { \
1074 XFadeContext *s = ctx->priv; \
1075 const int nb_planes = s->nb_planes; \
1076 const int width = out->width; \
1077 \
1078 for (int y = slice_start; y < slice_end; y++) { \
1079 for (int x = 0; x < width; x++) { \
1080 const float smooth = frand(x, y) * 2.f + progress * 2.f - 1.5f; \
1081 for (int p = 0; p < nb_planes; p++) { \
1082 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1083 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1084 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1085 \
1086 dst[x] = smooth >= 0.5f ? xf0[x] : xf1[x]; \
1087 } \
1088 } \
1089 } \
1090 }
1091
1092 DISSOLVE_TRANSITION(8, uint8_t, 1)
1093 DISSOLVE_TRANSITION(16, uint16_t, 2)
1094
1095 #define PIXELIZE_TRANSITION(name, type, div) \
1096 static void pixelize##name##_transition(AVFilterContext *ctx, \
1097 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1098 float progress, \
1099 int slice_start, int slice_end, int jobnr) \
1100 { \
1101 XFadeContext *s = ctx->priv; \
1102 const int nb_planes = s->nb_planes; \
1103 const int w = out->width; \
1104 const int h = out->height; \
1105 const float d = fminf(progress, 1.f - progress); \
1106 const float dist = ceilf(d * 50.f) / 50.f; \
1107 const float sqx = 2.f * dist * FFMIN(w, h) / 20.f; \
1108 const float sqy = 2.f * dist * FFMIN(w, h) / 20.f; \
1109 \
1110 for (int y = slice_start; y < slice_end; y++) { \
1111 for (int x = 0; x < w; x++) { \
1112 int sx = dist > 0.f ? FFMIN((floorf(x / sqx) + .5f) * sqx, w - 1) : x; \
1113 int sy = dist > 0.f ? FFMIN((floorf(y / sqy) + .5f) * sqy, h - 1) : y; \
1114 for (int p = 0; p < nb_planes; p++) { \
1115 const type *xf0 = (const type *)(a->data[p] + sy * a->linesize[p]); \
1116 const type *xf1 = (const type *)(b->data[p] + sy * b->linesize[p]); \
1117 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1118 \
1119 dst[x] = mix(xf0[sx], xf1[sx], progress); \
1120 } \
1121 } \
1122 } \
1123 }
1124
1125 PIXELIZE_TRANSITION(8, uint8_t, 1)
1126 PIXELIZE_TRANSITION(16, uint16_t, 2)
1127
1128 #define DIAGTL_TRANSITION(name, type, div) \
1129 static void diagtl##name##_transition(AVFilterContext *ctx, \
1130 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1131 float progress, \
1132 int slice_start, int slice_end, int jobnr) \
1133 { \
1134 XFadeContext *s = ctx->priv; \
1135 const int nb_planes = s->nb_planes; \
1136 const int width = out->width; \
1137 const float w = width; \
1138 const float h = out->height; \
1139 \
1140 for (int y = slice_start; y < slice_end; y++) { \
1141 for (int x = 0; x < width; x++) { \
1142 const float smooth = 1.f + x / w * y / h - progress * 2.f; \
1143 \
1144 for (int p = 0; p < nb_planes; p++) { \
1145 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1146 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1147 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1148 \
1149 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1150 } \
1151 } \
1152 } \
1153 }
1154
1155 DIAGTL_TRANSITION(8, uint8_t, 1)
1156 DIAGTL_TRANSITION(16, uint16_t, 2)
1157
1158 #define DIAGTR_TRANSITION(name, type, div) \
1159 static void diagtr##name##_transition(AVFilterContext *ctx, \
1160 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1161 float progress, \
1162 int slice_start, int slice_end, int jobnr) \
1163 { \
1164 XFadeContext *s = ctx->priv; \
1165 const int nb_planes = s->nb_planes; \
1166 const int width = out->width; \
1167 const float w = width; \
1168 const float h = out->height; \
1169 \
1170 for (int y = slice_start; y < slice_end; y++) { \
1171 for (int x = 0; x < width; x++) { \
1172 const float smooth = 1.f + (w - 1 - x) / w * y / h - progress * 2.f; \
1173 \
1174 for (int p = 0; p < nb_planes; p++) { \
1175 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1176 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1177 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1178 \
1179 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1180 } \
1181 } \
1182 } \
1183 }
1184
1185 DIAGTR_TRANSITION(8, uint8_t, 1)
1186 DIAGTR_TRANSITION(16, uint16_t, 2)
1187
1188 #define DIAGBL_TRANSITION(name, type, div) \
1189 static void diagbl##name##_transition(AVFilterContext *ctx, \
1190 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1191 float progress, \
1192 int slice_start, int slice_end, int jobnr) \
1193 { \
1194 XFadeContext *s = ctx->priv; \
1195 const int nb_planes = s->nb_planes; \
1196 const int width = out->width; \
1197 const float w = width; \
1198 const float h = out->height; \
1199 \
1200 for (int y = slice_start; y < slice_end; y++) { \
1201 for (int x = 0; x < width; x++) { \
1202 const float smooth = 1.f + x / w * (h - 1 - y) / h - progress * 2.f; \
1203 \
1204 for (int p = 0; p < nb_planes; p++) { \
1205 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1206 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1207 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1208 \
1209 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1210 } \
1211 } \
1212 } \
1213 }
1214
1215 DIAGBL_TRANSITION(8, uint8_t, 1)
1216 DIAGBL_TRANSITION(16, uint16_t, 2)
1217
1218 #define DIAGBR_TRANSITION(name, type, div) \
1219 static void diagbr##name##_transition(AVFilterContext *ctx, \
1220 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1221 float progress, \
1222 int slice_start, int slice_end, int jobnr) \
1223 { \
1224 XFadeContext *s = ctx->priv; \
1225 const int nb_planes = s->nb_planes; \
1226 const int width = out->width; \
1227 const float w = width; \
1228 const float h = out->height; \
1229 \
1230 for (int y = slice_start; y < slice_end; y++) { \
1231 for (int x = 0; x < width; x++) { \
1232 const float smooth = 1.f + (w - 1 - x) / w * (h - 1 - y) / h - \
1233 progress * 2.f; \
1234 \
1235 for (int p = 0; p < nb_planes; p++) { \
1236 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1237 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1238 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1239 \
1240 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1241 } \
1242 } \
1243 } \
1244 }
1245
1246 DIAGBR_TRANSITION(8, uint8_t, 1)
1247 DIAGBR_TRANSITION(16, uint16_t, 2)
1248
1249 #define HLSLICE_TRANSITION(name, type, div) \
1250 static void hlslice##name##_transition(AVFilterContext *ctx, \
1251 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1252 float progress, \
1253 int slice_start, int slice_end, int jobnr) \
1254 { \
1255 XFadeContext *s = ctx->priv; \
1256 const int nb_planes = s->nb_planes; \
1257 const int width = out->width; \
1258 const float w = width; \
1259 \
1260 for (int y = slice_start; y < slice_end; y++) { \
1261 for (int x = 0; x < width; x++) { \
1262 const float smooth = smoothstep(-0.5f, 0.f, x / w - progress * 1.5f); \
1263 const float ss = smooth <= fract(10.f * x / w) ? 0.f : 1.f; \
1264 \
1265 for (int p = 0; p < nb_planes; p++) { \
1266 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1267 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1268 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1269 \
1270 dst[x] = mix(xf1[x], xf0[x], ss); \
1271 } \
1272 } \
1273 } \
1274 }
1275
1276 HLSLICE_TRANSITION(8, uint8_t, 1)
1277 HLSLICE_TRANSITION(16, uint16_t, 2)
1278
1279 #define HRSLICE_TRANSITION(name, type, div) \
1280 static void hrslice##name##_transition(AVFilterContext *ctx, \
1281 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1282 float progress, \
1283 int slice_start, int slice_end, int jobnr) \
1284 { \
1285 XFadeContext *s = ctx->priv; \
1286 const int nb_planes = s->nb_planes; \
1287 const int width = out->width; \
1288 const float w = width; \
1289 \
1290 for (int y = slice_start; y < slice_end; y++) { \
1291 for (int x = 0; x < width; x++) { \
1292 const float xx = (w - 1 - x) / w; \
1293 const float smooth = smoothstep(-0.5f, 0.f, xx - progress * 1.5f); \
1294 const float ss = smooth <= fract(10.f * xx) ? 0.f : 1.f; \
1295 \
1296 for (int p = 0; p < nb_planes; p++) { \
1297 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1298 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1299 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1300 \
1301 dst[x] = mix(xf1[x], xf0[x], ss); \
1302 } \
1303 } \
1304 } \
1305 }
1306
1307 HRSLICE_TRANSITION(8, uint8_t, 1)
1308 HRSLICE_TRANSITION(16, uint16_t, 2)
1309
1310 #define VUSLICE_TRANSITION(name, type, div) \
1311 static void vuslice##name##_transition(AVFilterContext *ctx, \
1312 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1313 float progress, \
1314 int slice_start, int slice_end, int jobnr) \
1315 { \
1316 XFadeContext *s = ctx->priv; \
1317 const int nb_planes = s->nb_planes; \
1318 const int width = out->width; \
1319 const float h = out->height; \
1320 \
1321 for (int y = slice_start; y < slice_end; y++) { \
1322 const float smooth = smoothstep(-0.5f, 0.f, y / h - progress * 1.5f); \
1323 const float ss = smooth <= fract(10.f * y / h) ? 0.f : 1.f; \
1324 \
1325 for (int x = 0; x < width; x++) { \
1326 for (int p = 0; p < nb_planes; p++) { \
1327 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1328 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1329 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1330 \
1331 dst[x] = mix(xf1[x], xf0[x], ss); \
1332 } \
1333 } \
1334 } \
1335 }
1336
1337 VUSLICE_TRANSITION(8, uint8_t, 1)
1338 VUSLICE_TRANSITION(16, uint16_t, 2)
1339
1340 #define VDSLICE_TRANSITION(name, type, div) \
1341 static void vdslice##name##_transition(AVFilterContext *ctx, \
1342 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1343 float progress, \
1344 int slice_start, int slice_end, int jobnr) \
1345 { \
1346 XFadeContext *s = ctx->priv; \
1347 const int nb_planes = s->nb_planes; \
1348 const int width = out->width; \
1349 const float h = out->height; \
1350 \
1351 for (int y = slice_start; y < slice_end; y++) { \
1352 const float yy = (h - 1 - y) / h; \
1353 const float smooth = smoothstep(-0.5f, 0.f, yy - progress * 1.5f); \
1354 const float ss = smooth <= fract(10.f * yy) ? 0.f : 1.f; \
1355 \
1356 for (int x = 0; x < width; x++) { \
1357 for (int p = 0; p < nb_planes; p++) { \
1358 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1359 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1360 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1361 \
1362 dst[x] = mix(xf1[x], xf0[x], ss); \
1363 } \
1364 } \
1365 } \
1366 }
1367
1368 VDSLICE_TRANSITION(8, uint8_t, 1)
1369 VDSLICE_TRANSITION(16, uint16_t, 2)
1370
1371 #define HBLUR_TRANSITION(name, type, div) \
1372 static void hblur##name##_transition(AVFilterContext *ctx, \
1373 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1374 float progress, \
1375 int slice_start, int slice_end, int jobnr) \
1376 { \
1377 XFadeContext *s = ctx->priv; \
1378 const int nb_planes = s->nb_planes; \
1379 const int width = out->width; \
1380 const float prog = progress <= 0.5f ? progress * 2.f : (1.f - progress) * 2.f; \
1381 const int size = 1 + (width / 2) * prog; \
1382 \
1383 for (int y = slice_start; y < slice_end; y++) { \
1384 for (int p = 0; p < nb_planes; p++) { \
1385 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1386 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1387 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1388 float sum0 = 0.f; \
1389 float sum1 = 0.f; \
1390 float cnt = size; \
1391 \
1392 for (int x = 0; x < size; x++) { \
1393 sum0 += xf0[x]; \
1394 sum1 += xf1[x]; \
1395 } \
1396 \
1397 for (int x = 0; x < width; x++) { \
1398 dst[x] = mix(sum0 / cnt, sum1 / cnt, progress); \
1399 \
1400 if (x + size < width) { \
1401 sum0 += xf0[x + size] - xf0[x]; \
1402 sum1 += xf1[x + size] - xf1[x]; \
1403 } else { \
1404 sum0 -= xf0[x]; \
1405 sum1 -= xf1[x]; \
1406 cnt--; \
1407 } \
1408 } \
1409 } \
1410 } \
1411 }
1412
1413 HBLUR_TRANSITION(8, uint8_t, 1)
1414 HBLUR_TRANSITION(16, uint16_t, 2)
1415
1416 #define FADEGRAYS_TRANSITION(name, type, div) \
1417 static void fadegrays##name##_transition(AVFilterContext *ctx, \
1418 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1419 float progress, \
1420 int slice_start, int slice_end, int jobnr) \
1421 { \
1422 XFadeContext *s = ctx->priv; \
1423 const int width = out->width; \
1424 const int is_rgb = s->is_rgb; \
1425 const int mid = (s->max_value + 1) / 2; \
1426 const float phase = 0.2f; \
1427 \
1428 for (int y = slice_start; y < slice_end; y++) { \
1429 for (int x = 0; x < width; x++) { \
1430 int bg[2][4]; \
1431 if (is_rgb) { \
1432 bg[0][0] = bg[1][0] = 0; \
1433 for (int p = 0; p < s->nb_planes; p++) { \
1434 const type *xf0 = (const type *)(a->data[p] + \
1435 y * a->linesize[p]); \
1436 const type *xf1 = (const type *)(b->data[p] + \
1437 y * b->linesize[p]); \
1438 if (p == 3) { \
1439 bg[0][3] = xf0[x]; \
1440 bg[1][3] = xf1[x]; \
1441 } else { \
1442 bg[0][0] += xf0[x]; \
1443 bg[1][0] += xf1[x]; \
1444 } \
1445 } \
1446 bg[0][0] = bg[0][0] / 3; \
1447 bg[1][0] = bg[1][0] / 3; \
1448 bg[0][1] = bg[0][2] = bg[0][0]; \
1449 bg[1][1] = bg[1][2] = bg[1][0]; \
1450 } else { \
1451 const type *yf0 = (const type *)(a->data[0] + \
1452 y * a->linesize[0]); \
1453 const type *yf1 = (const type *)(b->data[0] + \
1454 y * a->linesize[0]); \
1455 bg[0][0] = yf0[x]; \
1456 bg[1][0] = yf1[x]; \
1457 if (s->nb_planes == 4) { \
1458 const type *af0 = (const type *)(a->data[3] + \
1459 y * a->linesize[3]); \
1460 const type *af1 = (const type *)(b->data[3] + \
1461 y * a->linesize[3]); \
1462 bg[0][3] = af0[x]; \
1463 bg[1][3] = af1[x]; \
1464 } \
1465 bg[0][1] = bg[1][1] = mid; \
1466 bg[0][2] = bg[1][2] = mid; \
1467 } \
1468 \
1469 for (int p = 0; p < s->nb_planes; p++) { \
1470 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1471 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1472 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1473 \
1474 dst[x] = mix(mix(xf0[x], bg[0][p], \
1475 smoothstep(1.f-phase, 1.f, progress)), \
1476 mix(bg[1][p], xf1[x], smoothstep(phase, 1.f, progress)), \
1477 progress); \
1478 } \
1479 } \
1480 } \
1481 }
1482
1483 FADEGRAYS_TRANSITION(8, uint8_t, 1)
1484 FADEGRAYS_TRANSITION(16, uint16_t, 2)
1485
1486 #define WIPETL_TRANSITION(name, type, div) \
1487 static void wipetl##name##_transition(AVFilterContext *ctx, \
1488 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1489 float progress, \
1490 int slice_start, int slice_end, int jobnr) \
1491 { \
1492 XFadeContext *s = ctx->priv; \
1493 const int height = slice_end - slice_start; \
1494 const int width = out->width; \
1495 const int zw = out->width * progress; \
1496 const int zh = out->height * progress; \
1497 \
1498 for (int p = 0; p < s->nb_planes; p++) { \
1499 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1500 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1501 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1502 \
1503 for (int y = 0; y < height; y++) { \
1504 for (int x = 0; x < width; x++) { \
1505 dst[x] = slice_start + y <= zh && \
1506 x <= zw ? xf0[x] : xf1[x]; \
1507 } \
1508 \
1509 dst += out->linesize[p] / div; \
1510 xf0 += a->linesize[p] / div; \
1511 xf1 += b->linesize[p] / div; \
1512 } \
1513 } \
1514 }
1515
1516 WIPETL_TRANSITION(8, uint8_t, 1)
1517 WIPETL_TRANSITION(16, uint16_t, 2)
1518
1519 #define WIPETR_TRANSITION(name, type, div) \
1520 static void wipetr##name##_transition(AVFilterContext *ctx, \
1521 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1522 float progress, \
1523 int slice_start, int slice_end, int jobnr) \
1524 { \
1525 XFadeContext *s = ctx->priv; \
1526 const int height = slice_end - slice_start; \
1527 const int width = out->width; \
1528 const int zw = width * (1.f - progress); \
1529 const int zh = out->height * progress; \
1530 \
1531 for (int p = 0; p < s->nb_planes; p++) { \
1532 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1533 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1534 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1535 \
1536 for (int y = 0; y < height; y++) { \
1537 for (int x = 0; x < width; x++) { \
1538 dst[x] = slice_start + y <= zh && \
1539 x > zw ? xf0[x] : xf1[x]; \
1540 } \
1541 \
1542 dst += out->linesize[p] / div; \
1543 xf0 += a->linesize[p] / div; \
1544 xf1 += b->linesize[p] / div; \
1545 } \
1546 } \
1547 }
1548
1549 WIPETR_TRANSITION(8, uint8_t, 1)
1550 WIPETR_TRANSITION(16, uint16_t, 2)
1551
1552 #define WIPEBL_TRANSITION(name, type, div) \
1553 static void wipebl##name##_transition(AVFilterContext *ctx, \
1554 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1555 float progress, \
1556 int slice_start, int slice_end, int jobnr) \
1557 { \
1558 XFadeContext *s = ctx->priv; \
1559 const int height = slice_end - slice_start; \
1560 const int width = out->width; \
1561 const int zw = width * progress; \
1562 const int zh = out->height * (1.f - progress); \
1563 \
1564 for (int p = 0; p < s->nb_planes; p++) { \
1565 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1566 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1567 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1568 \
1569 for (int y = 0; y < height; y++) { \
1570 for (int x = 0; x < width; x++) { \
1571 dst[x] = slice_start + y > zh && \
1572 x <= zw ? xf0[x] : xf1[x]; \
1573 } \
1574 \
1575 dst += out->linesize[p] / div; \
1576 xf0 += a->linesize[p] / div; \
1577 xf1 += b->linesize[p] / div; \
1578 } \
1579 } \
1580 }
1581
1582 WIPEBL_TRANSITION(8, uint8_t, 1)
1583 WIPEBL_TRANSITION(16, uint16_t, 2)
1584
1585 #define WIPEBR_TRANSITION(name, type, div) \
1586 static void wipebr##name##_transition(AVFilterContext *ctx, \
1587 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1588 float progress, \
1589 int slice_start, int slice_end, int jobnr) \
1590 { \
1591 XFadeContext *s = ctx->priv; \
1592 const int height = slice_end - slice_start; \
1593 const int zh = out->height * (1.f - progress); \
1594 const int width = out->width; \
1595 const int zw = width * (1.f - progress); \
1596 \
1597 for (int p = 0; p < s->nb_planes; p++) { \
1598 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1599 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1600 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1601 \
1602 for (int y = 0; y < height; y++) { \
1603 for (int x = 0; x < width; x++) { \
1604 dst[x] = slice_start + y > zh && \
1605 x > zw ? xf0[x] : xf1[x]; \
1606 } \
1607 \
1608 dst += out->linesize[p] / div; \
1609 xf0 += a->linesize[p] / div; \
1610 xf1 += b->linesize[p] / div; \
1611 } \
1612 } \
1613 }
1614
1615 WIPEBR_TRANSITION(8, uint8_t, 1)
1616 WIPEBR_TRANSITION(16, uint16_t, 2)
1617
1618 #define SQUEEZEH_TRANSITION(name, type, div) \
1619 static void squeezeh##name##_transition(AVFilterContext *ctx, \
1620 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1621 float progress, \
1622 int slice_start, int slice_end, int jobnr) \
1623 { \
1624 XFadeContext *s = ctx->priv; \
1625 const float h = out->height; \
1626 const int height = slice_end - slice_start; \
1627 const int width = out->width; \
1628 \
1629 for (int p = 0; p < s->nb_planes; p++) { \
1630 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1631 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1632 \
1633 for (int y = 0; y < height; y++) { \
1634 const float z = .5f + ((slice_start + y) / h - .5f) / progress; \
1635 \
1636 if (z < 0.f || z > 1.f) { \
1637 for (int x = 0; x < width; x++) \
1638 dst[x] = xf1[x]; \
1639 } else { \
1640 const int yy = lrintf(z * (h - 1.f)); \
1641 const type *xf0 = (const type *)(a->data[p] + yy * a->linesize[p]); \
1642 \
1643 for (int x = 0; x < width; x++) \
1644 dst[x] = xf0[x]; \
1645 } \
1646 \
1647 dst += out->linesize[p] / div; \
1648 xf1 += b->linesize[p] / div; \
1649 } \
1650 } \
1651 }
1652
1653 SQUEEZEH_TRANSITION(8, uint8_t, 1)
1654 SQUEEZEH_TRANSITION(16, uint16_t, 2)
1655
1656 #define SQUEEZEV_TRANSITION(name, type, div) \
1657 static void squeezev##name##_transition(AVFilterContext *ctx, \
1658 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1659 float progress, \
1660 int slice_start, int slice_end, int jobnr) \
1661 { \
1662 XFadeContext *s = ctx->priv; \
1663 const int width = out->width; \
1664 const float w = width; \
1665 const int height = slice_end - slice_start; \
1666 \
1667 for (int p = 0; p < s->nb_planes; p++) { \
1668 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1669 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1670 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1671 \
1672 for (int y = 0; y < height; y++) { \
1673 for (int x = 0; x < width; x++) { \
1674 const float z = .5f + (x / w - .5f) / progress; \
1675 \
1676 if (z < 0.f || z > 1.f) { \
1677 dst[x] = xf1[x]; \
1678 } else { \
1679 const int xx = lrintf(z * (w - 1.f)); \
1680 \
1681 dst[x] = xf0[xx]; \
1682 } \
1683 } \
1684 \
1685 dst += out->linesize[p] / div; \
1686 xf0 += a->linesize[p] / div; \
1687 xf1 += b->linesize[p] / div; \
1688 } \
1689 } \
1690 }
1691
1692 SQUEEZEV_TRANSITION(8, uint8_t, 1)
1693 SQUEEZEV_TRANSITION(16, uint16_t, 2)
1694
1695 static void zoom(float *u, float *v, float amount)
1696 {
1697 *u = 0.5f + ((*u - 0.5f) * amount);
1698 *v = 0.5f + ((*v - 0.5f) * amount);
1699 }
1700
1701 #define ZOOMIN_TRANSITION(name, type, div) \
1702 static void zoomin##name##_transition(AVFilterContext *ctx, \
1703 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1704 float progress, \
1705 int slice_start, int slice_end, int jobnr) \
1706 { \
1707 XFadeContext *s = ctx->priv; \
1708 const int width = out->width; \
1709 const float w = width; \
1710 const float h = out->height; \
1711 const float zf = smoothstep(0.5f, 1.f, progress); \
1712 \
1713 for (int p = 0; p < s->nb_planes; p++) { \
1714 const type *xf0 = (const type *)(a->data[p]); \
1715 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1716 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1717 \
1718 for (int y = slice_start; y < slice_end; y++) { \
1719 for (int x = 0; x < width; x++) { \
1720 float zv, u, v; \
1721 int iu, iv; \
1722 \
1723 u = x / w; \
1724 v = y / h; \
1725 zoom(&u, &v, zf); \
1726 iu = ceilf(u * (w - 1)); \
1727 iv = ceilf(v * (h - 1)); \
1728 zv = xf0[iu + iv * a->linesize[p] / div]; \
1729 dst[x] = mix(zv, xf1[x], smoothstep(0.f, 0.5f, progress)); \
1730 } \
1731 dst += out->linesize[p] / div; \
1732 xf1 += b->linesize[p] / div; \
1733 } \
1734 } \
1735 }
1736
1737 ZOOMIN_TRANSITION(8, uint8_t, 1)
1738 ZOOMIN_TRANSITION(16, uint16_t, 2)
1739
1740 #define FADEFAST_TRANSITION(name, type, div) \
1741 static void fadefast##name##_transition(AVFilterContext *ctx, \
1742 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1743 float progress, \
1744 int slice_start, int slice_end, int jobnr) \
1745 { \
1746 XFadeContext *s = ctx->priv; \
1747 const int height = slice_end - slice_start; \
1748 const int width = out->width; \
1749 const float imax = 1.f / s->max_value; \
1750 \
1751 for (int p = 0; p < s->nb_planes; p++) { \
1752 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1753 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1754 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1755 \
1756 for (int y = 0; y < height; y++) { \
1757 for (int x = 0; x < width; x++) { \
1758 dst[x] = mix(xf0[x], xf1[x], powf(progress, 1.f + \
1759 logf(1.f+FFABS(xf0[x]-xf1[x])*imax)\
1760 )); \
1761 } \
1762 \
1763 dst += out->linesize[p] / div; \
1764 xf0 += a->linesize[p] / div; \
1765 xf1 += b->linesize[p] / div; \
1766 } \
1767 } \
1768 }
1769
1770 FADEFAST_TRANSITION(8, uint8_t, 1)
1771 FADEFAST_TRANSITION(16, uint16_t, 2)
1772
1773 #define FADESLOW_TRANSITION(name, type, div) \
1774 static void fadeslow##name##_transition(AVFilterContext *ctx, \
1775 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1776 float progress, \
1777 int slice_start, int slice_end, int jobnr) \
1778 { \
1779 XFadeContext *s = ctx->priv; \
1780 const int height = slice_end - slice_start; \
1781 const int width = out->width; \
1782 const float imax = 1.f / s->max_value; \
1783 \
1784 for (int p = 0; p < s->nb_planes; p++) { \
1785 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1786 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1787 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1788 \
1789 for (int y = 0; y < height; y++) { \
1790 for (int x = 0; x < width; x++) { \
1791 dst[x] = mix(xf0[x], xf1[x], powf(progress, 1.f + \
1792 logf(2.f-FFABS(xf0[x]-xf1[x])*imax)\
1793 )); \
1794 } \
1795 \
1796 dst += out->linesize[p] / div; \
1797 xf0 += a->linesize[p] / div; \
1798 xf1 += b->linesize[p] / div; \
1799 } \
1800 } \
1801 }
1802
1803 FADESLOW_TRANSITION(8, uint8_t, 1)
1804 FADESLOW_TRANSITION(16, uint16_t, 2)
1805
1806 #define HWIND_TRANSITION(name, z, type, div, expr) \
1807 static void h##z##wind##name##_transition(AVFilterContext *ctx, \
1808 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1809 float progress, \
1810 int slice_start, int slice_end, int jobnr) \
1811 { \
1812 XFadeContext *s = ctx->priv; \
1813 const int width = out->width; \
1814 \
1815 for (int y = slice_start; y < slice_end; y++) { \
1816 const float r = frand(0, y); \
1817 for (int x = 0; x < width; x++) { \
1818 const float fx = expr x / (float)width; \
1819 for (int p = 0; p < s->nb_planes; p++) { \
1820 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1821 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1822 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1823 \
1824 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f,-0.2f, fx * (1.f - 0.2f)\
1825 + 0.2f * r - (1.f - progress)\
1826 * (1.f + 0.2f))); \
1827 } \
1828 } \
1829 } \
1830 }
1831
1832 HWIND_TRANSITION(8, l, uint8_t, 1, 1.f - )
1833 HWIND_TRANSITION(16, l, uint16_t, 2, 1.f - )
1834 HWIND_TRANSITION(8, r, uint8_t, 1, )
1835 HWIND_TRANSITION(16, r, uint16_t, 2, )
1836
1837 #define VWIND_TRANSITION(name, z, type, div, expr) \
1838 static void v##z##wind##name##_transition(AVFilterContext *ctx, \
1839 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1840 float progress, \
1841 int slice_start, int slice_end, int jobnr) \
1842 { \
1843 XFadeContext *s = ctx->priv; \
1844 const int width = out->width; \
1845 \
1846 for (int y = slice_start; y < slice_end; y++) { \
1847 const float fy = expr y / (float)out->height; \
1848 for (int x = 0; x < width; x++) { \
1849 const float r = frand(x, 0); \
1850 for (int p = 0; p < s->nb_planes; p++) { \
1851 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1852 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1853 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1854 \
1855 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f,-0.2f, fy * (1.f - 0.2f) \
1856 + 0.2f * r - (1.f - progress)\
1857 * (1.f + 0.2f))); \
1858 } \
1859 } \
1860 } \
1861 }
1862
1863 VWIND_TRANSITION(8, u, uint8_t, 1, 1.f - )
1864 VWIND_TRANSITION(16, u, uint16_t, 2, 1.f - )
1865 VWIND_TRANSITION(8, d, uint8_t, 1, )
1866 VWIND_TRANSITION(16, d, uint16_t, 2, )
1867
1868 #define COVERH_TRANSITION(dir, name, type, div, expr) \
1869 static void cover##dir##name##_transition(AVFilterContext *ctx, \
1870 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1871 float progress, \
1872 int slice_start, int slice_end, int jobnr) \
1873 { \
1874 XFadeContext *s = ctx->priv; \
1875 const int height = slice_end - slice_start; \
1876 const int width = out->width; \
1877 const int z = (expr progress) * width; \
1878 \
1879 for (int p = 0; p < s->nb_planes; p++) { \
1880 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1881 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1882 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1883 \
1884 for (int y = 0; y < height; y++) { \
1885 for (int x = 0; x < width; x++) { \
1886 const int zx = z + x; \
1887 const int zz = zx % width + width * (zx < 0); \
1888 dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[x]; \
1889 } \
1890 \
1891 dst += out->linesize[p] / div; \
1892 xf0 += a->linesize[p] / div; \
1893 xf1 += b->linesize[p] / div; \
1894 } \
1895 } \
1896 }
1897
1898 COVERH_TRANSITION(left, 8, uint8_t, 1, -)
1899 COVERH_TRANSITION(left, 16, uint16_t, 2, -)
1900 COVERH_TRANSITION(right, 8, uint8_t, 1, )
1901 COVERH_TRANSITION(right, 16, uint16_t, 2, )
1902
1903 #define COVERV_TRANSITION(dir, name, type, div, expr) \
1904 static void cover##dir##name##_transition(AVFilterContext *ctx, \
1905 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1906 float progress, \
1907 int slice_start, int slice_end, int jobnr) \
1908 { \
1909 XFadeContext *s = ctx->priv; \
1910 const int height = out->height; \
1911 const int width = out->width; \
1912 const int z = (expr progress) * height; \
1913 \
1914 for (int p = 0; p < s->nb_planes; p++) { \
1915 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1916 \
1917 for (int y = slice_start; y < slice_end; y++) { \
1918 const int zy = z + y; \
1919 const int zz = zy % height + height * (zy < 0); \
1920 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1921 const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]); \
1922 \
1923 for (int x = 0; x < width; x++) \
1924 dst[x] = (zy >= 0) && (zy < height) ? xf1[x] : xf0[x]; \
1925 \
1926 dst += out->linesize[p] / div; \
1927 } \
1928 } \
1929 }
1930
1931 COVERV_TRANSITION(up, 8, uint8_t, 1, -)
1932 COVERV_TRANSITION(up, 16, uint16_t, 2, -)
1933 COVERV_TRANSITION(down, 8, uint8_t, 1, )
1934 COVERV_TRANSITION(down, 16, uint16_t, 2, )
1935
1936 #define REVEALH_TRANSITION(dir, name, type, div, expr) \
1937 static void reveal##dir##name##_transition(AVFilterContext *ctx, \
1938 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1939 float progress, \
1940 int slice_start, int slice_end, int jobnr) \
1941 { \
1942 XFadeContext *s = ctx->priv; \
1943 const int height = slice_end - slice_start; \
1944 const int width = out->width; \
1945 const int z = (expr progress) * width; \
1946 \
1947 for (int p = 0; p < s->nb_planes; p++) { \
1948 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1949 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1950 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1951 \
1952 for (int y = 0; y < height; y++) { \
1953 for (int x = 0; x < width; x++) { \
1954 const int zx = z + x; \
1955 const int zz = zx % width + width * (zx < 0); \
1956 dst[x] = (zx >= 0) && (zx < width) ? xf1[x] : xf0[zz]; \
1957 } \
1958 \
1959 dst += out->linesize[p] / div; \
1960 xf0 += a->linesize[p] / div; \
1961 xf1 += b->linesize[p] / div; \
1962 } \
1963 } \
1964 }
1965
1966 REVEALH_TRANSITION(left, 8, uint8_t, 1, -)
1967 REVEALH_TRANSITION(left, 16, uint16_t, 2, -)
1968 REVEALH_TRANSITION(right, 8, uint8_t, 1, )
1969 REVEALH_TRANSITION(right, 16, uint16_t, 2, )
1970
1971 #define REVEALV_TRANSITION(dir, name, type, div, expr) \
1972 static void reveal##dir##name##_transition(AVFilterContext *ctx, \
1973 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1974 float progress, \
1975 int slice_start, int slice_end, int jobnr) \
1976 { \
1977 XFadeContext *s = ctx->priv; \
1978 const int height = out->height; \
1979 const int width = out->width; \
1980 const int z = (expr progress) * height; \
1981 \
1982 for (int p = 0; p < s->nb_planes; p++) { \
1983 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1984 \
1985 for (int y = slice_start; y < slice_end; y++) { \
1986 const int zy = z + y; \
1987 const int zz = zy % height + height * (zy < 0); \
1988 const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \
1989 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1990 \
1991 for (int x = 0; x < width; x++) \
1992 dst[x] = (zy >= 0) && (zy < height) ? xf1[x] : xf0[x]; \
1993 \
1994 dst += out->linesize[p] / div; \
1995 } \
1996 } \
1997 }
1998
1999 REVEALV_TRANSITION(up, 8, uint8_t, 1, -)
2000 REVEALV_TRANSITION(up, 16, uint16_t, 2, -)
2001 REVEALV_TRANSITION(down, 8, uint8_t, 1, )
2002 REVEALV_TRANSITION(down, 16, uint16_t, 2, )
2003
2004 static inline double getpix(void *priv, double x, double y, int plane, int nb)
2005 {
2006 XFadeContext *s = priv;
2007 AVFrame *in = s->xf[nb];
2008 const uint8_t *src = in->data[FFMIN(plane, s->nb_planes - 1)];
2009 int linesize = in->linesize[FFMIN(plane, s->nb_planes - 1)];
2010 const int w = in->width;
2011 const int h = in->height;
2012
2013 int xi, yi;
2014
2015 xi = av_clipd(x, 0, w - 1);
2016 yi = av_clipd(y, 0, h - 1);
2017
2018 if (s->depth > 8) {
2019 const uint16_t *src16 = (const uint16_t*)src;
2020
2021 linesize /= 2;
2022 return src16[xi + yi * linesize];
2023 } else {
2024 return src[xi + yi * linesize];
2025 }
2026 }
2027
2028 static double a0(void *priv, double x, double y) { return getpix(priv, x, y, 0, 0); }
2029 static double a1(void *priv, double x, double y) { return getpix(priv, x, y, 1, 0); }
2030 static double a2(void *priv, double x, double y) { return getpix(priv, x, y, 2, 0); }
2031 static double a3(void *priv, double x, double y) { return getpix(priv, x, y, 3, 0); }
2032
2033 static double b0(void *priv, double x, double y) { return getpix(priv, x, y, 0, 1); }
2034 static double b1(void *priv, double x, double y) { return getpix(priv, x, y, 1, 1); }
2035 static double b2(void *priv, double x, double y) { return getpix(priv, x, y, 2, 1); }
2036 static double b3(void *priv, double x, double y) { return getpix(priv, x, y, 3, 1); }
2037
2038 static int config_output(AVFilterLink *outlink)
2039 {
2040 AVFilterContext *ctx = outlink->src;
2041 AVFilterLink *inlink0 = ctx->inputs[0];
2042 AVFilterLink *inlink1 = ctx->inputs[1];
2043 FilterLink *inl0 = ff_filter_link(inlink0);
2044 FilterLink *inl1 = ff_filter_link(inlink1);
2045 FilterLink *ol = ff_filter_link(outlink);
2046 XFadeContext *s = ctx->priv;
2047 const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink0->format);
2048
2049 if (inlink0->w != inlink1->w || inlink0->h != inlink1->h) {
2050 av_log(ctx, AV_LOG_ERROR, "First input link %s parameters "
2051 "(size %dx%d) do not match the corresponding "
2052 "second input link %s parameters (size %dx%d)\n",
2053 ctx->input_pads[0].name, inlink0->w, inlink0->h,
2054 ctx->input_pads[1].name, inlink1->w, inlink1->h);
2055 return AVERROR(EINVAL);
2056 }
2057
2058 if (inlink0->time_base.num != inlink1->time_base.num ||
2059 inlink0->time_base.den != inlink1->time_base.den) {
2060 av_log(ctx, AV_LOG_ERROR, "First input link %s timebase "
2061 "(%d/%d) do not match the corresponding "
2062 "second input link %s timebase (%d/%d)\n",
2063 ctx->input_pads[0].name, inlink0->time_base.num, inlink0->time_base.den,
2064 ctx->input_pads[1].name, inlink1->time_base.num, inlink1->time_base.den);
2065 return AVERROR(EINVAL);
2066 }
2067
2068 if (!inl0->frame_rate.num || !inl0->frame_rate.den) {
2069 av_log(ctx, AV_LOG_ERROR, "The inputs needs to be a constant frame rate; "
2070 "current rate of %d/%d is invalid\n", inl0->frame_rate.num, inl0->frame_rate.den);
2071 return AVERROR(EINVAL);
2072 }
2073
2074 if (inl0->frame_rate.num != inl1->frame_rate.num ||
2075 inl0->frame_rate.den != inl1->frame_rate.den) {
2076 av_log(ctx, AV_LOG_ERROR, "First input link %s frame rate "
2077 "(%d/%d) do not match the corresponding "
2078 "second input link %s frame rate (%d/%d)\n",
2079 ctx->input_pads[0].name, inl0->frame_rate.num, inl0->frame_rate.den,
2080 ctx->input_pads[1].name, inl1->frame_rate.num, inl1->frame_rate.den);
2081 return AVERROR(EINVAL);
2082 }
2083
2084 outlink->w = inlink0->w;
2085 outlink->h = inlink0->h;
2086 outlink->time_base = inlink0->time_base;
2087 outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
2088 ol->frame_rate = inl0->frame_rate;
2089
2090 s->depth = pix_desc->comp[0].depth;
2091 s->is_rgb = !!(pix_desc->flags & AV_PIX_FMT_FLAG_RGB);
2092 s->nb_planes = av_pix_fmt_count_planes(inlink0->format);
2093 s->max_value = (1 << s->depth) - 1;
2094 s->black[0] = 0;
2095 s->black[1] = s->black[2] = s->is_rgb ? 0 : s->max_value / 2;
2096 s->black[3] = s->max_value;
2097 s->white[0] = s->white[3] = s->max_value;
2098 s->white[1] = s->white[2] = s->is_rgb ? s->max_value : s->max_value / 2;
2099
2100 s->start_pts = s->inputs_offset_pts = AV_NOPTS_VALUE;
2101
2102 if (s->duration)
2103 s->duration_pts = av_rescale_q(s->duration, AV_TIME_BASE_Q, outlink->time_base);
2104
2105 switch (s->transition) {
2106 case CUSTOM: s->transitionf = s->depth <= 8 ? custom8_transition : custom16_transition; break;
2107 case FADE: s->transitionf = s->depth <= 8 ? fade8_transition : fade16_transition; break;
2108 case WIPELEFT: s->transitionf = s->depth <= 8 ? wipeleft8_transition : wipeleft16_transition; break;
2109 case WIPERIGHT: s->transitionf = s->depth <= 8 ? wiperight8_transition : wiperight16_transition; break;
2110 case WIPEUP: s->transitionf = s->depth <= 8 ? wipeup8_transition : wipeup16_transition; break;
2111 case WIPEDOWN: s->transitionf = s->depth <= 8 ? wipedown8_transition : wipedown16_transition; break;
2112 case SLIDELEFT: s->transitionf = s->depth <= 8 ? slideleft8_transition : slideleft16_transition; break;
2113 case SLIDERIGHT: s->transitionf = s->depth <= 8 ? slideright8_transition : slideright16_transition; break;
2114 case SLIDEUP: s->transitionf = s->depth <= 8 ? slideup8_transition : slideup16_transition; break;
2115 case SLIDEDOWN: s->transitionf = s->depth <= 8 ? slidedown8_transition : slidedown16_transition; break;
2116 case CIRCLECROP: s->transitionf = s->depth <= 8 ? circlecrop8_transition : circlecrop16_transition; break;
2117 case RECTCROP: s->transitionf = s->depth <= 8 ? rectcrop8_transition : rectcrop16_transition; break;
2118 case DISTANCE: s->transitionf = s->depth <= 8 ? distance8_transition : distance16_transition; break;
2119 case FADEBLACK: s->transitionf = s->depth <= 8 ? fadeblack8_transition : fadeblack16_transition; break;
2120 case FADEWHITE: s->transitionf = s->depth <= 8 ? fadewhite8_transition : fadewhite16_transition; break;
2121 case RADIAL: s->transitionf = s->depth <= 8 ? radial8_transition : radial16_transition; break;
2122 case SMOOTHLEFT: s->transitionf = s->depth <= 8 ? smoothleft8_transition : smoothleft16_transition; break;
2123 case SMOOTHRIGHT:s->transitionf = s->depth <= 8 ? smoothright8_transition: smoothright16_transition;break;
2124 case SMOOTHUP: s->transitionf = s->depth <= 8 ? smoothup8_transition : smoothup16_transition; break;
2125 case SMOOTHDOWN: s->transitionf = s->depth <= 8 ? smoothdown8_transition : smoothdown16_transition; break;
2126 case CIRCLEOPEN: s->transitionf = s->depth <= 8 ? circleopen8_transition : circleopen16_transition; break;
2127 case CIRCLECLOSE:s->transitionf = s->depth <= 8 ? circleclose8_transition: circleclose16_transition;break;
2128 case VERTOPEN: s->transitionf = s->depth <= 8 ? vertopen8_transition : vertopen16_transition; break;
2129 case VERTCLOSE: s->transitionf = s->depth <= 8 ? vertclose8_transition : vertclose16_transition; break;
2130 case HORZOPEN: s->transitionf = s->depth <= 8 ? horzopen8_transition : horzopen16_transition; break;
2131 case HORZCLOSE: s->transitionf = s->depth <= 8 ? horzclose8_transition : horzclose16_transition; break;
2132 case DISSOLVE: s->transitionf = s->depth <= 8 ? dissolve8_transition : dissolve16_transition; break;
2133 case PIXELIZE: s->transitionf = s->depth <= 8 ? pixelize8_transition : pixelize16_transition; break;
2134 case DIAGTL: s->transitionf = s->depth <= 8 ? diagtl8_transition : diagtl16_transition; break;
2135 case DIAGTR: s->transitionf = s->depth <= 8 ? diagtr8_transition : diagtr16_transition; break;
2136 case DIAGBL: s->transitionf = s->depth <= 8 ? diagbl8_transition : diagbl16_transition; break;
2137 case DIAGBR: s->transitionf = s->depth <= 8 ? diagbr8_transition : diagbr16_transition; break;
2138 case HLSLICE: s->transitionf = s->depth <= 8 ? hlslice8_transition : hlslice16_transition; break;
2139 case HRSLICE: s->transitionf = s->depth <= 8 ? hrslice8_transition : hrslice16_transition; break;
2140 case VUSLICE: s->transitionf = s->depth <= 8 ? vuslice8_transition : vuslice16_transition; break;
2141 case VDSLICE: s->transitionf = s->depth <= 8 ? vdslice8_transition : vdslice16_transition; break;
2142 case HBLUR: s->transitionf = s->depth <= 8 ? hblur8_transition : hblur16_transition; break;
2143 case FADEGRAYS: s->transitionf = s->depth <= 8 ? fadegrays8_transition : fadegrays16_transition; break;
2144 case WIPETL: s->transitionf = s->depth <= 8 ? wipetl8_transition : wipetl16_transition; break;
2145 case WIPETR: s->transitionf = s->depth <= 8 ? wipetr8_transition : wipetr16_transition; break;
2146 case WIPEBL: s->transitionf = s->depth <= 8 ? wipebl8_transition : wipebl16_transition; break;
2147 case WIPEBR: s->transitionf = s->depth <= 8 ? wipebr8_transition : wipebr16_transition; break;
2148 case SQUEEZEH: s->transitionf = s->depth <= 8 ? squeezeh8_transition : squeezeh16_transition; break;
2149 case SQUEEZEV: s->transitionf = s->depth <= 8 ? squeezev8_transition : squeezev16_transition; break;
2150 case ZOOMIN: s->transitionf = s->depth <= 8 ? zoomin8_transition : zoomin16_transition; break;
2151 case FADEFAST: s->transitionf = s->depth <= 8 ? fadefast8_transition : fadefast16_transition; break;
2152 case FADESLOW: s->transitionf = s->depth <= 8 ? fadeslow8_transition : fadeslow16_transition; break;
2153 case HLWIND: s->transitionf = s->depth <= 8 ? hlwind8_transition : hlwind16_transition; break;
2154 case HRWIND: s->transitionf = s->depth <= 8 ? hrwind8_transition : hrwind16_transition; break;
2155 case VUWIND: s->transitionf = s->depth <= 8 ? vuwind8_transition : vuwind16_transition; break;
2156 case VDWIND: s->transitionf = s->depth <= 8 ? vdwind8_transition : vdwind16_transition; break;
2157 case COVERLEFT: s->transitionf = s->depth <= 8 ? coverleft8_transition : coverleft16_transition; break;
2158 case COVERRIGHT: s->transitionf = s->depth <= 8 ? coverright8_transition : coverright16_transition; break;
2159 case COVERUP: s->transitionf = s->depth <= 8 ? coverup8_transition : coverup16_transition; break;
2160 case COVERDOWN: s->transitionf = s->depth <= 8 ? coverdown8_transition : coverdown16_transition; break;
2161 case REVEALLEFT: s->transitionf = s->depth <= 8 ? revealleft8_transition : revealleft16_transition; break;
2162 case REVEALRIGHT:s->transitionf = s->depth <= 8 ? revealright8_transition: revealright16_transition;break;
2163 case REVEALUP: s->transitionf = s->depth <= 8 ? revealup8_transition : revealup16_transition; break;
2164 case REVEALDOWN: s->transitionf = s->depth <= 8 ? revealdown8_transition : revealdown16_transition; break;
2165 default: return AVERROR_BUG;
2166 }
2167
2168 if (s->transition == CUSTOM) {
2169 static const char *const func2_names[] = {
2170 "a0", "a1", "a2", "a3",
2171 "b0", "b1", "b2", "b3",
2172 NULL
2173 };
2174 double (*func2[])(void *, double, double) = {
2175 a0, a1, a2, a3,
2176 b0, b1, b2, b3,
2177 NULL };
2178 int ret;
2179
2180 if (!s->custom_str)
2181 return AVERROR(EINVAL);
2182 ret = av_expr_parse(&s->e, s->custom_str, var_names,
2183 NULL, NULL, func2_names, func2, 0, ctx);
2184 if (ret < 0)
2185 return ret;
2186 }
2187
2188 return 0;
2189 }
2190
2191 static int xfade_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
2192 {
2193 XFadeContext *s = ctx->priv;
2194 AVFilterLink *outlink = ctx->outputs[0];
2195 ThreadData *td = arg;
2196 int slice_start = (outlink->h * jobnr ) / nb_jobs;
2197 int slice_end = (outlink->h * (jobnr+1)) / nb_jobs;
2198
2199 s->transitionf(ctx, td->xf[0], td->xf[1], td->out, td->progress, slice_start, slice_end, jobnr);
2200
2201 return 0;
2202 }
2203
2204 static int xfade_frame(AVFilterContext *ctx, AVFrame *a, AVFrame *b)
2205 {
2206 XFadeContext *s = ctx->priv;
2207 AVFilterLink *outlink = ctx->outputs[0];
2208 float progress = av_clipf(1.f - ((float)(s->pts - s->start_pts) / s->duration_pts), 0.f, 1.f);
2209 ThreadData td;
2210 AVFrame *out;
2211
2212 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
2213 if (!out)
2214 return AVERROR(ENOMEM);
2215 av_frame_copy_props(out, a);
2216
2217 td.xf[0] = a, td.xf[1] = b, td.out = out, td.progress = progress;
2218 ff_filter_execute(ctx, xfade_slice, &td, NULL,
2219 FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
2220
2221 out->pts = s->pts;
2222
2223 return ff_filter_frame(outlink, out);
2224 }
2225
2226 static int forward_frame(XFadeContext *s,
2227 AVFilterLink *inlink, AVFilterLink *outlink)
2228 {
2229 int64_t status_pts;
2230 int ret = 0, status;
2231 AVFrame *frame = NULL;
2232
2233 ret = ff_inlink_consume_frame(inlink, &frame);
2234 if (ret < 0)
2235 return ret;
2236
2237 if (ret > 0) {
2238 // If we do not have an offset yet, it's because we
2239 // never got a first input. Just offset to 0
2240 if (s->inputs_offset_pts == AV_NOPTS_VALUE)
2241 s->inputs_offset_pts = -frame->pts;
2242
2243 // We got a frame, nothing to do other than adjusting the timestamp
2244 frame->pts += s->inputs_offset_pts;
2245 return ff_filter_frame(outlink, frame);
2246 }
2247
2248 // Forward status with our timestamp
2249 if (ff_inlink_acknowledge_status(inlink, &status, &status_pts)) {
2250 if (s->inputs_offset_pts == AV_NOPTS_VALUE)
2251 s->inputs_offset_pts = -status_pts;
2252
2253 ff_outlink_set_status(outlink, status, status_pts + s->inputs_offset_pts);
2254 return 0;
2255 }
2256
2257 // No frame available, request one if needed
2258 if (ff_outlink_frame_wanted(outlink))
2259 ff_inlink_request_frame(inlink);
2260
2261 return 0;
2262 }
2263
2264 static int xfade_activate(AVFilterContext *avctx)
2265 {
2266 XFadeContext *s = avctx->priv;
2267 AVFilterLink *in_a = avctx->inputs[0];
2268 AVFilterLink *in_b = avctx->inputs[1];
2269 AVFilterLink *outlink = avctx->outputs[0];
2270 int64_t status_pts;
2271
2272 FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, avctx);
2273
2274 // Check if we already transitioned or first input ended prematurely,
2275 // in which case just forward the frames from second input with adjusted
2276 // timestamps until EOF.
2277 if (s->status[0] && !s->status[1])
2278 return forward_frame(s, in_b, outlink);
2279
2280 // We did not finish transitioning yet and the first stream
2281 // did not end either, so check if there are more frames to consume.
2282 if (ff_inlink_check_available_frame(in_a)) {
2283 AVFrame *peeked_frame = ff_inlink_peek_frame(in_a, 0);
2284 s->pts = peeked_frame->pts;
2285
2286 if (s->start_pts == AV_NOPTS_VALUE)
2287 s->start_pts =
2288 s->pts + av_rescale_q(s->offset, AV_TIME_BASE_Q, in_a->time_base);
2289
2290 // Check if we are not yet transitioning, in which case
2291 // just request and forward the input frame.
2292 if (s->start_pts > s->pts) {
2293 int ret;
2294 s->passthrough = 1;
2295 ret = ff_inlink_consume_frame(in_a, &s->xf[0]);
2296 if (ret < 0)
2297 return ret;
2298 return ff_filter_frame(outlink, s->xf[0]);
2299 }
2300 s->passthrough = 0;
2301
2302 // We are transitioning, so we need a frame from second input
2303 if (ff_inlink_check_available_frame(in_b)) {
2304 int ret;
2305 ret = ff_inlink_consume_frame(avctx->inputs[0], &s->xf[0]);
2306 if (ret < 0)
2307 return ret;
2308 ret = ff_inlink_consume_frame(avctx->inputs[1], &s->xf[1]);
2309 if (ret < 0) {
2310 av_frame_free(&s->xf[0]);
2311 return ret;
2312 }
2313
2314 // Calculate PTS offset to first input
2315 if (s->inputs_offset_pts == AV_NOPTS_VALUE)
2316 s->inputs_offset_pts = s->pts - s->xf[1]->pts;
2317
2318 // Check if we finished transitioning, in which case we
2319 // report back EOF to first input as it is no longer needed.
2320 if (s->pts - s->start_pts > s->duration_pts) {
2321 s->status[0] = AVERROR_EOF;
2322 ff_inlink_set_status(in_a, AVERROR_EOF);
2323 s->passthrough = 1;
2324 }
2325 ret = xfade_frame(avctx, s->xf[0], s->xf[1]);
2326 av_frame_free(&s->xf[0]);
2327 av_frame_free(&s->xf[1]);
2328 return ret;
2329 }
2330
2331 // We did not get a frame from second input, check its status.
2332 if (ff_inlink_acknowledge_status(in_b, &s->status[1], &status_pts)) {
2333 // We should transition, but second input is EOF so just report EOF output now.
2334 ff_outlink_set_status(outlink, s->status[1], s->pts);
2335 return 0;
2336 }
2337
2338 // We did not get a frame for second input but no EOF either, so just request more.
2339 if (ff_outlink_frame_wanted(outlink)) {
2340 ff_inlink_request_frame(in_b);
2341 return 0;
2342 }
2343 }
2344
2345 // We did not get a frame from first input, check its status.
2346 if (ff_inlink_acknowledge_status(in_a, &s->status[0], &status_pts)) {
2347 // No more frames from first input, do not report EOF though, we will just
2348 // forward the second input frames in the next activate calls.
2349 s->passthrough = 1;
2350 ff_filter_set_ready(avctx, 100);
2351 return 0;
2352 }
2353
2354 // We have no frames yet from first input and no EOF, so request some.
2355 if (ff_outlink_frame_wanted(outlink)) {
2356 ff_inlink_request_frame(in_a);
2357 return 0;
2358 }
2359
2360 return FFERROR_NOT_READY;
2361 }
2362
2363 static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
2364 {
2365 XFadeContext *s = inlink->dst->priv;
2366
2367 return s->passthrough ?
2368 ff_null_get_video_buffer (inlink, w, h) :
2369 ff_default_get_video_buffer(inlink, w, h);
2370 }
2371
2372 static const AVFilterPad xfade_inputs[] = {
2373 {
2374 .name = "main",
2375 .type = AVMEDIA_TYPE_VIDEO,
2376 .get_buffer.video = get_video_buffer,
2377 },
2378 {
2379 .name = "xfade",
2380 .type = AVMEDIA_TYPE_VIDEO,
2381 .get_buffer.video = get_video_buffer,
2382 },
2383 };
2384
2385 static const AVFilterPad xfade_outputs[] = {
2386 {
2387 .name = "default",
2388 .type = AVMEDIA_TYPE_VIDEO,
2389 .config_props = config_output,
2390 },
2391 };
2392
2393 const FFFilter ff_vf_xfade = {
2394 .p.name = "xfade",
2395 .p.description = NULL_IF_CONFIG_SMALL("Cross fade one video with another video."),
2396 .p.priv_class = &xfade_class,
2397 .p.flags = AVFILTER_FLAG_SLICE_THREADS,
2398 .priv_size = sizeof(XFadeContext),
2399 .activate = xfade_activate,
2400 .uninit = uninit,
2401 FILTER_INPUTS(xfade_inputs),
2402 FILTER_OUTPUTS(xfade_outputs),
2403 FILTER_PIXFMTS_ARRAY(pix_fmts),
2404 };
2405

sapphire手表什么牌子 李白被人们称为什么 运钞车是什么车 莱赛尔纤维是什么面料 额头上长痘是什么原因
什么时候开始数伏 肌酐高什么原因引起的 police是什么品牌 什么样的人做什么样的事 什么样的月光
身上长红痘痘是什么原因 alt是什么意思 呆萌是什么意思 6月21号是什么日子 扁桃体肥大是什么原因造成的
苏州立秋吃什么 肠胃属于什么科 什么办法退烧快 为什么要做羊水穿刺检查 五月份什么星座
虫可念什么xinjiangjialails.com 羊水是什么颜色hcv9jop0ns9r.cn 洋参片泡水喝有什么功效hcv8jop7ns8r.cn 戴帽子是什么意思hcv8jop1ns0r.cn 表现手法有什么hcv9jop0ns9r.cn
mg什么意思hcv9jop2ns2r.cn 为什么会血压低hlguo.com 锁精环是什么wzqsfys.com 蟹粉是什么zhongyiyatai.com 今天是什么日子 农历tiangongnft.com
小囊肿是什么病严重吗hcv9jop1ns5r.cn 吉士粉是什么粉hcv9jop7ns1r.cn 西皮是什么意思hcv8jop7ns5r.cn 什么是直系亲属hcv8jop0ns5r.cn 头皮屑是什么东西hcv9jop7ns4r.cn
乳腺结节钙化是什么意思hcv9jop8ns1r.cn 大腿麻木是什么原因hcv9jop5ns0r.cn 医调委是什么机构hcv8jop5ns1r.cn 菊花代表什么象征意义hcv9jop5ns4r.cn 淋巴细胞绝对值偏低说明什么hcv8jop2ns8r.cn
百度