Browse code

lavfi: move video-related functions to a separate file.

This is easier to follow than having them randomly scattered in
avfilter.c and defaults.c.

Anton Khirnov authored on 2012/05/10 14:36:10
Showing 4 changed files
... ...
@@ -22,6 +22,7 @@ OBJS = allfilters.o                                                     \
22 22
        formats.o                                                        \
23 23
        graphparser.o                                                    \
24 24
        vf_scale.o                                                       \
25
+       video.o                                                          \
25 26
 
26 27
 OBJS-$(CONFIG_AFORMAT_FILTER)                += af_aformat.o
27 28
 OBJS-$(CONFIG_ANULL_FILTER)                  += af_anull.o
... ...
@@ -248,35 +248,6 @@ static char *ff_get_ref_perms_string(char *buf, size_t buf_size, int perms)
248 248
 }
249 249
 #endif
250 250
 
251
-static void ff_dlog_ref(void *ctx, AVFilterBufferRef *ref, int end)
252
-{
253
-    av_unused char buf[16];
254
-    av_dlog(ctx,
255
-            "ref[%p buf:%p refcount:%d perms:%s data:%p linesize[%d, %d, %d, %d] pts:%"PRId64" pos:%"PRId64,
256
-            ref, ref->buf, ref->buf->refcount, ff_get_ref_perms_string(buf, sizeof(buf), ref->perms), ref->data[0],
257
-            ref->linesize[0], ref->linesize[1], ref->linesize[2], ref->linesize[3],
258
-            ref->pts, ref->pos);
259
-
260
-    if (ref->video) {
261
-        av_dlog(ctx, " a:%d/%d s:%dx%d i:%c iskey:%d type:%c",
262
-                ref->video->pixel_aspect.num, ref->video->pixel_aspect.den,
263
-                ref->video->w, ref->video->h,
264
-                !ref->video->interlaced     ? 'P' :         /* Progressive  */
265
-                ref->video->top_field_first ? 'T' : 'B',    /* Top / Bottom */
266
-                ref->video->key_frame,
267
-                av_get_picture_type_char(ref->video->pict_type));
268
-    }
269
-    if (ref->audio) {
270
-        av_dlog(ctx, " cl:%"PRId64"d n:%d r:%d p:%d",
271
-                ref->audio->channel_layout,
272
-                ref->audio->nb_samples,
273
-                ref->audio->sample_rate,
274
-                ref->audio->planar);
275
-    }
276
-
277
-    av_dlog(ctx, "]%s", end ? "\n" : "");
278
-}
279
-
280 251
 void ff_dlog_link(void *ctx, AVFilterLink *link, int end)
281 252
 {
282 253
     if (link->type == AVMEDIA_TYPE_VIDEO) {
... ...
@@ -301,71 +272,6 @@ void ff_dlog_link(void *ctx, AVFilterLink *link, int end)
301 301
     }
302 302
 }
303 303
 
304
-AVFilterBufferRef *avfilter_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
305
-{
306
-    AVFilterBufferRef *ret = NULL;
307
-
308
-    av_unused char buf[16];
309
-    FF_DPRINTF_START(NULL, get_video_buffer); ff_dlog_link(NULL, link, 0);
310
-    av_dlog(NULL, " perms:%s w:%d h:%d\n", ff_get_ref_perms_string(buf, sizeof(buf), perms), w, h);
311
-
312
-    if (link->dstpad->get_video_buffer)
313
-        ret = link->dstpad->get_video_buffer(link, perms, w, h);
314
-
315
-    if (!ret)
316
-        ret = avfilter_default_get_video_buffer(link, perms, w, h);
317
-
318
-    if (ret)
319
-        ret->type = AVMEDIA_TYPE_VIDEO;
320
-
321
-    FF_DPRINTF_START(NULL, get_video_buffer); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " returning "); ff_dlog_ref(NULL, ret, 1);
322
-
323
-    return ret;
324
-}
325
-
326
-AVFilterBufferRef *
327
-avfilter_get_video_buffer_ref_from_arrays(uint8_t *data[4], int linesize[4], int perms,
328
-                                          int w, int h, enum PixelFormat format)
329
-{
330
-    AVFilterBuffer *pic = av_mallocz(sizeof(AVFilterBuffer));
331
-    AVFilterBufferRef *picref = av_mallocz(sizeof(AVFilterBufferRef));
332
-
333
-    if (!pic || !picref)
334
-        goto fail;
335
-
336
-    picref->buf = pic;
337
-    picref->buf->free = ff_avfilter_default_free_buffer;
338
-    if (!(picref->video = av_mallocz(sizeof(AVFilterBufferRefVideoProps))))
339
-        goto fail;
340
-
341
-    pic->w = picref->video->w = w;
342
-    pic->h = picref->video->h = h;
343
-
344
-    /* make sure the buffer gets read permission or it's useless for output */
345
-    picref->perms = perms | AV_PERM_READ;
346
-
347
-    pic->refcount = 1;
348
-    picref->type = AVMEDIA_TYPE_VIDEO;
349
-    pic->format = picref->format = format;
350
-
351
-    memcpy(pic->data,        data,          4*sizeof(data[0]));
352
-    memcpy(pic->linesize,    linesize,      4*sizeof(linesize[0]));
353
-    memcpy(picref->data,     pic->data,     sizeof(picref->data));
354
-    memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize));
355
-
356
-    pic->   extended_data = pic->data;
357
-    picref->extended_data = picref->data;
358
-
359
-    return picref;
360
-
361
-fail:
362
-    if (picref && picref->video)
363
-        av_free(picref->video);
364
-    av_free(picref);
365
-    av_free(pic);
366
-    return NULL;
367
-}
368
-
369 304
 int avfilter_request_frame(AVFilterLink *link)
370 305
 {
371 306
     FF_DPRINTF_START(NULL, request_frame); ff_dlog_link(NULL, link, 1);
... ...
@@ -395,96 +301,6 @@ int avfilter_poll_frame(AVFilterLink *link)
395 395
     return min;
396 396
 }
397 397
 
398
-/* XXX: should we do the duplicating of the picture ref here, instead of
399
- * forcing the source filter to do it? */
400
-void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
401
-{
402
-    void (*start_frame)(AVFilterLink *, AVFilterBufferRef *);
403
-    AVFilterPad *dst = link->dstpad;
404
-    int perms = picref->perms;
405
-
406
-    FF_DPRINTF_START(NULL, start_frame); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " "); ff_dlog_ref(NULL, picref, 1);
407
-
408
-    if (!(start_frame = dst->start_frame))
409
-        start_frame = avfilter_default_start_frame;
410
-
411
-    if (picref->linesize[0] < 0)
412
-        perms |= AV_PERM_NEG_LINESIZES;
413
-    /* prepare to copy the picture if it has insufficient permissions */
414
-    if ((dst->min_perms & perms) != dst->min_perms || dst->rej_perms & perms) {
415
-        av_log(link->dst, AV_LOG_DEBUG,
416
-                "frame copy needed (have perms %x, need %x, reject %x)\n",
417
-                picref->perms,
418
-                link->dstpad->min_perms, link->dstpad->rej_perms);
419
-
420
-        link->cur_buf = avfilter_get_video_buffer(link, dst->min_perms, link->w, link->h);
421
-        link->src_buf = picref;
422
-        avfilter_copy_buffer_ref_props(link->cur_buf, link->src_buf);
423
-    }
424
-    else
425
-        link->cur_buf = picref;
426
-
427
-    start_frame(link, link->cur_buf);
428
-}
429
-
430
-void avfilter_end_frame(AVFilterLink *link)
431
-{
432
-    void (*end_frame)(AVFilterLink *);
433
-
434
-    if (!(end_frame = link->dstpad->end_frame))
435
-        end_frame = avfilter_default_end_frame;
436
-
437
-    end_frame(link);
438
-
439
-    /* unreference the source picture if we're feeding the destination filter
440
-     * a copied version dues to permission issues */
441
-    if (link->src_buf) {
442
-        avfilter_unref_buffer(link->src_buf);
443
-        link->src_buf = NULL;
444
-    }
445
-}
446
-
447
-void avfilter_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
448
-{
449
-    uint8_t *src[4], *dst[4];
450
-    int i, j, vsub;
451
-    void (*draw_slice)(AVFilterLink *, int, int, int);
452
-
453
-    FF_DPRINTF_START(NULL, draw_slice); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " y:%d h:%d dir:%d\n", y, h, slice_dir);
454
-
455
-    /* copy the slice if needed for permission reasons */
456
-    if (link->src_buf) {
457
-        vsub = av_pix_fmt_descriptors[link->format].log2_chroma_h;
458
-
459
-        for (i = 0; i < 4; i++) {
460
-            if (link->src_buf->data[i]) {
461
-                src[i] = link->src_buf-> data[i] +
462
-                    (y >> (i==1 || i==2 ? vsub : 0)) * link->src_buf-> linesize[i];
463
-                dst[i] = link->cur_buf->data[i] +
464
-                    (y >> (i==1 || i==2 ? vsub : 0)) * link->cur_buf->linesize[i];
465
-            } else
466
-                src[i] = dst[i] = NULL;
467
-        }
468
-
469
-        for (i = 0; i < 4; i++) {
470
-            int planew =
471
-                av_image_get_linesize(link->format, link->cur_buf->video->w, i);
472
-
473
-            if (!src[i]) continue;
474
-
475
-            for (j = 0; j < h >> (i==1 || i==2 ? vsub : 0); j++) {
476
-                memcpy(dst[i], src[i], planew);
477
-                src[i] += link->src_buf->linesize[i];
478
-                dst[i] += link->cur_buf->linesize[i];
479
-            }
480
-        }
481
-    }
482
-
483
-    if (!(draw_slice = link->dstpad->draw_slice))
484
-        draw_slice = avfilter_default_draw_slice;
485
-    draw_slice(link, y, h, slice_dir);
486
-}
487
-
488 398
 #define MAX_REGISTERED_AVFILTERS_NB 64
489 399
 
490 400
 static AVFilter *registered_avfilters[MAX_REGISTERED_AVFILTERS_NB + 1];
... ...
@@ -36,73 +36,6 @@ void ff_avfilter_default_free_buffer(AVFilterBuffer *ptr)
36 36
     av_free(ptr);
37 37
 }
38 38
 
39
-/* TODO: set the buffer's priv member to a context structure for the whole
40
- * filter chain.  This will allow for a buffer pool instead of the constant
41
- * alloc & free cycle currently implemented. */
42
-AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
43
-{
44
-    int linesize[4];
45
-    uint8_t *data[4];
46
-    AVFilterBufferRef *picref = NULL;
47
-
48
-    // +2 is needed for swscaler, +16 to be SIMD-friendly
49
-    if (av_image_alloc(data, linesize, w, h, link->format, 16) < 0)
50
-        return NULL;
51
-
52
-    picref = avfilter_get_video_buffer_ref_from_arrays(data, linesize,
53
-                                                       perms, w, h, link->format);
54
-    if (!picref) {
55
-        av_free(data[0]);
56
-        return NULL;
57
-    }
58
-
59
-    return picref;
60
-}
61
-
62
-void avfilter_default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
63
-{
64
-    AVFilterLink *outlink = NULL;
65
-
66
-    if (inlink->dst->output_count)
67
-        outlink = inlink->dst->outputs[0];
68
-
69
-    if (outlink) {
70
-        outlink->out_buf = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
71
-        avfilter_copy_buffer_ref_props(outlink->out_buf, picref);
72
-        avfilter_start_frame(outlink, avfilter_ref_buffer(outlink->out_buf, ~0));
73
-    }
74
-}
75
-
76
-void avfilter_default_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
77
-{
78
-    AVFilterLink *outlink = NULL;
79
-
80
-    if (inlink->dst->output_count)
81
-        outlink = inlink->dst->outputs[0];
82
-
83
-    if (outlink)
84
-        avfilter_draw_slice(outlink, y, h, slice_dir);
85
-}
86
-
87
-void avfilter_default_end_frame(AVFilterLink *inlink)
88
-{
89
-    AVFilterLink *outlink = NULL;
90
-
91
-    if (inlink->dst->output_count)
92
-        outlink = inlink->dst->outputs[0];
93
-
94
-    avfilter_unref_buffer(inlink->cur_buf);
95
-    inlink->cur_buf = NULL;
96
-
97
-    if (outlink) {
98
-        if (outlink->out_buf) {
99
-            avfilter_unref_buffer(outlink->out_buf);
100
-            outlink->out_buf = NULL;
101
-        }
102
-        avfilter_end_frame(outlink);
103
-    }
104
-}
105
-
106 39
 /**
107 40
  * default config_link() implementation for output video links to simplify
108 41
  * the implementation of one input one output video filters */
... ...
@@ -186,23 +119,3 @@ int avfilter_default_query_formats(AVFilterContext *ctx)
186 186
 
187 187
     return 0;
188 188
 }
189
-
190
-void avfilter_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
191
-{
192
-    avfilter_start_frame(link->dst->outputs[0], picref);
193
-}
194
-
195
-void avfilter_null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
196
-{
197
-    avfilter_draw_slice(link->dst->outputs[0], y, h, slice_dir);
198
-}
199
-
200
-void avfilter_null_end_frame(AVFilterLink *link)
201
-{
202
-    avfilter_end_frame(link->dst->outputs[0]);
203
-}
204
-
205
-AVFilterBufferRef *avfilter_null_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
206
-{
207
-    return avfilter_get_video_buffer(link->dst->outputs[0], perms, w, h);
208
-}
209 189
new file mode 100644
... ...
@@ -0,0 +1,294 @@
0
+/*
1
+ * This file is part of Libav.
2
+ *
3
+ * Libav is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * Libav is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with Libav; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#include "libavutil/imgutils.h"
19
+
20
+#include "avfilter.h"
21
+#include "internal.h"
22
+
23
+static void ff_dlog_ref(void *ctx, AVFilterBufferRef *ref, int end)
24
+{
25
+    av_unused char buf[16];
26
+    av_dlog(ctx,
27
+            "ref[%p buf:%p refcount:%d perms:%s data:%p linesize[%d, %d, %d, %d] pts:%"PRId64" pos:%"PRId64,
28
+            ref, ref->buf, ref->buf->refcount, ff_get_ref_perms_string(buf, sizeof(buf), ref->perms), ref->data[0],
29
+            ref->linesize[0], ref->linesize[1], ref->linesize[2], ref->linesize[3],
30
+            ref->pts, ref->pos);
31
+
32
+    if (ref->video) {
33
+        av_dlog(ctx, " a:%d/%d s:%dx%d i:%c iskey:%d type:%c",
34
+                ref->video->pixel_aspect.num, ref->video->pixel_aspect.den,
35
+                ref->video->w, ref->video->h,
36
+                !ref->video->interlaced     ? 'P' :         /* Progressive  */
37
+                ref->video->top_field_first ? 'T' : 'B',    /* Top / Bottom */
38
+                ref->video->key_frame,
39
+                av_get_picture_type_char(ref->video->pict_type));
40
+    }
41
+    if (ref->audio) {
42
+        av_dlog(ctx, " cl:%"PRId64"d n:%d r:%d p:%d",
43
+                ref->audio->channel_layout,
44
+                ref->audio->nb_samples,
45
+                ref->audio->sample_rate,
46
+                ref->audio->planar);
47
+    }
48
+
49
+    av_dlog(ctx, "]%s", end ? "\n" : "");
50
+}
51
+
52
+AVFilterBufferRef *avfilter_null_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
53
+{
54
+    return avfilter_get_video_buffer(link->dst->outputs[0], perms, w, h);
55
+}
56
+
57
+/* TODO: set the buffer's priv member to a context structure for the whole
58
+ * filter chain.  This will allow for a buffer pool instead of the constant
59
+ * alloc & free cycle currently implemented. */
60
+AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
61
+{
62
+    int linesize[4];
63
+    uint8_t *data[4];
64
+    AVFilterBufferRef *picref = NULL;
65
+
66
+    // +2 is needed for swscaler, +16 to be SIMD-friendly
67
+    if (av_image_alloc(data, linesize, w, h, link->format, 16) < 0)
68
+        return NULL;
69
+
70
+    picref = avfilter_get_video_buffer_ref_from_arrays(data, linesize,
71
+                                                       perms, w, h, link->format);
72
+    if (!picref) {
73
+        av_free(data[0]);
74
+        return NULL;
75
+    }
76
+
77
+    return picref;
78
+}
79
+
80
+AVFilterBufferRef *
81
+avfilter_get_video_buffer_ref_from_arrays(uint8_t *data[4], int linesize[4], int perms,
82
+                                          int w, int h, enum PixelFormat format)
83
+{
84
+    AVFilterBuffer *pic = av_mallocz(sizeof(AVFilterBuffer));
85
+    AVFilterBufferRef *picref = av_mallocz(sizeof(AVFilterBufferRef));
86
+
87
+    if (!pic || !picref)
88
+        goto fail;
89
+
90
+    picref->buf = pic;
91
+    picref->buf->free = ff_avfilter_default_free_buffer;
92
+    if (!(picref->video = av_mallocz(sizeof(AVFilterBufferRefVideoProps))))
93
+        goto fail;
94
+
95
+    pic->w = picref->video->w = w;
96
+    pic->h = picref->video->h = h;
97
+
98
+    /* make sure the buffer gets read permission or it's useless for output */
99
+    picref->perms = perms | AV_PERM_READ;
100
+
101
+    pic->refcount = 1;
102
+    picref->type = AVMEDIA_TYPE_VIDEO;
103
+    pic->format = picref->format = format;
104
+
105
+    memcpy(pic->data,        data,          4*sizeof(data[0]));
106
+    memcpy(pic->linesize,    linesize,      4*sizeof(linesize[0]));
107
+    memcpy(picref->data,     pic->data,     sizeof(picref->data));
108
+    memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize));
109
+
110
+    pic->   extended_data = pic->data;
111
+    picref->extended_data = picref->data;
112
+
113
+    return picref;
114
+
115
+fail:
116
+    if (picref && picref->video)
117
+        av_free(picref->video);
118
+    av_free(picref);
119
+    av_free(pic);
120
+    return NULL;
121
+}
122
+
123
+AVFilterBufferRef *avfilter_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
124
+{
125
+    AVFilterBufferRef *ret = NULL;
126
+
127
+    av_unused char buf[16];
128
+    FF_DPRINTF_START(NULL, get_video_buffer); ff_dlog_link(NULL, link, 0);
129
+    av_dlog(NULL, " perms:%s w:%d h:%d\n", ff_get_ref_perms_string(buf, sizeof(buf), perms), w, h);
130
+
131
+    if (link->dstpad->get_video_buffer)
132
+        ret = link->dstpad->get_video_buffer(link, perms, w, h);
133
+
134
+    if (!ret)
135
+        ret = avfilter_default_get_video_buffer(link, perms, w, h);
136
+
137
+    if (ret)
138
+        ret->type = AVMEDIA_TYPE_VIDEO;
139
+
140
+    FF_DPRINTF_START(NULL, get_video_buffer); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " returning "); ff_dlog_ref(NULL, ret, 1);
141
+
142
+    return ret;
143
+}
144
+
145
+void avfilter_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
146
+{
147
+    avfilter_start_frame(link->dst->outputs[0], picref);
148
+}
149
+
150
+void avfilter_default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
151
+{
152
+    AVFilterLink *outlink = NULL;
153
+
154
+    if (inlink->dst->output_count)
155
+        outlink = inlink->dst->outputs[0];
156
+
157
+    if (outlink) {
158
+        outlink->out_buf = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
159
+        avfilter_copy_buffer_ref_props(outlink->out_buf, picref);
160
+        avfilter_start_frame(outlink, avfilter_ref_buffer(outlink->out_buf, ~0));
161
+    }
162
+}
163
+
164
+/* XXX: should we do the duplicating of the picture ref here, instead of
165
+ * forcing the source filter to do it? */
166
+void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
167
+{
168
+    void (*start_frame)(AVFilterLink *, AVFilterBufferRef *);
169
+    AVFilterPad *dst = link->dstpad;
170
+    int perms = picref->perms;
171
+
172
+    FF_DPRINTF_START(NULL, start_frame); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " "); ff_dlog_ref(NULL, picref, 1);
173
+
174
+    if (!(start_frame = dst->start_frame))
175
+        start_frame = avfilter_default_start_frame;
176
+
177
+    if (picref->linesize[0] < 0)
178
+        perms |= AV_PERM_NEG_LINESIZES;
179
+    /* prepare to copy the picture if it has insufficient permissions */
180
+    if ((dst->min_perms & perms) != dst->min_perms || dst->rej_perms & perms) {
181
+        av_log(link->dst, AV_LOG_DEBUG,
182
+                "frame copy needed (have perms %x, need %x, reject %x)\n",
183
+                picref->perms,
184
+                link->dstpad->min_perms, link->dstpad->rej_perms);
185
+
186
+        link->cur_buf = avfilter_get_video_buffer(link, dst->min_perms, link->w, link->h);
187
+        link->src_buf = picref;
188
+        avfilter_copy_buffer_ref_props(link->cur_buf, link->src_buf);
189
+    }
190
+    else
191
+        link->cur_buf = picref;
192
+
193
+    start_frame(link, link->cur_buf);
194
+}
195
+
196
+void avfilter_null_end_frame(AVFilterLink *link)
197
+{
198
+    avfilter_end_frame(link->dst->outputs[0]);
199
+}
200
+
201
+void avfilter_default_end_frame(AVFilterLink *inlink)
202
+{
203
+    AVFilterLink *outlink = NULL;
204
+
205
+    if (inlink->dst->output_count)
206
+        outlink = inlink->dst->outputs[0];
207
+
208
+    avfilter_unref_buffer(inlink->cur_buf);
209
+    inlink->cur_buf = NULL;
210
+
211
+    if (outlink) {
212
+        if (outlink->out_buf) {
213
+            avfilter_unref_buffer(outlink->out_buf);
214
+            outlink->out_buf = NULL;
215
+        }
216
+        avfilter_end_frame(outlink);
217
+    }
218
+}
219
+
220
+void avfilter_end_frame(AVFilterLink *link)
221
+{
222
+    void (*end_frame)(AVFilterLink *);
223
+
224
+    if (!(end_frame = link->dstpad->end_frame))
225
+        end_frame = avfilter_default_end_frame;
226
+
227
+    end_frame(link);
228
+
229
+    /* unreference the source picture if we're feeding the destination filter
230
+     * a copied version dues to permission issues */
231
+    if (link->src_buf) {
232
+        avfilter_unref_buffer(link->src_buf);
233
+        link->src_buf = NULL;
234
+    }
235
+}
236
+
237
+void avfilter_null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
238
+{
239
+    avfilter_draw_slice(link->dst->outputs[0], y, h, slice_dir);
240
+}
241
+
242
+void avfilter_default_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
243
+{
244
+    AVFilterLink *outlink = NULL;
245
+
246
+    if (inlink->dst->output_count)
247
+        outlink = inlink->dst->outputs[0];
248
+
249
+    if (outlink)
250
+        avfilter_draw_slice(outlink, y, h, slice_dir);
251
+}
252
+
253
+void avfilter_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
254
+{
255
+    uint8_t *src[4], *dst[4];
256
+    int i, j, vsub;
257
+    void (*draw_slice)(AVFilterLink *, int, int, int);
258
+
259
+    FF_DPRINTF_START(NULL, draw_slice); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " y:%d h:%d dir:%d\n", y, h, slice_dir);
260
+
261
+    /* copy the slice if needed for permission reasons */
262
+    if (link->src_buf) {
263
+        vsub = av_pix_fmt_descriptors[link->format].log2_chroma_h;
264
+
265
+        for (i = 0; i < 4; i++) {
266
+            if (link->src_buf->data[i]) {
267
+                src[i] = link->src_buf-> data[i] +
268
+                    (y >> (i==1 || i==2 ? vsub : 0)) * link->src_buf-> linesize[i];
269
+                dst[i] = link->cur_buf->data[i] +
270
+                    (y >> (i==1 || i==2 ? vsub : 0)) * link->cur_buf->linesize[i];
271
+            } else
272
+                src[i] = dst[i] = NULL;
273
+        }
274
+
275
+        for (i = 0; i < 4; i++) {
276
+            int planew =
277
+                av_image_get_linesize(link->format, link->cur_buf->video->w, i);
278
+
279
+            if (!src[i]) continue;
280
+
281
+            for (j = 0; j < h >> (i==1 || i==2 ? vsub : 0); j++) {
282
+                memcpy(dst[i], src[i], planew);
283
+                src[i] += link->src_buf->linesize[i];
284
+                dst[i] += link->cur_buf->linesize[i];
285
+            }
286
+        }
287
+    }
288
+
289
+    if (!(draw_slice = link->dstpad->draw_slice))
290
+        draw_slice = avfilter_default_draw_slice;
291
+    draw_slice(link, y, h, slice_dir);
292
+}
293
+