00001
00025 #include <stdlib.h>
00026 #include "avformat.h"
00027 #include "bitstream.h"
00028 #include "bytestream.h"
00029 #include "bswap.h"
00030 #include "oggdec.h"
00031 #include "avstring.h"
00032
00033 extern int
00034 vorbis_comment(AVFormatContext * as, uint8_t *buf, int size)
00035 {
00036 const uint8_t *p = buf;
00037 const uint8_t *end = buf + size;
00038 unsigned s, n, j;
00039
00040 if (size < 8)
00041 return -1;
00042
00043 s = bytestream_get_le32(&p);
00044
00045 if (end - p < s)
00046 return -1;
00047
00048 p += s;
00049
00050 n = bytestream_get_le32(&p);
00051
00052 while (p < end && n > 0) {
00053 const char *t, *v;
00054 int tl, vl;
00055
00056 s = bytestream_get_le32(&p);
00057
00058 if (end - p < s)
00059 break;
00060
00061 t = p;
00062 p += s;
00063 n--;
00064
00065 v = memchr(t, '=', s);
00066 if (!v)
00067 continue;
00068
00069 tl = v - t;
00070 vl = s - tl - 1;
00071 v++;
00072
00073 if (tl && vl) {
00074 char tt[tl + 1];
00075 char ct[vl + 1];
00076
00077 for (j = 0; j < tl; j++)
00078 tt[j] = toupper(t[j]);
00079 tt[tl] = 0;
00080
00081 memcpy(ct, v, vl);
00082 ct[vl] = 0;
00083
00084
00085 if (!strcmp(tt, "AUTHOR") || !strcmp(tt, "ARTIST"))
00086 av_strlcpy(as->author, ct, sizeof(as->author));
00087 else if (!strcmp(tt, "TITLE"))
00088 av_strlcpy(as->title, ct, sizeof(as->title));
00089 else if (!strcmp(tt, "COPYRIGHT"))
00090 av_strlcpy(as->copyright, ct, sizeof(as->copyright));
00091 else if (!strcmp(tt, "DESCRIPTION"))
00092 av_strlcpy(as->comment, ct, sizeof(as->comment));
00093 else if (!strcmp(tt, "GENRE"))
00094 av_strlcpy(as->genre, ct, sizeof(as->genre));
00095 else if (!strcmp(tt, "TRACKNUMBER"))
00096 as->track = atoi(ct);
00097 else if (!strcmp(tt, "ALBUM"))
00098 av_strlcpy(as->album, ct, sizeof(as->album));
00099 }
00100 }
00101
00102 if (p != end)
00103 av_log(as, AV_LOG_INFO, "%ti bytes of comment header remain\n", p-end);
00104 if (n > 0)
00105 av_log(as, AV_LOG_INFO,
00106 "truncated comment header, %i comments not found\n", n);
00107
00108 return 0;
00109 }
00110
00111
00125 typedef struct {
00126 unsigned int len[3];
00127 unsigned char *packet[3];
00128 } oggvorbis_private_t;
00129
00130
00131 static unsigned int
00132 fixup_vorbis_headers(AVFormatContext * as, oggvorbis_private_t *priv,
00133 uint8_t **buf)
00134 {
00135 int i,offset, len;
00136 unsigned char *ptr;
00137
00138 len = priv->len[0] + priv->len[1] + priv->len[2];
00139 ptr = *buf = av_mallocz(len + len/255 + 64);
00140
00141 ptr[0] = 2;
00142 offset = 1;
00143 offset += av_xiphlacing(&ptr[offset], priv->len[0]);
00144 offset += av_xiphlacing(&ptr[offset], priv->len[1]);
00145 for (i = 0; i < 3; i++) {
00146 memcpy(&ptr[offset], priv->packet[i], priv->len[i]);
00147 offset += priv->len[i];
00148 }
00149 *buf = av_realloc(*buf, offset);
00150 return offset;
00151 }
00152
00153
00154 static int
00155 vorbis_header (AVFormatContext * s, int idx)
00156 {
00157 ogg_t *ogg = s->priv_data;
00158 ogg_stream_t *os = ogg->streams + idx;
00159 AVStream *st = s->streams[idx];
00160 oggvorbis_private_t *priv;
00161
00162 if (os->seq > 2)
00163 return 0;
00164
00165 if (os->seq == 0) {
00166 os->private = av_mallocz(sizeof(oggvorbis_private_t));
00167 if (!os->private)
00168 return 0;
00169 }
00170
00171 if (os->psize < 1)
00172 return -1;
00173
00174 priv = os->private;
00175 priv->len[os->seq] = os->psize;
00176 priv->packet[os->seq] = av_mallocz(os->psize);
00177 memcpy(priv->packet[os->seq], os->buf + os->pstart, os->psize);
00178 if (os->buf[os->pstart] == 1) {
00179 const uint8_t *p = os->buf + os->pstart + 7;
00180 unsigned blocksize, bs0, bs1;
00181
00182 if (os->psize != 30)
00183 return -1;
00184
00185 if (bytestream_get_le32(&p) != 0)
00186 return -1;
00187
00188 st->codec->channels = bytestream_get_byte(&p);
00189 st->codec->sample_rate = bytestream_get_le32(&p);
00190 p += 4;
00191 st->codec->bit_rate = bytestream_get_le32(&p);
00192 p += 4;
00193
00194 blocksize = bytestream_get_byte(&p);
00195 bs0 = blocksize & 15;
00196 bs1 = blocksize >> 4;
00197
00198 if (bs0 > bs1)
00199 return -1;
00200 if (bs0 < 6 || bs1 > 13)
00201 return -1;
00202
00203 if (bytestream_get_byte(&p) != 1)
00204 return -1;
00205
00206 st->codec->codec_type = CODEC_TYPE_AUDIO;
00207 st->codec->codec_id = CODEC_ID_VORBIS;
00208
00209 st->time_base.num = 1;
00210 st->time_base.den = st->codec->sample_rate;
00211 } else if (os->buf[os->pstart] == 3) {
00212 if (os->psize > 8)
00213 vorbis_comment (s, os->buf + os->pstart + 7, os->psize - 8);
00214 } else {
00215 st->codec->extradata_size =
00216 fixup_vorbis_headers(s, priv, &st->codec->extradata);
00217 }
00218
00219 return os->seq < 3;
00220 }
00221
00222 ogg_codec_t vorbis_codec = {
00223 .magic = "\001vorbis",
00224 .magicsize = 7,
00225 .header = vorbis_header
00226 };