MP3Encoder.cpp

00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: MP3Encoder.cpp * 00006 * * 00007 * * 00008 * * 00009 * ITEC institute of the University of Klagenfurt (Austria) * 00010 * http://www.itec.uni-klu.ac.at * 00011 * * 00012 * * 00013 * For more information visit the ViTooKi homepage: * 00014 * http://ViTooKi.sourceforge.net * 00015 * vitooki-user@lists.sourceforge.net * 00016 * vitooki-devel@lists.sourceforge.net * 00017 * * 00018 * This file is part of ViTooKi, a free video toolkit. * 00019 * ViTooKi is free software; you can redistribute it and/or * 00020 * modify it under the terms of the GNU General Public License * 00021 * as published by the Free Software Foundation; either version 2 * 00022 * of the License, or (at your option) any later version. * 00023 * * 00024 * This program is distributed in the hope that it will be useful, * 00025 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00027 * GNU General Public License for more details. * 00028 * * 00029 * You should have received a copy of the GNU General Public License * 00030 * along with this program; if not, write to the Free Software * 00031 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * 00032 * MA 02111-1307, USA. * 00033 * * 00034 ***********************************************************************/ 00035 00036 /*********************************************************************** 00037 * * 00038 * REVISION HISTORY: * 00039 * * 00040 * * 00041 * * 00042 ***********************************************************************/ 00043 00044 #include "MP3Encoder.hpp" 00045 #include "CompressedVideoFrame.hpp" 00046 00047 00048 /***************************************************/ 00049 MP3Encoder::MP3Encoder(AudioESInfo * pESInfo, u32 targetBitRate, 00050 enum CodecID outFormat, char* encoderConfig) { 00051 this->mpEncoderHandle = encoderConfig; 00052 es = pESInfo; 00053 muiTargetBitrate = targetBitRate; 00054 initialized = false; 00055 strcpy(name,"MP3Encoder-FFMPEG"); 00056 outputFormat=outFormat; 00057 } 00058 00059 00060 /***************************************************/ 00061 void MP3Encoder::initialize() { 00062 if(initialized) 00063 return; 00064 dprintf_full("MP3Encoder::initialize() Handle: %p BW: %i bps\n", 00065 mpEncoderHandle, muiTargetBitrate); 00066 initialized = true; 00067 if (FFMPEGaudioEncoderInit(&mpEncoderHandle, muiTargetBitrate, 44100, 2, 16) != ERR_OK) { 00068 dprintf_err("MP3Encoder::initialize: Error creating encoder instance!\n"); 00069 initialized = false; 00070 } 00071 assert(mpEncoderHandle); 00072 es->setAvgBandwidth(muiTargetBitrate); 00073 es->setVOPTimeIncrement(2350); // FIXME: 90000 DIV 38 frames, known by analyzing ffmpeg :( 00074 muiFrameNumber = 0; 00075 inBufSize=0; 00076 firstFrame = true; 00077 } 00078 00079 00080 /***************************************************/ 00081 MP3Encoder::~MP3Encoder() { 00082 FFMPEGaudioEncoderClose(&mpEncoderHandle); 00083 } 00084 00085 00086 00087 /***************************************************/ 00088 list < Frame * >MP3Encoder::adapt(Frame * frm) { 00089 CompressedAudioFrame *mpgFrame = NULL; 00090 list < Frame * >frmList; 00091 u32 iFramesize = 0; 00092 00093 if (!initialized) 00094 initialize(); 00095 if (!initialized) 00096 return frmList; 00097 00098 #define PCM_FRAME_SIZE (1152*2*2) //FIXME: should be read from AVCodecContext->frame_size 00099 00100 if (inBufSize > 0) { // smth was left from last round.... 00101 memcpy(mpInBuf+inBufSize, frm->getAU()->payload, frm->getAU()->size); 00102 dprintf_full("MP3Encoder::adapt %i bytes were left from last round...stored further %i bytes\n",inBufSize,frm->getAU()->size); 00103 inBufSize += frm->getAU()->size; 00104 00105 if (inBufSize >= PCM_FRAME_SIZE) { 00106 iFramesize = FFMPEGaudioEncodeFrame(mpEncoderHandle, (char *)mpInBuf, mpOutBuf); 00107 inBufSize -= PCM_FRAME_SIZE; 00108 assert(inBufSize <= PCM_FRAME_SIZE); //avoid overlapping rest-buffer 00109 memcpy(mpInBuf,mpInBuf+PCM_FRAME_SIZE,inBufSize); //move rest to the front 00110 00111 if (iFramesize > 0) { 00112 AU *pAU = new AU(frm->getAU()); 00113 u8 *payload = new u8[iFramesize]; 00114 memcpy(payload, mpOutBuf, iFramesize); 00115 00116 pAU->size = iFramesize; 00117 pAU->payload = payload; 00118 pAU->cts = muiFrameNumber * es->getVOPTimeIncrement(); 00119 00120 mpgFrame = new CompressedAudioFrame(Frame::MP3_AUDIO); 00121 00122 //mpgFrame->detectFrameType(); 00123 mpgFrame->setAU(pAU); 00124 mpgFrame->setMediaTimeScale(es->getMediaTimeScale()); 00125 frmList.push_back(mpgFrame); 00126 dprintf_full("MP3Encoder::adapt overlapping frame: size %i bytes, %s frameNo %i, CTS %u:\r\n", 00127 pAU->size, Frame::VOPTypeToChar(mpgFrame->getType()), muiFrameNumber, 00128 mpgFrame->getAU()->cts); 00129 muiFrameNumber++; 00130 } else { 00131 dprintf_full("MP3Encoder::adapt ... filling encoder queue: no return data yet.\n"); 00132 } 00133 } else { 00134 dprintf_full("MP3Encoder::adapt ... still harvesting small pcm bits for one full frame...!\n"); 00135 } 00136 } // smth was left from last round.... 00137 else { //inBufSize==0, so store for next round 00138 memcpy(mpInBuf, frm->getAU()->payload, frm->getAU()->size); 00139 inBufSize= frm->getAU()->size; 00140 dprintf_full("MP3Encoder::adapt %i tail-bytes saved for next round...\n",inBufSize); 00141 } 00142 00143 return frmList; 00144 } 00145 00146 00147 /***************************************************/ 00148 list < Frame * >MP3Encoder::close() { 00149 CompressedAudioFrame *mpgFrame = NULL; 00150 list < Frame * >frmList; 00151 u32 iFramesize; 00152 00153 00154 dprintf_full("MP3Encoder::close ... there are %i bytes left in inBuf, draining....\n",inBufSize); 00155 00156 if (inBufSize > 0) { 00157 //maybe FIXME: for large input frames, maybe more than one PCM_FRAME_SIZE is still in buffer? --> while() needed... 00158 assert(inBufSize <= PCM_FRAME_SIZE); //avoid overlapping rest-buffer 00159 iFramesize = FFMPEGaudioEncodeFrame(mpEncoderHandle, (char *)mpInBuf, mpOutBuf); 00160 00161 do { 00162 if (iFramesize > 0) { 00163 AU *pAU = new AU(); 00164 u8 *payload = new u8[iFramesize]; 00165 memcpy(payload, mpOutBuf, iFramesize); 00166 00167 pAU->size = iFramesize; 00168 pAU->payload = payload; 00169 pAU->cts = muiFrameNumber * es->getVOPTimeIncrement(); 00170 00171 mpgFrame = new CompressedAudioFrame(Frame::MP3_AUDIO); 00172 00173 //mpgFrame->detectFrameType(); 00174 mpgFrame->setAU(pAU); 00175 mpgFrame->setMediaTimeScale(es->getMediaTimeScale()); 00176 frmList.push_back(mpgFrame); 00177 dprintf_full("MP3Encoder::close FINAL frame: size %i bytes, %s frameNo %i, CTS %u:\n", 00178 pAU->size, Frame::VOPTypeToChar(mpgFrame->getType()), muiFrameNumber, 00179 mpgFrame->getAU()->cts); 00180 muiFrameNumber++; 00181 } else { 00182 dprintf_err("MP3Encoder::close ... FINAL pcm samples didnt lead to encoded frame?!?!\n"); 00183 } 00184 iFramesize = FFMPEGaudioEncodeFrame(mpEncoderHandle, NULL /*FLUSH!*/, mpOutBuf); 00185 } while (iFramesize > 0); 00186 00187 } else { 00188 dprintf_full("MP3Encoder::close ... nothing left to decode.\n"); 00189 } 00190 00191 00192 return frmList; 00193 } 00194 00195 00196 /***************************************************/ 00197 Adaptor *MP3Encoder::clone() { 00198 char* copyEncoderConfig=NULL; 00199 #ifdef ENABLE_FFMPEG 00200 AVCodec *codec=NULL; 00201 /* Make sure that the required encoder exists in the ffmpeg library */ 00202 codec = avcodec_find_encoder(this->outputFormat); 00203 if(codec) { 00204 AVCodecContext* srcClone = avcodec_alloc_context(); 00205 avcodec_get_context_defaults(srcClone); 00206 00207 AVCodecContext* src=(AVCodecContext*) mpEncoderHandle; 00208 // don't do a memcpy --> pointers! 00209 srcClone->codec=codec; 00210 srcClone->b_frame_strategy=src->b_frame_strategy; 00211 srcClone->b_quant_factor=src->b_quant_factor; 00212 srcClone->b_quant_offset=src->b_quant_offset; 00213 srcClone->bit_rate=src->bit_rate; 00214 srcClone->rtp_payload_size=src->rtp_payload_size; 00215 srcClone->width=src->width; 00216 srcClone->height=src->height; 00217 srcClone->gop_size=srcClone->gop_size; 00218 srcClone->qmin=src->qmin; 00219 srcClone->qmax=src->qmax; 00220 srcClone->max_b_frames=src->max_b_frames; 00221 srcClone->sample_aspect_ratio.den=src->sample_aspect_ratio.den; 00222 srcClone->sample_aspect_ratio.num=src->sample_aspect_ratio.num; 00223 srcClone->rc_max_rate=src->rc_max_rate; 00224 srcClone->rc_min_rate=src->rc_min_rate; 00225 srcClone->mb_qmax=src->mb_qmax; 00226 srcClone->mb_qmin=src->mb_qmin; 00227 srcClone->time_base=src->time_base; 00228 // open the codec for encoding 00229 if (avcodec_open(srcClone, codec) < 0) { 00230 printf("MP3Encoder::clone(): Could not open codec\n"); 00231 av_free(srcClone); 00232 } 00233 else 00234 copyEncoderConfig=(char*)srcClone; 00235 } 00236 #else 00237 dprintf_err("MP3Encoder::clone: compiled without ffmpeg support!\n"); 00238 exit(1); 00239 #endif 00240 00241 return new MP3Encoder(es,muiTargetBitrate,outputFormat,copyEncoderConfig); 00242 } 00243 00244