You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	Opus decoder using libopus
Signed-off-by: Diego Biurrun <diego@biurrun.de>
This commit is contained in:
		
				
					committed by
					
						 Diego Biurrun
						Diego Biurrun
					
				
			
			
				
	
			
			
			
						parent
						
							e4aa3831b7
						
					
				
				
					commit
					44617d6ec9
				
			| @@ -49,6 +49,7 @@ version <next>: | ||||
| - RTP depacketization of JPEG | ||||
| - Smooth Streaming live segmenter muxer | ||||
| - RTP packetization of JPEG | ||||
| - Opus decoder using libopus | ||||
|  | ||||
|  | ||||
| version 0.8: | ||||
|   | ||||
							
								
								
									
										5
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @@ -181,6 +181,7 @@ External library support: | ||||
|   --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no] | ||||
|   --enable-libopencv       enable video filtering via libopencv [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-librtmp         enable RTMP[E] support via librtmp [no] | ||||
|   --enable-libschroedinger enable Dirac de/encoding via libschroedinger [no] | ||||
| @@ -1009,6 +1010,7 @@ CONFIG_LIST=" | ||||
|     libopencore_amrwb | ||||
|     libopencv | ||||
|     libopenjpeg | ||||
|     libopus | ||||
|     libpulse | ||||
|     librtmp | ||||
|     libschroedinger | ||||
| @@ -1580,6 +1582,7 @@ libopencore_amrnb_encoder_deps="libopencore_amrnb" | ||||
| libopencore_amrwb_decoder_deps="libopencore_amrwb" | ||||
| libopenjpeg_decoder_deps="libopenjpeg" | ||||
| libopenjpeg_encoder_deps="libopenjpeg" | ||||
| libopus_decoder_deps="libopus" | ||||
| libschroedinger_decoder_deps="libschroedinger" | ||||
| libschroedinger_encoder_deps="libschroedinger" | ||||
| libspeex_decoder_deps="libspeex" | ||||
| @@ -3291,6 +3294,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 libopencv  && require_pkg_config opencv opencv/cv.h cvCreateImageHeader | ||||
| 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 librtmp    && require_pkg_config librtmp librtmp/rtmp.h RTMP_Socket | ||||
| enabled libschroedinger && require_pkg_config schroedinger-1.0 schroedinger/schro.h schro_init | ||||
| @@ -3589,6 +3593,7 @@ echo "libopencore-amrnb support ${libopencore_amrnb-no}" | ||||
| echo "libopencore-amrwb support ${libopencore_amrwb-no}" | ||||
| echo "libopencv support         ${libopencv-no}" | ||||
| echo "libopenjpeg enabled       ${libopenjpeg-no}" | ||||
| echo "libopus enabled           ${libopus-no}" | ||||
| echo "libpulse enabled          ${libpulse-no}" | ||||
| echo "librtmp enabled           ${librtmp-no}" | ||||
| echo "libschroedinger enabled   ${libschroedinger-no}" | ||||
|   | ||||
| @@ -756,6 +756,8 @@ following image formats are supported: | ||||
| @item Musepack SV7           @tab     @tab  X | ||||
| @item Musepack SV8           @tab     @tab  X | ||||
| @item Nellymoser Asao        @tab  X  @tab  X | ||||
| @item Opus                   @tab     @tab  E | ||||
|     @tab supported through external library libopus | ||||
| @item PCM A-law              @tab  X  @tab  X | ||||
| @item PCM mu-law             @tab  X  @tab  X | ||||
| @item PCM 16-bit little-endian planar  @tab     @tab  X | ||||
|   | ||||
| @@ -581,6 +581,7 @@ OBJS-$(CONFIG_LIBOPENCORE_AMRNB_ENCODER)  += libopencore-amr.o | ||||
| OBJS-$(CONFIG_LIBOPENCORE_AMRWB_DECODER)  += libopencore-amr.o | ||||
| OBJS-$(CONFIG_LIBOPENJPEG_DECODER)        += libopenjpegdec.o | ||||
| OBJS-$(CONFIG_LIBOPENJPEG_ENCODER)        += libopenjpegenc.o | ||||
| OBJS-$(CONFIG_LIBOPUS_DECODER)            += libopusdec.o vorbis_data.o | ||||
| OBJS-$(CONFIG_LIBSCHROEDINGER_DECODER)    += libschroedingerdec.o \ | ||||
|                                              libschroedinger.o | ||||
| OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER)    += libschroedingerenc.o \ | ||||
|   | ||||
| @@ -393,6 +393,7 @@ void avcodec_register_all(void) | ||||
|     REGISTER_ENCDEC  (LIBOPENCORE_AMRNB, libopencore_amrnb); | ||||
|     REGISTER_DECODER (LIBOPENCORE_AMRWB, libopencore_amrwb); | ||||
|     REGISTER_ENCDEC  (LIBOPENJPEG, libopenjpeg); | ||||
|     REGISTER_DECODER (LIBOPUS, libopus); | ||||
|     REGISTER_ENCDEC  (LIBSCHROEDINGER, libschroedinger); | ||||
|     REGISTER_ENCDEC  (LIBSPEEX, libspeex); | ||||
|     REGISTER_ENCODER (LIBTHEORA, libtheora); | ||||
|   | ||||
							
								
								
									
										202
									
								
								libavcodec/libopusdec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								libavcodec/libopusdec.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | ||||
| /* | ||||
|  * Opus decoder using libopus | ||||
|  * Copyright (c) 2012 Nicolas George | ||||
|  * | ||||
|  * This file is part of Libav. | ||||
|  * | ||||
|  * Libav 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. | ||||
|  * | ||||
|  * Libav 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 Libav; 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 "libavutil/common.h" | ||||
| #include "libavutil/avassert.h" | ||||
| #include "libavutil/intreadwrite.h" | ||||
| #include "avcodec.h" | ||||
| #include "vorbis.h" | ||||
| #include "mathops.h" | ||||
|  | ||||
| struct libopus_context { | ||||
|     OpusMSDecoder *dec; | ||||
|     AVFrame frame; | ||||
| }; | ||||
|  | ||||
| static int opus_error_to_averror(int err) | ||||
| { | ||||
|     switch (err) { | ||||
|     case OPUS_BAD_ARG: | ||||
|         return AVERROR(EINVAL); | ||||
|     case OPUS_BUFFER_TOO_SMALL: | ||||
|         return AVERROR_UNKNOWN; | ||||
|     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_UNKNOWN; | ||||
|     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_decode_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) { | ||||
|         gain_db     = sign_extend(AV_RL16(avc->extradata + 16), 16); | ||||
|         channel_map = AV_RL8 (avc->extradata + 18); | ||||
|     } | ||||
|     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 opus_error_to_averror(ret); | ||||
|     } | ||||
|  | ||||
|     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)); | ||||
|  | ||||
|     avc->delay = 3840;  /* Decoder delay (in samples) at 48kHz */ | ||||
|     avcodec_get_frame_defaults(&opus->frame); | ||||
|     avc->coded_frame = &opus->frame; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static av_cold int libopus_decode_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_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; | ||||
|     } | ||||
|  | ||||
|     if (avc->sample_fmt == AV_SAMPLE_FMT_S16) | ||||
|         nb_samples = opus_multistream_decode(opus->dec, pkt->data, pkt->size, | ||||
|                                              (opus_int16 *)opus->frame.data[0], | ||||
|                                              opus->frame.nb_samples, 0); | ||||
|     else | ||||
|         nb_samples = opus_multistream_decode_float(opus->dec, pkt->data, pkt->size, | ||||
|                                                    (float *)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 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); | ||||
|     } | ||||
|  | ||||
|     opus->frame.nb_samples = nb_samples; | ||||
|     *(AVFrame *)frame = opus->frame; | ||||
|     *got_frame_ptr = 1; | ||||
|     return pkt->size; | ||||
| } | ||||
|  | ||||
| static void libopus_flush(AVCodecContext *avc) | ||||
| { | ||||
|     struct libopus_context *opus = avc->priv_data; | ||||
|  | ||||
|     opus_multistream_decoder_ctl(opus->dec, OPUS_RESET_STATE); | ||||
| } | ||||
|  | ||||
| AVCodec ff_libopus_decoder = { | ||||
|     .name           = "libopus", | ||||
|     .type           = AVMEDIA_TYPE_AUDIO, | ||||
|     .id             = AV_CODEC_ID_OPUS, | ||||
|     .priv_data_size = sizeof(struct libopus_context), | ||||
|     .init           = libopus_decode_init, | ||||
|     .close          = libopus_decode_close, | ||||
|     .decode         = libopus_decode, | ||||
|     .flush          = libopus_flush, | ||||
|     .capabilities   = CODEC_CAP_DR1, | ||||
|     .long_name      = NULL_IF_CONFIG_SMALL("libopus Opus"), | ||||
|     .sample_fmts    = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLT, | ||||
|                                                      AV_SAMPLE_FMT_S16, | ||||
|                                                      AV_SAMPLE_FMT_NONE }, | ||||
| }; | ||||
| @@ -27,7 +27,7 @@ | ||||
|  */ | ||||
|  | ||||
| #define LIBAVCODEC_VERSION_MAJOR 54 | ||||
| #define LIBAVCODEC_VERSION_MINOR 29 | ||||
| #define LIBAVCODEC_VERSION_MINOR 30 | ||||
| #define LIBAVCODEC_VERSION_MICRO  0 | ||||
|  | ||||
| #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user