avfilter/vf_v360: add padding option for cubemap
authorEugene Lyapustin <unishifft@gmail.com>
Thu, 15 Aug 2019 00:56:12 +0000 (03:56 +0300)
committerKieran Kunhya <kierank@obe.tv>
Mon, 19 Aug 2019 08:06:27 +0000 (09:06 +0100)
Signed-off-by: Eugene Lyapustin <unishifft@gmail.com>
doc/filters.texi
libavfilter/vf_v360.c

index 7b03520..599cb7a 100644 (file)
@@ -17917,6 +17917,20 @@ Cubemap with 3x2/6x1 layout.
 Format specific options:
 
 @table @option
+@item in_pad
+@item out_pad
+Set padding proprtion for the input/output cubemap. Values in decimals.
+
+Example values:
+@table @samp
+@item 0
+No padding.
+@item 0.01
+1% of face is padding. For example, with 1920x1280 resolution face size would be 640x640 and padding would be 3 pixels from each side. (640 * 0.01 = 6 pixels)
+@end table
+
+Default value is @b{@samp{0}}.
+
 @item in_forder
 @item out_forder
 Set order of faces for the input/output cubemap. Choose one direction for each position.
@@ -18017,9 +18031,9 @@ Flip the output video horizontally/vertically/in-depth. Boolean values.
 
 @itemize
 @item
-Convert equirectangular video to cubemap with 3x2 layout using bicubic interpolation:
+Convert equirectangular video to cubemap with 3x2 layout and 1% padding using bicubic interpolation:
 @example
-ffmpeg -i input.mkv -vf v360=e:c3x2:cubic output.mkv
+ffmpeg -i input.mkv -vf v360=e:c3x2:cubic:out_pad=0.01 output.mkv
 @end example
 @item
 Extract back view of Equi-Angular Cubemap:
index d23bcd3..22e1f72 100644 (file)
@@ -102,6 +102,8 @@ typedef struct V360Context {
     int in_cubemap_face_rotation[6];
     int out_cubemap_face_rotation[6];
 
+    float in_pad, out_pad;
+
     float yaw, pitch, roll;
 
     int h_flip, v_flip, d_flip;
@@ -155,6 +157,8 @@ static const AVOption v360_options[] = {
     {"out_forder", "output cubemap face order", OFFSET(out_forder), AV_OPT_TYPE_STRING, {.str="rludfb"},        0,     NB_DIRECTIONS-1, FLAGS, "out_forder"},
     {   "in_frot", "input cubemap face rotation",  OFFSET(in_frot), AV_OPT_TYPE_STRING, {.str="000000"},        0,     NB_DIRECTIONS-1, FLAGS, "in_frot"},
     {  "out_frot", "output cubemap face rotation",OFFSET(out_frot), AV_OPT_TYPE_STRING, {.str="000000"},        0,     NB_DIRECTIONS-1, FLAGS, "out_frot"},
+    {    "in_pad", "input cubemap pads",            OFFSET(in_pad), AV_OPT_TYPE_FLOAT,  {.dbl=0.f},           0.f,                 1.f, FLAGS, "in_pad"},
+    {   "out_pad", "output cubemap pads",          OFFSET(out_pad), AV_OPT_TYPE_FLOAT,  {.dbl=0.f},           0.f,                 1.f, FLAGS, "out_pad"},
     {       "yaw", "yaw rotation",                     OFFSET(yaw), AV_OPT_TYPE_FLOAT,  {.dbl=0.f},        -180.f,               180.f, FLAGS, "yaw"},
     {     "pitch", "pitch rotation",                 OFFSET(pitch), AV_OPT_TYPE_FLOAT,  {.dbl=0.f},        -180.f,               180.f, FLAGS, "pitch"},
     {      "roll", "roll rotation",                   OFFSET(roll), AV_OPT_TYPE_FLOAT,  {.dbl=0.f},        -180.f,               180.f, FLAGS, "roll"},
@@ -734,6 +738,9 @@ static void cube_to_xyz(const V360Context *s,
     float norm;
     float l_x, l_y, l_z;
 
+    uf /= (1.f - s->out_pad);
+    vf /= (1.f - s->out_pad);
+
     rotate_cube_face_inverse(&uf, &vf, s->out_cubemap_face_rotation[face]);
 
     switch (direction) {
@@ -1091,6 +1098,9 @@ static void xyz_to_cube3x2(const V360Context *s,
 
     xyz_to_cube(s, vec, &uf, &vf, &direction);
 
+    uf *= (1.f - s->in_pad);
+    vf *= (1.f - s->in_pad);
+
     face = s->in_cubemap_face_order[direction];
     u_face = face % 3;
     v_face = face / 3;
@@ -1108,22 +1118,44 @@ static void xyz_to_cube3x2(const V360Context *s,
 
     for (i = -1; i < 3; i++) {
         for (j = -1; j < 3; j++) {
-            float u, v;
+            int new_ui = ui + j;
+            int new_vi = vi + i;
             int u_shift, v_shift;
             int new_ewi, new_ehi;
 
-            process_cube_coordinates(s, 2.f * (ui + j) / ewi - 1.f,
-                                        2.f * (vi + i) / ehi - 1.f,
-                                        direction, &u, &v, &face);
-            u_face = face % 3;
-            v_face = face / 3;
-            u_shift = ceilf(ew * u_face);
-            v_shift = ceilf(eh * v_face);
-            new_ewi = ceilf(ew * (u_face + 1)) - u_shift;
-            new_ehi = ceilf(eh * (v_face + 1)) - v_shift;
-
-            us[i + 1][j + 1] = u_shift + av_clip(roundf(0.5f * new_ewi * (u + 1.f)), 0, new_ewi - 1);
-            vs[i + 1][j + 1] = v_shift + av_clip(roundf(0.5f * new_ehi * (v + 1.f)), 0, new_ehi - 1);
+            if (new_ui >= 0 && new_ui < ewi && new_vi >= 0 && new_vi < ehi) {
+                face = s->in_cubemap_face_order[direction];
+
+                u_face = face % 3;
+                v_face = face / 3;
+                u_shift = ceilf(ew * u_face);
+                v_shift = ceilf(eh * v_face);
+            } else {
+                uf = 2.f * new_ui / ewi - 1.f;
+                vf = 2.f * new_vi / ehi - 1.f;
+
+                uf /= (1.f - s->in_pad);
+                vf /= (1.f - s->in_pad);
+
+                process_cube_coordinates(s, uf, vf, direction, &uf, &vf, &face);
+
+                uf *= (1.f - s->in_pad);
+                vf *= (1.f - s->in_pad);
+
+                u_face = face % 3;
+                v_face = face / 3;
+                u_shift = ceilf(ew * u_face);
+                v_shift = ceilf(eh * v_face);
+                new_ewi = ceilf(ew * (u_face + 1)) - u_shift;
+                new_ehi = ceilf(eh * (v_face + 1)) - v_shift;
+
+                new_ui = av_clip(roundf(0.5f * new_ewi * (uf + 1.f)), 0, new_ewi - 1);
+                new_vi = av_clip(roundf(0.5f * new_ehi * (vf + 1.f)), 0, new_ehi - 1);
+            }
+
+
+            us[i + 1][j + 1] = u_shift + new_ui;
+            vs[i + 1][j + 1] = v_shift + new_vi;
         }
     }
 }
@@ -1173,7 +1205,7 @@ static void xyz_to_cube6x1(const V360Context *s,
                            uint16_t us[4][4], uint16_t vs[4][4], float *du, float *dv)
 {
     const float ew = width / 6.f;
-    const float eh = height;
+    const int ehi = height;
     float uf, vf;
     int ui, vi;
     int ewi;
@@ -1182,11 +1214,14 @@ static void xyz_to_cube6x1(const V360Context *s,
 
     xyz_to_cube(s, vec, &uf, &vf, &direction);
 
+    uf *= (1.f - s->in_pad);
+    vf *= (1.f - s->in_pad);
+
     face = s->in_cubemap_face_order[direction];
     ewi = ceilf(ew * (face + 1)) - ceilf(ew * face);
 
     uf = 0.5f * ewi * (uf + 1.f);
-    vf = 0.5f * eh  * (vf + 1.f);
+    vf = 0.5f * ehi * (vf + 1.f);
 
     ui = floorf(uf);
     vi = floorf(vf);
@@ -1196,18 +1231,37 @@ static void xyz_to_cube6x1(const V360Context *s,
 
     for (i = -1; i < 3; i++) {
         for (j = -1; j < 3; j++) {
-            float u, v;
+            int new_ui = ui + j;
+            int new_vi = vi + i;
             int u_shift;
             int new_ewi;
 
-            process_cube_coordinates(s, 2.f * (ui + j) / ewi - 1.f,
-                                        2.f * (vi + i) / eh  - 1.f,
-                                        direction, &u, &v, &face);
-            u_shift = ceilf(ew * face);
-            new_ewi = ceilf(ew * (face + 1)) - u_shift;
+            if (new_ui >= 0 && new_ui < ewi && new_vi >= 0 && new_vi < ehi) {
+                face = s->in_cubemap_face_order[direction];
+
+                u_shift = ceilf(ew * face);
+            } else {
+                uf = 2.f * new_ui / ewi - 1.f;
+                vf = 2.f * new_vi / ehi - 1.f;
+
+                uf /= (1.f - s->in_pad);
+                vf /= (1.f - s->in_pad);
+
+                process_cube_coordinates(s, uf, vf, direction, &uf, &vf, &face);
+
+                uf *= (1.f - s->in_pad);
+                vf *= (1.f - s->in_pad);
+
+                u_shift = ceilf(ew * face);
+                new_ewi = ceilf(ew * (face + 1)) - u_shift;
+
+                new_ui = av_clip(roundf(0.5f * new_ewi * (uf + 1.f)), 0, new_ewi - 1);
+                new_vi = av_clip(roundf(0.5f *     ehi * (vf + 1.f)), 0,     ehi - 1);
+            }
+
 
-            us[i + 1][j + 1] = u_shift + av_clip(roundf(0.5f * new_ewi * (u + 1.f)), 0, new_ewi - 1);
-            vs[i + 1][j + 1] =           av_clip(roundf(0.5f * eh      * (v + 1.f)), 0, eh      - 1);
+            us[i + 1][j + 1] = u_shift + new_ui;
+            vs[i + 1][j + 1] =           new_vi;
         }
     }
 }