History

avfilter/interlace: add complex vertical low-pass filter

This complex (-1 2 6 2 -1) filter slightly less reduces interlace 'twitter' but better retain detail and subjective sharpness impression compared to the linear (1 2 1) filter.

Thomas Mundt committed 9 years ago

Commit 2da5bf41 parent 20da41310 files · +246 −24Browse files

Unified · Split

10 files
  1. doc/filters.texi +23 −4
  2. libavfilter/interlace.h +6 −0
  3. libavfilter/tinterlace.h +4 −0
  4. libavfilter/vf_interlace.c +46 −3
  5. libavfilter/vf_tinterlace.c +50 −11
  6. libavfilter/x86/vf_interlace.asm +60 −0
  7. libavfilter/x86/vf_interlace_init.c +12 −3
  8. libavfilter/x86/vf_tinterlace_init.c +12 −3
  9. tests/fate/filter-video.mak +3 −0
  10. tests/ref/fate/filter-interlace-complex +30 −0
doc/filters.texi+23−4
@@ -9158,8 +9158,21 @@ This determines whether the interlaced frame is taken from the even · 9157 unmodified lines
91589158 (tff - default) or odd (bff) lines of the progressive frame.
91599159
91609160 @item lowpass
9161−Enable (default) or disable the vertical lowpass filter to avoid twitter
9162−interlacing and reduce moire patterns.
9161+Vertical lowpass filter to avoid twitter interlacing and
9162+reduce moire patterns.
9163+
9164+@table @samp
9165+@item 0, off
9166+Disable vertical lowpass filter
9167+
9168+@item 1, linear
9169+Enable linear filter (default)
9170+
9171+@item 2, complex
9172+Enable complex filter. This will slightly less reduce twitter and moire
9173+but better retain detail and subjective sharpness impression.
9174+
9175+@end table
91639176 @end table
91649177
91659178 @section kerndeint
@@ -13857,16 +13870,22 @@ Available value for @var{flags} is: · 4691 unmodified lines
1385713870
1385813871 @table @option
1385913872 @item low_pass_filter, vlfp
13860−Enable vertical low-pass filtering in the filter.
13873+Enable linear vertical low-pass filtering in the filter.
1386113874 Vertical low-pass filtering is required when creating an interlaced
1386213875 destination from a progressive source which contains high-frequency
1386313876 vertical detail. Filtering will reduce interlace 'twitter' and Moire
1386413877 patterning.
1386513878
13879+@item complex_filter, cvlfp
13880+Enable complex vertical low-pass filtering.
13881+This will slightly less reduce interlace 'twitter' and Moire
13882+patterning but better retain detail and subjective sharpness impression.
13883+
13884+@end table
13885+
1386613886 Vertical low-pass filtering can only be enabled for @option{mode}
1386713887 @var{interleave_top} and @var{interleave_bottom}.
1386813888
13869−@end table
1387013889 @end table
1387113890
1387213891 @section transpose
libavfilter/interlace.h+6−0
@@ -44,6 +44,12 @@ enum FieldType { · 43 unmodified lines
4444 FIELD_LOWER = 1,
4545 };
4646
47+enum VLPFilter {
48+ VLPF_OFF = 0,
49+ VLPF_LIN = 1,
50+ VLPF_CMP = 2,
51+};
52+
4753 typedef struct InterlaceContext {
4854 const AVClass *class;
4955 enum ScanMode scan; // top or bottom field first scanning
libavfilter/tinterlace.h+4−0
@@ -30,6 +30,10 @@ · 29 unmodified lines
3030 #include "libavutil/opt.h"
3131 #include "avfilter.h"
3232
33+#define TINTERLACE_FLAG_VLPF 01
34+#define TINTERLACE_FLAG_EXACT_TB 2
35+#define TINTERLACE_FLAG_CVLPF 4
36+
3337 enum TInterlaceMode {
3438 MODE_MERGE = 0,
3539 MODE_DROP_EVEN,
libavfilter/vf_interlace.c+46−3
@@ -3,6 +3,7 @@ · 2 unmodified lines
33 * Copyright (c) 2010 Baptiste Coudurier
44 * Copyright (c) 2011 Stefano Sabatini
55 * Copyright (c) 2013 Vittorio Giovara <vittorio.giovara@gmail.com>
6+ * Copyright (c) 2017 Thomas Mundt <tmundt75@gmail.com>
67 *
78 * This file is part of FFmpeg.
89 *
@@ -47,7 +48,13 @@ static const AVOption interlace_options[] = { · 38 unmodified lines
4748 { "bff", "bottom field first", 0,
4849 AV_OPT_TYPE_CONST, {.i64 = MODE_BFF }, INT_MIN, INT_MAX, .flags = FLAGS, .unit = "scan" },
4950 { "lowpass", "set vertical low-pass filter", OFFSET(lowpass),
50− AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, .flags = FLAGS },
51+ AV_OPT_TYPE_INT, {.i64 = VLPF_LIN }, 0, 2, .flags = FLAGS, .unit = "lowpass" },
52+ { "off", "disable vertical low-pass filter", 0,
53+ AV_OPT_TYPE_CONST, {.i64 = VLPF_OFF }, INT_MIN, INT_MAX, .flags = FLAGS, .unit = "lowpass" },
54+ { "linear", "linear vertical low-pass filter", 0,
55+ AV_OPT_TYPE_CONST, {.i64 = VLPF_LIN }, INT_MIN, INT_MAX, .flags = FLAGS, .unit = "lowpass" },
56+ { "complex", "complex vertical low-pass filter", 0,
57+ AV_OPT_TYPE_CONST, {.i64 = VLPF_CMP }, INT_MIN, INT_MAX, .flags = FLAGS, .unit = "lowpass" },
5158 { NULL }
5259 };
5360
@@ -68,6 +75,25 @@ static void lowpass_line_c(uint8_t *dstp, ptrdiff_t linesize, · 14 unmodified lines
6875 }
6976 }
7077
78+static void lowpass_line_complex_c(uint8_t *dstp, ptrdiff_t linesize,
79+ const uint8_t *srcp,
80+ ptrdiff_t mref, ptrdiff_t pref)
81+{
82+ const uint8_t *srcp_above = srcp + mref;
83+ const uint8_t *srcp_below = srcp + pref;
84+ const uint8_t *srcp_above2 = srcp + mref * 2;
85+ const uint8_t *srcp_below2 = srcp + pref * 2;
86+ int i;
87+ for (i = 0; i < linesize; i++) {
88+ // this calculation is an integer representation of
89+ // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
90+ // '4 +' is for rounding.
91+ dstp[i] = av_clip_uint8((4 + (srcp[i] << 2)
92+ + ((srcp[i] + srcp_above[i] + srcp_below[i]) << 1)
93+ - srcp_above2[i] - srcp_below2[i]) >> 3);
94+ }
95+}
96+
7197 static const enum AVPixelFormat formats_supported[] = {
7298 AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P,
7399 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUVA420P,
@@ -117,7 +143,10 @@ static int config_out_props(AVFilterLink *outlink) · 43 unmodified lines
117143
118144
119145 if (s->lowpass) {
120− s->lowpass_line = lowpass_line_c;
146+ if (s->lowpass == VLPF_LIN)
147+ s->lowpass_line = lowpass_line_c;
148+ else if (s->lowpass == VLPF_CMP)
149+ s->lowpass_line = lowpass_line_complex_c;
121150 if (ARCH_X86)
122151 ff_interlace_init_x86(s);
123152 }
@@ -151,7 +180,7 @@ static void copy_picture_field(InterlaceContext *s, · 27 unmodified lines
151180 srcp += src_frame->linesize[plane];
152181 dstp += dst_frame->linesize[plane];
153182 }
154− if (lowpass) {
183+ if (lowpass == VLPF_LIN) {
155184 int srcp_linesize = src_frame->linesize[plane] * 2;
156185 int dstp_linesize = dst_frame->linesize[plane] * 2;
157186 for (j = lines; j > 0; j--) {
@@ -165,6 +194,20 @@ static void copy_picture_field(InterlaceContext *s, · 7 unmodified lines
165194 dstp += dstp_linesize;
166195 srcp += srcp_linesize;
167196 }
197+ } else if (lowpass == VLPF_CMP) {
198+ int srcp_linesize = src_frame->linesize[plane] * 2;
199+ int dstp_linesize = dst_frame->linesize[plane] * 2;
200+ for (j = lines; j > 0; j--) {
201+ ptrdiff_t pref = src_frame->linesize[plane];
202+ ptrdiff_t mref = -pref;
203+ if (j >= (lines - 1))
204+ mref = 0;
205+ else if (j <= 2)
206+ pref = 0;
207+ s->lowpass_line(dstp, cols, srcp, mref, pref);
208+ dstp += dstp_linesize;
209+ srcp += srcp_linesize;
210+ }
168211 } else {
169212 av_image_copy_plane(dstp, dst_frame->linesize[plane] * 2,
170213 srcp, src_frame->linesize[plane] * 2,
libavfilter/vf_tinterlace.c+50−11
@@ -1,4 +1,5 @@
11 /*
2+ * Copyright (c) 2017 Thomas Mundt <tmundt75@gmail.com>
23 * Copyright (c) 2011 Stefano Sabatini
34 * Copyright (c) 2010 Baptiste Coudurier
45 * Copyright (c) 2003 Michael Zucchi <notzed@ximian.com>
@@ -34,8 +35,6 @@ · 29 unmodified lines
3435
3536 #define OFFSET(x) offsetof(TInterlaceContext, x)
3637 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
37−#define TINTERLACE_FLAG_VLPF 01
38−#define TINTERLACE_FLAG_EXACT_TB 2
3938
4039 static const AVOption tinterlace_options[] = {
4140 {"mode", "select interlace mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_MERGE}, 0, MODE_NB-1, FLAGS, "mode"},
@@ -51,6 +50,8 @@ static const AVOption tinterlace_options[] = { · 9 unmodified lines
5150 {"flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, INT_MAX, 0, "flags" },
5251 {"low_pass_filter", "enable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
5352 {"vlpf", "enable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
53+ {"complex_filter", "enable complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
54+ {"cvlpf", "enable complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
5455 {"exact_tb", "force a timebase which can represent timestamps exactly", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_EXACT_TB}, INT_MIN, INT_MAX, FLAGS, "flags" },
5556
5657 {NULL}
@@ -102,6 +103,24 @@ static void lowpass_line_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, · 45 unmodified lines
102103 }
103104 }
104105
106+static void lowpass_line_complex_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
107+ ptrdiff_t mref, ptrdiff_t pref)
108+{
109+ const uint8_t *srcp_above = srcp + mref;
110+ const uint8_t *srcp_below = srcp + pref;
111+ const uint8_t *srcp_above2 = srcp + mref * 2;
112+ const uint8_t *srcp_below2 = srcp + pref * 2;
113+ int i;
114+ for (i = 0; i < width; i++) {
115+ // this calculation is an integer representation of
116+ // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
117+ // '4 +' is for rounding.
118+ dstp[i] = av_clip_uint8((4 + (srcp[i] << 2)
119+ + ((srcp[i] + srcp_above[i] + srcp_below[i]) << 1)
120+ - srcp_above2[i] - srcp_below2[i]) >> 3);
121+ }
122+}
123+
105124 static av_cold void uninit(AVFilterContext *ctx)
106125 {
107126 TInterlaceContext *tinterlace = ctx->priv;
@@ -144,12 +163,14 @@ static int config_out_props(AVFilterLink *outlink) · 36 unmodified lines
144163 tinterlace->black_linesize[i] * h);
145164 }
146165 }
147− if ((tinterlace->flags & TINTERLACE_FLAG_VLPF)
166+ if ((tinterlace->flags & TINTERLACE_FLAG_VLPF
167+ || tinterlace->flags & TINTERLACE_FLAG_CVLPF)
148168 && !(tinterlace->mode == MODE_INTERLEAVE_TOP
149169 || tinterlace->mode == MODE_INTERLEAVE_BOTTOM)) {
150− av_log(ctx, AV_LOG_WARNING, "low_pass_filter flag ignored with mode %d\n",
170+ av_log(ctx, AV_LOG_WARNING, "low_pass_filter flags ignored with mode %d\n",
151171 tinterlace->mode);
152172 tinterlace->flags &= ~TINTERLACE_FLAG_VLPF;
173+ tinterlace->flags &= ~TINTERLACE_FLAG_CVLPF;
153174 }
154175 tinterlace->preout_time_base = inlink->time_base;
155176 if (tinterlace->mode == MODE_INTERLACEX2) {
@@ -172,14 +193,19 @@ static int config_out_props(AVFilterLink *outlink) · 16 unmodified lines
172193 (tinterlace->flags & TINTERLACE_FLAG_EXACT_TB))
173194 outlink->time_base = tinterlace->preout_time_base;
174195
175− if (tinterlace->flags & TINTERLACE_FLAG_VLPF) {
196+ if (tinterlace->flags & TINTERLACE_FLAG_CVLPF) {
197+ tinterlace->lowpass_line = lowpass_line_complex_c;
198+ if (ARCH_X86)
199+ ff_tinterlace_init_x86(tinterlace);
200+ } else if (tinterlace->flags & TINTERLACE_FLAG_VLPF) {
176201 tinterlace->lowpass_line = lowpass_line_c;
177202 if (ARCH_X86)
178203 ff_tinterlace_init_x86(tinterlace);
179204 }
180205
181− av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n",
182− tinterlace->mode, (tinterlace->flags & TINTERLACE_FLAG_VLPF) ? "on" : "off",
206+ av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n", tinterlace->mode,
207+ (tinterlace->flags & TINTERLACE_FLAG_CVLPF) ? "complex" :
208+ (tinterlace->flags & TINTERLACE_FLAG_VLPF) ? "linear" : "off",
183209 inlink->h, outlink->h);
184210
185211 return 0;
@@ -223,10 +249,23 @@ void copy_picture_field(TInterlaceContext *tinterlace, · 37 unmodified lines
223249 srcp += src_linesize[plane];
224250 if (interleave && dst_field == FIELD_LOWER)
225251 dstp += dst_linesize[plane];
226− if (flags & TINTERLACE_FLAG_VLPF) {
227− // Low-pass filtering is required when creating an interlaced destination from
228− // a progressive source which contains high-frequency vertical detail.
229− // Filtering will reduce interlace 'twitter' and Moire patterning.
252+ // Low-pass filtering is required when creating an interlaced destination from
253+ // a progressive source which contains high-frequency vertical detail.
254+ // Filtering will reduce interlace 'twitter' and Moire patterning.
255+ if (flags & TINTERLACE_FLAG_CVLPF) {
256+ int srcp_linesize = src_linesize[plane] * k;
257+ int dstp_linesize = dst_linesize[plane] * (interleave ? 2 : 1);
258+ for (h = lines; h > 0; h--) {
259+ ptrdiff_t pref = src_linesize[plane];
260+ ptrdiff_t mref = -pref;
261+ if (h >= (lines - 1)) mref = 0;
262+ else if (h <= 2) pref = 0;
263+
264+ tinterlace->lowpass_line(dstp, cols, srcp, mref, pref);
265+ dstp += dstp_linesize;
266+ srcp += srcp_linesize;
267+ }
268+ } else if (flags & TINTERLACE_FLAG_VLPF) {
230269 int srcp_linesize = src_linesize[plane] * k;
231270 int dstp_linesize = dst_linesize[plane] * (interleave ? 2 : 1);
232271 for (h = lines; h > 0; h--) {
libavfilter/x86/vf_interlace.asm+60−0
@@ -3,6 +3,7 @@ · 2 unmodified lines
33 ;*
44 ;* Copyright (C) 2014 Kieran Kunhya <kierank@obe.tv>
55 ;* Copyright (c) 2014 Michael Niedermayer <michaelni@gmx.at>
6+;* Copyright (c) 2017 Thomas Mundt <tmundt75@gmail.com>
67 ;*
78 ;* This file is part of FFmpeg.
89 ;*
@@ -25,6 +26,8 @@ · 16 unmodified lines
2526
2627 SECTION_RODATA
2728
29+pw_4: times 8 dw 4
30+
2831 SECTION .text
2932
3033 %macro LOWPASS_LINE 0
@@ -56,6 +59,60 @@ cglobal lowpass_line, 5, 5, 7, dst, h, src, mref, pref · 25 unmodified lines
5659 add hq, 2*mmsize
5760 jl .loop
5861 REP_RET
62+
63+%endmacro
64+
65+%macro LOWPASS_LINE_COMPLEX 0
66+cglobal lowpass_line_complex, 5, 5, 7, dst, h, src, mref, pref
67+ pxor m6, m6
68+.loop:
69+ mova m0, [srcq+mrefq]
70+ mova m2, [srcq+prefq]
71+ mova m1, m0
72+ mova m3, m2
73+ punpcklbw m0, m6
74+ punpcklbw m2, m6
75+ punpckhbw m1, m6
76+ punpckhbw m3, m6
77+ paddw m0, m2
78+ paddw m1, m3
79+ mova m2, [srcq+mrefq*2]
80+ mova m4, [srcq+prefq*2]
81+ mova m3, m2
82+ mova m5, m4
83+ punpcklbw m2, m6
84+ punpcklbw m4, m6
85+ punpckhbw m3, m6
86+ punpckhbw m5, m6
87+ paddw m2, m4
88+ paddw m3, m5
89+ mova m4, [srcq]
90+ mova m5, m4
91+ punpcklbw m4, m6
92+ punpckhbw m5, m6
93+ paddw m0, m4
94+ paddw m1, m5
95+ psllw m0, 1
96+ psllw m1, 1
97+ psllw m4, 2
98+ psllw m5, 2
99+ paddw m0, m4
100+ paddw m1, m5
101+ paddw m0, [pw_4]
102+ paddw m1, [pw_4]
103+ psubusw m0, m2
104+ psubusw m1, m3
105+ psrlw m0, 3
106+ psrlw m1, 3
107+ packuswb m0, m1
108+ mova [dstq], m0
109+
110+ add dstq, mmsize
111+ add srcq, mmsize
112+ sub hd, mmsize
113+ jg .loop
114+REP_RET
115+
59116 %endmacro
60117
61118 INIT_XMM sse2
@@ -63,3 +120,6 @@ LOWPASS_LINE · 1 unmodified line
63120
64121 INIT_XMM avx
65122 LOWPASS_LINE
123+
124+INIT_XMM sse2
125+LOWPASS_LINE_COMPLEX
libavfilter/x86/vf_interlace_init.c+12−3
@@ -33,12 +33,21 @@ void ff_lowpass_line_avx (uint8_t *dstp, ptrdiff_t linesize, · 32 unmodified lines
3333 const uint8_t *srcp,
3434 ptrdiff_t mref, ptrdiff_t pref);
3535
36+void ff_lowpass_line_complex_sse2(uint8_t *dstp, ptrdiff_t linesize,
37+ const uint8_t *srcp,
38+ ptrdiff_t mref, ptrdiff_t pref);
39+
3640 av_cold void ff_interlace_init_x86(InterlaceContext *s)
3741 {
3842 int cpu_flags = av_get_cpu_flags();
3943
40− if (EXTERNAL_SSE2(cpu_flags))
41− s->lowpass_line = ff_lowpass_line_sse2;
44+ if (EXTERNAL_SSE2(cpu_flags)) {
45+ if (s->lowpass == VLPF_LIN)
46+ s->lowpass_line = ff_lowpass_line_sse2;
47+ else if (s->lowpass == VLPF_CMP)
48+ s->lowpass_line = ff_lowpass_line_complex_sse2;
49+ }
4250 if (EXTERNAL_AVX(cpu_flags))
43− s->lowpass_line = ff_lowpass_line_avx;
51+ if (s->lowpass == VLPF_LIN)
52+ s->lowpass_line = ff_lowpass_line_avx;
4453 }
libavfilter/x86/vf_tinterlace_init.c+12−3
@@ -34,12 +34,21 @@ void ff_lowpass_line_avx (uint8_t *dstp, ptrdiff_t linesize, · 33 unmodified lines
3434 const uint8_t *srcp,
3535 ptrdiff_t mref, ptrdiff_t pref);
3636
37+void ff_lowpass_line_complex_sse2(uint8_t *dstp, ptrdiff_t linesize,
38+ const uint8_t *srcp,
39+ ptrdiff_t mref, ptrdiff_t pref);
40+
3741 av_cold void ff_tinterlace_init_x86(TInterlaceContext *s)
3842 {
3943 int cpu_flags = av_get_cpu_flags();
4044
41− if (EXTERNAL_SSE2(cpu_flags))
42− s->lowpass_line = ff_lowpass_line_sse2;
45+ if (EXTERNAL_SSE2(cpu_flags)) {
46+ if (!(s->flags & TINTERLACE_FLAG_CVLPF))
47+ s->lowpass_line = ff_lowpass_line_sse2;
48+ else
49+ s->lowpass_line = ff_lowpass_line_complex_sse2;
50+ }
4351 if (EXTERNAL_AVX(cpu_flags))
44− s->lowpass_line = ff_lowpass_line_avx;
52+ if (!(s->flags & TINTERLACE_FLAG_CVLPF))
53+ s->lowpass_line = ff_lowpass_line_avx;
4554 }
tests/fate/filter-video.mak+3−0
@@ -123,6 +123,9 @@ fate-filter-hqdn3d: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf hqdn3d · 122 unmodified lines
123123 FATE_FILTER_VSYNTH-$(CONFIG_INTERLACE_FILTER) += fate-filter-interlace
124124 fate-filter-interlace: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf interlace
125125
126+FATE_FILTER_VSYNTH-$(CONFIG_INTERLACE_FILTER) += fate-filter-interlace-complex
127+fate-filter-interlace-complex: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf interlace=lowpass=complex
128+
126129 FATE_FILTER_VSYNTH-$(call ALLYES, NEGATE_FILTER PERMS_FILTER) += fate-filter-negate
127130 fate-filter-negate: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf perms=random,negate
128131
tests/ref/fate/filter-interlace-complex+30−0
@@ -0,0 +1,30 @@
1+#tb 0: 2/25
2+#media_type 0: video
3+#codec_id 0: rawvideo
4+#dimensions 0: 352x288
5+#sar 0: 0/1
6+0, 0, 0, 1, 152064, 0x91290ae6
7+0, 1, 1, 1, 152064, 0x24f34baf
8+0, 2, 2, 1, 152064, 0x799fc436
9+0, 3, 3, 1, 152064, 0xfe42c0a9
10+0, 4, 4, 1, 152064, 0xb496f879
11+0, 5, 5, 1, 152064, 0xc43b36c9
12+0, 6, 6, 1, 152064, 0xb65abbf4
13+0, 7, 7, 1, 152064, 0xd1806312
14+0, 8, 8, 1, 152064, 0x0faf56c1
15+0, 9, 9, 1, 152064, 0x4de73b75
16+0, 10, 10, 1, 152064, 0xf90f24ce
17+0, 11, 11, 1, 152064, 0xc1efd6e0
18+0, 12, 12, 1, 152064, 0xeb8e5894
19+0, 13, 13, 1, 152064, 0xe8aacabc
20+0, 14, 14, 1, 152064, 0x8bd2163c
21+0, 15, 15, 1, 152064, 0xbfc72ac2
22+0, 16, 16, 1, 152064, 0x1e8f6f56
23+0, 17, 17, 1, 152064, 0xe3d19450
24+0, 18, 18, 1, 152064, 0x3872af32
25+0, 19, 19, 1, 152064, 0xf23be72a
26+0, 20, 20, 1, 152064, 0x024f8f2b
27+0, 21, 21, 1, 152064, 0xb49301ea
28+0, 22, 22, 1, 152064, 0x84f5d056
29+0, 23, 23, 1, 152064, 0xd2c09ca5
30+0, 24, 24, 1, 152064, 0xe9b5ddfd

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t