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;