diff options
| author | Tim Redfern <tim@eclectronics.org> | 2013-12-29 12:19:38 +0000 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2013-12-29 12:19:38 +0000 |
| commit | f7813a5324be39d13ab536c245d15dfc602a7849 (patch) | |
| tree | fad99148b88823d34a5df2f0a25881a002eb291b /ffmpeg/libavformat/oggparsevorbis.c | |
| parent | b7a5a477b8ff4d4e3028b9dfb9a9df0a41463f92 (diff) | |
basic type mechanism working
Diffstat (limited to 'ffmpeg/libavformat/oggparsevorbis.c')
| -rw-r--r-- | ffmpeg/libavformat/oggparsevorbis.c | 242 |
1 files changed, 138 insertions, 104 deletions
diff --git a/ffmpeg/libavformat/oggparsevorbis.c b/ffmpeg/libavformat/oggparsevorbis.c index da029a4..36ad738 100644 --- a/ffmpeg/libavformat/oggparsevorbis.c +++ b/ffmpeg/libavformat/oggparsevorbis.c @@ -1,35 +1,38 @@ -/** - 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. -**/ +/* + * 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> + #include "libavutil/avstring.h" +#include "libavutil/base64.h" #include "libavutil/bswap.h" #include "libavutil/dict.h" -#include "libavcodec/get_bits.h" #include "libavcodec/bytestream.h" +#include "libavcodec/get_bits.h" #include "libavcodec/vorbis_parser.h" #include "avformat.h" +#include "flac_picture.h" #include "internal.h" #include "oggdec.h" #include "vorbiscomment.h" @@ -39,19 +42,19 @@ 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) + if (keylen < 9 || sscanf(key, "CHAPTER%03d", &cnum) != 1) return 0; - if (keylen == 9) { + if (keylen <= 10) { if (sscanf(val, "%02d:%02d:%02d.%03d", &h, &m, &s, &ms) < 4) return 0; - avpriv_new_chapter(as, cnum, (AVRational){1,1000}, - ms + 1000*(s + 60*(m + 60*h)), - AV_NOPTS_VALUE, NULL); + avpriv_new_chapter(as, cnum, (AVRational) { 1, 1000 }, + 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++) + } else if (!strcmp(key + keylen - 4, "NAME")) { + for (i = 0; i < as->nb_chapters; i++) if (as->chapters[i]->id == cnum) { chapter = as->chapters[i]; break; @@ -59,8 +62,7 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val) if (!chapter) return 0; - av_dict_set(&chapter->metadata, "title", val, - AV_DICT_DONT_STRDUP_VAL); + av_dict_set(&chapter->metadata, "title", val, AV_DICT_DONT_STRDUP_VAL); } else return 0; @@ -68,21 +70,22 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val) return 1; } -int -ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, int size) +int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m, + const uint8_t *buf, int size) { - const uint8_t *p = buf; + const uint8_t *p = buf; const uint8_t *end = buf + size; unsigned n, j; int s; - if (size < 8) /* must have vendor_length and user_comment_list_length */ - return -1; + /* must have vendor_length and user_comment_list_length */ + if (size < 8) + return AVERROR_INVALIDDATA; s = bytestream_get_le32(&p); if (end - p - 4 < s || s < 0) - return -1; + return AVERROR_INVALIDDATA; p += s; @@ -97,7 +100,7 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in if (end - p < s || s < 0) break; - t = p; + t = p; p += s; n--; @@ -117,8 +120,7 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in if (!tt || !ct) { av_freep(&tt); av_freep(&ct); - av_log(as, AV_LOG_WARNING, "out-of-memory error. skipping VorbisComment tag.\n"); - continue; + return AVERROR(ENOMEM); } for (j = 0; j < tl; j++) @@ -128,15 +130,41 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in memcpy(ct, v, vl); ct[vl] = 0; - if (!ogm_chapter(as, tt, ct)) + /* The format in which the pictures are stored is the FLAC format. + * Xiph says: "The binary FLAC picture structure is base64 encoded + * and placed within a VorbisComment with the tag name + * 'METADATA_BLOCK_PICTURE'. This is the preferred and + * recommended way of embedding cover art within VorbisComments." + */ + if (!strcmp(tt, "METADATA_BLOCK_PICTURE")) { + int ret; + char *pict = av_malloc(vl); + + if (!pict) { + av_log(as, AV_LOG_WARNING, "out-of-memory error. Skipping cover art block.\n"); + av_freep(&tt); + av_freep(&ct); + continue; + } + if ((ret = av_base64_decode(pict, ct, vl)) > 0) + ret = ff_flac_parse_picture(as, pict, ret); + av_freep(&tt); + av_freep(&ct); + av_freep(&pict); + if (ret < 0) { + av_log(as, AV_LOG_WARNING, "Failed to parse cover art block.\n"); + continue; + } + } else if (!ogm_chapter(as, tt, ct)) av_dict_set(m, tt, ct, - AV_DICT_DONT_STRDUP_KEY | - AV_DICT_DONT_STRDUP_VAL); + AV_DICT_DONT_STRDUP_KEY | + AV_DICT_DONT_STRDUP_VAL); } } if (p != end) - av_log(as, AV_LOG_INFO, "%ti bytes of comment header remain\n", end-p); + av_log(as, AV_LOG_INFO, + "%ti bytes of comment header remain\n", end - p); if (n > 0) av_log(as, AV_LOG_INFO, "truncated comment header, %i comments not found\n", n); @@ -146,8 +174,9 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in return 0; } - -/** Parse the vorbis header +/* + * 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 @@ -158,7 +187,7 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in * [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 - * */ + */ struct oggvorbis_private { unsigned int len[3]; @@ -168,23 +197,23 @@ struct oggvorbis_private { int final_duration; }; - -static unsigned int -fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv, - uint8_t **buf) +static int fixup_vorbis_headers(AVFormatContext *as, + struct oggvorbis_private *priv, + uint8_t **buf) { - int i,offset, len, buf_len; + int i, offset, len, err; + int buf_len; unsigned char *ptr; len = priv->len[0] + priv->len[1] + priv->len[2]; - buf_len = len + len/255 + 64; + buf_len = len + len / 255 + 64; ptr = *buf = av_realloc(NULL, buf_len); - if (!*buf) - return 0; + if (!ptr) + return AVERROR(ENOMEM); memset(*buf, '\0', buf_len); - ptr[0] = 2; - offset = 1; + ptr[0] = 2; + offset = 1; offset += av_xiphlacing(&ptr[offset], priv->len[0]); offset += av_xiphlacing(&ptr[offset], priv->len[1]); for (i = 0; i < 3; i++) { @@ -192,7 +221,8 @@ fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv, offset += priv->len[i]; av_freep(&priv->packet[i]); } - *buf = av_realloc(*buf, offset + FF_INPUT_BUFFER_PADDING_SIZE); + if ((err = av_reallocp(buf, offset + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) + return err; return offset; } @@ -207,35 +237,34 @@ static void vorbis_cleanup(AVFormatContext *s, int idx) av_freep(&priv->packet[i]); } -static int -vorbis_header (AVFormatContext * s, int idx) +static int vorbis_header(AVFormatContext *s, int idx) { struct ogg *ogg = s->priv_data; + AVStream *st = s->streams[idx]; struct ogg_stream *os = ogg->streams + idx; - AVStream *st = s->streams[idx]; struct oggvorbis_private *priv; int pkt_type = os->buf[os->pstart]; - if (!(pkt_type & 1)) - return os->private ? 0 : -1; - if (!os->private) { os->private = av_mallocz(sizeof(struct oggvorbis_private)); if (!os->private) - return -1; + return AVERROR(ENOMEM); } + if (!(pkt_type & 1)) + return 0; + if (os->psize < 1 || pkt_type > 5) - return -1; + return AVERROR_INVALIDDATA; priv = os->private; - if (priv->packet[pkt_type>>1]) - return -1; + if (priv->packet[pkt_type >> 1]) + return AVERROR_INVALIDDATA; if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1]) - return -1; + return AVERROR_INVALIDDATA; - priv->len[pkt_type >> 1] = os->psize; + priv->len[pkt_type >> 1] = os->psize; priv->packet[pkt_type >> 1] = av_mallocz(os->psize); if (!priv->packet[pkt_type >> 1]) return AVERROR(ENOMEM); @@ -247,36 +276,36 @@ vorbis_header (AVFormatContext * s, int idx) int channels; if (os->psize != 30) - return -1; + return AVERROR_INVALIDDATA; if (bytestream_get_le32(&p) != 0) /* vorbis_version */ - return -1; + return AVERROR_INVALIDDATA; - channels= bytestream_get_byte(&p); + channels = bytestream_get_byte(&p); if (st->codec->channels && channels != st->codec->channels) { av_log(s, AV_LOG_ERROR, "Channel change is not supported\n"); return AVERROR_PATCHWELCOME; } st->codec->channels = channels; - srate = bytestream_get_le32(&p); + srate = bytestream_get_le32(&p); p += 4; // skip maximum bitrate st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate p += 4; // skip minimum bitrate blocksize = bytestream_get_byte(&p); - bs0 = blocksize & 15; - bs1 = blocksize >> 4; + bs0 = blocksize & 15; + bs1 = blocksize >> 4; if (bs0 > bs1) - return -1; + return AVERROR_INVALIDDATA; if (bs0 < 6 || bs1 > 13) - return -1; + return AVERROR_INVALIDDATA; if (bytestream_get_byte(&p) != 1) /* framing_flag */ - return -1; + return AVERROR_INVALIDDATA; st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_id = AV_CODEC_ID_VORBIS; + st->codec->codec_id = AV_CODEC_ID_VORBIS; if (srate > 0) { st->codec->sample_rate = srate; @@ -284,19 +313,23 @@ vorbis_header (AVFormatContext * s, int idx) } } else if (os->buf[os->pstart] == 3) { if (os->psize > 8 && - ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 8) >= 0) { + 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; + priv->len[1] = new_len; } } } else { - int ret; - st->codec->extradata_size = - fixup_vorbis_headers(s, priv, &st->codec->extradata); + int ret = fixup_vorbis_headers(s, priv, &st->codec->extradata); + if (ret < 0) { + st->codec->extradata_size = 0; + return ret; + } + st->codec->extradata_size = ret; if ((ret = avpriv_vorbis_parse_extradata(st->codec, &priv->vp))) { av_freep(&st->codec->extradata); st->codec->extradata_size = 0; @@ -315,13 +348,13 @@ static int vorbis_packet(AVFormatContext *s, int idx) int duration; /* first packet handling - here we parse the duration of each packet in the first page and compare - the total duration to the page granule to find the encoder delay and - set the first timestamp */ + * here we parse the duration of each packet in the first page and compare + * the total duration to the page granule to find the encoder delay and + * set the first timestamp */ if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) { int seg, d; - uint8_t *last_pkt = os->buf + os->pstart; - uint8_t *next_pkt = last_pkt; + uint8_t *last_pkt = os->buf + os->pstart; + uint8_t *next_pkt = last_pkt; avpriv_vorbis_parse_reset(&priv->vp); duration = 0; @@ -341,17 +374,18 @@ static int vorbis_packet(AVFormatContext *s, int idx) break; } duration += d; - last_pkt = next_pkt + os->segments[seg]; + last_pkt = next_pkt + os->segments[seg]; } next_pkt += os->segments[seg]; } - os->lastpts = os->lastdts = os->granule - duration; - if(s->streams[idx]->start_time == AV_NOPTS_VALUE) { + os->lastpts = + os->lastdts = os->granule - duration; + if (s->streams[idx]->start_time == AV_NOPTS_VALUE) { s->streams[idx]->start_time = FFMAX(os->lastpts, 0); if (s->streams[idx]->duration) s->streams[idx]->duration -= s->streams[idx]->start_time; } - priv->final_pts = AV_NOPTS_VALUE; + priv->final_pts = AV_NOPTS_VALUE; avpriv_vorbis_parse_reset(&priv->vp); } @@ -366,12 +400,12 @@ static int vorbis_packet(AVFormatContext *s, int idx) } /* final packet handling - here we save the pts of the first packet in the final page, sum up all - packet durations in the final page except for the last one, and compare - to the page granule to find the duration of the final packet */ + * here we save the pts of the first packet in the final page, sum up all + * packet durations in the final page except for the last one, and compare + * to the page granule to find the duration of the final packet */ if (os->flags & OGG_FLAG_EOS) { if (os->lastpts != AV_NOPTS_VALUE) { - priv->final_pts = os->lastpts; + priv->final_pts = os->lastpts; priv->final_duration = 0; } if (os->segp == os->nsegs) @@ -383,10 +417,10 @@ static int vorbis_packet(AVFormatContext *s, int idx) } const struct ogg_codec ff_vorbis_codec = { - .magic = "\001vorbis", + .magic = "\001vorbis", .magicsize = 7, - .header = vorbis_header, - .packet = vorbis_packet, - .cleanup= vorbis_cleanup, + .header = vorbis_header, + .packet = vorbis_packet, + .cleanup = vorbis_cleanup, .nb_header = 3, }; |
