diff --git a/Changelog b/Changelog index c896790cef..6668705623 100644 --- a/Changelog +++ b/Changelog @@ -9,6 +9,7 @@ version : - support for using metadata in stream specifiers in fftools - LZMA compression support in TIFF decoder - support for H.261 RTP payload format (RFC 4587) +- added codecview filter to visualize information exported by some codecs version 2.3: diff --git a/RELEASE_NOTES b/RELEASE_NOTES index eb73e8890b..3fbf556bac 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -37,6 +37,7 @@ • ported lenscorrection filter from frei0r filter • large optimizations in dctdnoiz to make it usable + • added codecview filter to visualize information exported by some codecs ┌────────────────────────────┐ │ libavutil │ @@ -49,3 +50,4 @@ └────────────────────────────┘ • dctdnoiz filter now uses a block size of 8x8 instead of 16x16 by default + • -vismv option is deprecated in favor of the codecview filter diff --git a/doc/codecs.texi b/doc/codecs.texi index 820dce51e6..5a1abb86cd 100644 --- a/doc/codecs.texi +++ b/doc/codecs.texi @@ -498,6 +498,8 @@ threading operations @item vismv @var{integer} (@emph{decoding,video}) Visualize motion vectors (MVs). +This option is deprecated, see the codecview filter instead. + Possible values: @table @samp @item pf diff --git a/doc/filters.texi b/doc/filters.texi index c16703704d..cca15fc03f 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -2805,6 +2805,42 @@ boxblur=luma_radius=min(h\,w)/10:luma_power=1:chroma_radius=min(cw\,ch)/10:chrom @end example @end itemize +@section codecview + +Visualize information exported by some codecs. + +Some codecs can export information through frames using side-data or other +means. For example, some MPEG based codecs export motion vectors through the +@var{export_mvs} flag in the codec @option{flags2} option. + +The filter accepts the following option: + +@table @option +@item mv +Set motion vectors to visualize. + +Available flags for @var{mv} are: + +@table @samp +@item pf +forward predicted MVs of P-frames +@item bf +forward predicted MVs of B-frames +@item bb +backward predicted MVs of B-frames +@end table +@end table + +@subsection Examples + +@itemize +@item +Visualizes multi-directionals MVs from P and B-Frames using @command{ffplay}: +@example +ffplay -flags2 +export_mvs input.mpg -vf codecview=mv=pf+bf+bb +@end example +@end itemize + @section colorbalance Modify intensity of primary colors (red, green and blue) of input frames. diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 6a0b822557..3ec81cef52 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -1983,6 +1983,7 @@ void ff_mpv_frame_end(MpegEncContext *s) } +#if FF_API_VISMV static int clip_line(int *sx, int *sy, int *ex, int *ey, int maxx) { if(*sx > *ex) @@ -2107,6 +2108,7 @@ static void draw_arrow(uint8_t *buf, int sx, int sy, int ex, } draw_line(buf, sx, sy, ex, ey, w, h, stride, color); } +#endif static int add_mb(AVMotionVector *mb, uint32_t mb_type, int dst_x, int dst_y, @@ -2292,13 +2294,15 @@ void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, uint8_t *mbskip_ if ((avctx->debug & (FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE)) || (avctx->debug_mv)) { - const int shift = 1 + quarter_sample; int mb_y; - uint8_t *ptr; int i; int h_chroma_shift, v_chroma_shift, block_height; +#if FF_API_VISMV + const int shift = 1 + quarter_sample; + uint8_t *ptr; const int width = avctx->width; const int height = avctx->height; +#endif const int mv_sample_log2 = avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_SVQ3 ? 2 : 1; const int mv_stride = (mb_width << mv_sample_log2) + (avctx->codec->id == AV_CODEC_ID_H264 ? 0 : 1); @@ -2310,13 +2314,16 @@ void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, uint8_t *mbskip_ av_frame_make_writable(pict); pict->opaque = NULL; +#if FF_API_VISMV ptr = pict->data[0]; +#endif block_height = 16 >> v_chroma_shift; for (mb_y = 0; mb_y < mb_height; mb_y++) { int mb_x; for (mb_x = 0; mb_x < mb_width; mb_x++) { const int mb_index = mb_x + mb_y * mb_stride; +#if FF_API_VISMV if ((avctx->debug_mv) && motion_val[0]) { int type; for (type = 0; type < 3; type++) { @@ -2396,6 +2403,7 @@ void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, uint8_t *mbskip_ } } } +#endif if ((avctx->debug & FF_DEBUG_VIS_QP)) { uint64_t c = (qscale_table[mb_index] * 128 / 31) * 0x0101010101010101ULL; diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h index 700053129e..ad3d52ecdf 100644 --- a/libavcodec/options_table.h +++ b/libavcodec/options_table.h @@ -262,10 +262,12 @@ static const AVOption avcodec_options[] = { {"buffers", "picture buffer allocations", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_BUFFERS }, INT_MIN, INT_MAX, V|D, "debug"}, {"thread_ops", "threading operations", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_THREADS }, INT_MIN, INT_MAX, V|A|D, "debug"}, {"nomc", "skip motion compensation", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_NOMC }, INT_MIN, INT_MAX, V|A|D, "debug"}, -{"vismv", "visualize motion vectors (MVs)", OFFSET(debug_mv), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, INT_MAX, V|D, "debug_mv"}, +#if FF_API_VISMV +{"vismv", "visualize motion vectors (MVs) (deprecated)", OFFSET(debug_mv), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, INT_MAX, V|D, "debug_mv"}, {"pf", "forward predicted MVs of P-frames", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MV_P_FOR }, INT_MIN, INT_MAX, V|D, "debug_mv"}, {"bf", "forward predicted MVs of B-frames", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MV_B_FOR }, INT_MIN, INT_MAX, V|D, "debug_mv"}, {"bb", "backward predicted MVs of B-frames", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MV_B_BACK }, INT_MIN, INT_MAX, V|D, "debug_mv"}, +#endif {"cmp", "full-pel ME compare function", OFFSET(me_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, {"subcmp", "sub-pel ME compare function", OFFSET(me_sub_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, {"mbcmp", "macroblock compare function", OFFSET(mb_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 6a40a032e8..985884f551 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -1435,6 +1435,12 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code goto free_and_end; } +#if FF_API_VISMV + if (avctx->debug_mv) + av_log(avctx, AV_LOG_WARNING, "The 'vismv' option is deprecated, " + "see the codecview filter instead.\n"); +#endif + if (av_codec_is_encoder(avctx->codec)) { int i; if (avctx->codec->sample_fmts) { diff --git a/libavcodec/version.h b/libavcodec/version.h index 2c871ba744..9da72abdd0 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -174,5 +174,9 @@ #ifndef FF_API_AFD #define FF_API_AFD (LIBAVCODEC_VERSION_MAJOR < 57) #endif +#ifndef FF_API_VISMV +/* XXX: don't forget to drop the -vismv documentation */ +#define FF_API_VISMV (LIBAVCODEC_VERSION_MAJOR < 57) +#endif #endif /* AVCODEC_VERSION_H */ diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 7486f96c9c..ce71ce1a24 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -97,6 +97,7 @@ OBJS-$(CONFIG_BLACKDETECT_FILTER) += vf_blackdetect.o OBJS-$(CONFIG_BLACKFRAME_FILTER) += vf_blackframe.o OBJS-$(CONFIG_BLEND_FILTER) += vf_blend.o dualinput.o framesync.o OBJS-$(CONFIG_BOXBLUR_FILTER) += vf_boxblur.o +OBJS-$(CONFIG_CODECVIEW_FILTER) += vf_codecview.o OBJS-$(CONFIG_COLORBALANCE_FILTER) += vf_colorbalance.o OBJS-$(CONFIG_COLORCHANNELMIXER_FILTER) += vf_colorchannelmixer.o OBJS-$(CONFIG_COLORMATRIX_FILTER) += vf_colormatrix.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index b1d6ff5b11..8fe2020901 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -115,6 +115,7 @@ void avfilter_register_all(void) REGISTER_FILTER(BLACKFRAME, blackframe, vf); REGISTER_FILTER(BLEND, blend, vf); REGISTER_FILTER(BOXBLUR, boxblur, vf); + REGISTER_FILTER(CODECVIEW, codecview, vf); REGISTER_FILTER(COLORBALANCE, colorbalance, vf); REGISTER_FILTER(COLORCHANNELMIXER, colorchannelmixer, vf); REGISTER_FILTER(COLORMATRIX, colormatrix, vf); diff --git a/libavfilter/vf_codecview.c b/libavfilter/vf_codecview.c new file mode 100644 index 0000000000..d777f97ef2 --- /dev/null +++ b/libavfilter/vf_codecview.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2002-2004 Michael Niedermayer + * Copyright (c) 2014 Clément Bœsch + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Codec debug viewer filter. + * + * All the MV drawing code from Michael Niedermayer is extracted from + * libavcodec/mpegvideo.c. + * + * TODO: segmentation + * TODO: quantization + */ + +#include "libavutil/imgutils.h" +#include "libavutil/motion_vector.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "internal.h" + +#define MV_P_FOR (1<<0) +#define MV_B_FOR (1<<1) +#define MV_B_BACK (1<<2) + +typedef struct { + const AVClass *class; + unsigned mv; +} CodecViewContext; + +#define OFFSET(x) offsetof(CodecViewContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM +static const AVOption codecview_options[] = { + { "mv", "set motion vectors to visualize", OFFSET(mv), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, INT_MAX, FLAGS, "mv" }, + {"pf", "forward predicted MVs of P-frames", 0, AV_OPT_TYPE_CONST, {.i64 = MV_P_FOR }, INT_MIN, INT_MAX, FLAGS, "mv"}, + {"bf", "forward predicted MVs of B-frames", 0, AV_OPT_TYPE_CONST, {.i64 = MV_B_FOR }, INT_MIN, INT_MAX, FLAGS, "mv"}, + {"bb", "backward predicted MVs of B-frames", 0, AV_OPT_TYPE_CONST, {.i64 = MV_B_BACK }, INT_MIN, INT_MAX, FLAGS, "mv"}, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(codecview); + +static int query_formats(AVFilterContext *ctx) +{ + // TODO: we can probably add way more pixel formats without any other + // changes; anything with 8-bit luma in first plane should be working + static const enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE}; + ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); + return 0; +} + +static int clip_line(int *sx, int *sy, int *ex, int *ey, int maxx) +{ + if(*sx > *ex) + return clip_line(ex, ey, sx, sy, maxx); + + if (*sx < 0) { + if (*ex < 0) + return 1; + *sy = *ey + (*sy - *ey) * (int64_t)*ex / (*ex - *sx); + *sx = 0; + } + + if (*ex > maxx) { + if (*sx > maxx) + return 1; + *ey = *sy + (*ey - *sy) * (int64_t)(maxx - *sx) / (*ex - *sx); + *ex = maxx; + } + return 0; +} + +/** + * Draw a line from (ex, ey) -> (sx, sy). + * @param w width of the image + * @param h height of the image + * @param stride stride/linesize of the image + * @param color color of the arrow + */ +static void draw_line(uint8_t *buf, int sx, int sy, int ex, int ey, + int w, int h, int stride, int color) +{ + int x, y, fr, f; + + if (clip_line(&sx, &sy, &ex, &ey, w - 1)) + return; + if (clip_line(&sy, &sx, &ey, &ex, h - 1)) + return; + + sx = av_clip(sx, 0, w - 1); + sy = av_clip(sy, 0, h - 1); + ex = av_clip(ex, 0, w - 1); + ey = av_clip(ey, 0, h - 1); + + buf[sy * stride + sx] += color; + + if (FFABS(ex - sx) > FFABS(ey - sy)) { + if (sx > ex) { + FFSWAP(int, sx, ex); + FFSWAP(int, sy, ey); + } + buf += sx + sy * stride; + ex -= sx; + f = ((ey - sy) << 16) / ex; + for (x = 0; x <= ex; x++) { + y = (x * f) >> 16; + fr = (x * f) & 0xFFFF; + buf[ y * stride + x] += (color * (0x10000 - fr)) >> 16; + if(fr) buf[(y + 1) * stride + x] += (color * fr ) >> 16; + } + } else { + if (sy > ey) { + FFSWAP(int, sx, ex); + FFSWAP(int, sy, ey); + } + buf += sx + sy * stride; + ey -= sy; + if (ey) + f = ((ex - sx) << 16) / ey; + else + f = 0; + for(y= 0; y <= ey; y++){ + x = (y*f) >> 16; + fr = (y*f) & 0xFFFF; + buf[y * stride + x ] += (color * (0x10000 - fr)) >> 16; + if(fr) buf[y * stride + x + 1] += (color * fr ) >> 16; + } + } +} + +/** + * Draw an arrow from (ex, ey) -> (sx, sy). + * @param w width of the image + * @param h height of the image + * @param stride stride/linesize of the image + * @param color color of the arrow + */ +static void draw_arrow(uint8_t *buf, int sx, int sy, int ex, + int ey, int w, int h, int stride, int color, int tail, int direction) +{ + int dx,dy; + + if (direction) { + FFSWAP(int, sx, ex); + FFSWAP(int, sy, ey); + } + + sx = av_clip(sx, -100, w + 100); + sy = av_clip(sy, -100, h + 100); + ex = av_clip(ex, -100, w + 100); + ey = av_clip(ey, -100, h + 100); + + dx = ex - sx; + dy = ey - sy; + + if (dx * dx + dy * dy > 3 * 3) { + int rx = dx + dy; + int ry = -dx + dy; + int length = sqrt((rx * rx + ry * ry) << 8); + + // FIXME subpixel accuracy + rx = ROUNDED_DIV(rx * 3 << 4, length); + ry = ROUNDED_DIV(ry * 3 << 4, length); + + if (tail) { + rx = -rx; + ry = -ry; + } + + draw_line(buf, sx, sy, sx + rx, sy + ry, w, h, stride, color); + draw_line(buf, sx, sy, sx - ry, sy + rx, w, h, stride, color); + } + draw_line(buf, sx, sy, ex, ey, w, h, stride, color); +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *frame) +{ + AVFilterContext *ctx = inlink->dst; + CodecViewContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + + AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MOTION_VECTORS); + if (sd) { + int i; + const AVMotionVector *mvs = (const AVMotionVector *)sd->data; + for (i = 0; i < sd->size / sizeof(*mvs); i++) { + const AVMotionVector *mv = &mvs[i]; + const int direction = mv->source > 0; + if ((direction == 0 && (s->mv & MV_P_FOR) && frame->pict_type == AV_PICTURE_TYPE_P) || + (direction == 0 && (s->mv & MV_B_FOR) && frame->pict_type == AV_PICTURE_TYPE_B) || + (direction == 1 && (s->mv & MV_B_BACK) && frame->pict_type == AV_PICTURE_TYPE_B)) + draw_arrow(frame->data[0], mv->dst_x, mv->dst_y, mv->src_x, mv->src_y, + frame->width, frame->height, frame->linesize[0], + 100, 0, mv->source > 0); + } + } + return ff_filter_frame(outlink, frame); +} + +static const AVFilterPad codecview_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + .needs_writable = 1, + }, + { NULL } +}; + +static const AVFilterPad codecview_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_codecview = { + .name = "codecview", + .description = NULL_IF_CONFIG_SMALL("Visualize information about some codecs"), + .priv_size = sizeof(CodecViewContext), + .query_formats = query_formats, + .inputs = codecview_inputs, + .outputs = codecview_outputs, + .priv_class = &codecview_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, +}; diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak index 053f3e7011..9239b379dd 100644 --- a/tests/fate/filter-video.mak +++ b/tests/fate/filter-video.mak @@ -23,6 +23,9 @@ fate-filter-mcdeint-medium: CMD = framecrc -flags bitexact -idct simple -i $(TAR FATE_FILTER-$(call ALLYES, MCDEINT_FILTER, MPEGTS_DEMUXER, MPEG2VIDEO_DECODER SNOW_ENCODER) += $(FATE_MCDEINT) +FATE_FILTER-$(call ALLYES, CODECVIEW_FILTER RM_DEMUXER RV40_DECODER) += fate-filter-codecview-mvs +fate-filter-codecview-mvs: CMD = framecrc -flags2 +export_mvs -i $(TARGET_SAMPLES)/real/spygames-2MB.rmvb -vf codecview=mv=pf+bf+bb -vframes 60 -an + FATE_SAMPLES_AVCONV += $(FATE_FILTER-yes) FATE_FILTER-$(call ALLYES, AVDEVICE LIFE_FILTER) += fate-filter-lavd-life diff --git a/tests/ref/fate/filter-codecview-mvs b/tests/ref/fate/filter-codecview-mvs new file mode 100644 index 0000000000..82b571fb4d --- /dev/null +++ b/tests/ref/fate/filter-codecview-mvs @@ -0,0 +1,61 @@ +#tb 0: 32768/785647 +0, 0, 0, 1, 276480, 0x5f7a0d4f +0, 1, 1, 1, 276480, 0x5f7a0d4f +0, 2, 2, 1, 276480, 0x5f7a0d4f +0, 3, 3, 1, 276480, 0x5f7a0d4f +0, 4, 4, 1, 276480, 0x5f7a0d4f +0, 5, 5, 1, 276480, 0x5f7a0d4f +0, 6, 6, 1, 276480, 0x5f7a0d4f +0, 7, 7, 1, 276480, 0x5f7a0d4f +0, 8, 8, 1, 276480, 0x5f7a0d4f +0, 9, 9, 1, 276480, 0x5f7a0d4f +0, 10, 10, 1, 276480, 0x5f7a0d4f +0, 11, 11, 1, 276480, 0x5f7a0d4f +0, 12, 12, 1, 276480, 0x5f7a0d4f +0, 13, 13, 1, 276480, 0x5f7a0d4f +0, 14, 14, 1, 276480, 0x5f7a0d4f +0, 15, 15, 1, 276480, 0x5f7a0d4f +0, 16, 16, 1, 276480, 0x5f7a0d4f +0, 17, 17, 1, 276480, 0x5f7a0d4f +0, 18, 18, 1, 276480, 0x5f7a0d4f +0, 19, 19, 1, 276480, 0x5f7a0d4f +0, 20, 20, 1, 276480, 0x5f7a0d4f +0, 21, 21, 1, 276480, 0x5f7a0d4f +0, 22, 22, 1, 276480, 0x5f7a0d4f +0, 23, 23, 1, 276480, 0x5f7a0d4f +0, 24, 24, 1, 276480, 0x5f7a0d4f +0, 25, 25, 1, 276480, 0x5f7a0d4f +0, 26, 26, 1, 276480, 0x5f7a0d4f +0, 27, 27, 1, 276480, 0x5f7a0d4f +0, 28, 28, 1, 276480, 0x5f7a0d4f +0, 29, 29, 1, 276480, 0x5f7a0d4f +0, 30, 30, 1, 276480, 0x5f7a0d4f +0, 31, 31, 1, 276480, 0x5f7a0d4f +0, 32, 32, 1, 276480, 0x5f7a0d4f +0, 33, 33, 1, 276480, 0x75641594 +0, 34, 34, 1, 276480, 0x32ee3526 +0, 35, 35, 1, 276480, 0xcb53479a +0, 36, 36, 1, 276480, 0x7ca9658e +0, 37, 37, 1, 276480, 0x5ce39368 +0, 38, 38, 1, 276480, 0x4ec1e418 +0, 39, 39, 1, 276480, 0x23c418ae +0, 40, 40, 1, 276480, 0x70ac4c76 +0, 41, 41, 1, 276480, 0x166ef020 +0, 42, 42, 1, 276480, 0xaa0614ab +0, 43, 43, 1, 276480, 0x8bc2fa2b +0, 44, 44, 1, 276480, 0x07956a97 +0, 45, 45, 1, 276480, 0x6fcb808b +0, 46, 46, 1, 276480, 0x841cf493 +0, 47, 47, 1, 276480, 0xe7834514 +0, 48, 48, 1, 276480, 0xb805fcb1 +0, 49, 49, 1, 276480, 0xe29bacc8 +0, 50, 50, 1, 276480, 0x6b79c3d3 +0, 51, 51, 1, 276480, 0x798c35c6 +0, 52, 52, 1, 276480, 0x1b31d2ed +0, 53, 53, 1, 276480, 0x6ceebf3e +0, 54, 54, 1, 276480, 0x7ac8de3c +0, 55, 55, 1, 276480, 0x14d6768c +0, 56, 56, 1, 276480, 0xcb08af08 +0, 57, 57, 1, 276480, 0xed3053ea +0, 58, 58, 1, 276480, 0x015782fb +0, 59, 59, 1, 276480, 0xf849eb88