|
|
|
@ -82,6 +82,10 @@ static av_cold int init(AVFilterContext *ctx) |
|
|
|
|
if (!s->frames) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
s->items = av_calloc(s->nb_inputs, sizeof(*s->items)); |
|
|
|
|
if (!s->items) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
if (!strcmp(ctx->filter->name, "xstack")) { |
|
|
|
|
if (!s->layout) { |
|
|
|
|
if (s->nb_inputs == 2) { |
|
|
|
@ -93,10 +97,6 @@ static av_cold int init(AVFilterContext *ctx) |
|
|
|
|
return AVERROR(EINVAL); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
s->items = av_calloc(s->nb_inputs, sizeof(*s->items)); |
|
|
|
|
if (!s->items) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (i = 0; i < s->nb_inputs; i++) { |
|
|
|
@ -123,7 +123,7 @@ static int process_frame(FFFrameSync *fs) |
|
|
|
|
StackContext *s = fs->opaque; |
|
|
|
|
AVFrame **in = s->frames; |
|
|
|
|
AVFrame *out; |
|
|
|
|
int i, p, ret, offset[4] = { 0 }; |
|
|
|
|
int i, p, ret; |
|
|
|
|
|
|
|
|
|
for (i = 0; i < s->nb_inputs; i++) { |
|
|
|
|
if ((ret = ff_framesync_get_frame(&s->fs, i, &in[i], 0)) < 0) |
|
|
|
@ -137,44 +137,14 @@ static int process_frame(FFFrameSync *fs) |
|
|
|
|
out->sample_aspect_ratio = outlink->sample_aspect_ratio; |
|
|
|
|
|
|
|
|
|
for (i = 0; i < s->nb_inputs; i++) { |
|
|
|
|
AVFilterLink *inlink = ctx->inputs[i]; |
|
|
|
|
int linesize[4]; |
|
|
|
|
int height[4]; |
|
|
|
|
|
|
|
|
|
if (s->is_horizontal || s->is_vertical) { |
|
|
|
|
if ((ret = av_image_fill_linesizes(linesize, inlink->format, inlink->w)) < 0) { |
|
|
|
|
av_frame_free(&out); |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
height[1] = height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); |
|
|
|
|
height[0] = height[3] = inlink->h; |
|
|
|
|
} |
|
|
|
|
StackItem *item = &s->items[i]; |
|
|
|
|
|
|
|
|
|
for (p = 0; p < s->nb_planes; p++) { |
|
|
|
|
if (s->is_vertical) { |
|
|
|
|
av_image_copy_plane(out->data[p] + offset[p] * out->linesize[p], |
|
|
|
|
out->linesize[p], |
|
|
|
|
in[i]->data[p], |
|
|
|
|
in[i]->linesize[p], |
|
|
|
|
linesize[p], height[p]); |
|
|
|
|
offset[p] += height[p]; |
|
|
|
|
} else if (s->is_horizontal) { |
|
|
|
|
av_image_copy_plane(out->data[p] + offset[p], |
|
|
|
|
out->linesize[p], |
|
|
|
|
in[i]->data[p], |
|
|
|
|
in[i]->linesize[p], |
|
|
|
|
linesize[p], height[p]); |
|
|
|
|
offset[p] += linesize[p]; |
|
|
|
|
} else { |
|
|
|
|
StackItem *item = &s->items[i]; |
|
|
|
|
|
|
|
|
|
av_image_copy_plane(out->data[p] + out->linesize[p] * item->y[p] + item->x[p], |
|
|
|
|
out->linesize[p], |
|
|
|
|
in[i]->data[p], |
|
|
|
|
in[i]->linesize[p], |
|
|
|
|
item->linesize[p], item->height[p]); |
|
|
|
|
} |
|
|
|
|
av_image_copy_plane(out->data[p] + out->linesize[p] * item->y[p] + item->x[p], |
|
|
|
|
out->linesize[p], |
|
|
|
|
in[i]->data[p], |
|
|
|
|
in[i]->linesize[p], |
|
|
|
|
item->linesize[p], item->height[p]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -197,20 +167,53 @@ static int config_output(AVFilterLink *outlink) |
|
|
|
|
return AVERROR_BUG; |
|
|
|
|
|
|
|
|
|
if (s->is_vertical) { |
|
|
|
|
for (i = 1; i < s->nb_inputs; i++) { |
|
|
|
|
for (i = 0; i < s->nb_inputs; i++) { |
|
|
|
|
AVFilterLink *inlink = ctx->inputs[i]; |
|
|
|
|
StackItem *item = &s->items[i]; |
|
|
|
|
|
|
|
|
|
if (ctx->inputs[i]->w != width) { |
|
|
|
|
av_log(ctx, AV_LOG_ERROR, "Input %d width %d does not match input %d width %d.\n", i, ctx->inputs[i]->w, 0, width); |
|
|
|
|
return AVERROR(EINVAL); |
|
|
|
|
} |
|
|
|
|
height += ctx->inputs[i]->h; |
|
|
|
|
|
|
|
|
|
if ((ret = av_image_fill_linesizes(item->linesize, inlink->format, inlink->w)) < 0) { |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
item->height[1] = item->height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); |
|
|
|
|
item->height[0] = item->height[3] = inlink->h; |
|
|
|
|
|
|
|
|
|
if (i) { |
|
|
|
|
item->y[1] = item->y[2] = AV_CEIL_RSHIFT(height, s->desc->log2_chroma_h); |
|
|
|
|
item->y[0] = item->y[3] = height; |
|
|
|
|
|
|
|
|
|
height += ctx->inputs[i]->h; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else if (s->is_horizontal) { |
|
|
|
|
for (i = 1; i < s->nb_inputs; i++) { |
|
|
|
|
for (i = 0; i < s->nb_inputs; i++) { |
|
|
|
|
AVFilterLink *inlink = ctx->inputs[i]; |
|
|
|
|
StackItem *item = &s->items[i]; |
|
|
|
|
|
|
|
|
|
if (ctx->inputs[i]->h != height) { |
|
|
|
|
av_log(ctx, AV_LOG_ERROR, "Input %d height %d does not match input %d height %d.\n", i, ctx->inputs[i]->h, 0, height); |
|
|
|
|
return AVERROR(EINVAL); |
|
|
|
|
} |
|
|
|
|
width += ctx->inputs[i]->w; |
|
|
|
|
|
|
|
|
|
if ((ret = av_image_fill_linesizes(item->linesize, inlink->format, inlink->w)) < 0) { |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
item->height[1] = item->height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); |
|
|
|
|
item->height[0] = item->height[3] = inlink->h; |
|
|
|
|
|
|
|
|
|
if (i) { |
|
|
|
|
if ((ret = av_image_fill_linesizes(item->x, inlink->format, width)) < 0) { |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
width += ctx->inputs[i]->w; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
char *arg, *p = s->layout, *saveptr = NULL; |
|
|
|
|