yading@11: /** yading@11: Copyright (C) 2005 Michael Ahlberg, Måns Rullgård yading@11: yading@11: Permission is hereby granted, free of charge, to any person yading@11: obtaining a copy of this software and associated documentation yading@11: files (the "Software"), to deal in the Software without yading@11: restriction, including without limitation the rights to use, copy, yading@11: modify, merge, publish, distribute, sublicense, and/or sell copies yading@11: of the Software, and to permit persons to whom the Software is yading@11: furnished to do so, subject to the following conditions: yading@11: yading@11: The above copyright notice and this permission notice shall be yading@11: included in all copies or substantial portions of the Software. yading@11: yading@11: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, yading@11: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF yading@11: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND yading@11: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT yading@11: HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, yading@11: WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, yading@11: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER yading@11: DEALINGS IN THE SOFTWARE. yading@11: **/ yading@11: yading@11: #include yading@11: #include "libavutil/avstring.h" yading@11: #include "libavutil/bswap.h" yading@11: #include "libavutil/dict.h" yading@11: #include "libavcodec/get_bits.h" yading@11: #include "libavcodec/bytestream.h" yading@11: #include "libavcodec/vorbis_parser.h" yading@11: #include "avformat.h" yading@11: #include "internal.h" yading@11: #include "oggdec.h" yading@11: #include "vorbiscomment.h" yading@11: yading@11: static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val) yading@11: { yading@11: int i, cnum, h, m, s, ms, keylen = strlen(key); yading@11: AVChapter *chapter = NULL; yading@11: yading@11: if (keylen < 9 || sscanf(key, "CHAPTER%02d", &cnum) != 1) yading@11: return 0; yading@11: yading@11: if (keylen == 9) { yading@11: if (sscanf(val, "%02d:%02d:%02d.%03d", &h, &m, &s, &ms) < 4) yading@11: return 0; yading@11: yading@11: avpriv_new_chapter(as, cnum, (AVRational){1,1000}, yading@11: ms + 1000*(s + 60*(m + 60*h)), yading@11: AV_NOPTS_VALUE, NULL); yading@11: av_free(val); yading@11: } else if (!strcmp(key+9, "NAME")) { yading@11: for(i = 0; i < as->nb_chapters; i++) yading@11: if (as->chapters[i]->id == cnum) { yading@11: chapter = as->chapters[i]; yading@11: break; yading@11: } yading@11: if (!chapter) yading@11: return 0; yading@11: yading@11: av_dict_set(&chapter->metadata, "title", val, yading@11: AV_DICT_DONT_STRDUP_VAL); yading@11: } else yading@11: return 0; yading@11: yading@11: av_free(key); yading@11: return 1; yading@11: } yading@11: yading@11: int yading@11: ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, int size) yading@11: { yading@11: const uint8_t *p = buf; yading@11: const uint8_t *end = buf + size; yading@11: unsigned n, j; yading@11: int s; yading@11: yading@11: if (size < 8) /* must have vendor_length and user_comment_list_length */ yading@11: return -1; yading@11: yading@11: s = bytestream_get_le32(&p); yading@11: yading@11: if (end - p - 4 < s || s < 0) yading@11: return -1; yading@11: yading@11: p += s; yading@11: yading@11: n = bytestream_get_le32(&p); yading@11: yading@11: while (end - p >= 4 && n > 0) { yading@11: const char *t, *v; yading@11: int tl, vl; yading@11: yading@11: s = bytestream_get_le32(&p); yading@11: yading@11: if (end - p < s || s < 0) yading@11: break; yading@11: yading@11: t = p; yading@11: p += s; yading@11: n--; yading@11: yading@11: v = memchr(t, '=', s); yading@11: if (!v) yading@11: continue; yading@11: yading@11: tl = v - t; yading@11: vl = s - tl - 1; yading@11: v++; yading@11: yading@11: if (tl && vl) { yading@11: char *tt, *ct; yading@11: yading@11: tt = av_malloc(tl + 1); yading@11: ct = av_malloc(vl + 1); yading@11: if (!tt || !ct) { yading@11: av_freep(&tt); yading@11: av_freep(&ct); yading@11: av_log(as, AV_LOG_WARNING, "out-of-memory error. skipping VorbisComment tag.\n"); yading@11: continue; yading@11: } yading@11: yading@11: for (j = 0; j < tl; j++) yading@11: tt[j] = av_toupper(t[j]); yading@11: tt[tl] = 0; yading@11: yading@11: memcpy(ct, v, vl); yading@11: ct[vl] = 0; yading@11: yading@11: if (!ogm_chapter(as, tt, ct)) yading@11: av_dict_set(m, tt, ct, yading@11: AV_DICT_DONT_STRDUP_KEY | yading@11: AV_DICT_DONT_STRDUP_VAL); yading@11: } yading@11: } yading@11: yading@11: if (p != end) yading@11: av_log(as, AV_LOG_INFO, "%ti bytes of comment header remain\n", end-p); yading@11: if (n > 0) yading@11: av_log(as, AV_LOG_INFO, yading@11: "truncated comment header, %i comments not found\n", n); yading@11: yading@11: ff_metadata_conv(m, NULL, ff_vorbiscomment_metadata_conv); yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: yading@11: /** Parse the vorbis header yading@11: * Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec yading@11: * [vorbis_version] = read 32 bits as unsigned integer | Not used yading@11: * [audio_channels] = read 8 bit integer as unsigned | Used yading@11: * [audio_sample_rate] = read 32 bits as unsigned integer | Used yading@11: * [bitrate_maximum] = read 32 bits as signed integer | Not used yet yading@11: * [bitrate_nominal] = read 32 bits as signed integer | Not used yet yading@11: * [bitrate_minimum] = read 32 bits as signed integer | Used as bitrate yading@11: * [blocksize_0] = read 4 bits as unsigned integer | Not Used yading@11: * [blocksize_1] = read 4 bits as unsigned integer | Not Used yading@11: * [framing_flag] = read one bit | Not Used yading@11: * */ yading@11: yading@11: struct oggvorbis_private { yading@11: unsigned int len[3]; yading@11: unsigned char *packet[3]; yading@11: VorbisParseContext vp; yading@11: int64_t final_pts; yading@11: int final_duration; yading@11: }; yading@11: yading@11: yading@11: static unsigned int yading@11: fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv, yading@11: uint8_t **buf) yading@11: { yading@11: int i,offset, len, buf_len; yading@11: unsigned char *ptr; yading@11: yading@11: len = priv->len[0] + priv->len[1] + priv->len[2]; yading@11: buf_len = len + len/255 + 64; yading@11: ptr = *buf = av_realloc(NULL, buf_len); yading@11: if (!*buf) yading@11: return 0; yading@11: memset(*buf, '\0', buf_len); yading@11: yading@11: ptr[0] = 2; yading@11: offset = 1; yading@11: offset += av_xiphlacing(&ptr[offset], priv->len[0]); yading@11: offset += av_xiphlacing(&ptr[offset], priv->len[1]); yading@11: for (i = 0; i < 3; i++) { yading@11: memcpy(&ptr[offset], priv->packet[i], priv->len[i]); yading@11: offset += priv->len[i]; yading@11: av_freep(&priv->packet[i]); yading@11: } yading@11: *buf = av_realloc(*buf, offset + FF_INPUT_BUFFER_PADDING_SIZE); yading@11: return offset; yading@11: } yading@11: yading@11: static void vorbis_cleanup(AVFormatContext *s, int idx) yading@11: { yading@11: struct ogg *ogg = s->priv_data; yading@11: struct ogg_stream *os = ogg->streams + idx; yading@11: struct oggvorbis_private *priv = os->private; yading@11: int i; yading@11: if (os->private) yading@11: for (i = 0; i < 3; i++) yading@11: av_freep(&priv->packet[i]); yading@11: } yading@11: yading@11: static int yading@11: vorbis_header (AVFormatContext * s, int idx) yading@11: { yading@11: struct ogg *ogg = s->priv_data; yading@11: struct ogg_stream *os = ogg->streams + idx; yading@11: AVStream *st = s->streams[idx]; yading@11: struct oggvorbis_private *priv; yading@11: int pkt_type = os->buf[os->pstart]; yading@11: yading@11: if (!(pkt_type & 1)) yading@11: return os->private ? 0 : -1; yading@11: yading@11: if (!os->private) { yading@11: os->private = av_mallocz(sizeof(struct oggvorbis_private)); yading@11: if (!os->private) yading@11: return -1; yading@11: } yading@11: yading@11: if (os->psize < 1 || pkt_type > 5) yading@11: return -1; yading@11: yading@11: priv = os->private; yading@11: yading@11: if (priv->packet[pkt_type>>1]) yading@11: return -1; yading@11: if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1]) yading@11: return -1; yading@11: yading@11: priv->len[pkt_type >> 1] = os->psize; yading@11: priv->packet[pkt_type >> 1] = av_mallocz(os->psize); yading@11: if (!priv->packet[pkt_type >> 1]) yading@11: return AVERROR(ENOMEM); yading@11: memcpy(priv->packet[pkt_type >> 1], os->buf + os->pstart, os->psize); yading@11: if (os->buf[os->pstart] == 1) { yading@11: const uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */ yading@11: unsigned blocksize, bs0, bs1; yading@11: int srate; yading@11: int channels; yading@11: yading@11: if (os->psize != 30) yading@11: return -1; yading@11: yading@11: if (bytestream_get_le32(&p) != 0) /* vorbis_version */ yading@11: return -1; yading@11: yading@11: channels= bytestream_get_byte(&p); yading@11: if (st->codec->channels && channels != st->codec->channels) { yading@11: av_log(s, AV_LOG_ERROR, "Channel change is not supported\n"); yading@11: return AVERROR_PATCHWELCOME; yading@11: } yading@11: st->codec->channels = channels; yading@11: srate = bytestream_get_le32(&p); yading@11: p += 4; // skip maximum bitrate yading@11: st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate yading@11: p += 4; // skip minimum bitrate yading@11: yading@11: blocksize = bytestream_get_byte(&p); yading@11: bs0 = blocksize & 15; yading@11: bs1 = blocksize >> 4; yading@11: yading@11: if (bs0 > bs1) yading@11: return -1; yading@11: if (bs0 < 6 || bs1 > 13) yading@11: return -1; yading@11: yading@11: if (bytestream_get_byte(&p) != 1) /* framing_flag */ yading@11: return -1; yading@11: yading@11: st->codec->codec_type = AVMEDIA_TYPE_AUDIO; yading@11: st->codec->codec_id = AV_CODEC_ID_VORBIS; yading@11: yading@11: if (srate > 0) { yading@11: st->codec->sample_rate = srate; yading@11: avpriv_set_pts_info(st, 64, 1, srate); yading@11: } yading@11: } else if (os->buf[os->pstart] == 3) { yading@11: if (os->psize > 8 && yading@11: ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 8) >= 0) { yading@11: // drop all metadata we parsed and which is not required by libvorbis yading@11: unsigned new_len = 7 + 4 + AV_RL32(priv->packet[1] + 7) + 4 + 1; yading@11: if (new_len >= 16 && new_len < os->psize) { yading@11: AV_WL32(priv->packet[1] + new_len - 5, 0); yading@11: priv->packet[1][new_len - 1] = 1; yading@11: priv->len[1] = new_len; yading@11: } yading@11: } yading@11: } else { yading@11: int ret; yading@11: st->codec->extradata_size = yading@11: fixup_vorbis_headers(s, priv, &st->codec->extradata); yading@11: if ((ret = avpriv_vorbis_parse_extradata(st->codec, &priv->vp))) { yading@11: av_freep(&st->codec->extradata); yading@11: st->codec->extradata_size = 0; yading@11: return ret; yading@11: } yading@11: } yading@11: yading@11: return 1; yading@11: } yading@11: yading@11: static int vorbis_packet(AVFormatContext *s, int idx) yading@11: { yading@11: struct ogg *ogg = s->priv_data; yading@11: struct ogg_stream *os = ogg->streams + idx; yading@11: struct oggvorbis_private *priv = os->private; yading@11: int duration; yading@11: yading@11: /* first packet handling yading@11: here we parse the duration of each packet in the first page and compare yading@11: the total duration to the page granule to find the encoder delay and yading@11: set the first timestamp */ yading@11: if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) { yading@11: int seg, d; yading@11: uint8_t *last_pkt = os->buf + os->pstart; yading@11: uint8_t *next_pkt = last_pkt; yading@11: yading@11: avpriv_vorbis_parse_reset(&priv->vp); yading@11: duration = 0; yading@11: seg = os->segp; yading@11: d = avpriv_vorbis_parse_frame(&priv->vp, last_pkt, 1); yading@11: if (d < 0) { yading@11: os->pflags |= AV_PKT_FLAG_CORRUPT; yading@11: return 0; yading@11: } yading@11: duration += d; yading@11: last_pkt = next_pkt = next_pkt + os->psize; yading@11: for (; seg < os->nsegs; seg++) { yading@11: if (os->segments[seg] < 255) { yading@11: int d = avpriv_vorbis_parse_frame(&priv->vp, last_pkt, 1); yading@11: if (d < 0) { yading@11: duration = os->granule; yading@11: break; yading@11: } yading@11: duration += d; yading@11: last_pkt = next_pkt + os->segments[seg]; yading@11: } yading@11: next_pkt += os->segments[seg]; yading@11: } yading@11: os->lastpts = os->lastdts = os->granule - duration; yading@11: if(s->streams[idx]->start_time == AV_NOPTS_VALUE) { yading@11: s->streams[idx]->start_time = FFMAX(os->lastpts, 0); yading@11: if (s->streams[idx]->duration) yading@11: s->streams[idx]->duration -= s->streams[idx]->start_time; yading@11: } yading@11: priv->final_pts = AV_NOPTS_VALUE; yading@11: avpriv_vorbis_parse_reset(&priv->vp); yading@11: } yading@11: yading@11: /* parse packet duration */ yading@11: if (os->psize > 0) { yading@11: duration = avpriv_vorbis_parse_frame(&priv->vp, os->buf + os->pstart, 1); yading@11: if (duration < 0) { yading@11: os->pflags |= AV_PKT_FLAG_CORRUPT; yading@11: return 0; yading@11: } yading@11: os->pduration = duration; yading@11: } yading@11: yading@11: /* final packet handling yading@11: here we save the pts of the first packet in the final page, sum up all yading@11: packet durations in the final page except for the last one, and compare yading@11: to the page granule to find the duration of the final packet */ yading@11: if (os->flags & OGG_FLAG_EOS) { yading@11: if (os->lastpts != AV_NOPTS_VALUE) { yading@11: priv->final_pts = os->lastpts; yading@11: priv->final_duration = 0; yading@11: } yading@11: if (os->segp == os->nsegs) yading@11: os->pduration = os->granule - priv->final_pts - priv->final_duration; yading@11: priv->final_duration += os->pduration; yading@11: } yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: const struct ogg_codec ff_vorbis_codec = { yading@11: .magic = "\001vorbis", yading@11: .magicsize = 7, yading@11: .header = vorbis_header, yading@11: .packet = vorbis_packet, yading@11: .cleanup= vorbis_cleanup, yading@11: .nb_header = 3, yading@11: };