Xiph CELT/Opus decoder using libcelt.
Signed-off-by: Nicolas George <nicolas.george@normalesup.org>
This commit is contained in:
		
							parent
							
								
									ddb00ad1d8
								
							
						
					
					
						commit
						89451dd6e4
					
				
							
								
								
									
										5
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @ -161,6 +161,7 @@ Configuration options: | ||||
| External library support: | ||||
|   --enable-avisynth        enable reading of AVISynth script files [no] | ||||
|   --enable-bzlib           enable bzlib [autodetect] | ||||
|   --enable-libcelt         enable CELT/Opus decoding via libcelt [no] | ||||
|   --enable-frei0r          enable frei0r video filtering | ||||
|   --enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no] | ||||
|   --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no] | ||||
| @ -929,6 +930,7 @@ CONFIG_LIST=" | ||||
|     h264pred | ||||
|     hardcoded_tables | ||||
|     huffman | ||||
|     libcelt | ||||
|     libdc1394 | ||||
|     libdirac | ||||
|     libfaac | ||||
| @ -1393,6 +1395,7 @@ vdpau_deps="vdpau_vdpau_h vdpau_vdpau_x11_h" | ||||
| h264_parser_select="golomb h264dsp h264pred" | ||||
| 
 | ||||
| # external libraries | ||||
| libcelt_decoder_deps="libcelt" | ||||
| libdirac_decoder_deps="libdirac !libschroedinger" | ||||
| libdirac_encoder_deps="libdirac" | ||||
| libfaac_encoder_deps="libfaac" | ||||
| @ -2888,6 +2891,7 @@ check_mathfunc truncf | ||||
| 
 | ||||
| # these are off by default, so fail if requested and not available | ||||
| enabled avisynth   && require2 vfw32 "windows.h vfw.h" AVIFileInit -lavifil32 | ||||
| enabled libcelt    && require libcelt celt/celt.h celt_decode -lcelt0 | ||||
| enabled frei0r     && { check_header frei0r.h || die "ERROR: frei0r.h header not found"; } | ||||
| enabled libdirac   && require_pkg_config dirac                          \ | ||||
|     "libdirac_decoder/dirac_parser.h libdirac_encoder/dirac_encoder.h"  \ | ||||
| @ -3167,6 +3171,7 @@ echo "threading support         ${thread_type-no}" | ||||
| echo "SDL support               ${sdl-no}" | ||||
| echo "Sun medialib support      ${mlib-no}" | ||||
| echo "AVISynth enabled          ${avisynth-no}" | ||||
| echo "libcelt enabled           ${libcelt-no}" | ||||
| echo "frei0r enabled            ${frei0r-no}" | ||||
| echo "libdc1394 support         ${libdc1394-no}" | ||||
| echo "libdirac enabled          ${libdirac-no}" | ||||
|  | ||||
| @ -553,6 +553,7 @@ OBJS-$(CONFIG_WEBM_MUXER)              += xiph.o mpeg4audio.o \ | ||||
|                                           mpegaudiodata.o | ||||
| 
 | ||||
| # external codec libraries
 | ||||
| OBJS-$(CONFIG_LIBCELT_DECODER)            += libcelt_dec.o | ||||
| OBJS-$(CONFIG_LIBDIRAC_DECODER)           += libdiracdec.o | ||||
| OBJS-$(CONFIG_LIBDIRAC_ENCODER)           += libdiracenc.o libdirac_libschro.o | ||||
| OBJS-$(CONFIG_LIBFAAC_ENCODER)            += libfaac.o | ||||
|  | ||||
| @ -365,6 +365,7 @@ void avcodec_register_all(void) | ||||
|     REGISTER_ENCDEC  (XSUB, xsub); | ||||
| 
 | ||||
|     /* external libraries */ | ||||
|     REGISTER_DECODER (LIBCELT, libcelt); | ||||
|     REGISTER_ENCDEC  (LIBDIRAC, libdirac); | ||||
|     REGISTER_ENCODER (LIBFAAC, libfaac); | ||||
|     REGISTER_ENCDEC  (LIBGSM, libgsm); | ||||
|  | ||||
							
								
								
									
										134
									
								
								libavcodec/libcelt_dec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								libavcodec/libcelt_dec.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,134 @@ | ||||
| /*
 | ||||
|  * Xiph CELT / Opus decoder using libcelt | ||||
|  * Copyright (c) 2011 Nicolas George | ||||
|  * | ||||
|  * This file is part of FFmpeg. | ||||
|  * | ||||
|  * FFmpeg is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Lesser General Public | ||||
|  * License as published by the Free Software Foundation; either | ||||
|  * version 2.1 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  * FFmpeg is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * Lesser General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public | ||||
|  * License along with FFmpeg; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| 
 | ||||
| #include <celt/celt.h> | ||||
| #include <celt/celt_header.h> | ||||
| #include "avcodec.h" | ||||
| #include "libavutil/intreadwrite.h" | ||||
| 
 | ||||
| struct libcelt_context { | ||||
|     CELTMode *mode; | ||||
|     CELTDecoder *dec; | ||||
|     int frame_bytes; | ||||
|     int discard; | ||||
| }; | ||||
| 
 | ||||
| static int ff_celt_error_to_averror(int err) | ||||
| { | ||||
|     switch(err) { | ||||
|         case CELT_BAD_ARG:          return AVERROR(EINVAL); | ||||
| #ifdef CELT_BUFFER_TOO_SMALL | ||||
|         case CELT_BUFFER_TOO_SMALL: return AVERROR(ENOBUFS); | ||||
| #endif | ||||
|         case CELT_INTERNAL_ERROR:   return AVERROR(EFAULT); | ||||
|         case CELT_CORRUPTED_DATA:   return AVERROR_INVALIDDATA; | ||||
|         case CELT_UNIMPLEMENTED:    return AVERROR(ENOTSUP); | ||||
|         case CELT_INVALID_STATE:    return AVERROR(ENOTRECOVERABLE); | ||||
|         case CELT_ALLOC_FAIL:       return AVERROR(ENOMEM); | ||||
|         default:                    return AVERROR_UNKNOWN; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static int ff_celt_bitstream_version_hack(CELTMode *mode) | ||||
| { | ||||
|     CELTHeader header = { .version_id = 0 }; | ||||
|     celt_header_init(&header, mode, 960, 2); | ||||
|     return header.version_id; | ||||
| } | ||||
| 
 | ||||
| static av_cold int libcelt_dec_init(AVCodecContext *c) | ||||
| { | ||||
|     struct libcelt_context *celt = c->priv_data; | ||||
|     int err; | ||||
| 
 | ||||
|     if (!c->channels || !c->frame_size || | ||||
|         c->frame_size > INT_MAX / sizeof(int16_t) / c->channels) | ||||
|         return AVERROR(EINVAL); | ||||
|     celt->frame_bytes = c->frame_size * c->channels * sizeof(int16_t); | ||||
|     celt->mode = celt_mode_create(c->sample_rate, c->frame_size, &err); | ||||
|     if (!celt->mode) | ||||
|         return ff_celt_error_to_averror(err); | ||||
|     celt->dec = celt_decoder_create_custom(celt->mode, c->channels, &err); | ||||
|     if (!celt->dec) { | ||||
|         celt_mode_destroy(celt->mode); | ||||
|         return ff_celt_error_to_averror(err); | ||||
|     } | ||||
|     if (c->extradata_size >= 4) { | ||||
|         celt->discard = AV_RL32(c->extradata); | ||||
|         if (celt->discard < 0 || celt->discard >= c->frame_size) { | ||||
|             av_log(c, AV_LOG_WARNING, | ||||
|                    "Invalid overlap (%d), ignored.\n", celt->discard); | ||||
|             celt->discard = 0; | ||||
|         } | ||||
|         celt->discard *= c->channels * sizeof(int16_t); | ||||
|     } | ||||
|     if(c->extradata_size >= 8) { | ||||
|         unsigned version = AV_RL32(c->extradata + 4); | ||||
|         unsigned lib_version = ff_celt_bitstream_version_hack(celt->mode); | ||||
|         if (version != lib_version) | ||||
|             av_log(c, AV_LOG_WARNING, | ||||
|                    "CELT bitstream version 0x%x may be " | ||||
|                    "improperly decoded by libcelt for version 0x%x.\n", | ||||
|                    version, lib_version); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static av_cold int libcelt_dec_close(AVCodecContext *c) | ||||
| { | ||||
|     struct libcelt_context *celt = c->priv_data; | ||||
| 
 | ||||
|     celt_decoder_destroy(celt->dec); | ||||
|     celt_mode_destroy(celt->mode); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int libcelt_dec_decode(AVCodecContext *c, void *pcm, int *pcm_size, | ||||
|                               AVPacket *pkt) | ||||
| { | ||||
|     struct libcelt_context *celt = c->priv_data; | ||||
|     int err; | ||||
| 
 | ||||
|     if (*pcm_size < celt->frame_bytes) | ||||
|         return AVERROR(ENOBUFS); | ||||
|     err = celt_decode(celt->dec, pkt->data, pkt->size, pcm, c->frame_size); | ||||
|     if (err < 0) | ||||
|         return ff_celt_error_to_averror(err); | ||||
|     *pcm_size = celt->frame_bytes; | ||||
|     if (celt->discard) { | ||||
|         *pcm_size = celt->frame_bytes - celt->discard; | ||||
|         memmove(pcm, (char *)pcm + celt->discard, *pcm_size); | ||||
|         celt->discard = 0; | ||||
|     } | ||||
|     return pkt->size; | ||||
| } | ||||
| 
 | ||||
| AVCodec ff_libcelt_decoder = { | ||||
|     .name           = "libcelt", | ||||
|     .type           = AVMEDIA_TYPE_AUDIO, | ||||
|     .id             = CODEC_ID_CELT, | ||||
|     .priv_data_size = sizeof(struct libcelt_context), | ||||
|     .init           = libcelt_dec_init, | ||||
|     .close          = libcelt_dec_close, | ||||
|     .decode         = libcelt_dec_decode, | ||||
|     .capabilities   = 0, | ||||
|     .long_name = NULL_IF_CONFIG_SMALL("Xiph CELT/Opus decoder using libcelt"), | ||||
| }; | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user