• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/oggparsevorbis.c

Go to the documentation of this file.
00001 
00025 #include <stdlib.h>
00026 #include "libavutil/avstring.h"
00027 #include "libavutil/bswap.h"
00028 #include "libavcodec/bitstream.h"
00029 #include "libavcodec/bytestream.h"
00030 #include "avformat.h"
00031 #include "oggdec.h"
00032 
00033 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) /* must have vendor_length and user_comment_list_length */
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, *ct;
00076 
00077             tt = av_malloc(tl + 1);
00078             ct = av_malloc(vl + 1);
00079             if (!tt || !ct) {
00080                 av_freep(&tt);
00081                 av_freep(&ct);
00082                 av_log(as, AV_LOG_WARNING, "out-of-memory error. skipping VorbisComment tag.\n");
00083                 continue;
00084             }
00085 
00086             for (j = 0; j < tl; j++)
00087                 tt[j] = toupper(t[j]);
00088             tt[tl] = 0;
00089 
00090             memcpy(ct, v, vl);
00091             ct[vl] = 0;
00092 
00093             av_metadata_set(&as->metadata, tt, ct);
00094 
00095             av_freep(&tt);
00096             av_freep(&ct);
00097         }
00098     }
00099 
00100     if (p != end)
00101         av_log(as, AV_LOG_INFO, "%ti bytes of comment header remain\n", p-end);
00102     if (n > 0)
00103         av_log(as, AV_LOG_INFO,
00104                "truncated comment header, %i comments not found\n", n);
00105 
00106     return 0;
00107 }
00108 
00109 
00123 struct oggvorbis_private {
00124     unsigned int len[3];
00125     unsigned char *packet[3];
00126 };
00127 
00128 
00129 static unsigned int
00130 fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv,
00131                      uint8_t **buf)
00132 {
00133     int i,offset, len;
00134     unsigned char *ptr;
00135 
00136     len = priv->len[0] + priv->len[1] + priv->len[2];
00137     ptr = *buf = av_mallocz(len + len/255 + 64);
00138 
00139     ptr[0] = 2;
00140     offset = 1;
00141     offset += av_xiphlacing(&ptr[offset], priv->len[0]);
00142     offset += av_xiphlacing(&ptr[offset], priv->len[1]);
00143     for (i = 0; i < 3; i++) {
00144         memcpy(&ptr[offset], priv->packet[i], priv->len[i]);
00145         offset += priv->len[i];
00146     }
00147     *buf = av_realloc(*buf, offset + FF_INPUT_BUFFER_PADDING_SIZE);
00148     return offset;
00149 }
00150 
00151 
00152 static int
00153 vorbis_header (AVFormatContext * s, int idx)
00154 {
00155     struct ogg *ogg = s->priv_data;
00156     struct ogg_stream *os = ogg->streams + idx;
00157     AVStream *st = s->streams[idx];
00158     struct oggvorbis_private *priv;
00159 
00160     if (os->seq > 2)
00161         return 0;
00162 
00163     if (os->seq == 0) {
00164         os->private = av_mallocz(sizeof(struct oggvorbis_private));
00165         if (!os->private)
00166             return 0;
00167     }
00168 
00169     if (os->psize < 1)
00170         return -1;
00171 
00172     priv = os->private;
00173     priv->len[os->seq] = os->psize;
00174     priv->packet[os->seq] = av_mallocz(os->psize);
00175     memcpy(priv->packet[os->seq], os->buf + os->pstart, os->psize);
00176     if (os->buf[os->pstart] == 1) {
00177         const uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */
00178         unsigned blocksize, bs0, bs1;
00179 
00180         if (os->psize != 30)
00181             return -1;
00182 
00183         if (bytestream_get_le32(&p) != 0) /* vorbis_version */
00184             return -1;
00185 
00186         st->codec->channels = bytestream_get_byte(&p);
00187         st->codec->sample_rate = bytestream_get_le32(&p);
00188         p += 4; // skip maximum bitrate
00189         st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate
00190         p += 4; // skip minimum bitrate
00191 
00192         blocksize = bytestream_get_byte(&p);
00193         bs0 = blocksize & 15;
00194         bs1 = blocksize >> 4;
00195 
00196         if (bs0 > bs1)
00197             return -1;
00198         if (bs0 < 6 || bs1 > 13)
00199             return -1;
00200 
00201         if (bytestream_get_byte(&p) != 1) /* framing_flag */
00202             return -1;
00203 
00204         st->codec->codec_type = CODEC_TYPE_AUDIO;
00205         st->codec->codec_id = CODEC_ID_VORBIS;
00206 
00207         st->time_base.num = 1;
00208         st->time_base.den = st->codec->sample_rate;
00209     } else if (os->buf[os->pstart] == 3) {
00210         if (os->psize > 8)
00211             vorbis_comment (s, os->buf + os->pstart + 7, os->psize - 8);
00212     } else {
00213         st->codec->extradata_size =
00214             fixup_vorbis_headers(s, priv, &st->codec->extradata);
00215     }
00216 
00217     return os->seq < 3;
00218 }
00219 
00220 const struct ogg_codec ff_vorbis_codec = {
00221     .magic = "\001vorbis",
00222     .magicsize = 7,
00223     .header = vorbis_header
00224 };

Generated on Tue Nov 4 2014 12:59:24 for ffmpeg by  doxygen 1.7.1