Originally committed as revision 26315 to svn://svn.ffmpeg.org/ffmpeg/trunk
Michael Niedermayer authored on 2011/01/12 08:53:24... | ... |
@@ -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); |