Merge remote-tracking branch 'qatar/master'
* qatar/master: FATE: use updated reference for aac-latm_stereo_to_51 avconv: use libavresample Add libavresample FATE: avoid channel mixing in lavf-dv_fmt Conflicts: Changelog Makefile cmdutils.c configure doc/APIchanges ffmpeg.c tests/lavf-regression.sh tests/ref/lavf/dv_fmt tests/ref/seek/lavf_dv Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
		
						commit
						3ead79eaa3
					
				| @ -26,6 +26,7 @@ version next: | |||||||
| - drawtext video filter: fontconfig support | - drawtext video filter: fontconfig support | ||||||
| - ffmpeg -benchmark_all option | - ffmpeg -benchmark_all option | ||||||
| - super2xsai filter ported from libmpcodecs | - super2xsai filter ported from libmpcodecs | ||||||
|  | - add libavresample audio conversion library for compatibility | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| version 0.10: | version 0.10: | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
									
									
									
									
								
							| @ -31,6 +31,7 @@ ALLMANPAGES = $(BASENAMES:%=%.1) | |||||||
| FFLIBS-$(CONFIG_AVDEVICE) += avdevice | FFLIBS-$(CONFIG_AVDEVICE) += avdevice | ||||||
| FFLIBS-$(CONFIG_AVFILTER) += avfilter | FFLIBS-$(CONFIG_AVFILTER) += avfilter | ||||||
| FFLIBS-$(CONFIG_AVFORMAT) += avformat | FFLIBS-$(CONFIG_AVFORMAT) += avformat | ||||||
|  | FFLIBS-$(CONFIG_AVRESAMPLE) += avresample | ||||||
| FFLIBS-$(CONFIG_AVCODEC)  += avcodec | FFLIBS-$(CONFIG_AVCODEC)  += avcodec | ||||||
| FFLIBS-$(CONFIG_POSTPROC) += postproc | FFLIBS-$(CONFIG_POSTPROC) += postproc | ||||||
| FFLIBS-$(CONFIG_SWRESAMPLE)+= swresample | FFLIBS-$(CONFIG_SWRESAMPLE)+= swresample | ||||||
|  | |||||||
| @ -32,6 +32,7 @@ | |||||||
| #include "libavformat/avformat.h" | #include "libavformat/avformat.h" | ||||||
| #include "libavfilter/avfilter.h" | #include "libavfilter/avfilter.h" | ||||||
| #include "libavdevice/avdevice.h" | #include "libavdevice/avdevice.h" | ||||||
|  | #include "libavresample/avresample.h" | ||||||
| #include "libswscale/swscale.h" | #include "libswscale/swscale.h" | ||||||
| #include "libswresample/swresample.h" | #include "libswresample/swresample.h" | ||||||
| #if CONFIG_POSTPROC | #if CONFIG_POSTPROC | ||||||
| @ -633,7 +634,8 @@ static int warned_cfg = 0; | |||||||
|         const char *indent = flags & INDENT? "  " : "";                 \ |         const char *indent = flags & INDENT? "  " : "";                 \ | ||||||
|         if (flags & SHOW_VERSION) {                                     \ |         if (flags & SHOW_VERSION) {                                     \ | ||||||
|             unsigned int version = libname##_version();                 \ |             unsigned int version = libname##_version();                 \ | ||||||
|             av_log(NULL, level, "%slib%-11s %2d.%3d.%3d / %2d.%3d.%3d\n",\ |             av_log(NULL, level,                                         \ | ||||||
|  |                    "%slib%-11s %2d.%3d.%3d / %2d.%3d.%3d\n",            \ | ||||||
|                    indent, #libname,                                    \ |                    indent, #libname,                                    \ | ||||||
|                    LIB##LIBNAME##_VERSION_MAJOR,                        \ |                    LIB##LIBNAME##_VERSION_MAJOR,                        \ | ||||||
|                    LIB##LIBNAME##_VERSION_MINOR,                        \ |                    LIB##LIBNAME##_VERSION_MINOR,                        \ | ||||||
| @ -662,6 +664,7 @@ static void print_all_libs_info(int flags, int level) | |||||||
|     PRINT_LIB_INFO(avformat, AVFORMAT, flags, level); |     PRINT_LIB_INFO(avformat, AVFORMAT, flags, level); | ||||||
|     PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level); |     PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level); | ||||||
|     PRINT_LIB_INFO(avfilter, AVFILTER, flags, level); |     PRINT_LIB_INFO(avfilter, AVFILTER, flags, level); | ||||||
|  | //    PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level);
 | ||||||
|     PRINT_LIB_INFO(swscale,  SWSCALE,  flags, level); |     PRINT_LIB_INFO(swscale,  SWSCALE,  flags, level); | ||||||
|     PRINT_LIB_INFO(swresample,SWRESAMPLE,  flags, level); |     PRINT_LIB_INFO(swresample,SWRESAMPLE,  flags, level); | ||||||
| #if CONFIG_POSTPROC | #if CONFIG_POSTPROC | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ $(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR)))) | |||||||
| $(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL)) | $(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL)) | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| ALLFFLIBS = avcodec avdevice avfilter avformat avutil postproc swscale swresample | ALLFFLIBS = avcodec avdevice avfilter avformat avresample avutil postproc swscale swresample | ||||||
| 
 | 
 | ||||||
| # NASM requires -I path terminated with /
 | # NASM requires -I path terminated with /
 | ||||||
| IFLAGS     := -I. -I$(SRC_PATH)/ | IFLAGS     := -I. -I$(SRC_PATH)/ | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @ -112,6 +112,7 @@ Component options: | |||||||
|   --disable-swscale        disable libswscale build |   --disable-swscale        disable libswscale build | ||||||
|   --disable-postproc       disable libpostproc build |   --disable-postproc       disable libpostproc build | ||||||
|   --disable-avfilter       disable video filter support [no] |   --disable-avfilter       disable video filter support [no] | ||||||
|  |   --disable-avresample     disable libavresample build [no] | ||||||
|   --disable-pthreads       disable pthreads [auto] |   --disable-pthreads       disable pthreads [auto] | ||||||
|   --disable-w32threads     disable Win32 threads [auto] |   --disable-w32threads     disable Win32 threads [auto] | ||||||
|   --disable-os2threads     disable OS/2 threads [auto] |   --disable-os2threads     disable OS/2 threads [auto] | ||||||
| @ -1013,6 +1014,7 @@ CONFIG_LIST=" | |||||||
|     avdevice |     avdevice | ||||||
|     avfilter |     avfilter | ||||||
|     avformat |     avformat | ||||||
|  |     avresample | ||||||
|     avisynth |     avisynth | ||||||
|     bzlib |     bzlib | ||||||
|     crystalhd |     crystalhd | ||||||
| @ -1870,6 +1872,7 @@ enable avcodec | |||||||
| enable avdevice | enable avdevice | ||||||
| enable avfilter | enable avfilter | ||||||
| enable avformat | enable avformat | ||||||
|  | enable avresample | ||||||
| enable avutil | enable avutil | ||||||
| enable postproc | enable postproc | ||||||
| enable stripping | enable stripping | ||||||
| @ -3724,6 +3727,7 @@ get_version LIBAVCODEC  libavcodec/version.h | |||||||
| get_version LIBAVDEVICE libavdevice/avdevice.h | get_version LIBAVDEVICE libavdevice/avdevice.h | ||||||
| get_version LIBAVFILTER libavfilter/version.h | get_version LIBAVFILTER libavfilter/version.h | ||||||
| get_version LIBAVFORMAT libavformat/version.h | get_version LIBAVFORMAT libavformat/version.h | ||||||
|  | get_version LIBAVRESAMPLE libavresample/version.h | ||||||
| get_version LIBAVUTIL   libavutil/avutil.h | get_version LIBAVUTIL   libavutil/avutil.h | ||||||
| get_version LIBPOSTPROC libpostproc/postprocess.h | get_version LIBPOSTPROC libpostproc/postprocess.h | ||||||
| get_version LIBSWRESAMPLE libswresample/swresample.h | get_version LIBSWRESAMPLE libswresample/swresample.h | ||||||
| @ -3869,5 +3873,6 @@ pkgconfig_generate libavformat "FFmpeg container format library" "$LIBAVFORMAT_V | |||||||
| pkgconfig_generate libavdevice "FFmpeg device handling library" "$LIBAVDEVICE_VERSION" "$extralibs" "$libavdevice_pc_deps" | pkgconfig_generate libavdevice "FFmpeg device handling library" "$LIBAVDEVICE_VERSION" "$extralibs" "$libavdevice_pc_deps" | ||||||
| pkgconfig_generate libavfilter "FFmpeg video filtering library" "$LIBAVFILTER_VERSION" "$extralibs" "$libavfilter_pc_deps" | pkgconfig_generate libavfilter "FFmpeg video filtering library" "$LIBAVFILTER_VERSION" "$extralibs" "$libavfilter_pc_deps" | ||||||
| pkgconfig_generate libpostproc "FFmpeg postprocessing library" "$LIBPOSTPROC_VERSION" "" "libavutil = $LIBAVUTIL_VERSION" | pkgconfig_generate libpostproc "FFmpeg postprocessing library" "$LIBPOSTPROC_VERSION" "" "libavutil = $LIBAVUTIL_VERSION" | ||||||
|  | pkgconfig_generate libavresample "Libav audio resampling library" "$LIBAVRESAMPLE_VERSION" "$extralibs" | ||||||
| pkgconfig_generate libswscale "FFmpeg image rescaling library" "$LIBSWSCALE_VERSION" "$LIBM" "libavutil = $LIBAVUTIL_VERSION" | pkgconfig_generate libswscale "FFmpeg image rescaling library" "$LIBSWSCALE_VERSION" "$LIBM" "libavutil = $LIBAVUTIL_VERSION" | ||||||
| pkgconfig_generate libswresample "FFmpeg audio rescaling library" "$LIBSWRESAMPLE_VERSION" "$LIBM" "libavutil = $LIBAVUTIL_VERSION" | pkgconfig_generate libswresample "FFmpeg audio rescaling library" "$LIBSWRESAMPLE_VERSION" "$LIBM" "libavutil = $LIBAVUTIL_VERSION" | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ libavcodec:  2012-01-27 | |||||||
| libavdevice: 2011-04-18 | libavdevice: 2011-04-18 | ||||||
| libavfilter: 2011-04-18 | libavfilter: 2011-04-18 | ||||||
| libavformat: 2012-01-27 | libavformat: 2012-01-27 | ||||||
|  | libavresample: 2012-xx-xx | ||||||
| libpostproc: 2011-04-18 | libpostproc: 2011-04-18 | ||||||
| libswscale:  2011-06-20 | libswscale:  2011-06-20 | ||||||
| libavutil:   2011-04-18 | libavutil:   2011-04-18 | ||||||
| @ -22,6 +23,9 @@ API changes, most recent first: | |||||||
| 2012-03-26 - a67d9cf - lavfi 2.66.100 | 2012-03-26 - a67d9cf - lavfi 2.66.100 | ||||||
|   Add avfilter_fill_frame_from_{audio_,}buffer_ref() functions. |   Add avfilter_fill_frame_from_{audio_,}buffer_ref() functions. | ||||||
| 
 | 
 | ||||||
|  | 2012-xx-xx - xxxxxxx - lavr 0.0.0 | ||||||
|  |   Add libavresample audio conversion library | ||||||
|  | 
 | ||||||
| 2012-xx-xx - xxxxxxx - lavu 51.28.0 - audio_fifo.h | 2012-xx-xx - xxxxxxx - lavu 51.28.0 - audio_fifo.h | ||||||
|   Add audio FIFO functions: |   Add audio FIFO functions: | ||||||
|     av_audio_fifo_free() |     av_audio_fifo_free() | ||||||
|  | |||||||
							
								
								
									
										53
									
								
								ffmpeg.c
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								ffmpeg.c
									
									
									
									
									
								
							| @ -36,7 +36,6 @@ | |||||||
| #include "libavdevice/avdevice.h" | #include "libavdevice/avdevice.h" | ||||||
| #include "libswscale/swscale.h" | #include "libswscale/swscale.h" | ||||||
| #include "libavutil/opt.h" | #include "libavutil/opt.h" | ||||||
| #include "libavcodec/audioconvert.h" |  | ||||||
| #include "libavutil/audioconvert.h" | #include "libavutil/audioconvert.h" | ||||||
| #include "libavutil/parseutils.h" | #include "libavutil/parseutils.h" | ||||||
| #include "libavutil/samplefmt.h" | #include "libavutil/samplefmt.h" | ||||||
| @ -300,6 +299,7 @@ typedef struct OutputStream { | |||||||
|     int audio_channels_mapped;           ///< number of channels in audio_channels_map
 |     int audio_channels_mapped;           ///< number of channels in audio_channels_map
 | ||||||
|     int resample_sample_fmt; |     int resample_sample_fmt; | ||||||
|     int resample_channels; |     int resample_channels; | ||||||
|  |     uint64_t resample_channel_layout; | ||||||
|     int resample_sample_rate; |     int resample_sample_rate; | ||||||
|     float rematrix_volume; |     float rematrix_volume; | ||||||
|     AVFifoBuffer *fifo;     /* for compression: one audio fifo per codec */ |     AVFifoBuffer *fifo;     /* for compression: one audio fifo per codec */ | ||||||
| @ -1525,7 +1525,7 @@ static int encode_audio_frame(AVFormatContext *s, OutputStream *ost, | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc, | static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc, | ||||||
|                                   int nb_samples) |                                   int nb_samples, int *buf_linesize) | ||||||
| { | { | ||||||
|     int64_t audio_buf_samples; |     int64_t audio_buf_samples; | ||||||
|     int audio_buf_size; |     int audio_buf_size; | ||||||
| @ -1538,7 +1538,7 @@ static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc, | |||||||
|     if (audio_buf_samples > INT_MAX) |     if (audio_buf_samples > INT_MAX) | ||||||
|         return AVERROR(EINVAL); |         return AVERROR(EINVAL); | ||||||
| 
 | 
 | ||||||
|     audio_buf_size = av_samples_get_buffer_size(NULL, enc->channels, |     audio_buf_size = av_samples_get_buffer_size(buf_linesize, enc->channels, | ||||||
|                                                 audio_buf_samples, |                                                 audio_buf_samples, | ||||||
|                                                 enc->sample_fmt, 0); |                                                 enc->sample_fmt, 0); | ||||||
|     if (audio_buf_size < 0) |     if (audio_buf_size < 0) | ||||||
| @ -1557,7 +1557,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, | |||||||
|     uint8_t *buftmp; |     uint8_t *buftmp; | ||||||
|     int64_t size_out; |     int64_t size_out; | ||||||
| 
 | 
 | ||||||
|     int frame_bytes, resample_changed; |     int frame_bytes, resample_changed, ret; | ||||||
|     AVCodecContext *enc = ost->st->codec; |     AVCodecContext *enc = ost->st->codec; | ||||||
|     AVCodecContext *dec = ist->st->codec; |     AVCodecContext *dec = ist->st->codec; | ||||||
|     int osize = av_get_bytes_per_sample(enc->sample_fmt); |     int osize = av_get_bytes_per_sample(enc->sample_fmt); | ||||||
| @ -1566,37 +1566,46 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, | |||||||
|     int size     = decoded_frame->nb_samples * dec->channels * isize; |     int size     = decoded_frame->nb_samples * dec->channels * isize; | ||||||
|     int planes   = av_sample_fmt_is_planar(dec->sample_fmt) ? dec->channels : 1; |     int planes   = av_sample_fmt_is_planar(dec->sample_fmt) ? dec->channels : 1; | ||||||
|     int i; |     int i; | ||||||
|  |     int out_linesize = 0; | ||||||
|  |     int buf_linesize = decoded_frame->linesize[0]; | ||||||
| 
 | 
 | ||||||
|     av_assert0(planes <= AV_NUM_DATA_POINTERS); |     av_assert0(planes <= AV_NUM_DATA_POINTERS); | ||||||
| 
 | 
 | ||||||
|     for(i=0; i<planes; i++) |     for(i=0; i<planes; i++) | ||||||
|         buf[i]= decoded_frame->data[i]; |         buf[i]= decoded_frame->data[i]; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     get_default_channel_layouts(ost, ist); |     get_default_channel_layouts(ost, ist); | ||||||
| 
 | 
 | ||||||
|     if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples) < 0) { |     if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples, &out_linesize) < 0) { | ||||||
|         av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); |         av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); | ||||||
|         exit_program(1); |         exit_program(1); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (enc->channels != dec->channels |     if (audio_sync_method > 1                      || | ||||||
|      || enc->sample_fmt != dec->sample_fmt |         enc->channels       != dec->channels       || | ||||||
|      || enc->sample_rate!= dec->sample_rate |         enc->channel_layout != dec->channel_layout || | ||||||
|     ) |         enc->sample_rate    != dec->sample_rate    || | ||||||
|  |         dec->sample_fmt     != enc->sample_fmt) | ||||||
|         ost->audio_resample = 1; |         ost->audio_resample = 1; | ||||||
| 
 | 
 | ||||||
|     resample_changed = ost->resample_sample_fmt  != dec->sample_fmt || |     resample_changed = ost->resample_sample_fmt  != dec->sample_fmt || | ||||||
|                        ost->resample_channels    != dec->channels   || |                        ost->resample_channels    != dec->channels   || | ||||||
|  |                        ost->resample_channel_layout != dec->channel_layout || | ||||||
|                        ost->resample_sample_rate != dec->sample_rate; |                        ost->resample_sample_rate != dec->sample_rate; | ||||||
| 
 | 
 | ||||||
|     if ((ost->audio_resample && !ost->swr) || resample_changed || ost->audio_channels_mapped) { |     if ((ost->audio_resample && !ost->swr) || resample_changed || ost->audio_channels_mapped) { | ||||||
|  | 
 | ||||||
|         if (resample_changed) { |         if (resample_changed) { | ||||||
|             av_log(NULL, AV_LOG_INFO, "Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d to rate:%d fmt:%s ch:%d\n", |             av_log(NULL, AV_LOG_INFO, "Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d chl:0x%"PRIx64" to rate:%d fmt:%s ch:%d chl:0x%"PRIx64"\n", | ||||||
|                    ist->file_index, ist->st->index, |                    ist->file_index, ist->st->index, | ||||||
|                    ost->resample_sample_rate, av_get_sample_fmt_name(ost->resample_sample_fmt), ost->resample_channels, |                    ost->resample_sample_rate, av_get_sample_fmt_name(ost->resample_sample_fmt), | ||||||
|                    dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), dec->channels); |                    ost->resample_channels, ost->resample_channel_layout, | ||||||
|  |                    dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), | ||||||
|  |                    dec->channels, dec->channel_layout); | ||||||
|             ost->resample_sample_fmt  = dec->sample_fmt; |             ost->resample_sample_fmt  = dec->sample_fmt; | ||||||
|             ost->resample_channels    = dec->channels; |             ost->resample_channels    = dec->channels; | ||||||
|  |             ost->resample_channel_layout = dec->channel_layout; | ||||||
|             ost->resample_sample_rate = dec->sample_rate; |             ost->resample_sample_rate = dec->sample_rate; | ||||||
|             swr_free(&ost->swr); |             swr_free(&ost->swr); | ||||||
|         } |         } | ||||||
| @ -1604,6 +1613,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, | |||||||
|         if (audio_sync_method <= 1 && !ost->audio_channels_mapped && |         if (audio_sync_method <= 1 && !ost->audio_channels_mapped && | ||||||
|             ost->resample_sample_fmt  == enc->sample_fmt && |             ost->resample_sample_fmt  == enc->sample_fmt && | ||||||
|             ost->resample_channels    == enc->channels   && |             ost->resample_channels    == enc->channels   && | ||||||
|  |             ost->resample_channel_layout == enc->channel_layout && | ||||||
|             ost->resample_sample_rate == enc->sample_rate) { |             ost->resample_sample_rate == enc->sample_rate) { | ||||||
|             //ost->swr = NULL;
 |             //ost->swr = NULL;
 | ||||||
|             ost->audio_resample = 0; |             ost->audio_resample = 0; | ||||||
| @ -1673,7 +1683,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, | |||||||
|                         exit_program(1); |                         exit_program(1); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples + idelta) < 0) { |                     if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples + idelta, &out_linesize) < 0) { | ||||||
|                         av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); |                         av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); | ||||||
|                         exit_program(1); |                         exit_program(1); | ||||||
|                     } |                     } | ||||||
| @ -1686,11 +1696,11 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, | |||||||
|                         buf[i] = t; |                         buf[i] = t; | ||||||
|                     } |                     } | ||||||
|                     size += byte_delta; |                     size += byte_delta; | ||||||
|  |                     buf_linesize = allocated_async_buf_size; | ||||||
|                     av_log(NULL, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", idelta); |                     av_log(NULL, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", idelta); | ||||||
|                 } |                 } | ||||||
|             } else if (audio_sync_method > 1) { |             } else if (audio_sync_method > 1) { | ||||||
|                 int comp = av_clip(delta, -audio_sync_method, audio_sync_method); |                 int comp = av_clip(delta, -audio_sync_method, audio_sync_method); | ||||||
|                 av_assert0(ost->audio_resample); |  | ||||||
|                 av_log(NULL, AV_LOG_VERBOSE, "compensating audio timestamp drift:%f compensation:%d in:%d\n", |                 av_log(NULL, AV_LOG_VERBOSE, "compensating audio timestamp drift:%f compensation:%d in:%d\n", | ||||||
|                        delta, comp, enc->sample_rate); |                        delta, comp, enc->sample_rate); | ||||||
| //                fprintf(stderr, "drift:%f len:%d opts:%"PRId64" ipts:%"PRId64" fifo:%d\n", delta, -1, ost->sync_opts, (int64_t)(get_sync_ipts(ost) * enc->sample_rate), av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2));
 | //                fprintf(stderr, "drift:%f len:%d opts:%"PRId64" ipts:%"PRId64" fifo:%d\n", delta, -1, ost->sync_opts, (int64_t)(get_sync_ipts(ost) * enc->sample_rate), av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2));
 | ||||||
| @ -1703,8 +1713,10 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, | |||||||
| 
 | 
 | ||||||
|     if (ost->audio_resample || ost->audio_channels_mapped) { |     if (ost->audio_resample || ost->audio_channels_mapped) { | ||||||
|         buftmp = audio_buf; |         buftmp = audio_buf; | ||||||
|         size_out = swr_convert(ost->swr, (      uint8_t*[]){buftmp}, allocated_audio_buf_size / (enc->channels * osize), |         size_out = swr_convert(ost->swr, (      uint8_t*[]){buftmp}, | ||||||
|                                          buf, size / (dec->channels * isize)); |                                       allocated_audio_buf_size / (enc->channels * osize), | ||||||
|  |                                       buf, | ||||||
|  |                                       size / (dec->channels * isize)); | ||||||
|         if (size_out < 0) { |         if (size_out < 0) { | ||||||
|             av_log(NULL, AV_LOG_FATAL, "swr_convert failed\n"); |             av_log(NULL, AV_LOG_FATAL, "swr_convert failed\n"); | ||||||
|             exit_program(1); |             exit_program(1); | ||||||
| @ -3078,6 +3090,7 @@ static int transcode_init(void) | |||||||
|                 if (!ost->fifo) { |                 if (!ost->fifo) { | ||||||
|                     return AVERROR(ENOMEM); |                     return AVERROR(ENOMEM); | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|                 if (!codec->sample_rate) |                 if (!codec->sample_rate) | ||||||
|                     codec->sample_rate = icodec->sample_rate; |                     codec->sample_rate = icodec->sample_rate; | ||||||
|                 choose_sample_rate(ost->st, ost->enc); |                 choose_sample_rate(ost->st, ost->enc); | ||||||
| @ -3110,13 +3123,15 @@ static int transcode_init(void) | |||||||
|                 if (av_get_channel_layout_nb_channels(codec->channel_layout) != codec->channels) |                 if (av_get_channel_layout_nb_channels(codec->channel_layout) != codec->channels) | ||||||
|                     codec->channel_layout = 0; |                     codec->channel_layout = 0; | ||||||
| 
 | 
 | ||||||
|                 ost->audio_resample       = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1; | 
 | ||||||
|                 ost->audio_resample      |=    codec->sample_fmt     != icodec->sample_fmt | //                 ost->audio_resample       = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1;
 | ||||||
|                                             || codec->channel_layout != icodec->channel_layout; | //                 ost->audio_resample      |=    codec->sample_fmt     != icodec->sample_fmt
 | ||||||
|  | //                                             || codec->channel_layout != icodec->channel_layout;
 | ||||||
|                 icodec->request_channels  = codec-> channels; |                 icodec->request_channels  = codec-> channels; | ||||||
|                 ost->resample_sample_fmt  = icodec->sample_fmt; |                 ost->resample_sample_fmt  = icodec->sample_fmt; | ||||||
|                 ost->resample_sample_rate = icodec->sample_rate; |                 ost->resample_sample_rate = icodec->sample_rate; | ||||||
|                 ost->resample_channels    = icodec->channels; |                 ost->resample_channels    = icodec->channels; | ||||||
|  |                 ost->resample_channel_layout = icodec->channel_layout; | ||||||
|                 break; |                 break; | ||||||
|             case AVMEDIA_TYPE_VIDEO: |             case AVMEDIA_TYPE_VIDEO: | ||||||
|                 if (!ost->filter) { |                 if (!ost->filter) { | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								libavresample/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								libavresample/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | NAME = avresample | ||||||
|  | FFLIBS = avutil | ||||||
|  | 
 | ||||||
|  | HEADERS = avresample.h                                                  \
 | ||||||
|  |           version.h | ||||||
|  | 
 | ||||||
|  | OBJS = audio_convert.o                                                  \
 | ||||||
|  |        audio_data.o                                                     \
 | ||||||
|  |        audio_mix.o                                                      \
 | ||||||
|  |        audio_mix_matrix.o                                               \
 | ||||||
|  |        options.o                                                        \
 | ||||||
|  |        resample.o                                                       \
 | ||||||
|  |        utils.o | ||||||
|  | 
 | ||||||
|  | TESTPROGS = avresample | ||||||
							
								
								
									
										334
									
								
								libavresample/audio_convert.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								libavresample/audio_convert.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,334 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 <stdint.h> | ||||||
|  | 
 | ||||||
|  | #include "config.h" | ||||||
|  | #include "libavutil/libm.h" | ||||||
|  | #include "libavutil/log.h" | ||||||
|  | #include "libavutil/mem.h" | ||||||
|  | #include "libavutil/samplefmt.h" | ||||||
|  | #include "audio_convert.h" | ||||||
|  | #include "audio_data.h" | ||||||
|  | 
 | ||||||
|  | enum ConvFuncType { | ||||||
|  |     CONV_FUNC_TYPE_FLAT, | ||||||
|  |     CONV_FUNC_TYPE_INTERLEAVE, | ||||||
|  |     CONV_FUNC_TYPE_DEINTERLEAVE, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef void (conv_func_flat)(uint8_t *out, const uint8_t *in, int len); | ||||||
|  | 
 | ||||||
|  | typedef void (conv_func_interleave)(uint8_t *out, uint8_t *const *in, | ||||||
|  |                                     int len, int channels); | ||||||
|  | 
 | ||||||
|  | typedef void (conv_func_deinterleave)(uint8_t **out, const uint8_t *in, int len, | ||||||
|  |                                       int channels); | ||||||
|  | 
 | ||||||
|  | struct AudioConvert { | ||||||
|  |     AVAudioResampleContext *avr; | ||||||
|  |     enum AVSampleFormat in_fmt; | ||||||
|  |     enum AVSampleFormat out_fmt; | ||||||
|  |     int channels; | ||||||
|  |     int planes; | ||||||
|  |     int ptr_align; | ||||||
|  |     int samples_align; | ||||||
|  |     int has_optimized_func; | ||||||
|  |     const char *func_descr; | ||||||
|  |     const char *func_descr_generic; | ||||||
|  |     enum ConvFuncType func_type; | ||||||
|  |     conv_func_flat         *conv_flat; | ||||||
|  |     conv_func_flat         *conv_flat_generic; | ||||||
|  |     conv_func_interleave   *conv_interleave; | ||||||
|  |     conv_func_interleave   *conv_interleave_generic; | ||||||
|  |     conv_func_deinterleave *conv_deinterleave; | ||||||
|  |     conv_func_deinterleave *conv_deinterleave_generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void ff_audio_convert_set_func(AudioConvert *ac, enum AVSampleFormat out_fmt, | ||||||
|  |                                enum AVSampleFormat in_fmt, int channels, | ||||||
|  |                                int ptr_align, int samples_align, | ||||||
|  |                                const char *descr, void *conv) | ||||||
|  | { | ||||||
|  |     int found = 0; | ||||||
|  | 
 | ||||||
|  |     switch (ac->func_type) { | ||||||
|  |     case CONV_FUNC_TYPE_FLAT: | ||||||
|  |         if (av_get_packed_sample_fmt(ac->in_fmt)  == in_fmt && | ||||||
|  |             av_get_packed_sample_fmt(ac->out_fmt) == out_fmt) { | ||||||
|  |             ac->conv_flat     = conv; | ||||||
|  |             ac->func_descr    = descr; | ||||||
|  |             ac->ptr_align     = ptr_align; | ||||||
|  |             ac->samples_align = samples_align; | ||||||
|  |             if (ptr_align == 1 && samples_align == 1) { | ||||||
|  |                 ac->conv_flat_generic  = conv; | ||||||
|  |                 ac->func_descr_generic = descr; | ||||||
|  |             } else { | ||||||
|  |                 ac->has_optimized_func = 1; | ||||||
|  |             } | ||||||
|  |             found = 1; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CONV_FUNC_TYPE_INTERLEAVE: | ||||||
|  |         if (ac->in_fmt == in_fmt && ac->out_fmt == out_fmt && | ||||||
|  |             (!channels || ac->channels == channels)) { | ||||||
|  |             ac->conv_interleave = conv; | ||||||
|  |             ac->func_descr      = descr; | ||||||
|  |             ac->ptr_align       = ptr_align; | ||||||
|  |             ac->samples_align   = samples_align; | ||||||
|  |             if (ptr_align == 1 && samples_align == 1) { | ||||||
|  |                 ac->conv_interleave_generic = conv; | ||||||
|  |                 ac->func_descr_generic      = descr; | ||||||
|  |             } else { | ||||||
|  |                 ac->has_optimized_func = 1; | ||||||
|  |             } | ||||||
|  |             found = 1; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CONV_FUNC_TYPE_DEINTERLEAVE: | ||||||
|  |         if (ac->in_fmt == in_fmt && ac->out_fmt == out_fmt && | ||||||
|  |             (!channels || ac->channels == channels)) { | ||||||
|  |             ac->conv_deinterleave = conv; | ||||||
|  |             ac->func_descr        = descr; | ||||||
|  |             ac->ptr_align         = ptr_align; | ||||||
|  |             ac->samples_align     = samples_align; | ||||||
|  |             if (ptr_align == 1 && samples_align == 1) { | ||||||
|  |                 ac->conv_deinterleave_generic = conv; | ||||||
|  |                 ac->func_descr_generic        = descr; | ||||||
|  |             } else { | ||||||
|  |                 ac->has_optimized_func = 1; | ||||||
|  |             } | ||||||
|  |             found = 1; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     if (found) { | ||||||
|  |         av_log(ac->avr, AV_LOG_DEBUG, "audio_convert: found function: %-4s " | ||||||
|  |                "to %-4s (%s)\n", av_get_sample_fmt_name(ac->in_fmt), | ||||||
|  |                av_get_sample_fmt_name(ac->out_fmt), descr); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define CONV_FUNC_NAME(dst_fmt, src_fmt) conv_ ## src_fmt ## _to_ ## dst_fmt | ||||||
|  | 
 | ||||||
|  | #define CONV_LOOP(otype, expr)                                              \ | ||||||
|  |     do {                                                                    \ | ||||||
|  |         *(otype *)po = expr;                                                \ | ||||||
|  |         pi += is;                                                           \ | ||||||
|  |         po += os;                                                           \ | ||||||
|  |     } while (po < end);                                                     \ | ||||||
|  | 
 | ||||||
|  | #define CONV_FUNC_FLAT(ofmt, otype, ifmt, itype, expr)                      \ | ||||||
|  | static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *out, const uint8_t *in,     \ | ||||||
|  |                                        int len)                             \ | ||||||
|  | {                                                                           \ | ||||||
|  |     int is       = sizeof(itype);                                           \ | ||||||
|  |     int os       = sizeof(otype);                                           \ | ||||||
|  |     const uint8_t *pi = in;                                                 \ | ||||||
|  |     uint8_t       *po = out;                                                \ | ||||||
|  |     uint8_t *end = out + os * len;                                          \ | ||||||
|  |     CONV_LOOP(otype, expr)                                                  \ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define CONV_FUNC_INTERLEAVE(ofmt, otype, ifmt, itype, expr)                \ | ||||||
|  | static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *out, const uint8_t **in,    \ | ||||||
|  |                                        int len, int channels)               \ | ||||||
|  | {                                                                           \ | ||||||
|  |     int ch;                                                                 \ | ||||||
|  |     int out_bps = sizeof(otype);                                            \ | ||||||
|  |     int is      = sizeof(itype);                                            \ | ||||||
|  |     int os      = channels * out_bps;                                       \ | ||||||
|  |     for (ch = 0; ch < channels; ch++) {                                     \ | ||||||
|  |         const uint8_t *pi = in[ch];                                         \ | ||||||
|  |         uint8_t       *po = out + ch * out_bps;                             \ | ||||||
|  |         uint8_t      *end = po + os * len;                                  \ | ||||||
|  |         CONV_LOOP(otype, expr)                                              \ | ||||||
|  |     }                                                                       \ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define CONV_FUNC_DEINTERLEAVE(ofmt, otype, ifmt, itype, expr)              \ | ||||||
|  | static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t **out, const uint8_t *in,    \ | ||||||
|  |                                        int len, int channels)               \ | ||||||
|  | {                                                                           \ | ||||||
|  |     int ch;                                                                 \ | ||||||
|  |     int in_bps = sizeof(itype);                                             \ | ||||||
|  |     int is     = channels * in_bps;                                         \ | ||||||
|  |     int os     = sizeof(otype);                                             \ | ||||||
|  |     for (ch = 0; ch < channels; ch++) {                                     \ | ||||||
|  |         const uint8_t *pi = in  + ch * in_bps;                              \ | ||||||
|  |         uint8_t       *po = out[ch];                                        \ | ||||||
|  |         uint8_t      *end = po + os * len;                                  \ | ||||||
|  |         CONV_LOOP(otype, expr)                                              \ | ||||||
|  |     }                                                                       \ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define CONV_FUNC_GROUP(ofmt, otype, ifmt, itype, expr) \ | ||||||
|  | CONV_FUNC_FLAT(        ofmt,      otype, ifmt,      itype, expr) \ | ||||||
|  | CONV_FUNC_INTERLEAVE(  ofmt,      otype, ifmt ## P, itype, expr) \ | ||||||
|  | CONV_FUNC_DEINTERLEAVE(ofmt ## P, otype, ifmt,      itype, expr) | ||||||
|  | 
 | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8,  uint8_t, AV_SAMPLE_FMT_U8,  uint8_t,  *(const uint8_t *)pi) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8,  uint8_t, (*(const uint8_t *)pi - 0x80) <<  8) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8,  uint8_t, (*(const uint8_t *)pi - 0x80) << 24) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float,   AV_SAMPLE_FMT_U8,  uint8_t, (*(const uint8_t *)pi - 0x80) * (1.0f / (1 << 7))) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double,  AV_SAMPLE_FMT_U8,  uint8_t, (*(const uint8_t *)pi - 0x80) * (1.0  / (1 << 7))) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8,  uint8_t, AV_SAMPLE_FMT_S16, int16_t, (*(const int16_t *)pi >> 8) + 0x80) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, int16_t,  *(const int16_t *)pi) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, int16_t,  *(const int16_t *)pi << 16) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float,   AV_SAMPLE_FMT_S16, int16_t,  *(const int16_t *)pi * (1.0f / (1 << 15))) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double,  AV_SAMPLE_FMT_S16, int16_t,  *(const int16_t *)pi * (1.0  / (1 << 15))) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8,  uint8_t, AV_SAMPLE_FMT_S32, int32_t, (*(const int32_t *)pi >> 24) + 0x80) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, int32_t,  *(const int32_t *)pi >> 16) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, int32_t,  *(const int32_t *)pi) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float,   AV_SAMPLE_FMT_S32, int32_t,  *(const int32_t *)pi * (1.0f / (1U << 31))) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double,  AV_SAMPLE_FMT_S32, int32_t,  *(const int32_t *)pi * (1.0  / (1U << 31))) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8,  uint8_t, AV_SAMPLE_FMT_FLT, float,   av_clip_uint8(  lrintf(*(const float *)pi * (1  <<  7)) + 0x80)) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float,   av_clip_int16(  lrintf(*(const float *)pi * (1  << 15)))) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float,   av_clipl_int32(llrintf(*(const float *)pi * (1U << 31)))) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float,   AV_SAMPLE_FMT_FLT, float,   *(const float *)pi) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double,  AV_SAMPLE_FMT_FLT, float,   *(const float *)pi) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8,  uint8_t, AV_SAMPLE_FMT_DBL, double,  av_clip_uint8(  lrint(*(const double *)pi * (1  <<  7)) + 0x80)) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double,  av_clip_int16(  lrint(*(const double *)pi * (1  << 15)))) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double,  av_clipl_int32(llrint(*(const double *)pi * (1U << 31)))) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float,   AV_SAMPLE_FMT_DBL, double,  *(const double *)pi) | ||||||
|  | CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double,  AV_SAMPLE_FMT_DBL, double,  *(const double *)pi) | ||||||
|  | 
 | ||||||
|  | #define SET_CONV_FUNC_GROUP(ofmt, ifmt)                                                             \ | ||||||
|  | ff_audio_convert_set_func(ac, ofmt,      ifmt,      0, 1, 1, "C", CONV_FUNC_NAME(ofmt,      ifmt)); \ | ||||||
|  | ff_audio_convert_set_func(ac, ofmt ## P, ifmt,      0, 1, 1, "C", CONV_FUNC_NAME(ofmt ## P, ifmt)); \ | ||||||
|  | ff_audio_convert_set_func(ac, ofmt,      ifmt ## P, 0, 1, 1, "C", CONV_FUNC_NAME(ofmt,      ifmt ## P)); | ||||||
|  | 
 | ||||||
|  | static void set_generic_function(AudioConvert *ac) | ||||||
|  | { | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8,  AV_SAMPLE_FMT_U8) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8,  AV_SAMPLE_FMT_S16) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8,  AV_SAMPLE_FMT_S32) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8,  AV_SAMPLE_FMT_FLT) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8,  AV_SAMPLE_FMT_DBL) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL) | ||||||
|  |     SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, | ||||||
|  |                                      enum AVSampleFormat out_fmt, | ||||||
|  |                                      enum AVSampleFormat in_fmt, | ||||||
|  |                                      int channels) | ||||||
|  | { | ||||||
|  |     AudioConvert *ac; | ||||||
|  |     int in_planar, out_planar; | ||||||
|  | 
 | ||||||
|  |     ac = av_mallocz(sizeof(*ac)); | ||||||
|  |     if (!ac) | ||||||
|  |         return NULL; | ||||||
|  | 
 | ||||||
|  |     ac->avr      = avr; | ||||||
|  |     ac->out_fmt  = out_fmt; | ||||||
|  |     ac->in_fmt   = in_fmt; | ||||||
|  |     ac->channels = channels; | ||||||
|  | 
 | ||||||
|  |     in_planar  = av_sample_fmt_is_planar(in_fmt); | ||||||
|  |     out_planar = av_sample_fmt_is_planar(out_fmt); | ||||||
|  | 
 | ||||||
|  |     if (in_planar == out_planar) { | ||||||
|  |         ac->func_type = CONV_FUNC_TYPE_FLAT; | ||||||
|  |         ac->planes    = in_planar ? ac->channels : 1; | ||||||
|  |     } else if (in_planar) | ||||||
|  |         ac->func_type = CONV_FUNC_TYPE_INTERLEAVE; | ||||||
|  |     else | ||||||
|  |         ac->func_type = CONV_FUNC_TYPE_DEINTERLEAVE; | ||||||
|  | 
 | ||||||
|  |     set_generic_function(ac); | ||||||
|  | 
 | ||||||
|  |     if (ARCH_X86) | ||||||
|  |         ff_audio_convert_init_x86(ac); | ||||||
|  | 
 | ||||||
|  |     return ac; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in, int len) | ||||||
|  | { | ||||||
|  |     int use_generic = 1; | ||||||
|  | 
 | ||||||
|  |     /* determine whether to use the optimized function based on pointer and
 | ||||||
|  |        samples alignment in both the input and output */ | ||||||
|  |     if (ac->has_optimized_func) { | ||||||
|  |         int ptr_align     = FFMIN(in->ptr_align,     out->ptr_align); | ||||||
|  |         int samples_align = FFMIN(in->samples_align, out->samples_align); | ||||||
|  |         int aligned_len   = FFALIGN(len, ac->samples_align); | ||||||
|  |         if (!(ptr_align % ac->ptr_align) && samples_align >= aligned_len) { | ||||||
|  |             len = aligned_len; | ||||||
|  |             use_generic = 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     av_dlog(ac->avr, "%d samples - audio_convert: %s to %s (%s)\n", len, | ||||||
|  |             av_get_sample_fmt_name(ac->in_fmt), | ||||||
|  |             av_get_sample_fmt_name(ac->out_fmt), | ||||||
|  |             use_generic ? ac->func_descr_generic : ac->func_descr); | ||||||
|  | 
 | ||||||
|  |     switch (ac->func_type) { | ||||||
|  |     case CONV_FUNC_TYPE_FLAT: { | ||||||
|  |         int p; | ||||||
|  |         if (!in->is_planar) | ||||||
|  |             len *= in->channels; | ||||||
|  |         if (use_generic) { | ||||||
|  |             for (p = 0; p < ac->planes; p++) | ||||||
|  |                 ac->conv_flat_generic(out->data[p], in->data[p], len); | ||||||
|  |         } else { | ||||||
|  |             for (p = 0; p < ac->planes; p++) | ||||||
|  |                 ac->conv_flat(out->data[p], in->data[p], len); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     case CONV_FUNC_TYPE_INTERLEAVE: | ||||||
|  |         if (use_generic) | ||||||
|  |             ac->conv_interleave_generic(out->data[0], in->data, len, ac->channels); | ||||||
|  |         else | ||||||
|  |             ac->conv_interleave(out->data[0], in->data, len, ac->channels); | ||||||
|  |         break; | ||||||
|  |     case CONV_FUNC_TYPE_DEINTERLEAVE: | ||||||
|  |         if (use_generic) | ||||||
|  |             ac->conv_deinterleave_generic(out->data, in->data[0], len, ac->channels); | ||||||
|  |         else | ||||||
|  |             ac->conv_deinterleave(out->data, in->data[0], len, ac->channels); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     out->nb_samples = in->nb_samples; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										87
									
								
								libavresample/audio_convert.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								libavresample/audio_convert.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef AVRESAMPLE_AUDIO_CONVERT_H | ||||||
|  | #define AVRESAMPLE_AUDIO_CONVERT_H | ||||||
|  | 
 | ||||||
|  | #include "libavutil/samplefmt.h" | ||||||
|  | #include "avresample.h" | ||||||
|  | #include "audio_data.h" | ||||||
|  | 
 | ||||||
|  | typedef struct AudioConvert AudioConvert; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Set conversion function if the parameters match. | ||||||
|  |  * | ||||||
|  |  * This compares the parameters of the conversion function to the parameters | ||||||
|  |  * in the AudioConvert context. If the parameters do not match, no changes are | ||||||
|  |  * made to the active functions. If the parameters do match and the alignment | ||||||
|  |  * is not constrained, the function is set as the generic conversion function. | ||||||
|  |  * If the parameters match and the alignment is constrained, the function is | ||||||
|  |  * set as the optimized conversion function. | ||||||
|  |  * | ||||||
|  |  * @param ac             AudioConvert context | ||||||
|  |  * @param out_fmt        output sample format | ||||||
|  |  * @param in_fmt         input sample format | ||||||
|  |  * @param channels       number of channels, or 0 for any number of channels | ||||||
|  |  * @param ptr_align      buffer pointer alignment, in bytes | ||||||
|  |  * @param sample_align   buffer size alignment, in samples | ||||||
|  |  * @param descr          function type description (e.g. "C" or "SSE") | ||||||
|  |  * @param conv           conversion function pointer | ||||||
|  |  */ | ||||||
|  | void ff_audio_convert_set_func(AudioConvert *ac, enum AVSampleFormat out_fmt, | ||||||
|  |                                enum AVSampleFormat in_fmt, int channels, | ||||||
|  |                                int ptr_align, int samples_align, | ||||||
|  |                                const char *descr, void *conv); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Allocate and initialize AudioConvert context for sample format conversion. | ||||||
|  |  * | ||||||
|  |  * @param avr      AVAudioResampleContext | ||||||
|  |  * @param out_fmt  output sample format | ||||||
|  |  * @param in_fmt   input sample format | ||||||
|  |  * @param channels number of channels | ||||||
|  |  * @return         newly-allocated AudioConvert context | ||||||
|  |  */ | ||||||
|  | AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, | ||||||
|  |                                      enum AVSampleFormat out_fmt, | ||||||
|  |                                      enum AVSampleFormat in_fmt, | ||||||
|  |                                      int channels); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Convert audio data from one sample format to another. | ||||||
|  |  * | ||||||
|  |  * For each call, the alignment of the input and output AudioData buffers are | ||||||
|  |  * examined to determine whether to use the generic or optimized conversion | ||||||
|  |  * function (when available). | ||||||
|  |  * | ||||||
|  |  * @param ac     AudioConvert context | ||||||
|  |  * @param out    output audio data | ||||||
|  |  * @param in     input audio data | ||||||
|  |  * @param len    number of samples to convert | ||||||
|  |  * @return       0 on success, negative AVERROR code on failure | ||||||
|  |  */ | ||||||
|  | int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in, int len); | ||||||
|  | 
 | ||||||
|  | /* arch-specific initialization functions */ | ||||||
|  | 
 | ||||||
|  | void ff_audio_convert_init_x86(AudioConvert *ac); | ||||||
|  | 
 | ||||||
|  | #endif /* AVRESAMPLE_AUDIO_CONVERT_H */ | ||||||
							
								
								
									
										345
									
								
								libavresample/audio_data.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										345
									
								
								libavresample/audio_data.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,345 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 <stdint.h> | ||||||
|  | 
 | ||||||
|  | #include "libavutil/mem.h" | ||||||
|  | #include "audio_data.h" | ||||||
|  | 
 | ||||||
|  | static const AVClass audio_data_class = { | ||||||
|  |     .class_name = "AudioData", | ||||||
|  |     .item_name  = av_default_item_name, | ||||||
|  |     .version    = LIBAVUTIL_VERSION_INT, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Calculate alignment for data pointers. | ||||||
|  |  */ | ||||||
|  | static void calc_ptr_alignment(AudioData *a) | ||||||
|  | { | ||||||
|  |     int p; | ||||||
|  |     int min_align = 128; | ||||||
|  | 
 | ||||||
|  |     for (p = 0; p < a->planes; p++) { | ||||||
|  |         int cur_align = 128; | ||||||
|  |         while ((intptr_t)a->data[p] % cur_align) | ||||||
|  |             cur_align >>= 1; | ||||||
|  |         if (cur_align < min_align) | ||||||
|  |             min_align = cur_align; | ||||||
|  |     } | ||||||
|  |     a->ptr_align = min_align; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ff_audio_data_set_channels(AudioData *a, int channels) | ||||||
|  | { | ||||||
|  |     if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS || | ||||||
|  |         channels > a->allocated_channels) | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  | 
 | ||||||
|  |     a->channels  = channels; | ||||||
|  |     a->planes    = a->is_planar ? channels : 1; | ||||||
|  | 
 | ||||||
|  |     calc_ptr_alignment(a); | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ff_audio_data_init(AudioData *a, void **src, int plane_size, int channels, | ||||||
|  |                        int nb_samples, enum AVSampleFormat sample_fmt, | ||||||
|  |                        int read_only, const char *name) | ||||||
|  | { | ||||||
|  |     int p; | ||||||
|  | 
 | ||||||
|  |     memset(a, 0, sizeof(*a)); | ||||||
|  |     a->class = &audio_data_class; | ||||||
|  | 
 | ||||||
|  |     if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) { | ||||||
|  |         av_log(a, AV_LOG_ERROR, "invalid channel count: %d\n", channels); | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     a->sample_size = av_get_bytes_per_sample(sample_fmt); | ||||||
|  |     if (!a->sample_size) { | ||||||
|  |         av_log(a, AV_LOG_ERROR, "invalid sample format\n"); | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  |     } | ||||||
|  |     a->is_planar = av_sample_fmt_is_planar(sample_fmt); | ||||||
|  |     a->planes    = a->is_planar ? channels : 1; | ||||||
|  |     a->stride    = a->sample_size * (a->is_planar ? 1 : channels); | ||||||
|  | 
 | ||||||
|  |     for (p = 0; p < (a->is_planar ? channels : 1); p++) { | ||||||
|  |         if (!src[p]) { | ||||||
|  |             av_log(a, AV_LOG_ERROR, "invalid NULL pointer for src[%d]\n", p); | ||||||
|  |             return AVERROR(EINVAL); | ||||||
|  |         } | ||||||
|  |         a->data[p] = src[p]; | ||||||
|  |     } | ||||||
|  |     a->allocated_samples  = nb_samples * !read_only; | ||||||
|  |     a->nb_samples         = nb_samples; | ||||||
|  |     a->sample_fmt         = sample_fmt; | ||||||
|  |     a->channels           = channels; | ||||||
|  |     a->allocated_channels = channels; | ||||||
|  |     a->read_only          = read_only; | ||||||
|  |     a->allow_realloc      = 0; | ||||||
|  |     a->name               = name ? name : "{no name}"; | ||||||
|  | 
 | ||||||
|  |     calc_ptr_alignment(a); | ||||||
|  |     a->samples_align = plane_size / a->stride; | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | AudioData *ff_audio_data_alloc(int channels, int nb_samples, | ||||||
|  |                                enum AVSampleFormat sample_fmt, const char *name) | ||||||
|  | { | ||||||
|  |     AudioData *a; | ||||||
|  |     int ret; | ||||||
|  | 
 | ||||||
|  |     if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) | ||||||
|  |         return NULL; | ||||||
|  | 
 | ||||||
|  |     a = av_mallocz(sizeof(*a)); | ||||||
|  |     if (!a) | ||||||
|  |         return NULL; | ||||||
|  | 
 | ||||||
|  |     a->sample_size = av_get_bytes_per_sample(sample_fmt); | ||||||
|  |     if (!a->sample_size) { | ||||||
|  |         av_free(a); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     a->is_planar = av_sample_fmt_is_planar(sample_fmt); | ||||||
|  |     a->planes    = a->is_planar ? channels : 1; | ||||||
|  |     a->stride    = a->sample_size * (a->is_planar ? 1 : channels); | ||||||
|  | 
 | ||||||
|  |     a->class              = &audio_data_class; | ||||||
|  |     a->sample_fmt         = sample_fmt; | ||||||
|  |     a->channels           = channels; | ||||||
|  |     a->allocated_channels = channels; | ||||||
|  |     a->read_only          = 0; | ||||||
|  |     a->allow_realloc      = 1; | ||||||
|  |     a->name               = name ? name : "{no name}"; | ||||||
|  | 
 | ||||||
|  |     if (nb_samples > 0) { | ||||||
|  |         ret = ff_audio_data_realloc(a, nb_samples); | ||||||
|  |         if (ret < 0) { | ||||||
|  |             av_free(a); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |         return a; | ||||||
|  |     } else { | ||||||
|  |         calc_ptr_alignment(a); | ||||||
|  |         return a; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ff_audio_data_realloc(AudioData *a, int nb_samples) | ||||||
|  | { | ||||||
|  |     int ret, new_buf_size, plane_size, p; | ||||||
|  | 
 | ||||||
|  |     /* check if buffer is already large enough */ | ||||||
|  |     if (a->allocated_samples >= nb_samples) | ||||||
|  |         return 0; | ||||||
|  | 
 | ||||||
|  |     /* validate that the output is not read-only and realloc is allowed */ | ||||||
|  |     if (a->read_only || !a->allow_realloc) | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  | 
 | ||||||
|  |     new_buf_size = av_samples_get_buffer_size(&plane_size, | ||||||
|  |                                               a->allocated_channels, nb_samples, | ||||||
|  |                                               a->sample_fmt, 0); | ||||||
|  |     if (new_buf_size < 0) | ||||||
|  |         return new_buf_size; | ||||||
|  | 
 | ||||||
|  |     /* if there is already data in the buffer and the sample format is planar,
 | ||||||
|  |        allocate a new buffer and copy the data, otherwise just realloc the | ||||||
|  |        internal buffer and set new data pointers */ | ||||||
|  |     if (a->nb_samples > 0 && a->is_planar) { | ||||||
|  |         uint8_t *new_data[AVRESAMPLE_MAX_CHANNELS] = { NULL }; | ||||||
|  | 
 | ||||||
|  |         ret = av_samples_alloc(new_data, &plane_size, a->allocated_channels, | ||||||
|  |                                nb_samples, a->sample_fmt, 0); | ||||||
|  |         if (ret < 0) | ||||||
|  |             return ret; | ||||||
|  | 
 | ||||||
|  |         for (p = 0; p < a->planes; p++) | ||||||
|  |             memcpy(new_data[p], a->data[p], a->nb_samples * a->stride); | ||||||
|  | 
 | ||||||
|  |         av_freep(&a->buffer); | ||||||
|  |         memcpy(a->data, new_data, sizeof(new_data)); | ||||||
|  |         a->buffer = a->data[0]; | ||||||
|  |     } else { | ||||||
|  |         av_freep(&a->buffer); | ||||||
|  |         a->buffer = av_malloc(new_buf_size); | ||||||
|  |         if (!a->buffer) | ||||||
|  |             return AVERROR(ENOMEM); | ||||||
|  |         ret = av_samples_fill_arrays(a->data, &plane_size, a->buffer, | ||||||
|  |                                      a->allocated_channels, nb_samples, | ||||||
|  |                                      a->sample_fmt, 0); | ||||||
|  |         if (ret < 0) | ||||||
|  |             return ret; | ||||||
|  |     } | ||||||
|  |     a->buffer_size       = new_buf_size; | ||||||
|  |     a->allocated_samples = nb_samples; | ||||||
|  | 
 | ||||||
|  |     calc_ptr_alignment(a); | ||||||
|  |     a->samples_align = plane_size / a->stride; | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ff_audio_data_free(AudioData **a) | ||||||
|  | { | ||||||
|  |     if (!*a) | ||||||
|  |         return; | ||||||
|  |     av_free((*a)->buffer); | ||||||
|  |     av_freep(a); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ff_audio_data_copy(AudioData *dst, AudioData *src) | ||||||
|  | { | ||||||
|  |     int ret, p; | ||||||
|  | 
 | ||||||
|  |     /* validate input/output compatibility */ | ||||||
|  |     if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels) | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  | 
 | ||||||
|  |     /* if the input is empty, just empty the output */ | ||||||
|  |     if (!src->nb_samples) { | ||||||
|  |         dst->nb_samples = 0; | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* reallocate output if necessary */ | ||||||
|  |     ret = ff_audio_data_realloc(dst, src->nb_samples); | ||||||
|  |     if (ret < 0) | ||||||
|  |         return ret; | ||||||
|  | 
 | ||||||
|  |     /* copy data */ | ||||||
|  |     for (p = 0; p < src->planes; p++) | ||||||
|  |         memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride); | ||||||
|  |     dst->nb_samples = src->nb_samples; | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src, | ||||||
|  |                           int src_offset, int nb_samples) | ||||||
|  | { | ||||||
|  |     int ret, p, dst_offset2, dst_move_size; | ||||||
|  | 
 | ||||||
|  |     /* validate input/output compatibility */ | ||||||
|  |     if (dst->sample_fmt != src->sample_fmt || dst->channels != src->channels) { | ||||||
|  |         av_log(src, AV_LOG_ERROR, "sample format mismatch\n"); | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* validate offsets are within the buffer bounds */ | ||||||
|  |     if (dst_offset < 0 || dst_offset > dst->nb_samples || | ||||||
|  |         src_offset < 0 || src_offset > src->nb_samples) { | ||||||
|  |         av_log(src, AV_LOG_ERROR, "offset out-of-bounds: src=%d dst=%d\n", | ||||||
|  |                src_offset, dst_offset); | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* check offsets and sizes to see if we can just do nothing and return */ | ||||||
|  |     if (nb_samples > src->nb_samples - src_offset) | ||||||
|  |         nb_samples = src->nb_samples - src_offset; | ||||||
|  |     if (nb_samples <= 0) | ||||||
|  |         return 0; | ||||||
|  | 
 | ||||||
|  |     /* validate that the output is not read-only */ | ||||||
|  |     if (dst->read_only) { | ||||||
|  |         av_log(dst, AV_LOG_ERROR, "dst is read-only\n"); | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* reallocate output if necessary */ | ||||||
|  |     ret = ff_audio_data_realloc(dst, dst->nb_samples + nb_samples); | ||||||
|  |     if (ret < 0) { | ||||||
|  |         av_log(dst, AV_LOG_ERROR, "error reallocating dst\n"); | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     dst_offset2   = dst_offset + nb_samples; | ||||||
|  |     dst_move_size = dst->nb_samples - dst_offset; | ||||||
|  | 
 | ||||||
|  |     for (p = 0; p < src->planes; p++) { | ||||||
|  |         if (dst_move_size > 0) { | ||||||
|  |             memmove(dst->data[p] + dst_offset2 * dst->stride, | ||||||
|  |                     dst->data[p] + dst_offset  * dst->stride, | ||||||
|  |                     dst_move_size * dst->stride); | ||||||
|  |         } | ||||||
|  |         memcpy(dst->data[p] + dst_offset * dst->stride, | ||||||
|  |                src->data[p] + src_offset * src->stride, | ||||||
|  |                nb_samples * src->stride); | ||||||
|  |     } | ||||||
|  |     dst->nb_samples += nb_samples; | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ff_audio_data_drain(AudioData *a, int nb_samples) | ||||||
|  | { | ||||||
|  |     if (a->nb_samples <= nb_samples) { | ||||||
|  |         /* drain the whole buffer */ | ||||||
|  |         a->nb_samples = 0; | ||||||
|  |     } else { | ||||||
|  |         int p; | ||||||
|  |         int move_offset = a->stride * nb_samples; | ||||||
|  |         int move_size   = a->stride * (a->nb_samples - nb_samples); | ||||||
|  | 
 | ||||||
|  |         for (p = 0; p < a->planes; p++) | ||||||
|  |             memmove(a->data[p], a->data[p] + move_offset, move_size); | ||||||
|  | 
 | ||||||
|  |         a->nb_samples -= nb_samples; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset, | ||||||
|  |                               int nb_samples) | ||||||
|  | { | ||||||
|  |     uint8_t *offset_data[AVRESAMPLE_MAX_CHANNELS]; | ||||||
|  |     int offset_size, p; | ||||||
|  | 
 | ||||||
|  |     if (offset >= a->nb_samples) | ||||||
|  |         return 0; | ||||||
|  |     offset_size = offset * a->stride; | ||||||
|  |     for (p = 0; p < a->planes; p++) | ||||||
|  |         offset_data[p] = a->data[p] + offset_size; | ||||||
|  | 
 | ||||||
|  |     return av_audio_fifo_write(af, (void **)offset_data, nb_samples); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples) | ||||||
|  | { | ||||||
|  |     int ret; | ||||||
|  | 
 | ||||||
|  |     if (a->read_only) | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  | 
 | ||||||
|  |     ret = ff_audio_data_realloc(a, nb_samples); | ||||||
|  |     if (ret < 0) | ||||||
|  |         return ret; | ||||||
|  | 
 | ||||||
|  |     ret = av_audio_fifo_read(af, (void **)a->data, nb_samples); | ||||||
|  |     if (ret >= 0) | ||||||
|  |         a->nb_samples = ret; | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
							
								
								
									
										173
									
								
								libavresample/audio_data.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								libavresample/audio_data.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,173 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef AVRESAMPLE_AUDIO_DATA_H | ||||||
|  | #define AVRESAMPLE_AUDIO_DATA_H | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | #include "libavutil/audio_fifo.h" | ||||||
|  | #include "libavutil/log.h" | ||||||
|  | #include "libavutil/samplefmt.h" | ||||||
|  | #include "avresample.h" | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Audio buffer used for intermediate storage between conversion phases. | ||||||
|  |  */ | ||||||
|  | typedef struct AudioData { | ||||||
|  |     const AVClass *class;               /**< AVClass for logging            */ | ||||||
|  |     uint8_t *data[AVRESAMPLE_MAX_CHANNELS]; /**< data plane pointers        */ | ||||||
|  |     uint8_t *buffer;                    /**< data buffer                    */ | ||||||
|  |     unsigned int buffer_size;           /**< allocated buffer size          */ | ||||||
|  |     int allocated_samples;              /**< number of samples the buffer can hold */ | ||||||
|  |     int nb_samples;                     /**< current number of samples      */ | ||||||
|  |     enum AVSampleFormat sample_fmt;     /**< sample format                  */ | ||||||
|  |     int channels;                       /**< channel count                  */ | ||||||
|  |     int allocated_channels;             /**< allocated channel count        */ | ||||||
|  |     int is_planar;                      /**< sample format is planar        */ | ||||||
|  |     int planes;                         /**< number of data planes          */ | ||||||
|  |     int sample_size;                    /**< bytes per sample               */ | ||||||
|  |     int stride;                         /**< sample byte offset within a plane */ | ||||||
|  |     int read_only;                      /**< data is read-only              */ | ||||||
|  |     int allow_realloc;                  /**< realloc is allowed             */ | ||||||
|  |     int ptr_align;                      /**< minimum data pointer alignment */ | ||||||
|  |     int samples_align;                  /**< allocated samples alignment    */ | ||||||
|  |     const char *name;                   /**< name for debug logging         */ | ||||||
|  | } AudioData; | ||||||
|  | 
 | ||||||
|  | int ff_audio_data_set_channels(AudioData *a, int channels); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Initialize AudioData using a given source. | ||||||
|  |  * | ||||||
|  |  * This does not allocate an internal buffer. It only sets the data pointers | ||||||
|  |  * and audio parameters. | ||||||
|  |  * | ||||||
|  |  * @param a               AudioData struct | ||||||
|  |  * @param src             source data pointers | ||||||
|  |  * @param plane_size      plane size, in bytes. | ||||||
|  |  *                        This can be 0 if unknown, but that will lead to | ||||||
|  |  *                        optimized functions not being used in many cases, | ||||||
|  |  *                        which could slow down some conversions. | ||||||
|  |  * @param channels        channel count | ||||||
|  |  * @param nb_samples      number of samples in the source data | ||||||
|  |  * @param sample_fmt      sample format | ||||||
|  |  * @param read_only       indicates if buffer is read only or read/write | ||||||
|  |  * @param name            name for debug logging (can be NULL) | ||||||
|  |  * @return                0 on success, negative AVERROR value on error | ||||||
|  |  */ | ||||||
|  | int ff_audio_data_init(AudioData *a, void **src, int plane_size, int channels, | ||||||
|  |                        int nb_samples, enum AVSampleFormat sample_fmt, | ||||||
|  |                        int read_only, const char *name); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Allocate AudioData. | ||||||
|  |  * | ||||||
|  |  * This allocates an internal buffer and sets audio parameters. | ||||||
|  |  * | ||||||
|  |  * @param channels        channel count | ||||||
|  |  * @param nb_samples      number of samples to allocate space for | ||||||
|  |  * @param sample_fmt      sample format | ||||||
|  |  * @param name            name for debug logging (can be NULL) | ||||||
|  |  * @return                newly allocated AudioData struct, or NULL on error | ||||||
|  |  */ | ||||||
|  | AudioData *ff_audio_data_alloc(int channels, int nb_samples, | ||||||
|  |                                enum AVSampleFormat sample_fmt, | ||||||
|  |                                const char *name); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Reallocate AudioData. | ||||||
|  |  * | ||||||
|  |  * The AudioData must have been previously allocated with ff_audio_data_alloc(). | ||||||
|  |  * | ||||||
|  |  * @param a           AudioData struct | ||||||
|  |  * @param nb_samples  number of samples to allocate space for | ||||||
|  |  * @return            0 on success, negative AVERROR value on error | ||||||
|  |  */ | ||||||
|  | int ff_audio_data_realloc(AudioData *a, int nb_samples); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Free AudioData. | ||||||
|  |  * | ||||||
|  |  * The AudioData must have been previously allocated with ff_audio_data_alloc(). | ||||||
|  |  * | ||||||
|  |  * @param a  AudioData struct | ||||||
|  |  */ | ||||||
|  | void ff_audio_data_free(AudioData **a); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Copy data from one AudioData to another. | ||||||
|  |  * | ||||||
|  |  * @param out  output AudioData | ||||||
|  |  * @param in   input AudioData | ||||||
|  |  * @return     0 on success, negative AVERROR value on error | ||||||
|  |  */ | ||||||
|  | int ff_audio_data_copy(AudioData *out, AudioData *in); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Append data from one AudioData to the end of another. | ||||||
|  |  * | ||||||
|  |  * @param dst         destination AudioData | ||||||
|  |  * @param dst_offset  offset, in samples, to start writing, relative to the | ||||||
|  |  *                    start of dst | ||||||
|  |  * @param src         source AudioData | ||||||
|  |  * @param src_offset  offset, in samples, to start copying, relative to the | ||||||
|  |  *                    start of the src | ||||||
|  |  * @param nb_samples  number of samples to copy | ||||||
|  |  * @return            0 on success, negative AVERROR value on error | ||||||
|  |  */ | ||||||
|  | int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src, | ||||||
|  |                           int src_offset, int nb_samples); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Drain samples from the start of the AudioData. | ||||||
|  |  * | ||||||
|  |  * Remaining samples are shifted to the start of the AudioData. | ||||||
|  |  * | ||||||
|  |  * @param a           AudioData struct | ||||||
|  |  * @param nb_samples  number of samples to drain | ||||||
|  |  */ | ||||||
|  | void ff_audio_data_drain(AudioData *a, int nb_samples); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Add samples in AudioData to an AVAudioFifo. | ||||||
|  |  * | ||||||
|  |  * @param af          Audio FIFO Buffer | ||||||
|  |  * @param a           AudioData struct | ||||||
|  |  * @param offset      number of samples to skip from the start of the data | ||||||
|  |  * @param nb_samples  number of samples to add to the FIFO | ||||||
|  |  * @return            number of samples actually added to the FIFO, or | ||||||
|  |  *                    negative AVERROR code on error | ||||||
|  |  */ | ||||||
|  | int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset, | ||||||
|  |                               int nb_samples); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Read samples from an AVAudioFifo to AudioData. | ||||||
|  |  * | ||||||
|  |  * @param af          Audio FIFO Buffer | ||||||
|  |  * @param a           AudioData struct | ||||||
|  |  * @param nb_samples  number of samples to read from the FIFO | ||||||
|  |  * @return            number of samples actually read from the FIFO, or | ||||||
|  |  *                    negative AVERROR code on error | ||||||
|  |  */ | ||||||
|  | int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples); | ||||||
|  | 
 | ||||||
|  | #endif /* AVRESAMPLE_AUDIO_DATA_H */ | ||||||
							
								
								
									
										356
									
								
								libavresample/audio_mix.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										356
									
								
								libavresample/audio_mix.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,356 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 <stdint.h> | ||||||
|  | 
 | ||||||
|  | #include "libavutil/libm.h" | ||||||
|  | #include "libavutil/samplefmt.h" | ||||||
|  | #include "avresample.h" | ||||||
|  | #include "internal.h" | ||||||
|  | #include "audio_data.h" | ||||||
|  | #include "audio_mix.h" | ||||||
|  | 
 | ||||||
|  | static const char *coeff_type_names[] = { "q6", "q15", "flt" }; | ||||||
|  | 
 | ||||||
|  | void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt, | ||||||
|  |                            enum AVMixCoeffType coeff_type, int in_channels, | ||||||
|  |                            int out_channels, int ptr_align, int samples_align, | ||||||
|  |                            const char *descr, void *mix_func) | ||||||
|  | { | ||||||
|  |     if (fmt == am->fmt && coeff_type == am->coeff_type && | ||||||
|  |         ( in_channels ==  am->in_channels ||  in_channels == 0) && | ||||||
|  |         (out_channels == am->out_channels || out_channels == 0)) { | ||||||
|  |         char chan_str[16]; | ||||||
|  |         am->mix           = mix_func; | ||||||
|  |         am->func_descr    = descr; | ||||||
|  |         am->ptr_align     = ptr_align; | ||||||
|  |         am->samples_align = samples_align; | ||||||
|  |         if (ptr_align == 1 && samples_align == 1) { | ||||||
|  |             am->mix_generic        = mix_func; | ||||||
|  |             am->func_descr_generic = descr; | ||||||
|  |         } else { | ||||||
|  |             am->has_optimized_func = 1; | ||||||
|  |         } | ||||||
|  |         if (in_channels) { | ||||||
|  |             if (out_channels) | ||||||
|  |                 snprintf(chan_str, sizeof(chan_str), "[%d to %d] ", | ||||||
|  |                          in_channels, out_channels); | ||||||
|  |             else | ||||||
|  |                 snprintf(chan_str, sizeof(chan_str), "[%d to any] ", | ||||||
|  |                          in_channels); | ||||||
|  |         } else if (out_channels) { | ||||||
|  |                 snprintf(chan_str, sizeof(chan_str), "[any to %d] ", | ||||||
|  |                          out_channels); | ||||||
|  |         } | ||||||
|  |         av_log(am->avr, AV_LOG_DEBUG, "audio_mix: found function: [fmt=%s] " | ||||||
|  |                "[c=%s] %s(%s)\n", av_get_sample_fmt_name(fmt), | ||||||
|  |                coeff_type_names[coeff_type], | ||||||
|  |                (in_channels || out_channels) ? chan_str : "", descr); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define MIX_FUNC_NAME(fmt, cfmt) mix_any_ ## fmt ##_## cfmt ##_c | ||||||
|  | 
 | ||||||
|  | #define MIX_FUNC_GENERIC(fmt, cfmt, stype, ctype, sumtype, expr)            \ | ||||||
|  | static void MIX_FUNC_NAME(fmt, cfmt)(stype **samples, ctype **matrix,       \ | ||||||
|  |                                      int len, int out_ch, int in_ch)        \ | ||||||
|  | {                                                                           \ | ||||||
|  |     int i, in, out;                                                         \ | ||||||
|  |     stype temp[AVRESAMPLE_MAX_CHANNELS];                                    \ | ||||||
|  |     for (i = 0; i < len; i++) {                                             \ | ||||||
|  |         for (out = 0; out < out_ch; out++) {                                \ | ||||||
|  |             sumtype sum = 0;                                                \ | ||||||
|  |             for (in = 0; in < in_ch; in++)                                  \ | ||||||
|  |                 sum += samples[in][i] * matrix[out][in];                    \ | ||||||
|  |             temp[out] = expr;                                               \ | ||||||
|  |         }                                                                   \ | ||||||
|  |         for (out = 0; out < out_ch; out++)                                  \ | ||||||
|  |             samples[out][i] = temp[out];                                    \ | ||||||
|  |     }                                                                       \ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MIX_FUNC_GENERIC(FLTP, FLT, float,   float,   float,   sum) | ||||||
|  | MIX_FUNC_GENERIC(S16P, FLT, int16_t, float,   float,   av_clip_int16(lrintf(sum))) | ||||||
|  | MIX_FUNC_GENERIC(S16P, Q15, int16_t, int32_t, int64_t, av_clip_int16(sum >> 15)) | ||||||
|  | MIX_FUNC_GENERIC(S16P, Q6,  int16_t, int16_t, int32_t, av_clip_int16(sum >> 6)) | ||||||
|  | 
 | ||||||
|  | /* TODO: templatize the channel-specific C functions */ | ||||||
|  | 
 | ||||||
|  | static void mix_2_to_1_fltp_flt_c(float **samples, float **matrix, int len, | ||||||
|  |                                   int out_ch, int in_ch) | ||||||
|  | { | ||||||
|  |     float *src0 = samples[0]; | ||||||
|  |     float *src1 = samples[1]; | ||||||
|  |     float *dst  = src0; | ||||||
|  |     float m0    = matrix[0][0]; | ||||||
|  |     float m1    = matrix[0][1]; | ||||||
|  | 
 | ||||||
|  |     while (len > 4) { | ||||||
|  |         *dst++ = *src0++ * m0 + *src1++ * m1; | ||||||
|  |         *dst++ = *src0++ * m0 + *src1++ * m1; | ||||||
|  |         *dst++ = *src0++ * m0 + *src1++ * m1; | ||||||
|  |         *dst++ = *src0++ * m0 + *src1++ * m1; | ||||||
|  |         len -= 4; | ||||||
|  |     } | ||||||
|  |     while (len > 0) { | ||||||
|  |         *dst++ = *src0++ * m0 + *src1++ * m1; | ||||||
|  |         len--; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void mix_1_to_2_fltp_flt_c(float **samples, float **matrix, int len, | ||||||
|  |                                   int out_ch, int in_ch) | ||||||
|  | { | ||||||
|  |     float v; | ||||||
|  |     float *dst0 = samples[0]; | ||||||
|  |     float *dst1 = samples[1]; | ||||||
|  |     float *src  = dst0; | ||||||
|  |     float m0    = matrix[0][0]; | ||||||
|  |     float m1    = matrix[1][0]; | ||||||
|  | 
 | ||||||
|  |     while (len > 4) { | ||||||
|  |         v = *src++; | ||||||
|  |         *dst0++ = v * m1; | ||||||
|  |         *dst1++ = v * m0; | ||||||
|  |         v = *src++; | ||||||
|  |         *dst0++ = v * m1; | ||||||
|  |         *dst1++ = v * m0; | ||||||
|  |         v = *src++; | ||||||
|  |         *dst0++ = v * m1; | ||||||
|  |         *dst1++ = v * m0; | ||||||
|  |         v = *src++; | ||||||
|  |         *dst0++ = v * m1; | ||||||
|  |         *dst1++ = v * m0; | ||||||
|  |         len -= 4; | ||||||
|  |     } | ||||||
|  |     while (len > 0) { | ||||||
|  |         v = *src++; | ||||||
|  |         *dst0++ = v * m1; | ||||||
|  |         *dst1++ = v * m0; | ||||||
|  |         len--; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void mix_6_to_2_fltp_flt_c(float **samples, float **matrix, int len, | ||||||
|  |                                   int out_ch, int in_ch) | ||||||
|  | { | ||||||
|  |     float v0, v1; | ||||||
|  |     float *src0 = samples[0]; | ||||||
|  |     float *src1 = samples[1]; | ||||||
|  |     float *src2 = samples[2]; | ||||||
|  |     float *src3 = samples[3]; | ||||||
|  |     float *src4 = samples[4]; | ||||||
|  |     float *src5 = samples[5]; | ||||||
|  |     float *dst0 = src0; | ||||||
|  |     float *dst1 = src1; | ||||||
|  |     float *m0   = matrix[0]; | ||||||
|  |     float *m1   = matrix[1]; | ||||||
|  | 
 | ||||||
|  |     while (len > 0) { | ||||||
|  |         v0 = *src0++; | ||||||
|  |         v1 = *src1++; | ||||||
|  |         *dst0++ = v0      * m0[0] + | ||||||
|  |                   v1      * m0[1] + | ||||||
|  |                   *src2   * m0[2] + | ||||||
|  |                   *src3   * m0[3] + | ||||||
|  |                   *src4   * m0[4] + | ||||||
|  |                   *src5   * m0[5]; | ||||||
|  |         *dst1++ = v0      * m1[0] + | ||||||
|  |                   v1      * m1[1] + | ||||||
|  |                   *src2++ * m1[2] + | ||||||
|  |                   *src3++ * m1[3] + | ||||||
|  |                   *src4++ * m1[4] + | ||||||
|  |                   *src5++ * m1[5]; | ||||||
|  |         len--; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void mix_2_to_6_fltp_flt_c(float **samples, float **matrix, int len, | ||||||
|  |                                   int out_ch, int in_ch) | ||||||
|  | { | ||||||
|  |     float v0, v1; | ||||||
|  |     float *dst0 = samples[0]; | ||||||
|  |     float *dst1 = samples[1]; | ||||||
|  |     float *dst2 = samples[2]; | ||||||
|  |     float *dst3 = samples[3]; | ||||||
|  |     float *dst4 = samples[4]; | ||||||
|  |     float *dst5 = samples[5]; | ||||||
|  |     float *src0 = dst0; | ||||||
|  |     float *src1 = dst1; | ||||||
|  | 
 | ||||||
|  |     while (len > 0) { | ||||||
|  |         v0 = *src0++; | ||||||
|  |         v1 = *src1++; | ||||||
|  |         *dst0++ = v0 * matrix[0][0] + v1 * matrix[0][1]; | ||||||
|  |         *dst1++ = v0 * matrix[1][0] + v1 * matrix[1][1]; | ||||||
|  |         *dst2++ = v0 * matrix[2][0] + v1 * matrix[2][1]; | ||||||
|  |         *dst3++ = v0 * matrix[3][0] + v1 * matrix[3][1]; | ||||||
|  |         *dst4++ = v0 * matrix[4][0] + v1 * matrix[4][1]; | ||||||
|  |         *dst5++ = v0 * matrix[5][0] + v1 * matrix[5][1]; | ||||||
|  |         len--; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int mix_function_init(AudioMix *am) | ||||||
|  | { | ||||||
|  |     /* any-to-any C versions */ | ||||||
|  | 
 | ||||||
|  |     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||||||
|  |                           0, 0, 1, 1, "C", MIX_FUNC_NAME(FLTP, FLT)); | ||||||
|  | 
 | ||||||
|  |     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, | ||||||
|  |                           0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, FLT)); | ||||||
|  | 
 | ||||||
|  |     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q15, | ||||||
|  |                           0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q15)); | ||||||
|  | 
 | ||||||
|  |     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q6, | ||||||
|  |                           0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q6)); | ||||||
|  | 
 | ||||||
|  |     /* channel-specific C versions */ | ||||||
|  | 
 | ||||||
|  |     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||||||
|  |                           2, 1, 1, 1, "C", mix_2_to_1_fltp_flt_c); | ||||||
|  | 
 | ||||||
|  |     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||||||
|  |                           1, 2, 1, 1, "C", mix_1_to_2_fltp_flt_c); | ||||||
|  | 
 | ||||||
|  |     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||||||
|  |                           6, 2, 1, 1, "C", mix_6_to_2_fltp_flt_c); | ||||||
|  | 
 | ||||||
|  |     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||||||
|  |                           2, 6, 1, 1, "C", mix_2_to_6_fltp_flt_c); | ||||||
|  | 
 | ||||||
|  |     if (ARCH_X86) | ||||||
|  |         ff_audio_mix_init_x86(am); | ||||||
|  | 
 | ||||||
|  |     if (!am->mix) { | ||||||
|  |         av_log(am->avr, AV_LOG_ERROR, "audio_mix: NO FUNCTION FOUND: [fmt=%s] " | ||||||
|  |                "[c=%s] [%d to %d]\n", av_get_sample_fmt_name(am->fmt), | ||||||
|  |                coeff_type_names[am->coeff_type], am->in_channels, | ||||||
|  |                am->out_channels); | ||||||
|  |         return AVERROR_PATCHWELCOME; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ff_audio_mix_init(AVAudioResampleContext *avr) | ||||||
|  | { | ||||||
|  |     int ret; | ||||||
|  | 
 | ||||||
|  |     /* build matrix if the user did not already set one */ | ||||||
|  |     if (!avr->am->matrix) { | ||||||
|  |         int i, j; | ||||||
|  |         char in_layout_name[128]; | ||||||
|  |         char out_layout_name[128]; | ||||||
|  |         double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels * | ||||||
|  |                                         sizeof(*matrix_dbl)); | ||||||
|  |         if (!matrix_dbl) | ||||||
|  |             return AVERROR(ENOMEM); | ||||||
|  | 
 | ||||||
|  |         ret = avresample_build_matrix(avr->in_channel_layout, | ||||||
|  |                                       avr->out_channel_layout, | ||||||
|  |                                       avr->center_mix_level, | ||||||
|  |                                       avr->surround_mix_level, | ||||||
|  |                                       avr->lfe_mix_level, 1, matrix_dbl, | ||||||
|  |                                       avr->in_channels); | ||||||
|  |         if (ret < 0) { | ||||||
|  |             av_free(matrix_dbl); | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name), | ||||||
|  |                                      avr->in_channels, avr->in_channel_layout); | ||||||
|  |         av_get_channel_layout_string(out_layout_name, sizeof(out_layout_name), | ||||||
|  |                                      avr->out_channels, avr->out_channel_layout); | ||||||
|  |         av_log(avr, AV_LOG_DEBUG, "audio_mix: %s to %s\n", | ||||||
|  |                in_layout_name, out_layout_name); | ||||||
|  |         for (i = 0; i < avr->out_channels; i++) { | ||||||
|  |             for (j = 0; j < avr->in_channels; j++) { | ||||||
|  |                 av_log(avr, AV_LOG_DEBUG, "  %0.3f ", | ||||||
|  |                        matrix_dbl[i * avr->in_channels + j]); | ||||||
|  |             } | ||||||
|  |             av_log(avr, AV_LOG_DEBUG, "\n"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ret = avresample_set_matrix(avr, matrix_dbl, avr->in_channels); | ||||||
|  |         if (ret < 0) { | ||||||
|  |             av_free(matrix_dbl); | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |         av_free(matrix_dbl); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     avr->am->fmt          = avr->internal_sample_fmt; | ||||||
|  |     avr->am->coeff_type   = avr->mix_coeff_type; | ||||||
|  |     avr->am->in_layout    = avr->in_channel_layout; | ||||||
|  |     avr->am->out_layout   = avr->out_channel_layout; | ||||||
|  |     avr->am->in_channels  = avr->in_channels; | ||||||
|  |     avr->am->out_channels = avr->out_channels; | ||||||
|  | 
 | ||||||
|  |     ret = mix_function_init(avr->am); | ||||||
|  |     if (ret < 0) | ||||||
|  |         return ret; | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ff_audio_mix_close(AudioMix *am) | ||||||
|  | { | ||||||
|  |     if (!am) | ||||||
|  |         return; | ||||||
|  |     if (am->matrix) { | ||||||
|  |         av_free(am->matrix[0]); | ||||||
|  |         am->matrix = NULL; | ||||||
|  |     } | ||||||
|  |     memset(am->matrix_q6,  0, sizeof(am->matrix_q6 )); | ||||||
|  |     memset(am->matrix_q15, 0, sizeof(am->matrix_q15)); | ||||||
|  |     memset(am->matrix_flt, 0, sizeof(am->matrix_flt)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ff_audio_mix(AudioMix *am, AudioData *src) | ||||||
|  | { | ||||||
|  |     int use_generic = 1; | ||||||
|  |     int len = src->nb_samples; | ||||||
|  | 
 | ||||||
|  |     /* determine whether to use the optimized function based on pointer and
 | ||||||
|  |        samples alignment in both the input and output */ | ||||||
|  |     if (am->has_optimized_func) { | ||||||
|  |         int aligned_len = FFALIGN(len, am->samples_align); | ||||||
|  |         if (!(src->ptr_align % am->ptr_align) && | ||||||
|  |             src->samples_align >= aligned_len) { | ||||||
|  |             len = aligned_len; | ||||||
|  |             use_generic = 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     av_dlog(am->avr, "audio_mix: %d samples - %d to %d channels (%s)\n", | ||||||
|  |             src->nb_samples, am->in_channels, am->out_channels, | ||||||
|  |             use_generic ? am->func_descr_generic : am->func_descr); | ||||||
|  | 
 | ||||||
|  |     if (use_generic) | ||||||
|  |         am->mix_generic(src->data, am->matrix, len, am->out_channels, | ||||||
|  |                         am->in_channels); | ||||||
|  |     else | ||||||
|  |         am->mix(src->data, am->matrix, len, am->out_channels, am->in_channels); | ||||||
|  | 
 | ||||||
|  |     ff_audio_data_set_channels(src, am->out_channels); | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										108
									
								
								libavresample/audio_mix.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								libavresample/audio_mix.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,108 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef AVRESAMPLE_AUDIO_MIX_H | ||||||
|  | #define AVRESAMPLE_AUDIO_MIX_H | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | #include "libavutil/samplefmt.h" | ||||||
|  | #include "avresample.h" | ||||||
|  | #include "audio_data.h" | ||||||
|  | 
 | ||||||
|  | typedef void (mix_func)(uint8_t **src, void **matrix, int len, int out_ch, | ||||||
|  |                         int in_ch); | ||||||
|  | 
 | ||||||
|  | typedef struct AudioMix { | ||||||
|  |     AVAudioResampleContext *avr; | ||||||
|  |     enum AVSampleFormat fmt; | ||||||
|  |     enum AVMixCoeffType coeff_type; | ||||||
|  |     uint64_t in_layout; | ||||||
|  |     uint64_t out_layout; | ||||||
|  |     int in_channels; | ||||||
|  |     int out_channels; | ||||||
|  | 
 | ||||||
|  |     int ptr_align; | ||||||
|  |     int samples_align; | ||||||
|  |     int has_optimized_func; | ||||||
|  |     const char *func_descr; | ||||||
|  |     const char *func_descr_generic; | ||||||
|  |     mix_func *mix; | ||||||
|  |     mix_func *mix_generic; | ||||||
|  | 
 | ||||||
|  |     int16_t *matrix_q6[AVRESAMPLE_MAX_CHANNELS]; | ||||||
|  |     int32_t *matrix_q15[AVRESAMPLE_MAX_CHANNELS]; | ||||||
|  |     float   *matrix_flt[AVRESAMPLE_MAX_CHANNELS]; | ||||||
|  |     void   **matrix; | ||||||
|  | } AudioMix; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Set mixing function if the parameters match. | ||||||
|  |  * | ||||||
|  |  * This compares the parameters of the mixing function to the parameters in the | ||||||
|  |  * AudioMix context. If the parameters do not match, no changes are made to the | ||||||
|  |  * active functions. If the parameters do match and the alignment is not | ||||||
|  |  * constrained, the function is set as the generic mixing function. If the | ||||||
|  |  * parameters match and the alignment is constrained, the function is set as | ||||||
|  |  * the optimized mixing function. | ||||||
|  |  * | ||||||
|  |  * @param am             AudioMix context | ||||||
|  |  * @param fmt            input/output sample format | ||||||
|  |  * @param coeff_type     mixing coefficient type | ||||||
|  |  * @param in_channels    number of input channels, or 0 for any number of channels | ||||||
|  |  * @param out_channels   number of output channels, or 0 for any number of channels | ||||||
|  |  * @param ptr_align      buffer pointer alignment, in bytes | ||||||
|  |  * @param sample_align   buffer size alignment, in samples | ||||||
|  |  * @param descr          function type description (e.g. "C" or "SSE") | ||||||
|  |  * @param mix_func       mixing function pointer | ||||||
|  |  */ | ||||||
|  | void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt, | ||||||
|  |                            enum AVMixCoeffType coeff_type, int in_channels, | ||||||
|  |                            int out_channels, int ptr_align, int samples_align, | ||||||
|  |                            const char *descr, void *mix_func); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Initialize the AudioMix context in the AVAudioResampleContext. | ||||||
|  |  * | ||||||
|  |  * The parameters in the AVAudioResampleContext are used to initialize the | ||||||
|  |  * AudioMix context and set the mixing matrix. | ||||||
|  |  * | ||||||
|  |  * @param avr  AVAudioResampleContext | ||||||
|  |  * @return     0 on success, negative AVERROR code on failure | ||||||
|  |  */ | ||||||
|  | int ff_audio_mix_init(AVAudioResampleContext *avr); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Close an AudioMix context. | ||||||
|  |  * | ||||||
|  |  * This clears and frees the mixing matrix arrays. | ||||||
|  |  */ | ||||||
|  | void ff_audio_mix_close(AudioMix *am); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Apply channel mixing to audio data using the current mixing matrix. | ||||||
|  |  */ | ||||||
|  | int ff_audio_mix(AudioMix *am, AudioData *src); | ||||||
|  | 
 | ||||||
|  | /* arch-specific initialization functions */ | ||||||
|  | 
 | ||||||
|  | void ff_audio_mix_init_x86(AudioMix *am); | ||||||
|  | 
 | ||||||
|  | #endif /* AVRESAMPLE_AUDIO_MIX_H */ | ||||||
							
								
								
									
										346
									
								
								libavresample/audio_mix_matrix.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								libavresample/audio_mix_matrix.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,346 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at) | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 <stdint.h> | ||||||
|  | 
 | ||||||
|  | #include "libavutil/libm.h" | ||||||
|  | #include "libavutil/samplefmt.h" | ||||||
|  | #include "avresample.h" | ||||||
|  | #include "internal.h" | ||||||
|  | #include "audio_data.h" | ||||||
|  | #include "audio_mix.h" | ||||||
|  | 
 | ||||||
|  | /* channel positions */ | ||||||
|  | #define FRONT_LEFT              0 | ||||||
|  | #define FRONT_RIGHT             1 | ||||||
|  | #define FRONT_CENTER            2 | ||||||
|  | #define LOW_FREQUENCY           3 | ||||||
|  | #define BACK_LEFT               4 | ||||||
|  | #define BACK_RIGHT              5 | ||||||
|  | #define FRONT_LEFT_OF_CENTER    6 | ||||||
|  | #define FRONT_RIGHT_OF_CENTER   7 | ||||||
|  | #define BACK_CENTER             8 | ||||||
|  | #define SIDE_LEFT               9 | ||||||
|  | #define SIDE_RIGHT             10 | ||||||
|  | #define TOP_CENTER             11 | ||||||
|  | #define TOP_FRONT_LEFT         12 | ||||||
|  | #define TOP_FRONT_CENTER       13 | ||||||
|  | #define TOP_FRONT_RIGHT        14 | ||||||
|  | #define TOP_BACK_LEFT          15 | ||||||
|  | #define TOP_BACK_CENTER        16 | ||||||
|  | #define TOP_BACK_RIGHT         17 | ||||||
|  | #define STEREO_LEFT            29 | ||||||
|  | #define STEREO_RIGHT           30 | ||||||
|  | #define WIDE_LEFT              31 | ||||||
|  | #define WIDE_RIGHT             32 | ||||||
|  | #define SURROUND_DIRECT_LEFT   33 | ||||||
|  | #define SURROUND_DIRECT_RIGHT  34 | ||||||
|  | 
 | ||||||
|  | static av_always_inline int even(uint64_t layout) | ||||||
|  | { | ||||||
|  |     return (!layout || (layout & (layout - 1))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int sane_layout(uint64_t layout) | ||||||
|  | { | ||||||
|  |     /* check that there is at least 1 front speaker */ | ||||||
|  |     if (!(layout & AV_CH_LAYOUT_SURROUND)) | ||||||
|  |         return 0; | ||||||
|  | 
 | ||||||
|  |     /* check for left/right symmetry */ | ||||||
|  |     if (!even(layout & (AV_CH_FRONT_LEFT           | AV_CH_FRONT_RIGHT))           || | ||||||
|  |         !even(layout & (AV_CH_SIDE_LEFT            | AV_CH_SIDE_RIGHT))            || | ||||||
|  |         !even(layout & (AV_CH_BACK_LEFT            | AV_CH_BACK_RIGHT))            || | ||||||
|  |         !even(layout & (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER)) || | ||||||
|  |         !even(layout & (AV_CH_TOP_FRONT_LEFT       | AV_CH_TOP_FRONT_RIGHT))       || | ||||||
|  |         !even(layout & (AV_CH_TOP_BACK_LEFT        | AV_CH_TOP_BACK_RIGHT))        || | ||||||
|  |         !even(layout & (AV_CH_STEREO_LEFT          | AV_CH_STEREO_RIGHT))          || | ||||||
|  |         !even(layout & (AV_CH_WIDE_LEFT            | AV_CH_WIDE_RIGHT))            || | ||||||
|  |         !even(layout & (AV_CH_SURROUND_DIRECT_LEFT | AV_CH_SURROUND_DIRECT_RIGHT))) | ||||||
|  |         return 0; | ||||||
|  | 
 | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout, | ||||||
|  |                             double center_mix_level, double surround_mix_level, | ||||||
|  |                             double lfe_mix_level, int normalize, | ||||||
|  |                             double *matrix_out, int stride) | ||||||
|  | { | ||||||
|  |     int i, j, out_i, out_j; | ||||||
|  |     double matrix[64][64] = {{0}}; | ||||||
|  |     int64_t unaccounted = in_layout & ~out_layout; | ||||||
|  |     double maxcoef = 0; | ||||||
|  |     int in_channels, out_channels; | ||||||
|  | 
 | ||||||
|  |     in_channels  = av_get_channel_layout_nb_channels( in_layout); | ||||||
|  |     out_channels = av_get_channel_layout_nb_channels(out_layout); | ||||||
|  | 
 | ||||||
|  |     memset(matrix_out, 0, out_channels * stride * sizeof(*matrix_out)); | ||||||
|  | 
 | ||||||
|  |     /* check if layouts are supported */ | ||||||
|  |     if (!in_layout || in_channels > AVRESAMPLE_MAX_CHANNELS) | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  |     if (!out_layout || out_channels > AVRESAMPLE_MAX_CHANNELS) | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  | 
 | ||||||
|  |     /* check if layouts are unbalanced or abnormal */ | ||||||
|  |     if (!sane_layout(in_layout) || !sane_layout(out_layout)) | ||||||
|  |         return AVERROR_PATCHWELCOME; | ||||||
|  | 
 | ||||||
|  |     /* route matching input/output channels */ | ||||||
|  |     for (i = 0; i < 64; i++) { | ||||||
|  |         if (in_layout & out_layout & (1ULL << i)) | ||||||
|  |             matrix[i][i] = 1.0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* mix front center to front left/right */ | ||||||
|  |     if (unaccounted & AV_CH_FRONT_CENTER) { | ||||||
|  |         if ((out_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO) { | ||||||
|  |             matrix[FRONT_LEFT ][FRONT_CENTER] += M_SQRT1_2; | ||||||
|  |             matrix[FRONT_RIGHT][FRONT_CENTER] += M_SQRT1_2; | ||||||
|  |         } else | ||||||
|  |             return AVERROR_PATCHWELCOME; | ||||||
|  |     } | ||||||
|  |     /* mix front left/right to center */ | ||||||
|  |     if (unaccounted & AV_CH_LAYOUT_STEREO) { | ||||||
|  |         if (out_layout & AV_CH_FRONT_CENTER) { | ||||||
|  |             matrix[FRONT_CENTER][FRONT_LEFT ] += M_SQRT1_2; | ||||||
|  |             matrix[FRONT_CENTER][FRONT_RIGHT] += M_SQRT1_2; | ||||||
|  |             /* mix left/right/center to center */ | ||||||
|  |             if (in_layout & AV_CH_FRONT_CENTER) | ||||||
|  |                 matrix[FRONT_CENTER][FRONT_CENTER] = center_mix_level * M_SQRT2; | ||||||
|  |         } else | ||||||
|  |             return AVERROR_PATCHWELCOME; | ||||||
|  |     } | ||||||
|  |     /* mix back center to back, side, or front */ | ||||||
|  |     if (unaccounted & AV_CH_BACK_CENTER) { | ||||||
|  |         if (out_layout & AV_CH_BACK_LEFT) { | ||||||
|  |             matrix[BACK_LEFT ][BACK_CENTER] += M_SQRT1_2; | ||||||
|  |             matrix[BACK_RIGHT][BACK_CENTER] += M_SQRT1_2; | ||||||
|  |         } else if (out_layout & AV_CH_SIDE_LEFT) { | ||||||
|  |             matrix[SIDE_LEFT ][BACK_CENTER] += M_SQRT1_2; | ||||||
|  |             matrix[SIDE_RIGHT][BACK_CENTER] += M_SQRT1_2; | ||||||
|  |         } else if (out_layout & AV_CH_FRONT_LEFT) { | ||||||
|  |             matrix[FRONT_LEFT ][BACK_CENTER] += surround_mix_level * M_SQRT1_2; | ||||||
|  |             matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2; | ||||||
|  |         } else if (out_layout & AV_CH_FRONT_CENTER) { | ||||||
|  |             matrix[FRONT_CENTER][BACK_CENTER] += surround_mix_level * M_SQRT1_2; | ||||||
|  |         } else | ||||||
|  |             return AVERROR_PATCHWELCOME; | ||||||
|  |     } | ||||||
|  |     /* mix back left/right to back center, side, or front */ | ||||||
|  |     if (unaccounted & AV_CH_BACK_LEFT) { | ||||||
|  |         if (out_layout & AV_CH_BACK_CENTER) { | ||||||
|  |             matrix[BACK_CENTER][BACK_LEFT ] += M_SQRT1_2; | ||||||
|  |             matrix[BACK_CENTER][BACK_RIGHT] += M_SQRT1_2; | ||||||
|  |         } else if (out_layout & AV_CH_SIDE_LEFT) { | ||||||
|  |             /* if side channels do not exist in the input, just copy back
 | ||||||
|  |                channels to side channels, otherwise mix back into side */ | ||||||
|  |             if (in_layout & AV_CH_SIDE_LEFT) { | ||||||
|  |                 matrix[SIDE_LEFT ][BACK_LEFT ] += M_SQRT1_2; | ||||||
|  |                 matrix[SIDE_RIGHT][BACK_RIGHT] += M_SQRT1_2; | ||||||
|  |             } else { | ||||||
|  |                 matrix[SIDE_LEFT ][BACK_LEFT ] += 1.0; | ||||||
|  |                 matrix[SIDE_RIGHT][BACK_RIGHT] += 1.0; | ||||||
|  |             } | ||||||
|  |         } else if (out_layout & AV_CH_FRONT_LEFT) { | ||||||
|  |             matrix[FRONT_LEFT ][BACK_LEFT ] += surround_mix_level; | ||||||
|  |             matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level; | ||||||
|  |         } else if (out_layout & AV_CH_FRONT_CENTER) { | ||||||
|  |             matrix[FRONT_CENTER][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; | ||||||
|  |             matrix[FRONT_CENTER][BACK_RIGHT] += surround_mix_level * M_SQRT1_2; | ||||||
|  |         } else | ||||||
|  |             return AVERROR_PATCHWELCOME; | ||||||
|  |     } | ||||||
|  |     /* mix side left/right into back or front */ | ||||||
|  |     if (unaccounted & AV_CH_SIDE_LEFT) { | ||||||
|  |         if (out_layout & AV_CH_BACK_LEFT) { | ||||||
|  |             /* if back channels do not exist in the input, just copy side
 | ||||||
|  |                channels to back channels, otherwise mix side into back */ | ||||||
|  |             if (in_layout & AV_CH_BACK_LEFT) { | ||||||
|  |                 matrix[BACK_LEFT ][SIDE_LEFT ] += M_SQRT1_2; | ||||||
|  |                 matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2; | ||||||
|  |             } else { | ||||||
|  |                 matrix[BACK_LEFT ][SIDE_LEFT ] += 1.0; | ||||||
|  |                 matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0; | ||||||
|  |             } | ||||||
|  |         } else if (out_layout & AV_CH_BACK_CENTER) { | ||||||
|  |             matrix[BACK_CENTER][SIDE_LEFT ] += M_SQRT1_2; | ||||||
|  |             matrix[BACK_CENTER][SIDE_RIGHT] += M_SQRT1_2; | ||||||
|  |         } else if (out_layout & AV_CH_FRONT_LEFT) { | ||||||
|  |             matrix[FRONT_LEFT ][SIDE_LEFT ] += surround_mix_level; | ||||||
|  |             matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level; | ||||||
|  |         } else if (out_layout & AV_CH_FRONT_CENTER) { | ||||||
|  |             matrix[FRONT_CENTER][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; | ||||||
|  |             matrix[FRONT_CENTER][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2; | ||||||
|  |         } else | ||||||
|  |             return AVERROR_PATCHWELCOME; | ||||||
|  |     } | ||||||
|  |     /* mix left-of-center/right-of-center into front left/right or center */ | ||||||
|  |     if (unaccounted & AV_CH_FRONT_LEFT_OF_CENTER) { | ||||||
|  |         if (out_layout & AV_CH_FRONT_LEFT) { | ||||||
|  |             matrix[FRONT_LEFT ][FRONT_LEFT_OF_CENTER ] += 1.0; | ||||||
|  |             matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER] += 1.0; | ||||||
|  |         } else if (out_layout & AV_CH_FRONT_CENTER) { | ||||||
|  |             matrix[FRONT_CENTER][FRONT_LEFT_OF_CENTER ] += M_SQRT1_2; | ||||||
|  |             matrix[FRONT_CENTER][FRONT_RIGHT_OF_CENTER] += M_SQRT1_2; | ||||||
|  |         } else | ||||||
|  |             return AVERROR_PATCHWELCOME; | ||||||
|  |     } | ||||||
|  |     /* mix LFE into front left/right or center */ | ||||||
|  |     if (unaccounted & AV_CH_LOW_FREQUENCY) { | ||||||
|  |         if (out_layout & AV_CH_FRONT_CENTER) { | ||||||
|  |             matrix[FRONT_CENTER][LOW_FREQUENCY] += lfe_mix_level; | ||||||
|  |         } else if (out_layout & AV_CH_FRONT_LEFT) { | ||||||
|  |             matrix[FRONT_LEFT ][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2; | ||||||
|  |             matrix[FRONT_RIGHT][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2; | ||||||
|  |         } else | ||||||
|  |             return AVERROR_PATCHWELCOME; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* transfer internal matrix to output matrix and calculate maximum
 | ||||||
|  |        per-channel coefficient sum */ | ||||||
|  |     for (out_i = i = 0; out_i < out_channels && i < 64; i++) { | ||||||
|  |         double sum = 0; | ||||||
|  |         for (out_j = j = 0; out_j < in_channels && j < 64; j++) { | ||||||
|  |             matrix_out[out_i * stride + out_j] = matrix[i][j]; | ||||||
|  |             sum += fabs(matrix[i][j]); | ||||||
|  |             if (in_layout & (1ULL << j)) | ||||||
|  |                 out_j++; | ||||||
|  |         } | ||||||
|  |         maxcoef = FFMAX(maxcoef, sum); | ||||||
|  |         if (out_layout & (1ULL << i)) | ||||||
|  |             out_i++; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* normalize */ | ||||||
|  |     if (normalize && maxcoef > 1.0) { | ||||||
|  |         for (i = 0; i < out_channels; i++) | ||||||
|  |             for (j = 0; j < in_channels; j++) | ||||||
|  |                 matrix_out[i * stride + j] /= maxcoef; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix, | ||||||
|  |                           int stride) | ||||||
|  | { | ||||||
|  |     int in_channels, out_channels, i, o; | ||||||
|  | 
 | ||||||
|  |     in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout); | ||||||
|  |     out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); | ||||||
|  | 
 | ||||||
|  |     if ( in_channels < 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS || | ||||||
|  |         out_channels < 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) { | ||||||
|  |         av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n"); | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     switch (avr->mix_coeff_type) { | ||||||
|  |     case AV_MIX_COEFF_TYPE_Q6: | ||||||
|  |         if (!avr->am->matrix_q6[0]) { | ||||||
|  |             av_log(avr, AV_LOG_ERROR, "matrix is not set\n"); | ||||||
|  |             return AVERROR(EINVAL); | ||||||
|  |         } | ||||||
|  |         for (o = 0; o < out_channels; o++) | ||||||
|  |             for (i = 0; i < in_channels; i++) | ||||||
|  |                 matrix[o * stride + i] = avr->am->matrix_q6[o][i] / 64.0; | ||||||
|  |         break; | ||||||
|  |     case AV_MIX_COEFF_TYPE_Q15: | ||||||
|  |         if (!avr->am->matrix_q15[0]) { | ||||||
|  |             av_log(avr, AV_LOG_ERROR, "matrix is not set\n"); | ||||||
|  |             return AVERROR(EINVAL); | ||||||
|  |         } | ||||||
|  |         for (o = 0; o < out_channels; o++) | ||||||
|  |             for (i = 0; i < in_channels; i++) | ||||||
|  |                 matrix[o * stride + i] = avr->am->matrix_q15[o][i] / 32768.0; | ||||||
|  |         break; | ||||||
|  |     case AV_MIX_COEFF_TYPE_FLT: | ||||||
|  |         if (!avr->am->matrix_flt[0]) { | ||||||
|  |             av_log(avr, AV_LOG_ERROR, "matrix is not set\n"); | ||||||
|  |             return AVERROR(EINVAL); | ||||||
|  |         } | ||||||
|  |         for (o = 0; o < out_channels; o++) | ||||||
|  |             for (i = 0; i < in_channels; i++) | ||||||
|  |                 matrix[o * stride + i] = avr->am->matrix_flt[o][i]; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         av_log(avr, AV_LOG_ERROR, "Invalid mix coeff type\n"); | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, | ||||||
|  |                           int stride) | ||||||
|  | { | ||||||
|  |     int in_channels, out_channels, i, o; | ||||||
|  | 
 | ||||||
|  |     in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout); | ||||||
|  |     out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); | ||||||
|  | 
 | ||||||
|  |     if ( in_channels < 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS || | ||||||
|  |         out_channels < 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) { | ||||||
|  |         av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n"); | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (avr->am->matrix) | ||||||
|  |         av_freep(avr->am->matrix); | ||||||
|  | 
 | ||||||
|  | #define CONVERT_MATRIX(type, expr)                                          \ | ||||||
|  |     avr->am->matrix_## type[0] = av_mallocz(out_channels * in_channels *    \ | ||||||
|  |                                             sizeof(*avr->am->matrix_## type[0])); \ | ||||||
|  |     if (!avr->am->matrix_## type[0])                                        \ | ||||||
|  |         return AVERROR(ENOMEM);                                             \ | ||||||
|  |     for (o = 0; o < out_channels; o++) {                                    \ | ||||||
|  |         if (o > 0)                                                          \ | ||||||
|  |             avr->am->matrix_## type[o] = avr->am->matrix_## type[o - 1] +   \ | ||||||
|  |                                          in_channels;                       \ | ||||||
|  |         for (i = 0; i < in_channels; i++) {                                 \ | ||||||
|  |             double v = matrix[o * stride + i];                              \ | ||||||
|  |             avr->am->matrix_## type[o][i] = expr;                           \ | ||||||
|  |         }                                                                   \ | ||||||
|  |     }                                                                       \ | ||||||
|  |     avr->am->matrix = (void **)avr->am->matrix_## type; | ||||||
|  | 
 | ||||||
|  |     switch (avr->mix_coeff_type) { | ||||||
|  |     case AV_MIX_COEFF_TYPE_Q6: | ||||||
|  |         CONVERT_MATRIX(q6, av_clip_int16(lrint(64.0 * v))) | ||||||
|  |         break; | ||||||
|  |     case AV_MIX_COEFF_TYPE_Q15: | ||||||
|  |         CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v))) | ||||||
|  |         break; | ||||||
|  |     case AV_MIX_COEFF_TYPE_FLT: | ||||||
|  |         CONVERT_MATRIX(flt, v) | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         av_log(avr, AV_LOG_ERROR, "Invalid mix coeff type\n"); | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* TODO: detect situations where we can just swap around pointers
 | ||||||
|  |              instead of doing matrix multiplications with 0.0 and 1.0 */ | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										340
									
								
								libavresample/avresample-test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										340
									
								
								libavresample/avresample-test.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,340 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2002 Fabrice Bellard | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 <stdint.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | 
 | ||||||
|  | #include "libavutil/avstring.h" | ||||||
|  | #include "libavutil/lfg.h" | ||||||
|  | #include "libavutil/libm.h" | ||||||
|  | #include "libavutil/log.h" | ||||||
|  | #include "libavutil/mem.h" | ||||||
|  | #include "libavutil/opt.h" | ||||||
|  | #include "libavutil/samplefmt.h" | ||||||
|  | #include "avresample.h" | ||||||
|  | 
 | ||||||
|  | static double dbl_rand(AVLFG *lfg) | ||||||
|  | { | ||||||
|  |     return 2.0 * (av_lfg_get(lfg) / (double)UINT_MAX) - 1.0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define PUT_FUNC(name, fmt, type, expr)                                     \ | ||||||
|  | static void put_sample_ ## name(void **data, enum AVSampleFormat sample_fmt,\ | ||||||
|  |                                 int channels, int sample, int ch,           \ | ||||||
|  |                                 double v_dbl)                               \ | ||||||
|  | {                                                                           \ | ||||||
|  |     type v = expr;                                                          \ | ||||||
|  |     type **out = (type **)data;                                             \ | ||||||
|  |     if (av_sample_fmt_is_planar(sample_fmt))                                \ | ||||||
|  |         out[ch][sample] = v;                                                \ | ||||||
|  |     else                                                                    \ | ||||||
|  |         out[0][sample * channels + ch] = v;                                 \ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PUT_FUNC(u8,  AV_SAMPLE_FMT_U8,  uint8_t, av_clip_uint8 ( lrint(v_dbl * (1  <<  7)) + 128)) | ||||||
|  | PUT_FUNC(s16, AV_SAMPLE_FMT_S16, int16_t, av_clip_int16 ( lrint(v_dbl * (1  << 15)))) | ||||||
|  | PUT_FUNC(s32, AV_SAMPLE_FMT_S32, int32_t, av_clipl_int32(llrint(v_dbl * (1U << 31)))) | ||||||
|  | PUT_FUNC(flt, AV_SAMPLE_FMT_FLT, float,   v_dbl) | ||||||
|  | PUT_FUNC(dbl, AV_SAMPLE_FMT_DBL, double,  v_dbl) | ||||||
|  | 
 | ||||||
|  | static void put_sample(void **data, enum AVSampleFormat sample_fmt, | ||||||
|  |                        int channels, int sample, int ch, double v_dbl) | ||||||
|  | { | ||||||
|  |     switch (av_get_packed_sample_fmt(sample_fmt)) { | ||||||
|  |     case AV_SAMPLE_FMT_U8: | ||||||
|  |         put_sample_u8(data, sample_fmt, channels, sample, ch, v_dbl); | ||||||
|  |         break; | ||||||
|  |     case AV_SAMPLE_FMT_S16: | ||||||
|  |         put_sample_s16(data, sample_fmt, channels, sample, ch, v_dbl); | ||||||
|  |         break; | ||||||
|  |     case AV_SAMPLE_FMT_S32: | ||||||
|  |         put_sample_s32(data, sample_fmt, channels, sample, ch, v_dbl); | ||||||
|  |         break; | ||||||
|  |     case AV_SAMPLE_FMT_FLT: | ||||||
|  |         put_sample_flt(data, sample_fmt, channels, sample, ch, v_dbl); | ||||||
|  |         break; | ||||||
|  |     case AV_SAMPLE_FMT_DBL: | ||||||
|  |         put_sample_dbl(data, sample_fmt, channels, sample, ch, v_dbl); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void audiogen(AVLFG *rnd, void **data, enum AVSampleFormat sample_fmt, | ||||||
|  |                      int channels, int sample_rate, int nb_samples) | ||||||
|  | { | ||||||
|  |     int i, ch, k; | ||||||
|  |     double v, f, a, ampa; | ||||||
|  |     double tabf1[AVRESAMPLE_MAX_CHANNELS]; | ||||||
|  |     double tabf2[AVRESAMPLE_MAX_CHANNELS]; | ||||||
|  |     double taba[AVRESAMPLE_MAX_CHANNELS]; | ||||||
|  | 
 | ||||||
|  | #define PUT_SAMPLE put_sample(data, sample_fmt, channels, k, ch, v); | ||||||
|  | 
 | ||||||
|  |     k = 0; | ||||||
|  | 
 | ||||||
|  |     /* 1 second of single freq sinus at 1000 Hz */ | ||||||
|  |     a = 0; | ||||||
|  |     for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { | ||||||
|  |         v = sin(a) * 0.30; | ||||||
|  |         for (ch = 0; ch < channels; ch++) | ||||||
|  |             PUT_SAMPLE | ||||||
|  |         a += M_PI * 1000.0 * 2.0 / sample_rate; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* 1 second of varing frequency between 100 and 10000 Hz */ | ||||||
|  |     a = 0; | ||||||
|  |     for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { | ||||||
|  |         v = sin(a) * 0.30; | ||||||
|  |         for (ch = 0; ch < channels; ch++) | ||||||
|  |             PUT_SAMPLE | ||||||
|  |         f  = 100.0 + (((10000.0 - 100.0) * i) / sample_rate); | ||||||
|  |         a += M_PI * f * 2.0 / sample_rate; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* 0.5 second of low amplitude white noise */ | ||||||
|  |     for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) { | ||||||
|  |         v = dbl_rand(rnd) * 0.30; | ||||||
|  |         for (ch = 0; ch < channels; ch++) | ||||||
|  |             PUT_SAMPLE | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* 0.5 second of high amplitude white noise */ | ||||||
|  |     for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) { | ||||||
|  |         v = dbl_rand(rnd); | ||||||
|  |         for (ch = 0; ch < channels; ch++) | ||||||
|  |             PUT_SAMPLE | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* 1 second of unrelated ramps for each channel */ | ||||||
|  |     for (ch = 0; ch < channels; ch++) { | ||||||
|  |         taba[ch]  = 0; | ||||||
|  |         tabf1[ch] = 100 + av_lfg_get(rnd) % 5000; | ||||||
|  |         tabf2[ch] = 100 + av_lfg_get(rnd) % 5000; | ||||||
|  |     } | ||||||
|  |     for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { | ||||||
|  |         for (ch = 0; ch < channels; ch++) { | ||||||
|  |             v = sin(taba[ch]) * 0.30; | ||||||
|  |             PUT_SAMPLE | ||||||
|  |             f = tabf1[ch] + (((tabf2[ch] - tabf1[ch]) * i) / sample_rate); | ||||||
|  |             taba[ch] += M_PI * f * 2.0 / sample_rate; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* 2 seconds of 500 Hz with varying volume */ | ||||||
|  |     a    = 0; | ||||||
|  |     ampa = 0; | ||||||
|  |     for (i = 0; i < 2 * sample_rate && k < nb_samples; i++, k++) { | ||||||
|  |         for (ch = 0; ch < channels; ch++) { | ||||||
|  |             double amp = (1.0 + sin(ampa)) * 0.15; | ||||||
|  |             if (ch & 1) | ||||||
|  |                 amp = 0.30 - amp; | ||||||
|  |             v = sin(a) * amp; | ||||||
|  |             PUT_SAMPLE | ||||||
|  |             a    += M_PI * 500.0 * 2.0 / sample_rate; | ||||||
|  |             ampa += M_PI *  2.0 / sample_rate; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* formats, rates, and layouts are ordered for priority in testing.
 | ||||||
|  |    e.g. 'avresample-test 4 2 2' will test all input/output combinations of | ||||||
|  |    S16/FLTP/S16P/FLT, 48000/44100, and stereo/mono */ | ||||||
|  | 
 | ||||||
|  | static const enum AVSampleFormat formats[] = { | ||||||
|  |     AV_SAMPLE_FMT_S16, | ||||||
|  |     AV_SAMPLE_FMT_FLTP, | ||||||
|  |     AV_SAMPLE_FMT_S16P, | ||||||
|  |     AV_SAMPLE_FMT_FLT, | ||||||
|  |     AV_SAMPLE_FMT_S32P, | ||||||
|  |     AV_SAMPLE_FMT_S32, | ||||||
|  |     AV_SAMPLE_FMT_U8P, | ||||||
|  |     AV_SAMPLE_FMT_U8, | ||||||
|  |     AV_SAMPLE_FMT_DBLP, | ||||||
|  |     AV_SAMPLE_FMT_DBL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const int rates[] = { | ||||||
|  |     48000, | ||||||
|  |     44100, | ||||||
|  |     16000 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const uint64_t layouts[] = { | ||||||
|  |     AV_CH_LAYOUT_STEREO, | ||||||
|  |     AV_CH_LAYOUT_MONO, | ||||||
|  |     AV_CH_LAYOUT_5POINT1, | ||||||
|  |     AV_CH_LAYOUT_7POINT1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | int main(int argc, char **argv) | ||||||
|  | { | ||||||
|  |     AVAudioResampleContext *s; | ||||||
|  |     AVLFG rnd; | ||||||
|  |     int ret = 0; | ||||||
|  |     uint8_t *in_buf = NULL; | ||||||
|  |     uint8_t *out_buf = NULL; | ||||||
|  |     unsigned int in_buf_size; | ||||||
|  |     unsigned int out_buf_size; | ||||||
|  |     uint8_t  *in_data[AVRESAMPLE_MAX_CHANNELS] = { 0 }; | ||||||
|  |     uint8_t *out_data[AVRESAMPLE_MAX_CHANNELS] = { 0 }; | ||||||
|  |     int in_linesize; | ||||||
|  |     int out_linesize; | ||||||
|  |     uint64_t in_ch_layout; | ||||||
|  |     int in_channels; | ||||||
|  |     enum AVSampleFormat in_fmt; | ||||||
|  |     int in_rate; | ||||||
|  |     uint64_t out_ch_layout; | ||||||
|  |     int out_channels; | ||||||
|  |     enum AVSampleFormat out_fmt; | ||||||
|  |     int out_rate; | ||||||
|  |     int num_formats, num_rates, num_layouts; | ||||||
|  |     int i, j, k, l, m, n; | ||||||
|  | 
 | ||||||
|  |     num_formats = 2; | ||||||
|  |     num_rates   = 2; | ||||||
|  |     num_layouts = 2; | ||||||
|  |     if (argc > 1) { | ||||||
|  |         if (!av_strncasecmp(argv[1], "-h", 3)) { | ||||||
|  |             av_log(NULL, AV_LOG_INFO, "Usage: avresample-test [<num formats> " | ||||||
|  |                    "[<num sample rates> [<num channel layouts>]]]\n" | ||||||
|  |                    "Default is 2 2 2\n"); | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |         num_formats = strtol(argv[1], NULL, 0); | ||||||
|  |         num_formats = av_clip(num_formats, 1, FF_ARRAY_ELEMS(formats)); | ||||||
|  |     } | ||||||
|  |     if (argc > 2) { | ||||||
|  |         num_rates = strtol(argv[2], NULL, 0); | ||||||
|  |         num_rates = av_clip(num_rates, 1, FF_ARRAY_ELEMS(rates)); | ||||||
|  |     } | ||||||
|  |     if (argc > 3) { | ||||||
|  |         num_layouts = strtol(argv[3], NULL, 0); | ||||||
|  |         num_layouts = av_clip(num_layouts, 1, FF_ARRAY_ELEMS(layouts)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     av_log_set_level(AV_LOG_DEBUG); | ||||||
|  | 
 | ||||||
|  |     av_lfg_init(&rnd, 0xC0FFEE); | ||||||
|  | 
 | ||||||
|  |     in_buf_size = av_samples_get_buffer_size(&in_linesize, 8, 48000 * 6, | ||||||
|  |                                              AV_SAMPLE_FMT_DBLP, 0); | ||||||
|  |     out_buf_size = in_buf_size; | ||||||
|  | 
 | ||||||
|  |     in_buf = av_malloc(in_buf_size); | ||||||
|  |     if (!in_buf) | ||||||
|  |         goto end; | ||||||
|  |     out_buf = av_malloc(out_buf_size); | ||||||
|  |     if (!out_buf) | ||||||
|  |         goto end; | ||||||
|  | 
 | ||||||
|  |     s = avresample_alloc_context(); | ||||||
|  |     if (!s) { | ||||||
|  |         av_log(NULL, AV_LOG_ERROR, "Error allocating AVAudioResampleContext\n"); | ||||||
|  |         ret = 1; | ||||||
|  |         goto end; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (i = 0; i < num_formats; i++) { | ||||||
|  |         in_fmt = formats[i]; | ||||||
|  |         for (k = 0; k < num_layouts; k++) { | ||||||
|  |             in_ch_layout = layouts[k]; | ||||||
|  |             in_channels  = av_get_channel_layout_nb_channels(in_ch_layout); | ||||||
|  |             for (m = 0; m < num_rates; m++) { | ||||||
|  |                 in_rate = rates[m]; | ||||||
|  | 
 | ||||||
|  |                 ret = av_samples_fill_arrays(in_data, &in_linesize, in_buf, | ||||||
|  |                                              in_channels, in_rate * 6, | ||||||
|  |                                              in_fmt, 0); | ||||||
|  |                 if (ret < 0) { | ||||||
|  |                     av_log(s, AV_LOG_ERROR, "failed in_data fill arrays\n"); | ||||||
|  |                     goto end; | ||||||
|  |                 } | ||||||
|  |                 audiogen(&rnd, (void **)in_data, in_fmt, in_channels, in_rate, in_rate * 6); | ||||||
|  | 
 | ||||||
|  |                 for (j = 0; j < num_formats; j++) { | ||||||
|  |                     out_fmt = formats[j]; | ||||||
|  |                     for (l = 0; l < num_layouts; l++) { | ||||||
|  |                         out_ch_layout = layouts[l]; | ||||||
|  |                         out_channels  = av_get_channel_layout_nb_channels(out_ch_layout); | ||||||
|  |                         for (n = 0; n < num_rates; n++) { | ||||||
|  |                             out_rate = rates[n]; | ||||||
|  | 
 | ||||||
|  |                             av_log(NULL, AV_LOG_INFO, "%s to %s, %d to %d channels, %d Hz to %d Hz\n", | ||||||
|  |                                    av_get_sample_fmt_name(in_fmt), av_get_sample_fmt_name(out_fmt), | ||||||
|  |                                    in_channels, out_channels, in_rate, out_rate); | ||||||
|  | 
 | ||||||
|  |                             ret = av_samples_fill_arrays(out_data, &out_linesize, | ||||||
|  |                                                          out_buf, out_channels, | ||||||
|  |                                                          out_rate * 6, out_fmt, 0); | ||||||
|  |                             if (ret < 0) { | ||||||
|  |                                 av_log(s, AV_LOG_ERROR, "failed out_data fill arrays\n"); | ||||||
|  |                                 goto end; | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             av_opt_set_int(s, "in_channel_layout",  in_ch_layout,  0); | ||||||
|  |                             av_opt_set_int(s, "in_sample_fmt",      in_fmt,        0); | ||||||
|  |                             av_opt_set_int(s, "in_sample_rate",     in_rate,       0); | ||||||
|  |                             av_opt_set_int(s, "out_channel_layout", out_ch_layout, 0); | ||||||
|  |                             av_opt_set_int(s, "out_sample_fmt",     out_fmt,       0); | ||||||
|  |                             av_opt_set_int(s, "out_sample_rate",    out_rate,      0); | ||||||
|  | 
 | ||||||
|  |                             av_opt_set_int(s, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); | ||||||
|  | 
 | ||||||
|  |                             ret = avresample_open(s); | ||||||
|  |                             if (ret < 0) { | ||||||
|  |                                 av_log(s, AV_LOG_ERROR, "Error opening context\n"); | ||||||
|  |                                 goto end; | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             ret = avresample_convert(s, (void **)out_data, out_linesize, out_rate * 6, | ||||||
|  |                                                         (void **) in_data,  in_linesize,  in_rate * 6); | ||||||
|  |                             if (ret < 0) { | ||||||
|  |                                 char errbuf[256]; | ||||||
|  |                                 av_strerror(ret, errbuf, sizeof(errbuf)); | ||||||
|  |                                 av_log(NULL, AV_LOG_ERROR, "%s\n", errbuf); | ||||||
|  |                                 goto end; | ||||||
|  |                             } | ||||||
|  |                             av_log(NULL, AV_LOG_INFO, "Converted %d samples to %d samples\n", | ||||||
|  |                                    in_rate * 6, ret); | ||||||
|  |                             if (avresample_get_delay(s) > 0) | ||||||
|  |                                 av_log(NULL, AV_LOG_INFO, "%d delay samples not converted\n", | ||||||
|  |                                        avresample_get_delay(s)); | ||||||
|  |                             if (avresample_available(s) > 0) | ||||||
|  |                                 av_log(NULL, AV_LOG_INFO, "%d samples available for output\n", | ||||||
|  |                                        avresample_available(s)); | ||||||
|  |                             av_log(NULL, AV_LOG_INFO, "\n"); | ||||||
|  | 
 | ||||||
|  |                             avresample_close(s); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ret = 0; | ||||||
|  | 
 | ||||||
|  | end: | ||||||
|  |     av_freep(&in_buf); | ||||||
|  |     av_freep(&out_buf); | ||||||
|  |     avresample_free(&s); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
							
								
								
									
										283
									
								
								libavresample/avresample.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								libavresample/avresample.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,283 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef AVRESAMPLE_AVRESAMPLE_H | ||||||
|  | #define AVRESAMPLE_AVRESAMPLE_H | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @file | ||||||
|  |  * external API header | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include "libavutil/audioconvert.h" | ||||||
|  | #include "libavutil/avutil.h" | ||||||
|  | #include "libavutil/dict.h" | ||||||
|  | #include "libavutil/log.h" | ||||||
|  | 
 | ||||||
|  | #include "libavresample/version.h" | ||||||
|  | 
 | ||||||
|  | #define AVRESAMPLE_MAX_CHANNELS 32 | ||||||
|  | 
 | ||||||
|  | typedef struct AVAudioResampleContext AVAudioResampleContext; | ||||||
|  | 
 | ||||||
|  | /** Mixing Coefficient Types */ | ||||||
|  | enum AVMixCoeffType { | ||||||
|  |     AV_MIX_COEFF_TYPE_Q6,   /** 16-bit 10.6 fixed-point                     */ | ||||||
|  |     AV_MIX_COEFF_TYPE_Q15,  /** 32-bit 17.15 fixed-point                    */ | ||||||
|  |     AV_MIX_COEFF_TYPE_FLT,  /** floating-point                              */ | ||||||
|  |     AV_MIX_COEFF_TYPE_NB,   /** Number of coeff types. Not part of ABI      */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Return the LIBAVRESAMPLE_VERSION_INT constant. | ||||||
|  |  */ | ||||||
|  | unsigned avresample_version(void); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Return the libavresample build-time configuration. | ||||||
|  |  * @return  configure string | ||||||
|  |  */ | ||||||
|  | const char *avresample_configuration(void); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Return the libavresample license. | ||||||
|  |  */ | ||||||
|  | const char *avresample_license(void); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Get the AVClass for AVAudioResampleContext. | ||||||
|  |  * | ||||||
|  |  * Can be used in combination with AV_OPT_SEARCH_FAKE_OBJ for examining options | ||||||
|  |  * without allocating a context. | ||||||
|  |  * | ||||||
|  |  * @see av_opt_find(). | ||||||
|  |  * | ||||||
|  |  * @return AVClass for AVAudioResampleContext | ||||||
|  |  */ | ||||||
|  | const AVClass *avresample_get_class(void); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Allocate AVAudioResampleContext and set options. | ||||||
|  |  * | ||||||
|  |  * @return  allocated audio resample context, or NULL on failure | ||||||
|  |  */ | ||||||
|  | AVAudioResampleContext *avresample_alloc_context(void); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Initialize AVAudioResampleContext. | ||||||
|  |  * | ||||||
|  |  * @param avr  audio resample context | ||||||
|  |  * @return     0 on success, negative AVERROR code on failure | ||||||
|  |  */ | ||||||
|  | int avresample_open(AVAudioResampleContext *avr); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Close AVAudioResampleContext. | ||||||
|  |  * | ||||||
|  |  * This closes the context, but it does not change the parameters. The context | ||||||
|  |  * can be reopened with avresample_open(). It does, however, clear the output | ||||||
|  |  * FIFO and any remaining leftover samples in the resampling delay buffer. If | ||||||
|  |  * there was a custom matrix being used, that is also cleared. | ||||||
|  |  * | ||||||
|  |  * @see avresample_convert() | ||||||
|  |  * @see avresample_set_matrix() | ||||||
|  |  * | ||||||
|  |  * @param avr  audio resample context | ||||||
|  |  */ | ||||||
|  | void avresample_close(AVAudioResampleContext *avr); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Free AVAudioResampleContext and associated AVOption values. | ||||||
|  |  * | ||||||
|  |  * This also calls avresample_close() before freeing. | ||||||
|  |  * | ||||||
|  |  * @param avr  audio resample context | ||||||
|  |  */ | ||||||
|  | void avresample_free(AVAudioResampleContext **avr); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Generate a channel mixing matrix. | ||||||
|  |  * | ||||||
|  |  * This function is the one used internally by libavresample for building the | ||||||
|  |  * default mixing matrix. It is made public just as a utility function for | ||||||
|  |  * building custom matrices. | ||||||
|  |  * | ||||||
|  |  * @param in_layout           input channel layout | ||||||
|  |  * @param out_layout          output channel layout | ||||||
|  |  * @param center_mix_level    mix level for the center channel | ||||||
|  |  * @param surround_mix_level  mix level for the surround channel(s) | ||||||
|  |  * @param lfe_mix_level       mix level for the low-frequency effects channel | ||||||
|  |  * @param normalize           if 1, coefficients will be normalized to prevent | ||||||
|  |  *                            overflow. if 0, coefficients will not be | ||||||
|  |  *                            normalized. | ||||||
|  |  * @param[out] matrix         mixing coefficients; matrix[i + stride * o] is | ||||||
|  |  *                            the weight of input channel i in output channel o. | ||||||
|  |  * @param stride              distance between adjacent input channels in the | ||||||
|  |  *                            matrix array | ||||||
|  |  * @return                    0 on success, negative AVERROR code on failure | ||||||
|  |  */ | ||||||
|  | int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout, | ||||||
|  |                             double center_mix_level, double surround_mix_level, | ||||||
|  |                             double lfe_mix_level, int normalize, double *matrix, | ||||||
|  |                             int stride); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Get the current channel mixing matrix. | ||||||
|  |  * | ||||||
|  |  * @param avr     audio resample context | ||||||
|  |  * @param matrix  mixing coefficients; matrix[i + stride * o] is the weight of | ||||||
|  |  *                input channel i in output channel o. | ||||||
|  |  * @param stride  distance between adjacent input channels in the matrix array | ||||||
|  |  * @return        0 on success, negative AVERROR code on failure | ||||||
|  |  */ | ||||||
|  | int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix, | ||||||
|  |                           int stride); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Set channel mixing matrix. | ||||||
|  |  * | ||||||
|  |  * Allows for setting a custom mixing matrix, overriding the default matrix | ||||||
|  |  * generated internally during avresample_open(). This function can be called | ||||||
|  |  * anytime on an allocated context, either before or after calling | ||||||
|  |  * avresample_open(). avresample_convert() always uses the current matrix. | ||||||
|  |  * Calling avresample_close() on the context will clear the current matrix. | ||||||
|  |  * | ||||||
|  |  * @see avresample_close() | ||||||
|  |  * | ||||||
|  |  * @param avr     audio resample context | ||||||
|  |  * @param matrix  mixing coefficients; matrix[i + stride * o] is the weight of | ||||||
|  |  *                input channel i in output channel o. | ||||||
|  |  * @param stride  distance between adjacent input channels in the matrix array | ||||||
|  |  * @return        0 on success, negative AVERROR code on failure | ||||||
|  |  */ | ||||||
|  | int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, | ||||||
|  |                           int stride); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Set compensation for resampling. | ||||||
|  |  * | ||||||
|  |  * This can be called anytime after avresample_open(). If resampling was not | ||||||
|  |  * being done previously, the AVAudioResampleContext is closed and reopened | ||||||
|  |  * with resampling enabled. In this case, any samples remaining in the output | ||||||
|  |  * FIFO and the current channel mixing matrix will be restored after reopening | ||||||
|  |  * the context. | ||||||
|  |  * | ||||||
|  |  * @param avr                    audio resample context | ||||||
|  |  * @param sample_delta           compensation delta, in samples | ||||||
|  |  * @param compensation_distance  compensation distance, in samples | ||||||
|  |  * @return                       0 on success, negative AVERROR code on failure | ||||||
|  |  */ | ||||||
|  | int avresample_set_compensation(AVAudioResampleContext *avr, int sample_delta, | ||||||
|  |                                 int compensation_distance); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Convert input samples and write them to the output FIFO. | ||||||
|  |  * | ||||||
|  |  * The output data can be NULL or have fewer allocated samples than required. | ||||||
|  |  * In this case, any remaining samples not written to the output will be added | ||||||
|  |  * to an internal FIFO buffer, to be returned at the next call to this function | ||||||
|  |  * or to avresample_read(). | ||||||
|  |  * | ||||||
|  |  * If converting sample rate, there may be data remaining in the internal | ||||||
|  |  * resampling delay buffer. avresample_get_delay() tells the number of remaining | ||||||
|  |  * samples. To get this data as output, call avresample_convert() with NULL | ||||||
|  |  * input. | ||||||
|  |  * | ||||||
|  |  * At the end of the conversion process, there may be data remaining in the | ||||||
|  |  * internal FIFO buffer. avresample_available() tells the number of remaining | ||||||
|  |  * samples. To get this data as output, either call avresample_convert() with | ||||||
|  |  * NULL input or call avresample_read(). | ||||||
|  |  * | ||||||
|  |  * @see avresample_available() | ||||||
|  |  * @see avresample_read() | ||||||
|  |  * @see avresample_get_delay() | ||||||
|  |  * | ||||||
|  |  * @param avr             audio resample context | ||||||
|  |  * @param output          output data pointers | ||||||
|  |  * @param out_plane_size  output plane size, in bytes. | ||||||
|  |  *                        This can be 0 if unknown, but that will lead to | ||||||
|  |  *                        optimized functions not being used directly on the | ||||||
|  |  *                        output, which could slow down some conversions. | ||||||
|  |  * @param out_samples     maximum number of samples that the output buffer can hold | ||||||
|  |  * @param input           input data pointers | ||||||
|  |  * @param in_plane_size   input plane size, in bytes | ||||||
|  |  *                        This can be 0 if unknown, but that will lead to | ||||||
|  |  *                        optimized functions not being used directly on the | ||||||
|  |  *                        input, which could slow down some conversions. | ||||||
|  |  * @param in_samples      number of input samples to convert | ||||||
|  |  * @return                number of samples written to the output buffer, | ||||||
|  |  *                        not including converted samples added to the internal | ||||||
|  |  *                        output FIFO | ||||||
|  |  */ | ||||||
|  | int avresample_convert(AVAudioResampleContext *avr, void **output, | ||||||
|  |                        int out_plane_size, int out_samples, void **input, | ||||||
|  |                        int in_plane_size, int in_samples); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Return the number of samples currently in the resampling delay buffer. | ||||||
|  |  * | ||||||
|  |  * When resampling, there may be a delay between the input and output. Any | ||||||
|  |  * unconverted samples in each call are stored internally in a delay buffer. | ||||||
|  |  * This function allows the user to determine the current number of samples in | ||||||
|  |  * the delay buffer, which can be useful for synchronization. | ||||||
|  |  * | ||||||
|  |  * @see avresample_convert() | ||||||
|  |  * | ||||||
|  |  * @param avr  audio resample context | ||||||
|  |  * @return     number of samples currently in the resampling delay buffer | ||||||
|  |  */ | ||||||
|  | int avresample_get_delay(AVAudioResampleContext *avr); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Return the number of available samples in the output FIFO. | ||||||
|  |  * | ||||||
|  |  * During conversion, if the user does not specify an output buffer or | ||||||
|  |  * specifies an output buffer that is smaller than what is needed, remaining | ||||||
|  |  * samples that are not written to the output are stored to an internal FIFO | ||||||
|  |  * buffer. The samples in the FIFO can be read with avresample_read() or | ||||||
|  |  * avresample_convert(). | ||||||
|  |  * | ||||||
|  |  * @see avresample_read() | ||||||
|  |  * @see avresample_convert() | ||||||
|  |  * | ||||||
|  |  * @param avr  audio resample context | ||||||
|  |  * @return     number of samples available for reading | ||||||
|  |  */ | ||||||
|  | int avresample_available(AVAudioResampleContext *avr); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Read samples from the output FIFO. | ||||||
|  |  * | ||||||
|  |  * During conversion, if the user does not specify an output buffer or | ||||||
|  |  * specifies an output buffer that is smaller than what is needed, remaining | ||||||
|  |  * samples that are not written to the output are stored to an internal FIFO | ||||||
|  |  * buffer. This function can be used to read samples from that internal FIFO. | ||||||
|  |  * | ||||||
|  |  * @see avresample_available() | ||||||
|  |  * @see avresample_convert() | ||||||
|  |  * | ||||||
|  |  * @param avr         audio resample context | ||||||
|  |  * @param output      output data pointers | ||||||
|  |  * @param nb_samples  number of samples to read from the FIFO | ||||||
|  |  * @return            the number of samples written to output | ||||||
|  |  */ | ||||||
|  | int avresample_read(AVAudioResampleContext *avr, void **output, int nb_samples); | ||||||
|  | 
 | ||||||
|  | #endif /* AVRESAMPLE_AVRESAMPLE_H */ | ||||||
							
								
								
									
										75
									
								
								libavresample/internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								libavresample/internal.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef AVRESAMPLE_INTERNAL_H | ||||||
|  | #define AVRESAMPLE_INTERNAL_H | ||||||
|  | 
 | ||||||
|  | #include "libavutil/audio_fifo.h" | ||||||
|  | #include "libavutil/log.h" | ||||||
|  | #include "libavutil/opt.h" | ||||||
|  | #include "libavutil/samplefmt.h" | ||||||
|  | #include "avresample.h" | ||||||
|  | #include "audio_convert.h" | ||||||
|  | #include "audio_data.h" | ||||||
|  | #include "audio_mix.h" | ||||||
|  | #include "resample.h" | ||||||
|  | 
 | ||||||
|  | struct AVAudioResampleContext { | ||||||
|  |     const AVClass *av_class;        /**< AVClass for logging and AVOptions  */ | ||||||
|  | 
 | ||||||
|  |     uint64_t in_channel_layout;                 /**< input channel layout   */ | ||||||
|  |     enum AVSampleFormat in_sample_fmt;          /**< input sample format    */ | ||||||
|  |     int in_sample_rate;                         /**< input sample rate      */ | ||||||
|  |     uint64_t out_channel_layout;                /**< output channel layout  */ | ||||||
|  |     enum AVSampleFormat out_sample_fmt;         /**< output sample format   */ | ||||||
|  |     int out_sample_rate;                        /**< output sample rate     */ | ||||||
|  |     enum AVSampleFormat internal_sample_fmt;    /**< internal sample format */ | ||||||
|  |     enum AVMixCoeffType mix_coeff_type;         /**< mixing coefficient type */ | ||||||
|  |     double center_mix_level;                    /**< center mix level       */ | ||||||
|  |     double surround_mix_level;                  /**< surround mix level     */ | ||||||
|  |     double lfe_mix_level;                       /**< lfe mix level          */ | ||||||
|  |     int force_resampling;                       /**< force resampling       */ | ||||||
|  |     int filter_size;                            /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */ | ||||||
|  |     int phase_shift;                            /**< log2 of the number of entries in the resampling polyphase filterbank */ | ||||||
|  |     int linear_interp;                          /**< if 1 then the resampling FIR filter will be linearly interpolated */ | ||||||
|  |     double cutoff;                              /**< resampling cutoff frequency. 1.0 corresponds to half the output sample rate */ | ||||||
|  | 
 | ||||||
|  |     int in_channels;        /**< number of input channels                   */ | ||||||
|  |     int out_channels;       /**< number of output channels                  */ | ||||||
|  |     int resample_channels;  /**< number of channels used for resampling     */ | ||||||
|  |     int downmix_needed;     /**< downmixing is needed                       */ | ||||||
|  |     int upmix_needed;       /**< upmixing is needed                         */ | ||||||
|  |     int mixing_needed;      /**< either upmixing or downmixing is needed    */ | ||||||
|  |     int resample_needed;    /**< resampling is needed                       */ | ||||||
|  |     int in_convert_needed;  /**< input sample format conversion is needed   */ | ||||||
|  |     int out_convert_needed; /**< output sample format conversion is needed  */ | ||||||
|  | 
 | ||||||
|  |     AudioData *in_buffer;           /**< buffer for converted input         */ | ||||||
|  |     AudioData *resample_out_buffer; /**< buffer for output from resampler   */ | ||||||
|  |     AudioData *out_buffer;          /**< buffer for converted output        */ | ||||||
|  |     AVAudioFifo *out_fifo;          /**< FIFO for output samples            */ | ||||||
|  | 
 | ||||||
|  |     AudioConvert *ac_in;        /**< input sample format conversion context  */ | ||||||
|  |     AudioConvert *ac_out;       /**< output sample format conversion context */ | ||||||
|  |     ResampleContext *resample;  /**< resampling context                      */ | ||||||
|  |     AudioMix *am;               /**< channel mixing context                  */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif /* AVRESAMPLE_INTERNAL_H */ | ||||||
							
								
								
									
										4
									
								
								libavresample/libavresample.v
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								libavresample/libavresample.v
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | LIBAVRESAMPLE_$MAJOR { | ||||||
|  |         global: av*; | ||||||
|  |         local:  *; | ||||||
|  | }; | ||||||
							
								
								
									
										89
									
								
								libavresample/options.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								libavresample/options.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,89 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 "libavutil/mathematics.h" | ||||||
|  | #include "libavutil/opt.h" | ||||||
|  | #include "avresample.h" | ||||||
|  | #include "internal.h" | ||||||
|  | #include "audio_mix.h" | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @file | ||||||
|  |  * Options definition for AVAudioResampleContext. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define OFFSET(x) offsetof(AVAudioResampleContext, x) | ||||||
|  | #define PARAM AV_OPT_FLAG_AUDIO_PARAM | ||||||
|  | 
 | ||||||
|  | static const AVOption options[] = { | ||||||
|  |     { "in_channel_layout",      "Input Channel Layout",     OFFSET(in_channel_layout),      AV_OPT_TYPE_INT64,  { 0                     }, INT64_MIN,            INT64_MAX,              PARAM }, | ||||||
|  |     { "in_sample_fmt",          "Input Sample Format",      OFFSET(in_sample_fmt),          AV_OPT_TYPE_INT,    { AV_SAMPLE_FMT_S16     }, AV_SAMPLE_FMT_U8,     AV_SAMPLE_FMT_NB-1,     PARAM }, | ||||||
|  |     { "in_sample_rate",         "Input Sample Rate",        OFFSET(in_sample_rate),         AV_OPT_TYPE_INT,    { 48000                 }, 1,                    INT_MAX,                PARAM }, | ||||||
|  |     { "out_channel_layout",     "Output Channel Layout",    OFFSET(out_channel_layout),     AV_OPT_TYPE_INT64,  { 0                     }, INT64_MIN,            INT64_MAX,              PARAM }, | ||||||
|  |     { "out_sample_fmt",         "Output Sample Format",     OFFSET(out_sample_fmt),         AV_OPT_TYPE_INT,    { AV_SAMPLE_FMT_S16     }, AV_SAMPLE_FMT_U8,     AV_SAMPLE_FMT_NB-1,     PARAM }, | ||||||
|  |     { "out_sample_rate",        "Output Sample Rate",       OFFSET(out_sample_rate),        AV_OPT_TYPE_INT,    { 48000                 }, 1,                    INT_MAX,                PARAM }, | ||||||
|  |     { "internal_sample_fmt",    "Internal Sample Format",   OFFSET(internal_sample_fmt),    AV_OPT_TYPE_INT,    { AV_SAMPLE_FMT_FLTP    }, AV_SAMPLE_FMT_NONE,   AV_SAMPLE_FMT_NB-1,     PARAM }, | ||||||
|  |     { "mix_coeff_type",         "Mixing Coefficient Type",  OFFSET(mix_coeff_type),         AV_OPT_TYPE_INT,    { AV_MIX_COEFF_TYPE_FLT }, AV_MIX_COEFF_TYPE_Q6, AV_MIX_COEFF_TYPE_NB-1, PARAM, "mix_coeff_type" }, | ||||||
|  |         { "q6",  "16-bit 10.6 Fixed-Point",  0, AV_OPT_TYPE_CONST, { AV_MIX_COEFF_TYPE_Q6  }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" }, | ||||||
|  |         { "q15", "32-bit 17.15 Fixed-Point", 0, AV_OPT_TYPE_CONST, { AV_MIX_COEFF_TYPE_Q15 }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" }, | ||||||
|  |         { "flt", "Floating-Point",           0, AV_OPT_TYPE_CONST, { AV_MIX_COEFF_TYPE_FLT }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" }, | ||||||
|  |     { "center_mix_level",       "Center Mix Level",         OFFSET(center_mix_level),       AV_OPT_TYPE_DOUBLE, { M_SQRT1_2             }, -32.0,                32.0,                   PARAM }, | ||||||
|  |     { "surround_mix_level",     "Surround Mix Level",       OFFSET(surround_mix_level),     AV_OPT_TYPE_DOUBLE, { M_SQRT1_2             }, -32.0,                32.0,                   PARAM }, | ||||||
|  |     { "lfe_mix_level",          "LFE Mix Level",            OFFSET(lfe_mix_level),          AV_OPT_TYPE_DOUBLE, { 0.0                   }, -32.0,                32.0,                   PARAM }, | ||||||
|  |     { "force_resampling",       "Force Resampling",         OFFSET(force_resampling),       AV_OPT_TYPE_INT,    { 0                     }, 0,                    1,                      PARAM }, | ||||||
|  |     { "filter_size",            "Resampling Filter Size",   OFFSET(filter_size),            AV_OPT_TYPE_INT,    { 16                    }, 0,                    32, /* ??? */           PARAM }, | ||||||
|  |     { "phase_shift",            "Resampling Phase Shift",   OFFSET(phase_shift),            AV_OPT_TYPE_INT,    { 10                    }, 0,                    30, /* ??? */           PARAM }, | ||||||
|  |     { "linear_interp",          "Use Linear Interpolation", OFFSET(linear_interp),          AV_OPT_TYPE_INT,    { 0                     }, 0,                    1,                      PARAM }, | ||||||
|  |     { "cutoff",                 "Cutoff Frequency Ratio",   OFFSET(cutoff),                 AV_OPT_TYPE_DOUBLE, { 0.8                   }, 0.0,                  1.0,                    PARAM }, | ||||||
|  |     { NULL }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const AVClass av_resample_context_class = { | ||||||
|  |     .class_name = "AVAudioResampleContext", | ||||||
|  |     .item_name  = av_default_item_name, | ||||||
|  |     .option     = options, | ||||||
|  |     .version    = LIBAVUTIL_VERSION_INT, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | AVAudioResampleContext *avresample_alloc_context(void) | ||||||
|  | { | ||||||
|  |     AVAudioResampleContext *avr; | ||||||
|  | 
 | ||||||
|  |     avr = av_mallocz(sizeof(*avr)); | ||||||
|  |     if (!avr) | ||||||
|  |         return NULL; | ||||||
|  | 
 | ||||||
|  |     avr->av_class = &av_resample_context_class; | ||||||
|  |     av_opt_set_defaults(avr); | ||||||
|  | 
 | ||||||
|  |     avr->am = av_mallocz(sizeof(*avr->am)); | ||||||
|  |     if (!avr->am) { | ||||||
|  |         av_free(avr); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     avr->am->avr = avr; | ||||||
|  | 
 | ||||||
|  |     return avr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const AVClass *avresample_get_class(void) | ||||||
|  | { | ||||||
|  |     return &av_resample_context_class; | ||||||
|  | } | ||||||
							
								
								
									
										480
									
								
								libavresample/resample.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										480
									
								
								libavresample/resample.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,480 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 "libavutil/libm.h" | ||||||
|  | #include "libavutil/log.h" | ||||||
|  | #include "internal.h" | ||||||
|  | #include "audio_data.h" | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_RESAMPLE_FLT | ||||||
|  | /* float template */ | ||||||
|  | #define FILTER_SHIFT  0 | ||||||
|  | #define FELEM         float | ||||||
|  | #define FELEM2        float | ||||||
|  | #define FELEML        float | ||||||
|  | #define WINDOW_TYPE   24 | ||||||
|  | #elifdef CONFIG_RESAMPLE_S32 | ||||||
|  | /* s32 template */ | ||||||
|  | #define FILTER_SHIFT  30 | ||||||
|  | #define FELEM         int32_t | ||||||
|  | #define FELEM2        int64_t | ||||||
|  | #define FELEML        int64_t | ||||||
|  | #define FELEM_MAX     INT32_MAX | ||||||
|  | #define FELEM_MIN     INT32_MIN | ||||||
|  | #define WINDOW_TYPE   12 | ||||||
|  | #else | ||||||
|  | /* s16 template */ | ||||||
|  | #define FILTER_SHIFT  15 | ||||||
|  | #define FELEM         int16_t | ||||||
|  | #define FELEM2        int32_t | ||||||
|  | #define FELEML        int64_t | ||||||
|  | #define FELEM_MAX     INT16_MAX | ||||||
|  | #define FELEM_MIN     INT16_MIN | ||||||
|  | #define WINDOW_TYPE   9 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | struct ResampleContext { | ||||||
|  |     AVAudioResampleContext *avr; | ||||||
|  |     AudioData *buffer; | ||||||
|  |     FELEM *filter_bank; | ||||||
|  |     int filter_length; | ||||||
|  |     int ideal_dst_incr; | ||||||
|  |     int dst_incr; | ||||||
|  |     int index; | ||||||
|  |     int frac; | ||||||
|  |     int src_incr; | ||||||
|  |     int compensation_distance; | ||||||
|  |     int phase_shift; | ||||||
|  |     int phase_mask; | ||||||
|  |     int linear; | ||||||
|  |     double factor; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * 0th order modified bessel function of the first kind. | ||||||
|  |  */ | ||||||
|  | static double bessel(double x) | ||||||
|  | { | ||||||
|  |     double v     = 1; | ||||||
|  |     double lastv = 0; | ||||||
|  |     double t     = 1; | ||||||
|  |     int i; | ||||||
|  | 
 | ||||||
|  |     x = x * x / 4; | ||||||
|  |     for (i = 1; v != lastv; i++) { | ||||||
|  |         lastv = v; | ||||||
|  |         t    *= x / (i * i); | ||||||
|  |         v    += t; | ||||||
|  |     } | ||||||
|  |     return v; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Build a polyphase filterbank. | ||||||
|  |  * | ||||||
|  |  * @param[out] filter       filter coefficients | ||||||
|  |  * @param      factor       resampling factor | ||||||
|  |  * @param      tap_count    tap count | ||||||
|  |  * @param      phase_count  phase count | ||||||
|  |  * @param      scale        wanted sum of coefficients for each filter | ||||||
|  |  * @param      type         0->cubic | ||||||
|  |  *                          1->blackman nuttall windowed sinc | ||||||
|  |  *                          2..16->kaiser windowed sinc beta=2..16 | ||||||
|  |  * @return                  0 on success, negative AVERROR code on failure | ||||||
|  |  */ | ||||||
|  | static int build_filter(FELEM *filter, double factor, int tap_count, | ||||||
|  |                         int phase_count, int scale, int type) | ||||||
|  | { | ||||||
|  |     int ph, i; | ||||||
|  |     double x, y, w; | ||||||
|  |     double *tab; | ||||||
|  |     const int center = (tap_count - 1) / 2; | ||||||
|  | 
 | ||||||
|  |     tab = av_malloc(tap_count * sizeof(*tab)); | ||||||
|  |     if (!tab) | ||||||
|  |         return AVERROR(ENOMEM); | ||||||
|  | 
 | ||||||
|  |     /* if upsampling, only need to interpolate, no filter */ | ||||||
|  |     if (factor > 1.0) | ||||||
|  |         factor = 1.0; | ||||||
|  | 
 | ||||||
|  |     for (ph = 0; ph < phase_count; ph++) { | ||||||
|  |         double norm = 0; | ||||||
|  |         for (i = 0; i < tap_count; i++) { | ||||||
|  |             x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor; | ||||||
|  |             if (x == 0) y = 1.0; | ||||||
|  |             else        y = sin(x) / x; | ||||||
|  |             switch (type) { | ||||||
|  |             case 0: { | ||||||
|  |                 const float d = -0.5; //first order derivative = -0.5
 | ||||||
|  |                 x = fabs(((double)(i - center) - (double)ph / phase_count) * factor); | ||||||
|  |                 if (x < 1.0) y = 1 - 3 * x*x + 2 * x*x*x + d * (                -x*x + x*x*x); | ||||||
|  |                 else         y =                           d * (-4 + 8 * x - 5 * x*x + x*x*x); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             case 1: | ||||||
|  |                 w  = 2.0 * x / (factor * tap_count) + M_PI; | ||||||
|  |                 y *= 0.3635819 - 0.4891775 * cos(    w) + | ||||||
|  |                                  0.1365995 * cos(2 * w) - | ||||||
|  |                                  0.0106411 * cos(3 * w); | ||||||
|  |                 break; | ||||||
|  |             default: | ||||||
|  |                 w  = 2.0 * x / (factor * tap_count * M_PI); | ||||||
|  |                 y *= bessel(type * sqrt(FFMAX(1 - w * w, 0))); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             tab[i] = y; | ||||||
|  |             norm  += y; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /* normalize so that an uniform color remains the same */ | ||||||
|  |         for (i = 0; i < tap_count; i++) { | ||||||
|  | #ifdef CONFIG_RESAMPLE_FLT | ||||||
|  |             filter[ph * tap_count + i] = tab[i] / norm; | ||||||
|  | #else | ||||||
|  |             filter[ph * tap_count + i] = av_clip(lrintf(tab[i] * scale / norm), | ||||||
|  |                                                  FELEM_MIN, FELEM_MAX); | ||||||
|  | #endif | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     av_free(tab); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResampleContext *ff_audio_resample_init(AVAudioResampleContext *avr) | ||||||
|  | { | ||||||
|  |     ResampleContext *c; | ||||||
|  |     int out_rate    = avr->out_sample_rate; | ||||||
|  |     int in_rate     = avr->in_sample_rate; | ||||||
|  |     double factor   = FFMIN(out_rate * avr->cutoff / in_rate, 1.0); | ||||||
|  |     int phase_count = 1 << avr->phase_shift; | ||||||
|  | 
 | ||||||
|  |     /* TODO: add support for s32 and float internal formats */ | ||||||
|  |     if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P) { | ||||||
|  |         av_log(avr, AV_LOG_ERROR, "Unsupported internal format for " | ||||||
|  |                "resampling: %s\n", | ||||||
|  |                av_get_sample_fmt_name(avr->internal_sample_fmt)); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     c = av_mallocz(sizeof(*c)); | ||||||
|  |     if (!c) | ||||||
|  |         return NULL; | ||||||
|  | 
 | ||||||
|  |     c->avr           = avr; | ||||||
|  |     c->phase_shift   = avr->phase_shift; | ||||||
|  |     c->phase_mask    = phase_count - 1; | ||||||
|  |     c->linear        = avr->linear_interp; | ||||||
|  |     c->factor        = factor; | ||||||
|  |     c->filter_length = FFMAX((int)ceil(avr->filter_size / factor), 1); | ||||||
|  | 
 | ||||||
|  |     c->filter_bank = av_mallocz(c->filter_length * (phase_count + 1) * sizeof(FELEM)); | ||||||
|  |     if (!c->filter_bank) | ||||||
|  |         goto error; | ||||||
|  | 
 | ||||||
|  |     if (build_filter(c->filter_bank, factor, c->filter_length, phase_count, | ||||||
|  |                      1 << FILTER_SHIFT, WINDOW_TYPE) < 0) | ||||||
|  |         goto error; | ||||||
|  | 
 | ||||||
|  |     memcpy(&c->filter_bank[c->filter_length * phase_count + 1], | ||||||
|  |            c->filter_bank, (c->filter_length - 1) * sizeof(FELEM)); | ||||||
|  |     c->filter_bank[c->filter_length * phase_count] = c->filter_bank[c->filter_length - 1]; | ||||||
|  | 
 | ||||||
|  |     c->compensation_distance = 0; | ||||||
|  |     if (!av_reduce(&c->src_incr, &c->dst_incr, out_rate, | ||||||
|  |                    in_rate * (int64_t)phase_count, INT32_MAX / 2)) | ||||||
|  |         goto error; | ||||||
|  |     c->ideal_dst_incr = c->dst_incr; | ||||||
|  | 
 | ||||||
|  |     c->index = -phase_count * ((c->filter_length - 1) / 2); | ||||||
|  |     c->frac  = 0; | ||||||
|  | 
 | ||||||
|  |     /* allocate internal buffer */ | ||||||
|  |     c->buffer = ff_audio_data_alloc(avr->resample_channels, 0, | ||||||
|  |                                     avr->internal_sample_fmt, | ||||||
|  |                                     "resample buffer"); | ||||||
|  |     if (!c->buffer) | ||||||
|  |         goto error; | ||||||
|  | 
 | ||||||
|  |     av_log(avr, AV_LOG_DEBUG, "resample: %s from %d Hz to %d Hz\n", | ||||||
|  |            av_get_sample_fmt_name(avr->internal_sample_fmt), | ||||||
|  |            avr->in_sample_rate, avr->out_sample_rate); | ||||||
|  | 
 | ||||||
|  |     return c; | ||||||
|  | 
 | ||||||
|  | error: | ||||||
|  |     ff_audio_data_free(&c->buffer); | ||||||
|  |     av_free(c->filter_bank); | ||||||
|  |     av_free(c); | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ff_audio_resample_free(ResampleContext **c) | ||||||
|  | { | ||||||
|  |     if (!*c) | ||||||
|  |         return; | ||||||
|  |     ff_audio_data_free(&(*c)->buffer); | ||||||
|  |     av_free((*c)->filter_bank); | ||||||
|  |     av_freep(c); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int avresample_set_compensation(AVAudioResampleContext *avr, int sample_delta, | ||||||
|  |                                 int compensation_distance) | ||||||
|  | { | ||||||
|  |     ResampleContext *c; | ||||||
|  |     AudioData *fifo_buf = NULL; | ||||||
|  |     int ret = 0; | ||||||
|  | 
 | ||||||
|  |     if (compensation_distance < 0) | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  |     if (!compensation_distance && sample_delta) | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  | 
 | ||||||
|  |     /* if resampling was not enabled previously, re-initialize the
 | ||||||
|  |        AVAudioResampleContext and force resampling */ | ||||||
|  |     if (!avr->resample_needed) { | ||||||
|  |         int fifo_samples; | ||||||
|  |         double matrix[AVRESAMPLE_MAX_CHANNELS * AVRESAMPLE_MAX_CHANNELS] = { 0 }; | ||||||
|  | 
 | ||||||
|  |         /* buffer any remaining samples in the output FIFO before closing */ | ||||||
|  |         fifo_samples = av_audio_fifo_size(avr->out_fifo); | ||||||
|  |         if (fifo_samples > 0) { | ||||||
|  |             fifo_buf = ff_audio_data_alloc(avr->out_channels, fifo_samples, | ||||||
|  |                                            avr->out_sample_fmt, NULL); | ||||||
|  |             if (!fifo_buf) | ||||||
|  |                 return AVERROR(EINVAL); | ||||||
|  |             ret = ff_audio_data_read_from_fifo(avr->out_fifo, fifo_buf, | ||||||
|  |                                                fifo_samples); | ||||||
|  |             if (ret < 0) | ||||||
|  |                 goto reinit_fail; | ||||||
|  |         } | ||||||
|  |         /* save the channel mixing matrix */ | ||||||
|  |         ret = avresample_get_matrix(avr, matrix, AVRESAMPLE_MAX_CHANNELS); | ||||||
|  |         if (ret < 0) | ||||||
|  |             goto reinit_fail; | ||||||
|  | 
 | ||||||
|  |         /* close the AVAudioResampleContext */ | ||||||
|  |         avresample_close(avr); | ||||||
|  | 
 | ||||||
|  |         avr->force_resampling = 1; | ||||||
|  | 
 | ||||||
|  |         /* restore the channel mixing matrix */ | ||||||
|  |         ret = avresample_set_matrix(avr, matrix, AVRESAMPLE_MAX_CHANNELS); | ||||||
|  |         if (ret < 0) | ||||||
|  |             goto reinit_fail; | ||||||
|  | 
 | ||||||
|  |         /* re-open the AVAudioResampleContext */ | ||||||
|  |         ret = avresample_open(avr); | ||||||
|  |         if (ret < 0) | ||||||
|  |             goto reinit_fail; | ||||||
|  | 
 | ||||||
|  |         /* restore buffered samples to the output FIFO */ | ||||||
|  |         if (fifo_samples > 0) { | ||||||
|  |             ret = ff_audio_data_add_to_fifo(avr->out_fifo, fifo_buf, 0, | ||||||
|  |                                             fifo_samples); | ||||||
|  |             if (ret < 0) | ||||||
|  |                 goto reinit_fail; | ||||||
|  |             ff_audio_data_free(&fifo_buf); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     c = avr->resample; | ||||||
|  |     c->compensation_distance = compensation_distance; | ||||||
|  |     if (compensation_distance) { | ||||||
|  |         c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * | ||||||
|  |                       (int64_t)sample_delta / compensation_distance; | ||||||
|  |     } else { | ||||||
|  |         c->dst_incr = c->ideal_dst_incr; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | 
 | ||||||
|  | reinit_fail: | ||||||
|  |     ff_audio_data_free(&fifo_buf); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int resample(ResampleContext *c, int16_t *dst, const int16_t *src, | ||||||
|  |                     int *consumed, int src_size, int dst_size, int update_ctx) | ||||||
|  | { | ||||||
|  |     int dst_index, i; | ||||||
|  |     int index         = c->index; | ||||||
|  |     int frac          = c->frac; | ||||||
|  |     int dst_incr_frac = c->dst_incr % c->src_incr; | ||||||
|  |     int dst_incr      = c->dst_incr / c->src_incr; | ||||||
|  |     int compensation_distance = c->compensation_distance; | ||||||
|  | 
 | ||||||
|  |     if (!dst != !src) | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  | 
 | ||||||
|  |     if (compensation_distance == 0 && c->filter_length == 1 && | ||||||
|  |         c->phase_shift == 0) { | ||||||
|  |         int64_t index2 = ((int64_t)index) << 32; | ||||||
|  |         int64_t incr   = (1LL << 32) * c->dst_incr / c->src_incr; | ||||||
|  |         dst_size       = FFMIN(dst_size, | ||||||
|  |                                (src_size-1-index) * (int64_t)c->src_incr / | ||||||
|  |                                c->dst_incr); | ||||||
|  | 
 | ||||||
|  |         if (dst) { | ||||||
|  |             for(dst_index = 0; dst_index < dst_size; dst_index++) { | ||||||
|  |                 dst[dst_index] = src[index2 >> 32]; | ||||||
|  |                 index2 += incr; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             dst_index = dst_size; | ||||||
|  |         } | ||||||
|  |         index += dst_index * dst_incr; | ||||||
|  |         index += (frac + dst_index * (int64_t)dst_incr_frac) / c->src_incr; | ||||||
|  |         frac   = (frac + dst_index * (int64_t)dst_incr_frac) % c->src_incr; | ||||||
|  |     } else { | ||||||
|  |         for (dst_index = 0; dst_index < dst_size; dst_index++) { | ||||||
|  |             FELEM *filter = c->filter_bank + | ||||||
|  |                             c->filter_length * (index & c->phase_mask); | ||||||
|  |             int sample_index = index >> c->phase_shift; | ||||||
|  | 
 | ||||||
|  |             if (!dst && (sample_index + c->filter_length > src_size || | ||||||
|  |                          -sample_index >= src_size)) | ||||||
|  |                 break; | ||||||
|  | 
 | ||||||
|  |             if (dst) { | ||||||
|  |                 FELEM2 val = 0; | ||||||
|  | 
 | ||||||
|  |                 if (sample_index < 0) { | ||||||
|  |                     for (i = 0; i < c->filter_length; i++) | ||||||
|  |                         val += src[FFABS(sample_index + i) % src_size] * | ||||||
|  |                                (FELEM2)filter[i]; | ||||||
|  |                 } else if (sample_index + c->filter_length > src_size) { | ||||||
|  |                     break; | ||||||
|  |                 } else if (c->linear) { | ||||||
|  |                     FELEM2 v2 = 0; | ||||||
|  |                     for (i = 0; i < c->filter_length; i++) { | ||||||
|  |                         val += src[abs(sample_index + i)] * (FELEM2)filter[i]; | ||||||
|  |                         v2  += src[abs(sample_index + i)] * (FELEM2)filter[i + c->filter_length]; | ||||||
|  |                     } | ||||||
|  |                     val += (v2 - val) * (FELEML)frac / c->src_incr; | ||||||
|  |                 } else { | ||||||
|  |                     for (i = 0; i < c->filter_length; i++) | ||||||
|  |                         val += src[sample_index + i] * (FELEM2)filter[i]; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_RESAMPLE_FLT | ||||||
|  |                 dst[dst_index] = av_clip_int16(lrintf(val)); | ||||||
|  | #else | ||||||
|  |                 val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT; | ||||||
|  |                 dst[dst_index] = av_clip_int16(val); | ||||||
|  | #endif | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             frac  += dst_incr_frac; | ||||||
|  |             index += dst_incr; | ||||||
|  |             if (frac >= c->src_incr) { | ||||||
|  |                 frac -= c->src_incr; | ||||||
|  |                 index++; | ||||||
|  |             } | ||||||
|  |             if (dst_index + 1 == compensation_distance) { | ||||||
|  |                 compensation_distance = 0; | ||||||
|  |                 dst_incr_frac = c->ideal_dst_incr % c->src_incr; | ||||||
|  |                 dst_incr      = c->ideal_dst_incr / c->src_incr; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (consumed) | ||||||
|  |         *consumed = FFMAX(index, 0) >> c->phase_shift; | ||||||
|  | 
 | ||||||
|  |     if (update_ctx) { | ||||||
|  |         if (index >= 0) | ||||||
|  |             index &= c->phase_mask; | ||||||
|  | 
 | ||||||
|  |         if (compensation_distance) { | ||||||
|  |             compensation_distance -= dst_index; | ||||||
|  |             if (compensation_distance <= 0) | ||||||
|  |                 return AVERROR_BUG; | ||||||
|  |         } | ||||||
|  |         c->frac     = frac; | ||||||
|  |         c->index    = index; | ||||||
|  |         c->dst_incr = dst_incr_frac + c->src_incr*dst_incr; | ||||||
|  |         c->compensation_distance = compensation_distance; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return dst_index; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ff_audio_resample(ResampleContext *c, AudioData *dst, AudioData *src, | ||||||
|  |                       int *consumed) | ||||||
|  | { | ||||||
|  |     int ch, in_samples, in_leftover, out_samples = 0; | ||||||
|  |     int ret = AVERROR(EINVAL); | ||||||
|  | 
 | ||||||
|  |     in_samples  = src ? src->nb_samples : 0; | ||||||
|  |     in_leftover = c->buffer->nb_samples; | ||||||
|  | 
 | ||||||
|  |     /* add input samples to the internal buffer */ | ||||||
|  |     if (src) { | ||||||
|  |         ret = ff_audio_data_combine(c->buffer, in_leftover, src, 0, in_samples); | ||||||
|  |         if (ret < 0) | ||||||
|  |             return ret; | ||||||
|  |     } else if (!in_leftover) { | ||||||
|  |         /* no remaining samples to flush */ | ||||||
|  |         return 0; | ||||||
|  |     } else { | ||||||
|  |         /* TODO: pad buffer to flush completely */ | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* calculate output size and reallocate output buffer if needed */ | ||||||
|  |     /* TODO: try to calculate this without the dummy resample() run */ | ||||||
|  |     if (!dst->read_only && dst->allow_realloc) { | ||||||
|  |         out_samples = resample(c, NULL, NULL, NULL, c->buffer->nb_samples, | ||||||
|  |                                INT_MAX, 0); | ||||||
|  |         ret = ff_audio_data_realloc(dst, out_samples); | ||||||
|  |         if (ret < 0) { | ||||||
|  |             av_log(c->avr, AV_LOG_ERROR, "error reallocating output\n"); | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* resample each channel plane */ | ||||||
|  |     for (ch = 0; ch < c->buffer->channels; ch++) { | ||||||
|  |         out_samples = resample(c, (int16_t *)dst->data[ch], | ||||||
|  |                                (const int16_t *)c->buffer->data[ch], consumed, | ||||||
|  |                                c->buffer->nb_samples, dst->allocated_samples, | ||||||
|  |                                ch + 1 == c->buffer->channels); | ||||||
|  |     } | ||||||
|  |     if (out_samples < 0) { | ||||||
|  |         av_log(c->avr, AV_LOG_ERROR, "error during resampling\n"); | ||||||
|  |         return out_samples; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* drain consumed samples from the internal buffer */ | ||||||
|  |     ff_audio_data_drain(c->buffer, *consumed); | ||||||
|  | 
 | ||||||
|  |     av_dlog(c->avr, "resampled %d in + %d leftover to %d out + %d leftover\n", | ||||||
|  |             in_samples, in_leftover, out_samples, c->buffer->nb_samples); | ||||||
|  | 
 | ||||||
|  |     dst->nb_samples = out_samples; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int avresample_get_delay(AVAudioResampleContext *avr) | ||||||
|  | { | ||||||
|  |     if (!avr->resample_needed || !avr->resample) | ||||||
|  |         return 0; | ||||||
|  | 
 | ||||||
|  |     return avr->resample->buffer->nb_samples; | ||||||
|  | } | ||||||
							
								
								
									
										70
									
								
								libavresample/resample.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								libavresample/resample.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> | ||||||
|  |  * | ||||||
|  |  * 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 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef AVRESAMPLE_RESAMPLE_H | ||||||
|  | #define AVRESAMPLE_RESAMPLE_H | ||||||
|  | 
 | ||||||
|  | #include "avresample.h" | ||||||
|  | #include "audio_data.h" | ||||||
|  | 
 | ||||||
|  | typedef struct ResampleContext ResampleContext; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Allocate and initialize a ResampleContext. | ||||||
|  |  * | ||||||
|  |  * The parameters in the AVAudioResampleContext are used to initialize the | ||||||
|  |  * ResampleContext. | ||||||
|  |  * | ||||||
|  |  * @param avr  AVAudioResampleContext | ||||||
|  |  * @return     newly-allocated ResampleContext | ||||||
|  |  */ | ||||||
|  | ResampleContext *ff_audio_resample_init(AVAudioResampleContext *avr); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Free a ResampleContext. | ||||||
|  |  * | ||||||
|  |  * @param c  ResampleContext | ||||||
|  |  */ | ||||||
|  | void ff_audio_resample_free(ResampleContext **c); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Resample audio data. | ||||||
|  |  * | ||||||
|  |  * Changes the sample rate. | ||||||
|  |  * | ||||||
|  |  * @par | ||||||
|  |  * All samples in the source data may not be consumed depending on the | ||||||
|  |  * resampling parameters and the size of the output buffer. The unconsumed | ||||||
|  |  * samples are automatically added to the start of the source in the next call. | ||||||
|  |  * If the destination data can be reallocated, that may be done in this function | ||||||
|  |  * in order to fit all available output. If it cannot be reallocated, fewer | ||||||
|  |  * input samples will be consumed in order to have the output fit in the | ||||||
|  |  * destination data buffers. | ||||||
|  |  * | ||||||
|  |  * @param c         ResampleContext | ||||||
|  |  * @param dst       destination audio data | ||||||
|  |  * @param src       source audio data | ||||||
|  |  * @param consumed  number of samples consumed from the source | ||||||
|  |  * @return          number of samples written to the destination | ||||||
|  |  */ | ||||||
|  | int ff_audio_resample(ResampleContext *c, AudioData *dst, AudioData *src, | ||||||
|  |                       int *consumed); | ||||||
|  | 
 | ||||||
|  | #endif /* AVRESAMPLE_RESAMPLE_H */ | ||||||
							
								
								
									
										405
									
								
								libavresample/utils.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										405
									
								
								libavresample/utils.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,405 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 "libavutil/dict.h" | ||||||
|  | // #include "libavutil/error.h"
 | ||||||
|  | #include "libavutil/log.h" | ||||||
|  | #include "libavutil/mem.h" | ||||||
|  | #include "libavutil/opt.h" | ||||||
|  | 
 | ||||||
|  | #include "avresample.h" | ||||||
|  | #include "audio_data.h" | ||||||
|  | #include "internal.h" | ||||||
|  | 
 | ||||||
|  | int avresample_open(AVAudioResampleContext *avr) | ||||||
|  | { | ||||||
|  |     int ret; | ||||||
|  | 
 | ||||||
|  |     /* set channel mixing parameters */ | ||||||
|  |     avr->in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); | ||||||
|  |     if (avr->in_channels <= 0 || avr->in_channels > AVRESAMPLE_MAX_CHANNELS) { | ||||||
|  |         av_log(avr, AV_LOG_ERROR, "Invalid input channel layout: %"PRIu64"\n", | ||||||
|  |                avr->in_channel_layout); | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  |     } | ||||||
|  |     avr->out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); | ||||||
|  |     if (avr->out_channels <= 0 || avr->out_channels > AVRESAMPLE_MAX_CHANNELS) { | ||||||
|  |         av_log(avr, AV_LOG_ERROR, "Invalid output channel layout: %"PRIu64"\n", | ||||||
|  |                avr->out_channel_layout); | ||||||
|  |         return AVERROR(EINVAL); | ||||||
|  |     } | ||||||
|  |     avr->resample_channels = FFMIN(avr->in_channels, avr->out_channels); | ||||||
|  |     avr->downmix_needed    = avr->in_channels  > avr->out_channels; | ||||||
|  |     avr->upmix_needed      = avr->out_channels > avr->in_channels || | ||||||
|  |                              avr->am->matrix                      || | ||||||
|  |                              (avr->out_channels == avr->in_channels && | ||||||
|  |                               avr->in_channel_layout != avr->out_channel_layout); | ||||||
|  |     avr->mixing_needed     = avr->downmix_needed || avr->upmix_needed; | ||||||
|  | 
 | ||||||
|  |     /* set resampling parameters */ | ||||||
|  |     avr->resample_needed   = avr->in_sample_rate != avr->out_sample_rate || | ||||||
|  |                              avr->force_resampling; | ||||||
|  | 
 | ||||||
|  |     /* set sample format conversion parameters */ | ||||||
|  |     /* override user-requested internal format to avoid unexpected failures
 | ||||||
|  |        TODO: support more internal formats */ | ||||||
|  |     if (avr->resample_needed && avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P) { | ||||||
|  |         av_log(avr, AV_LOG_WARNING, "Using s16p as internal sample format\n"); | ||||||
|  |         avr->internal_sample_fmt = AV_SAMPLE_FMT_S16P; | ||||||
|  |     } else if (avr->mixing_needed && | ||||||
|  |                avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P && | ||||||
|  |                avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) { | ||||||
|  |         av_log(avr, AV_LOG_WARNING, "Using fltp as internal sample format\n"); | ||||||
|  |         avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; | ||||||
|  |     } | ||||||
|  |     if (avr->in_channels == 1) | ||||||
|  |         avr->in_sample_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt); | ||||||
|  |     if (avr->out_channels == 1) | ||||||
|  |         avr->out_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); | ||||||
|  |     avr->in_convert_needed = (avr->resample_needed || avr->mixing_needed) && | ||||||
|  |                               avr->in_sample_fmt != avr->internal_sample_fmt; | ||||||
|  |     if (avr->resample_needed || avr->mixing_needed) | ||||||
|  |         avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt; | ||||||
|  |     else | ||||||
|  |         avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt; | ||||||
|  | 
 | ||||||
|  |     /* allocate buffers */ | ||||||
|  |     if (avr->mixing_needed || avr->in_convert_needed) { | ||||||
|  |         avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels), | ||||||
|  |                                              0, avr->internal_sample_fmt, | ||||||
|  |                                              "in_buffer"); | ||||||
|  |         if (!avr->in_buffer) { | ||||||
|  |             ret = AVERROR(EINVAL); | ||||||
|  |             goto error; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (avr->resample_needed) { | ||||||
|  |         avr->resample_out_buffer = ff_audio_data_alloc(avr->out_channels, | ||||||
|  |                                                        0, avr->internal_sample_fmt, | ||||||
|  |                                                        "resample_out_buffer"); | ||||||
|  |         if (!avr->resample_out_buffer) { | ||||||
|  |             ret = AVERROR(EINVAL); | ||||||
|  |             goto error; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (avr->out_convert_needed) { | ||||||
|  |         avr->out_buffer = ff_audio_data_alloc(avr->out_channels, 0, | ||||||
|  |                                               avr->out_sample_fmt, "out_buffer"); | ||||||
|  |         if (!avr->out_buffer) { | ||||||
|  |             ret = AVERROR(EINVAL); | ||||||
|  |             goto error; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     avr->out_fifo = av_audio_fifo_alloc(avr->out_sample_fmt, avr->out_channels, | ||||||
|  |                                         1024); | ||||||
|  |     if (!avr->out_fifo) { | ||||||
|  |         ret = AVERROR(ENOMEM); | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* setup contexts */ | ||||||
|  |     if (avr->in_convert_needed) { | ||||||
|  |         avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt, | ||||||
|  |                                             avr->in_sample_fmt, avr->in_channels); | ||||||
|  |         if (!avr->ac_in) { | ||||||
|  |             ret = AVERROR(ENOMEM); | ||||||
|  |             goto error; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (avr->out_convert_needed) { | ||||||
|  |         enum AVSampleFormat src_fmt; | ||||||
|  |         if (avr->in_convert_needed) | ||||||
|  |             src_fmt = avr->internal_sample_fmt; | ||||||
|  |         else | ||||||
|  |             src_fmt = avr->in_sample_fmt; | ||||||
|  |         avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt, | ||||||
|  |                                              avr->out_channels); | ||||||
|  |         if (!avr->ac_out) { | ||||||
|  |             ret = AVERROR(ENOMEM); | ||||||
|  |             goto error; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (avr->resample_needed) { | ||||||
|  |         avr->resample = ff_audio_resample_init(avr); | ||||||
|  |         if (!avr->resample) { | ||||||
|  |             ret = AVERROR(ENOMEM); | ||||||
|  |             goto error; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (avr->mixing_needed) { | ||||||
|  |         ret = ff_audio_mix_init(avr); | ||||||
|  |         if (ret < 0) | ||||||
|  |             goto error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | 
 | ||||||
|  | error: | ||||||
|  |     avresample_close(avr); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void avresample_close(AVAudioResampleContext *avr) | ||||||
|  | { | ||||||
|  |     ff_audio_data_free(&avr->in_buffer); | ||||||
|  |     ff_audio_data_free(&avr->resample_out_buffer); | ||||||
|  |     ff_audio_data_free(&avr->out_buffer); | ||||||
|  |     av_audio_fifo_free(avr->out_fifo); | ||||||
|  |     avr->out_fifo = NULL; | ||||||
|  |     av_freep(&avr->ac_in); | ||||||
|  |     av_freep(&avr->ac_out); | ||||||
|  |     ff_audio_resample_free(&avr->resample); | ||||||
|  |     ff_audio_mix_close(avr->am); | ||||||
|  |     return; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void avresample_free(AVAudioResampleContext **avr) | ||||||
|  | { | ||||||
|  |     if (!*avr) | ||||||
|  |         return; | ||||||
|  |     avresample_close(*avr); | ||||||
|  |     av_freep(&(*avr)->am); | ||||||
|  |     av_opt_free(*avr); | ||||||
|  |     av_freep(avr); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int handle_buffered_output(AVAudioResampleContext *avr, | ||||||
|  |                                   AudioData *output, AudioData *converted) | ||||||
|  | { | ||||||
|  |     int ret; | ||||||
|  | 
 | ||||||
|  |     if (!output || av_audio_fifo_size(avr->out_fifo) > 0 || | ||||||
|  |         (converted && output->allocated_samples < converted->nb_samples)) { | ||||||
|  |         if (converted) { | ||||||
|  |             /* if there are any samples in the output FIFO or if the
 | ||||||
|  |                user-supplied output buffer is not large enough for all samples, | ||||||
|  |                we add to the output FIFO */ | ||||||
|  |             av_dlog(avr, "[FIFO] add %s to out_fifo\n", converted->name); | ||||||
|  |             ret = ff_audio_data_add_to_fifo(avr->out_fifo, converted, 0, | ||||||
|  |                                             converted->nb_samples); | ||||||
|  |             if (ret < 0) | ||||||
|  |                 return ret; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /* if the user specified an output buffer, read samples from the output
 | ||||||
|  |            FIFO to the user output */ | ||||||
|  |         if (output && output->allocated_samples > 0) { | ||||||
|  |             av_dlog(avr, "[FIFO] read from out_fifo to output\n"); | ||||||
|  |             av_dlog(avr, "[end conversion]\n"); | ||||||
|  |             return ff_audio_data_read_from_fifo(avr->out_fifo, output, | ||||||
|  |                                                 output->allocated_samples); | ||||||
|  |         } | ||||||
|  |     } else if (converted) { | ||||||
|  |         /* copy directly to output if it is large enough or there is not any
 | ||||||
|  |            data in the output FIFO */ | ||||||
|  |         av_dlog(avr, "[copy] %s to output\n", converted->name); | ||||||
|  |         output->nb_samples = 0; | ||||||
|  |         ret = ff_audio_data_copy(output, converted); | ||||||
|  |         if (ret < 0) | ||||||
|  |             return ret; | ||||||
|  |         av_dlog(avr, "[end conversion]\n"); | ||||||
|  |         return output->nb_samples; | ||||||
|  |     } | ||||||
|  |     av_dlog(avr, "[end conversion]\n"); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int avresample_convert(AVAudioResampleContext *avr, void **output, | ||||||
|  |                        int out_plane_size, int out_samples, void **input, | ||||||
|  |                        int in_plane_size, int in_samples) | ||||||
|  | { | ||||||
|  |     AudioData input_buffer; | ||||||
|  |     AudioData output_buffer; | ||||||
|  |     AudioData *current_buffer; | ||||||
|  |     int ret; | ||||||
|  | 
 | ||||||
|  |     /* reset internal buffers */ | ||||||
|  |     if (avr->in_buffer) { | ||||||
|  |         avr->in_buffer->nb_samples = 0; | ||||||
|  |         ff_audio_data_set_channels(avr->in_buffer, | ||||||
|  |                                    avr->in_buffer->allocated_channels); | ||||||
|  |     } | ||||||
|  |     if (avr->resample_out_buffer) { | ||||||
|  |         avr->resample_out_buffer->nb_samples = 0; | ||||||
|  |         ff_audio_data_set_channels(avr->resample_out_buffer, | ||||||
|  |                                    avr->resample_out_buffer->allocated_channels); | ||||||
|  |     } | ||||||
|  |     if (avr->out_buffer) { | ||||||
|  |         avr->out_buffer->nb_samples = 0; | ||||||
|  |         ff_audio_data_set_channels(avr->out_buffer, | ||||||
|  |                                    avr->out_buffer->allocated_channels); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     av_dlog(avr, "[start conversion]\n"); | ||||||
|  | 
 | ||||||
|  |     /* initialize output_buffer with output data */ | ||||||
|  |     if (output) { | ||||||
|  |         ret = ff_audio_data_init(&output_buffer, output, out_plane_size, | ||||||
|  |                                  avr->out_channels, out_samples, | ||||||
|  |                                  avr->out_sample_fmt, 0, "output"); | ||||||
|  |         if (ret < 0) | ||||||
|  |             return ret; | ||||||
|  |         output_buffer.nb_samples = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (input) { | ||||||
|  |         /* initialize input_buffer with input data */ | ||||||
|  |         ret = ff_audio_data_init(&input_buffer, input, in_plane_size, | ||||||
|  |                                  avr->in_channels, in_samples, | ||||||
|  |                                  avr->in_sample_fmt, 1, "input"); | ||||||
|  |         if (ret < 0) | ||||||
|  |             return ret; | ||||||
|  |         current_buffer = &input_buffer; | ||||||
|  | 
 | ||||||
|  |         if (avr->upmix_needed && !avr->in_convert_needed && !avr->resample_needed && | ||||||
|  |             !avr->out_convert_needed && output && out_samples >= in_samples) { | ||||||
|  |             /* in some rare cases we can copy input to output and upmix
 | ||||||
|  |                directly in the output buffer */ | ||||||
|  |             av_dlog(avr, "[copy] %s to output\n", current_buffer->name); | ||||||
|  |             ret = ff_audio_data_copy(&output_buffer, current_buffer); | ||||||
|  |             if (ret < 0) | ||||||
|  |                 return ret; | ||||||
|  |             current_buffer = &output_buffer; | ||||||
|  |         } else if (avr->mixing_needed || avr->in_convert_needed) { | ||||||
|  |             /* if needed, copy or convert input to in_buffer, and downmix if
 | ||||||
|  |                applicable */ | ||||||
|  |             if (avr->in_convert_needed) { | ||||||
|  |                 ret = ff_audio_data_realloc(avr->in_buffer, | ||||||
|  |                                             current_buffer->nb_samples); | ||||||
|  |                 if (ret < 0) | ||||||
|  |                     return ret; | ||||||
|  |                 av_dlog(avr, "[convert] %s to in_buffer\n", current_buffer->name); | ||||||
|  |                 ret = ff_audio_convert(avr->ac_in, avr->in_buffer, current_buffer, | ||||||
|  |                                        current_buffer->nb_samples); | ||||||
|  |                 if (ret < 0) | ||||||
|  |                     return ret; | ||||||
|  |             } else { | ||||||
|  |                 av_dlog(avr, "[copy] %s to in_buffer\n", current_buffer->name); | ||||||
|  |                 ret = ff_audio_data_copy(avr->in_buffer, current_buffer); | ||||||
|  |                 if (ret < 0) | ||||||
|  |                     return ret; | ||||||
|  |             } | ||||||
|  |             ff_audio_data_set_channels(avr->in_buffer, avr->in_channels); | ||||||
|  |             if (avr->downmix_needed) { | ||||||
|  |                 av_dlog(avr, "[downmix] in_buffer\n"); | ||||||
|  |                 ret = ff_audio_mix(avr->am, avr->in_buffer); | ||||||
|  |                 if (ret < 0) | ||||||
|  |                     return ret; | ||||||
|  |             } | ||||||
|  |             current_buffer = avr->in_buffer; | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         /* flush resampling buffer and/or output FIFO if input is NULL */ | ||||||
|  |         if (!avr->resample_needed) | ||||||
|  |             return handle_buffered_output(avr, output ? &output_buffer : NULL, | ||||||
|  |                                           NULL); | ||||||
|  |         current_buffer = NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (avr->resample_needed) { | ||||||
|  |         AudioData *resample_out; | ||||||
|  |         int consumed = 0; | ||||||
|  | 
 | ||||||
|  |         if (!avr->out_convert_needed && output && out_samples > 0) | ||||||
|  |             resample_out = &output_buffer; | ||||||
|  |         else | ||||||
|  |             resample_out = avr->resample_out_buffer; | ||||||
|  |         av_dlog(avr, "[resample] %s to %s\n", current_buffer->name, | ||||||
|  |                 resample_out->name); | ||||||
|  |         ret = ff_audio_resample(avr->resample, resample_out, | ||||||
|  |                                 current_buffer, &consumed); | ||||||
|  |         if (ret < 0) | ||||||
|  |             return ret; | ||||||
|  | 
 | ||||||
|  |         /* if resampling did not produce any samples, just return 0 */ | ||||||
|  |         if (resample_out->nb_samples == 0) { | ||||||
|  |             av_dlog(avr, "[end conversion]\n"); | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         current_buffer = resample_out; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (avr->upmix_needed) { | ||||||
|  |         av_dlog(avr, "[upmix] %s\n", current_buffer->name); | ||||||
|  |         ret = ff_audio_mix(avr->am, current_buffer); | ||||||
|  |         if (ret < 0) | ||||||
|  |             return ret; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* if we resampled or upmixed directly to output, return here */ | ||||||
|  |     if (current_buffer == &output_buffer) { | ||||||
|  |         av_dlog(avr, "[end conversion]\n"); | ||||||
|  |         return current_buffer->nb_samples; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (avr->out_convert_needed) { | ||||||
|  |         if (output && out_samples >= current_buffer->nb_samples) { | ||||||
|  |             /* convert directly to output */ | ||||||
|  |             av_dlog(avr, "[convert] %s to output\n", current_buffer->name); | ||||||
|  |             ret = ff_audio_convert(avr->ac_out, &output_buffer, current_buffer, | ||||||
|  |                                    current_buffer->nb_samples); | ||||||
|  |             if (ret < 0) | ||||||
|  |                 return ret; | ||||||
|  | 
 | ||||||
|  |             av_dlog(avr, "[end conversion]\n"); | ||||||
|  |             return output_buffer.nb_samples; | ||||||
|  |         } else { | ||||||
|  |             ret = ff_audio_data_realloc(avr->out_buffer, | ||||||
|  |                                         current_buffer->nb_samples); | ||||||
|  |             if (ret < 0) | ||||||
|  |                 return ret; | ||||||
|  |             av_dlog(avr, "[convert] %s to out_buffer\n", current_buffer->name); | ||||||
|  |             ret = ff_audio_convert(avr->ac_out, avr->out_buffer, | ||||||
|  |                                    current_buffer, current_buffer->nb_samples); | ||||||
|  |             if (ret < 0) | ||||||
|  |                 return ret; | ||||||
|  |             current_buffer = avr->out_buffer; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return handle_buffered_output(avr, &output_buffer, current_buffer); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int avresample_available(AVAudioResampleContext *avr) | ||||||
|  | { | ||||||
|  |     return av_audio_fifo_size(avr->out_fifo); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int avresample_read(AVAudioResampleContext *avr, void **output, int nb_samples) | ||||||
|  | { | ||||||
|  |     return av_audio_fifo_read(avr->out_fifo, output, nb_samples); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | unsigned avresample_version(void) | ||||||
|  | { | ||||||
|  |     return LIBAVRESAMPLE_VERSION_INT; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char *avresample_license(void) | ||||||
|  | { | ||||||
|  | #define LICENSE_PREFIX "libavresample license: " | ||||||
|  |     return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char *avresample_configuration(void) | ||||||
|  | { | ||||||
|  |     return FFMPEG_CONFIGURATION; | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								libavresample/version.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								libavresample/version.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | /*
 | ||||||
|  |  * 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 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef AVRESAMPLE_VERSION_H | ||||||
|  | #define AVRESAMPLE_VERSION_H | ||||||
|  | 
 | ||||||
|  | #define LIBAVRESAMPLE_VERSION_MAJOR  0 | ||||||
|  | #define LIBAVRESAMPLE_VERSION_MINOR  0 | ||||||
|  | #define LIBAVRESAMPLE_VERSION_MICRO  0 | ||||||
|  | 
 | ||||||
|  | #define LIBAVRESAMPLE_VERSION_INT  AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR, \ | ||||||
|  |                                                   LIBAVRESAMPLE_VERSION_MINOR, \ | ||||||
|  |                                                   LIBAVRESAMPLE_VERSION_MICRO) | ||||||
|  | #define LIBAVRESAMPLE_VERSION          AV_VERSION(LIBAVRESAMPLE_VERSION_MAJOR, \ | ||||||
|  |                                                   LIBAVRESAMPLE_VERSION_MINOR, \ | ||||||
|  |                                                   LIBAVRESAMPLE_VERSION_MICRO) | ||||||
|  | #define LIBAVRESAMPLE_BUILD        LIBAVRESAMPLE_VERSION_INT | ||||||
|  | 
 | ||||||
|  | #define LIBAVRESAMPLE_IDENT        "Lavr" AV_STRINGIFY(LIBAVRESAMPLE_VERSION) | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * These FF_API_* defines are not part of public API. | ||||||
|  |  * They may change, break or disappear at any time. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #endif /* AVRESAMPLE_VERSION_H */ | ||||||
							
								
								
									
										5
									
								
								libavresample/x86/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								libavresample/x86/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | OBJS      += x86/audio_convert_init.o                                   \
 | ||||||
|  |              x86/audio_mix_init.o | ||||||
|  | 
 | ||||||
|  | YASM-OBJS += x86/audio_convert.o                                        \
 | ||||||
|  |              x86/audio_mix.o | ||||||
							
								
								
									
										104
									
								
								libavresample/x86/audio_convert.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								libavresample/x86/audio_convert.asm
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | |||||||
|  | ;****************************************************************************** | ||||||
|  | ;* x86 optimized Format Conversion Utils | ||||||
|  | ;* Copyright (c) 2008 Loren Merritt | ||||||
|  | ;* | ||||||
|  | ;* 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 "x86inc.asm" | ||||||
|  | %include "x86util.asm" | ||||||
|  | 
 | ||||||
|  | SECTION_TEXT | ||||||
|  | 
 | ||||||
|  | ;----------------------------------------------------------------------------- | ||||||
|  | ; void ff_conv_fltp_to_flt_6ch(float *dst, float *const *src, int len, | ||||||
|  | ;                              int channels); | ||||||
|  | ;----------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | %macro CONV_FLTP_TO_FLT_6CH 0 | ||||||
|  | cglobal conv_fltp_to_flt_6ch, 2,8,7, dst, src, src1, src2, src3, src4, src5, len | ||||||
|  | %if ARCH_X86_64 | ||||||
|  |     mov     lend, r2d | ||||||
|  | %else | ||||||
|  |     %define lend dword r2m | ||||||
|  | %endif | ||||||
|  |     mov    src1q, [srcq+1*gprsize] | ||||||
|  |     mov    src2q, [srcq+2*gprsize] | ||||||
|  |     mov    src3q, [srcq+3*gprsize] | ||||||
|  |     mov    src4q, [srcq+4*gprsize] | ||||||
|  |     mov    src5q, [srcq+5*gprsize] | ||||||
|  |     mov     srcq, [srcq] | ||||||
|  |     sub    src1q, srcq | ||||||
|  |     sub    src2q, srcq | ||||||
|  |     sub    src3q, srcq | ||||||
|  |     sub    src4q, srcq | ||||||
|  |     sub    src5q, srcq | ||||||
|  | .loop: | ||||||
|  |     mova      m0, [srcq      ] | ||||||
|  |     mova      m1, [srcq+src1q] | ||||||
|  |     mova      m2, [srcq+src2q] | ||||||
|  |     mova      m3, [srcq+src3q] | ||||||
|  |     mova      m4, [srcq+src4q] | ||||||
|  |     mova      m5, [srcq+src5q] | ||||||
|  | %if cpuflag(sse) | ||||||
|  |     SBUTTERFLYPS 0, 1, 6 | ||||||
|  |     SBUTTERFLYPS 2, 3, 6 | ||||||
|  |     SBUTTERFLYPS 4, 5, 6 | ||||||
|  | 
 | ||||||
|  |     movaps    m6, m4 | ||||||
|  |     shufps    m4, m0, q3210 | ||||||
|  |     movlhps   m0, m2 | ||||||
|  |     movhlps   m6, m2 | ||||||
|  |     movaps [dstq   ], m0 | ||||||
|  |     movaps [dstq+16], m4 | ||||||
|  |     movaps [dstq+32], m6 | ||||||
|  | 
 | ||||||
|  |     movaps    m6, m5 | ||||||
|  |     shufps    m5, m1, q3210 | ||||||
|  |     movlhps   m1, m3 | ||||||
|  |     movhlps   m6, m3 | ||||||
|  |     movaps [dstq+48], m1 | ||||||
|  |     movaps [dstq+64], m5 | ||||||
|  |     movaps [dstq+80], m6 | ||||||
|  | %else ; mmx | ||||||
|  |     SBUTTERFLY dq, 0, 1, 6 | ||||||
|  |     SBUTTERFLY dq, 2, 3, 6 | ||||||
|  |     SBUTTERFLY dq, 4, 5, 6 | ||||||
|  | 
 | ||||||
|  |     movq   [dstq   ], m0 | ||||||
|  |     movq   [dstq+ 8], m2 | ||||||
|  |     movq   [dstq+16], m4 | ||||||
|  |     movq   [dstq+24], m1 | ||||||
|  |     movq   [dstq+32], m3 | ||||||
|  |     movq   [dstq+40], m5 | ||||||
|  | %endif | ||||||
|  |     add      srcq, mmsize | ||||||
|  |     add      dstq, mmsize*6 | ||||||
|  |     sub      lend, mmsize/4 | ||||||
|  |     jg .loop | ||||||
|  | %if mmsize == 8 | ||||||
|  |     emms | ||||||
|  |     RET | ||||||
|  | %else | ||||||
|  |     REP_RET | ||||||
|  | %endif | ||||||
|  | %endmacro | ||||||
|  | 
 | ||||||
|  | INIT_MMX mmx | ||||||
|  | CONV_FLTP_TO_FLT_6CH | ||||||
|  | INIT_XMM sse | ||||||
|  | CONV_FLTP_TO_FLT_6CH | ||||||
							
								
								
									
										42
									
								
								libavresample/x86/audio_convert_init.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								libavresample/x86/audio_convert_init.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 "config.h" | ||||||
|  | #include "libavutil/cpu.h" | ||||||
|  | #include "libavresample/audio_convert.h" | ||||||
|  | 
 | ||||||
|  | extern void ff_conv_fltp_to_flt_6ch_mmx(float *dst, float *const *src, int len); | ||||||
|  | extern void ff_conv_fltp_to_flt_6ch_sse(float *dst, float *const *src, int len); | ||||||
|  | 
 | ||||||
|  | av_cold void ff_audio_convert_init_x86(AudioConvert *ac) | ||||||
|  | { | ||||||
|  | #if HAVE_YASM | ||||||
|  |     int mm_flags = av_get_cpu_flags(); | ||||||
|  | 
 | ||||||
|  |     if (mm_flags & AV_CPU_FLAG_MMX && HAVE_MMX) { | ||||||
|  |         ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, | ||||||
|  |                                   6, 1, 4, "MMX", ff_conv_fltp_to_flt_6ch_mmx); | ||||||
|  |     } | ||||||
|  |     if (mm_flags & AV_CPU_FLAG_SSE && HAVE_SSE) { | ||||||
|  |         ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, | ||||||
|  |                                   6, 16, 4, "SSE", ff_conv_fltp_to_flt_6ch_sse); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | } | ||||||
							
								
								
									
										64
									
								
								libavresample/x86/audio_mix.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								libavresample/x86/audio_mix.asm
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | |||||||
|  | ;****************************************************************************** | ||||||
|  | ;* x86 optimized channel mixing | ||||||
|  | ;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  | ;* | ||||||
|  | ;* 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 "x86inc.asm" | ||||||
|  | %include "x86util.asm" | ||||||
|  | 
 | ||||||
|  | SECTION_TEXT | ||||||
|  | 
 | ||||||
|  | ;----------------------------------------------------------------------------- | ||||||
|  | ; void ff_mix_2_to_1_fltp_flt(float **src, float **matrix, int len, | ||||||
|  | ;                             int out_ch, int in_ch); | ||||||
|  | ;----------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | %macro MIX_2_TO_1_FLTP_FLT 0 | ||||||
|  | cglobal mix_2_to_1_fltp_flt, 3,4,6, src, matrix, len, src1 | ||||||
|  |     mov       src1q, [srcq+gprsize] | ||||||
|  |     mov        srcq, [srcq        ] | ||||||
|  |     sub       src1q, srcq | ||||||
|  |     mov     matrixq, [matrixq  ] | ||||||
|  |     VBROADCASTSS m4, [matrixq  ] | ||||||
|  |     VBROADCASTSS m5, [matrixq+4] | ||||||
|  |     ALIGN 16 | ||||||
|  | .loop: | ||||||
|  |     mulps        m0, m4, [srcq             ] | ||||||
|  |     mulps        m1, m5, [srcq+src1q       ] | ||||||
|  |     mulps        m2, m4, [srcq+      mmsize] | ||||||
|  |     mulps        m3, m5, [srcq+src1q+mmsize] | ||||||
|  |     addps        m0, m0, m1 | ||||||
|  |     addps        m2, m2, m3 | ||||||
|  |     mova  [srcq       ], m0 | ||||||
|  |     mova  [srcq+mmsize], m2 | ||||||
|  |     add        srcq, mmsize*2 | ||||||
|  |     sub        lend, mmsize*2/4 | ||||||
|  |     jg .loop | ||||||
|  | %if mmsize == 32 | ||||||
|  |     vzeroupper | ||||||
|  |     RET | ||||||
|  | %else | ||||||
|  |     REP_RET | ||||||
|  | %endif | ||||||
|  | %endmacro | ||||||
|  | 
 | ||||||
|  | INIT_XMM sse | ||||||
|  | MIX_2_TO_1_FLTP_FLT | ||||||
|  | INIT_YMM avx | ||||||
|  | MIX_2_TO_1_FLTP_FLT | ||||||
							
								
								
									
										44
									
								
								libavresample/x86/audio_mix_init.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								libavresample/x86/audio_mix_init.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||||||
|  |  * | ||||||
|  |  * 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 "config.h" | ||||||
|  | #include "libavutil/cpu.h" | ||||||
|  | #include "libavresample/audio_mix.h" | ||||||
|  | 
 | ||||||
|  | extern void ff_mix_2_to_1_fltp_flt_sse(float **src, float **matrix, int len, | ||||||
|  |                                        int out_ch, int in_ch); | ||||||
|  | extern void ff_mix_2_to_1_fltp_flt_avx(float **src, float **matrix, int len, | ||||||
|  |                                        int out_ch, int in_ch); | ||||||
|  | 
 | ||||||
|  | av_cold void ff_audio_mix_init_x86(AudioMix *am) | ||||||
|  | { | ||||||
|  | #if HAVE_YASM | ||||||
|  |     int mm_flags = av_get_cpu_flags(); | ||||||
|  | 
 | ||||||
|  |     if (mm_flags & AV_CPU_FLAG_SSE && HAVE_SSE) { | ||||||
|  |         ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||||||
|  |                               2, 1, 16, 8, "SSE", ff_mix_2_to_1_fltp_flt_sse); | ||||||
|  |     } | ||||||
|  |     if (mm_flags & AV_CPU_FLAG_AVX && HAVE_AVX) { | ||||||
|  |         ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||||||
|  |                               2, 1, 32, 16, "AVX", ff_mix_2_to_1_fltp_flt_avx); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | } | ||||||
| @ -585,3 +585,12 @@ | |||||||
|     pminsd  %1, %3 |     pminsd  %1, %3 | ||||||
|     pmaxsd  %1, %2 |     pmaxsd  %1, %2 | ||||||
| %endmacro | %endmacro | ||||||
|  | 
 | ||||||
|  | %macro VBROADCASTSS 2 ; dst xmm/ymm, src m32 | ||||||
|  | %if cpuflag(avx) | ||||||
|  |     vbroadcastss %1, %2 | ||||||
|  | %else ; sse | ||||||
|  |     movss        %1, %2 | ||||||
|  |     shufps       %1, %1, 0 | ||||||
|  | %endif | ||||||
|  | %endmacro | ||||||
|  | |||||||
| @ -55,8 +55,8 @@ fate-aac-ap05_48: CMD = pcm -i $(SAMPLES)/aac/ap05_48.mp4 | |||||||
| fate-aac-ap05_48: REF = $(SAMPLES)/aac/ap05_48.s16 | fate-aac-ap05_48: REF = $(SAMPLES)/aac/ap05_48.s16 | ||||||
| 
 | 
 | ||||||
| FATE_AAC += fate-aac-latm_stereo_to_51 | FATE_AAC += fate-aac-latm_stereo_to_51 | ||||||
| fate-aac-latm_stereo_to_51: CMD = pcm -i $(SAMPLES)/aac/latm_stereo_to_51.ts -ac 6 | fate-aac-latm_stereo_to_51: CMD = pcm -i $(SAMPLES)/aac/latm_stereo_to_51.ts -channel_layout 5.1 | ||||||
| fate-aac-latm_stereo_to_51: REF = $(SAMPLES)/aac/latm_stereo_to_51.s16 | fate-aac-latm_stereo_to_51: REF = $(SAMPLES)/aac/latm_stereo_to_51_ref.s16 | ||||||
| 
 | 
 | ||||||
| fate-aac-ct%: CMD = pcm -i $(SAMPLES)/aac/CT_DecoderCheck/$(@:fate-aac-ct-%=%) | fate-aac-ct%: CMD = pcm -i $(SAMPLES)/aac/CT_DecoderCheck/$(@:fate-aac-ct-%=%) | ||||||
| fate-aac-ct%: REF = $(SAMPLES)/aac/CT_DecoderCheck/aacPlusv2.wav | fate-aac-ct%: REF = $(SAMPLES)/aac/CT_DecoderCheck/aacPlusv2.wav | ||||||
|  | |||||||
| @ -118,7 +118,7 @@ fi | |||||||
| if [ -n "$do_dv_fmt" ] ; then | if [ -n "$do_dv_fmt" ] ; then | ||||||
| do_lavf_timecode_nodrop dv "-ar 48000 -r 25 -s pal -ac 2" | do_lavf_timecode_nodrop dv "-ar 48000 -r 25 -s pal -ac 2" | ||||||
| do_lavf_timecode_drop   dv "-ar 48000 -pix_fmt yuv411p -s ntsc -ac 2" | do_lavf_timecode_drop   dv "-ar 48000 -pix_fmt yuv411p -s ntsc -ac 2" | ||||||
| do_lavf dv "-ar 48000" "-r 25 -s pal -ac 2" | do_lavf dv "-ar 48000 -channel_layout stereo" "-r 25 -s pal" | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| if [ -n "$do_gxf" ] ; then | if [ -n "$do_gxf" ] ; then | ||||||
|  | |||||||
| @ -4,6 +4,6 @@ | |||||||
| cc33ae4f9e6828914dea0f09d1241b7e *./tests/data/lavf/lavf.dv | cc33ae4f9e6828914dea0f09d1241b7e *./tests/data/lavf/lavf.dv | ||||||
| 3480000 ./tests/data/lavf/lavf.dv | 3480000 ./tests/data/lavf/lavf.dv | ||||||
| ./tests/data/lavf/lavf.dv CRC=0x8d5e9e8f | ./tests/data/lavf/lavf.dv CRC=0x8d5e9e8f | ||||||
| b36c83cd0ba0ebe719f09f885c4bbcd3 *./tests/data/lavf/lavf.dv | 87d3b20f656235671383a7eaa2f66330 *./tests/data/lavf/lavf.dv | ||||||
| 3600000 ./tests/data/lavf/lavf.dv | 3600000 ./tests/data/lavf/lavf.dv | ||||||
| ./tests/data/lavf/lavf.dv CRC=0x2bc2ae3a | ./tests/data/lavf/lavf.dv CRC=0x0e868a82 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user