# Transform360 projects 360 video from equirectangular to cubemap inside ffmpeg

> Transform360 is a C++ library that Facebook exposes as an ffmpeg video filter for converting 360 video between projections, usually equirectangular input to cubemap output. The transform logic is kept out of ffmpeg, but the deployment unit is a patched ffmpeg build, which is the real cost of adopting it.

**facebook/transform360** — Transform360 is an equirectangular to cubemap transform for 360 video.

- Repository: https://github.com/facebook/transform360
- Stars: 1,035 · Forks: 241
- Language: C++
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/facebook-transform360

## A projection transform for 360 video

Transform360 is described as a video and image filter that transforms a 360 video from one projection to another. Usually the input projection is equirectangular and the output is cubemap, which is the conversion that a video platform or a headset pipeline needs when a single spherical image has to become a set of cube faces.

The project lives in the Facebook organisation, and the code is C++ invoked by an ffmpeg video filter. The previous version of the transform, called Transform_V1, is kept in the repository alongside the current one, which tells you something about the project's history: this is an evolution of an existing filter rather than a new tool.

The audience is a video engineer who already works with ffmpeg and needs 360 handling with more control than a generic filter provides. The typical use is a pipeline that takes an uploaded equirectangular master and produces a cubemap deliverable, and the person running it cares about output quality, about how much memory the transform consumes on a large frame, and about whether the conversion is fast enough for a batch job.

The repository itself is small. The top level holds the README, the LICENSE, a code of conduct, a contributing guide and the Transform360 directory with the library. There is no example gallery, no documentation site and no published package, which is a fair description of a component that is expected to be compiled into a larger tool rather than consumed on its own.

## The three advantages the project claims

The documentation lists three advantages, and they are worth reading as design goals rather than as marketing.

The first is efficiency across the board: Transform360 achieves better performance in memory usage and visual quality, and for many different algorithm and parameter settings in real world applications it also achieves better processing speed. That is a claim about the whole envelope rather than about one metric, and the claim is scoped to real world applications with varying parameters, which is where a transform usually falls down.

The second is control over output quality, and it is the most interesting of the three because it extends past the frame. Control over the quality of the output video frames is the normal expectation; control over the quality of different regions within a frame is not. That matters in 360 specifically, because a single equirectangular frame contains regions with very different content, and the seam areas and the poles are usually the ones that reveal the artefacts of a resampling filter. A transform that can be tuned per region can be made to look right where it matters instead of being optimised on average.

The third is architectural: Transform360 separates the computation and transform logic from ffmpeg. The stated consequence is that people have much more flexibility to use different resources to develop the transforms, and do not need to be concerned with the details of the ffmpeg implementation and integration. In practice this is what lets the same code exist as a standalone library and as an ffmpeg filter, and it is why the build produces a library that ffmpeg then links against.

The practical way to see advantage two and three in the options is in the filter's parameter list, which is where segment granularity and interpolation choices appear.

## The deployment unit is a patched ffmpeg

The build instructions are the part of this project that decide whether it suits you, so they are worth reading closely before anything else.

Transform360 is implemented in C++ and is invoked by an ffmpeg video filter. To use it you check out the transform360 repository, check out the ffmpeg source, install ffmpeg along with development versions of OpenCV and the codec libraries you need, then build and install transform360 in the Transform360 folder. After that you copy vf_transform360.c into the libavfilter subdirectory of the ffmpeg source, register the filter in the video filter registration section, add the object to the filter section of libavfilter/Makefile, edit the include paths in the copied file, configure ffmpeg, and build it.

Registration is a two line edit, and the form depends on your ffmpeg version:

```c
extern AVFilter ff_vf_transform360;
```

For older ffmpeg versions, where existing filters are registered with REGISTER_FILTER, the alternative is:

```c
REGISTER_FILTER(TRANSFORM360, transform360, vf);
```

The Makefile addition follows the same pattern:

```makefile
OBJS-$(CONFIG_TRANSFORM360_FILTER) += vf_transform360.o
```

And the include paths in the copied file are changed from the lower case paths to the paths where the library actually installs:

```c
#include "Transform360/Library/VideoFrameTransformHandler.h"
#include "Transform360/Library/VideoFrameTransformHelper.h"
```

That is the whole integration story. There is no plugin directory to drop a shared object into, no separate binary to run, and no upstream ffmpeg package that ships the filter. The result is that adopting Transform360 means owning an ffmpeg build, carrying patches against libavfilter, and rebuilding when you move to a new ffmpeg version. For a team that already builds ffmpeg from source, that is routine. For anyone who installs ffmpeg from a package, it is the entire project.

## Building the library and configuring ffmpeg against it

The dependency step installs ffmpeg, the OpenCV development package and the codec libraries:

```bash
sudo apt-get install ffmpeg
sudo apt-get install libopencv-dev
sudo apt-get install nasm libxvidcore-dev libass-dev libfdk-aac-dev libvpx-dev libx264-dev
```

The library itself is a standard CMake project, built and installed from the Transform360 folder:

```bash
cmake ./
make
sudo make install
```

The ffmpeg configure step is where the linkage happens, and the prefix keeps the custom build separate from any system ffmpeg, which is the detail that makes this workable on a workstation:

```bash
./configure --prefix=/usr/local/transform/ffmpeg --enable-gpl --enable-nonfree --enable-libass --enable-libfdk-aac --enable-libfreetype --enable-libvpx --enable-libx264 --enable-libxvid --enable-libopencv --extra-libs='-lTransform360 -lstdc++'
```

The extra libs line is the important one. It adds the Transform360 library and the C++ standard library to the link, which is what makes the filter resolvable at link time. The prefix means the resulting ffmpeg binary lives in its own directory, and the instructions then tell you to use the local binary with ./ffmpeg or install it with make install.

Note the flags. Building ffmpeg with --enable-gpl and --enable-nonfree and with libfdk-aac means the resulting binary is not redistributable in the way a stock ffmpeg build is, and that is a legal and distribution question for anyone shipping the tool rather than running it on their own machines. The --enable-nonfree and libfdk-aac combination in particular is a known constraint on redistribution, independent of this project.

Once the build is done, the filter's options are discovered the usual way, by running ffmpeg -h filter=transform360, and the documentation calls that the way to check the options for the filter.

## Running the filter, and the parameters that control quality

A typical invocation looks like this, and the parameter list is where the claimed control over output and per region quality becomes concrete:

```sh
ffmpeg -i input.mp4
    -vf transform360="input_stereo_format=MONO
    :cube_edge_length=512
    :interpolation_alg=cubic
    :enable_low_pass_filter=1
    :enable_multi_threading=1
    :num_horizontal_segments=32
    :num_vertical_segments=15
    :adjust_kernel=1"
    output.mp4
```

Reading the parameters tells you what the transform exposes. input_stereo_format declares whether the source is monoscopic or stereoscopic. cube_edge_length sets the edge length of the cube faces, which is the resolution knob of the whole pipeline, since a cubemap of edge length 512 produces 512 by 512 faces. interpolation_alg selects the resampling algorithm, with cubic as one choice. enable_low_pass_filter turns on the smoothing that suppresses aliasing introduced by the resampling, at the cost of softness. enable_multi_threading uses more than one core.

The two segment parameters, num_horizontal_segments and num_vertical_segments, are the ones that correspond to the per region quality claim. They set how finely the frame is subdivided, so the kernel and the low pass filter can be applied differently across the frame instead of uniformly. adjust_kernel is the switch that enables the adjusted kernel behaviour.

The full list is longer than this example, and ffmpeg -h filter=transform360 is the authoritative reference for a given build, since the option set is tied to the library version you compiled in.

One practical note for anyone building a pipeline: the option syntax uses colons to separate key and value inside a single quoted argument, which is the ffmpeg filter convention. That is why the example is split across lines, since the line breaks are inside the quoted string and the whole thing stays one argument.

## Transform_V1 stays for comparison and for older pipelines

The previous transform is not history that was deleted. Transform_V1 is kept in the file vf_transform_v1.c and has its own build and run instructions, which makes it useful in two ways.

The first is comparison. When you are evaluating whether the new transform is better for your content, having the old one available as a separate filter in the same ffmpeg build is exactly the A/B you need, and the project explicitly claims better visual quality and speed for Transform360 across many algorithm and parameter settings.

The second is continuity. The build steps for Transform_V1 are shorter, because it is a single file filter rather than a library with headers to rewire. You check out the ffmpeg source, copy vf_transform_v1.c into the libavfilter subdirectory, register the filter with the extern AVFilter ff_vf_transform_v1 line or the REGISTER_FILTER(TRANSFORM_V1, transform_v1, vf); form for older versions, add OBJS-$(CONFIG_TRANSFORM_V1_FILTER) += vf_transform_v1.o to the filter section of libavfilter/Makefile, and configure and build ffmpeg as usual.

Its parameter set is smaller and differently named, which is itself informative about the redesign:

```sh
ffmpeg -i input.mp4
    -vf transform_v1="input_stereo_format=MONO
    :w_subdivisions=4
    :h_subdivisions=4
    :max_cube_edge_length=512"
    output.mp4
```

The old filter uses w_subdivisions and h_subdivisions with a max_cube_edge_length, where the current one uses num_horizontal_segments and num_vertical_segments with a cube_edge_length, and the current one adds interpolation algorithm selection, the low pass filter switch, multithreading and the kernel adjustment. A pipeline written against V1 is not a drop in replacement for Transform360, and the parameter rename is the clearest marker of the change.

## Licence, maintenance and the cost of the ffmpeg fork

The licence needs one sentence of care. The project documentation states that Transform360 and Transform_V1 are BSD licensed, as found in the LICENSE file, while the licence field on the GitHub page is listed as a custom licence that GitHub cannot classify. The repository does contain a LICENSE file, so read it, and treat the badge and the file as the sources rather than the metadata field.

The maintenance picture is modest. The repository is not archived, and the last push was on 2026-05-08, with no GitHub releases published, so there is no tagged version to pin and no changelog to read beyond the repository history. There is a contributing guide and a code of conduct, which is the extent of the project governance.

The bigger issue is not the cadence but the integration shape. Because the filter must be compiled into ffmpeg, every consumer needs a patched ffmpeg source tree, and every ffmpeg upgrade means reapplying the registration, the Makefile entry and the include path change, then rebuilding. A team that upgrades ffmpeg regularly should expect to maintain that patch, and the project offers no upstream pull request path for it, since the filter is not part of ffmpeg itself.

Against that, the returns are specific. If you need to tune quality per region of an equirectangular frame, or you want the transform logic decoupled from ffmpeg so you can develop it independently, this design delivers that. If you simply want to convert a 360 video, then the practical question is whether your distribution ffmpeg already has a cubemap filter that is good enough, because the cost of getting one you can tune is a custom build of the entire tool.

## Conclusion

Transform360 suits a team that already builds ffmpeg from source, or that needs per region quality control when converting 360 video for a headset pipeline, since the transform exposes segment counts, interpolation choice and kernel adjustments. It is the wrong choice if you need a drop-in ffmpeg you can install from a package manager, because the filter has to be compiled into a custom ffmpeg, and a poor match if you want a standalone converter, since the tool ships no command of its own. Before adopting, check the option list for your ffmpeg build with ffmpeg -h filter=transform360, confirm your ffmpeg source tree is one you can carry patches in, and read the LICENSE file directly, since the README describes a BSD licence while the repository licence field is listed as unclassified.

## FAQ

### What does Transform360 do and how is it used?

It transforms a 360 video or image from one projection to another, usually equirectangular input to cubemap output, and it is invoked as an ffmpeg video filter called transform360. You can list its options with ffmpeg -h filter=transform360.

### Do I have to build ffmpeg from source to use Transform360?

Yes. The filter is not shipped as a standalone binary or plugin; you copy vf_transform360.c into the libavfilter subdirectory of the ffmpeg source, register the filter, add the object to libavfilter/Makefile, adjust the include paths, and configure ffmpeg with --extra-libs pointing at the Transform360 library.

### Which parameters control the output quality of the transform?

cube_edge_length sets the face resolution, interpolation_alg selects the resampling algorithm, enable_low_pass_filter switches on the smoothing that reduces aliasing, num_horizontal_segments and num_vertical_segments control how finely the frame is subdivided, and adjust_kernel enables the adjusted kernel behaviour.

### What is the difference between Transform360 and Transform_V1?

Transform_V1 is the previous version of the filter, kept in vf_transform_v1.c with its own build instructions. It uses w_subdivisions, h_subdivisions and max_cube_edge_length, while Transform360 uses segment counts and cube_edge_length and adds interpolation selection, a low pass filter switch, multithreading and kernel adjustment, and separates the transform logic from ffmpeg.

## Sources

- [facebook/transform360 on GitHub](https://github.com/facebook/transform360)
- [Issues](https://github.com/facebook/transform360/issues)
- [README](https://github.com/facebook/transform360/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/facebook-transform360
