return 0;
}
-static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
{
- AVFilterLink *outlink = inlink->dst->outputs[0];
TransContext *trans = inlink->dst->priv;
- AVFrame *out;
- int plane;
- out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
- if (!out) {
- av_frame_free(&in);
- return AVERROR(ENOMEM);
- }
+ return trans->passthrough ?
+ ff_null_get_video_buffer (inlink, w, h) :
+ ff_default_get_video_buffer(inlink, w, h);
+}
- out->pts = in->pts;
+typedef struct ThreadData {
+ AVFrame *in, *out;
+} ThreadData;
- if (in->sample_aspect_ratio.num == 0) {
- out->sample_aspect_ratio = in->sample_aspect_ratio;
- } else {
- out->sample_aspect_ratio.num = in->sample_aspect_ratio.den;
- out->sample_aspect_ratio.den = in->sample_aspect_ratio.num;
- }
+static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr,
+ int nb_jobs)
+{
+ TransContext *trans = ctx->priv;
+ ThreadData *td = arg;
+ AVFrame *out = td->out;
+ AVFrame *in = td->in;
+ int plane;
for (plane = 0; out->data[plane]; plane++) {
- int hsub = plane == 1 || plane == 2 ? trans->hsub : 0;
- int vsub = plane == 1 || plane == 2 ? trans->vsub : 0;
+ int hsub = plane == 1 || plane == 2 ? trans->hsub : 0;
+ int vsub = plane == 1 || plane == 2 ? trans->vsub : 0;
int pixstep = trans->pixsteps[plane];
- int inh = in->height >> vsub;
- int outw = FF_CEIL_RSHIFT(out->width, hsub);
- int outh = FF_CEIL_RSHIFT(out->height, vsub);
- int start = (outh * jobnr ) / nb_jobs;
- int end = (outh * (jobnr+1)) / nb_jobs;
- int inh = in->height >> vsub;
- int outw = out->width >> hsub;
- int outh = out->height >> vsub;
++ int inh = in->height >> vsub;
++ int outw = FF_CEIL_RSHIFT(out->width, hsub);
++ int outh = FF_CEIL_RSHIFT(out->height, vsub);
++ int start = (outh * jobnr ) / nb_jobs;
++ int end = (outh * (jobnr+1)) / nb_jobs;
uint8_t *dst, *src;
int dstlinesize, srclinesize;
int x, y;
- dst = out->data[plane];
dstlinesize = out->linesize[plane];
- dst = out->data[plane] + start * dstlinesize;
- src = in->data[plane];
++ dst = out->data[plane] + start * dstlinesize;
+ src = in->data[plane];
srclinesize = in->linesize[plane];
- if (trans->dir&1) {
- src += in->linesize[plane] * (inh-1);
+ if (trans->dir & 1) {
+ src += in->linesize[plane] * (inh - 1);
srclinesize *= -1;
}
- if (trans->dir&2) {
- dst = out->data[plane] + dstlinesize * (outh-start-1);
+ if (trans->dir & 2) {
- dst += out->linesize[plane] * (outh - 1);
++ dst = out->data[plane] + dstlinesize * (outh - start - 1);
dstlinesize *= -1;
}
- for (y = 0; y < outh; y++) {
- switch (pixstep) {
- case 1:
+ switch (pixstep) {
+ case 1:
+ for (y = start; y < end; y++, dst += dstlinesize)
for (x = 0; x < outw; x++)
- dst[x] = src[x*srclinesize + y];
+ dst[x] = src[x * srclinesize + y];
- break;
- case 2:
+ break;
+ case 2:
+ for (y = start; y < end; y++, dst += dstlinesize) {
for (x = 0; x < outw; x++)
- *((uint16_t *)(dst + 2*x)) = *((uint16_t *)(src + x*srclinesize + y*2));
+ *((uint16_t *)(dst + 2 * x)) =
+ *((uint16_t *)(src + x * srclinesize + y * 2));
- break;
- case 3:
+ }
+ break;
+ case 3:
+ for (y = start; y < end; y++, dst += dstlinesize) {
for (x = 0; x < outw; x++) {
- int32_t v = AV_RB24(src + x*srclinesize + y*3);
- AV_WB24(dst + 3*x, v);
+ int32_t v = AV_RB24(src + x * srclinesize + y * 3);
+ AV_WB24(dst + 3 * x, v);
}
- break;
- case 4:
+ }
+ break;
+ case 4:
+ for (y = start; y < end; y++, dst += dstlinesize) {
for (x = 0; x < outw; x++)
- *((uint32_t *)(dst + 4*x)) = *((uint32_t *)(src + x*srclinesize + y*4));
+ *((uint32_t *)(dst + 4 * x)) =
+ *((uint32_t *)(src + x * srclinesize + y * 4));
- break;
}
- dst += dstlinesize;
+ break;
+ case 6:
+ for (y = start; y < end; y++, dst += dstlinesize) {
+ for (x = 0; x < outw; x++) {
- int64_t v = AV_RB48(src + x*srclinesize + y*6);
++ int64_t v = AV_RB48(src + x * srclinesize + y*6);
+ AV_WB48(dst + 6*x, v);
+ }
+ }
+ break;
+ case 8:
+ for (y = start; y < end; y++, dst += dstlinesize) {
+ for (x = 0; x < outw; x++)
- *((uint64_t *)(dst + 8*x)) = *((uint64_t *)(src + x*srclinesize + y*8));
++ *((uint64_t *)(dst + 8*x)) = *((uint64_t *)(src + x * srclinesize + y*8));
+ }
+ break;
}
}
}
#define OFFSET(x) offsetof(TransContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "dir", "Transpose direction", OFFSET(dir), AV_OPT_TYPE_INT, { .i64 = TRANSPOSE_CCLOCK_FLIP },
- TRANSPOSE_CCLOCK_FLIP, TRANSPOSE_CLOCK_FLIP, FLAGS, "dir" },
- { "cclock_flip", "counter-clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK_FLIP }, .unit = "dir" },
- { "clock", "clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK }, .unit = "dir" },
- { "cclock", "counter-clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK }, .unit = "dir" },
- { "clock_flip", "clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK_FLIP }, .unit = "dir" },
- { NULL },
-};
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption transpose_options[] = {
+ { "dir", "set transpose direction", OFFSET(dir), AV_OPT_TYPE_INT, { .i64 = TRANSPOSE_CCLOCK_FLIP }, 0, 7, FLAGS, "dir" },
+ { "cclock_flip", "rotate counter-clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK_FLIP }, .unit = "dir" },
+ { "clock", "rotate clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK }, .unit = "dir" },
+ { "cclock", "rotate counter-clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK }, .unit = "dir" },
+ { "clock_flip", "rotate clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK_FLIP }, .unit = "dir" },
-static const AVClass transpose_class = {
- .class_name = "transpose",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
+ { "passthrough", "do not apply transposition if the input matches the specified geometry",
+ OFFSET(passthrough), AV_OPT_TYPE_INT, {.i64=TRANSPOSE_PT_TYPE_NONE}, 0, INT_MAX, FLAGS, "passthrough" },
+ { "none", "always apply transposition", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_NONE}, INT_MIN, INT_MAX, FLAGS, "passthrough" },
+ { "portrait", "preserve portrait geometry", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_PORTRAIT}, INT_MIN, INT_MAX, FLAGS, "passthrough" },
+ { "landscape", "preserve landscape geometry", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_LANDSCAPE}, INT_MIN, INT_MAX, FLAGS, "passthrough" },
+
+ { NULL }
};
+AVFILTER_DEFINE_CLASS(transpose);
+
static const AVFilterPad avfilter_vf_transpose_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .get_video_buffer = get_video_buffer,
- .filter_frame = filter_frame,
+ .filter_frame = filter_frame,
},
{ NULL }
};