| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- /******************************************************************************
- *
- * Copyright (C) 2014 The Android Open Source Project
- * Copyright 2006 Open Interface North America, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************/
- /**********************************************************************************
- $Revision: #1 $
- ***********************************************************************************/
- /** @file
- @ingroup codec_internal
- */
- /**@addtogroup codec_internal */
- /**@{*/
- #include "common/bt_target.h"
- #include "oi_codec_sbc_private.h"
- #include "oi_bitstream.h"
- #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE)
- #define SPECIALIZE_READ_SAMPLES_JOINT
- /**
- * Scans through a buffer looking for a codec syncword. If the decoder has been
- * set for enhanced operation using OI_CODEC_SBC_DecoderReset(), it will search
- * for both a standard and an enhanced syncword.
- */
- PRIVATE OI_STATUS FindSyncword(OI_CODEC_SBC_DECODER_CONTEXT *context,
- const OI_BYTE **frameData,
- OI_UINT32 *frameBytes)
- {
- #ifdef SBC_ENHANCED
- OI_BYTE search1 = OI_SBC_SYNCWORD;
- OI_BYTE search2 = OI_SBC_ENHANCED_SYNCWORD;
- #endif // SBC_ENHANCED
- if (*frameBytes == 0) {
- return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
- }
- #ifdef SBC_ENHANCED
- if (context->limitFrameFormat && context->enhancedEnabled) {
- /* If the context is restricted, only search for specified SYNCWORD */
- search1 = search2;
- } else if (context->enhancedEnabled == FALSE) {
- /* If enhanced is not enabled, only search for classic SBC SYNCWORD*/
- search2 = search1;
- }
- while (*frameBytes && (**frameData != search1) && (**frameData != search2)) {
- (*frameBytes)--;
- (*frameData)++;
- }
- if (*frameBytes) {
- /* Syncword found, *frameData points to it, and *frameBytes correctly
- * reflects the number of bytes available to read, including the
- * syncword. */
- context->common.frameInfo.enhanced = (**frameData == OI_SBC_ENHANCED_SYNCWORD);
- return OI_OK;
- } else {
- /* No syncword was found anywhere in the provided input data.
- * *frameData points past the end of the original input, and
- * *frameBytes is 0. */
- return OI_CODEC_SBC_NO_SYNCWORD;
- }
- #else // SBC_ENHANCED
- while (*frameBytes
- && (!(context->sbc_mode == OI_SBC_MODE_STD && **frameData == OI_SBC_SYNCWORD))
- && (!(context->sbc_mode == OI_SBC_MODE_MSBC && **frameData == OI_mSBC_SYNCWORD))) {
- (*frameBytes)--;
- (*frameData)++;
- }
- if (*frameBytes) {
- /* Syncword found, *frameData points to it, and *frameBytes correctly
- * reflects the number of bytes available to read, including the
- * syncword. */
- context->common.frameInfo.enhanced = FALSE;
- return OI_OK;
- } else {
- /* No syncword was found anywhere in the provided input data.
- * *frameData points past the end of the original input, and
- * *frameBytes is 0. */
- return OI_CODEC_SBC_NO_SYNCWORD;
- }
- #endif // SBC_ENHANCED
- }
- static OI_STATUS DecodeBody(OI_CODEC_SBC_DECODER_CONTEXT *context,
- const OI_BYTE *bodyData,
- OI_INT16 *pcmData,
- OI_UINT32 *pcmBytes,
- OI_BOOL allowPartial)
- {
- OI_BITSTREAM bs;
- OI_UINT frameSamples = context->common.frameInfo.nrof_blocks * context->common.frameInfo.nrof_subbands;
- OI_UINT decode_block_count;
- /*
- * Based on the header data, make sure that there is enough room to write the output samples.
- */
- if (*pcmBytes < (sizeof(OI_INT16) * frameSamples * context->common.pcmStride) && !allowPartial) {
- /* If we're not allowing partial decodes, we need room for the entire
- * codec frame */
- TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA"));
- return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA;
- } else if (*pcmBytes < sizeof (OI_INT16) * context->common.frameInfo.nrof_subbands * context->common.pcmStride) {
- /* Even if we're allowing partials, we can still only decode on a frame
- * boundary */
- return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA;
- }
- if (context->bufferedBlocks == 0) {
- TRACE(("Reading scalefactors"));
- OI_SBC_ReadScalefactors(&context->common, bodyData, &bs);
- TRACE(("Computing bit allocation"));
- OI_SBC_ComputeBitAllocation(&context->common);
- TRACE(("Reading samples"));
- if (context->common.frameInfo.mode == SBC_JOINT_STEREO) {
- OI_SBC_ReadSamplesJoint(context, &bs);
- } else {
- OI_SBC_ReadSamples(context, &bs);
- }
- context->bufferedBlocks = context->common.frameInfo.nrof_blocks;
- }
- if (allowPartial) {
- decode_block_count = *pcmBytes / sizeof(OI_INT16) / context->common.pcmStride / context->common.frameInfo.nrof_subbands;
- if (decode_block_count > context->bufferedBlocks) {
- decode_block_count = context->bufferedBlocks;
- }
- } else {
- decode_block_count = context->common.frameInfo.nrof_blocks;
- }
- TRACE(("Synthesizing frame"));
- {
- OI_UINT start_block = context->common.frameInfo.nrof_blocks - context->bufferedBlocks;
- OI_SBC_SynthFrame(context, pcmData, start_block, decode_block_count);
- }
- OI_ASSERT(context->bufferedBlocks >= decode_block_count);
- context->bufferedBlocks -= decode_block_count;
- frameSamples = decode_block_count * context->common.frameInfo.nrof_subbands;
- /*
- * When decoding mono into a stride-2 array, copy pcm data to second channel
- */
- if (context->common.frameInfo.nrof_channels == 1 && context->common.pcmStride == 2) {
- OI_UINT i;
- for (i = 0; i < frameSamples; ++i) {
- pcmData[2 * i + 1] = pcmData[2 * i];
- }
- }
- /*
- * Return number of pcm bytes generated by the decode operation.
- */
- *pcmBytes = frameSamples * sizeof(OI_INT16) * context->common.pcmStride;
- if (context->bufferedBlocks > 0) {
- return OI_CODEC_SBC_PARTIAL_DECODE;
- } else {
- return OI_OK;
- }
- }
- PRIVATE OI_STATUS internal_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT *context,
- OI_UINT8 bitpool,
- const OI_BYTE **frameData,
- OI_UINT32 *frameBytes,
- OI_INT16 *pcmData,
- OI_UINT32 *pcmBytes)
- {
- OI_STATUS status;
- OI_UINT bodyLen;
- TRACE(("+OI_CODEC_SBC_DecodeRaw"));
- if (context->bufferedBlocks == 0) {
- /*
- * The bitallocator needs to know the bitpool value.
- */
- context->common.frameInfo.bitpool = bitpool;
- /*
- * Compute the frame length and check we have enough frame data to proceed
- */
- bodyLen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo) - SBC_HEADER_LEN;
- if (*frameBytes < bodyLen) {
- TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA"));
- return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
- }
- } else {
- bodyLen = 0;
- }
- /*
- * Decode the SBC data. Pass TRUE to DecodeBody to allow partial decoding of
- * tones.
- */
- status = DecodeBody(context, *frameData, pcmData, pcmBytes, TRUE);
- if (OI_SUCCESS(status) || status == OI_CODEC_SBC_PARTIAL_DECODE) {
- *frameData += bodyLen;
- *frameBytes -= bodyLen;
- }
- TRACE(("-OI_CODEC_SBC_DecodeRaw: %d", status));
- return status;
- }
- OI_STATUS OI_CODEC_SBC_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
- OI_UINT32 *decoderData,
- OI_UINT32 decoderDataBytes,
- OI_UINT8 maxChannels,
- OI_UINT8 pcmStride,
- OI_BOOL enhanced,
- OI_BOOL msbc_enable)
- {
- return internal_DecoderReset(context, decoderData, decoderDataBytes, maxChannels, pcmStride, enhanced, msbc_enable);
- }
- OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context,
- const OI_BYTE **frameData,
- OI_UINT32 *frameBytes,
- OI_INT16 *pcmData,
- OI_UINT32 *pcmBytes)
- {
- OI_STATUS status;
- OI_UINT framelen;
- OI_UINT8 crc;
- TRACE(("+OI_CODEC_SBC_DecodeFrame"));
- TRACE(("Finding syncword"));
- status = FindSyncword(context, frameData, frameBytes);
- if (!OI_SUCCESS(status)) {
- return status;
- }
- /* Make sure enough data remains to read the header. */
- if (*frameBytes < SBC_HEADER_LEN) {
- TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA"));
- return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
- }
- TRACE(("Reading Header"));
- OI_SBC_ReadHeader(&context->common, *frameData);
- /*
- * Some implementations load the decoder into RAM and use overlays for 4 vs 8 subbands. We need
- * to ensure that the SBC parameters for this frame are compatible with the restrictions imposed
- * by the loaded overlays.
- */
- if (context->limitFrameFormat && (context->common.frameInfo.subbands != context->restrictSubbands)) {
- ERROR(("SBC parameters incompatible with loaded overlay"));
- return OI_STATUS_INVALID_PARAMETERS;
- }
- if (context->common.frameInfo.nrof_channels > context->common.maxChannels) {
- ERROR(("SBC parameters incompatible with number of channels specified during reset"));
- return OI_STATUS_INVALID_PARAMETERS;
- }
- if (context->common.pcmStride < 1 || context->common.pcmStride > 2) {
- ERROR(("PCM stride not set correctly during reset"));
- return OI_STATUS_INVALID_PARAMETERS;
- }
- /*
- * At this point a header has been read. However, it's possible that we found a false syncword,
- * so the header data might be invalid. Make sure we have enough bytes to read in the
- * CRC-protected header, but don't require we have the whole frame. That way, if it turns out
- * that we're acting on bogus header data, we don't stall the decoding process by waiting for
- * data that we don't actually need.
- */
- framelen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo);
- if (*frameBytes < framelen) {
- TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA"));
- return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
- }
- TRACE(("Calculating checksum"));
- crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData);
- if (crc != context->common.frameInfo.crc) {
- TRACE(("CRC Mismatch: calc=%02x read=%02x\n", crc, context->common.frameInfo.crc));
- TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_CHECKSUM_MISMATCH"));
- return OI_CODEC_SBC_CHECKSUM_MISMATCH;
- }
- #ifdef OI_DEBUG
- /*
- * Make sure the bitpool values are sane.
- */
- if ((context->common.frameInfo.bitpool < SBC_MIN_BITPOOL) && !context->common.frameInfo.enhanced) {
- ERROR(("Bitpool too small: %d (must be >= 2)", context->common.frameInfo.bitpool));
- return OI_STATUS_INVALID_PARAMETERS;
- }
- if (context->common.frameInfo.bitpool > OI_SBC_MaxBitpool(&context->common.frameInfo)) {
- ERROR(("Bitpool too large: %d (must be <= %ld)", context->common.frameInfo.bitpool, OI_SBC_MaxBitpool(&context->common.frameInfo)));
- return OI_STATUS_INVALID_PARAMETERS;
- }
- #endif
- /*
- * Now decode the SBC data. Partial decode is not yet implemented for an SBC
- * stream, so pass FALSE to decode body to have it enforce the old rule that
- * you have to decode a whole packet at a time.
- */
- status = DecodeBody(context, *frameData + SBC_HEADER_LEN, pcmData, pcmBytes, FALSE);
- if (OI_SUCCESS(status)) {
- *frameData += framelen;
- *frameBytes -= framelen;
- }
- TRACE(("-OI_CODEC_SBC_DecodeFrame: %d", status));
- return status;
- }
- OI_STATUS OI_CODEC_SBC_SkipFrame(OI_CODEC_SBC_DECODER_CONTEXT *context,
- const OI_BYTE **frameData,
- OI_UINT32 *frameBytes)
- {
- OI_STATUS status;
- OI_UINT framelen;
- OI_UINT headerlen;
- OI_UINT8 crc;
- status = FindSyncword(context, frameData, frameBytes);
- if (!OI_SUCCESS(status)) {
- return status;
- }
- if (*frameBytes < SBC_HEADER_LEN) {
- return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
- }
- OI_SBC_ReadHeader(&context->common, *frameData);
- framelen = OI_SBC_CalculateFrameAndHeaderlen(&context->common.frameInfo, &headerlen);
- if (*frameBytes < headerlen) {
- return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
- }
- crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData);
- if (crc != context->common.frameInfo.crc) {
- return OI_CODEC_SBC_CHECKSUM_MISMATCH;
- }
- if (*frameBytes < framelen) {
- return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
- }
- context->bufferedBlocks = 0;
- *frameData += framelen;
- *frameBytes -= framelen;
- return OI_OK;
- }
- OI_UINT8 OI_CODEC_SBC_FrameCount(OI_BYTE *frameData,
- OI_UINT32 frameBytes)
- {
- OI_UINT8 mode;
- OI_UINT8 blocks;
- OI_UINT8 subbands;
- OI_UINT8 frameCount = 0;
- OI_UINT frameLen;
- while (frameBytes) {
- while (frameBytes && ((frameData[0] & 0xFE) != 0x9C)) {
- frameData++;
- frameBytes--;
- }
- if (frameBytes < SBC_HEADER_LEN) {
- return frameCount;
- }
- /* Extract and translate required fields from Header */
- subbands = mode = blocks = frameData[1];;
- mode = (mode & (BIT3 | BIT2)) >> 2;
- blocks = block_values[(blocks & (BIT5 | BIT4)) >> 4];
- subbands = band_values[(subbands & BIT0)];
- /* Inline logic to avoid corrupting context */
- frameLen = blocks * frameData[2];
- switch (mode) {
- case SBC_JOINT_STEREO:
- frameLen += subbands + (8 * subbands);
- break;
- case SBC_DUAL_CHANNEL:
- frameLen *= 2;
- /* fall through */
- default:
- if (mode == SBC_MONO) {
- frameLen += 4 * subbands;
- } else {
- frameLen += 8 * subbands;
- }
- }
- frameCount++;
- frameLen = SBC_HEADER_LEN + (frameLen + 7) / 8;
- if (frameBytes > frameLen) {
- frameBytes -= frameLen;
- frameData += frameLen;
- } else {
- frameBytes = 0;
- }
- }
- return frameCount;
- }
- /** Read quantized subband samples from the input bitstream and expand them. */
- #ifdef SPECIALIZE_READ_SAMPLES_JOINT
- PRIVATE void OI_SBC_ReadSamplesJoint4(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs)
- {
- #define NROF_SUBBANDS 4
- #include "readsamplesjoint.inc"
- #undef NROF_SUBBANDS
- }
- PRIVATE void OI_SBC_ReadSamplesJoint8(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs)
- {
- #define NROF_SUBBANDS 8
- #include "readsamplesjoint.inc"
- #undef NROF_SUBBANDS
- }
- typedef void (*READ_SAMPLES)(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs);
- static const READ_SAMPLES SpecializedReadSamples[] = {
- OI_SBC_ReadSamplesJoint4,
- OI_SBC_ReadSamplesJoint8
- };
- #endif /* SPECIALIZE_READ_SAMPLES_JOINT */
- PRIVATE void OI_SBC_ReadSamplesJoint(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs)
- {
- OI_CODEC_SBC_COMMON_CONTEXT *common = &context->common;
- OI_UINT nrof_subbands = common->frameInfo.nrof_subbands;
- #ifdef SPECIALIZE_READ_SAMPLES_JOINT
- OI_ASSERT((nrof_subbands >> 3u) <= 1u);
- SpecializedReadSamples[nrof_subbands >> 3](context, global_bs);
- #else
- #define NROF_SUBBANDS nrof_subbands
- #include "readsamplesjoint.inc"
- #undef NROF_SUBBANDS
- #endif /* SPECIALIZE_READ_SAMPLES_JOINT */
- }
- /**@}*/
- #endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */
|