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