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