[4/6] mov: Parse uuid box and detect spherical videos

Message ID 1459887547-85253-4-git-send-email-vittorio.giovara@gmail.com
State Not Applicable
Headers show

Commit Message

Vittorio Giovara April 5, 2016, 8:19 p.m.
---
Note: I am not affiliated with the specification draft in any way.
https://github.com/google/spatial-media/blob/master/docs/spherical-video-rfc.md

Also matroska could have the same metadata but the demuxer reads tags *after*
reading the header, and that makes adding stream side data from metadata
quite difficult (if not extremely ugly).

Vittorio

 libavformat/isom.h |  3 +++
 libavformat/mov.c  | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)

Comments

Luca Barbato April 5, 2016, 10 p.m. | #1
On 05/04/16 22:19, Vittorio Giovara wrote:
> ---
> Note: I am not affiliated with the specification draft in any way.
> https://github.com/google/spatial-media/blob/master/docs/spherical-video-rfc.md
> 
> Also matroska could have the same metadata but the demuxer reads tags *after*
> reading the header, and that makes adding stream side data from metadata
> quite difficult (if not extremely ugly).
> 
> Vittorio
> 
>  libavformat/isom.h |  3 +++
>  libavformat/mov.c  | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 75 insertions(+)
> 
> diff --git a/libavformat/isom.h b/libavformat/isom.h
> index aec623b..78bfb87 100644
> --- a/libavformat/isom.h
> +++ b/libavformat/isom.h
> @@ -24,6 +24,8 @@
>  #ifndef AVFORMAT_ISOM_H
>  #define AVFORMAT_ISOM_H
>  
> +#include "libavutil/stereo3d.h"
> +
>  #include "avio.h"
>  #include "internal.h"
>  #include "dv.h"
> @@ -138,6 +140,7 @@ typedef struct MOVStreamContext {
>      MOVSbgp *rap_group;
>  
>      int32_t *display_matrix;
> +    AVStereo3D *stereo_mode;
>  } MOVStreamContext;
>  
>  typedef struct MOVContext {
> diff --git a/libavformat/mov.c b/libavformat/mov.c
> index 9d271f8..2045b98 100644
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -36,6 +36,7 @@
>  #include "libavutil/avstring.h"
>  #include "libavutil/dict.h"
>  #include "libavutil/opt.h"
> +#include "libavutil/stereo3d.h"
>  #include "libavcodec/ac3tab.h"
>  #include "avformat.h"
>  #include "internal.h"
> @@ -3082,6 +3083,58 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
>      return 0;
>  }
>  
> +static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
> +{
> +    AVStream *st;
> +    MOVStreamContext *sc;
> +    int ret, size = atom.size - 16;
> +
> +    if (c->fc->nb_streams < 1)
> +        return 0;
> +    st = c->fc->streams[c->fc->nb_streams - 1];
> +    sc = st->priv_data;
> +
> +    if (avio_rb64(pb) == 0xffcc8263f8554a93 && avio_rb64(pb) == 0x8814587a02521fdd) {

those magic numbers might enjoy being constants.

The rest is not exactly wonderful but I assume nobody sane will add
spaces just because he could. (and addressing those issues can be done
on a later time)

lu
Tim Walker April 6, 2016, 3 a.m. | #2
On Wed, Apr 6, 2016 at 12:00 AM, Luca Barbato <lu_zero@gentoo.org> wrote:

> those magic numbers might enjoy being constants.
>

Yes please.

Tim

Patch

diff --git a/libavformat/isom.h b/libavformat/isom.h
index aec623b..78bfb87 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -24,6 +24,8 @@ 
 #ifndef AVFORMAT_ISOM_H
 #define AVFORMAT_ISOM_H
 
+#include "libavutil/stereo3d.h"
+
 #include "avio.h"
 #include "internal.h"
 #include "dv.h"
@@ -138,6 +140,7 @@  typedef struct MOVStreamContext {
     MOVSbgp *rap_group;
 
     int32_t *display_matrix;
+    AVStereo3D *stereo_mode;
 } MOVStreamContext;
 
 typedef struct MOVContext {
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 9d271f8..2045b98 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -36,6 +36,7 @@ 
 #include "libavutil/avstring.h"
 #include "libavutil/dict.h"
 #include "libavutil/opt.h"
+#include "libavutil/stereo3d.h"
 #include "libavcodec/ac3tab.h"
 #include "avformat.h"
 #include "internal.h"
@@ -3082,6 +3083,58 @@  static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     return 0;
 }
 
+static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+    AVStream *st;
+    MOVStreamContext *sc;
+    int ret, size = atom.size - 16;
+
+    if (c->fc->nb_streams < 1)
+        return 0;
+    st = c->fc->streams[c->fc->nb_streams - 1];
+    sc = st->priv_data;
+
+    if (avio_rb64(pb) == 0xffcc8263f8554a93 && avio_rb64(pb) == 0x8814587a02521fdd) {
+        char *spherical_xml = av_malloc(size + 1);
+        if (!spherical_xml)
+            return AVERROR(ENOMEM);
+        spherical_xml[size] = '\0';
+
+        ret = ffio_read_size(pb, spherical_xml, size);
+        if (ret < 0) {
+            av_free(spherical_xml);
+            return ret;
+        }
+
+        /* Mandatory tags (StitchingSoftware ignored) */
+        if (strcasestr(spherical_xml, "<GSpherical:Spherical>true</GSpherical:Spherical>") &&
+            strcasestr(spherical_xml, "<GSpherical:Stitched>true</GSpherical:Stitched>") &&
+            strcasestr(spherical_xml, "<GSpherical:ProjectionType>equirectangular</GSpherical:ProjectionType>")) {
+            sc->stereo_mode = av_stereo3d_alloc();
+            if (!sc->stereo_mode) {
+                av_free(spherical_xml);
+                return AVERROR(ENOMEM);
+            }
+
+            if (strcasestr(spherical_xml, "<GSpherical:StereoMode>left-right</GSpherical:StereoMode>"))
+                sc->stereo_mode->type = AV_STEREO3D_SIDEBYSIDE;
+            else if (strcasestr(spherical_xml, "<GSpherical:StereoMode>top-bottom</GSpherical:StereoMode>"))
+                sc->stereo_mode->type = AV_STEREO3D_TOPBOTTOM;
+            else /* Default */
+                sc->stereo_mode->type = AV_STEREO3D_2D;
+
+            sc->stereo_mode->flags = AV_STEREO3D_FLAG_SPHERICAL;
+        } else {
+            av_log(c->fc, AV_LOG_WARNING, "Invalid spherical metadata found\n");
+        }
+        av_free(spherical_xml);
+    } else {
+        av_log(c->fc, AV_LOG_DEBUG, "Unknown UUID found\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 },
@@ -3143,6 +3196,7 @@  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('u','u','i','d'), mov_read_uuid },
 { MKTAG('-','-','-','-'), mov_read_custom },
 { 0, NULL }
 };
@@ -3366,6 +3420,7 @@  static int mov_read_close(AVFormatContext *s)
         av_freep(&sc->stps_data);
         av_freep(&sc->rap_group);
         av_freep(&sc->display_matrix);
+        av_freep(&sc->stereo_mode);
     }
 
     if (mov->dv_demux) {
@@ -3464,6 +3519,23 @@  static int mov_read_header(AVFormatContext *s)
                 sd->data = (uint8_t*)sc->display_matrix;
                 sc->display_matrix = NULL;
             }
+            if (sc->stereo_mode) {
+                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->stereo_mode);
+                sd->data = (uint8_t *)sc->stereo_mode;
+                sc->stereo_mode = NULL;
+            }
             break;
         }
     }