external_ffmpeg/libavcodec/ldacdec.c

218 lines
7.5 KiB
C

/*
* LDAC decoder
*
* 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
* LDAC decoder implementation
*/
#include "avcodec.h"
#include "decode.h"
#include "codec_internal.h"
#include "ldacBT.h"
#define LDAC_MIN_BUF_SIZE 128
#define LDAC_MID_BUF_SIZE 256
#define LDAC_MAX_BUF_SIZE 512
#define CASE_RETURN_STR(err_code) \
case err_code: \
return #err_code;
typedef struct LdacDecContext {
AVClass *class;
HANDLE_LDAC_BT handle_ldac_bt;
LDACBT_SMPL_FMT_T sample_fmt;
int nb_samples;
} LdacDecContext;
static const char *ldac_errcode2str(int ErrCode)
{
switch (ErrCode) {
CASE_RETURN_STR(LDACBT_ERR_NONE);
CASE_RETURN_STR(LDACBT_ERR_NON_FATAL);
CASE_RETURN_STR(LDACBT_ERR_BIT_ALLOCATION);
CASE_RETURN_STR(LDACBT_ERR_NOT_IMPLEMENTED);
CASE_RETURN_STR(LDACBT_ERR_NON_FATAL_ENCODE);
CASE_RETURN_STR(LDACBT_ERR_FATAL);
CASE_RETURN_STR(LDACBT_ERR_SYNTAX_BAND);
CASE_RETURN_STR(LDACBT_ERR_SYNTAX_GRAD_A);
CASE_RETURN_STR(LDACBT_ERR_SYNTAX_GRAD_B);
CASE_RETURN_STR(LDACBT_ERR_SYNTAX_GRAD_C);
CASE_RETURN_STR(LDACBT_ERR_SYNTAX_GRAD_D);
CASE_RETURN_STR(LDACBT_ERR_SYNTAX_GRAD_E);
CASE_RETURN_STR(LDACBT_ERR_SYNTAX_IDSF);
CASE_RETURN_STR(LDACBT_ERR_SYNTAX_SPEC);
CASE_RETURN_STR(LDACBT_ERR_BIT_PACKING);
CASE_RETURN_STR(LDACBT_ERR_ALLOC_MEMORY);
CASE_RETURN_STR(LDACBT_ERR_FATAL_HANDLE);
CASE_RETURN_STR(LDACBT_ERR_ILL_SYNCWORD);
CASE_RETURN_STR(LDACBT_ERR_ILL_SMPL_FORMAT);
CASE_RETURN_STR(LDACBT_ERR_ILL_PARAM);
CASE_RETURN_STR(LDACBT_ERR_ASSERT_SAMPLING_FREQ);
CASE_RETURN_STR(LDACBT_ERR_ASSERT_SUP_SAMPLING_FREQ);
CASE_RETURN_STR(LDACBT_ERR_CHECK_SAMPLING_FREQ);
CASE_RETURN_STR(LDACBT_ERR_ASSERT_CHANNEL_CONFIG);
CASE_RETURN_STR(LDACBT_ERR_CHECK_CHANNEL_CONFIG);
CASE_RETURN_STR(LDACBT_ERR_ASSERT_FRAME_LENGTH);
CASE_RETURN_STR(LDACBT_ERR_ASSERT_SUP_FRAME_LENGTH);
CASE_RETURN_STR(LDACBT_ERR_ASSERT_FRAME_STATUS);
CASE_RETURN_STR(LDACBT_ERR_ASSERT_NSHIFT);
CASE_RETURN_STR(LDACBT_ERR_ASSERT_CHANNEL_MODE);
CASE_RETURN_STR(LDACBT_ERR_ENC_INIT_ALLOC);
CASE_RETURN_STR(LDACBT_ERR_ENC_ILL_GRADMODE);
CASE_RETURN_STR(LDACBT_ERR_ENC_ILL_GRADPAR_A);
CASE_RETURN_STR(LDACBT_ERR_ENC_ILL_GRADPAR_B);
CASE_RETURN_STR(LDACBT_ERR_ENC_ILL_GRADPAR_C);
CASE_RETURN_STR(LDACBT_ERR_ENC_ILL_GRADPAR_D);
CASE_RETURN_STR(LDACBT_ERR_ENC_ILL_NBANDS);
CASE_RETURN_STR(LDACBT_ERR_PACK_BLOCK_FAILED);
CASE_RETURN_STR(LDACBT_ERR_DEC_INIT_ALLOC);
CASE_RETURN_STR(LDACBT_ERR_INPUT_BUFFER_SIZE);
CASE_RETURN_STR(LDACBT_ERR_UNPACK_BLOCK_FAILED);
CASE_RETURN_STR(LDACBT_ERR_UNPACK_BLOCK_ALIGN);
CASE_RETURN_STR(LDACBT_ERR_UNPACK_FRAME_ALIGN);
CASE_RETURN_STR(LDACBT_ERR_FRAME_LENGTH_OVER);
CASE_RETURN_STR(LDACBT_ERR_FRAME_ALIGN_OVER);
CASE_RETURN_STR(LDACBT_ERR_ALTER_EQMID_LIMITED);
CASE_RETURN_STR(LDACBT_ERR_ILL_EQMID);
CASE_RETURN_STR(LDACBT_ERR_ILL_SAMPLING_FREQ);
CASE_RETURN_STR(LDACBT_ERR_ILL_NUM_CHANNEL);
CASE_RETURN_STR(LDACBT_ERR_ILL_MTU_SIZE);
CASE_RETURN_STR(LDACBT_ERR_HANDLE_NOT_INIT);
default:
return "unknown-error-code";
}
}
static av_cold int ldac_decode_init(AVCodecContext *avctx)
{
LdacDecContext *s = avctx->priv_data;
int channel_size;
int error_code;
int cm;
cm = LDACBT_CHANNEL_MODE_STEREO;
if (avctx->ch_layout.nb_channels == 1)
cm = LDACBT_CHANNEL_MODE_MONO;
switch (avctx->sample_fmt) {
case AV_SAMPLE_FMT_S16:
s->sample_fmt = LDACBT_SMPL_FMT_S16;
break;
case AV_SAMPLE_FMT_S32:
s->sample_fmt = LDACBT_SMPL_FMT_S32;
break;
case AV_SAMPLE_FMT_FLT:
s->sample_fmt = LDACBT_SMPL_FMT_F32;
break;
default:
av_log(s, AV_LOG_ERROR, "Unsupported fmt %d!\n", avctx->sample_fmt);
return AVERROR(EINVAL);
}
switch (avctx->sample_rate) {
case 44100:
case 48000:
s->nb_samples = LDAC_MIN_BUF_SIZE;
break;
case 88200:
case 96000:
s->nb_samples = LDAC_MID_BUF_SIZE;
break;
case 176400:
case 192000:
s->nb_samples = LDAC_MAX_BUF_SIZE;
break;
default:
av_log(s, AV_LOG_ERROR, "Unsupported sample rate %d!\n", avctx->sample_rate);
return AVERROR(EINVAL);
}
s->handle_ldac_bt = ldacBT_get_handle();
if (!s->handle_ldac_bt) {
av_log(s, AV_LOG_ERROR, "Can not Get LDAC Handle!\n");
return AVERROR(ENOMEM);
}
if (ldacBT_init_handle_decode(s->handle_ldac_bt, cm, avctx->sample_rate, 0, 0, 0) < 0) {
error_code = ldacBT_get_error_code(s->handle_ldac_bt);
av_log(s, AV_LOG_ERROR, "Initializing LDAC Handle for synthesis!"
"Error code API:%s, Handle:%s, Block:%s\n",
ldac_errcode2str(LDACBT_API_ERR(error_code)),
ldac_errcode2str(LDACBT_HANDLE_ERR(error_code)),
ldac_errcode2str(LDACBT_BLOCK_ERR(error_code)));
return AVERROR(EINVAL);
}
return 0;
}
static int ldac_decode_frame(AVCodecContext *avctx, AVFrame *frame,
int *got_frame_ptr, AVPacket *avpkt)
{
LdacDecContext *s = avctx->priv_data;
int got_bytes;
int used_bytes;
int ret;
frame->nb_samples = s->nb_samples;
if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
ret = ldacBT_decode(s->handle_ldac_bt, avpkt->data, frame->data[0],
s->sample_fmt, avpkt->size, &used_bytes, &got_bytes);
if (ret) {
av_log(s, AV_LOG_ERROR, "LDAC audio frame error!\n");
return ret;
}
*got_frame_ptr = 1;
return avpkt->size;
}
static int ldac_decode_close(AVCodecContext *avctx)
{
LdacDecContext *s = avctx->priv_data;
ldacBT_close_handle(s->handle_ldac_bt);
ldacBT_free_handle(s->handle_ldac_bt);
s->handle_ldac_bt = NULL;
return 0;
}
const FFCodec ff_ldac_decoder = {
.p.name = "ldac",
.p.long_name = NULL_IF_CONFIG_SMALL("LDAC AUDIO Decoder"),
.p.type = AVMEDIA_TYPE_AUDIO,
.p.id = AV_CODEC_ID_LDAC,
.priv_data_size = sizeof(LdacDecContext),
.init = ldac_decode_init,
FF_CODEC_DECODE_CB(ldac_decode_frame),
.close = ldac_decode_close,
.p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1,
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
.p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_S32,
AV_SAMPLE_FMT_FLT,
AV_SAMPLE_FMT_NONE },
};