Changeset 1045

Show
Ignore:
Timestamp:
10/31/07 11:42:04 (15 months ago)
Author:
stephen_booth
Message:

Improve seeking speed

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/Audio/Decoders/MPEGDecoder.m

    r1036 r1045  
    2727 
    2828#define INPUT_BUFFER_SIZE       (5 * 8192) 
    29 #define SEEK_BUFFER_SIZE        1024 
    3029#define LAME_HEADER_SIZE        ((8 * 5) + 4 + 4 + 8 + 32 + 16 + 16 + 4 + 4 + 8 + 12 + 12 + 8 + 8 + 2 + 3 + 11 + 32 + 32 + 32) 
    3130 
     
    682681        NSParameterAssert(0 <= frame && frame < [self totalFrames]); 
    683682         
    684         // Brute-force seeking is necessary since frame-accurate seeking is required 
     683        // Brute force seeking is necessary since frame-accurate seeking is required 
     684         
     685        UInt32                  bytesToRead; 
     686        UInt32                  bytesRemaining; 
     687        unsigned char   *readStartPointer; 
     688        int32_t                 audioSample; 
     689         
     690        BOOL                    readEOF                                 = NO; 
     691        float                   scaleFactor                             = (1L << (BIT_RESOLUTION - 1)); 
    685692         
    686693        // To seek to a frame earlier in the file, rewind to the beginning 
     
    702709                mad_stream_buffer(&_mad_stream, NULL, 0); 
    703710        } 
    704          
    705         // Allocate a buffer list to use for seeking 
    706         AudioBufferList *bufferList = calloc(sizeof(AudioBufferList) + (sizeof(AudioBuffer) * (_format.mChannelsPerFrame - 1)), 1); 
    707         NSAssert(NULL != bufferList, @"Unable to allocate memory"); 
    708          
    709         bufferList->mNumberBuffers = _format.mChannelsPerFrame; 
    710          
    711         unsigned i; 
    712         for(i = 0; i < bufferList->mNumberBuffers; ++i) { 
    713                 bufferList->mBuffers[i].mData = calloc(SEEK_BUFFER_SIZE, sizeof(float)); 
    714                 NSAssert(NULL != bufferList->mBuffers[i].mData, @"Unable to allocate memory"); 
    715                  
    716                 bufferList->mBuffers[i].mNumberChannels = 1; 
     711 
     712        for(;;) { 
     713                // All requested frames were skipped or read 
     714                if(_samplesDecoded >= frame) 
     715                        break; 
     716 
     717                // If the file contains a Xing header but not LAME gapless information, 
     718                // decode the number of MPEG frames specified by the Xing header 
     719                if(_foundXingHeader && NO == _foundLAMEHeader && 1 + _mpegFramesDecoded == _totalMPEGFrames) 
     720                        break; 
     721                 
     722                // The LAME header indicates how many samples are in the file 
     723                if(_foundLAMEHeader && [self totalFrames] == _samplesDecoded) 
     724                        break; 
     725                 
     726                // Feed the input buffer if necessary 
     727                if(NULL == _mad_stream.buffer || MAD_ERROR_BUFLEN == _mad_stream.error) { 
     728                        if(NULL != _mad_stream.next_frame) { 
     729                                bytesRemaining = _mad_stream.bufend - _mad_stream.next_frame; 
     730                                memmove(_inputBuffer, _mad_stream.next_frame, bytesRemaining); 
     731                                 
     732                                readStartPointer        = _inputBuffer + bytesRemaining; 
     733                                bytesToRead                     = INPUT_BUFFER_SIZE - bytesRemaining; 
     734                        } 
     735                        else { 
     736                                bytesToRead                     = INPUT_BUFFER_SIZE, 
     737                                readStartPointer        = _inputBuffer, 
     738                                bytesRemaining          = 0; 
     739                        } 
     740                         
     741                        // Read raw bytes from the MP3 file 
     742                        size_t bytesRead = fread(readStartPointer, 1, bytesToRead, _file); 
     743                        if(ferror(_file)) { 
     744#if DEBUG 
     745                                NSLog(@"Read error: %s.", strerror(errno)); 
     746#endif 
     747                                break; 
     748                        } 
     749                         
     750                        // MAD_BUFFER_GUARD zeroes are required to decode the last frame of the file 
     751                        if(feof(_file)) { 
     752                                memset(readStartPointer + bytesRead, 0, MAD_BUFFER_GUARD); 
     753                                bytesRead       += MAD_BUFFER_GUARD; 
     754                                readEOF         = YES; 
     755                        } 
     756                         
     757                        mad_stream_buffer(&_mad_stream, _inputBuffer, bytesRead + bytesRemaining); 
     758                        _mad_stream.error = MAD_ERROR_NONE; 
     759                } 
     760                 
     761                // Decode the header only of the MPEG frame for speed 
     762                int result = mad_header_decode(&_mad_frame.header, &_mad_stream); 
     763                if(-1 == result) { 
     764                        if(MAD_RECOVERABLE(_mad_stream.error)) { 
     765                                // Prevent ID3 tags from reporting recoverable frame errors 
     766                                const uint8_t   *buffer                 = _mad_stream.this_frame; 
     767                                unsigned                buflen                  = _mad_stream.bufend - _mad_stream.this_frame; 
     768                                uint32_t                id3_length              = 0; 
     769                                 
     770                                if(10 <= buflen && 0x49 == buffer[0] && 0x44 == buffer[1] && 0x33 == buffer[2]) { 
     771                                        id3_length = (((buffer[6] & 0x7F) << (3 * 7)) | ((buffer[7] & 0x7F) << (2 * 7)) | 
     772                                                                  ((buffer[8] & 0x7F) << (1 * 7)) | ((buffer[9] & 0x7F) << (0 * 7))); 
     773                                         
     774                                        // Add 10 bytes for ID3 header 
     775                                        id3_length += 10; 
     776                                         
     777                                        mad_stream_skip(&_mad_stream, id3_length); 
     778                                } 
     779#if DEBUG 
     780                                else 
     781                                        NSLog(@"Recoverable frame level error (%s)", mad_stream_errorstr(&_mad_stream)); 
     782#endif 
     783                                 
     784                                continue; 
     785                        } 
     786                        // EOS for non-Xing streams occurs when EOF is reached and no further frames can be decoded 
     787                        else if(MAD_ERROR_BUFLEN == _mad_stream.error && readEOF) 
     788                                break; 
     789                        else if(MAD_ERROR_BUFLEN == _mad_stream.error) 
     790                                continue; 
     791                        else { 
     792#if DEBUG 
     793                                NSLog(@"Unrecoverable frame level error (%s)", mad_stream_errorstr(&_mad_stream)); 
     794#endif 
     795                                break; 
     796                        } 
     797                } 
     798                 
     799                // Housekeeping 
     800                ++_mpegFramesDecoded; 
     801 
     802                // Skip any samples that remain from last frame 
     803                // This can happen if the encoder delay is greater than the number of samples in a frame 
     804                unsigned startingSample = _samplesToSkipInNextFrame; 
     805                 
     806                // Skip the Xing header (it contains empty audio) 
     807                if(_foundXingHeader && 1 == _mpegFramesDecoded) 
     808                        continue; 
     809                // Adjust the first real audio frame for gapless playback 
     810                else if(_foundLAMEHeader && 2 == _mpegFramesDecoded) 
     811                        startingSample += _encoderDelay; 
     812 
     813                // The number of samples in this frame 
     814                unsigned sampleCount = 32 * MAD_NSBSAMPLES(&_mad_frame.header); 
     815                 
     816                // Skip this entire frame if necessary 
     817                if(startingSample > sampleCount) { 
     818                        _samplesToSkipInNextFrame += startingSample - sampleCount; 
     819                        continue; 
     820                } 
     821                else 
     822                        _samplesToSkipInNextFrame = 0; 
     823                 
     824                // If a LAME header was found, the total number of audio frames (AKA samples)  
     825                // is known.  Ensure only that many are output 
     826                if(_foundLAMEHeader && [self totalFrames] < _samplesDecoded + (sampleCount - startingSample)) 
     827                        sampleCount = [self totalFrames] - _samplesDecoded; 
     828 
     829                // If this MPEG frame contains the desired seek frame, synthesize its audio to PCM 
     830                if(_samplesDecoded + (sampleCount - startingSample) > frame) { 
     831                        // Finish decoding the MPEG frame 
     832                        result = mad_frame_decode(&_mad_frame, &_mad_stream); 
     833                        if(-1 == result) { 
     834                                if(MAD_RECOVERABLE(_mad_stream.error)) { 
     835        #if DEBUG 
     836                                        NSLog(@"Recoverable frame level error (%s)", mad_stream_errorstr(&_mad_stream)); 
     837        #endif 
     838                                        continue; 
     839                                } 
     840                                else { 
     841        #if DEBUG 
     842                                        NSLog(@"Unrecoverable frame level error (%s)", mad_stream_errorstr(&_mad_stream)); 
     843        #endif 
     844                                        break; 
     845                                } 
     846                        } 
     847                         
     848                        // Synthesize the frame into PCM 
     849                        mad_synth_frame(&_mad_synth, &_mad_frame); 
     850 
     851                        // Skip any audio frames before the sample we are seeking to 
     852                        unsigned additionalSamplesToSkip = frame - _samplesDecoded; 
     853                         
     854                        // Output samples in 32-bit float PCM 
     855                        unsigned channel, sample; 
     856                        for(channel = 0; channel < MAD_NCHANNELS(&_mad_frame.header); ++channel) { 
     857                                float *floatBuffer = _bufferList->mBuffers[channel].mData; 
     858                                 
     859                                for(sample = startingSample + additionalSamplesToSkip; sample < sampleCount; ++sample) { 
     860                                        audioSample = audio_linear_round(BIT_RESOLUTION, _mad_synth.pcm.samples[channel][sample]); 
     861                                         
     862                                        if(0 <= audioSample) 
     863                                                *floatBuffer++ = (float)(audioSample / (scaleFactor - 1)); 
     864                                        else 
     865                                                *floatBuffer++ = (float)(audioSample / scaleFactor); 
     866                                } 
     867                                 
     868                                _bufferList->mBuffers[channel].mNumberChannels  = 1; 
     869                                _bufferList->mBuffers[channel].mDataByteSize    = (sampleCount - (startingSample + additionalSamplesToSkip)) * sizeof(float); 
     870                        } 
     871 
     872                        // Only a portion of the frame was skipped- the rest was synthesized and stored in our buffers 
     873                        _samplesDecoded += additionalSamplesToSkip; 
     874                } 
     875                // The entire frame was skipped 
     876                else 
     877                        _samplesDecoded += (sampleCount - startingSample); 
    717878        } 
    718879         
    719         // Decode until the desired frame is reached             
    720         for(;;) { 
    721                 UInt32 framesRemaining  = frame - [self currentFrame]; 
    722                 UInt32 framesToRead             = (SEEK_BUFFER_SIZE > framesRemaining ? framesRemaining : SEEK_BUFFER_SIZE);; 
    723                  
    724                 if(0 == framesRemaining) 
    725                         break; 
    726                  
    727                 UInt32 framesRead = [self readAudio:bufferList frameCount:framesToRead]; 
    728                 if(0 == framesRead) 
    729                         break; 
    730         } 
    731          
    732         for(i = 0; i < bufferList->mNumberBuffers; ++i) 
    733                 free(bufferList->mBuffers[i].mData), bufferList->mBuffers[i].mData = NULL;       
    734         free(bufferList), bufferList = NULL; 
     880        _currentFrame = _samplesDecoded; 
    735881         
    736882        return [self currentFrame];