Signed-off-by: Vittorio Giovara <vittorio.giov...@gmail.com>
---
 libavformat/isom.h |   4 +
 libavformat/mov.c  | 277 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 281 insertions(+)

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 58f0a20..2e22575 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -28,6 +28,8 @@
 #include "internal.h"
 #include "dv.h"
 
+#include "libavutil/stereo3d.h"
+
 /* isom.c */
 extern const AVCodecTag ff_mp4_obj_type[];
 extern const AVCodecTag ff_codec_movvideo_tags[];
@@ -145,6 +147,8 @@ typedef struct MOVStreamContext {
     int stsd_count;
 
     int32_t *display_matrix;
+    AVSphericalVideo *spherical;
+    AVStereo3D *stereo3d;
 } MOVStreamContext;
 
 typedef struct MOVContext {
diff --git a/libavformat/mov.c b/libavformat/mov.c
index fb2b7d6..d1f336b 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -37,6 +37,7 @@
 #include "libavutil/dict.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
+#include "libavutil/stereo3d.h"
 #include "libavcodec/ac3tab.h"
 #include "avformat.h"
 #include "internal.h"
@@ -3154,6 +3155,242 @@ static int mov_read_elst(MOVContext *c, AVIOContext 
*pb, MOVAtom atom)
     return 0;
 }
 
+static int mov_read_st3d(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+    AVStream *st;
+    MOVStreamContext *sc;
+    enum AVStereo3DType type;
+    int mode;
+
+    if (c->fc->nb_streams < 1)
+        return 0;
+
+    st = c->fc->streams[c->fc->nb_streams - 1];
+    sc = st->priv_data;
+
+    if (atom.size < 1) {
+        av_log(c->fc, AV_LOG_ERROR, "Empty stereoscopic video box\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    mode = avio_r8(pb);
+    switch(mode) {
+    case 0:
+        type = AV_STEREO3D_2D;
+        break;
+    case 1:
+        type = AV_STEREO3D_TOPBOTTOM;
+        break;
+    case 2:
+        type = AV_STEREO3D_SIDEBYSIDE;
+        break;
+    default:
+        av_log(c->fc, AV_LOG_WARNING, "Unknown st3d mode value %d\n", mode);
+        return 0;
+    }
+
+    sc->stereo3d = av_stereo3d_alloc();
+    if (!sc->stereo3d)
+        return AVERROR(ENOMEM);
+
+    sc->stereo3d->type = type;
+    return 0;
+}
+
+static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+    AVStream *st;
+    MOVStreamContext *sc;
+    int size;
+    int32_t yaw, pitch, roll;
+    uint32_t tag;
+    enum AVSphericalType type;
+
+    if (c->fc->nb_streams < 1)
+        return 0;
+
+    st = c->fc->streams[c->fc->nb_streams - 1];
+    sc = st->priv_data;
+
+    if (atom.size < 4) {
+        av_log(c->fc, AV_LOG_ERROR, "Empty spherical video box\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    size = avio_rb32(pb);
+    if (size > atom.size)
+        return AVERROR_INVALIDDATA;
+
+    tag = avio_rl32(pb);
+    if (tag != MKTAG('s','v','h','d')) {
+        av_log(c->fc, AV_LOG_ERROR, "Missing spherical video header\n");
+        return 0;
+    }
+    avio_skip(pb, size - 8); /* metadata_source */
+
+    size = avio_rb32(pb);
+    if (size > atom.size)
+        return AVERROR_INVALIDDATA;
+
+    tag = avio_rl32(pb);
+    if (tag != MKTAG('p','r','o','j')) {
+        av_log(c->fc, AV_LOG_ERROR, "Missing projection box\n");
+        return 0;
+    }
+
+    size = avio_rb32(pb);
+    if (size > atom.size)
+        return AVERROR_INVALIDDATA;
+
+    tag = avio_rl32(pb);
+    if (tag != MKTAG('p','r','h','d')) {
+        av_log(c->fc, AV_LOG_ERROR, "Missing projection header box\n");
+        return 0;
+    }
+
+    /* 16.16 fixed point */
+    yaw   = avio_rb32(pb);
+    pitch = avio_rb32(pb);
+    roll  = avio_rb32(pb);
+
+    avio_skip(pb, size - 20);
+
+    size = avio_rb32(pb);
+    if (size > atom.size)
+        return AVERROR_INVALIDDATA;
+
+    tag = avio_rl32(pb);
+    switch(tag) {
+    case MKTAG('c','b','m','p'):
+        type = AV_SPHERICAL_CUBEMAP;
+        break;
+    case MKTAG('e','q','u','i'):
+        type = AV_SPHERICAL_EQUIRECTANGULAR;
+        break;
+    case MKTAG('m','s','h','p'):
+        type = AV_SPHERICAL_MESH;
+        break;
+    default:
+        av_log(c->fc, AV_LOG_ERROR, "Unknown projection type\n");
+        return 0;
+    }
+
+    sc->spherical = av_spherical_alloc(NULL);
+    if (!sc->spherical)
+        return AVERROR(ENOMEM);
+
+    sc->spherical->type = type;
+
+    sc->spherical->yaw   = ((double) yaw)   / (1 << 16);
+    sc->spherical->pitch = ((double) pitch) / (1 << 16);
+    sc->spherical->roll  = ((double) roll)  / (1 << 16);
+
+    return 0;
+}
+
+static int mov_parse_uuid_spherical(MOVStreamContext *sc, AVIOContext *pb, 
size_t len)
+{
+    int ret = 0;
+    uint8_t *buffer = av_malloc(len + 1);
+    const char *val;
+
+    if (!buffer)
+        return AVERROR(ENOMEM);
+    buffer[len] = '\0';
+
+    ret = ffio_read_size(pb, buffer, len);
+    if (ret < 0)
+        goto out;
+
+    /* Check for mandatory keys and values, try to support XML as best-effort 
*/
+    if (av_stristr(buffer, "<GSpherical:StitchingSoftware>") &&
+        (val = av_stristr(buffer, "<GSpherical:Spherical>")) &&
+        av_stristr(val, "true") &&
+        (val = av_stristr(buffer, "<GSpherical:Stitched>")) &&
+        av_stristr(val, "true") &&
+        (val = av_stristr(buffer, "<GSpherical:ProjectionType>")) &&
+        av_stristr(val, "equirectangular")) {
+        sc->spherical = av_spherical_alloc(NULL);
+        if (!sc->spherical)
+            goto out;
+
+        sc->spherical->type = AV_SPHERICAL_EQUIRECTANGULAR;
+
+        val = av_stristr(buffer, "<GSpherical:InitialViewHeadingDegrees>");
+        if (val)
+            sc->spherical->yaw = strtol(val, NULL, 10);
+        val = av_stristr(buffer, "<GSpherical:InitialViewPitchDegrees>");
+        if (val)
+            sc->spherical->pitch = strtol(val, NULL, 10);
+        val = av_stristr(buffer, "<GSpherical:InitialViewRollDegrees>");
+        if (val)
+            sc->spherical->roll = strtol(val, NULL, 10);
+
+        if (av_stristr(buffer, "<GSpherical:StereoMode>")) {
+            enum AVStereo3DType mode;
+
+            if (av_stristr(buffer, "left-right"))
+                mode = AV_STEREO3D_SIDEBYSIDE;
+            else if (av_stristr(buffer, "top-bottom"))
+                mode = AV_STEREO3D_TOPBOTTOM;
+            else
+                mode = AV_STEREO3D_2D;
+
+            sc->stereo3d = av_stereo3d_alloc();
+            if (!sc->stereo3d)
+                goto out;
+
+            sc->stereo3d->type = mode;
+        }
+    }
+
+out:
+    av_free(buffer);
+    return ret;
+}
+
+static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+    AVStream *st;
+    MOVStreamContext *sc;
+    int ret;
+
+    uint8_t uuid[16];
+    static const uint8_t uuid_spherical[] = {
+        0xff, 0xcc, 0x82, 0x63, 0xf8, 0x55, 0x4a, 0x93,
+        0x88, 0x14, 0x58, 0x7a, 0x02, 0x52, 0x1f, 0xdd,
+    };
+
+    if (atom.size < sizeof(uuid) || atom.size == INT64_MAX)
+        return AVERROR_INVALIDDATA;
+
+    if (c->fc->nb_streams < 1)
+        return 0;
+    st = c->fc->streams[c->fc->nb_streams - 1];
+    sc = st->priv_data;
+
+    ret = ffio_read_size(pb, uuid, sizeof(uuid));
+    if (ret < 0)
+        return ret;
+
+    if (!memcmp(uuid, uuid_spherical, sizeof(uuid)) && !sc->spherical) {
+        size_t len = atom.size - sizeof(uuid);
+        ret = mov_parse_uuid_spherical(sc, pb, len);
+        if (ret < 0)
+            return ret;
+        if (!sc->spherical)
+            av_log(c->fc, AV_LOG_WARNING, "Invalid spherical metadata 
found\n");
+    } else {
+        int i;
+        av_log(c->fc, AV_LOG_VERBOSE, "Unknown UUID found: 0x");
+        for (i = 0; i < sizeof(uuid); i++)
+            av_log(c->fc, AV_LOG_WARNING, "%02x", uuid[i]);
+        av_log(c->fc, AV_LOG_WARNING, "\n");
+    }
+
+    return 0;
+}
+
 static const MOVParseTableEntry mov_default_parse_table[] = {
 { MKTAG('a','v','s','s'), mov_read_extradata },
 { MKTAG('c','h','p','l'), mov_read_chpl },
@@ -3215,6 +3452,9 @@ static const MOVParseTableEntry mov_default_parse_table[] 
= {
 { MKTAG('d','v','c','1'), mov_read_dvc1 },
 { MKTAG('s','b','g','p'), mov_read_sbgp },
 { MKTAG('h','v','c','C'), mov_read_glbl },
+{ MKTAG('s','t','3','d'), mov_read_st3d }, /* stereoscopic 3D video box */
+{ MKTAG('s','v','3','d'), mov_read_sv3d }, /* spherical video box */
+{ MKTAG('u','u','i','d'), mov_read_uuid }, /* universal unique identifier */
 { MKTAG('-','-','-','-'), mov_read_custom },
 { 0, NULL }
 };
@@ -3443,6 +3683,9 @@ static int mov_read_close(AVFormatContext *s)
             av_free(sc->extradata[j]);
         av_freep(&sc->extradata);
         av_freep(&sc->extradata_size);
+
+        av_freep(&sc->spherical);
+        av_freep(&sc->stereo3d);
     }
 
     if (mov->dv_demux) {
@@ -3541,6 +3784,40 @@ static int mov_read_header(AVFormatContext *s)
                 sd->data = (uint8_t*)sc->display_matrix;
                 sc->display_matrix = NULL;
             }
+            if (sc->spherical) {
+                AVPacketSideData *sd, *tmp;
+
+                tmp = av_realloc_array(st->side_data,
+                                       st->nb_side_data + 1, sizeof(*tmp));
+                if (!tmp)
+                    return AVERROR(ENOMEM);
+
+                st->side_data = tmp;
+                st->nb_side_data++;
+
+                sd = &st->side_data[st->nb_side_data - 1];
+                sd->type = AV_PKT_DATA_SPHERICAL;
+                sd->size = sizeof(*sc->spherical);
+                sd->data = (uint8_t *)sc->spherical;
+                sc->spherical = NULL;
+            }
+            if (sc->stereo3d) {
+                AVPacketSideData *sd, *tmp;
+
+                tmp = av_realloc_array(st->side_data,
+                                       st->nb_side_data + 1, sizeof(*tmp));
+                if (!tmp)
+                    return AVERROR(ENOMEM);
+
+                st->side_data = tmp;
+                st->nb_side_data++;
+
+                sd = &st->side_data[st->nb_side_data - 1];
+                sd->type = AV_PKT_DATA_STEREO3D;
+                sd->size = sizeof(*sc->stereo3d);
+                sd->data = (uint8_t *)sc->stereo3d;
+                sc->stereo3d = NULL;
+            }
             break;
         }
     }
-- 
2.10.0

_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to