avfilter/vf_v360: add padding option for cubemap

Signed-off-by: Eugene Lyapustin <unishifft@gmail.com>
This commit is contained in:
Eugene Lyapustin 2019-08-15 03:56:12 +03:00 committed by Kieran Kunhya
parent b26094e217
commit d044252aac
2 changed files with 92 additions and 24 deletions

View 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:

View 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;
if (new_ui >= 0 && new_ui < ewi && new_vi >= 0 && new_vi < ehi) {
face = s->in_cubemap_face_order[direction];
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);
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];
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);
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 + new_ui;
vs[i + 1][j + 1] = new_vi;
}
}
}