lavc: Opus decoder using libopus.
This commit is contained in:
		
							parent
							
								
									e62fd6619f
								
							
						
					
					
						commit
						a6cf296bd9
					
				| @ -32,6 +32,7 @@ version next: | |||||||
| - 3GPP Timed Text decoder | - 3GPP Timed Text decoder | ||||||
| - GeoTIFF decoder support | - GeoTIFF decoder support | ||||||
| - ffmpeg -(no)stdin option | - ffmpeg -(no)stdin option | ||||||
|  | - Opus decoder using libopus | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| version 0.11: | version 0.11: | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @ -191,6 +191,7 @@ External library support: | |||||||
|   --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no] |   --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no] | ||||||
|   --enable-libopencv       enable video filtering via libopencv [no] |   --enable-libopencv       enable video filtering via libopencv [no] | ||||||
|   --enable-libopenjpeg     enable JPEG 2000 de/encoding via OpenJPEG [no] |   --enable-libopenjpeg     enable JPEG 2000 de/encoding via OpenJPEG [no] | ||||||
|  |   --enable-libopus         enable Opus decoding via libopus [no] | ||||||
|   --enable-libpulse        enable Pulseaudio input via libpulse [no] |   --enable-libpulse        enable Pulseaudio input via libpulse [no] | ||||||
|   --enable-librtmp         enable RTMP[E] support via librtmp [no] |   --enable-librtmp         enable RTMP[E] support via librtmp [no] | ||||||
|   --enable-libschroedinger enable Dirac de/encoding via libschroedinger [no] |   --enable-libschroedinger enable Dirac de/encoding via libschroedinger [no] | ||||||
| @ -1066,6 +1067,7 @@ CONFIG_LIST=" | |||||||
|     libopencore_amrwb |     libopencore_amrwb | ||||||
|     libopencv |     libopencv | ||||||
|     libopenjpeg |     libopenjpeg | ||||||
|  |     libopus | ||||||
|     libpulse |     libpulse | ||||||
|     librtmp |     librtmp | ||||||
|     libschroedinger |     libschroedinger | ||||||
| @ -1635,6 +1637,7 @@ libopencore_amrnb_encoder_deps="libopencore_amrnb" | |||||||
| libopencore_amrwb_decoder_deps="libopencore_amrwb" | libopencore_amrwb_decoder_deps="libopencore_amrwb" | ||||||
| libopenjpeg_decoder_deps="libopenjpeg" | libopenjpeg_decoder_deps="libopenjpeg" | ||||||
| libopenjpeg_encoder_deps="libopenjpeg" | libopenjpeg_encoder_deps="libopenjpeg" | ||||||
|  | libopus_decoder_deps="libopus" | ||||||
| libschroedinger_decoder_deps="libschroedinger" | libschroedinger_decoder_deps="libschroedinger" | ||||||
| libschroedinger_encoder_deps="libschroedinger" | libschroedinger_encoder_deps="libschroedinger" | ||||||
| libspeex_decoder_deps="libspeex" | libspeex_decoder_deps="libspeex" | ||||||
| @ -3321,6 +3324,7 @@ enabled libopencore_amrnb  && require libopencore_amrnb opencore-amrnb/interf_de | |||||||
| enabled libopencore_amrwb  && require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb | enabled libopencore_amrwb  && require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb | ||||||
| enabled libopencv  && require_pkg_config opencv opencv/cxcore.h cvCreateImageHeader | enabled libopencv  && require_pkg_config opencv opencv/cxcore.h cvCreateImageHeader | ||||||
| enabled libopenjpeg && require libopenjpeg openjpeg.h opj_version -lopenjpeg | enabled libopenjpeg && require libopenjpeg openjpeg.h opj_version -lopenjpeg | ||||||
|  | enabled libopus    && require_pkg_config opus opus_multistream.h opus_multistream_decoder_create | ||||||
| enabled libpulse && require_pkg_config libpulse-simple pulse/simple.h pa_simple_new | enabled libpulse && require_pkg_config libpulse-simple pulse/simple.h pa_simple_new | ||||||
| enabled librtmp    && require_pkg_config librtmp librtmp/rtmp.h RTMP_Socket | enabled librtmp    && require_pkg_config librtmp librtmp/rtmp.h RTMP_Socket | ||||||
| enabled libschroedinger && require_pkg_config schroedinger-1.0 schroedinger/schro.h schro_init | enabled libschroedinger && require_pkg_config schroedinger-1.0 schroedinger/schro.h schro_init | ||||||
| @ -3699,6 +3703,7 @@ echo "libopencore-amrnb support ${libopencore_amrnb-no}" | |||||||
| echo "libopencore-amrwb support ${libopencore_amrwb-no}" | echo "libopencore-amrwb support ${libopencore_amrwb-no}" | ||||||
| echo "libopencv support         ${libopencv-no}" | echo "libopencv support         ${libopencv-no}" | ||||||
| echo "libopenjpeg enabled       ${libopenjpeg-no}" | echo "libopenjpeg enabled       ${libopenjpeg-no}" | ||||||
|  | echo "libopus enabled           ${libopus-no}" | ||||||
| echo "libpulse enabled          ${libpulse-no}" | echo "libpulse enabled          ${libpulse-no}" | ||||||
| echo "librtmp enabled           ${librtmp-no}" | echo "librtmp enabled           ${librtmp-no}" | ||||||
| echo "libschroedinger enabled   ${libschroedinger-no}" | echo "libschroedinger enabled   ${libschroedinger-no}" | ||||||
|  | |||||||
| @ -684,6 +684,7 @@ OBJS-$(CONFIG_LIBOPENCORE_AMRNB_ENCODER)  += libopencore-amr.o \ | |||||||
| OBJS-$(CONFIG_LIBOPENCORE_AMRWB_DECODER)  += libopencore-amr.o | OBJS-$(CONFIG_LIBOPENCORE_AMRWB_DECODER)  += libopencore-amr.o | ||||||
| OBJS-$(CONFIG_LIBOPENJPEG_DECODER)        += libopenjpegdec.o | OBJS-$(CONFIG_LIBOPENJPEG_DECODER)        += libopenjpegdec.o | ||||||
| OBJS-$(CONFIG_LIBOPENJPEG_ENCODER)        += libopenjpegenc.o | OBJS-$(CONFIG_LIBOPENJPEG_ENCODER)        += libopenjpegenc.o | ||||||
|  | OBJS-$(CONFIG_LIBOPUS_DECODER)            += libopus_dec.o vorbis_data.o | ||||||
| OBJS-$(CONFIG_LIBSCHROEDINGER_DECODER)    += libschroedingerdec.o \
 | OBJS-$(CONFIG_LIBSCHROEDINGER_DECODER)    += libschroedingerdec.o \
 | ||||||
|                                              libschroedinger.o |                                              libschroedinger.o | ||||||
| OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER)    += libschroedingerenc.o \
 | OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER)    += libschroedingerenc.o \
 | ||||||
|  | |||||||
| @ -427,6 +427,7 @@ void avcodec_register_all(void) | |||||||
|     REGISTER_ENCDEC  (LIBOPENCORE_AMRNB, libopencore_amrnb); |     REGISTER_ENCDEC  (LIBOPENCORE_AMRNB, libopencore_amrnb); | ||||||
|     REGISTER_DECODER (LIBOPENCORE_AMRWB, libopencore_amrwb); |     REGISTER_DECODER (LIBOPENCORE_AMRWB, libopencore_amrwb); | ||||||
|     REGISTER_ENCDEC  (LIBOPENJPEG, libopenjpeg); |     REGISTER_ENCDEC  (LIBOPENJPEG, libopenjpeg); | ||||||
|  |     REGISTER_DECODER (LIBOPUS, libopus); | ||||||
|     REGISTER_ENCDEC  (LIBSCHROEDINGER, libschroedinger); |     REGISTER_ENCDEC  (LIBSCHROEDINGER, libschroedinger); | ||||||
|     REGISTER_ENCDEC  (LIBSPEEX, libspeex); |     REGISTER_ENCDEC  (LIBSPEEX, libspeex); | ||||||
|     REGISTER_DECODER (LIBSTAGEFRIGHT_H264, libstagefright_h264); |     REGISTER_DECODER (LIBSTAGEFRIGHT_H264, libstagefright_h264); | ||||||
|  | |||||||
							
								
								
									
										221
									
								
								libavcodec/libopus_dec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								libavcodec/libopus_dec.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,221 @@ | |||||||
|  | /*
 | ||||||
|  |  * Opus decoder using libopus | ||||||
|  |  * Copyright (c) 2012 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 <opus.h> | ||||||
|  | #include <opus_multistream.h> | ||||||
|  | #include "avcodec.h" | ||||||
|  | #include "internal.h" | ||||||
|  | #include "vorbis.h" | ||||||
|  | #include "libavutil/avassert.h" | ||||||
|  | #include "libavutil/intreadwrite.h" | ||||||
|  | 
 | ||||||
|  | struct libopus_context { | ||||||
|  |     OpusMSDecoder *dec; | ||||||
|  |     AVFrame frame; | ||||||
|  |     int pre_skip; | ||||||
|  | #ifndef OPUS_SET_GAIN | ||||||
|  |     union { int i; double d; } gain; | ||||||
|  | #endif | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static int ff_opus_error_to_averror(int err) | ||||||
|  | { | ||||||
|  |     switch (err) { | ||||||
|  |         case OPUS_BAD_ARG:          return AVERROR(EINVAL); | ||||||
|  |         case OPUS_BUFFER_TOO_SMALL: return AVERROR_BUFFER_TOO_SMALL; | ||||||
|  |         case OPUS_INTERNAL_ERROR:   return AVERROR(EFAULT); | ||||||
|  |         case OPUS_INVALID_PACKET:   return AVERROR_INVALIDDATA; | ||||||
|  |         case OPUS_UNIMPLEMENTED:    return AVERROR(ENOSYS); | ||||||
|  |         case OPUS_INVALID_STATE:    return AVERROR_EXTERNAL; | ||||||
|  |         case OPUS_ALLOC_FAIL:       return AVERROR(ENOMEM); | ||||||
|  |         default:                    return AVERROR(EINVAL); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void reorder(uint8_t *data, unsigned channels, unsigned bps, | ||||||
|  |                            unsigned samples, const uint8_t *map) | ||||||
|  | { | ||||||
|  |     uint8_t tmp[8 * 4]; | ||||||
|  |     unsigned i; | ||||||
|  | 
 | ||||||
|  |     av_assert1(channels * bps <= sizeof(tmp)); | ||||||
|  |     for (; samples > 0; samples--) { | ||||||
|  |         for (i = 0; i < channels; i++) | ||||||
|  |             memcpy(tmp + bps * i, data + bps * map[i], bps); | ||||||
|  |         memcpy(data, tmp, bps * channels); | ||||||
|  |         data += bps * channels; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define OPUS_HEAD_SIZE 19 | ||||||
|  | 
 | ||||||
|  | static av_cold int libopus_dec_init(AVCodecContext *avc) | ||||||
|  | { | ||||||
|  |     struct libopus_context *opus = avc->priv_data; | ||||||
|  |     int ret, channel_map = 0, gain_db = 0, nb_streams, nb_coupled; | ||||||
|  |     uint8_t mapping_stereo[] = { 0, 1 }, *mapping; | ||||||
|  | 
 | ||||||
|  |     avc->sample_rate = 48000; | ||||||
|  |     avc->sample_fmt = avc->request_sample_fmt == AV_SAMPLE_FMT_FLT ? | ||||||
|  |                       AV_SAMPLE_FMT_FLT : AV_SAMPLE_FMT_S16; | ||||||
|  |     avc->channel_layout = avc->channels > 8 ? 0 : | ||||||
|  |                           ff_vorbis_channel_layouts[avc->channels - 1]; | ||||||
|  | 
 | ||||||
|  |     if (avc->extradata_size >= OPUS_HEAD_SIZE) { | ||||||
|  |         opus->pre_skip = AV_RL16(avc->extradata + 10); | ||||||
|  |         gain_db        = AV_RL16(avc->extradata + 16); | ||||||
|  |         channel_map    = AV_RL8 (avc->extradata + 18); | ||||||
|  |         gain_db -= (gain_db & 0x8000) << 1; /* signed */ | ||||||
|  |     } | ||||||
|  |     if (avc->extradata_size >= OPUS_HEAD_SIZE + 2 + avc->channels) { | ||||||
|  |         nb_streams = avc->extradata[OPUS_HEAD_SIZE + 0]; | ||||||
|  |         nb_coupled = avc->extradata[OPUS_HEAD_SIZE + 1]; | ||||||
|  |         if (nb_streams + nb_coupled != avc->channels) | ||||||
|  |             av_log(avc, AV_LOG_WARNING, "Inconsistent channel mapping.\n"); | ||||||
|  |         mapping = avc->extradata + OPUS_HEAD_SIZE + 2; | ||||||
|  |     } else { | ||||||
|  |         if (avc->channels > 2 || channel_map) { | ||||||
|  |             av_log(avc, AV_LOG_ERROR, | ||||||
|  |                    "No channel mapping for %d channels.\n", avc->channels); | ||||||
|  |             return AVERROR(EINVAL); | ||||||
|  |         } | ||||||
|  |         nb_streams = 1; | ||||||
|  |         nb_coupled = avc->channels > 1; | ||||||
|  |         mapping = mapping_stereo; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     opus->dec = opus_multistream_decoder_create( | ||||||
|  |         avc->sample_rate, avc->channels, | ||||||
|  |         nb_streams, nb_coupled, mapping, &ret); | ||||||
|  |     if (!opus->dec) { | ||||||
|  |         av_log(avc, AV_LOG_ERROR, "Unable to create decoder: %s\n", | ||||||
|  |                opus_strerror(ret)); | ||||||
|  |         return ff_opus_error_to_averror(ret); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | #ifdef OPUS_SET_GAIN | ||||||
|  |     ret = opus_multistream_decoder_ctl(opus->dec, OPUS_SET_GAIN(gain_db)); | ||||||
|  |     if (ret != OPUS_OK) | ||||||
|  |         av_log(avc, AV_LOG_WARNING, "Failed to set gain: %s\n", | ||||||
|  |                opus_strerror(ret)); | ||||||
|  | #else | ||||||
|  |     { | ||||||
|  |         double gain_lin = pow(10, gain_db / (20.0 * 256)); | ||||||
|  |         if (avc->sample_fmt == AV_SAMPLE_FMT_FLT) | ||||||
|  |             opus->gain.d = gain_lin; | ||||||
|  |         else | ||||||
|  |             opus->gain.i = FFMIN(gain_lin * 65536, INT_MAX); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     avc->internal->skip_samples = opus->pre_skip; | ||||||
|  |     avcodec_get_frame_defaults(&opus->frame); | ||||||
|  |     avc->coded_frame = &opus->frame; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static av_cold int libopus_dec_close(AVCodecContext *avc) | ||||||
|  | { | ||||||
|  |     struct libopus_context *opus = avc->priv_data; | ||||||
|  | 
 | ||||||
|  |     opus_multistream_decoder_destroy(opus->dec); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define MAX_FRAME_SIZE (960*6) | ||||||
|  | 
 | ||||||
|  | static int libopus_dec_decode(AVCodecContext *avc, void *frame, | ||||||
|  |                               int *got_frame_ptr, AVPacket *pkt) | ||||||
|  | { | ||||||
|  |     struct libopus_context *opus = avc->priv_data; | ||||||
|  |     int ret, nb_samples; | ||||||
|  | 
 | ||||||
|  |     opus->frame.nb_samples = MAX_FRAME_SIZE; | ||||||
|  |     ret = avc->get_buffer(avc, &opus->frame); | ||||||
|  |     if (ret < 0) { | ||||||
|  |         av_log(avc, AV_LOG_ERROR, "get_buffer() failed\n"); | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     nb_samples = avc->sample_fmt == AV_SAMPLE_FMT_S16 ? | ||||||
|  |                  opus_multistream_decode      (opus->dec, pkt->data, pkt->size, | ||||||
|  |                                                (void *)opus->frame.data[0], | ||||||
|  |                                                opus->frame.nb_samples, 0) : | ||||||
|  |                  opus_multistream_decode_float(opus->dec, pkt->data, pkt->size, | ||||||
|  |                                                (void *)opus->frame.data[0], | ||||||
|  |                                                opus->frame.nb_samples, 0); | ||||||
|  |     if (nb_samples < 0) { | ||||||
|  |         av_log(avc, AV_LOG_ERROR, "Decoding error: %s\n", | ||||||
|  |                opus_strerror(nb_samples)); | ||||||
|  |         return ff_opus_error_to_averror(nb_samples); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (avc->channels > 3 && avc->channels <= 8) { | ||||||
|  |         const uint8_t *m = ff_vorbis_channel_layout_offsets[avc->channels - 1]; | ||||||
|  |         if (avc->sample_fmt == AV_SAMPLE_FMT_S16) | ||||||
|  |             reorder(opus->frame.data[0], avc->channels, 2, nb_samples, m); | ||||||
|  |         else | ||||||
|  |             reorder(opus->frame.data[0], avc->channels, 4, nb_samples, m); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | #ifndef OPUS_SET_GAIN | ||||||
|  |     { | ||||||
|  |         int i = avc->channels * nb_samples; | ||||||
|  |         if (avc->sample_fmt == AV_SAMPLE_FMT_FLT) { | ||||||
|  |             float *pcm = (float *)opus->frame.data[0]; | ||||||
|  |             for (; i > 0; i--, pcm++) | ||||||
|  |                 *pcm = av_clipf(*pcm * opus->gain.d, -1, 1); | ||||||
|  |         } else { | ||||||
|  |             int16_t *pcm = (int16_t *)opus->frame.data[0]; | ||||||
|  |             for (; i > 0; i--, pcm++) | ||||||
|  |                 *pcm = av_clip_int16(((int64_t)opus->gain.i * *pcm) >> 16); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     opus->frame.nb_samples = nb_samples; | ||||||
|  |     *(AVFrame *)frame = opus->frame; | ||||||
|  |     *got_frame_ptr = 1; | ||||||
|  |     return pkt->size; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void libopus_dec_flush(AVCodecContext *avc) | ||||||
|  | { | ||||||
|  |     struct libopus_context *opus = avc->priv_data; | ||||||
|  | 
 | ||||||
|  |     opus_multistream_decoder_ctl(opus->dec, OPUS_RESET_STATE); | ||||||
|  |     /* The stream can have been extracted by a tool that is not Opus-aware.
 | ||||||
|  |        Therefore, any packet can become the first of the stream. */ | ||||||
|  |     avc->internal->skip_samples = opus->pre_skip; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | AVCodec ff_libopus_decoder = { | ||||||
|  |     .name           = "libopus", | ||||||
|  |     .type           = AVMEDIA_TYPE_AUDIO, | ||||||
|  |     .id             = CODEC_ID_OPUS, | ||||||
|  |     .priv_data_size = sizeof(struct libopus_context), | ||||||
|  |     .init           = libopus_dec_init, | ||||||
|  |     .close          = libopus_dec_close, | ||||||
|  |     .decode         = libopus_dec_decode, | ||||||
|  |     .flush          = libopus_dec_flush, | ||||||
|  |     .capabilities   = CODEC_CAP_DR1, | ||||||
|  |     .long_name      = NULL_IF_CONFIG_SMALL("libopus Opus"), | ||||||
|  | }; | ||||||
| @ -27,7 +27,7 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #define LIBAVCODEC_VERSION_MAJOR 54 | #define LIBAVCODEC_VERSION_MAJOR 54 | ||||||
| #define LIBAVCODEC_VERSION_MINOR  41 | #define LIBAVCODEC_VERSION_MINOR  42 | ||||||
| #define LIBAVCODEC_VERSION_MICRO 100 | #define LIBAVCODEC_VERSION_MICRO 100 | ||||||
| 
 | 
 | ||||||
| #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user