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