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

Generated on Fri Sep 16 2011 17:17:50 for FFmpeg by  doxygen 1.7.1