external_ffmpeg/libavcodec/libfluoride-sbcdec.c

242 lines
8.8 KiB
C

/*
* Bluetooth low-complexity, subband codec (SBC)
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* SBC decoder implementation
*/
#include "avcodec.h"
#include "codec_internal.h"
#include "decode.h"
#include "internal.h"
#include "libavutil/intreadwrite.h"
#include <oi_codec_sbc.h>
#define MSBC_MAX_BLOCKS 15
#define SBC_SAMPLES_PER_FRAME (SBC_MAX_BANDS * SBC_MAX_BLOCKS)
#define MSBC_SAMPLES_PER_FRAME (SBC_MAX_BANDS * MSBC_MAX_BLOCKS)
#define DECODER_DATA_SIZE (SBC_MAX_CHANNELS * SBC_MAX_BLOCKS * SBC_MAX_BANDS * 4 \
+ SBC_CODEC_MIN_FILTER_BUFFERS * SBC_MAX_BANDS * SBC_MAX_CHANNELS * 2)
typedef struct SBCDecContext {
AVClass *class;
uint8_t data[DECODER_DATA_SIZE + 3];
OI_CODEC_SBC_DECODER_CONTEXT context;
} SBCDecContext;
static int sbc_decode_init(AVCodecContext *avctx)
{
SBCDecContext *sbc = avctx->priv_data;
OI_STATUS status;
/*
*msbc sample size is fixed to 120 by the sbc parser,
*and we use this to determine whether it is msbc.
*sbc sample size is usually 128.
*/
if (avctx->frame_size == MSBC_SAMPLES_PER_FRAME) {
status = OI_CODEC_SBC_DecoderReset(&sbc->context, (uint32_t *)sbc->data,
sizeof(sbc->data), 1, avctx->ch_layout.nb_channels, false);
if (!OI_SUCCESS(status))
return AVERROR(status);
status = OI_CODEC_SBC_DecoderConfigureMSbc(&sbc->context);
if (!OI_SUCCESS(status))
return AVERROR(status);
} else {
status = OI_CODEC_SBC_DecoderReset(&sbc->context, (uint32_t *)sbc->data,
sizeof(sbc->data), 2, avctx->ch_layout.nb_channels, false);
if (!OI_SUCCESS(status))
return AVERROR(status);
}
avctx->sample_fmt = AV_SAMPLE_FMT_S16;
return 0;
}
static int sbc_packed_decode_frame(AVCodecContext *avctx, AVFrame *frame,
int *got_frame_ptr, AVPacket *avpkt)
{
SBCDecContext *sbc = avctx->priv_data;
const OI_BYTE* in_data;
uint32_t in_size, out_avail;
uint8_t *out_ptr;
int nframes;
int ret;
int i;
if (!sbc)
return AVERROR(EIO);
nframes = avpkt->data[0] & 0xf;
if (avpkt->data[1] == OI_SBC_MSBC_SYNCWORD)
frame->nb_samples = nframes * MSBC_SAMPLES_PER_FRAME;
else if (avpkt->data[1] == OI_SBC_SYNCWORD)
frame->nb_samples = nframes * SBC_SAMPLES_PER_FRAME;
else
return AVERROR(EINVAL);
if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
in_data = avpkt->data + 1;
in_size = avpkt->size - 1;
out_ptr = frame->extended_data[0];
out_avail = frame->linesize[0];
for (i = 0; i < nframes; i++) {
uint32_t out_size = out_avail;
OI_STATUS status = OI_CODEC_SBC_DecodeFrame(&sbc->context, &in_data,
&in_size, (int16_t *)out_ptr, &out_size);
if (!OI_SUCCESS(status)) {
av_log(avctx, AV_LOG_ERROR, "SBC decode failed, status:%d\n", status);
return AVERROR(status);
}
out_avail -= out_size;
out_ptr += out_size;
}
if (in_size)
return AVERROR(EINVAL);
*got_frame_ptr = 1;
return avpkt->size;
}
static int sbc_decode_frame(AVCodecContext *avctx, AVFrame *frame,
int *got_frame_ptr, AVPacket *avpkt)
{
SBCDecContext *sbc = avctx->priv_data;
const OI_BYTE* in_data;
uint32_t in_size, out_size;
OI_STATUS status;
int ret;
if (!sbc)
return AVERROR(EIO);
if (avpkt->data[0] == OI_SBC_MSBC_SYNCWORD)
frame->nb_samples = MSBC_SAMPLES_PER_FRAME;
else if (avpkt->data[0] == OI_SBC_SYNCWORD)
frame->nb_samples = SBC_SAMPLES_PER_FRAME;
else
return AVERROR(EINVAL);
if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
in_data = avpkt->data;
in_size = avpkt->size;
out_size = frame->linesize[0];
status = OI_CODEC_SBC_DecodeFrame(&sbc->context, &in_data,
&in_size, (int16_t *)frame->extended_data[0], &out_size);
if (!OI_SUCCESS(status)) {
av_log(avctx, AV_LOG_ERROR, "%s, status: %d, in_size:%d\n", __func__, status, avpkt->size);
return AVERROR(status);
}
*got_frame_ptr = 1;
return avpkt->size - in_size;
}
#define LATM_HEADER 0x56e000 // 0x2b7 (11 bits)
#define LATM_MASK 0xFFE000 // top 11 bits
#define LATM_SIZE_MASK 0x001FFF // bottom 13 bits
#define LATM_HEADER_SIZE 0x03
static int sbc_packed_a2dp_decode_frame(AVCodecContext *avctx, AVFrame *frame,
int *got_frame_ptr, AVPacket *avpkt)
{
uint32_t state = AV_RB24(avpkt->data);
AVPacket pkt;
int ret;
if ((state & LATM_MASK) != LATM_HEADER)
return AVERROR(EINVAL);
if ((state & LATM_SIZE_MASK) != (avpkt->size - LATM_HEADER_SIZE))
return AVERROR(EINVAL);
pkt.data = avpkt->data + LATM_HEADER_SIZE;
pkt.size = avpkt->size - LATM_HEADER_SIZE;
ret = sbc_packed_decode_frame(avctx, frame, got_frame_ptr, &pkt);
if (ret < 0)
return ret;
return avpkt->size;
}
const FFCodec ff_libfluoride_sbc_decoder = {
.p.name = "libfluoride_sbc",
.p.long_name = NULL_IF_CONFIG_SMALL("libfluoride SBC (low-complexity subband codec)"),
.p.type = AVMEDIA_TYPE_AUDIO,
.p.id = AV_CODEC_ID_SBC,
.priv_data_size = sizeof(SBCDecContext),
.init = sbc_decode_init,
FF_CODEC_DECODE_CB(sbc_decode_frame),
.p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1,
.p.supported_samplerates = (const int[]) { 16000, 32000, 44100, 48000, 0 },
.p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
.p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO,
AV_CHANNEL_LAYOUT_STEREO, { 0 } },
.bsfs = "a2dp_rechunk",
};
const FFCodec ff_libfluoride_sbc_packed_decoder = {
.p.name = "libfluoride_sbc-packed",
.p.long_name = NULL_IF_CONFIG_SMALL("libfluoride SBC packed (low-complexity subband codec)"),
.p.type = AVMEDIA_TYPE_AUDIO,
.p.id = AV_CODEC_ID_SBC_PACKED,
.priv_data_size = sizeof(SBCDecContext),
.init = sbc_decode_init,
FF_CODEC_DECODE_CB(sbc_packed_decode_frame),
.p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1,
.p.supported_samplerates = (const int[]) { 16000, 32000, 44100, 48000, 0 },
.p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
.p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO,
AV_CHANNEL_LAYOUT_STEREO, { 0 } },
.bsfs = "a2dp_rechunk",
};
const FFCodec ff_libfluoride_sbc_packed_a2dp_decoder = {
.p.name = "libfluoride_sbc-packed_a2dp",
.p.long_name = NULL_IF_CONFIG_SMALL("libfluoride SBC packed with latm header (low-complexity subband codec)"),
.p.type = AVMEDIA_TYPE_AUDIO,
.p.id = AV_CODEC_ID_SBC_PACKED_A2DP,
.priv_data_size = sizeof(SBCDecContext),
.init = sbc_decode_init,
FF_CODEC_DECODE_CB(sbc_packed_a2dp_decode_frame),
.p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1,
.p.ch_layouts = (const AVChannelLayout[]) { AV_CH_LAYOUT_MONO,
AV_CH_LAYOUT_STEREO, {0}},
.p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
.p.supported_samplerates = (const int[]) { 16000, 32000, 44100, 48000, 0 },
.bsfs = "a2dp_rechunk",
};