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