--- a/src/mp3transcode/mp3transcode.cpp +++ b/src/mp3transcode/mp3transcode.cpp @@ -41,10 +41,28 @@ " God knows what. Chris can read the \"best documentation " " there is\" to find out. :P" ); } + + // Maybe give these a good start value? They'll grow as needed anyway. + m_decBufSize = 1; // On my machine this grows to about 120K + m_encBufSize = 1; // And this grows to about 6K or so. + m_encBufReadIndex = m_encBufWriteIndex = 0; + m_decBufReadIndex = m_decBufWriteIndex = 0; + m_decodedBuffer = (char*)malloc( m_decBufSize ); + m_encodedBuffer = (char*)malloc( m_encBufSize ); } MP3Transcode::~MP3Transcode() { + if ( m_decodedBuffer ) + { + free( m_decodedBuffer); + m_decodedBuffer = NULL; + } + if ( m_encodedBuffer ) + { + free( m_encodedBuffer); + m_encodedBuffer = NULL; + } ExitMP3( &mpeg ); } @@ -61,24 +79,84 @@ return QStringList( "mp3" ); } +void +MP3Transcode::expandRingBuffer( char** buffer, int& bufSize, int& readIndex, int& writeIndex, int growSize ) +{ + //qDebug() << "resizing buffer from" << bufSize + // << "to" << bufSize + growSize; + char* tmp; + tmp = (char*)realloc( *buffer, sizeof(char) * ( bufSize + growSize ) ); + if ( tmp == NULL ) + { + Q_ASSERT( !"Could not reallocate buffer!" ); + return; + } + else + *buffer = tmp; + + // Don't screw up the read order or ugly noises will ensue + if ( readIndex > writeIndex ) + { + memmove( *buffer + readIndex + growSize, + *buffer + readIndex, + bufSize - readIndex ); + readIndex += growSize; + } + bufSize += growSize; +} + + bool MP3Transcode::processData( const QByteArray &buffer ) { - m_encodedBuffer.append( buffer ); + int length = buffer.size(); + int cnt; + const char* src = buffer.data(); + int neededSize = getEncodedBufferFilled() + buffer.size(); + + if ( neededSize >= m_encBufSize ) + expandRingBuffer( &m_encodedBuffer, m_encBufSize, + m_encBufReadIndex, m_encBufWriteIndex, + neededSize - m_encBufSize + 1 ); + + while ( length > 0 ) + { + int wr; + cnt = qMin( length, m_encBufSize - m_encBufWriteIndex ); + memcpy( m_encodedBuffer + m_encBufWriteIndex, src, cnt ); + wr = (m_encBufWriteIndex + cnt) % m_encBufSize; + m_encBufWriteIndex = wr; + length -= cnt; + src += cnt; + } // wait till we got a minimal buffer of data, which we need for mpglib // being able to properly read the audio metadata (samplerate, channels...) - if ( m_encodedBuffer.size() <= MP3_MIN_BUFFER_SIZE ) + if ( getEncodedBufferFilled() <= MP3_MIN_BUFFER_SIZE ) { return true; } char tempBuffer[16384]; int size; + unsigned char inTemp[MP3_MIN_BUFFER_SIZE]; + length = MP3_MIN_BUFFER_SIZE; + int outLen = 0; + while ( length > 0 ) + { + int rd; + cnt = qMin(length, m_encBufSize - m_encBufReadIndex); + memcpy( inTemp + outLen, m_encodedBuffer + m_encBufReadIndex, cnt); + rd = (m_encBufReadIndex + cnt) % m_encBufSize; + m_encBufReadIndex = rd; + length -= cnt; + outLen += cnt; + } + int result = decodeMP3( &mpeg, // handle - (unsigned char*)m_encodedBuffer.data(), // in-data + inTemp, // in-data MP3_MIN_BUFFER_SIZE, // size of in-data tempBuffer, // out-data sizeof( tempBuffer ), // size of out-data @@ -111,11 +189,29 @@ emit streamInitialized( sampleRate, channels ); } - m_encodedBuffer.remove( 0, MP3_MIN_BUFFER_SIZE ); while ( result == MP3_OK ) { - m_decodedBuffer.append( QByteArray::fromRawData( tempBuffer, size ) ); - + int length = size; + int cnt; + const char* src = tempBuffer; + int neededSize = getDecodedBufferFilled() + size; + + if ( neededSize >= m_decBufSize ) + expandRingBuffer( &m_decodedBuffer, m_decBufSize, + m_decBufReadIndex, m_decBufWriteIndex, + ( neededSize - m_decBufSize + 1 ) ); + + while (length > 0) + { + int wr; + cnt = qMin(length, m_decBufSize - m_decBufWriteIndex); + memcpy( m_decodedBuffer + m_decBufWriteIndex, src, cnt); + wr = (m_decBufWriteIndex + cnt) % m_decBufSize; + m_decBufWriteIndex = wr; + length -= cnt; + src += cnt; + } + result = decodeMP3( &mpeg, NULL, 0, tempBuffer, sizeof( tempBuffer ), &size ); if ( result == MP3_ERR ) @@ -134,8 +230,8 @@ { ExitMP3( &mpeg ); - m_encodedBuffer.clear(); - m_decodedBuffer.clear(); + m_decBufReadIndex = m_decBufWriteIndex = 0; + m_encBufReadIndex = m_encBufWriteIndex = 0; m_mpegInitialised = false; if ( !InitMP3( &mpeg ) ) @@ -146,26 +242,56 @@ } } +int +MP3Transcode::getEncodedBufferFilled() +{ + if ( m_encBufWriteIndex >= m_encBufReadIndex ) + { + return m_encBufWriteIndex - m_encBufReadIndex; + } + return ( m_encBufSize - ( m_encBufReadIndex - m_encBufWriteIndex ) ); +} + +int +MP3Transcode::getDecodedBufferFilled() +{ + if ( m_decBufWriteIndex >= m_decBufReadIndex ) + { + return m_decBufWriteIndex - m_decBufReadIndex; + } + return ( m_decBufSize - ( m_decBufReadIndex - m_decBufWriteIndex ) ); +} bool MP3Transcode::needsData() { - return m_decodedBuffer.size() < m_decodedBufferCapacity; + return getDecodedBufferFilled() < m_decodedBufferCapacity; } bool MP3Transcode::hasData() { - return !m_decodedBuffer.isEmpty(); + return ( getDecodedBufferFilled() > 0 ); } void MP3Transcode::data( QByteArray& fillMe, int numBytes ) { - fillMe = m_decodedBuffer.left( numBytes ); - m_decodedBuffer.remove( 0, numBytes ); + int length; + int cnt; + length = qMin( numBytes, getDecodedBufferFilled() ); + + while (length > 0) + { + int rd; + cnt = qMin (length, m_decBufSize - m_decBufReadIndex ); + fillMe.append( QByteArray::fromRawData( m_decodedBuffer + m_decBufReadIndex, cnt ) ); + rd = ( m_decBufReadIndex + cnt ) % m_decBufSize; + m_decBufReadIndex = rd; + length -= cnt; + } } --- a/src/mp3transcode/mp3transcode.h +++ b/src/mp3transcode/mp3transcode.h @@ -26,8 +26,6 @@ #include "mpglib/interface.h" #include <QByteArray> #include <QObject> -#include <QMutex> -#include <QFile> /*************************************************************************/ /** @@ -64,7 +62,7 @@ setBufferCapacity( int bytes ) { m_decodedBufferCapacity = bytes; } int - bufferSize() { return m_decodedBuffer.size(); } + bufferSize() { return getDecodedBufferFilled(); } public slots: virtual void clearBuffers(); @@ -74,12 +72,20 @@ void streamInitialized( long sampleRate, int channels ); private: - QByteArray m_encodedBuffer; - QByteArray m_decodedBuffer; - + char* m_encodedBuffer; + char* m_decodedBuffer; + int m_decBufSize, m_decBufWriteIndex, m_decBufReadIndex; + int m_encBufSize, m_encBufWriteIndex, m_encBufReadIndex; + int m_decodedBufferCapacity; bool m_mpegInitialised; + + int getDecodedBufferFilled(); + int getEncodedBufferFilled(); + void expandRingBuffer( char** buffer, int& bufSize, + int& readIndex, int& writeIndex, + int growSize ); }; #endif