]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/vf_transpose.c
Merge commit 'd15c21e5fa3961f10026da1a3080a3aa3cf4cec9'
[ffmpeg] / libavfilter / vf_transpose.c
index 4161050c74af6d2dec32c79ce4c41f568540d02f..dc2ee2128caaac90d7ea93c85c5076dd2f1bf1a8 100644 (file)
@@ -28,6 +28,7 @@
 #include <stdio.h>
 
 #include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/internal.h"
 #include "internal.h"
 #include "video.h"
 
+typedef enum {
+    TRANSPOSE_PT_TYPE_NONE,
+    TRANSPOSE_PT_TYPE_LANDSCAPE,
+    TRANSPOSE_PT_TYPE_PORTRAIT,
+} PassthroughType;
+
 typedef struct {
+    const AVClass *class;
     int hsub, vsub;
     int pixsteps[4];
 
@@ -45,46 +53,58 @@ typedef struct {
     /* 2    Rotate by 90 degrees counterclockwise.           */
     /* 3    Rotate by 90 degrees clockwise and vflip.        */
     int dir;
-    int passthrough; ///< landscape passthrough mode enabled
+    PassthroughType passthrough; ///< landscape passthrough mode enabled
 } TransContext;
 
+#define OFFSET(x) offsetof(TransContext, x)
+#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=0},  0, 7, FLAGS },
+
+    { "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 av_cold int init(AVFilterContext *ctx, const char *args)
 {
     TransContext *trans = ctx->priv;
-    trans->dir = 0;
+    const char *shorthand[] = { "dir", "passthrough", NULL };
 
-    if (args)
-        sscanf(args, "%d", &trans->dir);
+    trans->class = &transpose_class;
+    av_opt_set_defaults(trans);
 
-    if (trans->dir < 0 || trans->dir > 7) {
-        av_log(ctx, AV_LOG_ERROR, "Invalid value %d not between 0 and 7.\n",
-               trans->dir);
-        return AVERROR(EINVAL);
-    }
-    return 0;
+    return av_opt_set_from_string(trans, args, shorthand, "=", ":");
 }
 
 static int query_formats(AVFilterContext *ctx)
 {
-    enum PixelFormat pix_fmts[] = {
-        PIX_FMT_ARGB,         PIX_FMT_RGBA,
-        PIX_FMT_ABGR,         PIX_FMT_BGRA,
-        PIX_FMT_RGB24,        PIX_FMT_BGR24,
-        PIX_FMT_RGB565BE,     PIX_FMT_RGB565LE,
-        PIX_FMT_RGB555BE,     PIX_FMT_RGB555LE,
-        PIX_FMT_BGR565BE,     PIX_FMT_BGR565LE,
-        PIX_FMT_BGR555BE,     PIX_FMT_BGR555LE,
-        PIX_FMT_GRAY16BE,     PIX_FMT_GRAY16LE,
-        PIX_FMT_YUV420P16LE,  PIX_FMT_YUV420P16BE,
-        PIX_FMT_YUV444P16LE,  PIX_FMT_YUV444P16BE,
-        PIX_FMT_NV12,         PIX_FMT_NV21,
-        PIX_FMT_RGB8,         PIX_FMT_BGR8,
-        PIX_FMT_RGB4_BYTE,    PIX_FMT_BGR4_BYTE,
-        PIX_FMT_YUV444P,      PIX_FMT_YUVJ444P,
-        PIX_FMT_YUV420P,      PIX_FMT_YUVJ420P,
-        PIX_FMT_YUV410P,
-        PIX_FMT_YUVA420P,     PIX_FMT_GRAY8,
-        PIX_FMT_NONE
+    enum AVPixelFormat pix_fmts[] = {
+        AV_PIX_FMT_ARGB,         AV_PIX_FMT_RGBA,
+        AV_PIX_FMT_ABGR,         AV_PIX_FMT_BGRA,
+        AV_PIX_FMT_RGB24,        AV_PIX_FMT_BGR24,
+        AV_PIX_FMT_RGB565BE,     AV_PIX_FMT_RGB565LE,
+        AV_PIX_FMT_RGB555BE,     AV_PIX_FMT_RGB555LE,
+        AV_PIX_FMT_BGR565BE,     AV_PIX_FMT_BGR565LE,
+        AV_PIX_FMT_BGR555BE,     AV_PIX_FMT_BGR555LE,
+        AV_PIX_FMT_GRAY16BE,     AV_PIX_FMT_GRAY16LE,
+        AV_PIX_FMT_YUV420P16LE,  AV_PIX_FMT_YUV420P16BE,
+        AV_PIX_FMT_YUV444P16LE,  AV_PIX_FMT_YUV444P16BE,
+        AV_PIX_FMT_NV12,         AV_PIX_FMT_NV21,
+        AV_PIX_FMT_RGB8,         AV_PIX_FMT_BGR8,
+        AV_PIX_FMT_RGB4_BYTE,    AV_PIX_FMT_BGR4_BYTE,
+        AV_PIX_FMT_YUV444P,      AV_PIX_FMT_YUVJ444P,
+        AV_PIX_FMT_YUV420P,      AV_PIX_FMT_YUVJ420P,
+        AV_PIX_FMT_YUV410P,
+        AV_PIX_FMT_YUVA420P,     AV_PIX_FMT_GRAY8,
+        AV_PIX_FMT_NONE
     };
 
     ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
@@ -96,24 +116,30 @@ static int config_props_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     TransContext *trans = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
-    const AVPixFmtDescriptor *pixdesc = &av_pix_fmt_descriptors[outlink->format];
+    const AVPixFmtDescriptor *desc_out = av_pix_fmt_desc_get(outlink->format);
+    const AVPixFmtDescriptor *desc_in  = av_pix_fmt_desc_get(inlink->format);
 
     if (trans->dir&4) {
+        av_log(ctx, AV_LOG_WARNING,
+               "dir values greater than 3 are deprecated, use the passthrough option instead\n");
         trans->dir &= 3;
-        if (inlink->w >= inlink->h) {
-            trans->passthrough = 1;
+        trans->passthrough = TRANSPOSE_PT_TYPE_LANDSCAPE;
+    }
 
-            av_log(ctx, AV_LOG_VERBOSE,
-                   "w:%d h:%d -> w:%d h:%d (landscape passthrough mode)\n",
-                   inlink->w, inlink->h, outlink->w, outlink->h);
-            return 0;
-        }
+    if ((inlink->w >= inlink->h && trans->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) ||
+        (inlink->w <= inlink->h && trans->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) {
+        av_log(ctx, AV_LOG_VERBOSE,
+               "w:%d h:%d -> w:%d h:%d (passthrough mode)\n",
+               inlink->w, inlink->h, inlink->w, inlink->h);
+        return 0;
+    } else {
+        trans->passthrough = TRANSPOSE_PT_TYPE_NONE;
     }
 
-    trans->hsub = av_pix_fmt_descriptors[inlink->format].log2_chroma_w;
-    trans->vsub = av_pix_fmt_descriptors[inlink->format].log2_chroma_h;
+    trans->hsub = desc_in->log2_chroma_w;
+    trans->vsub = desc_in->log2_chroma_h;
 
-    av_image_fill_max_pixsteps(trans->pixsteps, NULL, pixdesc);
+    av_image_fill_max_pixsteps(trans->pixsteps, NULL, desc_out);
 
     outlink->w = inlink->h;
     outlink->h = inlink->w;
@@ -241,6 +267,28 @@ static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
     return trans->passthrough ? ff_null_draw_slice(inlink, y, h, slice_dir) : 0;
 }
 
+static const AVFilterPad avfilter_vf_transpose_inputs[] = {
+    {
+        .name        = "default",
+        .type        = AVMEDIA_TYPE_VIDEO,
+        .get_video_buffer= get_video_buffer,
+        .start_frame = start_frame,
+        .draw_slice  = draw_slice,
+        .end_frame   = end_frame,
+        .min_perms   = AV_PERM_READ,
+    },
+    { NULL }
+};
+
+static const AVFilterPad avfilter_vf_transpose_outputs[] = {
+    {
+        .name         = "default",
+        .config_props = config_props_output,
+        .type         = AVMEDIA_TYPE_VIDEO,
+    },
+    { NULL }
+};
+
 AVFilter avfilter_vf_transpose = {
     .name      = "transpose",
     .description = NULL_IF_CONFIG_SMALL("Transpose input video."),
@@ -250,16 +298,7 @@ AVFilter avfilter_vf_transpose = {
 
     .query_formats = query_formats,
 
-    .inputs    = (const AVFilterPad[]) {{ .name            = "default",
-                                          .type            = AVMEDIA_TYPE_VIDEO,
-                                          .get_video_buffer= get_video_buffer,
-                                          .start_frame     = start_frame,
-                                          .draw_slice      = draw_slice,
-                                          .end_frame       = end_frame,
-                                          .min_perms       = AV_PERM_READ, },
-                                        { .name = NULL}},
-    .outputs   = (const AVFilterPad[]) {{ .name            = "default",
-                                          .config_props    = config_props_output,
-                                          .type            = AVMEDIA_TYPE_VIDEO, },
-                                        { .name = NULL}},
+    .inputs    = avfilter_vf_transpose_inputs,
+    .outputs   = avfilter_vf_transpose_outputs,
+    .priv_class = &transpose_class,
 };