Libav
|
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 };