change extradata format for vorbis
authorMåns Rullgård <mans@mansr.com>
Fri, 13 May 2005 18:10:23 +0000 (18:10 +0000)
committerMåns Rullgård <mans@mansr.com>
Fri, 13 May 2005 18:10:23 +0000 (18:10 +0000)
Originally committed as revision 4235 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavcodec/avcodec.h
libavcodec/oggvorbis.c
libavcodec/utils.c
libavformat/matroska.c
libavformat/oggparsevorbis.c

index bb84d15..b9fccc4 100644 (file)
@@ -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
index e5dd106..9a47aee 100644 (file)
@@ -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;
         }
index 3eea9a9..16d00bc 100644 (file)
@@ -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;
+}
index b0c62ad..cc23781 100644 (file)
@@ -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) ||
index 539f80a..877b1a9 100644 (file)
@@ -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;