[FFmpeg-devel] [PATCH][RFC] avutil/spherical: add a flag to signal tiled/padded projections

James Almer jamrial at gmail.com
Wed Mar 29 21:01:24 EEST 2017


A new field is added to AVSphericalMapping for this purpose,
and is used by both Equirectangular and Cubemap projections.
This is a replacement for duplicate projection enums like
AV_SPHERICAL_EQUIRECTANGULAR_TILE, which are therefore
removed.

Signed-off-by: James Almer <jamrial at gmail.com>
---
This patch depends on the av_spherical_projection_name() patchset for
simplicity purposes.

Ok, this is an RFC mainly because of the API/ABI break it represents.
The AV_SPHERICAL_EQUIRECTANGULAR_TILE projection is a month and a half
old and not present in any release, plus a major bump is queued as part
of the merges, so i personally think this change is acceptable as is for
such an niche and recent feature.
If not then i can deprecate said projection enum value instead and keep
the current muxer functionality for it for a while. It will need a lot
of preprocessor guards, though.

The reason for this change is that eventually, a new projection enum
for padded cubemap may be suggested with the same arguments as the ones
used to introduce the one for tiled equirectangular. Then if any new
real projections are added, we'd could end up with duplicate enums for
them as well, when setting a single shared flag would be enough.
Stereo3D avoided a lot of duplicate types with the inverted flag, so i
figured the same should be done here.

Improved doxy and/or flag name is extremely welcome (Read: needed).

 doc/APIchanges                         |  4 ++++
 ffprobe.c                              |  4 +++-
 libavformat/dump.c                     |  6 ++++--
 libavformat/matroskadec.c              | 11 +++++++----
 libavformat/matroskaenc.c              | 10 ++++------
 libavformat/mov.c                      | 10 ++++++----
 libavformat/movenc.c                   |  2 --
 libavutil/spherical.c                  |  2 --
 libavutil/spherical.h                  | 28 ++++++++++++++++------------
 tests/ref/fate/matroska-spherical-mono |  3 ++-
 tests/ref/fate/mov-spherical-mono      |  3 ++-
 11 files changed, 48 insertions(+), 35 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index f600777072..7453e80711 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -16,6 +16,10 @@ libavutil:     2015-08-28
 API changes, most recent first:
 
 2017-xx-xx - xxxxxxx - lavu 55.xx.xxx - spherical.h
+  Add flags field to AVSphericalMapping and AV_SPHERICAL_FLAG_CROPPED flag.
+  Remove AV_SPHERICAL_EQUIRECTANGULAR_TILE AVSphericalProjection.
+
+2017-xx-xx - xxxxxxx - lavu 55.xx.xxx - spherical.h
   Add av_spherical_projection_name()
   
 2017-03-xx - xxxxxxx - lavu 55.52.100 - avutil.h
diff --git a/ffprobe.c b/ffprobe.c
index ad3b77d74d..8e242ed680 100644
--- a/ffprobe.c
+++ b/ffprobe.c
@@ -1874,11 +1874,13 @@ static void print_pkt_side_data(WriterContext *w,
             const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data;
             print_str("projection", av_spherical_projection_name(spherical->projection));
             if (spherical->projection == AV_SPHERICAL_CUBEMAP) {
+                print_int("padded", !!(spherical->flags & AV_SPHERICAL_FLAG_CROPPED));
                 print_int("padding", spherical->padding);
-            } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {
+            } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR) {
                 size_t l, t, r, b;
                 av_spherical_tile_bounds(spherical, par->width, par->height,
                                          &l, &t, &r, &b);
+                print_int("tiled", !!(spherical->flags & AV_SPHERICAL_FLAG_CROPPED));
                 print_int("bound_left", l);
                 print_int("bound_top", t);
                 print_int("bound_right", r);
diff --git a/libavformat/dump.c b/libavformat/dump.c
index e27d1b9422..37b46ae305 100644
--- a/libavformat/dump.c
+++ b/libavformat/dump.c
@@ -356,7 +356,6 @@ static void dump_spherical(void *ctx, AVCodecParameters *par, AVPacketSideData *
     av_log(ctx, AV_LOG_INFO, "%s", av_spherical_projection_name(spherical->projection));
 
     if (spherical->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
-        spherical->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
         spherical->projection != AV_SPHERICAL_CUBEMAP) {
         return;
     }
@@ -366,7 +365,10 @@ static void dump_spherical(void *ctx, AVCodecParameters *par, AVPacketSideData *
     roll = ((double)spherical->roll) / (1 << 16);
     av_log(ctx, AV_LOG_INFO, " (%f/%f/%f) ", yaw, pitch, roll);
 
-    if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {
+    if (!(spherical->flags & AV_SPHERICAL_FLAG_CROPPED))
+        return;
+
+    if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR) {
         size_t l, t, r, b;
         av_spherical_tile_bounds(spherical, par->width, par->height,
                                  &l, &t, &r, &b);
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 2e2a814b4f..9e1b5f8d45 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -1915,7 +1915,7 @@ static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track)
     size_t spherical_size;
     uint32_t l = 0, t = 0, r = 0, b = 0;
     uint32_t padding = 0;
-    int ret;
+    int ret, flags = 0;
     GetByteContext gb;
 
     bytestream2_init(&gb, track->video.projection.private.data,
@@ -1930,6 +1930,7 @@ static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track)
 
     switch (track->video.projection.type) {
     case MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR:
+        projection = AV_SPHERICAL_EQUIRECTANGULAR;
         if (track->video.projection.private.size == 20) {
             t = bytestream2_get_be32(&gb);
             b = bytestream2_get_be32(&gb);
@@ -1949,9 +1950,7 @@ static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track)
         }
 
         if (l || t || r || b)
-            projection = AV_SPHERICAL_EQUIRECTANGULAR_TILE;
-        else
-            projection = AV_SPHERICAL_EQUIRECTANGULAR;
+            flags |= AV_SPHERICAL_FLAG_CROPPED;
         break;
     case MATROSKA_VIDEO_PROJECTION_TYPE_CUBEMAP:
         if (track->video.projection.private.size < 4) {
@@ -1966,6 +1965,9 @@ static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track)
             }
             projection = AV_SPHERICAL_CUBEMAP;
             padding = bytestream2_get_be32(&gb);
+
+            if (padding)
+                flags |= AV_SPHERICAL_FLAG_CROPPED;
         } else {
             av_log(NULL, AV_LOG_ERROR, "Unknown spherical metadata\n");
             return AVERROR_INVALIDDATA;
@@ -1979,6 +1981,7 @@ static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track)
     if (!spherical)
         return AVERROR(ENOMEM);
     spherical->projection = projection;
+    spherical->flags      = flags;
 
     spherical->yaw   = (int32_t)(track->video.projection.yaw   * (1 << 16));
     spherical->pitch = (int32_t)(track->video.projection.pitch * (1 << 16));
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index af941ceb8f..0adbe3b46b 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -936,17 +936,15 @@ static int mkv_write_video_projection(AVFormatContext *s, AVIOContext *pb, AVStr
 
         switch (spherical->projection) {
         case AV_SPHERICAL_EQUIRECTANGULAR:
-            put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE,
-                          MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR);
-            break;
-        case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
         {
             AVIOContext b;
             uint8_t private[20];
-            ffio_init_context(&b, private, sizeof(private),
-                              1, NULL, NULL, NULL, NULL);
             put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE,
                           MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR);
+            if (!(spherical->flags & AV_SPHERICAL_FLAG_CROPPED))
+                break;
+            ffio_init_context(&b, private, sizeof(private),
+                              1, NULL, NULL, NULL, NULL);
             avio_wb32(&b, 0); // version + flags
             avio_wb32(&b, spherical->bound_top);
             avio_wb32(&b, spherical->bound_bottom);
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 127aec1d1d..3bbf3507d1 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -4634,7 +4634,7 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
     AVStream *st;
     MOVStreamContext *sc;
-    int size, layout;
+    int size, layout, flags = 0;
     int32_t yaw, pitch, roll;
     uint32_t l = 0, t = 0, r = 0, b = 0;
     uint32_t tag, padding = 0;
@@ -4705,6 +4705,8 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom)
         }
         projection = AV_SPHERICAL_CUBEMAP;
         padding = avio_rb32(pb);
+        if (padding)
+            flags |= AV_SPHERICAL_FLAG_CROPPED;
         break;
     case MKTAG('e','q','u','i'):
         t = avio_rb32(pb);
@@ -4719,10 +4721,9 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom)
             return AVERROR_INVALIDDATA;
         }
 
+        projection = AV_SPHERICAL_EQUIRECTANGULAR;
         if (l || t || r || b)
-            projection = AV_SPHERICAL_EQUIRECTANGULAR_TILE;
-        else
-            projection = AV_SPHERICAL_EQUIRECTANGULAR;
+            flags |= AV_SPHERICAL_FLAG_CROPPED;
         break;
     default:
         av_log(c->fc, AV_LOG_ERROR, "Unknown projection type\n");
@@ -4734,6 +4735,7 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom)
         return AVERROR(ENOMEM);
 
     sc->spherical->projection = projection;
+    sc->spherical->flags = flags;
 
     sc->spherical->yaw   = yaw;
     sc->spherical->pitch = pitch;
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index a54aa879e9..fd96701d11 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -1640,7 +1640,6 @@ static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMa
     const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
 
     if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
-        spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
         spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
         av_log(pb, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
         return 0;
@@ -1670,7 +1669,6 @@ static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMa
 
     switch (spherical_mapping->projection) {
     case AV_SPHERICAL_EQUIRECTANGULAR:
-    case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
         avio_wb32(pb, 28);    /* size */
         ffio_wfourcc(pb, "equi");
         avio_wb32(pb, 0); /* version = 0 & flags = 0 */
diff --git a/libavutil/spherical.c b/libavutil/spherical.c
index 1d06e7c552..29a386787e 100644
--- a/libavutil/spherical.c
+++ b/libavutil/spherical.c
@@ -54,8 +54,6 @@ void av_spherical_tile_bounds(const AVSphericalMapping *map,
 static const char *spherical_projection_names[] = {
     [AV_SPHERICAL_EQUIRECTANGULAR]      = "equirectangular",
     [AV_SPHERICAL_CUBEMAP]              = "cubemap",
-    [AV_SPHERICAL_EQUIRECTANGULAR_TILE] = "tiled equirectangular",
-
 };
 
 const char *av_spherical_projection_name(enum AVSphericalProjection projection)
diff --git a/libavutil/spherical.h b/libavutil/spherical.h
index 2c8dd3cd97..e628c3621a 100644
--- a/libavutil/spherical.h
+++ b/libavutil/spherical.h
@@ -63,16 +63,14 @@ enum AVSphericalProjection {
      * to the back.
      */
     AV_SPHERICAL_CUBEMAP,
-
-    /**
-     * Video represents a portion of a sphere mapped on a flat surface
-     * using equirectangular projection. The @ref bounding fields indicate
-     * the position of the current video in a larger surface.
-     */
-    AV_SPHERICAL_EQUIRECTANGULAR_TILE,
 };
 
 /**
+ * Projection has padding/cropping
+ */
+#define AV_SPHERICAL_FLAG_CROPPED     (1 << 0)
+
+/**
  * This structure describes how to handle spherical videos, outlining
  * information about projection, initial layout, and any other view modifier.
  *
@@ -160,9 +158,10 @@ typedef struct AVSphericalMapping {
      *     original_height = tile->height + bound_top  + bound_bottom;
      * @endcode
      *
-     * @note These values are valid only for the tiled equirectangular
-     *       projection type (@ref AV_SPHERICAL_EQUIRECTANGULAR_TILE),
-     *       and should be ignored in all other cases.
+     * @note These values are valid only for the equirectangular projection
+     *       type (@ref AV_SPHERICAL_EQUIRECTANGULAR) when the
+     *       (@ref AV_SPHERICAL_FLAG_CROPPED) flag is set, and should be
+     *       ignored in all other cases.
      */
     uint32_t bound_left;   ///< Distance from the left edge
     uint32_t bound_top;    ///< Distance from the top edge
@@ -176,10 +175,15 @@ typedef struct AVSphericalMapping {
      * Number of pixels to pad from the edge of each cube face.
      *
      * @note This value is valid for only for the cubemap projection type
-     *       (@ref AV_SPHERICAL_CUBEMAP), and should be ignored in all other
-     *       cases.
+     *       (@ref AV_SPHERICAL_CUBEMAP) when the (@ref AV_SPHERICAL_FLAG_CROPPED)
+     *       flag is set, and should be ignored in all other cases.
      */
     uint32_t padding;
+
+    /**
+     * Additional information about the projection.
+     */
+    int flags;
 } AVSphericalMapping;
 
 /**
diff --git a/tests/ref/fate/matroska-spherical-mono b/tests/ref/fate/matroska-spherical-mono
index bd57d94514..078c7f5248 100644
--- a/tests/ref/fate/matroska-spherical-mono
+++ b/tests/ref/fate/matroska-spherical-mono
@@ -6,7 +6,8 @@ inverted=0
 [/SIDE_DATA]
 [SIDE_DATA]
 side_data_type=Spherical Mapping
-projection=tiled equirectangular
+projection=equirectangular
+tiled=1
 bound_left=148
 bound_top=73
 bound_right=147
diff --git a/tests/ref/fate/mov-spherical-mono b/tests/ref/fate/mov-spherical-mono
index bd57d94514..078c7f5248 100644
--- a/tests/ref/fate/mov-spherical-mono
+++ b/tests/ref/fate/mov-spherical-mono
@@ -6,7 +6,8 @@ inverted=0
 [/SIDE_DATA]
 [SIDE_DATA]
 side_data_type=Spherical Mapping
-projection=tiled equirectangular
+projection=equirectangular
+tiled=1
 bound_left=148
 bound_top=73
 bound_right=147
-- 
2.12.1



More information about the ffmpeg-devel mailing list