Browse code

Fix design of the pad filter. Previously the pad filter just drawed borders in the surrounding of the input without checking if this area was allocated or writeable. Now we check and allocate a new buffer if the input is unsuitable.

Originally committed as revision 26315 to svn://svn.ffmpeg.org/ffmpeg/trunk

Michael Niedermayer authored on 2011/01/12 08:53:24
Showing 1 changed files
... ...
@@ -27,6 +27,7 @@
27 27
 #include "avfilter.h"
28 28
 #include "libavutil/pixdesc.h"
29 29
 #include "libavutil/colorspace.h"
30
+#include "libavutil/avassert.h"
30 31
 #include "libavcore/imgutils.h"
31 32
 #include "libavcore/parseutils.h"
32 33
 
... ...
@@ -100,6 +101,24 @@ static void draw_rectangle(AVFilterBufferRef *outpic, uint8_t *line[4], int line
100 100
     }
101 101
 }
102 102
 
103
+static void copy_rectangle(AVFilterBufferRef *outpic,uint8_t *line[4], int line_step[4], int linesize[4],
104
+                           int hsub, int vsub, int x, int y, int y2, int w, int h)
105
+{
106
+    int i, plane;
107
+    uint8_t *p;
108
+
109
+    for (plane = 0; plane < 4 && outpic->data[plane]; plane++) {
110
+        int hsub1 = plane == 1 || plane == 2 ? hsub : 0;
111
+        int vsub1 = plane == 1 || plane == 2 ? vsub : 0;
112
+
113
+        p = outpic->data[plane] + (y >> vsub1) * outpic->linesize[plane];
114
+        for (i = 0; i < (h >> vsub1); i++) {
115
+            memcpy(p + (x >> hsub1) * line_step[plane], line[plane] + linesize[plane]*(i+(y2>>vsub1)), (w >> hsub1) * line_step[plane]);
116
+            p += outpic->linesize[plane];
117
+        }
118
+    }
119
+}
120
+
103 121
 static int query_formats(AVFilterContext *ctx)
104 122
 {
105 123
     static const enum PixelFormat pix_fmts[] = {
... ...
@@ -132,6 +151,7 @@ typedef struct {
132 132
     uint8_t *line[4];
133 133
     int      line_step[4];
134 134
     int hsub, vsub;         ///< chroma subsampling values
135
+    int needs_copy;
135 136
 } PadContext;
136 137
 
137 138
 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
... ...
@@ -243,21 +263,65 @@ static AVFilterBufferRef *get_video_buffer(AVFilterLink *inlink, int perms, int
243 243
     return picref;
244 244
 }
245 245
 
246
+static int does_clip(PadContext *pad, AVFilterBufferRef *outpicref, int plane, int hsub, int vsub, int x, int y)
247
+{
248
+    int64_t x_in_buf, y_in_buf;
249
+
250
+    x_in_buf =  outpicref->data[plane] - outpicref->buf->data[plane]
251
+             +  (x >> hsub) * pad      ->line_step[plane]
252
+             +  (y >> vsub) * outpicref->linesize [plane];
253
+
254
+    if(x_in_buf < 0 || x_in_buf % pad->line_step[plane])
255
+        return 1;
256
+    x_in_buf /= pad->line_step[plane];
257
+
258
+    av_assert0(outpicref->buf->linesize[plane]>0); //while reference can use negative linesize the main buffer should not
259
+
260
+    y_in_buf = x_in_buf / outpicref->buf->linesize[plane];
261
+    x_in_buf %= outpicref->buf->linesize[plane];
262
+
263
+    if(   y_in_buf<<vsub >= outpicref->buf->h
264
+       || x_in_buf<<hsub >= outpicref->buf->w)
265
+        return 1;
266
+    return 0;
267
+}
268
+
246 269
 static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
247 270
 {
248 271
     PadContext *pad = inlink->dst->priv;
249 272
     AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0);
250 273
     int plane;
251 274
 
252
-    inlink->dst->outputs[0]->out_buf = outpicref;
253
-
254 275
     for (plane = 0; plane < 4 && outpicref->data[plane]; plane++) {
255 276
         int hsub = (plane == 1 || plane == 2) ? pad->hsub : 0;
256 277
         int vsub = (plane == 1 || plane == 2) ? pad->vsub : 0;
257 278
 
258
-        outpicref->data[plane] -= (pad->x >> hsub) * pad->line_step[plane] +
259
-            (pad->y >> vsub) * outpicref->linesize[plane];
279
+        av_assert0(outpicref->buf->w>0 && outpicref->buf->h>0);
280
+
281
+        if(outpicref->format != outpicref->buf->format) //unsupported currently
282
+            break;
283
+
284
+        outpicref->data[plane] -=   (pad->x  >> hsub) * pad      ->line_step[plane]
285
+                                  + (pad->y  >> vsub) * outpicref->linesize [plane];
286
+
287
+        if(   does_clip(pad, outpicref, plane, hsub, vsub, 0, 0)
288
+           || does_clip(pad, outpicref, plane, hsub, vsub, 0, pad->h-1)
289
+           || does_clip(pad, outpicref, plane, hsub, vsub, pad->w-1, 0)
290
+           || does_clip(pad, outpicref, plane, hsub, vsub, pad->w-1, pad->h-1)
291
+          )
292
+            break;
260 293
     }
294
+    pad->needs_copy= plane < 4 && outpicref->data[plane];
295
+    if(pad->needs_copy){
296
+        av_log(inlink->dst, AV_LOG_DEBUG, "Direct padding impossible allocating new frame\n");
297
+        avfilter_unref_buffer(outpicref);
298
+        outpicref = avfilter_get_video_buffer(inlink->dst->outputs[0], AV_PERM_WRITE | AV_PERM_NEG_LINESIZES,
299
+                                                       FFMAX(inlink->w, pad->w),
300
+                                                       FFMAX(inlink->h, pad->h));
301
+        avfilter_copy_buffer_ref_props(outpicref, inpicref);
302
+    }
303
+
304
+    inlink->dst->outputs[0]->out_buf = outpicref;
261 305
 
262 306
     outpicref->video->w = pad->w;
263 307
     outpicref->video->h = pad->h;
... ...
@@ -298,6 +362,7 @@ static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
298 298
 {
299 299
     PadContext *pad = link->dst->priv;
300 300
     AVFilterBufferRef *outpic = link->dst->outputs[0]->out_buf;
301
+    AVFilterBufferRef *inpic = link->cur_buf;
301 302
 
302 303
     y += pad->y;
303 304
 
... ...
@@ -311,6 +376,13 @@ static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
311 311
     /* left border */
312 312
     draw_rectangle(outpic, pad->line, pad->line_step, pad->hsub, pad->vsub,
313 313
                    0, y, pad->x, h);
314
+
315
+    if(pad->needs_copy){
316
+        copy_rectangle(outpic,
317
+                       inpic->data, pad->line_step, inpic->linesize, pad->hsub, pad->vsub,
318
+                       pad->x, y, y-pad->y, inpic->video->w, h);
319
+    }
320
+
314 321
     /* right border */
315 322
     draw_rectangle(outpic, pad->line, pad->line_step, pad->hsub, pad->vsub,
316 323
                    pad->x + pad->in_w, y, pad->w - pad->x - pad->in_w, h);