|
|
|
@@ -42,6 +42,8 @@ |
|
|
|
#include "libavutil/aes.h" |
|
|
|
#include "libavutil/aes_ctr.h" |
|
|
|
#include "libavutil/sha.h" |
|
|
|
#include "libavutil/spherical.h" |
|
|
|
#include "libavutil/stereo3d.h" |
|
|
|
#include "libavutil/timecode.h" |
|
|
|
#include "libavcodec/ac3tab.h" |
|
|
|
#include "libavcodec/flac.h" |
|
|
|
@@ -4498,8 +4500,204 @@ static int mov_read_tmcd(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 < 5) { |
|
|
|
av_log(c->fc, AV_LOG_ERROR, "Empty stereoscopic video box\n"); |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
avio_skip(pb, 4); /* version + flags */ |
|
|
|
|
|
|
|
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 AVSphericalProjection projection; |
|
|
|
|
|
|
|
if (c->fc->nb_streams < 1) |
|
|
|
return 0; |
|
|
|
|
|
|
|
st = c->fc->streams[c->fc->nb_streams - 1]; |
|
|
|
sc = st->priv_data; |
|
|
|
|
|
|
|
if (atom.size < 8) { |
|
|
|
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, 4); /* version + flags */ |
|
|
|
avio_skip(pb, avio_r8(pb)); /* 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; |
|
|
|
} |
|
|
|
avio_skip(pb, 4); /* version + flags */ |
|
|
|
|
|
|
|
/* 16.16 fixed point */ |
|
|
|
yaw = avio_rb32(pb); |
|
|
|
pitch = avio_rb32(pb); |
|
|
|
roll = avio_rb32(pb); |
|
|
|
|
|
|
|
size = avio_rb32(pb); |
|
|
|
if (size > atom.size) |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
tag = avio_rl32(pb); |
|
|
|
avio_skip(pb, 4); /* version + flags */ |
|
|
|
switch (tag) { |
|
|
|
case MKTAG('c','b','m','p'): |
|
|
|
projection = AV_SPHERICAL_CUBEMAP; |
|
|
|
break; |
|
|
|
case MKTAG('e','q','u','i'): |
|
|
|
projection = AV_SPHERICAL_EQUIRECTANGULAR; |
|
|
|
break; |
|
|
|
default: |
|
|
|
av_log(c->fc, AV_LOG_ERROR, "Unknown projection type\n"); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
sc->spherical = av_spherical_alloc(&sc->spherical_size); |
|
|
|
if (!sc->spherical) |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
sc->spherical->projection = projection; |
|
|
|
|
|
|
|
sc->spherical->yaw = yaw; |
|
|
|
sc->spherical->pitch = pitch; |
|
|
|
sc->spherical->roll = roll; |
|
|
|
|
|
|
|
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(&sc->spherical_size); |
|
|
|
if (!sc->spherical) |
|
|
|
goto out; |
|
|
|
|
|
|
|
sc->spherical->projection = AV_SPHERICAL_EQUIRECTANGULAR; |
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
|
|
|
|
/* orientation */ |
|
|
|
val = av_stristr(buffer, "<GSpherical:InitialViewHeadingDegrees>"); |
|
|
|
if (val) |
|
|
|
sc->spherical->yaw = strtol(val, NULL, 10) * (1 << 16); |
|
|
|
val = av_stristr(buffer, "<GSpherical:InitialViewPitchDegrees>"); |
|
|
|
if (val) |
|
|
|
sc->spherical->pitch = strtol(val, NULL, 10) * (1 << 16); |
|
|
|
val = av_stristr(buffer, "<GSpherical:InitialViewRollDegrees>"); |
|
|
|
if (val) |
|
|
|
sc->spherical->roll = strtol(val, NULL, 10) * (1 << 16); |
|
|
|
} |
|
|
|
|
|
|
|
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_isml_manifest[] = { |
|
|
|
@@ -4510,10 +4708,19 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom) |
|
|
|
0xbe, 0x7a, 0xcf, 0xcb, 0x97, 0xa9, 0x42, 0xe8, |
|
|
|
0x9c, 0x71, 0x99, 0x94, 0x91, 0xe3, 0xaf, 0xac |
|
|
|
}; |
|
|
|
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 = avio_read(pb, uuid, sizeof(uuid)); |
|
|
|
if (ret < 0) { |
|
|
|
return ret; |
|
|
|
@@ -4585,7 +4792,14 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom) |
|
|
|
av_dict_set(&c->fc->metadata, "xmp", buffer, 0); |
|
|
|
} |
|
|
|
av_free(buffer); |
|
|
|
} |
|
|
|
} else if (!memcmp(uuid, uuid_spherical, sizeof(uuid))) { |
|
|
|
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"); } |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
@@ -4973,6 +5187,8 @@ static const MOVParseTableEntry mov_default_parse_table[] = { |
|
|
|
{ MKTAG('s','e','n','c'), mov_read_senc }, |
|
|
|
{ MKTAG('s','a','i','z'), mov_read_saiz }, |
|
|
|
{ MKTAG('d','f','L','a'), mov_read_dfla }, |
|
|
|
{ MKTAG('s','t','3','d'), mov_read_st3d }, /* stereoscopic 3D video box */ |
|
|
|
{ MKTAG('s','v','3','d'), mov_read_sv3d }, /* spherical video box */ |
|
|
|
{ 0, NULL } |
|
|
|
}; |
|
|
|
|
|
|
|
@@ -5393,6 +5609,9 @@ static int mov_read_close(AVFormatContext *s) |
|
|
|
av_freep(&sc->cenc.auxiliary_info); |
|
|
|
av_freep(&sc->cenc.auxiliary_info_sizes); |
|
|
|
av_aes_ctr_free(sc->cenc.aes_ctr); |
|
|
|
|
|
|
|
av_freep(&sc->stereo3d); |
|
|
|
av_freep(&sc->spherical); |
|
|
|
} |
|
|
|
|
|
|
|
if (mov->dv_demux) { |
|
|
|
@@ -5711,6 +5930,24 @@ static int mov_read_header(AVFormatContext *s) |
|
|
|
|
|
|
|
sc->display_matrix = NULL; |
|
|
|
} |
|
|
|
if (sc->stereo3d) { |
|
|
|
err = av_stream_add_side_data(st, AV_PKT_DATA_STEREO3D, |
|
|
|
(uint8_t *)sc->stereo3d, |
|
|
|
sizeof(*sc->stereo3d)); |
|
|
|
if (err < 0) |
|
|
|
return err; |
|
|
|
|
|
|
|
sc->stereo3d = NULL; |
|
|
|
} |
|
|
|
if (sc->spherical) { |
|
|
|
err = av_stream_add_side_data(st, AV_PKT_DATA_SPHERICAL, |
|
|
|
(uint8_t *)sc->spherical, |
|
|
|
sc->spherical_size); |
|
|
|
if (err < 0) |
|
|
|
return err; |
|
|
|
|
|
|
|
sc->spherical = NULL; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|