liveMedia/ADTSAudioFileSource.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00015 **********/
00016 // "liveMedia"
00017 // Copyright (c) 1996-2008 Live Networks, Inc.  All rights reserved.
00018 // A source object for AAC audio files in ADTS format
00019 // Implementation
00020 
00021 #include "ADTSAudioFileSource.hh"
00022 #include "InputFile.hh"
00023 #include <GroupsockHelper.hh>
00024 
00026 
00027 static unsigned const samplingFrequencyTable[16] = {
00028   96000, 88200, 64000, 48000,
00029   44100, 32000, 24000, 22050,
00030   16000, 12000, 11025, 8000,
00031   7350, 0, 0, 0
00032 };
00033 
00034 ADTSAudioFileSource*
00035 ADTSAudioFileSource::createNew(UsageEnvironment& env, char const* fileName) {
00036   FILE* fid = NULL;
00037   do {
00038     fid = OpenInputFile(env, fileName);
00039     if (fid == NULL) break;
00040 
00041     // Now, having opened the input file, read the fixed header of the first frame,
00042     // to get the audio stream's parameters:
00043     unsigned char fixedHeader[4]; // it's actually 3.5 bytes long
00044     if (fread(fixedHeader, 1, sizeof fixedHeader, fid) < sizeof fixedHeader) break;
00045     
00046     // Check the 'syncword':
00047     if (!(fixedHeader[0] == 0xFF && (fixedHeader[1]&0xF0) == 0xF0)) {
00048       env.setResultMsg("Bad 'syncword' at start of ADTS file");
00049       break;
00050     }
00051     
00052     // Get and check the 'profile':
00053     u_int8_t profile = (fixedHeader[2]&0xC0)>>6; // 2 bits
00054     if (profile == 3) {
00055       env.setResultMsg("Bad (reserved) 'profile': 3 in first frame of ADTS file");
00056       break;
00057     }
00058 
00059     // Get and check the 'sampling_frequency_index':
00060     u_int8_t sampling_frequency_index = (fixedHeader[2]&0x3C)>>2; // 4 bits
00061     if (samplingFrequencyTable[sampling_frequency_index] == 0) {
00062       env.setResultMsg("Bad 'sampling_frequency_index' in first frame of ADTS file");
00063       break;
00064     }
00065 
00066     // Get and check the 'channel_configuration':
00067     u_int8_t channel_configuration
00068       = ((fixedHeader[2]&0x01)<<2)|((fixedHeader[3]&0xC0)>>6); // 3 bits
00069 
00070     // If we get here, the frame header was OK.
00071     // Reset the fid to the beginning of the file:
00072 #ifndef _WIN32_WCE
00073     rewind(fid);
00074 #else
00075     fseek(fid, SEEK_SET,0);
00076 #endif
00077 #ifdef DEBUG
00078     fprintf(stderr, "Read first frame: profile %d, "
00079             "sampling_frequency_index %d => samplingFrequency %d, "
00080             "channel_configuration %d\n",
00081             profile,
00082             sampling_frequency_index, samplingFrequencyTable[sampling_frequency_index],
00083             channel_configuration);
00084 #endif
00085     return new ADTSAudioFileSource(env, fid, profile,
00086                                    sampling_frequency_index, channel_configuration);
00087   } while (0);
00088 
00089   // An error occurred:
00090   CloseInputFile(fid);
00091   return NULL;
00092 }
00093 
00094 ADTSAudioFileSource
00095 ::ADTSAudioFileSource(UsageEnvironment& env, FILE* fid, u_int8_t profile,
00096                       u_int8_t samplingFrequencyIndex, u_int8_t channelConfiguration)
00097   : FramedFileSource(env, fid) {
00098   fSamplingFrequency = samplingFrequencyTable[samplingFrequencyIndex];
00099   fNumChannels = channelConfiguration == 0 ? 2 : channelConfiguration;
00100   fuSecsPerFrame
00101     = (1024/*samples-per-frame*/*1000000) / fSamplingFrequency/*samples-per-second*/;
00102 
00103   // Construct the 'AudioSpecificConfig', and from it, the corresponding ASCII string:
00104   unsigned char audioSpecificConfig[2];
00105   u_int8_t const audioObjectType = profile + 1;
00106   audioSpecificConfig[0] = (audioObjectType<<3) | (samplingFrequencyIndex>>1);
00107   audioSpecificConfig[1] = (samplingFrequencyIndex<<7) | (channelConfiguration<<3);
00108   sprintf(fConfigStr, "%02X%02x", audioSpecificConfig[0], audioSpecificConfig[1]);
00109 }
00110 
00111 ADTSAudioFileSource::~ADTSAudioFileSource() {
00112   CloseInputFile(fFid);
00113 }
00114 
00115 // Note: We should change the following to use asynchronous file reading, #####
00116 // as we now do with ByteStreamFileSource. #####
00117 void ADTSAudioFileSource::doGetNextFrame() {
00118   // Begin by reading the 7-byte fixed_variable headers:
00119   unsigned char headers[7];
00120   if (fread(headers, 1, sizeof headers, fFid) < sizeof headers
00121       || feof(fFid) || ferror(fFid)) {
00122     // The input source has ended:
00123     handleClosure(this);
00124     return;
00125   }
00126 
00127   // Extract important fields from the headers:
00128   Boolean protection_absent = headers[1]&0x01;
00129   u_int16_t frame_length
00130     = ((headers[3]&0x03)<<11) | (headers[4]<<3) | ((headers[5]&0xE0)>>5);
00131 #ifdef DEBUG
00132   u_int16_t syncword = (headers[0]<<4) | (headers[1]>>4);
00133   fprintf(stderr, "Read frame: syncword 0x%x, protection_absent %d, frame_length %d\n", syncword, protection_absent, frame_length);
00134   if (syncword != 0xFFF) fprintf(stderr, "WARNING: Bad syncword!\n");
00135 #endif
00136   unsigned numBytesToRead
00137     = frame_length > sizeof headers ? frame_length - sizeof headers : 0;
00138 
00139   // If there's a 'crc_check' field, skip it:
00140   if (!protection_absent) {
00141     fseek(fFid, 2, SEEK_CUR);
00142     numBytesToRead = numBytesToRead > 2 ? numBytesToRead - 2 : 0;
00143   }
00144 
00145   // Next, read the raw frame data into the buffer provided:
00146   if (numBytesToRead > fMaxSize) {
00147     fNumTruncatedBytes = numBytesToRead - fMaxSize;
00148     numBytesToRead = fMaxSize;
00149   }
00150   int numBytesRead = fread(fTo, 1, numBytesToRead, fFid);
00151   if (numBytesRead < 0) numBytesRead = 0;
00152   fFrameSize = numBytesRead;
00153   fNumTruncatedBytes += numBytesToRead - numBytesRead;
00154 
00155   // Set the 'presentation time':
00156   if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) {
00157     // This is the first frame, so use the current time:
00158     gettimeofday(&fPresentationTime, NULL);
00159   } else {
00160     // Increment by the play time of the previous frame:
00161     unsigned uSeconds = fPresentationTime.tv_usec + fuSecsPerFrame;
00162     fPresentationTime.tv_sec += uSeconds/1000000;
00163     fPresentationTime.tv_usec = uSeconds%1000000;
00164   }
00165 
00166   fDurationInMicroseconds = fuSecsPerFrame;
00167 
00168   // Switch to another task, and inform the reader that he has data:
00169   nextTask() = envir().taskScheduler().scheduleDelayedTask(0,
00170                                 (TaskFunc*)FramedSource::afterGetting, this);
00171 }

Generated on Tue Jul 22 06:39:05 2008 for live by  doxygen 1.5.2