avcodec/liblc3dec: support sample format negotiation and planar layout.

1. Adds support for respecting the requested sample format. Previously,
   the decoder always used AV_SAMPLE_FMT_FLTP. Now it checks if the
   caller requested a specific format via avctx->request_sample_fmt and
   honors that request when supported.

2. Improves planar/interleaved audio buffer handling. The decoding
   logic now properly handles both planar and interleaved sample
   formats by calculating the correct stride and buffer pointers based
   on the actual sample format.

The changes include:
- Added format mapping between AVSampleFormat and lc3_pcm_format
- Implemented format selection logic in initialization.
- Updated buffer pointer calculation for planar/interleaved data.
- Maintained backward compatibility with existing behavior.

Signed-off-by: cenzhanquan1 <cenzhanquan1@xiaomi.com>
This commit is contained in:
cenzhanquan1
2025-10-20 14:52:24 +08:00
parent cb5e201f5c
commit 0eb572f080

View File

@@ -43,6 +43,14 @@ static av_cold int liblc3_decode_init(AVCodecContext *avctx)
int ep_mode;
unsigned decoder_size;
static const struct {
enum AVSampleFormat av_format;
enum lc3_pcm_format lc3_format;
} format_map[] = {
{ AV_SAMPLE_FMT_FLT, LC3_PCM_FORMAT_FLOAT },
{ AV_SAMPLE_FMT_FLTP, LC3_PCM_FORMAT_FLOAT },
};
if (avctx->extradata_size < 6)
return AVERROR_INVALIDDATA;
if (channels < 0 || channels > DECODER_MAX_CHANNELS) {
@@ -83,6 +91,15 @@ static av_cold int liblc3_decode_init(AVCodecContext *avctx)
}
avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
if (avctx->request_sample_fmt != AV_SAMPLE_FMT_NONE) {
for (int i = 0; i < FF_ARRAY_ELEMS(format_map); i++) {
if (format_map[i].av_format == avctx->request_sample_fmt) {
avctx->sample_fmt = avctx->request_sample_fmt;
break;
}
}
}
avctx->delay = lc3_hr_delay_samples(
liblc3->hr_mode, liblc3->frame_us, liblc3->srate_hz);
avctx->internal->skip_samples = avctx->delay;
@@ -106,6 +123,8 @@ static int liblc3_decode(AVCodecContext *avctx, AVFrame *frame,
int channels = avctx->ch_layout.nb_channels;
uint8_t *in = avpkt->data;
int block_bytes, ret;
size_t sample_size;
int is_planar;
frame->nb_samples = av_rescale(
liblc3->frame_us, liblc3->srate_hz, 1000*1000);
@@ -113,11 +132,17 @@ static int liblc3_decode(AVCodecContext *avctx, AVFrame *frame,
return ret;
block_bytes = avpkt->size;
is_planar = av_sample_fmt_is_planar(avctx->sample_fmt);
sample_size = av_get_bytes_per_sample(avctx->sample_fmt);
for (int ch = 0; ch < channels; ch++) {
int nbytes = block_bytes / channels + (ch < block_bytes % channels);
void *pcm_data = is_planar ? frame->extended_data[ch] :
frame->extended_data[0] + ch * sample_size;
int stride = is_planar ? 1 : channels;
ret = lc3_decode(liblc3->decoder[ch], in, nbytes,
LC3_PCM_FORMAT_FLOAT, frame->data[ch], 1);
LC3_PCM_FORMAT_FLOAT, pcm_data, stride);
if (ret < 0)
return AVERROR_INVALIDDATA;