Signed-off-by: Nicolas George <nicolas.george@normalesup.org>
| ... | ... |
@@ -161,6 +161,7 @@ Configuration options: |
| 161 | 161 |
External library support: |
| 162 | 162 |
--enable-avisynth enable reading of AVISynth script files [no] |
| 163 | 163 |
--enable-bzlib enable bzlib [autodetect] |
| 164 |
+ --enable-libcelt enable CELT/Opus decoding via libcelt [no] |
|
| 164 | 165 |
--enable-frei0r enable frei0r video filtering |
| 165 | 166 |
--enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no] |
| 166 | 167 |
--enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no] |
| ... | ... |
@@ -929,6 +930,7 @@ CONFIG_LIST=" |
| 929 | 929 |
h264pred |
| 930 | 930 |
hardcoded_tables |
| 931 | 931 |
huffman |
| 932 |
+ libcelt |
|
| 932 | 933 |
libdc1394 |
| 933 | 934 |
libdirac |
| 934 | 935 |
libfaac |
| ... | ... |
@@ -1393,6 +1395,7 @@ vdpau_deps="vdpau_vdpau_h vdpau_vdpau_x11_h" |
| 1393 | 1393 |
h264_parser_select="golomb h264dsp h264pred" |
| 1394 | 1394 |
|
| 1395 | 1395 |
# external libraries |
| 1396 |
+libcelt_decoder_deps="libcelt" |
|
| 1396 | 1397 |
libdirac_decoder_deps="libdirac !libschroedinger" |
| 1397 | 1398 |
libdirac_encoder_deps="libdirac" |
| 1398 | 1399 |
libfaac_encoder_deps="libfaac" |
| ... | ... |
@@ -2888,6 +2891,7 @@ check_mathfunc truncf |
| 2888 | 2888 |
|
| 2889 | 2889 |
# these are off by default, so fail if requested and not available |
| 2890 | 2890 |
enabled avisynth && require2 vfw32 "windows.h vfw.h" AVIFileInit -lavifil32 |
| 2891 |
+enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 |
|
| 2891 | 2892 |
enabled frei0r && { check_header frei0r.h || die "ERROR: frei0r.h header not found"; }
|
| 2892 | 2893 |
enabled libdirac && require_pkg_config dirac \ |
| 2893 | 2894 |
"libdirac_decoder/dirac_parser.h libdirac_encoder/dirac_encoder.h" \ |
| ... | ... |
@@ -3167,6 +3171,7 @@ echo "threading support ${thread_type-no}"
|
| 3167 | 3167 |
echo "SDL support ${sdl-no}"
|
| 3168 | 3168 |
echo "Sun medialib support ${mlib-no}"
|
| 3169 | 3169 |
echo "AVISynth enabled ${avisynth-no}"
|
| 3170 |
+echo "libcelt enabled ${libcelt-no}"
|
|
| 3170 | 3171 |
echo "frei0r enabled ${frei0r-no}"
|
| 3171 | 3172 |
echo "libdc1394 support ${libdc1394-no}"
|
| 3172 | 3173 |
echo "libdirac enabled ${libdirac-no}"
|
| ... | ... |
@@ -553,6 +553,7 @@ OBJS-$(CONFIG_WEBM_MUXER) += xiph.o mpeg4audio.o \ |
| 553 | 553 |
mpegaudiodata.o |
| 554 | 554 |
|
| 555 | 555 |
# external codec libraries |
| 556 |
+OBJS-$(CONFIG_LIBCELT_DECODER) += libcelt_dec.o |
|
| 556 | 557 |
OBJS-$(CONFIG_LIBDIRAC_DECODER) += libdiracdec.o |
| 557 | 558 |
OBJS-$(CONFIG_LIBDIRAC_ENCODER) += libdiracenc.o libdirac_libschro.o |
| 558 | 559 |
OBJS-$(CONFIG_LIBFAAC_ENCODER) += libfaac.o |
| ... | ... |
@@ -365,6 +365,7 @@ void avcodec_register_all(void) |
| 365 | 365 |
REGISTER_ENCDEC (XSUB, xsub); |
| 366 | 366 |
|
| 367 | 367 |
/* external libraries */ |
| 368 |
+ REGISTER_DECODER (LIBCELT, libcelt); |
|
| 368 | 369 |
REGISTER_ENCDEC (LIBDIRAC, libdirac); |
| 369 | 370 |
REGISTER_ENCODER (LIBFAAC, libfaac); |
| 370 | 371 |
REGISTER_ENCDEC (LIBGSM, libgsm); |
| 371 | 372 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,134 @@ |
| 0 |
+/* |
|
| 1 |
+ * Xiph CELT / Opus decoder using libcelt |
|
| 2 |
+ * Copyright (c) 2011 Nicolas George |
|
| 3 |
+ * |
|
| 4 |
+ * This file is part of FFmpeg. |
|
| 5 |
+ * |
|
| 6 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
| 7 |
+ * modify it under the terms of the GNU Lesser General Public |
|
| 8 |
+ * License as published by the Free Software Foundation; either |
|
| 9 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
| 10 |
+ * |
|
| 11 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
| 12 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 13 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
| 14 |
+ * Lesser General Public License for more details. |
|
| 15 |
+ * |
|
| 16 |
+ * You should have received a copy of the GNU Lesser General Public |
|
| 17 |
+ * License along with FFmpeg; if not, write to the Free Software |
|
| 18 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
| 19 |
+ */ |
|
| 20 |
+ |
|
| 21 |
+#include <celt/celt.h> |
|
| 22 |
+#include <celt/celt_header.h> |
|
| 23 |
+#include "avcodec.h" |
|
| 24 |
+#include "libavutil/intreadwrite.h" |
|
| 25 |
+ |
|
| 26 |
+struct libcelt_context {
|
|
| 27 |
+ CELTMode *mode; |
|
| 28 |
+ CELTDecoder *dec; |
|
| 29 |
+ int frame_bytes; |
|
| 30 |
+ int discard; |
|
| 31 |
+}; |
|
| 32 |
+ |
|
| 33 |
+static int ff_celt_error_to_averror(int err) |
|
| 34 |
+{
|
|
| 35 |
+ switch(err) {
|
|
| 36 |
+ case CELT_BAD_ARG: return AVERROR(EINVAL); |
|
| 37 |
+#ifdef CELT_BUFFER_TOO_SMALL |
|
| 38 |
+ case CELT_BUFFER_TOO_SMALL: return AVERROR(ENOBUFS); |
|
| 39 |
+#endif |
|
| 40 |
+ case CELT_INTERNAL_ERROR: return AVERROR(EFAULT); |
|
| 41 |
+ case CELT_CORRUPTED_DATA: return AVERROR_INVALIDDATA; |
|
| 42 |
+ case CELT_UNIMPLEMENTED: return AVERROR(ENOTSUP); |
|
| 43 |
+ case CELT_INVALID_STATE: return AVERROR(ENOTRECOVERABLE); |
|
| 44 |
+ case CELT_ALLOC_FAIL: return AVERROR(ENOMEM); |
|
| 45 |
+ default: return AVERROR_UNKNOWN; |
|
| 46 |
+ } |
|
| 47 |
+} |
|
| 48 |
+ |
|
| 49 |
+static int ff_celt_bitstream_version_hack(CELTMode *mode) |
|
| 50 |
+{
|
|
| 51 |
+ CELTHeader header = { .version_id = 0 };
|
|
| 52 |
+ celt_header_init(&header, mode, 960, 2); |
|
| 53 |
+ return header.version_id; |
|
| 54 |
+} |
|
| 55 |
+ |
|
| 56 |
+static av_cold int libcelt_dec_init(AVCodecContext *c) |
|
| 57 |
+{
|
|
| 58 |
+ struct libcelt_context *celt = c->priv_data; |
|
| 59 |
+ int err; |
|
| 60 |
+ |
|
| 61 |
+ if (!c->channels || !c->frame_size || |
|
| 62 |
+ c->frame_size > INT_MAX / sizeof(int16_t) / c->channels) |
|
| 63 |
+ return AVERROR(EINVAL); |
|
| 64 |
+ celt->frame_bytes = c->frame_size * c->channels * sizeof(int16_t); |
|
| 65 |
+ celt->mode = celt_mode_create(c->sample_rate, c->frame_size, &err); |
|
| 66 |
+ if (!celt->mode) |
|
| 67 |
+ return ff_celt_error_to_averror(err); |
|
| 68 |
+ celt->dec = celt_decoder_create_custom(celt->mode, c->channels, &err); |
|
| 69 |
+ if (!celt->dec) {
|
|
| 70 |
+ celt_mode_destroy(celt->mode); |
|
| 71 |
+ return ff_celt_error_to_averror(err); |
|
| 72 |
+ } |
|
| 73 |
+ if (c->extradata_size >= 4) {
|
|
| 74 |
+ celt->discard = AV_RL32(c->extradata); |
|
| 75 |
+ if (celt->discard < 0 || celt->discard >= c->frame_size) {
|
|
| 76 |
+ av_log(c, AV_LOG_WARNING, |
|
| 77 |
+ "Invalid overlap (%d), ignored.\n", celt->discard); |
|
| 78 |
+ celt->discard = 0; |
|
| 79 |
+ } |
|
| 80 |
+ celt->discard *= c->channels * sizeof(int16_t); |
|
| 81 |
+ } |
|
| 82 |
+ if(c->extradata_size >= 8) {
|
|
| 83 |
+ unsigned version = AV_RL32(c->extradata + 4); |
|
| 84 |
+ unsigned lib_version = ff_celt_bitstream_version_hack(celt->mode); |
|
| 85 |
+ if (version != lib_version) |
|
| 86 |
+ av_log(c, AV_LOG_WARNING, |
|
| 87 |
+ "CELT bitstream version 0x%x may be " |
|
| 88 |
+ "improperly decoded by libcelt for version 0x%x.\n", |
|
| 89 |
+ version, lib_version); |
|
| 90 |
+ } |
|
| 91 |
+ return 0; |
|
| 92 |
+} |
|
| 93 |
+ |
|
| 94 |
+static av_cold int libcelt_dec_close(AVCodecContext *c) |
|
| 95 |
+{
|
|
| 96 |
+ struct libcelt_context *celt = c->priv_data; |
|
| 97 |
+ |
|
| 98 |
+ celt_decoder_destroy(celt->dec); |
|
| 99 |
+ celt_mode_destroy(celt->mode); |
|
| 100 |
+ return 0; |
|
| 101 |
+} |
|
| 102 |
+ |
|
| 103 |
+static int libcelt_dec_decode(AVCodecContext *c, void *pcm, int *pcm_size, |
|
| 104 |
+ AVPacket *pkt) |
|
| 105 |
+{
|
|
| 106 |
+ struct libcelt_context *celt = c->priv_data; |
|
| 107 |
+ int err; |
|
| 108 |
+ |
|
| 109 |
+ if (*pcm_size < celt->frame_bytes) |
|
| 110 |
+ return AVERROR(ENOBUFS); |
|
| 111 |
+ err = celt_decode(celt->dec, pkt->data, pkt->size, pcm, c->frame_size); |
|
| 112 |
+ if (err < 0) |
|
| 113 |
+ return ff_celt_error_to_averror(err); |
|
| 114 |
+ *pcm_size = celt->frame_bytes; |
|
| 115 |
+ if (celt->discard) {
|
|
| 116 |
+ *pcm_size = celt->frame_bytes - celt->discard; |
|
| 117 |
+ memmove(pcm, (char *)pcm + celt->discard, *pcm_size); |
|
| 118 |
+ celt->discard = 0; |
|
| 119 |
+ } |
|
| 120 |
+ return pkt->size; |
|
| 121 |
+} |
|
| 122 |
+ |
|
| 123 |
+AVCodec ff_libcelt_decoder = {
|
|
| 124 |
+ .name = "libcelt", |
|
| 125 |
+ .type = AVMEDIA_TYPE_AUDIO, |
|
| 126 |
+ .id = CODEC_ID_CELT, |
|
| 127 |
+ .priv_data_size = sizeof(struct libcelt_context), |
|
| 128 |
+ .init = libcelt_dec_init, |
|
| 129 |
+ .close = libcelt_dec_close, |
|
| 130 |
+ .decode = libcelt_dec_decode, |
|
| 131 |
+ .capabilities = 0, |
|
| 132 |
+ .long_name = NULL_IF_CONFIG_SMALL("Xiph CELT/Opus decoder using libcelt"),
|
|
| 133 |
+}; |