1 /**********************************************************************
2             \file            muxerMp4v2
3             \brief           libmp4v2 muxer
4                              -------------------
5 
6     copyright            : (C) 2011 by mean
7     email                : fixounet@free.fr
8     Strongly inspired by handbrake code
9 
10  ***************************************************************************/
11 
12 /***************************************************************************
13  *                                                                         *
14  *   This program is free software; you can redistribute it and/or modify  *
15  *   it under the terms of the GNU General Public License as published by  *
16  *   the Free Software Foundation; either version 2 of the License, or     *
17  *   (at your option) any later version.                                   *
18  *                                                                         *
19  ***************************************************************************/
20 
21 #include "ADM_default.h"
22 #include "fourcc.h"
23 #include "muxerMp4v2.h"
24 #include "ADM_codecType.h"
25 #include "ADM_imageFlags.h"
26 #include "ADM_vidMisc.h"
27 #if 1
28 #define aprintf(...) {}
29 #define bprintf(...) {} // ADM_info
30 #define MP4_DEBUG 0
31 #else
32 #define aprintf ADM_info
33 #define bprintf ADM_info
34 #define MP4_DEBUG MP4_DETAILS_ALL
35 #endif
36 
37 #warning add audioDelay
38 #warning fix audio not starting at 0
39 /**
40     \fn addAC3
41     \brief Setup AC3 audio track
42 */
addAc3(int index,WAVHeader * header)43 bool muxerMp4v2::addAc3(int index, WAVHeader *header)
44 {
45         int fscod=0;
46         switch(header->frequency)
47         {
48                 case 48000: fscod=0;break;
49                 case 44100: fscod=1;break;
50                 case 32000: fscod=2;break;
51                 default:
52                     {
53                     GUI_Error_HIG("", QT_TRANSLATE_NOOP("mp4v2muxer","Invalid frequency for AC3. Only 32, 44.1 & 48 kHz"));
54                     return false;
55                     }
56         }
57         int bitrate;
58         static const uint16_t ac3_bitrate_tab[19] = { // From handbrake
59                      32, 40, 48, 56, 64, 80, 96, 112, 128,
60                      160, 192, 224, 256, 320, 384, 448, 512, 576, 640
61                  };
62         int Ceil=sizeof(ac3_bitrate_tab)/sizeof(const uint16_t);
63         bitrate=-1;
64         for(int ix=0;ix<Ceil;ix++)
65                 if(header->byterate==(ac3_bitrate_tab[ix]*1000)/8)
66                 {
67                     bitrate=ix;
68                     break;
69                 }
70         if(-1==bitrate)
71         {
72             GUI_Error_HIG("",QT_TRANSLATE_NOOP("mp4v2muxer","Invalid bitrate for AC3"));
73             return false;
74         }
75         int acmod,lfe=0;
76         switch(header->channels)
77         {
78                 case 1: acmod=1;break;
79                 case 2: acmod=2;break;
80                 case 5: acmod=7;lfe=0;break;
81 #warning Check!
82                 case 6: acmod=7;lfe=1;break;
83                 default:
84                         {
85                                   GUI_Error_HIG("",QT_TRANSLATE_NOOP("mp4v2muxer","Invalid number of channels for AC3"));
86                                   return false;
87                         }
88         }
89         audioTrackIds[index]=MP4AddAC3AudioTrack(handle,
90                                               header->frequency,// samplingRate,
91                                                fscod,           // fscod
92                                                8,               // bsid,
93                                                0,               // bsmod,
94                                                acmod,           // acmod
95                                                lfe,             // lfeon
96                                                bitrate);        // bit_rate_code
97         if(MP4_INVALID_TRACK_ID==audioTrackIds[index])
98         {
99             ADM_error("Error adding audio track %i of type 0x%x\n",index,header->encoding);
100             return false;
101         }
102         aprintf("Add Track %d fq %d (AC3)\n",audioTrackIds[index],header->frequency);
103         return true;
104 }
105 /**
106     \fn initAudio
107 */
initAudio(void)108 bool muxerMp4v2::initAudio(void)
109 {
110     audioTrackIds=new MP4TrackId[nbAStreams];
111     audioPackets=new mp4v2AudioPacket[nbAStreams];
112 
113     for(int i=0;i<nbAStreams;i++)
114     {
115         WAVHeader *header=aStreams[i]->getInfo();
116         ADM_audioStream*a=aStreams[i];
117         audioPackets[i].clock=new audioClock(header->frequency);
118         // Preload this track...
119         if(false==loadAndToggleAudioSlot(i))
120         {
121             audioPackets[i].eos=true;
122             continue;
123         }
124 
125         switch(header->encoding)
126         {
127             case WAV_AAC:
128                     {
129                         uint8_t *extraData=NULL;
130                         uint32_t extraDataLen=0;
131                         if(!a->getExtraData(&extraDataLen,&extraData))
132                             {
133                                  GUI_Error_HIG("AAC",QT_TRANSLATE_NOOP("mp4v2muxer","Cannot get AAC Extra data\n"));
134                                  return false;
135                             }
136                         uint32_t frameLength=a->getSamplesPerPacket();
137                         audioTrackIds[i]=MP4AddAudioTrack(handle,
138                                                       header->frequency,
139                                                       frameLength,
140                                                       MP4_MPEG4_AUDIO_TYPE);
141                         if(MP4_INVALID_TRACK_ID==audioTrackIds[i])
142                         {
143                             ADM_error("Error adding audio track %i of type 0x%x\n",i,header->encoding);
144                             return false;
145                         }
146                         aprintf("Add Track %d fq %d\n",audioTrackIds[i],header->frequency);
147                         MP4SetAudioProfileLevel(handle,0x0f);
148                         MP4SetTrackIntegerProperty(handle,audioTrackIds[i],"mdia.minf.stbl.stsd.mp4a.channels",
149                                     header->channels);
150                         MP4SetTrackESConfiguration(handle,audioTrackIds[i],extraData,extraDataLen);
151                     break;
152                     }
153             case WAV_AC3:
154                     if(false==addAc3(i, header))
155                     {
156                             return false;
157                     }
158                     break;
159             case WAV_MP2:
160             case WAV_MP3:
161                     audioTrackIds[i]=MP4AddAudioTrack(handle,
162                                                       header->frequency,
163                                                       audioPackets[i].blocks[0].nbSamples,
164                                                       MP4_MPEG2_AUDIO_TYPE);
165                     if(MP4_INVALID_TRACK_ID==audioTrackIds[i])
166                     {
167                         ADM_error("Error adding audio track %i of type 0x%x\n",i,header->encoding);
168                         return false;
169                     }
170                     aprintf("Add Track %d fq %d\n",audioTrackIds[i],header->frequency);
171                     MP4SetAudioProfileLevel(handle,0x0f);
172                     MP4SetTrackIntegerProperty(handle,audioTrackIds[i],"mdia.minf.stbl.stsd.mp4a.channels",
173                                 header->channels);
174                     break;
175             default:
176                     ADM_error("Cannot create audio track of type 0x%x\n",header->encoding);
177                     return false;
178         }
179         if(aStreams[i]->isLanguageSet())
180         {
181                 MP4SetTrackLanguage(handle,audioTrackIds[i],aStreams[i]->getLanguage().c_str());
182                 ADM_info("[MP4v2] Setting language to %s \n",aStreams[i]->getLanguage().c_str());
183         }else
184             ADM_warning("[MP4v2] Language is undefined\n");
185 
186          MP4SetTrackBytesProperty(handle,audioTrackIds[i],"udta.name.value",
187                     (const uint8_t*)"Stereo", strlen("Stereo"));
188 
189     }
190     if(nbAStreams)
191          MP4SetTrackIntegerProperty(handle, audioTrackIds[0], "tkhd.flags", 3);
192     return true;
193 }
194 /**
195     \fn loadAndToggleAudioSlot
196 */
loadAndToggleAudioSlot(int index)197 bool muxerMp4v2::loadAndToggleAudioSlot(int index)
198 {
199         ADM_audioStream                     *a=aStreams[index];
200         mp4v2AudioPacket                    *pkt=&(audioPackets[index]);
201         mp4v2AudioPacket::mp4v2AudioBlock   *blk=&(pkt->blocks[pkt->nextWrite]);
202         if(!a->getPacket(blk->buffer,
203                          &(blk->sizeInBytes),
204                          AUDIO_BUFFER_SIZE,
205                          &(blk->nbSamples),
206                          &(blk->dts)))
207         {
208                 ADM_warning("Cannot get audio packet for stream %d\n",index);
209                 pkt->eos=true;
210                 return false;
211         }
212         if(blk->dts!=ADM_NO_PTS)
213             blk->dts+=audioDelay;
214         blk->present=true;
215         pkt->nextWrite=!pkt->nextWrite;
216         aprintf("Read audio block, size=%d bytes, dts=%s\n",blk->sizeInBytes,ADM_us2plain(blk->dts));
217         return true;
218 }
219 /**
220     \fn writeAudioBlock
221 */
writeAudioBlock(int index,mp4v2AudioPacket::mp4v2AudioBlock * block,uint64_t nbSamples)222 bool muxerMp4v2::writeAudioBlock(int index,mp4v2AudioPacket::mp4v2AudioBlock *block,uint64_t nbSamples)
223 {
224     aprintf("Writting audio block : size=%d, samples=%d nbSamples=%d \n",block->sizeInBytes,block->nbSamples,(int)nbSamples);
225     bool r=MP4WriteSample(handle,audioTrackIds[index],
226                             block->buffer,
227                             block->sizeInBytes,
228                             nbSamples,
229                             0,1);
230     encoding->pushAudioFrame(block->sizeInBytes);
231     if(false==r)
232                         {
233                             ADM_error("Cannot write audio sample for track %d\n",index);
234                             return false;
235                         }
236     return true;
237 }
238 /**
239     \fn fillAudio
240     \brief push audio packets until nextDts is reached
241 */
fillAudio(uint64_t targetDts)242 bool muxerMp4v2::fillAudio(uint64_t targetDts)
243 {
244     for(int audioIndex=0;audioIndex<nbAStreams;audioIndex++)
245     {
246                 ADM_audioStream         *a=aStreams[audioIndex];
247                 mp4v2AudioPacket       *pkt=&(audioPackets[audioIndex]);
248                 audioClock             *clock=pkt->clock;
249                 if(pkt->eos)            continue;
250                 uint64_t                extraSamples=0;
251 
252                  WAVHeader *info=a->getInfo();
253                 if(!info) // no more track
254                     continue;
255                 uint32_t fq=info->frequency;
256 
257                 while(1)
258                 {
259                         int current=!pkt->nextWrite;
260                         int other=pkt->nextWrite;
261                         mp4v2AudioPacket::mp4v2AudioBlock        *currentBlock=&(pkt->blocks[current]);
262                         mp4v2AudioPacket::mp4v2AudioBlock        *otherBlock=&(pkt->blocks[other]);
263                         // Get our currentDts
264                         uint64_t currentDts=clock->getTimeUs();
265                         uint64_t blockDts=currentBlock->dts;
266                         if(pkt->eos)            break;
267                         extraSamples=0;
268                         // Take either block Dts or our own if no DTS is provided
269                         if(currentBlock->dts!=ADM_NO_PTS)
270                         {
271                             bprintf("Current audio Dts=%" PRId64"\n",currentDts);
272                             bprintf("Incoming block, dts=%" PRId64"\n",currentBlock->dts);
273                             bprintf("Delta =%d ms\n",(int)(currentDts-currentBlock->dts));
274                             if( labs((long int)currentBlock->dts-(long int)currentDts)>MP4V2_MAX_JITTER)
275                             {
276                                 if(currentBlock->dts<currentDts)
277                                     {
278                                             ADM_warning("Audio going back in time audio track %d\n",audioIndex);
279                                             ADM_warning("expected %d ms, got %d ms",currentDts/1000,currentBlock->dts/1000);
280                                             ADM_warning("Dropping packet\n");
281                                             goto nextOne;
282                                     }
283                                 // We have a hole, increase duration of current packet
284                                 double holeDurationUs=currentBlock->dts-currentDts;
285                                 ADM_warning("Hole detected in audio of %d ms, track %d\n",(int)(holeDurationUs/1000),audioIndex);
286                                 ADM_warning("we got a timing of %s",ADM_us2plain(currentBlock->dts));
287                                 ADM_warning("and expected %s\n",ADM_us2plain(currentDts));
288                                 holeDurationUs*=fq;
289                                 holeDurationUs/=1000*1000;
290                                 ADM_warning("Increasing hole duration by %d samples\n",(int)holeDurationUs);
291                                 extraSamples=(uint64_t)holeDurationUs;
292                             }
293                         }else
294                             blockDts=currentDts;
295                         if(blockDts>targetDts) // In the future
296                             break;
297                         if(false==writeAudioBlock(audioIndex,currentBlock,currentBlock->nbSamples+extraSamples))
298                         {
299                             ADM_error("Cannot write audio sample for track %d\n",audioIndex);
300                             pkt->eos=true;
301                             return false;
302                         }
303                         // load next
304 
305                         clock->advanceBySample(currentBlock->nbSamples+extraSamples);
306 nextOne:
307                         if(false==loadAndToggleAudioSlot(audioIndex))
308                         {
309                             ADM_warning("End of audio stream %d\n",audioIndex);
310                             #warning Purge other slot
311                             pkt->eos=true;
312                         }
313                 }
314     }
315     return true;
316 }
317 //EOF
318 
319 
320 
321