• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • 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 "libavutil/dict.h"
00029 #include "libavcodec/get_bits.h"
00030 #include "libavcodec/bytestream.h"
00031 #include "avformat.h"
00032 #include "internal.h"
00033 #include "oggdec.h"
00034 #include "vorbiscomment.h"
00035 
00036 static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val)
00037 {
00038     int i, cnum, h, m, s, ms, keylen = strlen(key);
00039     AVChapter *chapter = NULL;
00040 
00041     if (keylen < 9 || sscanf(key, "CHAPTER%02d", &cnum) != 1)
00042         return 0;
00043 
00044     if (keylen == 9) {
00045         if (sscanf(val, "%02d:%02d:%02d.%03d", &h, &m, &s, &ms) < 4)
00046             return 0;
00047 
00048         avpriv_new_chapter(as, cnum, (AVRational){1,1000},
00049                        ms + 1000*(s + 60*(m + 60*h)),
00050                        AV_NOPTS_VALUE, NULL);
00051         av_free(val);
00052     } else if (!strcmp(key+9, "NAME")) {
00053         for(i = 0; i < as->nb_chapters; i++)
00054             if (as->chapters[i]->id == cnum) {
00055                 chapter = as->chapters[i];
00056                 break;
00057             }
00058         if (!chapter)
00059             return 0;
00060 
00061         av_dict_set(&chapter->metadata, "title", val,
00062                          AV_DICT_DONT_STRDUP_VAL);
00063     } else
00064         return 0;
00065 
00066     av_free(key);
00067     return 1;
00068 }
00069 
00070 int
00071 ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, int size)
00072 {
00073     const uint8_t *p = buf;
00074     const uint8_t *end = buf + size;
00075     unsigned n, j;
00076     int s;
00077 
00078     if (size < 8) /* must have vendor_length and user_comment_list_length */
00079         return -1;
00080 
00081     s = bytestream_get_le32(&p);
00082 
00083     if (end - p - 4 < s || s < 0)
00084         return -1;
00085 
00086     p += s;
00087 
00088     n = bytestream_get_le32(&p);
00089 
00090     while (end - p >= 4 && n > 0) {
00091         const char *t, *v;
00092         int tl, vl;
00093 
00094         s = bytestream_get_le32(&p);
00095 
00096         if (end - p < s || s < 0)
00097             break;
00098 
00099         t = p;
00100         p += s;
00101         n--;
00102 
00103         v = memchr(t, '=', s);
00104         if (!v)
00105             continue;
00106 
00107         tl = v - t;
00108         vl = s - tl - 1;
00109         v++;
00110 
00111         if (tl && vl) {
00112             char *tt, *ct;
00113 
00114             tt = av_malloc(tl + 1);
00115             ct = av_malloc(vl + 1);
00116             if (!tt || !ct) {
00117                 av_freep(&tt);
00118                 av_freep(&ct);
00119                 av_log(as, AV_LOG_WARNING, "out-of-memory error. skipping VorbisComment tag.\n");
00120                 continue;
00121             }
00122 
00123             for (j = 0; j < tl; j++)
00124                 tt[j] = toupper(t[j]);
00125             tt[tl] = 0;
00126 
00127             memcpy(ct, v, vl);
00128             ct[vl] = 0;
00129 
00130             if (!ogm_chapter(as, tt, ct))
00131                 av_dict_set(m, tt, ct,
00132                                    AV_DICT_DONT_STRDUP_KEY |
00133                                    AV_DICT_DONT_STRDUP_VAL);
00134         }
00135     }
00136 
00137     if (p != end)
00138         av_log(as, AV_LOG_INFO, "%ti bytes of comment header remain\n", end-p);
00139     if (n > 0)
00140         av_log(as, AV_LOG_INFO,
00141                "truncated comment header, %i comments not found\n", n);
00142 
00143     ff_metadata_conv(m, NULL, ff_vorbiscomment_metadata_conv);
00144 
00145     return 0;
00146 }
00147 
00148 
00162 struct oggvorbis_private {
00163     unsigned int len[3];
00164     unsigned char *packet[3];
00165 };
00166 
00167 
00168 static unsigned int
00169 fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv,
00170                      uint8_t **buf)
00171 {
00172     int i,offset, len;
00173     unsigned char *ptr;
00174 
00175     len = priv->len[0] + priv->len[1] + priv->len[2];
00176     ptr = *buf = av_mallocz(len + len/255 + 64);
00177 
00178     ptr[0] = 2;
00179     offset = 1;
00180     offset += av_xiphlacing(&ptr[offset], priv->len[0]);
00181     offset += av_xiphlacing(&ptr[offset], priv->len[1]);
00182     for (i = 0; i < 3; i++) {
00183         memcpy(&ptr[offset], priv->packet[i], priv->len[i]);
00184         offset += priv->len[i];
00185         av_freep(&priv->packet[i]);
00186     }
00187     *buf = av_realloc(*buf, offset + FF_INPUT_BUFFER_PADDING_SIZE);
00188     return offset;
00189 }
00190 
00191 
00192 static int
00193 vorbis_header (AVFormatContext * s, int idx)
00194 {
00195     struct ogg *ogg = s->priv_data;
00196     struct ogg_stream *os = ogg->streams + idx;
00197     AVStream *st = s->streams[idx];
00198     struct oggvorbis_private *priv;
00199     int pkt_type = os->buf[os->pstart];
00200 
00201     if (!(pkt_type & 1))
00202         return 0;
00203 
00204     if (!os->private) {
00205         os->private = av_mallocz(sizeof(struct oggvorbis_private));
00206         if (!os->private)
00207             return 0;
00208     }
00209 
00210     if (os->psize < 1 || pkt_type > 5)
00211         return -1;
00212 
00213     priv = os->private;
00214 
00215     if (priv->packet[pkt_type>>1])
00216         return -1;
00217     if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1])
00218         return -1;
00219 
00220     priv->len[pkt_type >> 1] = os->psize;
00221     priv->packet[pkt_type >> 1] = av_mallocz(os->psize);
00222     memcpy(priv->packet[pkt_type >> 1], os->buf + os->pstart, os->psize);
00223     if (os->buf[os->pstart] == 1) {
00224         const uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */
00225         unsigned blocksize, bs0, bs1;
00226         int srate;
00227 
00228         if (os->psize != 30)
00229             return -1;
00230 
00231         if (bytestream_get_le32(&p) != 0) /* vorbis_version */
00232             return -1;
00233 
00234         st->codec->channels = bytestream_get_byte(&p);
00235         srate = bytestream_get_le32(&p);
00236         p += 4; // skip maximum bitrate
00237         st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate
00238         p += 4; // skip minimum bitrate
00239 
00240         blocksize = bytestream_get_byte(&p);
00241         bs0 = blocksize & 15;
00242         bs1 = blocksize >> 4;
00243 
00244         if (bs0 > bs1)
00245             return -1;
00246         if (bs0 < 6 || bs1 > 13)
00247             return -1;
00248 
00249         if (bytestream_get_byte(&p) != 1) /* framing_flag */
00250             return -1;
00251 
00252         st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00253         st->codec->codec_id = CODEC_ID_VORBIS;
00254 
00255         if (srate > 0) {
00256             st->codec->sample_rate = srate;
00257             avpriv_set_pts_info(st, 64, 1, srate);
00258         }
00259     } else if (os->buf[os->pstart] == 3) {
00260         if (os->psize > 8 &&
00261             ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 8) >= 0) {
00262             // drop all metadata we parsed and which is not required by libvorbis
00263             unsigned new_len = 7 + 4 + AV_RL32(priv->packet[1] + 7) + 4 + 1;
00264             if (new_len >= 16 && new_len < os->psize) {
00265                 AV_WL32(priv->packet[1] + new_len - 5, 0);
00266                 priv->packet[1][new_len - 1] = 1;
00267                 priv->len[1] = new_len;
00268             }
00269         }
00270     } else {
00271         st->codec->extradata_size =
00272             fixup_vorbis_headers(s, priv, &st->codec->extradata);
00273     }
00274 
00275     return 1;
00276 }
00277 
00278 const struct ogg_codec ff_vorbis_codec = {
00279     .magic = "\001vorbis",
00280     .magicsize = 7,
00281     .header = vorbis_header
00282 };
Generated on Thu Jan 24 2013 17:08:55 for Libav by doxygen 1.7.1