1 /***************************************************************************
2 \file audiofilter_encoder.cpp
3 \brief Generate a access class = to the output of encoder + filterchain
4 (c) 2006 Mean , fixounet@free.fr
5 ***************************************************************************/
6
7 /***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16
17 #include "ADM_cpp.h"
18 using std::string;
19 #include "ADM_default.h"
20 #include "ADM_edit.hxx"
21 #include "ADM_vidMisc.h"
22 #include "ADM_ptrQueue.h"
23 #include "ADM_audioClock.h"
24 #include <math.h>
25
26 #if 1
27 #define changeState(x) {state=StreamCopy##x;}
28 #define aprintf(...) {}
29 #else
30 #define changeState(x) {printf("Changing state from %d to %d\n",state,StreamCopy##x);state=StreamCopy##x;}
31 #define aprintf ADM_info
32 #endif
33
34 extern ADM_Composer *video_body;
35 #define MAX_SKEW 80000
36 #define MIN_SKEW 10000
37 /**
38 \fn ADM_audioStream
39 \brief Base class for audio stream
40
41 */
42 class ADM_audioStreamCopy : public ADM_audioStream
43 {
44 protected:
45 ADM_audioStream *in;
46 uint64_t startTime;
47 int64_t shift;
48 public:
49 ADM_audioStreamCopy(ADM_audioStream *input,uint64_t startTime, int64_t shift);
50 virtual ~ADM_audioStreamCopy();
getInfo(void)51 virtual WAVHeader *getInfo(void) {return in->getInfo();};
52 virtual uint8_t getPacket(uint8_t *buffer,uint32_t *size, uint32_t sizeMax,uint32_t *nbSample,uint64_t *dts);
53 virtual bool getExtraData(uint32_t *l, uint8_t **d);
54 uint64_t getDurationInUs(void);
55 bool isCBR();
56 };
57 /**
58 \class ADM_audioStreamCopyPerfect
59 */
60 class ADM_audioStreamCopyPerfect : public ADM_audioStreamCopy
61 {
62 protected:
63 /**
64 * \class perfectAudioPacket
65 */
66 class perfectAudioPacket
67 {
68 protected:
69 uint64_t dts;
70 uint32_t size;
71 uint32_t samples;
72 uint8_t *data;
73 public:
perfectAudioPacket(uint8_t * data,uint32_t size,uint64_t dts,uint32_t samples)74 perfectAudioPacket(uint8_t *data, uint32_t size, uint64_t dts, uint32_t samples)
75 {
76 this->data=new uint8_t[size];
77 memcpy(this->data,data,size);
78 this->size=size;
79 this->samples=samples;
80 this->dts=dts;
81 }
~perfectAudioPacket()82 ~perfectAudioPacket()
83 {
84 delete [] data;
85 data=NULL;
86 size=0;
87 };
clone(uint8_t * dst,uint32_t * s,uint64_t * d,uint32_t * sam)88 bool clone(uint8_t *dst, uint32_t *s, uint64_t *d, uint32_t *sam)
89 {
90 memcpy(dst,data,size);
91 *s=size;
92 *d=dts;
93 *sam=samples;
94 return true;
95 }
96 };
97 protected:
98 typedef enum
99 {
100 StreamCopyIdle,StreamCopyDuping,StreamCopyFlushing
101 }StreamCopyState;
102 // Needed for duplication
103 ADM_ptrQueue <perfectAudioPacket> audioQueue;
104 audioClock *clock;
105 uint64_t nextDts;
106 StreamCopyState state;
107 uint32_t channels;
dupePacket(uint8_t * data,uint32_t size,uint32_t nbSamples,uint64_t dts)108 bool dupePacket(uint8_t *data, uint32_t size, uint32_t nbSamples, uint64_t dts)
109 {
110 perfectAudioPacket *packet=new perfectAudioPacket(data,size,dts,nbSamples);
111 audioQueue.pushBack(packet);
112 return true;
113 }
popBackPacket(uint8_t * data,uint32_t * size,uint32_t * nbSample,uint64_t * dts)114 bool popBackPacket(uint8_t *data, uint32_t *size, uint32_t *nbSample,uint64_t *dts)
115 {
116 perfectAudioPacket *p= audioQueue.pop();
117 ADM_assert(p);
118 p->clone(data,size,dts,nbSample);
119 delete p;
120 return true;
121 }
122 public:
123
124 ADM_audioStreamCopyPerfect(ADM_audioStream *input,uint64_t startTime, int64_t shift);
125 ~ADM_audioStreamCopyPerfect();
126 virtual uint8_t getPacket(uint8_t *buffer,uint32_t *size, uint32_t sizeMax,uint32_t *nbSample,uint64_t *dts);
127 };
128
129 /**
130 * \fn dtor
131 */
~ADM_audioStreamCopy()132 ADM_audioStreamCopy::~ADM_audioStreamCopy()
133 {
134 }
135 // Pass Through class, just do the timing
136 /**
137 * \fn ctor
138 * @param input
139 * @param startTime
140 * @param shift
141 * @param needPerfectAudio
142 */
ADM_audioStreamCopy(ADM_audioStream * input,uint64_t startTime,int64_t shift)143 ADM_audioStreamCopy::ADM_audioStreamCopy(ADM_audioStream *input,uint64_t startTime, int64_t shift) :
144 ADM_audioStream(NULL,NULL)
145 {
146 ADM_info("Creating copy stream, startTime=%s, shift=%d\n",
147 ADM_us2plain(startTime),(int)shift);
148 in=input;
149 this->startTime=startTime;
150 in->goToTime(startTime);
151 this->shift=shift;
152 setLanguage(input->getLanguage());
153
154 }
155 /**
156 * \fn isCBR
157 * @return
158 */
isCBR()159 bool ADM_audioStreamCopy::isCBR()
160 {
161 return in->isCBR();
162 }
163 /**
164 * getExtraData
165 * @param l
166 * @param d
167 * @return
168 */
getExtraData(uint32_t * l,uint8_t ** d)169 bool ADM_audioStreamCopy::getExtraData(uint32_t *l, uint8_t **d)
170 {
171 return in->getExtraData(l,d);
172 }
173 /**
174 * \fn getDurationInUs
175 * @return
176 */
getDurationInUs(void)177 uint64_t ADM_audioStreamCopy::getDurationInUs(void)
178 {
179 return in->getDurationInUs();
180 }
181 /**
182 * \fn getPacket
183 * @param buffer
184 * @param size
185 * @param sizeMax
186 * @param nbSample
187 * @param dts
188 * @return
189 */
getPacket(uint8_t * buffer,uint32_t * size,uint32_t sizeMax,uint32_t * nbSample,uint64_t * dts)190 uint8_t ADM_audioStreamCopy::getPacket(uint8_t *buffer,uint32_t *size, uint32_t sizeMax,uint32_t *nbSample,uint64_t *dts)
191 {
192
193 again:
194 if(false==in->getPacket(buffer,size,sizeMax,nbSample,dts))
195 {
196 // done processing that
197 return false;
198 }
199 if(*dts!=ADM_NO_PTS)
200 {
201 int64_t corrected=*dts;
202 corrected+=shift;
203 if(corrected<(int64_t)startTime) goto again; // cant have <0 dts
204 *dts=corrected-startTime;
205 }
206 return true;
207
208 }
209 /**
210 \fn audioCreateCopyStream
211 */
audioCreateCopyStream(uint64_t startTime,int32_t shift,ADM_audioStream * input,bool needPerfectAudio)212 ADM_audioStream *audioCreateCopyStream(uint64_t startTime,int32_t shift,ADM_audioStream *input,bool needPerfectAudio)
213 {
214 shift*=-1000; // ms -> us
215 // fixup startTime and shift
216 if(shift>0)
217 {
218 startTime+=shift;
219 shift=0;
220 }
221 else
222 { // shift <0
223 int64_t comp=-shift;
224 if(comp<startTime)
225 {
226 startTime-=comp;
227 shift=0;
228 }else
229 {
230 shift=comp-startTime;
231 startTime=0;
232 }
233 }
234 ADM_info("Creating audio stream copy with compensation : startTime=%s\n",ADM_us2plain(startTime));
235 ADM_info("and shift =%s\n",ADM_us2plain(shift));
236 bool canRelyOnAudioDts=true;
237 if(input->getInfo()->encoding==WAV_WMA)
238 canRelyOnAudioDts=false;
239 if(needPerfectAudio && canRelyOnAudioDts)
240 return new ADM_audioStreamCopyPerfect(input,startTime,shift);
241 else
242 return new ADM_audioStreamCopy(input,startTime,shift);
243 }
244 /**
245 * \fn ctor
246 * @param input
247 * @param startTime
248 * @param shift
249 * @param needPerfectAudio
250 */
ADM_audioStreamCopyPerfect(ADM_audioStream * input,uint64_t startTime,int64_t shift)251 ADM_audioStreamCopyPerfect::ADM_audioStreamCopyPerfect(ADM_audioStream *input,uint64_t startTime, int64_t shift) :
252 ADM_audioStreamCopy(input,startTime,shift)
253 {
254 ADM_info("Creating Perfect copy stream, startTime=%s, shift=%d\n",
255 ADM_us2plain(startTime),(int)shift);
256
257 state=StreamCopyIdle;
258 clock=new audioClock(in->getInfo()->frequency);
259 channels=in->getInfo()->channels;
260 nextDts=0;
261 }
262 /**
263 * \fn dtor
264 */
~ADM_audioStreamCopyPerfect()265 ADM_audioStreamCopyPerfect::~ADM_audioStreamCopyPerfect()
266 {
267 if(clock)
268 {
269 delete clock;
270 clock=NULL;
271 }
272 // empty queue
273 }
274 /**
275 * \fn getPacket
276 * @param buffer
277 * @param size
278 * @param sizeMax
279 * @param nbSample
280 * @param dts
281 * @return
282 */
getPacket(uint8_t * buffer,uint32_t * size,uint32_t sizeMax,uint32_t * nbSample,uint64_t * dts)283 uint8_t ADM_audioStreamCopyPerfect::getPacket(uint8_t *buffer,uint32_t *size, uint32_t sizeMax,
284 uint32_t *nbSample,uint64_t *dts)
285 {
286
287 again:
288 if(state==StreamCopyFlushing)
289 {
290
291 if(audioQueue.isEmpty())
292 {
293 changeState(Idle);
294 aprintf("Flushed\n");
295 goto again;;
296 }
297 bool r=popBackPacket(buffer, size, nbSample, dts);//int8_t *data, uint32_t *size, uint32_t *nbSample,uint64_t *dts
298 *dts=clock->getTimeUs();
299 clock->advanceBySample(*nbSample);
300 aprintf("Flushing time=%d\n",*dts);
301 return r;
302 }
303 // if we can't get an new packet...
304 if(false==in->getPacket(buffer,size,sizeMax,nbSample,dts))
305 {
306 switch(state)
307 {
308 case StreamCopyDuping:
309 {
310 state=StreamCopyFlushing;
311 goto again;
312 break;
313 }
314
315 case StreamCopyIdle:
316 // done processing that
317 return false;
318 break;
319 default: ADM_assert(0);break;
320 }
321 }
322
323 // Either we are duping or just passing data around
324 // fix up the DTS..
325 if(*dts!=ADM_NO_PTS)
326 {
327 int64_t fixup=*dts;
328 fixup+=shift;
329 if(fixup < (int64_t)startTime) goto again ; // too early...
330 fixup-=startTime;
331 *dts=(uint64_t)fixup;
332 }else
333 {
334 *dts=clock->getTimeUs();
335 }
336 aprintf("[PerfectAudio] target=%d current=%d\n",(int)clock->getTimeUs(),(int)*dts);
337 switch(state)
338 {
339 case StreamCopyIdle:
340 {
341 uint64_t targetTime=clock->getTimeUs();
342 int skew=(int) fabs((double)*dts-(double)targetTime);
343 aprintf("Skew= %d\n",skew);
344 if(skew>MIN_SKEW)
345 {
346 ADM_warning("[PerfectAudio]Warning skew of %d us\n",skew);
347 ADM_warning("[PerfectAudio]Warning target=%d current=%d\n",(int)targetTime,*dts);
348 }
349 if(skew<MAX_SKEW)
350 {
351
352 *dts=targetTime; // correct some varying around ideal value
353 clock->advanceBySample(*nbSample);
354 aprintf("copying : Dts=%d\n",(int)*dts);
355 return true;
356 }
357 if(*dts<targetTime)
358 {
359 // in the past, drop
360 ADM_warning("Audio packet in the past, dropping\n");
361 goto again;
362 }
363 // in the future
364
365 nextDts=*dts;
366 changeState(Duping);
367 dupePacket(buffer,*size,*nbSample,*dts);
368 *dts=clock->getTimeUs();
369 clock->advanceBySample(*nbSample);
370 aprintf("In the future, dts=%d, syncDts=%d\n",*dts,nextDts);
371 return true;
372 }
373 break;
374 case StreamCopyDuping:
375 {
376 uint64_t currentClock=clock->getTimeUs();
377 aprintf("Duping clockDts=%d, syncDts=%d\n",currentClock,nextDts);
378 if( (fabs((double)nextDts-(double)currentClock)<MIN_SKEW) || (currentClock>nextDts) )
379 {
380 aprintf("Close enough..\n");
381 changeState(Flushing);
382 }
383 dupePacket(buffer,*size,*nbSample,*dts);
384 *dts=currentClock;
385 clock->advanceBySample(*nbSample);
386 return true;
387 }
388 break;
389 case StreamCopyFlushing:
390 {
391 if(audioQueue.isEmpty())
392 {
393 changeState(Idle);
394 goto again;
395 }
396 bool r=popBackPacket(buffer, size, nbSample, dts);
397 *dts=clock->getTimeUs();
398 clock->advanceBySample(*nbSample);
399 return r;
400 }
401 break;
402 default: ADM_assert(0);break;
403 }
404 return true;
405
406 }
407 // EOF
408