00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <celt/celt.h>
00023 #include <celt/celt_header.h>
00024 #include "avcodec.h"
00025 #include "internal.h"
00026 #include "libavutil/intreadwrite.h"
00027
00028 struct libcelt_context {
00029 CELTMode *mode;
00030 CELTDecoder *dec;
00031 AVFrame frame;
00032 int discard;
00033 };
00034
00035 static int ff_celt_error_to_averror(int err)
00036 {
00037 switch (err) {
00038 case CELT_BAD_ARG: return AVERROR(EINVAL);
00039 #ifdef CELT_BUFFER_TOO_SMALL
00040 case CELT_BUFFER_TOO_SMALL: return AVERROR(ENOBUFS);
00041 #endif
00042 case CELT_INTERNAL_ERROR: return AVERROR(EFAULT);
00043 case CELT_CORRUPTED_DATA: return AVERROR_INVALIDDATA;
00044 case CELT_UNIMPLEMENTED: return AVERROR(ENOSYS);
00045 #ifdef ENOTRECOVERABLE
00046 case CELT_INVALID_STATE: return AVERROR(ENOTRECOVERABLE);
00047 #endif
00048 case CELT_ALLOC_FAIL: return AVERROR(ENOMEM);
00049 default: return AVERROR(EINVAL);
00050 }
00051 }
00052
00053 static int ff_celt_bitstream_version_hack(CELTMode *mode)
00054 {
00055 CELTHeader header = { .version_id = 0 };
00056 celt_header_init(&header, mode, 960, 2);
00057 return header.version_id;
00058 }
00059
00060 static av_cold int libcelt_dec_init(AVCodecContext *c)
00061 {
00062 struct libcelt_context *celt = c->priv_data;
00063 int err;
00064
00065 if (!c->channels || !c->frame_size ||
00066 c->frame_size > INT_MAX / sizeof(int16_t) / c->channels)
00067 return AVERROR(EINVAL);
00068 celt->mode = celt_mode_create(c->sample_rate, c->frame_size, &err);
00069 if (!celt->mode)
00070 return ff_celt_error_to_averror(err);
00071 celt->dec = celt_decoder_create_custom(celt->mode, c->channels, &err);
00072 if (!celt->dec) {
00073 celt_mode_destroy(celt->mode);
00074 return ff_celt_error_to_averror(err);
00075 }
00076 if (c->extradata_size >= 4) {
00077 celt->discard = AV_RL32(c->extradata);
00078 if (celt->discard < 0 || celt->discard >= c->frame_size) {
00079 av_log(c, AV_LOG_WARNING,
00080 "Invalid overlap (%d), ignored.\n", celt->discard);
00081 celt->discard = 0;
00082 }
00083 }
00084 if (c->extradata_size >= 8) {
00085 unsigned version = AV_RL32(c->extradata + 4);
00086 unsigned lib_version = ff_celt_bitstream_version_hack(celt->mode);
00087 if (version != lib_version)
00088 av_log(c, AV_LOG_WARNING,
00089 "CELT bitstream version 0x%x may be "
00090 "improperly decoded by libcelt for version 0x%x.\n",
00091 version, lib_version);
00092 }
00093 c->sample_fmt = AV_SAMPLE_FMT_S16;
00094 avcodec_get_frame_defaults(&celt->frame);
00095 c->coded_frame = &celt->frame;
00096 return 0;
00097 }
00098
00099 static av_cold int libcelt_dec_close(AVCodecContext *c)
00100 {
00101 struct libcelt_context *celt = c->priv_data;
00102
00103 celt_decoder_destroy(celt->dec);
00104 celt_mode_destroy(celt->mode);
00105 return 0;
00106 }
00107
00108 static int libcelt_dec_decode(AVCodecContext *c, void *frame,
00109 int *got_frame_ptr, AVPacket *pkt)
00110 {
00111 struct libcelt_context *celt = c->priv_data;
00112 int err;
00113 int16_t *pcm;
00114
00115 celt->frame.nb_samples = c->frame_size;
00116 err = ff_get_buffer(c, &celt->frame);
00117 if (err < 0) {
00118 av_log(c, AV_LOG_ERROR, "get_buffer() failed\n");
00119 return err;
00120 }
00121 pcm = (int16_t *)celt->frame.data[0];
00122 err = celt_decode(celt->dec, pkt->data, pkt->size, pcm, c->frame_size);
00123 if (err < 0)
00124 return ff_celt_error_to_averror(err);
00125 if (celt->discard) {
00126 celt->frame.nb_samples -= celt->discard;
00127 memmove(pcm, pcm + celt->discard * c->channels,
00128 celt->frame.nb_samples * c->channels * sizeof(int16_t));
00129 celt->discard = 0;
00130 }
00131 *got_frame_ptr = 1;
00132 *(AVFrame *)frame = celt->frame;
00133 return pkt->size;
00134 }
00135
00136 AVCodec ff_libcelt_decoder = {
00137 .name = "libcelt",
00138 .type = AVMEDIA_TYPE_AUDIO,
00139 .id = AV_CODEC_ID_CELT,
00140 .priv_data_size = sizeof(struct libcelt_context),
00141 .init = libcelt_dec_init,
00142 .close = libcelt_dec_close,
00143 .decode = libcelt_dec_decode,
00144 .capabilities = CODEC_CAP_DR1,
00145 .long_name = NULL_IF_CONFIG_SMALL("Xiph CELT decoder using libcelt"),
00146 };