]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - mp4.c
mp4: Simplify parse_sub_atoms().
[paraslash.git] / mp4.c
diff --git a/mp4.c b/mp4.c
index 1d8af6cb20853c33a4aff5d151eb143951bd5a90..d030d62d3e759c81ddfa440a6b47613e87f4d14e 100644 (file)
--- a/mp4.c
+++ b/mp4.c
@@ -145,86 +145,34 @@ static bool atom_compare(int8_t a1, int8_t b1, int8_t c1, int8_t d1,
 
 enum atoms {
        /* atoms with subatoms */
-       ATOM_MOOV = 1,
-       ATOM_TRAK = 2,
-       ATOM_EDTS = 3,
-       ATOM_MDIA = 4,
-       ATOM_MINF = 5,
-       ATOM_STBL = 6,
-       ATOM_UDTA = 7,
-       ATOM_ILST = 8, /* iTunes Metadata list */
-       ATOM_TITLE = 9,
-       ATOM_ARTIST = 10,
-       ATOM_WRITER = 11,
-       ATOM_ALBUM = 12,
-       ATOM_DATE = 13,
-       ATOM_TOOL = 14,
-       ATOM_COMMENT = 15,
-       ATOM_GENRE1 = 16,
-       ATOM_TRACK = 17,
-       ATOM_DISC = 18,
-       ATOM_COMPILATION = 19,
-       ATOM_GENRE2 = 20,
-       ATOM_TEMPO = 21,
-       ATOM_COVER = 22,
-       ATOM_DRMS = 23,
-       ATOM_SINF = 24,
-       ATOM_SCHI = 25,
+       ATOM_MOOV,
+       ATOM_TRAK,
+       ATOM_MDIA,
+       ATOM_MINF,
+       ATOM_STBL,
+       ATOM_UDTA,
+       ATOM_ILST, /* iTunes Metadata list */
+       ATOM_TITLE,
+       ATOM_ARTIST,
+       ATOM_ALBUM,
+       ATOM_DATE,
+       ATOM_COMMENT,
 
        SUBATOMIC = 128,
 
        /* atoms without subatoms */
-       ATOM_FTYP = 129,
-       ATOM_MDAT = 130,
-       ATOM_MVHD = 131,
-       ATOM_TKHD = 132,
-       ATOM_TREF = 133,
-       ATOM_MDHD = 134, /* track header */
-       ATOM_VMHD = 135,
-       ATOM_SMHD = 136,
-       ATOM_HMHD = 137,
-       ATOM_STSD = 138, /* sample description box */
-       ATOM_STTS = 139, /* time to sample box */
-       ATOM_STSZ = 140, /* sample size box */
-       ATOM_STZ2 = 141,
-       ATOM_STCO = 142, /* chunk offset box */
-       ATOM_STSC = 143, /* sample to chunk box */
-       ATOM_MP4A = 144,
-       ATOM_MP4V = 145,
-       ATOM_MP4S = 146,
-       ATOM_ESDS = 147,
-       ATOM_META = 148, /* iTunes Metadata box */
-       ATOM_NAME = 149, /* iTunes Metadata name box */
-       ATOM_DATA = 150, /* iTunes Metadata data box */
-       ATOM_CTTS = 151,
-       ATOM_FRMA = 152,
-       ATOM_IVIV = 153,
-       ATOM_PRIV = 154,
-       ATOM_USER = 155,
-       ATOM_KEY = 156,
-       ATOM_ALBUM_ARTIST = 157,
-       ATOM_CONTENTGROUP = 158,
-       ATOM_LYRICS = 159,
-       ATOM_DESCRIPTION = 160,
-       ATOM_NETWORK = 161,
-       ATOM_SHOW = 162,
-       ATOM_EPISODENAME = 163,
-       ATOM_SORTTITLE = 164,
-       ATOM_SORTALBUM = 165,
-       ATOM_SORTARTIST = 166,
-       ATOM_SORTALBUMARTIST = 167,
-       ATOM_SORTWRITER = 168,
-       ATOM_SORTSHOW = 169,
-       ATOM_SEASON = 170,
-       ATOM_EPISODE = 171,
-       ATOM_PODCAST = 172,
-
+       ATOM_MDHD, /* track header */
+       ATOM_STSD, /* sample description box */
+       ATOM_STTS, /* time to sample box */
+       ATOM_STSZ, /* sample size box */
+       ATOM_STCO, /* chunk offset box */
+       ATOM_STSC, /* sample to chunk box */
+       ATOM_MP4A,
+       ATOM_META, /* iTunes Metadata box */
+       ATOM_DATA, /* iTunes Metadata data box */
        ATOM_UNKNOWN = 255
 };
 
-#define ATOM_FREE ATOM_UNKNOWN
-#define ATOM_SKIP ATOM_UNKNOWN
-
 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
 
 static uint8_t atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d)
@@ -236,46 +184,18 @@ static uint8_t atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d)
                        return ATOM_MINF;
                else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
                        return ATOM_MDIA;
-               else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
-                       return ATOM_MDAT;
                else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
                        return ATOM_MDHD;
-               else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
-                       return ATOM_MVHD;
                else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
                        return ATOM_MP4A;
-               else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
-                       return ATOM_MP4V;
-               else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
-                       return ATOM_MP4S;
                else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
                        return ATOM_META;
        } else if (a == 't') {
                if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
                        return ATOM_TRAK;
-               else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
-                       return ATOM_TKHD;
-               else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
-                       return ATOM_TREF;
-               else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
-                       return ATOM_TRACK;
-               else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
-                       return ATOM_TEMPO;
-               else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
-                       return ATOM_NETWORK;
-               else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
-                       return ATOM_SHOW;
-               else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
-                       return ATOM_EPISODENAME;
-               else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
-                       return ATOM_SEASON;
-               else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
-                       return ATOM_EPISODE;
        } else if (a == 's') {
                if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
                        return ATOM_STBL;
-               else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
-                       return ATOM_SMHD;
                else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
                        return ATOM_STSD;
                else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
@@ -286,97 +206,24 @@ static uint8_t atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d)
                        return ATOM_STSC;
                else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
                        return ATOM_STSZ;
-               else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
-                       return ATOM_STZ2;
-               else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
-                       return ATOM_SKIP;
-               else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
-                       return ATOM_SINF;
-               else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
-                       return ATOM_SCHI;
-               else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
-                       return ATOM_SORTTITLE;
-               else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
-                       return ATOM_SORTALBUM;
-               else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
-                       return ATOM_SORTARTIST;
-               else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
-                       return ATOM_SORTALBUMARTIST;
-               else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
-                       return ATOM_SORTWRITER;
-               else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
-                       return ATOM_SORTSHOW;
        } else if (a == COPYRIGHT_SYMBOL) {
                if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
                        return ATOM_TITLE;
                else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
                        return ATOM_ARTIST;
-               else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
-                       return ATOM_WRITER;
                else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
                        return ATOM_ALBUM;
                else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
                        return ATOM_DATE;
-               else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
-                       return ATOM_TOOL;
                else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
                        return ATOM_COMMENT;
-               else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
-                       return ATOM_GENRE1;
-               else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
-                       return ATOM_CONTENTGROUP;
-               else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
-                       return ATOM_LYRICS;
        }
-
-       if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
-               return ATOM_EDTS;
-       else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
-               return ATOM_ESDS;
-       else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
-               return ATOM_FTYP;
-       else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
-               return ATOM_FREE;
-       else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
-               return ATOM_HMHD;
-       else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
-               return ATOM_VMHD;
-       else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
+       if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
                return ATOM_UDTA;
        else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
                return ATOM_ILST;
-       else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
-               return ATOM_NAME;
        else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
                return ATOM_DATA;
-       else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
-               return ATOM_DISC;
-       else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
-               return ATOM_GENRE2;
-       else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
-               return ATOM_COVER;
-       else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
-               return ATOM_COMPILATION;
-       else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
-               return ATOM_CTTS;
-       else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
-               return ATOM_DRMS;
-       else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
-               return ATOM_FRMA;
-       else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
-               return ATOM_PRIV;
-       else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
-               return ATOM_IVIV;
-       else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
-               return ATOM_USER;
-       else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
-               return ATOM_KEY;
-       else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
-               return ATOM_ALBUM_ARTIST;
-       else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
-               return ATOM_DESCRIPTION;
-       else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
-               return ATOM_PODCAST;
        else
                return ATOM_UNKNOWN;
 }
@@ -865,18 +712,16 @@ static bool need_atom(uint8_t atom_type, bool meta_only)
 static int parse_sub_atoms(struct mp4 *f, uint64_t total_size, bool meta_only)
 {
        int ret;
-       uint64_t size;
-       uint8_t atom_type = 0;
-       uint64_t counted_size = 0;
-       uint8_t header_size = 0;
+       uint64_t dest, size, end = get_position(f) + total_size;
 
-       while (counted_size < total_size) {
+       for (dest = get_position(f); dest < end; set_position(f, dest)) {
+               uint8_t header_size, atom_type;
                ret = atom_read_header(f, &atom_type, &header_size, &size);
                if (ret <= 0)
                        return ret;
                if (size == 0)
                        return -1;
-               counted_size += size;
+               dest = get_position(f) + size - header_size;
                if (atom_type == ATOM_TRAK) {
                        if (f->total_tracks >= MAX_TRACKS)
                                return -1;
@@ -887,10 +732,8 @@ static int parse_sub_atoms(struct mp4 *f, uint64_t total_size, bool meta_only)
                        f->udta_offset = get_position(f) - header_size;
                        f->udta_size = size;
                }
-               if (!need_atom(atom_type, meta_only)) {
-                       set_position(f, get_position(f) + size - header_size);
+               if (!need_atom(atom_type, meta_only))
                        continue;
-               }
                if (atom_type < SUBATOMIC) /* atom contains subatoms */
                        ret = parse_sub_atoms(f, size - header_size, meta_only);
                else
@@ -1083,68 +926,11 @@ struct mp4_metadata *mp4_get_meta(struct mp4 *f)
        return &f->meta;
 }
 
-struct membuffer {
-       void *data;
-       unsigned written;
-       unsigned allocated;
-};
-
-static struct membuffer *membuffer_create(void)
-{
-       struct membuffer *buf = para_calloc(sizeof(*buf));
-
-       buf->allocated = 256;
-       buf->data = para_malloc(buf->allocated);
-       return buf;
-}
-
-static void membuffer_write(struct membuffer *buf, const void *ptr,
-               unsigned bytes)
-{
-       unsigned dest_size = buf->written + bytes;
-
-       if (dest_size > buf->allocated) {
-               do {
-                       buf->allocated <<= 1;
-               } while (dest_size > buf->allocated);
-               buf->data = para_realloc(buf->data, buf->allocated);
-       }
-
-       if (ptr)
-               memcpy((char *) buf->data + buf->written, ptr, bytes);
-       buf->written += bytes;
-}
-
-static void membuffer_write_atom_name(struct membuffer *buf, const char *data)
-{
-       membuffer_write(buf, data, 4);
-}
-
-static void membuffer_write_int32(struct membuffer *buf, uint32_t data)
-{
-       uint8_t temp[4];
-       write_u32_be(temp, data);
-       membuffer_write(buf, temp, 4);
-}
-
-static unsigned membuffer_get_size(const struct membuffer *buf)
-{
-       return buf->written;
-}
-
-static void *membuffer_detach(struct membuffer *buf)
+/** Total length of an on-disk metadata tag. */
+#define TAG_LEN(_len) (24 + (_len))
+static void create_ilst(const struct mp4_metadata *meta, uint8_t *out)
 {
-       void *ret = para_realloc(buf->data, buf->written);
-       free(buf);
-       return ret;
-}
-
-static void *create_ilst(const struct mp4_metadata *meta, uint32_t *out_size)
-{
-       struct membuffer *buf = membuffer_create();
-       unsigned n;
-
-       for (n = 0; n < meta->count; n++) {
+       for (unsigned n = 0; n < meta->count; n++) {
                struct mp4_tag *tag = meta->tags + n;
                unsigned len = strlen(tag->value);
                const char *atom_name;
@@ -1161,21 +947,17 @@ static void *create_ilst(const struct mp4_metadata *meta, uint32_t *out_size)
                        atom_name = "\xA9" "cmt";
                else
                        assert(false);
-               membuffer_write_int32(buf, 8 /* atom header */
-                       + 8 /* data atom header */
-                       + 8 /* flags + reserved */
-                       + len);
-               membuffer_write_atom_name(buf, atom_name);
-               membuffer_write_int32(buf, 8 /* data atom header */
+               write_u32_be(out, TAG_LEN(len));
+               memcpy(out + 4, atom_name, 4);
+               write_u32_be(out + 8, 8 /* data atom header */
                        + 8 /* flags + reserved */
                        + len);
-               membuffer_write_atom_name(buf, "data");
-               membuffer_write_int32(buf, 1);  /* flags */
-               membuffer_write_int32(buf, 0);  /* reserved */
-               membuffer_write(buf, tag->value, len);
+               memcpy(out + 12, "data", 4);
+               write_u32_be(out + 16, 1); /* flags */
+               write_u32_be(out + 20, 0); /* reserved */
+               memcpy(out + 24, tag->value, len);
+               out += TAG_LEN(len);
        }
-       *out_size = membuffer_get_size(buf);
-       return membuffer_detach(buf);
 }
 
 static uint32_t fix_byte_order_32(uint32_t src)
@@ -1188,13 +970,14 @@ static void *modify_moov(struct mp4 *f, uint32_t *out_size)
        int ret;
        uint64_t total_base = f->moov_offset + 8;
        uint32_t total_size = (uint32_t) (f->moov_size - 8);
-       uint32_t new_ilst_size;
-       void *new_ilst_buffer, *out_buffer;
+       uint32_t new_ilst_size = 0;
+       void *out_buffer;
        uint8_t *p_out;
        int32_t size_delta;
        uint32_t tmp;
 
-       new_ilst_buffer = create_ilst(&f->meta, &new_ilst_size);
+       for (unsigned n = 0; n < f->meta.count; n++)
+               new_ilst_size += TAG_LEN(strlen(f->meta.tags[n].value));
        size_delta = new_ilst_size - (f->ilst_size - 8);
        *out_size = total_size + size_delta;
        out_buffer = para_malloc(*out_size);
@@ -1239,14 +1022,13 @@ static void *modify_moov(struct mp4 *f, uint32_t *out_size)
        if (ret <= 0)
                return NULL;
        p_out += 4;
-       memcpy(p_out, new_ilst_buffer, new_ilst_size);
+       create_ilst(&f->meta, p_out);
        p_out += new_ilst_size;
        set_position(f, f->ilst_offset + f->ilst_size);
        ret = read_data(f, p_out, total_size - (f->ilst_offset - total_base)
                - f->ilst_size);
        if (ret <= 0)
                return NULL;
-       free(new_ilst_buffer);
        return out_buffer;
 }