1/* 2 * copyright (c) 2007 Bobby Bingham 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/** 22 * @file 23 * video slicing filter 24 */ 25 26#include "avfilter.h" 27#include "libavutil/pixdesc.h" 28 29typedef struct { 30 int h; ///< output slice height 31 int vshift; ///< vertical chroma subsampling shift 32 uint32_t lcg_state; ///< LCG state used to compute random slice height 33 int use_random_h; ///< enable the use of random slice height values 34} SliceContext; 35 36static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) 37{ 38 SliceContext *slice = ctx->priv; 39 40 slice->h = 16; 41 if (args) { 42 if (!strcmp(args, "random")) { 43 slice->use_random_h = 1; 44 } else { 45 sscanf(args, "%d", &slice->h); 46 } 47 } 48 return 0; 49} 50 51static int config_props(AVFilterLink *link) 52{ 53 SliceContext *slice = link->dst->priv; 54 55 slice->vshift = av_pix_fmt_descriptors[link->format].log2_chroma_h; 56 57 return 0; 58} 59 60static void start_frame(AVFilterLink *link, AVFilterPicRef *picref) 61{ 62 SliceContext *slice = link->dst->priv; 63 64 if (slice->use_random_h) { 65 slice->lcg_state = slice->lcg_state * 1664525 + 1013904223; 66 slice->h = 8 + (uint64_t)slice->lcg_state * 25 / UINT32_MAX; 67 } 68 69 /* ensure that slices play nice with chroma subsampling, and enforce 70 * a reasonable minimum size for the slices */ 71 slice->h = FFMAX(8, slice->h & (-1 << slice->vshift)); 72 73 av_log(link->dst, AV_LOG_DEBUG, "h:%d\n", slice->h); 74 75 avfilter_start_frame(link->dst->outputs[0], picref); 76} 77 78static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir) 79{ 80 SliceContext *slice = link->dst->priv; 81 int y2; 82 83 if (slice_dir == 1) { 84 for (y2 = y; y2 + slice->h <= y + h; y2 += slice->h) 85 avfilter_draw_slice(link->dst->outputs[0], y2, slice->h, slice_dir); 86 87 if (y2 < y + h) 88 avfilter_draw_slice(link->dst->outputs[0], y2, y + h - y2, slice_dir); 89 } else if (slice_dir == -1) { 90 for (y2 = y + h; y2 - slice->h >= y; y2 -= slice->h) 91 avfilter_draw_slice(link->dst->outputs[0], y2 - slice->h, slice->h, slice_dir); 92 93 if (y2 > y) 94 avfilter_draw_slice(link->dst->outputs[0], y, y2 - y, slice_dir); 95 } 96} 97 98AVFilter avfilter_vf_slicify = { 99 .name = "slicify", 100 .description = "Pass the images of input video on to next video filter as multiple slices.", 101 102 .init = init, 103 104 .priv_size = sizeof(SliceContext), 105 106 .inputs = (AVFilterPad[]) {{ .name = "default", 107 .type = AVMEDIA_TYPE_VIDEO, 108 .get_video_buffer = avfilter_null_get_video_buffer, 109 .start_frame = start_frame, 110 .draw_slice = draw_slice, 111 .config_props = config_props, 112 .end_frame = avfilter_null_end_frame, }, 113 { .name = NULL}}, 114 .outputs = (AVFilterPad[]) {{ .name = "default", 115 .type = AVMEDIA_TYPE_VIDEO, }, 116 { .name = NULL}}, 117}; 118