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 #if 0 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 */ 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("", "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("","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("","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 */ 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","Cannot get AAC Extra data\n"); 134 return false; 135 } 136 audioTrackIds[i]=MP4AddAudioTrack(handle, 137 header->frequency, 138 1024, 139 MP4_MPEG4_AUDIO_TYPE); 140 if(MP4_INVALID_TRACK_ID==audioTrackIds[i]) 141 { 142 ADM_error("Error adding audio track %i of type 0x%x\n",i,header->encoding); 143 return false; 144 } 145 aprintf("Add Track %d fq %d\n",audioTrackIds[i],header->frequency); 146 MP4SetAudioProfileLevel(handle,0x0f); 147 MP4SetTrackIntegerProperty(handle,audioTrackIds[i],"mdia.minf.stbl.stsd.mp4a.channels", 148 header->channels); 149 MP4SetTrackESConfiguration(handle,audioTrackIds[i],extraData,extraDataLen); 150 break; 151 } 152 case WAV_AC3: 153 if(false==addAc3(i, header)) 154 { 155 return false; 156 } 157 break; 158 case WAV_MP2: 159 case WAV_MP3: 160 audioTrackIds[i]=MP4AddAudioTrack(handle, 161 header->frequency, 162 audioPackets[i].blocks[0].nbSamples, 163 MP4_MPEG2_AUDIO_TYPE); 164 if(MP4_INVALID_TRACK_ID==audioTrackIds[i]) 165 { 166 ADM_error("Error adding audio track %i of type 0x%x\n",i,header->encoding); 167 return false; 168 } 169 aprintf("Add Track %d fq %d\n",audioTrackIds[i],header->frequency); 170 MP4SetAudioProfileLevel(handle,0x0f); 171 MP4SetTrackIntegerProperty(handle,audioTrackIds[i],"mdia.minf.stbl.stsd.mp4a.channels", 172 header->channels); 173 break; 174 default: 175 ADM_error("Cannot create audio track of type 0x%x\n",header->encoding); 176 return false; 177 } 178 MP4SetTrackBytesProperty(handle,audioTrackIds[i],"udta.name.value", 179 (const uint8_t*)"Stereo", strlen("Stereo")); 180 181 } 182 if(nbAStreams) 183 MP4SetTrackIntegerProperty(handle, audioTrackIds[0], "tkhd.flags", 3); 184 return true; 185 } 186 /** 187 \fn loadAndToggleAudioSlot 188 */ 189 bool muxerMp4v2::loadAndToggleAudioSlot(int index) 190 { 191 ADM_audioStream *a=aStreams[index]; 192 mp4v2AudioPacket *pkt=&(audioPackets[index]); 193 mp4v2AudioPacket::mp4v2AudioBlock *blk=&(pkt->blocks[pkt->nextWrite]); 194 if(!a->getPacket(blk->buffer, 195 &(blk->sizeInBytes), 196 AUDIO_BUFFER_SIZE, 197 &(blk->nbSamples), 198 &(blk->dts))) 199 { 200 ADM_warning("Cannot get audio packet for stream %d\n",index); 201 pkt->eos=true; 202 return false; 203 } 204 if(blk->dts!=ADM_NO_PTS) 205 blk->dts+=audioDelay; 206 blk->present=true; 207 pkt->nextWrite=!pkt->nextWrite; 208 aprintf("Read audio block, size=%d bytes, dts=%s\n",blk->sizeInBytes,ADM_us2plain(blk->dts)); 209 return true; 210 } 211 /** 212 \fn writeAudioBlock 213 */ 214 bool muxerMp4v2::writeAudioBlock(int index,mp4v2AudioPacket::mp4v2AudioBlock *block,uint64_t nbSamples) 215 { 216 aprintf("Writting audio block : size=%d, samples=%d nbSamples=%d \n",block->sizeInBytes,block->nbSamples,(int)nbSamples); 217 bool r=MP4WriteSample(handle,audioTrackIds[index], 218 block->buffer, 219 block->sizeInBytes, 220 nbSamples, 221 0,1); 222 encoding->pushAudioFrame(block->sizeInBytes); 223 if(false==r) 224 { 225 ADM_error("Cannot write audio sample for track %d\n",index); 226 return false; 227 } 228 return true; 229 } 230 /** 231 \fn fillAudio 232 \brief push audio packets until nextDts is reached 233 */ 234 bool muxerMp4v2::fillAudio(uint64_t targetDts) 235 { 236 for(int audioIndex=0;audioIndex<nbAStreams;audioIndex++) 237 { 238 ADM_audioStream *a=aStreams[audioIndex]; 239 uint32_t fq=a->getInfo()->frequency; 240 mp4v2AudioPacket *pkt=&(audioPackets[audioIndex]); 241 audioClock *clock=pkt->clock; 242 if(pkt->eos) continue; 243 uint64_t extraSamples=0; 244 while(1) 245 { 246 int current=!pkt->nextWrite; 247 int other=pkt->nextWrite; 248 mp4v2AudioPacket::mp4v2AudioBlock *currentBlock=&(pkt->blocks[current]); 249 mp4v2AudioPacket::mp4v2AudioBlock *otherBlock=&(pkt->blocks[other]); 250 // Get our currentDts 251 uint64_t currentDts=clock->getTimeUs(); 252 uint64_t blockDts=currentBlock->dts; 253 if(pkt->eos) break; 254 extraSamples=0; 255 // Take either block Dts or our own if no DTS is provided 256 if(currentBlock->dts!=ADM_NO_PTS) 257 { 258 bprintf("Current audio Dts=%"PRId64"\n",currentDts); 259 bprintf("Incoming block, dts=%"PRId64"\n",currentBlock->dts); 260 bprintf("Delta =%d ms\n",(int)(currentDts-currentBlock->dts)); 261 if( abs(currentBlock->dts-currentDts)>MP4V2_MAX_JITTER) 262 { 263 if(currentBlock->dts<currentDts) 264 { 265 ADM_warning("Audio going back in time audio track %d\n",audioIndex); 266 ADM_warning("expected %d ms, got %d ms",currentDts/1000,currentBlock->dts/1000); 267 ADM_warning("Dropping packet\n"); 268 goto nextOne; 269 } 270 // We have a hole, increase duration of current packet 271 double holeDurationUs=currentBlock->dts-currentDts; 272 ADM_warning("Hole detected in audio of %d ms, track %d\n",(int)(holeDurationUs/1000),audioIndex); 273 ADM_warning("we got a timing of %s",ADM_us2plain(currentBlock->dts)); 274 ADM_warning("and expected %s\n",ADM_us2plain(currentDts)); 275 holeDurationUs*=fq; 276 holeDurationUs/=1000*1000; 277 ADM_warning("Increasing hole duration by %d samples\n",(int)holeDurationUs); 278 extraSamples=(uint64_t)holeDurationUs; 279 } 280 }else 281 blockDts=currentDts; 282 if(blockDts>targetDts) // In the future 283 break; 284 if(false==writeAudioBlock(audioIndex,currentBlock,currentBlock->nbSamples+extraSamples)) 285 { 286 ADM_error("Cannot write audio sample for track %d\n",audioIndex); 287 pkt->eos=true; 288 return false; 289 } 290 // load next 291 292 clock->advanceBySample(currentBlock->nbSamples+extraSamples); 293 nextOne: 294 if(false==loadAndToggleAudioSlot(audioIndex)) 295 { 296 ADM_warning("End of audio stream %d\n",audioIndex); 297 #warning Purge other slot 298 pkt->eos=true; 299 } 300 } 301 } 302 return true; 303 } 304 #endif 305 //EOF 306 307 308 309