summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libavcodec/avcodec.h2
-rw-r--r--libavcodec/oggvorbis.c81
-rw-r--r--libavcodec/utils.c14
-rw-r--r--libavformat/matroska.c43
-rw-r--r--libavformat/oggparsevorbis.c50
5 files changed, 122 insertions, 68 deletions
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index bb84d158a3..b9fccc4cff 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -2357,6 +2357,8 @@ extern void av_log_set_callback(void (*)(void*, int, const char*, va_list));
((uint8_t*)(x))[0])
#endif
+extern unsigned int av_xiphlacing(unsigned char *s, unsigned int v);
+
#ifdef __cplusplus
}
#endif
diff --git a/libavcodec/oggvorbis.c b/libavcodec/oggvorbis.c
index e5dd106424..9a47aeec97 100644
--- a/libavcodec/oggvorbis.c
+++ b/libavcodec/oggvorbis.c
@@ -49,6 +49,7 @@ static int oggvorbis_encode_init(AVCodecContext *avccontext) {
OggVorbisContext *context = avccontext->priv_data ;
ogg_packet header, header_comm, header_code;
uint8_t *p;
+ unsigned int offset, len;
vorbis_info_init(&context->vi) ;
if(oggvorbis_init_encoder(&context->vi, avccontext) < 0) {
@@ -64,22 +65,21 @@ static int oggvorbis_encode_init(AVCodecContext *avccontext) {
vorbis_analysis_headerout(&context->vd, &context->vc, &header,
&header_comm, &header_code);
- avccontext->extradata_size= 3*2 + header.bytes + header_comm.bytes + header_code.bytes;
- p= avccontext->extradata= av_mallocz(avccontext->extradata_size);
-
- *(p++) = header.bytes>>8;
- *(p++) = header.bytes&0xFF;
- memcpy(p, header.packet, header.bytes);
- p += header.bytes;
-
- *(p++) = header_comm.bytes>>8;
- *(p++) = header_comm.bytes&0xFF;
- memcpy(p, header_comm.packet, header_comm.bytes);
- p += header_comm.bytes;
-
- *(p++) = header_code.bytes>>8;
- *(p++) = header_code.bytes&0xFF;
- memcpy(p, header_code.packet, header_code.bytes);
+ len = header.bytes + header_comm.bytes + header_code.bytes;
+ avccontext->extradata_size= 64 + len + len/255;
+ p = avccontext->extradata= av_mallocz(avccontext->extradata_size);
+ p[0] = 2;
+ offset = 1;
+ offset += av_xiphlacing(&p[offset], header.bytes);
+ offset += av_xiphlacing(&p[offset], header_comm.bytes);
+ memcpy(&p[offset], header.packet, header.bytes);
+ offset += header.bytes;
+ memcpy(&p[offset], header_comm.packet, header_comm.bytes);
+ offset += header_comm.bytes;
+ memcpy(&p[offset], header_code.packet, header_code.bytes);
+ offset += header_code.bytes;
+ avccontext->extradata_size = offset;
+ avccontext->extradata= av_realloc(avccontext->extradata, avccontext->extradata_size);
/* vorbis_block_clear(&context->vb);
vorbis_dsp_clear(&context->vd);
@@ -184,19 +184,54 @@ AVCodec oggvorbis_encoder = {
static int oggvorbis_decode_init(AVCodecContext *avccontext) {
OggVorbisContext *context = avccontext->priv_data ;
uint8_t *p= avccontext->extradata;
- int i;
+ int i, hsizes[3];
+ unsigned char *headers[3], *extradata = avccontext->extradata;
+ unsigned int offset;
vorbis_info_init(&context->vi) ;
vorbis_comment_init(&context->vc) ;
+ if(! avccontext->extradata_size || ! p) {
+ av_log(avccontext, AV_LOG_ERROR, "vorbis extradata absent\n");
+ return -1;
+ }
+ if(*p != 2) {
+ av_log(avccontext, AV_LOG_ERROR,
+ "vorbis initial header len is wrong: %d\n", *p);
+ return -1;
+ }
+ offset = 1;
+ p++;
+ for(i=0; i<2; i++) {
+ hsizes[i] = 0;
+ while((*p == 0xFF) && (offset < avccontext->extradata_size)) {
+ hsizes[i] += 0xFF;
+ offset++;
+ p++;
+ }
+ if(offset >= avccontext->extradata_size - 1) {
+ av_log(avccontext, AV_LOG_ERROR, "vorbis header sizes damaged\n");
+ return -1;
+ }
+ hsizes[i] += *p;
+ offset++;
+ p++;
+ }
+ hsizes[2] = avccontext->extradata_size - hsizes[0] - hsizes[1] - offset;
+#if 0
+ av_log(avccontext, AV_LOG_DEBUG,
+ "vorbis header sizes: %d, %d, %d, / extradata_len is %d \n",
+ hsizes[0], hsizes[1], hsizes[2], avccontext->extradata_size);
+#endif
+ headers[0] = extradata + offset;
+ headers[1] = extradata + offset + hsizes[0];
+ headers[2] = extradata + offset + hsizes[0] + hsizes[1];
+
for(i=0; i<3; i++){
context->op.b_o_s= i==0;
- context->op.bytes= *(p++)<<8;
- context->op.bytes+=*(p++);
- context->op.packet= p;
- p += context->op.bytes;
-
- if(vorbis_synthesis_headerin(&context->vi, &context->vc, &context->op)<0){
+ context->op.bytes = hsizes[i];
+ context->op.packet = headers[i];
+ if(vorbis_synthesis_headerin(&context->vi, &context->vc, &context->op)<0){
av_log(avccontext, AV_LOG_ERROR, "%d. vorbis header damaged\n", i+1);
return -1;
}
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 3eea9a962f..16d00bc33a 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -1015,3 +1015,17 @@ int avcodec_thread_init(AVCodecContext *s, int thread_count){
return -1;
}
#endif
+
+unsigned int av_xiphlacing(unsigned char *s, unsigned int v)
+{
+ unsigned int n = 0;
+
+ while(v >= 0xff) {
+ *s++ = 0xff;
+ v -= 0xff;
+ n++;
+ }
+ *s = v;
+ n++;
+ return n;
+}
diff --git a/libavformat/matroska.c b/libavformat/matroska.c
index b0c62ad882..cc23781d85 100644
--- a/libavformat/matroska.c
+++ b/libavformat/matroska.c
@@ -2243,44 +2243,13 @@ matroska_read_header (AVFormatContext *s,
/* codec_id = CODEC_ID_DTS; */
else if (!strcmp(track->codec_id,
MATROSKA_CODEC_ID_AUDIO_VORBIS)) {
- unsigned char *p = track->codec_priv, *cdp;
- int cps = track->codec_priv_size;
- int nf, s[3], cds;
- int i;
-
- nf = *p++;
- cps--;
-
- if(nf != 2)
- continue;
-
- for(i = 0; i < 2; i++){
- int xv;
- s[i] = 0;
- do {
- xv = *p++;
- s[i] += xv;
- cps--;
- } while(xv == 255);
+ extradata_size = track->codec_priv_size;
+ if(extradata_size) {
+ extradata = av_malloc(extradata_size);
+ if(extradata == NULL)
+ return AVERROR_NOMEM;
+ memcpy(extradata, track->codec_priv, extradata_size);
}
-
- s[2] = cps - s[0] - s[1];
-
- cds = cps + 6;
- extradata = cdp = av_malloc(cds);
- if(extradata == NULL)
- return AVERROR_NOMEM;
- extradata_size = cds;
-
- for(i = 0; i < 3; i++){
- *cdp++ = s[i] >> 8;
- *cdp++ = s[i] & 0xff;
- memcpy(cdp, p, s[i]);
- cdp += s[i];
- p += s[i];
- cps -= s[i];
- }
-
codec_id = CODEC_ID_VORBIS;
} else if (!strcmp(track->codec_id,
MATROSKA_CODEC_ID_AUDIO_MPEG2) ||
diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c
index 539f80ab94..877b1a9a8a 100644
--- a/libavformat/oggparsevorbis.c
+++ b/libavformat/oggparsevorbis.c
@@ -126,25 +126,56 @@ vorbis_comment (AVFormatContext * as, char *buf, int size)
* [framing_flag] = read one bit | Not Used
* */
+typedef struct {
+ unsigned int len[3];
+ unsigned char *packet[3];
+} oggvorbis_private_t;
+
+
+static unsigned int
+fixup_vorbis_headers(AVFormatContext * as, oggvorbis_private_t *priv,
+ void **buf)
+{
+ int i,offset, len;
+ unsigned char *ptr;
+
+ len = priv->len[0] + priv->len[1] + priv->len[2];
+ ptr = *buf = av_mallocz(len + len/255 + 64);
+
+ ptr[0] = 2;
+ offset = 1;
+ offset += av_xiphlacing(&ptr[offset], priv->len[0]);
+ offset += av_xiphlacing(&ptr[offset], priv->len[1]);
+ for(i = 0; i < 3; i++) {
+ memcpy(&ptr[offset], priv->packet[i], priv->len[i]);
+ offset += priv->len[i];
+ }
+ *buf = av_realloc(*buf, offset);
+ return offset;
+}
+
+
static int
vorbis_header (AVFormatContext * s, int idx)
{
ogg_t *ogg = s->priv_data;
ogg_stream_t *os = ogg->streams + idx;
AVStream *st = s->streams[idx];
- int cds = st->codec.extradata_size + os->psize + 2;
- uint8_t *cdp;
+ oggvorbis_private_t *priv;
if (os->seq > 2)
return 0;
- st->codec.extradata = av_realloc (st->codec.extradata, cds);
- cdp = st->codec.extradata + st->codec.extradata_size;
- *cdp++ = os->psize >> 8;
- *cdp++ = os->psize & 0xff;
- memcpy (cdp, os->buf + os->pstart, os->psize);
- st->codec.extradata_size = cds;
+ if(os->seq == 0) {
+ os->private = av_mallocz(sizeof(oggvorbis_private_t));
+ if(!os->private)
+ return 0;
+ }
+ priv = os->private;
+ priv->len[os->seq] = os->psize;
+ priv->packet[os->seq] = av_mallocz(os->psize);
+ memcpy(priv->packet[os->seq], os->buf + os->pstart, os->psize);
if (os->buf[os->pstart] == 1) {
uint8_t *p = os->buf + os->pstart + 11; //skip up to the audio channels
st->codec.channels = *p++;
@@ -157,6 +188,9 @@ vorbis_header (AVFormatContext * s, int idx)
} else if (os->buf[os->pstart] == 3) {
vorbis_comment (s, os->buf + os->pstart + 7, os->psize - 8);
+ } else {
+ st->codec.extradata_size =
+ fixup_vorbis_headers(s, priv, &st->codec.extradata);
}
return os->seq < 3;