1 /***************************************************************************
2    \fn  ADMedAVIAUD.cpp
3    \brief Interface to audio track(s) from editor
4 
5     Handle switching from pieces of movie
6     Also fix the gap/overlap in audio to offer a strictly continuous audio stream
7 
8     copyright            : (C) 2008/2009 by mean
9     email                : fixounet@free.fr
10 
11 Todo:
12 -----
13         x Fix handling of overlay/gap, it is wrong.
14 
15 
16  ***************************************************************************/
17 
18 /***************************************************************************
19  *                                                                         *
20  *   This program is free software; you can redistribute it and/or modify  *
21  *   it under the terms of the GNU General Public License as published by  *
22  *   the Free Software Foundation; either version 2 of the License, or     *
23  *   (at your option) any later version.                                   *
24  *                                                                         *
25  ***************************************************************************/
26 
27 #include <string.h>
28 #include "ADM_cpp.h"
29 #include "ADM_default.h"
30 #include <math.h>
31 
32 #include "fourcc.h"
33 #include "ADM_edit.hxx"
34 #include "ADM_edAudioTrackFromVideo.h"
35 #include "ADM_vidMisc.h"
36 
37 #ifdef _MSC_VER
38 #define abs(x) _abs64(x)
39 #endif
40 
41 #if 1
42 #define vprintf(...) {}
43 #else
44 #define vprintf printf
45 #endif
46 /**
47     \fn     getOutputFrequency
48     \brief  Get output fq, 2*wavheader->fq for sbr
49 
50 */
51 
getOutputFrequency(void)52 uint32_t        ADM_edAudioTrackFromVideo::getOutputFrequency(void)
53 {
54     ADM_audioStreamTrack *trk=getCurrentTrack();
55     if(!trk)
56     {
57         ADM_warning("No audio track\n");
58         return 0;
59     }
60     if(!trk->codec)
61         return trk->wavheader.frequency;
62     return trk->codec->getOutputFrequency();
63 }
64 
65 /**
66     \fn getOutputChannels
67     \brief get nb of channels as seen by codec
68 */
getOutputChannels(void)69 uint32_t ADM_edAudioTrackFromVideo::getOutputChannels(void)
70 {
71     ADM_audioStreamTrack *trk=getCurrentTrack();
72     if(!trk)
73     {
74         ADM_warning("No audio track\n");
75         return 0;
76     }
77     if(!trk->codec)
78         return trk->wavheader.channels;
79     return trk->codec->getOutputChannels();
80 }
81 
82 /**
83     \fn     getPCMPacket
84     \brief  Get audio packet
85 
86 */
87 
getPCMPacket(float * dest,uint32_t sizeMax,uint32_t * samples,uint64_t * odts)88 bool ADM_edAudioTrackFromVideo::getPCMPacket(float  *dest, uint32_t sizeMax, uint32_t *samples,uint64_t *odts)
89 {
90 uint32_t fillerSample=0;   // FIXME : Store & fix the DTS error correctly!!!!
91 bool drop=false;
92 bool checkDts;
93 static bool fail=false;
94 uint32_t outFrequency=getOutputFrequency();
95 uint32_t outChannels=getOutputChannels();
96 
97     if(!outChannels) return false;
98 
99  vprintf("[PCMPacket]  request TRK %d:%x\n",myTrackNumber,(long int)getCurrentTrack());
100 again:
101     *samples=0;
102     ADM_audioStreamTrack *trk=getCurrentTrack();
103     if(!trk) return false;
104     if(trk->codec->isDummy()) return false;
105     checkDts=(trk->stream->constantSamplesPerPacket() && !trk->isbr);
106     // Do we already have a packet ?
107     if(!packetBufferSize)
108     {
109         if(!refillPacketBuffer())
110         {
111             if(fail==false)
112               ADM_warning("[Editor] Cannot refill audio\n");
113             fail=true;
114             return false;
115         }
116     }
117     // We do now
118     vprintf("[PCMPacket]  TRK %d Got %d samples, time code %08" PRIu64"  lastDts=%08" PRIu64" delta =%" PRId64"\n",
119                 myTrackNumber,packetBufferSamples,packetBufferDts,lastDts,packetBufferDts-lastDts);
120     fail=false;
121 
122     // Check if the Dts matches
123     if(checkDts && lastDts!=ADM_AUDIO_NO_DTS &&packetBufferDts!=ADM_AUDIO_NO_DTS)
124     {
125         if(labs((int64_t)lastDts-(int64_t)packetBufferDts)>ADM_ALLOWED_DRIFT_US)
126         {
127             printf("[Composer::getPCMPacket] Track %d, %p ", (int)myTrackNumber,trk);
128             printf(": drift %d, computed : %s", (int)(lastDts-packetBufferDts),ADM_us2plain(lastDts));
129             printf(" got %s\n", ADM_us2plain(packetBufferDts));
130             if(packetBufferDts<lastDts)
131             {
132                 printf("[Composer::getPCMPacket] Track %d:%" PRIx64" : Dropping packet %" PRIu32" last =%" PRIu32"\n",myTrackNumber,(uint64_t)trk,(uint32_t)(lastDts/1000),(uint32_t)(packetBufferDts/1000));
133                 drop=true;
134             }else
135             {
136                 // There is a "hole" in audio
137                 // Let's add some filler
138                 // Compute filler size
139                 *odts=lastDts;
140                 float f=packetBufferDts-lastDts; // in us
141                 f*=outFrequency;
142                 f/=1000000.;
143                 // in samples!
144                 uint32_t fillerSample=(uint32_t )(f+0.49);
145                 uint32_t mx=sizeMax/outChannels;
146 
147                 if(mx<fillerSample) fillerSample=mx;
148                 // arbitrary cap, max 4kSample in one go
149                 // about 100 ms
150                 if(fillerSample>4*1024)
151                 {
152                     fillerSample=4*1024;
153                 }
154                 uint32_t start=fillerSample*sizeof(float)*outChannels;
155                 memset(dest,0,start);
156 
157                 advanceDtsByCustomSample(fillerSample,outFrequency);
158                 dest+=fillerSample*outChannels;
159                 *samples=fillerSample;
160                 vprintf("[Composer::getPCMPacket] Track %d:%x  Adding %u padding samples, dts is now %lu\n",
161                             myTrackNumber,(long  int)trk,fillerSample,lastDts);
162                 return true;
163        }
164       }
165     }
166     // If lastDts is not initialized....
167     if(lastDts==ADM_AUDIO_NO_DTS) lastDts=packetBufferDts;
168 
169     //
170     //  The packet is ok, decode it...
171     //
172     uint32_t nbOut=0; // Nb sample as seen by codec
173     if(!trk->codec->run(packetBuffer, packetBufferSize, dest, &nbOut))
174     {
175             packetBufferSize=0; // consume
176             ADM_warning("Track %d at 0x%p : decoding failed\n",myTrackNumber,trk);
177             return false;
178     }
179     packetBufferSize=0; // consume
180 
181     // Compute how much decoded sample to compare with what demuxer said
182     uint32_t decodedSample=nbOut;
183     decodedSample/=outChannels;
184     if(!decodedSample) goto again;
185 #define ADM_MAX_JITTER 5000  // in samples, due to clock accuracy, it can be +er, -er, + er, -er etc etc
186     if(checkDts && labs((int64_t)decodedSample-(int64_t)packetBufferSamples)>ADM_MAX_JITTER)
187     {
188         ADM_warning("[Composer::getPCMPacket] Track %d:%x Demuxer was wrong %d vs %d samples!\n",
189                     myTrackNumber,trk,packetBufferSamples,decodedSample);
190     }
191 
192     // This packet has been dropped (too early packt), try the next one
193     if(drop==true)
194     {
195         // TODO Check if the packet somehow overlaps, i.e. starts too early but finish ok
196         goto again;
197     }
198     // Update infos
199     *samples=(decodedSample);
200     *odts=lastDts;
201     advanceDtsByCustomSample(decodedSample,outFrequency);
202     vprintf("[Composer::getPCMPacket] Track %d:%p Adding %u decoded, Adding %u filler sample, dts is now %" PRIu64", fq: %d\n",
203                     myTrackNumber,trk,decodedSample,fillerSample,lastDts,outFrequency);
204     ADM_assert(sizeMax>=(fillerSample+decodedSample)*outChannels);
205     return true;
206 }
207 
208 
209 //EOF
210 
211