libavformat/oggparsevorbis.c
9146ca37
 /**
       Copyright (C) 2005  Michael Ahlberg, Måns Rullgård
 
       Permission is hereby granted, free of charge, to any person
       obtaining a copy of this software and associated documentation
       files (the "Software"), to deal in the Software without
       restriction, including without limitation the rights to use, copy,
       modify, merge, publish, distribute, sublicense, and/or sell copies
       of the Software, and to permit persons to whom the Software is
       furnished to do so, subject to the following conditions:
 
       The above copyright notice and this permission notice shall be
       included in all copies or substantial portions of the Software.
 
       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
       NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
       WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
       DEALINGS IN THE SOFTWARE.
 **/
 
 #include <stdlib.h>
245976da
 #include "libavutil/avstring.h"
 #include "libavutil/bswap.h"
d2d67e42
 #include "libavutil/dict.h"
9106a698
 #include "libavcodec/get_bits.h"
245976da
 #include "libavcodec/bytestream.h"
9146ca37
 #include "avformat.h"
19711af5
 #include "internal.h"
a0ddef24
 #include "oggdec.h"
fb66c31d
 #include "vorbiscomment.h"
9146ca37
 
8730fad5
 static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val)
 {
     int i, cnum, h, m, s, ms, keylen = strlen(key);
     AVChapter *chapter = NULL;
 
     if (keylen < 9 || sscanf(key, "CHAPTER%02d", &cnum) != 1)
         return 0;
 
     if (keylen == 9) {
         if (sscanf(val, "%02d:%02d:%02d.%03d", &h, &m, &s, &ms) < 4)
             return 0;
 
1fa395e4
         avpriv_new_chapter(as, cnum, (AVRational){1,1000},
8730fad5
                        ms + 1000*(s + 60*(m + 60*h)),
                        AV_NOPTS_VALUE, NULL);
         av_free(val);
     } else if (!strcmp(key+9, "NAME")) {
         for(i = 0; i < as->nb_chapters; i++)
             if (as->chapters[i]->id == cnum) {
                 chapter = as->chapters[i];
                 break;
             }
         if (!chapter)
             return 0;
 
d2d67e42
         av_dict_set(&chapter->metadata, "title", val,
                          AV_DICT_DONT_STRDUP_VAL);
8730fad5
     } else
         return 0;
 
     av_free(key);
     return 1;
 }
 
9686df2b
 int
d2d67e42
 ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, int size)
9146ca37
 {
47a0513b
     const uint8_t *p = buf;
     const uint8_t *end = buf + size;
98422c44
     unsigned n, j;
     int s;
9146ca37
 
f5475e1b
     if (size < 8) /* must have vendor_length and user_comment_list_length */
9146ca37
         return -1;
 
0a770ae7
     s = bytestream_get_le32(&p);
9146ca37
 
98422c44
     if (end - p - 4 < s || s < 0)
9146ca37
         return -1;
 
     p += s;
 
0a770ae7
     n = bytestream_get_le32(&p);
9146ca37
 
98422c44
     while (end - p >= 4 && n > 0) {
47a0513b
         const char *t, *v;
9146ca37
         int tl, vl;
 
0a770ae7
         s = bytestream_get_le32(&p);
9146ca37
 
98422c44
         if (end - p < s || s < 0)
9146ca37
             break;
 
         t = p;
         p += s;
         n--;
 
4bd684bc
         v = memchr(t, '=', s);
9146ca37
         if (!v)
             continue;
 
         tl = v - t;
         vl = s - tl - 1;
         v++;
 
4bd684bc
         if (tl && vl) {
e3b44649
             char *tt, *ct;
 
             tt = av_malloc(tl + 1);
             ct = av_malloc(vl + 1);
             if (!tt || !ct) {
                 av_freep(&tt);
                 av_freep(&ct);
                 av_log(as, AV_LOG_WARNING, "out-of-memory error. skipping VorbisComment tag.\n");
                 continue;
             }
9146ca37
 
             for (j = 0; j < tl; j++)
4bd684bc
                 tt[j] = toupper(t[j]);
9146ca37
             tt[tl] = 0;
 
4bd684bc
             memcpy(ct, v, vl);
9146ca37
             ct[vl] = 0;
 
8730fad5
             if (!ogm_chapter(as, tt, ct))
d2d67e42
                 av_dict_set(m, tt, ct,
                                    AV_DICT_DONT_STRDUP_KEY |
                                    AV_DICT_DONT_STRDUP_VAL);
9146ca37
         }
     }
 
972c5f9e
     if (p != end)
7d507ceb
         av_log(as, AV_LOG_INFO, "%ti bytes of comment header remain\n", end-p);
9146ca37
     if (n > 0)
4bd684bc
         av_log(as, AV_LOG_INFO,
                "truncated comment header, %i comments not found\n", n);
9146ca37
 
ad7768f4
     ff_metadata_conv(m, NULL, ff_vorbiscomment_metadata_conv);
03700d39
 
9146ca37
     return 0;
 }
 
 
 /** Parse the vorbis header
  * Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec
  * [vorbis_version] = read 32 bits as unsigned integer | Not used
  * [audio_channels] = read 8 bit integer as unsigned | Used
115329f1
  * [audio_sample_rate] = read 32 bits as unsigned integer | Used
9146ca37
  * [bitrate_maximum] = read 32 bits as signed integer | Not used yet
  * [bitrate_nominal] = read 32 bits as signed integer | Not used yet
  * [bitrate_minimum] = read 32 bits as signed integer | Used as bitrate
  * [blocksize_0] = read 4 bits as unsigned integer | Not Used
  * [blocksize_1] = read 4 bits as unsigned integer | Not Used
  * [framing_flag] = read one bit | Not Used
  *    */
 
77be08ee
 struct oggvorbis_private {
ad2b531d
     unsigned int len[3];
     unsigned char *packet[3];
77be08ee
 };
ad2b531d
 
 
 static unsigned int
77be08ee
 fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv,
19f4ceca
                      uint8_t **buf)
ad2b531d
 {
     int i,offset, len;
     unsigned char *ptr;
 
     len = priv->len[0] + priv->len[1] + priv->len[2];
     ptr = *buf = av_mallocz(len + len/255 + 64);
 
     ptr[0] = 2;
     offset = 1;
     offset += av_xiphlacing(&ptr[offset], priv->len[0]);
     offset += av_xiphlacing(&ptr[offset], priv->len[1]);
4bd684bc
     for (i = 0; i < 3; i++) {
ad2b531d
         memcpy(&ptr[offset], priv->packet[i], priv->len[i]);
         offset += priv->len[i];
2ac41150
         av_freep(&priv->packet[i]);
ad2b531d
     }
589790c2
     *buf = av_realloc(*buf, offset + FF_INPUT_BUFFER_PADDING_SIZE);
ad2b531d
     return offset;
 }
 
119b7a6c
 static void vorbis_cleanup(AVFormatContext *s, int idx)
8829c790
 {
     struct ogg *ogg = s->priv_data;
     struct ogg_stream *os = ogg->streams + idx;
     struct oggvorbis_private *priv = os->private;
     int i;
     if (os->private)
         for (i = 0; i < 3; i++)
             av_freep(&priv->packet[i]);
 }
ad2b531d
 
9146ca37
 static int
 vorbis_header (AVFormatContext * s, int idx)
 {
77be08ee
     struct ogg *ogg = s->priv_data;
     struct ogg_stream *os = ogg->streams + idx;
9146ca37
     AVStream *st = s->streams[idx];
77be08ee
     struct oggvorbis_private *priv;
8f8320d7
     int pkt_type = os->buf[os->pstart];
9146ca37
 
8f8320d7
     if (!(pkt_type & 1))
9146ca37
         return 0;
 
8f8320d7
     if (!os->private) {
77be08ee
         os->private = av_mallocz(sizeof(struct oggvorbis_private));
4bd684bc
         if (!os->private)
ad2b531d
             return 0;
     }
9146ca37
 
8f8320d7
     if (os->psize < 1 || pkt_type > 5)
f5475e1b
         return -1;
 
ad2b531d
     priv = os->private;
73c44cb2
 
     if (priv->packet[pkt_type>>1])
         return -1;
     if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1])
         return -1;
 
8f8320d7
     priv->len[pkt_type >> 1] = os->psize;
     priv->packet[pkt_type >> 1] = av_mallocz(os->psize);
     memcpy(priv->packet[pkt_type >> 1], os->buf + os->pstart, os->psize);
9146ca37
     if (os->buf[os->pstart] == 1) {
47a0513b
         const uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */
736e63ed
         unsigned blocksize, bs0, bs1;
ce20edb7
         int srate;
f5475e1b
 
         if (os->psize != 30)
             return -1;
 
736e63ed
         if (bytestream_get_le32(&p) != 0) /* vorbis_version */
             return -1;
 
739587bf
         st->codec->channels = bytestream_get_byte(&p);
ce20edb7
         srate = bytestream_get_le32(&p);
739587bf
         p += 4; // skip maximum bitrate
         st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate
736e63ed
         p += 4; // skip minimum bitrate
 
         blocksize = bytestream_get_byte(&p);
         bs0 = blocksize & 15;
         bs1 = blocksize >> 4;
 
         if (bs0 > bs1)
             return -1;
         if (bs0 < 6 || bs1 > 13)
             return -1;
 
         if (bytestream_get_byte(&p) != 1) /* framing_flag */
             return -1;
9146ca37
 
72415b2a
         st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
01f4895c
         st->codec->codec_id = CODEC_ID_VORBIS;
9146ca37
 
ce20edb7
         if (srate > 0) {
             st->codec->sample_rate = srate;
c3f9ebf7
             avpriv_set_pts_info(st, 64, 1, srate);
ce20edb7
         }
9146ca37
     } else if (os->buf[os->pstart] == 3) {
8cb3c557
         if (os->psize > 8 &&
             ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 8) >= 0) {
             // drop all metadata we parsed and which is not required by libvorbis
             unsigned new_len = 7 + 4 + AV_RL32(priv->packet[1] + 7) + 4 + 1;
             if (new_len >= 16 && new_len < os->psize) {
                 AV_WL32(priv->packet[1] + new_len - 5, 0);
                 priv->packet[1][new_len - 1] = 1;
                 priv->len[1] = new_len;
             }
         }
ad2b531d
     } else {
01f4895c
         st->codec->extradata_size =
             fixup_vorbis_headers(s, priv, &st->codec->extradata);
9146ca37
     }
 
8f8320d7
     return 1;
9146ca37
 }
 
77be08ee
 const struct ogg_codec ff_vorbis_codec = {
9146ca37
     .magic = "\001vorbis",
     .magicsize = 7,
8829c790
     .header = vorbis_header,
     .cleanup= vorbis_cleanup,
     .nb_header = 3,
9146ca37
 };