Boolean CASpeexDecoder::GenerateFrames() { Boolean ret = true; int result; mBDCStatus = kBDCStatusOK; SpeexFramePacket &sfp = mSpeexFPList.front(); speex_bits_read_from(&mSpeexBits, reinterpret_cast<char*> (mBDCBuffer.GetData()), sfp.bytes); if (sfp.frames > 0 && (sfp.frames - mSpeexHeader.frame_size * mSpeexHeader.frames_per_packet > 0)) { UInt32 zeroBytes = mOutputFormat.FramesToBytes(sfp.frames - mSpeexHeader.frame_size * mSpeexHeader.frames_per_packet); memset(mOutBuffer + mOutBufferUsedSize, 0, zeroBytes); mOutBufferUsedSize += zeroBytes; } for (SInt32 i = 0; i < mSpeexHeader.frames_per_packet; i++) { if (mOutputFormat.mFormatFlags & kAudioFormatFlagsNativeFloatPacked != 0) result = speex_decode(mSpeexDecoderState, &mSpeexBits, reinterpret_cast<float*> (mOutBuffer + mOutBufferUsedSize)); else result = speex_decode_int(mSpeexDecoderState, &mSpeexBits, reinterpret_cast<spx_int16_t*> (mOutBuffer + mOutBufferUsedSize)); if (result < 0) { mBDCStatus = kBDCStatusAbort; return false; } if (mSpeexHeader.nb_channels == 2) { if (mOutputFormat.mFormatFlags & kAudioFormatFlagsNativeFloatPacked != 0) speex_decode_stereo(reinterpret_cast<float*> (mOutBuffer + mOutBufferUsedSize), mSpeexHeader.frame_size, &mSpeexStereoState); else speex_decode_stereo_int(reinterpret_cast<spx_int16_t*> (mOutBuffer + mOutBufferUsedSize), mSpeexHeader.frame_size, &mSpeexStereoState); } mOutBufferUsedSize += mOutputFormat.FramesToBytes(mSpeexHeader.frame_size); } if (sfp.frames == 0) { mNumFrames += mSpeexHeader.frame_size * mSpeexHeader.frames_per_packet; } else if (sfp.frames > 0) { mNumFrames += sfp.frames; if (mSpeexHeader.frame_size * mSpeexHeader.frames_per_packet - sfp.frames != 0) mOutBufferStart += mOutputFormat.FramesToBytes(mSpeexHeader.frame_size * mSpeexHeader.frames_per_packet - sfp.frames); } else { mNumFrames -= sfp.frames; } mBDCBuffer.Zap(sfp.bytes); mSpeexFPList.erase(mSpeexFPList.begin()); return ret; }
void speex_decode_stereo_int(short *data, int frame_size, SpeexStereoState *stereo) { int i; /* FIXME: Do some dynamic allocation here */ float float_data[2*MAX_IN_SAMPLES]; speex_decode_stereo(float_data, frame_size, stereo); for (i=0;i<frame_size;i++) { if (float_data[i]>32767.f) data[i] = 32767; else if (float_data[i]<-32768.f) data[i] = -32768; else data[i] = (short)floor(.5+float_data[i]); } }
UInt32 OggSpeexDecoder::ReadAudio(AudioBufferList *bufferList, UInt32 frameCount) { if(!IsOpen() || NULL == bufferList || bufferList->mNumberBuffers != mFormat.mChannelsPerFrame || 0 == frameCount) return 0; UInt32 framesRead = 0; // Reset output buffer data size for(UInt32 i = 0; i < bufferList->mNumberBuffers; ++i) bufferList->mBuffers[i].mDataByteSize = 0; for(;;) { UInt32 framesRemaining = frameCount - framesRead; UInt32 framesToSkip = static_cast<UInt32>(bufferList->mBuffers[0].mDataByteSize / sizeof(float)); UInt32 framesInBuffer = static_cast<UInt32>(mBufferList->mBuffers[0].mDataByteSize / sizeof(float)); UInt32 framesToCopy = std::min(framesInBuffer, framesRemaining); // Copy data from the buffer to output for(UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i) { float *floatBuffer = static_cast<float *>(bufferList->mBuffers[i].mData); memcpy(floatBuffer + framesToSkip, mBufferList->mBuffers[i].mData, framesToCopy * sizeof(float)); bufferList->mBuffers[i].mDataByteSize += static_cast<UInt32>(framesToCopy * sizeof(float)); // Move remaining data in buffer to beginning if(framesToCopy != framesInBuffer) { floatBuffer = static_cast<float *>(mBufferList->mBuffers[i].mData); memmove(floatBuffer, floatBuffer + framesToCopy, (framesInBuffer - framesToCopy) * sizeof(float)); } mBufferList->mBuffers[i].mDataByteSize -= static_cast<UInt32>(framesToCopy * sizeof(float)); } framesRead += framesToCopy; // All requested frames were read if(framesRead == frameCount) break; // EOS reached if(mSpeexEOSReached) break; // Attempt to process the desired number of packets unsigned packetsDesired = 1; while(0 < packetsDesired && !mSpeexEOSReached) { // Process any packets in the current page while(0 < packetsDesired && !mSpeexEOSReached) { // Grab a packet from the streaming layer ogg_packet oggPacket; int result = ogg_stream_packetout(&mOggStreamState, &oggPacket); if(-1 == result) { LOGGER_ERR("org.sbooth.AudioEngine.AudioDecoder.OggSpeex", "Ogg Speex decoding error: Ogg loss of streaming"); break; } // If result is 0, there is insufficient data to assemble a packet if(0 == result) break; // Otherwise, we got a valid packet for processing if(1 == result) { if(5 <= oggPacket.bytes && !memcmp(oggPacket.packet, "Speex", 5)) mSpeexSerialNumber = mOggStreamState.serialno; if(-1 == mSpeexSerialNumber || mOggStreamState.serialno != mSpeexSerialNumber) break; // Ignore the following: // - Speex comments in packet #2 // - Extra headers (optionally) in packets 3+ if(1 != mOggPacketCount && 1 + mExtraSpeexHeaderCount <= mOggPacketCount) { // Detect Speex EOS if(oggPacket.e_o_s && mOggStreamState.serialno == mSpeexSerialNumber) mSpeexEOSReached = true; // SPEEX_GET_FRAME_SIZE is in samples spx_int32_t speexFrameSize; speex_decoder_ctl(mSpeexDecoder, SPEEX_GET_FRAME_SIZE, &speexFrameSize); float buffer [(2 == mFormat.mChannelsPerFrame) ? 2 * speexFrameSize : speexFrameSize]; // Copy the Ogg packet to the Speex bitstream speex_bits_read_from(&mSpeexBits, (char *)oggPacket.packet, static_cast<int>(oggPacket.bytes)); // Decode each frame in the Speex packet for(spx_int32_t i = 0; i < mSpeexFramesPerOggPacket; ++i) { result = speex_decode(mSpeexDecoder, &mSpeexBits, buffer); // -1 indicates EOS if(-1 == result) break; else if(-2 == result) { LOGGER_ERR("org.sbooth.AudioEngine.AudioDecoder.OggSpeex", "Ogg Speex decoding error: possible corrupted stream"); break; } if(0 > speex_bits_remaining(&mSpeexBits)) { LOGGER_ERR("org.sbooth.AudioEngine.AudioDecoder.OggSpeex", "Ogg Speex decoding overflow: possible corrupted stream"); break; } // Normalize the values float maxSampleValue = 1u << 15; vDSP_vsdiv(buffer, 1, &maxSampleValue, buffer, 1, speexFrameSize); // Copy the frames from the decoding buffer to the output buffer, skipping over any frames already decoded framesInBuffer = static_cast<UInt32>(mBufferList->mBuffers[0].mDataByteSize / sizeof(float)); memcpy(static_cast<float *>(mBufferList->mBuffers[0].mData) + framesInBuffer, buffer, speexFrameSize * sizeof(float)); mBufferList->mBuffers[0].mDataByteSize += static_cast<UInt32>(speexFrameSize * sizeof(float)); // Process stereo channel, if present if(2 == mFormat.mChannelsPerFrame) { speex_decode_stereo(buffer, speexFrameSize, mSpeexStereoState); vDSP_vsdiv(buffer + speexFrameSize, 1, &maxSampleValue, buffer + speexFrameSize, 1, speexFrameSize); memcpy(static_cast<float *>(mBufferList->mBuffers[1].mData) + framesInBuffer, buffer + speexFrameSize, speexFrameSize * sizeof(float)); mBufferList->mBuffers[1].mDataByteSize += static_cast<UInt32>(speexFrameSize * sizeof(float)); } // Packet processing finished --packetsDesired; } } ++mOggPacketCount; } } // Grab a new Ogg page for processing, if necessary if(!mSpeexEOSReached && 0 < packetsDesired) { while(1 != ogg_sync_pageout(&mOggSyncState, &mOggPage)) { // Get the ogg buffer for writing char *data = ogg_sync_buffer(&mOggSyncState, READ_SIZE_BYTES); // Read bitstream from input file ssize_t bytesRead = GetInputSource()->Read(data, READ_SIZE_BYTES); if(-1 == bytesRead) { LOGGER_ERR("org.sbooth.AudioEngine.AudioDecoder.OggSpeex", "Unable to read from the input file"); break; } ogg_sync_wrote(&mOggSyncState, bytesRead); // No more data available from input file if(0 == bytesRead) break; } // Ensure all Ogg streams are read if(ogg_page_serialno(&mOggPage) != mOggStreamState.serialno) ogg_stream_reset_serialno(&mOggStreamState, ogg_page_serialno(&mOggPage)); // Get the resultant Ogg page int result = ogg_stream_pagein(&mOggStreamState, &mOggPage); if(0 != result) { LOGGER_ERR("org.sbooth.AudioEngine.AudioDecoder.OggSpeex", "Error reading Ogg page"); break; } } } } mCurrentFrame += framesRead; if(0 == framesRead && mSpeexEOSReached) mTotalFrames = mCurrentFrame; return framesRead; }
static gint xmms_speex_read (xmms_xform_t *xform, gpointer buf, gint len, xmms_error_t *err) { gint ret = 0, n; gfloat outfloat [2000]; gint16 *outbuf = (gint16 *) buf; xmms_speex_data_t *data; xmms_error_t error; SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT; g_return_val_if_fail (xform, -1); data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, -1); /* convert from bytes to samples */ len /= 2; /* first, copy already decoded samples over if we have any. */ if (data->samples_count) { n = MIN (data->samples_count, len); memcpy (outbuf, data->samples_start, n * 2); data->samples_count -= n; if (!data->samples_count) { data->samples_start = data->samples_buf; } else { data->samples_start += n; } /* convert from samples to bytes */ return n * 2; } while (42) { gint samples_per_frame; samples_per_frame = data->speexheader->frame_size * data->speexheader->nb_channels; while (ogg_stream_packetout (&data->stream_state, &data->ogg_packet) == 1) { gint frame; speex_bits_read_from (&data->speex_bits, (char *)data->ogg_packet.packet, data->ogg_packet.bytes); for (frame = 0; frame < data->speexheader->frames_per_packet; frame++) { gint cnt; speex_decode (data->speex_state, &data->speex_bits, outfloat); if (data->speexheader->nb_channels == 2) { speex_decode_stereo (outfloat, data->speexheader->frame_size,&stereo); } n = MIN (samples_per_frame, len); /* copy as many samples to the output buffer as * possible. */ for (cnt = 0; cnt < n; cnt++) { *outbuf++ = outfloat[cnt]; len--; ret += 2; } /* store the remaining samples for later use */ for (; cnt < samples_per_frame; cnt++) { data->samples_buf[data->samples_count++] = outfloat[cnt]; } } return ret; } /* Need more data */ do { gint ret; data->ogg_data = ogg_sync_buffer (&data->sync_state, 200); ret = xmms_xform_read (xform, data->ogg_data, 200, &error); ogg_sync_wrote (&data->sync_state, ret); if (ret <= 0) { return ret; } } while (ogg_sync_pageout (&data->sync_state, &data->ogg_page) != 1); ogg_stream_pagein (&data->stream_state, &data->ogg_page); } }