00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "MP3StreamState.hh"
00022 #include "InputFile.hh"
00023 #include "GroupsockHelper.hh"
00024
00025 #if defined(__WIN32__) || defined(_WIN32)
00026 #define snprintf _snprintf
00027 #endif
00028
00029 #define MILLION 1000000
00030
00031 MP3StreamState::MP3StreamState(UsageEnvironment& env)
00032 : fEnv(env), fFid(NULL), fPresentationTimeScale(1) {
00033 }
00034
00035 MP3StreamState::~MP3StreamState() {
00036
00037 if (fFid != NULL && fFid != stdin) {
00038 if (fFidIsReallyASocket) {
00039 intptr_t fid_long = (intptr_t)fFid;
00040 closeSocket((int)fid_long);
00041 } else {
00042 CloseInputFile(fFid);
00043 }
00044 }
00045 }
00046
00047 void MP3StreamState::assignStream(FILE* fid, unsigned fileSize) {
00048 fFid = fid;
00049
00050 if (fileSize == (unsigned)(-1)) {
00051 fFidIsReallyASocket = 1;
00052 fFileSize = 0;
00053 } else {
00054 fFidIsReallyASocket = 0;
00055 fFileSize = fileSize;
00056 }
00057 fNumFramesInFile = 0;
00058 fIsVBR = fHasXingTOC = False;
00059
00060
00061 gettimeofday(&fNextFramePresentationTime, NULL);
00062 }
00063
00064 struct timeval MP3StreamState::currentFramePlayTime() const {
00065 unsigned const numSamples = 1152;
00066 unsigned const freq = fr().samplingFreq*(1 + fr().isMPEG2);
00067
00068
00069 unsigned const uSeconds
00070 = ((numSamples*2*MILLION)/freq + 1)/2;
00071
00072 struct timeval result;
00073 result.tv_sec = uSeconds/MILLION;
00074 result.tv_usec = uSeconds%MILLION;
00075 return result;
00076 }
00077
00078 float MP3StreamState::filePlayTime() const {
00079 unsigned numFramesInFile = fNumFramesInFile;
00080 if (numFramesInFile == 0) {
00081
00082
00083 numFramesInFile = fFileSize/(4 + fCurrentFrame.frameSize);
00084 }
00085
00086 struct timeval const pt = currentFramePlayTime();
00087 return numFramesInFile*(pt.tv_sec + pt.tv_usec/(float)MILLION);
00088 }
00089
00090 unsigned MP3StreamState::getByteNumberFromPositionFraction(float fraction) {
00091 if (fHasXingTOC) {
00092
00093 float percent = fraction*100.0f;
00094 unsigned a = (unsigned)percent;
00095 if (a > 99) a = 99;
00096
00097 unsigned fa = fXingTOC[a];
00098 unsigned fb;
00099 if (a < 99) {
00100 fb = fXingTOC[a+1];
00101 } else {
00102 fb = 256;
00103 }
00104 fraction = (fa + (fb-fa)*(percent-a))/256.0f;
00105 }
00106
00107 return (unsigned)(fraction*fFileSize);
00108 }
00109
00110 void MP3StreamState::seekWithinFile(unsigned seekByteNumber) {
00111 if (fFidIsReallyASocket) return;
00112
00113 SeekFile64(fFid, seekByteNumber, SEEK_SET);
00114 }
00115
00116 unsigned MP3StreamState::findNextHeader(struct timeval& presentationTime) {
00117 presentationTime = fNextFramePresentationTime;
00118
00119 if (!findNextFrame()) return 0;
00120
00121
00122 struct timeval framePlayTime = currentFramePlayTime();
00123 if (fPresentationTimeScale > 1) {
00124
00125 unsigned secondsRem = framePlayTime.tv_sec % fPresentationTimeScale;
00126 framePlayTime.tv_sec -= secondsRem;
00127 framePlayTime.tv_usec += secondsRem*MILLION;
00128 framePlayTime.tv_sec /= fPresentationTimeScale;
00129 framePlayTime.tv_usec /= fPresentationTimeScale;
00130 }
00131 fNextFramePresentationTime.tv_usec += framePlayTime.tv_usec;
00132 fNextFramePresentationTime.tv_sec
00133 += framePlayTime.tv_sec + fNextFramePresentationTime.tv_usec/MILLION;
00134 fNextFramePresentationTime.tv_usec %= MILLION;
00135
00136 return fr().hdr;
00137 }
00138
00139 Boolean MP3StreamState::readFrame(unsigned char* outBuf, unsigned outBufSize,
00140 unsigned& resultFrameSize,
00141 unsigned& resultDurationInMicroseconds) {
00142
00143
00144 resultFrameSize = 4 + fr().frameSize;
00145
00146 if (outBufSize < resultFrameSize) {
00147 #ifdef DEBUG_ERRORS
00148 fprintf(stderr, "Insufficient buffer size for reading input frame (%d, need %d)\n",
00149 outBufSize, resultFrameSize);
00150 #endif
00151 if (outBufSize < 4) outBufSize = 0;
00152 resultFrameSize = outBufSize;
00153
00154 return False;
00155 }
00156
00157 if (resultFrameSize >= 4) {
00158 unsigned& hdr = fr().hdr;
00159 *outBuf++ = (unsigned char)(hdr>>24);
00160 *outBuf++ = (unsigned char)(hdr>>16);
00161 *outBuf++ = (unsigned char)(hdr>>8);
00162 *outBuf++ = (unsigned char)(hdr);
00163
00164 memmove(outBuf, fr().frameBytes, resultFrameSize-4);
00165 }
00166
00167 struct timeval const pt = currentFramePlayTime();
00168 resultDurationInMicroseconds = pt.tv_sec*MILLION + pt.tv_usec;
00169
00170 return True;
00171 }
00172
00173 void MP3StreamState::getAttributes(char* buffer, unsigned bufferSize) const {
00174 char const* formatStr
00175 = "bandwidth %d MPEGnumber %d MPEGlayer %d samplingFrequency %d isStereo %d playTime %d isVBR %d";
00176 unsigned fpt = (unsigned)(filePlayTime() + 0.5);
00177 #if defined(IRIX) || defined(ALPHA) || defined(_QNX4) || defined(IMN_PIM) || defined(CRIS)
00178
00179 sprintf(buffer, formatStr,
00180 fr().bitrate, fr().isMPEG2 ? 2 : 1, fr().layer, fr().samplingFreq, fr().isStereo,
00181 fpt, fIsVBR);
00182 #else
00183 snprintf(buffer, bufferSize, formatStr,
00184 fr().bitrate, fr().isMPEG2 ? 2 : 1, fr().layer, fr().samplingFreq, fr().isStereo,
00185 fpt, fIsVBR);
00186 #endif
00187 }
00188
00189 void MP3StreamState::writeGetCmd(char const* hostName,
00190 unsigned short portNum,
00191 char const* fileName) {
00192 char const* const getCmdFmt = "GET %s HTTP/1.1\r\nHost: %s:%d\r\n\r\n";
00193
00194 if (fFidIsReallyASocket) {
00195 intptr_t fid_long = (intptr_t)fFid;
00196 int sock = (int)fid_long;
00197 char writeBuf[100];
00198 #if defined(IRIX) || defined(ALPHA) || defined(_QNX4) || defined(IMN_PIM) || defined(CRIS)
00199
00200
00201 sprintf(writeBuf, getCmdFmt, fileName, hostName, portNum);
00202 #else
00203 snprintf(writeBuf, sizeof writeBuf, getCmdFmt,
00204 fileName, hostName, portNum);
00205 #endif
00206 send(sock, writeBuf, strlen(writeBuf), 0);
00207 } else {
00208 fprintf(fFid, getCmdFmt, fileName, hostName, portNum);
00209 fflush(fFid);
00210 }
00211 }
00212
00213
00214 #define HDRCMPMASK 0xfffffd00
00215
00216 Boolean MP3StreamState::findNextFrame() {
00217 unsigned char hbuf[8];
00218 unsigned l; int i;
00219 int attempt = 0;
00220
00221 read_again:
00222 if (readFromStream(hbuf, 4) != 4) return False;
00223
00224 fr().hdr = ((unsigned long) hbuf[0] << 24)
00225 | ((unsigned long) hbuf[1] << 16)
00226 | ((unsigned long) hbuf[2] << 8)
00227 | (unsigned long) hbuf[3];
00228
00229 #ifdef DEBUG_PARSE
00230 fprintf(stderr, "fr().hdr: 0x%08x\n", fr().hdr);
00231 #endif
00232 if (fr().oldHdr != fr().hdr || !fr().oldHdr) {
00233 i = 0;
00234 init_resync:
00235 #ifdef DEBUG_PARSE
00236 fprintf(stderr, "init_resync: fr().hdr: 0x%08x\n", fr().hdr);
00237 #endif
00238 if ( (fr().hdr & 0xffe00000) != 0xffe00000
00239 || (fr().hdr & 0x00060000) == 0
00240 || (fr().hdr & 0x0000F000) == 0
00241 || (fr().hdr & 0x0000F000) == 0x0000F000
00242 || (fr().hdr & 0x00000C00) == 0x00000C00
00243 || (fr().hdr & 0x00000003) != 0x00000000
00244 ) {
00245
00246
00247
00248
00249
00250 if (fr().hdr == ('R'<<24)+('I'<<16)+('F'<<8)+'F') {
00251 unsigned char buf[70 ];
00252 #ifdef DEBUG_ERRORS
00253 fprintf(stderr,"Skipped RIFF header\n");
00254 #endif
00255 readFromStream(buf, 66);
00256 goto read_again;
00257 }
00258
00259 if ((fr().hdr&0xFFFFFF00) == ('I'<<24)+('D'<<16)+('3'<<8)) {
00260 unsigned tagSize, bytesToSkip;
00261 unsigned char buf[1000];
00262 readFromStream(buf, 6);
00263 tagSize = ((buf[2]&0x7F)<<21) + ((buf[3]&0x7F)<<14) + ((buf[4]&0x7F)<<7) + (buf[5]&0x7F);
00264 bytesToSkip = tagSize;
00265 while (bytesToSkip > 0) {
00266 unsigned bytesToRead = sizeof buf;
00267 if (bytesToRead > bytesToSkip) {
00268 bytesToRead = bytesToSkip;
00269 }
00270 readFromStream(buf, bytesToRead);
00271 bytesToSkip -= bytesToRead;
00272 }
00273 #ifdef DEBUG_ERRORS
00274 fprintf(stderr,"Skipped %d-byte ID3 header\n", tagSize);
00275 #endif
00276 goto read_again;
00277 }
00278
00279 if (i++ < 20000) {
00280 memmove (&hbuf[0], &hbuf[1], 3);
00281 if (readFromStream(hbuf+3,1) != 1) {
00282 return False;
00283 }
00284 fr().hdr <<= 8;
00285 fr().hdr |= hbuf[3];
00286 fr().hdr &= 0xffffffff;
00287 #ifdef DEBUG_PARSE
00288 fprintf(stderr, "calling init_resync %d\n", i);
00289 #endif
00290 goto init_resync;
00291 }
00292 #ifdef DEBUG_ERRORS
00293 fprintf(stderr,"Giving up searching valid MPEG header\n");
00294 #endif
00295 return False;
00296
00297 #ifdef DEBUG_ERRORS
00298 fprintf(stderr,"Illegal Audio-MPEG-Header 0x%08lx at offset 0x%lx.\n",
00299 fr().hdr,tell_stream(str)-4);
00300 #endif
00301
00302
00303
00304
00305
00306 do {
00307 attempt++;
00308 memmove (&hbuf[0], &hbuf[1], 7);
00309 if (readFromStream(&hbuf[3],1) != 1) {
00310 return False;
00311 }
00312
00313
00314 fr().hdr = ((fr().hdr << 8) | hbuf[3]) & 0xffffffff;
00315
00316 if (!fr().oldHdr)
00317 goto init_resync;
00318
00319 } while ((fr().hdr & HDRCMPMASK) != (fr().oldHdr & HDRCMPMASK)
00320 && (fr().hdr & HDRCMPMASK) != (fr().firstHdr & HDRCMPMASK));
00321 #ifdef DEBUG_ERRORS
00322 fprintf (stderr, "Skipped %d bytes in input.\n", attempt);
00323 #endif
00324 }
00325 if (!fr().firstHdr) {
00326 fr().firstHdr = fr().hdr;
00327 }
00328
00329 fr().setParamsFromHeader();
00330 fr().setBytePointer(fr().frameBytes, fr().frameSize);
00331
00332 fr().oldHdr = fr().hdr;
00333
00334 if (fr().isFreeFormat) {
00335 #ifdef DEBUG_ERRORS
00336 fprintf(stderr,"Free format not supported.\n");
00337 #endif
00338 return False;
00339 }
00340
00341 #ifdef MP3_ONLY
00342 if (fr().layer != 3) {
00343 #ifdef DEBUG_ERRORS
00344 fprintf(stderr, "MPEG layer %d is not supported!\n", fr().layer);
00345 #endif
00346 return False;
00347 }
00348 #endif
00349 }
00350
00351 if ((l = readFromStream(fr().frameBytes, fr().frameSize))
00352 != fr().frameSize) {
00353 if (l == 0) return False;
00354 memset(fr().frameBytes+1, 0, fr().frameSize-1);
00355 }
00356
00357 return True;
00358 }
00359
00360 static Boolean socketIsReadable(int socket) {
00361 const unsigned numFds = socket+1;
00362 fd_set rd_set;
00363 FD_ZERO(&rd_set);
00364 FD_SET((unsigned)socket, &rd_set);
00365 struct timeval timeout;
00366 timeout.tv_sec = timeout.tv_usec = 0;
00367
00368 int result = select(numFds, &rd_set, NULL, NULL, &timeout);
00369 return result != 0;
00370 }
00371
00372 static char watchVariable;
00373
00374 static void checkFunc(void* ) {
00375 watchVariable = ~0;
00376 }
00377
00378 static void waitUntilSocketIsReadable(UsageEnvironment& env, int socket) {
00379 while (!socketIsReadable(socket)) {
00380
00381 unsigned usecsToDelay = 1000;
00382 env.taskScheduler().scheduleDelayedTask(usecsToDelay,
00383 (TaskFunc*)checkFunc, (void*)NULL);
00384 watchVariable = 0;
00385 env.taskScheduler().doEventLoop(&watchVariable);
00386
00387 }
00388 }
00389
00390 unsigned MP3StreamState::readFromStream(unsigned char* buf,
00391 unsigned numChars) {
00392
00393 if (fFidIsReallyASocket) {
00394 intptr_t fid_long = (intptr_t)fFid;
00395 int sock = (int)fid_long;
00396 unsigned totBytesRead = 0;
00397 do {
00398 waitUntilSocketIsReadable(fEnv, sock);
00399 int bytesRead
00400 = recv(sock, &((char*)buf)[totBytesRead], numChars-totBytesRead, 0);
00401 if (bytesRead < 0) return 0;
00402
00403 totBytesRead += (unsigned)bytesRead;
00404 } while (totBytesRead < numChars);
00405
00406 return totBytesRead;
00407 } else {
00408 #ifndef _WIN32_WCE
00409 waitUntilSocketIsReadable(fEnv, (int)fileno(fFid));
00410 #endif
00411 return fread(buf, 1, numChars, fFid);
00412 }
00413 }
00414
00415 #define XING_FRAMES_FLAG 0x0001
00416 #define XING_BYTES_FLAG 0x0002
00417 #define XING_TOC_FLAG 0x0004
00418 #define XING_VBR_SCALE_FLAG 0x0008
00419
00420 void MP3StreamState::checkForXingHeader() {
00421
00422 if (fr().frameSize < fr().sideInfoSize) return;
00423 unsigned bytesAvailable = fr().frameSize - fr().sideInfoSize;
00424 unsigned char* p = &(fr().frameBytes[fr().sideInfoSize]);
00425
00426 if (bytesAvailable < 8) return;
00427 if (p[0] != 'X' || p[1] != 'i' || p[2] != 'n' || p[3] != 'g') return;
00428
00429
00430 fIsVBR = True;
00431
00432 u_int32_t flags = (p[4]<<24) | (p[5]<<16) | (p[6]<<8) | p[7];
00433 unsigned i = 8;
00434 bytesAvailable -= 8;
00435
00436 if (flags&XING_FRAMES_FLAG) {
00437
00438 if (bytesAvailable < 4) return;
00439 fNumFramesInFile = (p[i]<<24)|(p[i+1]<<16)|(p[i+2]<<8)|(p[i+3]);
00440 i += 4; bytesAvailable -= 4;
00441 }
00442
00443 if (flags&XING_BYTES_FLAG) {
00444
00445 if (bytesAvailable < 4) return;
00446 fFileSize = (p[i]<<24)|(p[i+1]<<16)|(p[i+2]<<8)|(p[i+3]);
00447 i += 4; bytesAvailable -= 4;
00448 }
00449
00450 if (flags&XING_TOC_FLAG) {
00451
00452 if (bytesAvailable < XING_TOC_LENGTH) return;
00453 fHasXingTOC = True;
00454 for (unsigned j = 0; j < XING_TOC_LENGTH; ++j) {
00455 fXingTOC[j] = p[i+j];
00456 }
00457 i += XING_TOC_FLAG; bytesAvailable -= XING_TOC_FLAG;
00458 }
00459 }