Libav 0.7.1
|
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 ff_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 av_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 };