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