1 /**
2     \file  ADM_audioXiphUtils
3     \brief Xiph lacing utilities
4 
5     \author copyright            : (C) 2016 by mean
6  ***************************************************************************/
7 
8 /***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  ***************************************************************************/
16 
17 #include "ADM_default.h"
18 #include "ADM_audiodef.h"
19 #include "ADM_audioCodecEnum.h"
20 #include "ADM_audioIdentify.h"
21 #include "fourcc.h"
22 #include "ADM_audioXiphUtils.h"
23 
24 /**
25  *
26  * @param hd
27  * @return
28  */
xypheLacingRead(uint8_t ** hd)29 static int xypheLacingRead(uint8_t **hd)
30 {
31       int x=0;
32       uint8_t *p=*hd;
33       while(*p==0xff)
34       {
35         x+=0xff;
36         p++;
37       }
38       x+=*p;
39       p++;
40       *hd=p;
41       return x;
42 }
43 
44 
45 
46 
47 namespace ADMXiph
48 {
49 #define HEADER_LEN (4*3)
50 
51 
52 /**
53     \fn xiphExtraData2Adm
54     \brief reformat vorbis extra data to avidemux style
55 */
56 /*
57   The private data contains the first three Vorbis packet in order. The lengths of the packets precedes them. The actual layout is:
58 Byte 1: number of distinct packets '#p' minus one inside the CodecPrivate block. This should be '2' for current Vorbis headers.
59 Bytes 2..n: lengths of the first '#p' packets, coded in Xiph-style lacing. The length of the last packet is the length of the CodecPrivate block minus the lengths coded in these bytes minus one.
60 Bytes n+1..: The Vorbis identification header, followed by the Vorbis comment header followed by the codec setup header.
61 */
62 
xiphExtraData2Adm(uint8_t * extraData,int extraLen,uint8_t ** newExtra,int * newExtraLen)63 bool xiphExtraData2Adm(uint8_t *extraData, int extraLen,uint8_t **newExtra,int *newExtraLen)
64 {
65   *newExtra=NULL;
66   *newExtraLen=0;
67   if(!extraData)
68       return false;
69   uint8_t *oldata=extraData;
70   int oldlen=extraLen;
71   int len1,len2,len3;
72   uint8_t *head;
73       if(*oldata!=2) // 3 packets -1 = 2
74       {
75           ADM_warning("[MKV] weird vorbis audio, expect problems\n");
76           return false;
77       }
78       // First packet length
79       head=oldata+1;
80 
81       len1=xypheLacingRead(&head);
82       len2=xypheLacingRead(&head);
83 
84       int consumed=head-oldata;
85       len3=oldlen-consumed; // left in extradata
86 
87       if(len3<0)
88       {
89         ADM_warning("Error in vorbis header, len3 too small %d %d / %d\n",len1,len2,len3);
90         return false;
91       }
92       len3-=(len1+len2);
93       ADM_info("Found packets len : %d- %d- %d, total size %d\n",len1,len2,len3,oldlen);
94       // Now build our own packet...
95       // Allocate uint32 for alignment purpose
96 
97       uint32_t *buffer=new uint32_t[3+(4+len1+len2+len3)/4];
98       uint32_t nwlen=len1+len2+len3+sizeof(uint32_t)*3; // in bytes
99 
100       uint8_t *cp=(uint8_t *)(buffer+3); // data part
101       memcpy(cp,head,len1);
102       cp+=len1;head+=len1;
103 
104       memcpy(cp,head,len2);
105       cp+=len2;head+=len2;
106 
107       memcpy(cp,head,len3);
108 
109       buffer[0]=len1;
110       buffer[1]=len2;
111       buffer[2]=len3;
112       // Destroy old datas
113       *newExtra=(uint8_t *)(buffer);
114       *newExtraLen=nwlen;
115   return true;
116 }
117 
118 
119 /**
120  *  \fn extraData2packets
121  *  \brief converts adm extradata to 3 packets
122  */
admExtraData2packets(uint8_t * extraData,int extraLen,uint8_t ** packs,int * packLen)123 bool admExtraData2packets(uint8_t *extraData, int extraLen,uint8_t **packs,int *packLen)
124 {
125 
126   uint32_t *ptr=(uint32_t *)extraData;
127   int sum=0;
128   for(int i=0;i<3;i++)
129   {
130       packLen[i]=ptr[i];
131       sum+=ptr[i];
132   }
133   if((sum+HEADER_LEN)!=extraLen)
134   {
135       ADM_warning("Incorrect xiph extra data (%d vs %d)\n",sum+HEADER_LEN,extraLen);
136       return false;
137   }
138   extraData+=HEADER_LEN;
139 
140 
141   packs[0]=extraData;
142   packs[1]=extraData+packLen[0];
143   packs[2]=extraData+packLen[0]+packLen[1];
144   return true;
145 }
146 
147 
148 /**
149  * \fn admExtraData2xiph
150  * \brief convert adm extradata to xiph extradata
151  * @param l
152  * @param src
153  * @param dst
154  * @return
155  */
admExtraData2xiph(int l,uint8_t * src,uint8_t * dstOrg)156 int admExtraData2xiph(int l, uint8_t *src, uint8_t *dstOrg)
157 {
158     int length[3],total=0;
159     uint8_t *dst=dstOrg;
160     ADM_info("insize=%d\n",l);
161     *dst++=0x2;
162     for(int i=0;i<3;i++)
163     {
164         total+=length[i]=(src[3]<<24)+(src[2]<<16)+(src[1]<<8)+src[0];
165         if(total>l)
166         {
167             ADM_warning("Invalid data found: sum of packet lengths %d exceeds input size %d\n",total,l);
168             return 0;
169         }
170         src+=4;
171         //printf("Packet %d size %d\n",i,length[i]);
172         // encode length
173         if(i!=2)
174         {
175             int encode=length[i];
176             while(encode>=255)
177             {
178                 *dst++=0xff;
179                 encode-=0xff;
180             }
181             *dst++=encode;
182         }
183     }
184     // now copy blocks
185     for(int i=0;i<3;i++)
186     {
187         int block=length[i];
188         memcpy(dst,src,block);
189         src+=block;
190         dst+=block;
191     }
192     int outSize= (int)(dst-dstOrg);
193     ADM_info("OutSize=%d\n",outSize);
194     return outSize;
195 }
196 
197 
198 
199 
200 }
201