aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandre Sicard <alexandre.sicard@smartjog.com>2013-07-08 11:56:40 +0200
committerMichael Niedermayer <michaelni@gmx.at>2013-07-08 17:36:45 +0200
commit70b922f371e27440a51ee1e9cc1c7db0e042ebd1 (patch)
treefb7aef979a1f2c6a406e612e25176817ae943a25
parente096283ea55bc36a637b47329e19ddb26fb1440b (diff)
downloadffmpeg-70b922f371e27440a51ee1e9cc1c7db0e042ebd1.tar.gz
avformat/mov: read stream bitrates from isml manifest
This allows to read a live isml movie and segment it using the smoothstreaming muxer, which requires the bitrates to be known for each stream. Signed-off-by: Alexandre Sicard <alexandre.sicard@smartjog.com> Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r--libavformat/isom.h2
-rw-r--r--libavformat/mov.c74
2 files changed, 76 insertions, 0 deletions
diff --git a/libavformat/isom.h b/libavformat/isom.h
index 220b2df4e1..b0fa453de6 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -162,6 +162,8 @@ typedef struct MOVContext {
int use_absolute_path;
int ignore_editlist;
int64_t next_root_atom; ///< offset of the next root atom
+ int *bitrates; ///< bitrates read before streams creation
+ int bitrates_count;
} MOVContext;
int ff_mp4_read_descr_len(AVIOContext *pb);
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 9833d7badd..99c396e296 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -2731,6 +2731,72 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
+static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ int ret;
+ uint8_t uuid[16];
+ static const uint8_t uuid_isml_manifest[] = {
+ 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
+ 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
+ };
+
+ if (atom.size < sizeof(uuid) || atom.size == INT64_MAX)
+ return AVERROR_INVALIDDATA;
+
+ ret = avio_read(pb, uuid, sizeof(uuid));
+ if (ret < 0) {
+ return ret;
+ } else if (ret != sizeof(uuid)) {
+ return AVERROR_INVALIDDATA;
+ }
+ if (!memcmp(uuid, uuid_isml_manifest, sizeof(uuid))) {
+ uint8_t *buffer, *ptr;
+ char *endptr;
+ size_t len = atom.size - sizeof(uuid);
+
+ if (len < 4) {
+ return AVERROR_INVALIDDATA;
+ }
+ ret = avio_skip(pb, 4); // zeroes
+ len -= 4;
+
+ buffer = av_mallocz(len + 1);
+ if (!buffer) {
+ return AVERROR(ENOMEM);
+ }
+ ret = avio_read(pb, buffer, len);
+ if (ret < 0) {
+ av_free(buffer);
+ return ret;
+ } else if (ret != len) {
+ av_free(buffer);
+ return AVERROR_INVALIDDATA;
+ }
+
+ ptr = buffer;
+ while ((ptr = av_stristr(ptr, "systemBitrate=\"")) != NULL) {
+ ptr += sizeof("systemBitrate=\"") - 1;
+ c->bitrates_count++;
+ c->bitrates = av_realloc_f(c->bitrates, c->bitrates_count, sizeof(*c->bitrates));
+ if (!c->bitrates) {
+ c->bitrates_count = 0;
+ av_free(buffer);
+ return AVERROR(ENOMEM);
+ }
+ errno = 0;
+ ret = strtol(ptr, &endptr, 10);
+ if (ret < 0 || errno || *endptr != '"') {
+ c->bitrates[c->bitrates_count - 1] = 0;
+ } else {
+ c->bitrates[c->bitrates_count - 1] = ret;
+ }
+ }
+
+ av_free(buffer);
+ }
+ return 0;
+}
+
static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('A','C','L','R'), mov_read_avid },
{ MKTAG('A','P','R','G'), mov_read_avid },
@@ -2794,6 +2860,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('c','h','a','n'), mov_read_chan }, /* channel layout */
{ MKTAG('d','v','c','1'), mov_read_dvc1 },
{ MKTAG('s','b','g','p'), mov_read_sbgp },
+{ MKTAG('u','u','i','d'), mov_read_uuid },
{ 0, NULL }
};
@@ -3110,6 +3177,7 @@ static int mov_read_close(AVFormatContext *s)
}
av_freep(&mov->trex_data);
+ av_freep(&mov->bitrates);
return 0;
}
@@ -3222,6 +3290,12 @@ static int mov_read_header(AVFormatContext *s)
}
}
+ for (i = 0; i < mov->bitrates_count && i < s->nb_streams; i++) {
+ if (mov->bitrates[i]) {
+ s->streams[i]->codec->bit_rate = mov->bitrates[i];
+ }
+ }
+
return 0;
}