2 * Xiph CELT decoder using libcelt
3 * Copyright (c) 2011 Nicolas George
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <celt/celt.h>
23 #include <celt/celt_header.h>
26 #include "libavutil/intreadwrite.h"
28 struct libcelt_context
{
34 static int ff_celt_error_to_averror(int err
)
37 case CELT_BAD_ARG
: return AVERROR(EINVAL
);
38 #ifdef CELT_BUFFER_TOO_SMALL
39 case CELT_BUFFER_TOO_SMALL
: return AVERROR(ENOBUFS
);
41 case CELT_INTERNAL_ERROR
: return AVERROR(EFAULT
);
42 case CELT_CORRUPTED_DATA
: return AVERROR_INVALIDDATA
;
43 case CELT_UNIMPLEMENTED
: return AVERROR(ENOSYS
);
44 #ifdef ENOTRECOVERABLE
45 case CELT_INVALID_STATE
: return AVERROR(ENOTRECOVERABLE
);
47 case CELT_ALLOC_FAIL
: return AVERROR(ENOMEM
);
48 default: return AVERROR(EINVAL
);
52 static int ff_celt_bitstream_version_hack(CELTMode
*mode
)
54 CELTHeader header
= { .version_id
= 0 };
55 celt_header_init(&header
, mode
, 960, 2);
56 return header
.version_id
;
59 static av_cold
int libcelt_dec_init(AVCodecContext
*c
)
61 struct libcelt_context
*celt
= c
->priv_data
;
64 if (!c
->channels
|| !c
->frame_size
||
65 c
->frame_size
> INT_MAX
/ sizeof(int16_t) / c
->channels
)
66 return AVERROR(EINVAL
);
67 celt
->mode
= celt_mode_create(c
->sample_rate
, c
->frame_size
, &err
);
69 return ff_celt_error_to_averror(err
);
70 celt
->dec
= celt_decoder_create_custom(celt
->mode
, c
->channels
, &err
);
72 celt_mode_destroy(celt
->mode
);
73 return ff_celt_error_to_averror(err
);
75 if (c
->extradata_size
>= 4) {
76 celt
->discard
= AV_RL32(c
->extradata
);
77 if (celt
->discard
< 0 || celt
->discard
>= c
->frame_size
) {
78 av_log(c
, AV_LOG_WARNING
,
79 "Invalid overlap (%d), ignored.\n", celt
->discard
);
83 if (c
->extradata_size
>= 8) {
84 unsigned version
= AV_RL32(c
->extradata
+ 4);
85 unsigned lib_version
= ff_celt_bitstream_version_hack(celt
->mode
);
86 if (version
!= lib_version
)
87 av_log(c
, AV_LOG_WARNING
,
88 "CELT bitstream version 0x%x may be "
89 "improperly decoded by libcelt for version 0x%x.\n",
90 version
, lib_version
);
92 c
->sample_fmt
= AV_SAMPLE_FMT_S16
;
96 static av_cold
int libcelt_dec_close(AVCodecContext
*c
)
98 struct libcelt_context
*celt
= c
->priv_data
;
100 celt_decoder_destroy(celt
->dec
);
101 celt_mode_destroy(celt
->mode
);
105 static int libcelt_dec_decode(AVCodecContext
*c
, void *data
,
106 int *got_frame_ptr
, AVPacket
*pkt
)
108 struct libcelt_context
*celt
= c
->priv_data
;
109 AVFrame
*frame
= data
;
113 frame
->nb_samples
= c
->frame_size
;
114 if ((err
= ff_get_buffer(c
, frame
, 0)) < 0)
116 pcm
= (int16_t *)frame
->data
[0];
117 err
= celt_decode(celt
->dec
, pkt
->data
, pkt
->size
, pcm
, c
->frame_size
);
119 return ff_celt_error_to_averror(err
);
121 frame
->nb_samples
-= celt
->discard
;
122 memmove(pcm
, pcm
+ celt
->discard
* c
->channels
,
123 frame
->nb_samples
* c
->channels
* sizeof(int16_t));
130 AVCodec ff_libcelt_decoder
= {
132 .long_name
= NULL_IF_CONFIG_SMALL("Xiph CELT decoder using libcelt"),
133 .type
= AVMEDIA_TYPE_AUDIO
,
134 .id
= AV_CODEC_ID_CELT
,
135 .priv_data_size
= sizeof(struct libcelt_context
),
136 .init
= libcelt_dec_init
,
137 .close
= libcelt_dec_close
,
138 .decode
= libcelt_dec_decode
,
139 .capabilities
= CODEC_CAP_DR1
,