/contrib/sdk/sources/ffmpeg/libavresample/Makefile |
---|
0,0 → 1,16 |
NAME = avresample |
FFLIBS = avutil |
HEADERS = avresample.h \ |
version.h \ |
OBJS = audio_convert.o \ |
audio_data.o \ |
audio_mix.o \ |
audio_mix_matrix.o \ |
dither.o \ |
options.o \ |
resample.o \ |
utils.o \ |
TESTPROGS = avresample |
/contrib/sdk/sources/ffmpeg/libavresample/arm/Makefile |
---|
0,0 → 1,2 |
OBJS += arm/audio_convert_init.o |
NEON-OBJS += arm/audio_convert_neon.o |
/contrib/sdk/sources/ffmpeg/libavresample/arm/audio_convert_init.c |
---|
0,0 → 1,49 |
/* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include <stdint.h> |
#include "config.h" |
#include "libavutil/attributes.h" |
#include "libavutil/cpu.h" |
#include "libavutil/arm/cpu.h" |
#include "libavutil/samplefmt.h" |
#include "libavresample/audio_convert.h" |
void ff_conv_flt_to_s16_neon(int16_t *dst, const float *src, int len); |
void ff_conv_fltp_to_s16_neon(int16_t *dst, float *const *src, |
int len, int channels); |
void ff_conv_fltp_to_s16_2ch_neon(int16_t *dst, float *const *src, |
int len, int channels); |
av_cold void ff_audio_convert_init_arm(AudioConvert *ac) |
{ |
int cpu_flags = av_get_cpu_flags(); |
if (have_neon(cpu_flags)) { |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT, |
0, 16, 8, "NEON", |
ff_conv_flt_to_s16_neon); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, |
0, 16, 8, "NEON", |
ff_conv_fltp_to_s16_neon); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, |
2, 16, 8, "NEON", |
ff_conv_fltp_to_s16_2ch_neon); |
} |
} |
/contrib/sdk/sources/ffmpeg/libavresample/arm/audio_convert_neon.S |
---|
0,0 → 1,363 |
/* |
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com> |
* |
* This file is part of FFmpeg |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include "config.h" |
#include "libavutil/arm/asm.S" |
function ff_conv_flt_to_s16_neon, export=1 |
subs r2, r2, #8 |
vld1.32 {q0}, [r1,:128]! |
vcvt.s32.f32 q8, q0, #31 |
vld1.32 {q1}, [r1,:128]! |
vcvt.s32.f32 q9, q1, #31 |
beq 3f |
bics r12, r2, #15 |
beq 2f |
1: subs r12, r12, #16 |
vqrshrn.s32 d4, q8, #16 |
vld1.32 {q0}, [r1,:128]! |
vcvt.s32.f32 q0, q0, #31 |
vqrshrn.s32 d5, q9, #16 |
vld1.32 {q1}, [r1,:128]! |
vcvt.s32.f32 q1, q1, #31 |
vqrshrn.s32 d6, q0, #16 |
vst1.16 {q2}, [r0,:128]! |
vqrshrn.s32 d7, q1, #16 |
vld1.32 {q8}, [r1,:128]! |
vcvt.s32.f32 q8, q8, #31 |
vld1.32 {q9}, [r1,:128]! |
vcvt.s32.f32 q9, q9, #31 |
vst1.16 {q3}, [r0,:128]! |
bne 1b |
ands r2, r2, #15 |
beq 3f |
2: vld1.32 {q0}, [r1,:128]! |
vqrshrn.s32 d4, q8, #16 |
vcvt.s32.f32 q0, q0, #31 |
vld1.32 {q1}, [r1,:128]! |
vqrshrn.s32 d5, q9, #16 |
vcvt.s32.f32 q1, q1, #31 |
vqrshrn.s32 d6, q0, #16 |
vst1.16 {q2}, [r0,:128]! |
vqrshrn.s32 d7, q1, #16 |
vst1.16 {q3}, [r0,:128]! |
bx lr |
3: vqrshrn.s32 d4, q8, #16 |
vqrshrn.s32 d5, q9, #16 |
vst1.16 {q2}, [r0,:128]! |
bx lr |
endfunc |
function ff_conv_fltp_to_s16_2ch_neon, export=1 |
ldm r1, {r1, r3} |
subs r2, r2, #8 |
vld1.32 {q0}, [r1,:128]! |
vcvt.s32.f32 q8, q0, #31 |
vld1.32 {q1}, [r1,:128]! |
vcvt.s32.f32 q9, q1, #31 |
vld1.32 {q10}, [r3,:128]! |
vcvt.s32.f32 q10, q10, #31 |
vld1.32 {q11}, [r3,:128]! |
vcvt.s32.f32 q11, q11, #31 |
beq 3f |
bics r12, r2, #15 |
beq 2f |
1: subs r12, r12, #16 |
vld1.32 {q0}, [r1,:128]! |
vcvt.s32.f32 q0, q0, #31 |
vsri.32 q10, q8, #16 |
vld1.32 {q1}, [r1,:128]! |
vcvt.s32.f32 q1, q1, #31 |
vld1.32 {q12}, [r3,:128]! |
vcvt.s32.f32 q12, q12, #31 |
vld1.32 {q13}, [r3,:128]! |
vsri.32 q11, q9, #16 |
vst1.16 {q10}, [r0,:128]! |
vcvt.s32.f32 q13, q13, #31 |
vst1.16 {q11}, [r0,:128]! |
vsri.32 q12, q0, #16 |
vld1.32 {q8}, [r1,:128]! |
vsri.32 q13, q1, #16 |
vst1.16 {q12}, [r0,:128]! |
vcvt.s32.f32 q8, q8, #31 |
vld1.32 {q9}, [r1,:128]! |
vcvt.s32.f32 q9, q9, #31 |
vld1.32 {q10}, [r3,:128]! |
vcvt.s32.f32 q10, q10, #31 |
vld1.32 {q11}, [r3,:128]! |
vcvt.s32.f32 q11, q11, #31 |
vst1.16 {q13}, [r0,:128]! |
bne 1b |
ands r2, r2, #15 |
beq 3f |
2: vsri.32 q10, q8, #16 |
vld1.32 {q0}, [r1,:128]! |
vcvt.s32.f32 q0, q0, #31 |
vld1.32 {q1}, [r1,:128]! |
vcvt.s32.f32 q1, q1, #31 |
vld1.32 {q12}, [r3,:128]! |
vcvt.s32.f32 q12, q12, #31 |
vsri.32 q11, q9, #16 |
vld1.32 {q13}, [r3,:128]! |
vcvt.s32.f32 q13, q13, #31 |
vst1.16 {q10}, [r0,:128]! |
vsri.32 q12, q0, #16 |
vst1.16 {q11}, [r0,:128]! |
vsri.32 q13, q1, #16 |
vst1.16 {q12-q13},[r0,:128]! |
bx lr |
3: vsri.32 q10, q8, #16 |
vsri.32 q11, q9, #16 |
vst1.16 {q10-q11},[r0,:128]! |
bx lr |
endfunc |
function ff_conv_fltp_to_s16_neon, export=1 |
cmp r3, #2 |
itt lt |
ldrlt r1, [r1] |
blt ff_conv_flt_to_s16_neon |
beq ff_conv_fltp_to_s16_2ch_neon |
push {r4-r8, lr} |
cmp r3, #4 |
lsl r12, r3, #1 |
blt 4f |
@ 4 channels |
5: ldm r1!, {r4-r7} |
mov lr, r2 |
mov r8, r0 |
vld1.32 {q8}, [r4,:128]! |
vcvt.s32.f32 q8, q8, #31 |
vld1.32 {q9}, [r5,:128]! |
vcvt.s32.f32 q9, q9, #31 |
vld1.32 {q10}, [r6,:128]! |
vcvt.s32.f32 q10, q10, #31 |
vld1.32 {q11}, [r7,:128]! |
vcvt.s32.f32 q11, q11, #31 |
6: subs lr, lr, #8 |
vld1.32 {q0}, [r4,:128]! |
vcvt.s32.f32 q0, q0, #31 |
vsri.32 q9, q8, #16 |
vld1.32 {q1}, [r5,:128]! |
vcvt.s32.f32 q1, q1, #31 |
vsri.32 q11, q10, #16 |
vld1.32 {q2}, [r6,:128]! |
vcvt.s32.f32 q2, q2, #31 |
vzip.32 d18, d22 |
vld1.32 {q3}, [r7,:128]! |
vcvt.s32.f32 q3, q3, #31 |
vzip.32 d19, d23 |
vst1.16 {d18}, [r8], r12 |
vsri.32 q1, q0, #16 |
vst1.16 {d22}, [r8], r12 |
vsri.32 q3, q2, #16 |
vst1.16 {d19}, [r8], r12 |
vzip.32 d2, d6 |
vst1.16 {d23}, [r8], r12 |
vzip.32 d3, d7 |
beq 7f |
vld1.32 {q8}, [r4,:128]! |
vcvt.s32.f32 q8, q8, #31 |
vst1.16 {d2}, [r8], r12 |
vld1.32 {q9}, [r5,:128]! |
vcvt.s32.f32 q9, q9, #31 |
vst1.16 {d6}, [r8], r12 |
vld1.32 {q10}, [r6,:128]! |
vcvt.s32.f32 q10, q10, #31 |
vst1.16 {d3}, [r8], r12 |
vld1.32 {q11}, [r7,:128]! |
vcvt.s32.f32 q11, q11, #31 |
vst1.16 {d7}, [r8], r12 |
b 6b |
7: vst1.16 {d2}, [r8], r12 |
vst1.16 {d6}, [r8], r12 |
vst1.16 {d3}, [r8], r12 |
vst1.16 {d7}, [r8], r12 |
subs r3, r3, #4 |
it eq |
popeq {r4-r8, pc} |
cmp r3, #4 |
add r0, r0, #8 |
bge 5b |
@ 2 channels |
4: cmp r3, #2 |
blt 4f |
ldm r1!, {r4-r5} |
mov lr, r2 |
mov r8, r0 |
tst lr, #8 |
vld1.32 {q8}, [r4,:128]! |
vcvt.s32.f32 q8, q8, #31 |
vld1.32 {q9}, [r5,:128]! |
vcvt.s32.f32 q9, q9, #31 |
vld1.32 {q10}, [r4,:128]! |
vcvt.s32.f32 q10, q10, #31 |
vld1.32 {q11}, [r5,:128]! |
vcvt.s32.f32 q11, q11, #31 |
beq 6f |
subs lr, lr, #8 |
beq 7f |
vsri.32 d18, d16, #16 |
vsri.32 d19, d17, #16 |
vld1.32 {q8}, [r4,:128]! |
vcvt.s32.f32 q8, q8, #31 |
vst1.32 {d18[0]}, [r8], r12 |
vsri.32 d22, d20, #16 |
vst1.32 {d18[1]}, [r8], r12 |
vsri.32 d23, d21, #16 |
vst1.32 {d19[0]}, [r8], r12 |
vst1.32 {d19[1]}, [r8], r12 |
vld1.32 {q9}, [r5,:128]! |
vcvt.s32.f32 q9, q9, #31 |
vst1.32 {d22[0]}, [r8], r12 |
vst1.32 {d22[1]}, [r8], r12 |
vld1.32 {q10}, [r4,:128]! |
vcvt.s32.f32 q10, q10, #31 |
vst1.32 {d23[0]}, [r8], r12 |
vst1.32 {d23[1]}, [r8], r12 |
vld1.32 {q11}, [r5,:128]! |
vcvt.s32.f32 q11, q11, #31 |
6: subs lr, lr, #16 |
vld1.32 {q0}, [r4,:128]! |
vcvt.s32.f32 q0, q0, #31 |
vsri.32 d18, d16, #16 |
vld1.32 {q1}, [r5,:128]! |
vcvt.s32.f32 q1, q1, #31 |
vsri.32 d19, d17, #16 |
vld1.32 {q2}, [r4,:128]! |
vcvt.s32.f32 q2, q2, #31 |
vld1.32 {q3}, [r5,:128]! |
vcvt.s32.f32 q3, q3, #31 |
vst1.32 {d18[0]}, [r8], r12 |
vsri.32 d22, d20, #16 |
vst1.32 {d18[1]}, [r8], r12 |
vsri.32 d23, d21, #16 |
vst1.32 {d19[0]}, [r8], r12 |
vsri.32 d2, d0, #16 |
vst1.32 {d19[1]}, [r8], r12 |
vsri.32 d3, d1, #16 |
vst1.32 {d22[0]}, [r8], r12 |
vsri.32 d6, d4, #16 |
vst1.32 {d22[1]}, [r8], r12 |
vsri.32 d7, d5, #16 |
vst1.32 {d23[0]}, [r8], r12 |
vst1.32 {d23[1]}, [r8], r12 |
beq 6f |
vld1.32 {q8}, [r4,:128]! |
vcvt.s32.f32 q8, q8, #31 |
vst1.32 {d2[0]}, [r8], r12 |
vst1.32 {d2[1]}, [r8], r12 |
vld1.32 {q9}, [r5,:128]! |
vcvt.s32.f32 q9, q9, #31 |
vst1.32 {d3[0]}, [r8], r12 |
vst1.32 {d3[1]}, [r8], r12 |
vld1.32 {q10}, [r4,:128]! |
vcvt.s32.f32 q10, q10, #31 |
vst1.32 {d6[0]}, [r8], r12 |
vst1.32 {d6[1]}, [r8], r12 |
vld1.32 {q11}, [r5,:128]! |
vcvt.s32.f32 q11, q11, #31 |
vst1.32 {d7[0]}, [r8], r12 |
vst1.32 {d7[1]}, [r8], r12 |
bgt 6b |
6: vst1.32 {d2[0]}, [r8], r12 |
vst1.32 {d2[1]}, [r8], r12 |
vst1.32 {d3[0]}, [r8], r12 |
vst1.32 {d3[1]}, [r8], r12 |
vst1.32 {d6[0]}, [r8], r12 |
vst1.32 {d6[1]}, [r8], r12 |
vst1.32 {d7[0]}, [r8], r12 |
vst1.32 {d7[1]}, [r8], r12 |
b 8f |
7: vsri.32 d18, d16, #16 |
vsri.32 d19, d17, #16 |
vst1.32 {d18[0]}, [r8], r12 |
vsri.32 d22, d20, #16 |
vst1.32 {d18[1]}, [r8], r12 |
vsri.32 d23, d21, #16 |
vst1.32 {d19[0]}, [r8], r12 |
vst1.32 {d19[1]}, [r8], r12 |
vst1.32 {d22[0]}, [r8], r12 |
vst1.32 {d22[1]}, [r8], r12 |
vst1.32 {d23[0]}, [r8], r12 |
vst1.32 {d23[1]}, [r8], r12 |
8: subs r3, r3, #2 |
add r0, r0, #4 |
it eq |
popeq {r4-r8, pc} |
@ 1 channel |
4: ldr r4, [r1] |
tst r2, #8 |
mov lr, r2 |
mov r5, r0 |
vld1.32 {q0}, [r4,:128]! |
vcvt.s32.f32 q0, q0, #31 |
vld1.32 {q1}, [r4,:128]! |
vcvt.s32.f32 q1, q1, #31 |
bne 8f |
6: subs lr, lr, #16 |
vld1.32 {q2}, [r4,:128]! |
vcvt.s32.f32 q2, q2, #31 |
vld1.32 {q3}, [r4,:128]! |
vcvt.s32.f32 q3, q3, #31 |
vst1.16 {d0[1]}, [r5,:16], r12 |
vst1.16 {d0[3]}, [r5,:16], r12 |
vst1.16 {d1[1]}, [r5,:16], r12 |
vst1.16 {d1[3]}, [r5,:16], r12 |
vst1.16 {d2[1]}, [r5,:16], r12 |
vst1.16 {d2[3]}, [r5,:16], r12 |
vst1.16 {d3[1]}, [r5,:16], r12 |
vst1.16 {d3[3]}, [r5,:16], r12 |
beq 7f |
vld1.32 {q0}, [r4,:128]! |
vcvt.s32.f32 q0, q0, #31 |
vld1.32 {q1}, [r4,:128]! |
vcvt.s32.f32 q1, q1, #31 |
7: vst1.16 {d4[1]}, [r5,:16], r12 |
vst1.16 {d4[3]}, [r5,:16], r12 |
vst1.16 {d5[1]}, [r5,:16], r12 |
vst1.16 {d5[3]}, [r5,:16], r12 |
vst1.16 {d6[1]}, [r5,:16], r12 |
vst1.16 {d6[3]}, [r5,:16], r12 |
vst1.16 {d7[1]}, [r5,:16], r12 |
vst1.16 {d7[3]}, [r5,:16], r12 |
bgt 6b |
pop {r4-r8, pc} |
8: subs lr, lr, #8 |
vst1.16 {d0[1]}, [r5,:16], r12 |
vst1.16 {d0[3]}, [r5,:16], r12 |
vst1.16 {d1[1]}, [r5,:16], r12 |
vst1.16 {d1[3]}, [r5,:16], r12 |
vst1.16 {d2[1]}, [r5,:16], r12 |
vst1.16 {d2[3]}, [r5,:16], r12 |
vst1.16 {d3[1]}, [r5,:16], r12 |
vst1.16 {d3[3]}, [r5,:16], r12 |
it eq |
popeq {r4-r8, pc} |
vld1.32 {q0}, [r4,:128]! |
vcvt.s32.f32 q0, q0, #31 |
vld1.32 {q1}, [r4,:128]! |
vcvt.s32.f32 q1, q1, #31 |
b 6b |
endfunc |
/contrib/sdk/sources/ffmpeg/libavresample/audio_convert.c |
---|
0,0 → 1,414 |
/* |
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include <stdint.h> |
#include "config.h" |
#include "libavutil/common.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" |
#include "dither.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; |
DitherContext *dc; |
enum AVSampleFormat in_fmt; |
enum AVSampleFormat out_fmt; |
int apply_map; |
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) |
} |
void ff_audio_convert_free(AudioConvert **ac) |
{ |
if (!*ac) |
return; |
ff_dither_free(&(*ac)->dc); |
av_freep(ac); |
} |
AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, |
enum AVSampleFormat out_fmt, |
enum AVSampleFormat in_fmt, |
int channels, int sample_rate, |
int apply_map) |
{ |
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; |
ac->apply_map = apply_map; |
if (avr->dither_method != AV_RESAMPLE_DITHER_NONE && |
av_get_packed_sample_fmt(out_fmt) == AV_SAMPLE_FMT_S16 && |
av_get_bytes_per_sample(in_fmt) > 2) { |
ac->dc = ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, |
apply_map); |
if (!ac->dc) { |
av_free(ac); |
return NULL; |
} |
return ac; |
} |
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_ARM) |
ff_audio_convert_init_arm(ac); |
if (ARCH_X86) |
ff_audio_convert_init_x86(ac); |
return ac; |
} |
int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) |
{ |
int use_generic = 1; |
int len = in->nb_samples; |
int p; |
if (ac->dc) { |
/* dithered conversion */ |
av_dlog(ac->avr, "%d samples - audio_convert: %s to %s (dithered)\n", |
len, av_get_sample_fmt_name(ac->in_fmt), |
av_get_sample_fmt_name(ac->out_fmt)); |
return ff_convert_dither(ac->dc, out, in); |
} |
/* 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); |
if (ac->apply_map) { |
ChannelMapInfo *map = &ac->avr->ch_map_info; |
if (!av_sample_fmt_is_planar(ac->out_fmt)) { |
av_log(ac->avr, AV_LOG_ERROR, "cannot remap packed format during conversion\n"); |
return AVERROR(EINVAL); |
} |
if (map->do_remap) { |
if (av_sample_fmt_is_planar(ac->in_fmt)) { |
conv_func_flat *convert = use_generic ? ac->conv_flat_generic : |
ac->conv_flat; |
for (p = 0; p < ac->planes; p++) |
if (map->channel_map[p] >= 0) |
convert(out->data[p], in->data[map->channel_map[p]], len); |
} else { |
uint8_t *data[AVRESAMPLE_MAX_CHANNELS]; |
conv_func_deinterleave *convert = use_generic ? |
ac->conv_deinterleave_generic : |
ac->conv_deinterleave; |
for (p = 0; p < ac->channels; p++) |
data[map->input_map[p]] = out->data[p]; |
convert(data, in->data[0], len, ac->channels); |
} |
} |
if (map->do_copy || map->do_zero) { |
for (p = 0; p < ac->planes; p++) { |
if (map->channel_copy[p]) |
memcpy(out->data[p], out->data[map->channel_copy[p]], |
len * out->stride); |
else if (map->channel_zero[p]) |
av_samples_set_silence(&out->data[p], 0, len, 1, ac->out_fmt); |
} |
} |
} else { |
switch (ac->func_type) { |
case CONV_FUNC_TYPE_FLAT: { |
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; |
} |
/contrib/sdk/sources/ffmpeg/libavresample/audio_convert.h |
---|
0,0 → 1,102 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#ifndef AVRESAMPLE_AUDIO_CONVERT_H |
#define AVRESAMPLE_AUDIO_CONVERT_H |
#include "libavutil/samplefmt.h" |
#include "avresample.h" |
#include "internal.h" |
#include "audio_data.h" |
/** |
* 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 samples_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 |
* @param sample_rate sample rate (used for dithering) |
* @param apply_map apply channel map during conversion |
* @return newly-allocated AudioConvert context |
*/ |
AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, |
enum AVSampleFormat out_fmt, |
enum AVSampleFormat in_fmt, |
int channels, int sample_rate, |
int apply_map); |
/** |
* Free AudioConvert. |
* |
* The AudioConvert must have been previously allocated with ff_audio_convert_alloc(). |
* |
* @param ac AudioConvert struct |
*/ |
void ff_audio_convert_free(AudioConvert **ac); |
/** |
* 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). |
* |
* The number of samples to convert is determined by in->nb_samples. The output |
* buffer must be large enough to handle this many samples. out->nb_samples is |
* set by this function before a successful return. |
* |
* @param ac AudioConvert context |
* @param out output audio data |
* @param in input audio data |
* @return 0 on success, negative AVERROR code on failure |
*/ |
int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in); |
/* arch-specific initialization functions */ |
void ff_audio_convert_init_arm(AudioConvert *ac); |
void ff_audio_convert_init_x86(AudioConvert *ac); |
#endif /* AVRESAMPLE_AUDIO_CONVERT_H */ |
/contrib/sdk/sources/ffmpeg/libavresample/audio_data.c |
---|
0,0 → 1,372 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include <stdint.h> |
#include <string.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, uint8_t **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, ChannelMapInfo *map) |
{ |
int ret, p; |
/* validate input/output compatibility */ |
if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels) |
return AVERROR(EINVAL); |
if (map && !src->is_planar) { |
av_log(src, AV_LOG_ERROR, "cannot remap packed format during copy\n"); |
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 */ |
if (map) { |
if (map->do_remap) { |
for (p = 0; p < src->planes; p++) { |
if (map->channel_map[p] >= 0) |
memcpy(dst->data[p], src->data[map->channel_map[p]], |
src->nb_samples * src->stride); |
} |
} |
if (map->do_copy || map->do_zero) { |
for (p = 0; p < src->planes; p++) { |
if (map->channel_copy[p]) |
memcpy(dst->data[p], dst->data[map->channel_copy[p]], |
src->nb_samples * src->stride); |
else if (map->channel_zero[p]) |
av_samples_set_silence(&dst->data[p], 0, src->nb_samples, |
1, dst->sample_fmt); |
} |
} |
} else { |
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; |
} |
/contrib/sdk/sources/ffmpeg/libavresample/audio_data.h |
---|
0,0 → 1,175 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#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" |
#include "internal.h" |
/** |
* Audio buffer used for intermediate storage between conversion phases. |
*/ |
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 */ |
}; |
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, uint8_t **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 |
* @param map channel map, NULL if not remapping |
* @return 0 on success, negative AVERROR value on error |
*/ |
int ff_audio_data_copy(AudioData *out, AudioData *in, ChannelMapInfo *map); |
/** |
* 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 */ |
/contrib/sdk/sources/ffmpeg/libavresample/audio_mix.c |
---|
0,0 → 1,739 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include <stdint.h> |
#include "libavutil/common.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[] = { "q8", "q15", "flt" }; |
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; |
int in_matrix_channels; |
int out_matrix_channels; |
int output_zero[AVRESAMPLE_MAX_CHANNELS]; |
int input_skip[AVRESAMPLE_MAX_CHANNELS]; |
int output_skip[AVRESAMPLE_MAX_CHANNELS]; |
int16_t *matrix_q8[AVRESAMPLE_MAX_CHANNELS]; |
int32_t *matrix_q15[AVRESAMPLE_MAX_CHANNELS]; |
float *matrix_flt[AVRESAMPLE_MAX_CHANNELS]; |
void **matrix; |
}; |
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_matrix_channels || in_channels == 0) && |
(out_channels == am->out_matrix_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); |
} else { |
snprintf(chan_str, sizeof(chan_str), "[any to any] "); |
} |
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], 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, Q8, int16_t, int16_t, int32_t, av_clip_int16(sum >> 8)) |
/* 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_2_to_1_s16p_flt_c(int16_t **samples, float **matrix, int len, |
int out_ch, int in_ch) |
{ |
int16_t *src0 = samples[0]; |
int16_t *src1 = samples[1]; |
int16_t *dst = src0; |
float m0 = matrix[0][0]; |
float m1 = matrix[0][1]; |
while (len > 4) { |
*dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); |
*dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); |
*dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); |
*dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); |
len -= 4; |
} |
while (len > 0) { |
*dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); |
len--; |
} |
} |
static void mix_2_to_1_s16p_q8_c(int16_t **samples, int16_t **matrix, int len, |
int out_ch, int in_ch) |
{ |
int16_t *src0 = samples[0]; |
int16_t *src1 = samples[1]; |
int16_t *dst = src0; |
int16_t m0 = matrix[0][0]; |
int16_t m1 = matrix[0][1]; |
while (len > 4) { |
*dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; |
*dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; |
*dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; |
*dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; |
len -= 4; |
} |
while (len > 0) { |
*dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; |
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 * m0; |
*dst1++ = v * m1; |
v = *src++; |
*dst0++ = v * m0; |
*dst1++ = v * m1; |
v = *src++; |
*dst0++ = v * m0; |
*dst1++ = v * m1; |
v = *src++; |
*dst0++ = v * m0; |
*dst1++ = v * m1; |
len -= 4; |
} |
while (len > 0) { |
v = *src++; |
*dst0++ = v * m0; |
*dst1++ = v * m1; |
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 av_cold int mix_function_init(AudioMix *am) |
{ |
am->func_descr = am->func_descr_generic = "n/a"; |
am->mix = am->mix_generic = NULL; |
/* no need to set a mix function when we're skipping mixing */ |
if (!am->in_matrix_channels || !am->out_matrix_channels) |
return 0; |
/* 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_Q8, |
0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q8)); |
/* 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_S16P, AV_MIX_COEFF_TYPE_FLT, |
2, 1, 1, 1, "C", mix_2_to_1_s16p_flt_c); |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8, |
2, 1, 1, 1, "C", mix_2_to_1_s16p_q8_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; |
} |
AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr) |
{ |
AudioMix *am; |
int ret; |
am = av_mallocz(sizeof(*am)); |
if (!am) |
return NULL; |
am->avr = avr; |
if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P && |
avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) { |
av_log(avr, AV_LOG_ERROR, "Unsupported internal format for " |
"mixing: %s\n", |
av_get_sample_fmt_name(avr->internal_sample_fmt)); |
goto error; |
} |
am->fmt = avr->internal_sample_fmt; |
am->coeff_type = avr->mix_coeff_type; |
am->in_layout = avr->in_channel_layout; |
am->out_layout = avr->out_channel_layout; |
am->in_channels = avr->in_channels; |
am->out_channels = avr->out_channels; |
/* build matrix if the user did not already set one */ |
if (avr->mix_matrix) { |
ret = ff_audio_mix_set_matrix(am, avr->mix_matrix, avr->in_channels); |
if (ret < 0) |
goto error; |
av_freep(&avr->mix_matrix); |
} else { |
double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels * |
sizeof(*matrix_dbl)); |
if (!matrix_dbl) |
goto error; |
ret = avresample_build_matrix(avr->in_channel_layout, |
avr->out_channel_layout, |
avr->center_mix_level, |
avr->surround_mix_level, |
avr->lfe_mix_level, |
avr->normalize_mix_level, |
matrix_dbl, |
avr->in_channels, |
avr->matrix_encoding); |
if (ret < 0) { |
av_free(matrix_dbl); |
goto error; |
} |
ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels); |
if (ret < 0) { |
av_log(avr, AV_LOG_ERROR, "error setting mix matrix\n"); |
av_free(matrix_dbl); |
goto error; |
} |
av_free(matrix_dbl); |
} |
return am; |
error: |
av_free(am); |
return NULL; |
} |
void ff_audio_mix_free(AudioMix **am_p) |
{ |
AudioMix *am; |
if (!*am_p) |
return; |
am = *am_p; |
if (am->matrix) { |
av_free(am->matrix[0]); |
am->matrix = NULL; |
} |
memset(am->matrix_q8, 0, sizeof(am->matrix_q8 )); |
memset(am->matrix_q15, 0, sizeof(am->matrix_q15)); |
memset(am->matrix_flt, 0, sizeof(am->matrix_flt)); |
av_freep(am_p); |
} |
int ff_audio_mix(AudioMix *am, AudioData *src) |
{ |
int use_generic = 1; |
int len = src->nb_samples; |
int i, j; |
/* 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 (am->in_matrix_channels && am->out_matrix_channels) { |
uint8_t **data; |
uint8_t *data0[AVRESAMPLE_MAX_CHANNELS]; |
if (am->out_matrix_channels < am->out_channels || |
am->in_matrix_channels < am->in_channels) { |
for (i = 0, j = 0; i < FFMAX(am->in_channels, am->out_channels); i++) { |
if (am->input_skip[i] || am->output_skip[i] || am->output_zero[i]) |
continue; |
data0[j++] = src->data[i]; |
} |
data = data0; |
} else { |
data = src->data; |
} |
if (use_generic) |
am->mix_generic(data, am->matrix, len, am->out_matrix_channels, |
am->in_matrix_channels); |
else |
am->mix(data, am->matrix, len, am->out_matrix_channels, |
am->in_matrix_channels); |
} |
if (am->out_matrix_channels < am->out_channels) { |
for (i = 0; i < am->out_channels; i++) |
if (am->output_zero[i]) |
av_samples_set_silence(&src->data[i], 0, len, 1, am->fmt); |
} |
ff_audio_data_set_channels(src, am->out_channels); |
return 0; |
} |
int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride) |
{ |
int i, o, i0, o0; |
if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS || |
am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) { |
av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n"); |
return AVERROR(EINVAL); |
} |
#define GET_MATRIX_CONVERT(suffix, scale) \ |
if (!am->matrix_ ## suffix[0]) { \ |
av_log(am->avr, AV_LOG_ERROR, "matrix is not set\n"); \ |
return AVERROR(EINVAL); \ |
} \ |
for (o = 0, o0 = 0; o < am->out_channels; o++) { \ |
for (i = 0, i0 = 0; i < am->in_channels; i++) { \ |
if (am->input_skip[i] || am->output_zero[o]) \ |
matrix[o * stride + i] = 0.0; \ |
else \ |
matrix[o * stride + i] = am->matrix_ ## suffix[o0][i0] * \ |
(scale); \ |
if (!am->input_skip[i]) \ |
i0++; \ |
} \ |
if (!am->output_zero[o]) \ |
o0++; \ |
} |
switch (am->coeff_type) { |
case AV_MIX_COEFF_TYPE_Q8: |
GET_MATRIX_CONVERT(q8, 1.0 / 256.0); |
break; |
case AV_MIX_COEFF_TYPE_Q15: |
GET_MATRIX_CONVERT(q15, 1.0 / 32768.0); |
break; |
case AV_MIX_COEFF_TYPE_FLT: |
GET_MATRIX_CONVERT(flt, 1.0); |
break; |
default: |
av_log(am->avr, AV_LOG_ERROR, "Invalid mix coeff type\n"); |
return AVERROR(EINVAL); |
} |
return 0; |
} |
static void reduce_matrix(AudioMix *am, const double *matrix, int stride) |
{ |
int i, o; |
memset(am->output_zero, 0, sizeof(am->output_zero)); |
memset(am->input_skip, 0, sizeof(am->input_skip)); |
memset(am->output_skip, 0, sizeof(am->output_skip)); |
/* exclude output channels if they can be zeroed instead of mixed */ |
for (o = 0; o < am->out_channels; o++) { |
int zero = 1; |
/* check if the output is always silent */ |
for (i = 0; i < am->in_channels; i++) { |
if (matrix[o * stride + i] != 0.0) { |
zero = 0; |
break; |
} |
} |
/* check if the corresponding input channel makes a contribution to |
any output channel */ |
if (o < am->in_channels) { |
for (i = 0; i < am->out_channels; i++) { |
if (matrix[i * stride + o] != 0.0) { |
zero = 0; |
break; |
} |
} |
} |
if (zero) { |
am->output_zero[o] = 1; |
am->out_matrix_channels--; |
} |
} |
if (am->out_matrix_channels == 0) { |
am->in_matrix_channels = 0; |
return; |
} |
/* skip input channels that contribute fully only to the corresponding |
output channel */ |
for (i = 0; i < FFMIN(am->in_channels, am->out_channels); i++) { |
int skip = 1; |
for (o = 0; o < am->out_channels; o++) { |
int i0; |
if ((o != i && matrix[o * stride + i] != 0.0) || |
(o == i && matrix[o * stride + i] != 1.0)) { |
skip = 0; |
break; |
} |
/* if the input contributes fully to the output, also check that no |
other inputs contribute to this output */ |
if (o == i) { |
for (i0 = 0; i0 < am->in_channels; i0++) { |
if (i0 != i && matrix[o * stride + i0] != 0.0) { |
skip = 0; |
break; |
} |
} |
} |
} |
if (skip) { |
am->input_skip[i] = 1; |
am->in_matrix_channels--; |
} |
} |
/* skip input channels that do not contribute to any output channel */ |
for (; i < am->in_channels; i++) { |
int contrib = 0; |
for (o = 0; o < am->out_channels; o++) { |
if (matrix[o * stride + i] != 0.0) { |
contrib = 1; |
break; |
} |
} |
if (!contrib) { |
am->input_skip[i] = 1; |
am->in_matrix_channels--; |
} |
} |
if (am->in_matrix_channels == 0) { |
am->out_matrix_channels = 0; |
return; |
} |
/* skip output channels that only get full contribution from the |
corresponding input channel */ |
for (o = 0; o < FFMIN(am->in_channels, am->out_channels); o++) { |
int skip = 1; |
int o0; |
for (i = 0; i < am->in_channels; i++) { |
if ((o != i && matrix[o * stride + i] != 0.0) || |
(o == i && matrix[o * stride + i] != 1.0)) { |
skip = 0; |
break; |
} |
} |
/* check if the corresponding input channel makes a contribution to |
any other output channel */ |
i = o; |
for (o0 = 0; o0 < am->out_channels; o0++) { |
if (o0 != i && matrix[o0 * stride + i] != 0.0) { |
skip = 0; |
break; |
} |
} |
if (skip) { |
am->output_skip[o] = 1; |
am->out_matrix_channels--; |
} |
} |
if (am->out_matrix_channels == 0) { |
am->in_matrix_channels = 0; |
return; |
} |
} |
int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride) |
{ |
int i, o, i0, o0, ret; |
char in_layout_name[128]; |
char out_layout_name[128]; |
if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS || |
am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) { |
av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n"); |
return AVERROR(EINVAL); |
} |
if (am->matrix) { |
av_free(am->matrix[0]); |
am->matrix = NULL; |
} |
am->in_matrix_channels = am->in_channels; |
am->out_matrix_channels = am->out_channels; |
reduce_matrix(am, matrix, stride); |
#define CONVERT_MATRIX(type, expr) \ |
am->matrix_## type[0] = av_mallocz(am->out_matrix_channels * \ |
am->in_matrix_channels * \ |
sizeof(*am->matrix_## type[0])); \ |
if (!am->matrix_## type[0]) \ |
return AVERROR(ENOMEM); \ |
for (o = 0, o0 = 0; o < am->out_channels; o++) { \ |
if (am->output_zero[o] || am->output_skip[o]) \ |
continue; \ |
if (o0 > 0) \ |
am->matrix_## type[o0] = am->matrix_## type[o0 - 1] + \ |
am->in_matrix_channels; \ |
for (i = 0, i0 = 0; i < am->in_channels; i++) { \ |
double v; \ |
if (am->input_skip[i]) \ |
continue; \ |
v = matrix[o * stride + i]; \ |
am->matrix_## type[o0][i0] = expr; \ |
i0++; \ |
} \ |
o0++; \ |
} \ |
am->matrix = (void **)am->matrix_## type; |
if (am->in_matrix_channels && am->out_matrix_channels) { |
switch (am->coeff_type) { |
case AV_MIX_COEFF_TYPE_Q8: |
CONVERT_MATRIX(q8, av_clip_int16(lrint(256.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(am->avr, AV_LOG_ERROR, "Invalid mix coeff type\n"); |
return AVERROR(EINVAL); |
} |
} |
ret = mix_function_init(am); |
if (ret < 0) |
return ret; |
av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name), |
am->in_channels, am->in_layout); |
av_get_channel_layout_string(out_layout_name, sizeof(out_layout_name), |
am->out_channels, am->out_layout); |
av_log(am->avr, AV_LOG_DEBUG, "audio_mix: %s to %s\n", |
in_layout_name, out_layout_name); |
av_log(am->avr, AV_LOG_DEBUG, "matrix size: %d x %d\n", |
am->in_matrix_channels, am->out_matrix_channels); |
for (o = 0; o < am->out_channels; o++) { |
for (i = 0; i < am->in_channels; i++) { |
if (am->output_zero[o]) |
av_log(am->avr, AV_LOG_DEBUG, " (ZERO)"); |
else if (am->input_skip[i] || am->output_skip[o]) |
av_log(am->avr, AV_LOG_DEBUG, " (SKIP)"); |
else |
av_log(am->avr, AV_LOG_DEBUG, " %0.3f ", |
matrix[o * am->in_channels + i]); |
} |
av_log(am->avr, AV_LOG_DEBUG, "\n"); |
} |
return 0; |
} |
/contrib/sdk/sources/ffmpeg/libavresample/audio_mix.h |
---|
0,0 → 1,94 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#ifndef AVRESAMPLE_AUDIO_MIX_H |
#define AVRESAMPLE_AUDIO_MIX_H |
#include <stdint.h> |
#include "libavutil/samplefmt.h" |
#include "avresample.h" |
#include "internal.h" |
#include "audio_data.h" |
typedef void (mix_func)(uint8_t **src, void **matrix, int len, int out_ch, |
int in_ch); |
/** |
* 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 samples_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); |
/** |
* Allocate and initialize an AudioMix context. |
* |
* The parameters in the AVAudioResampleContext are used to initialize the |
* AudioMix context. |
* |
* @param avr AVAudioResampleContext |
* @return newly-allocated AudioMix context. |
*/ |
AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr); |
/** |
* Free an AudioMix context. |
*/ |
void ff_audio_mix_free(AudioMix **am); |
/** |
* Apply channel mixing to audio data using the current mixing matrix. |
*/ |
int ff_audio_mix(AudioMix *am, AudioData *src); |
/** |
* Get the current mixing matrix. |
*/ |
int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride); |
/** |
* Set the current mixing matrix. |
*/ |
int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride); |
/* arch-specific initialization functions */ |
void ff_audio_mix_init_x86(AudioMix *am); |
#endif /* AVRESAMPLE_AUDIO_MIX_H */ |
/contrib/sdk/sources/ffmpeg/libavresample/audio_mix_matrix.c |
---|
0,0 → 1,289 |
/* |
* Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at) |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include <stdint.h> |
#include "libavutil/common.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 |
#define LOW_FREQUENCY_2 35 |
#define SQRT3_2 1.22474487139158904909 /* sqrt(3/2) */ |
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, |
enum AVMatrixEncoding matrix_encoding) |
{ |
int i, j, out_i, out_j; |
double matrix[64][64] = {{0}}; |
int64_t unaccounted; |
double maxcoef = 0; |
int in_channels, out_channels; |
if ((out_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == AV_CH_LAYOUT_STEREO_DOWNMIX) { |
out_layout = AV_CH_LAYOUT_STEREO; |
} |
unaccounted = in_layout & ~out_layout; |
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) { |
if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY || |
matrix_encoding == AV_MATRIX_ENCODING_DPLII) { |
if (unaccounted & (AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT)) { |
matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level * M_SQRT1_2; |
matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2; |
} else { |
matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level; |
matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level; |
} |
} else { |
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) { |
if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { |
matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * M_SQRT1_2; |
matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2; |
matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; |
matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * M_SQRT1_2; |
} else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { |
matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * SQRT3_2; |
matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2; |
matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; |
matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * SQRT3_2; |
} else { |
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) { |
if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { |
matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * M_SQRT1_2; |
matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2; |
matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; |
matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2; |
} else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { |
matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * SQRT3_2; |
matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2; |
matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; |
matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * SQRT3_2; |
} else { |
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; |
} |
/contrib/sdk/sources/ffmpeg/libavresample/avresample-test.c |
---|
0,0 → 1,341 |
/* |
* Copyright (c) 2002 Fabrice Bellard |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include <stdint.h> |
#include <stdio.h> |
#include "libavutil/avstring.h" |
#include "libavutil/common.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 sine 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 varying 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, out_data, out_linesize, out_rate * 6, |
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; |
} |
/contrib/sdk/sources/ffmpeg/libavresample/avresample.h |
---|
0,0 → 1,409 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#ifndef AVRESAMPLE_AVRESAMPLE_H |
#define AVRESAMPLE_AVRESAMPLE_H |
/** |
* @file |
* @ingroup lavr |
* external API header |
*/ |
/** |
* @defgroup lavr Libavresample |
* @{ |
* |
* Libavresample (lavr) is a library that handles audio resampling, sample |
* format conversion and mixing. |
* |
* Interaction with lavr is done through AVAudioResampleContext, which is |
* allocated with avresample_alloc_context(). It is opaque, so all parameters |
* must be set with the @ref avoptions API. |
* |
* For example the following code will setup conversion from planar float sample |
* format to interleaved signed 16-bit integer, downsampling from 48kHz to |
* 44.1kHz and downmixing from 5.1 channels to stereo (using the default mixing |
* matrix): |
* @code |
* AVAudioResampleContext *avr = avresample_alloc_context(); |
* av_opt_set_int(avr, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0); |
* av_opt_set_int(avr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); |
* av_opt_set_int(avr, "in_sample_rate", 48000, 0); |
* av_opt_set_int(avr, "out_sample_rate", 44100, 0); |
* av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); |
* av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); |
* @endcode |
* |
* Once the context is initialized, it must be opened with avresample_open(). If |
* you need to change the conversion parameters, you must close the context with |
* avresample_close(), change the parameters as described above, then reopen it |
* again. |
* |
* The conversion itself is done by repeatedly calling avresample_convert(). |
* Note that the samples may get buffered in two places in lavr. The first one |
* is the output FIFO, where the samples end up if the output buffer is not |
* large enough. The data stored in there may be retrieved at any time with |
* avresample_read(). The second place is the resampling delay buffer, |
* applicable only when resampling is done. The samples in it require more input |
* before they can be processed. Their current amount is returned by |
* avresample_get_delay(). At the end of conversion the resampling buffer can be |
* flushed by calling avresample_convert() with NULL input. |
* |
* The following code demonstrates the conversion loop assuming the parameters |
* from above and caller-defined functions get_input() and handle_output(): |
* @code |
* uint8_t **input; |
* int in_linesize, in_samples; |
* |
* while (get_input(&input, &in_linesize, &in_samples)) { |
* uint8_t *output |
* int out_linesize; |
* int out_samples = avresample_available(avr) + |
* av_rescale_rnd(avresample_get_delay(avr) + |
* in_samples, 44100, 48000, AV_ROUND_UP); |
* av_samples_alloc(&output, &out_linesize, 2, out_samples, |
* AV_SAMPLE_FMT_S16, 0); |
* out_samples = avresample_convert(avr, &output, out_linesize, out_samples, |
* input, in_linesize, in_samples); |
* handle_output(output, out_linesize, out_samples); |
* av_freep(&output); |
* } |
* @endcode |
* |
* When the conversion is finished and the FIFOs are flushed if required, the |
* conversion context and everything associated with it must be freed with |
* avresample_free(). |
*/ |
#include "libavutil/avutil.h" |
#include "libavutil/channel_layout.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_Q8, /** 16-bit 8.8 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 */ |
}; |
/** Resampling Filter Types */ |
enum AVResampleFilterType { |
AV_RESAMPLE_FILTER_TYPE_CUBIC, /**< Cubic */ |
AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL, /**< Blackman Nuttall Windowed Sinc */ |
AV_RESAMPLE_FILTER_TYPE_KAISER, /**< Kaiser Windowed Sinc */ |
}; |
enum AVResampleDitherMethod { |
AV_RESAMPLE_DITHER_NONE, /**< Do not use dithering */ |
AV_RESAMPLE_DITHER_RECTANGULAR, /**< Rectangular Dither */ |
AV_RESAMPLE_DITHER_TRIANGULAR, /**< Triangular Dither*/ |
AV_RESAMPLE_DITHER_TRIANGULAR_HP, /**< Triangular Dither with High Pass */ |
AV_RESAMPLE_DITHER_TRIANGULAR_NS, /**< Triangular Dither with Noise Shaping */ |
AV_RESAMPLE_DITHER_NB, /**< Number of dither 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 |
* @param matrix_encoding matrixed stereo downmix mode (e.g. dplii) |
* @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, enum AVMatrixEncoding matrix_encoding); |
/** |
* Get the current channel mixing matrix. |
* |
* If no custom matrix has been previously set or the AVAudioResampleContext is |
* not open, an error is returned. |
* |
* @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(), as long as the channel layouts have been set. |
* 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 a customized input channel mapping. |
* |
* This function can only be called when the allocated context is not open. |
* Also, the input channel layout must have already been set. |
* |
* Calling avresample_close() on the context will clear the channel mapping. |
* |
* The map for each input channel specifies the channel index in the source to |
* use for that particular channel, or -1 to mute the channel. Source channels |
* can be duplicated by using the same index for multiple input channels. |
* |
* Examples: |
* |
* Reordering 5.1 AAC order (C,L,R,Ls,Rs,LFE) to FFmpeg order (L,R,C,LFE,Ls,Rs): |
* { 1, 2, 0, 5, 3, 4 } |
* |
* Muting the 3rd channel in 4-channel input: |
* { 0, 1, -1, 3 } |
* |
* Duplicating the left channel of stereo input: |
* { 0, 0 } |
* |
* @param avr audio resample context |
* @param channel_map customized input channel mapping |
* @return 0 on success, negative AVERROR code on failure |
*/ |
int avresample_set_channel_mapping(AVAudioResampleContext *avr, |
const int *channel_map); |
/** |
* Set compensation for resampling. |
* |
* This can be called anytime after avresample_open(). If resampling is not |
* automatically enabled because of a sample rate conversion, the |
* "force_resampling" option must have been set to 1 when opening the context |
* in order to use resampling compensation. |
* |
* @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 upper bound on the number of output samples is given by |
* avresample_available() + (avresample_get_delay() + number of input samples) * |
* output sample rate / input sample rate. |
* |
* 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, uint8_t **output, |
int out_plane_size, int out_samples, uint8_t **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. May be NULL, in which case |
* nb_samples of data is discarded from output FIFO. |
* @param nb_samples number of samples to read from the FIFO |
* @return the number of samples written to output |
*/ |
int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_samples); |
/** |
* @} |
*/ |
#endif /* AVRESAMPLE_AVRESAMPLE_H */ |
/contrib/sdk/sources/ffmpeg/libavresample/dither.c |
---|
0,0 → 1,440 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* Triangular with Noise Shaping is based on opusfile. |
* Copyright (c) 1994-2012 by the Xiph.Org Foundation and contributors |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
/** |
* @file |
* Dithered Audio Sample Quantization |
* |
* Converts from dbl, flt, or s32 to s16 using dithering. |
*/ |
#include <math.h> |
#include <stdint.h> |
#include "libavutil/attributes.h" |
#include "libavutil/common.h" |
#include "libavutil/lfg.h" |
#include "libavutil/mem.h" |
#include "libavutil/samplefmt.h" |
#include "audio_convert.h" |
#include "dither.h" |
#include "internal.h" |
typedef struct DitherState { |
int mute; |
unsigned int seed; |
AVLFG lfg; |
float *noise_buf; |
int noise_buf_size; |
int noise_buf_ptr; |
float dither_a[4]; |
float dither_b[4]; |
} DitherState; |
struct DitherContext { |
DitherDSPContext ddsp; |
enum AVResampleDitherMethod method; |
int apply_map; |
ChannelMapInfo *ch_map_info; |
int mute_dither_threshold; // threshold for disabling dither |
int mute_reset_threshold; // threshold for resetting noise shaping |
const float *ns_coef_b; // noise shaping coeffs |
const float *ns_coef_a; // noise shaping coeffs |
int channels; |
DitherState *state; // dither states for each channel |
AudioData *flt_data; // input data in fltp |
AudioData *s16_data; // dithered output in s16p |
AudioConvert *ac_in; // converter for input to fltp |
AudioConvert *ac_out; // converter for s16p to s16 (if needed) |
void (*quantize)(int16_t *dst, const float *src, float *dither, int len); |
int samples_align; |
}; |
/* mute threshold, in seconds */ |
#define MUTE_THRESHOLD_SEC 0.000333 |
/* scale factor for 16-bit output. |
The signal is attenuated slightly to avoid clipping */ |
#define S16_SCALE 32753.0f |
/* scale to convert lfg from INT_MIN/INT_MAX to -0.5/0.5 */ |
#define LFG_SCALE (1.0f / (2.0f * INT32_MAX)) |
/* noise shaping coefficients */ |
static const float ns_48_coef_b[4] = { |
2.2374f, -0.7339f, -0.1251f, -0.6033f |
}; |
static const float ns_48_coef_a[4] = { |
0.9030f, 0.0116f, -0.5853f, -0.2571f |
}; |
static const float ns_44_coef_b[4] = { |
2.2061f, -0.4707f, -0.2534f, -0.6213f |
}; |
static const float ns_44_coef_a[4] = { |
1.0587f, 0.0676f, -0.6054f, -0.2738f |
}; |
static void dither_int_to_float_rectangular_c(float *dst, int *src, int len) |
{ |
int i; |
for (i = 0; i < len; i++) |
dst[i] = src[i] * LFG_SCALE; |
} |
static void dither_int_to_float_triangular_c(float *dst, int *src0, int len) |
{ |
int i; |
int *src1 = src0 + len; |
for (i = 0; i < len; i++) { |
float r = src0[i] * LFG_SCALE; |
r += src1[i] * LFG_SCALE; |
dst[i] = r; |
} |
} |
static void quantize_c(int16_t *dst, const float *src, float *dither, int len) |
{ |
int i; |
for (i = 0; i < len; i++) |
dst[i] = av_clip_int16(lrintf(src[i] * S16_SCALE + dither[i])); |
} |
#define SQRT_1_6 0.40824829046386301723f |
static void dither_highpass_filter(float *src, int len) |
{ |
int i; |
/* filter is from libswresample in FFmpeg */ |
for (i = 0; i < len - 2; i++) |
src[i] = (-src[i] + 2 * src[i + 1] - src[i + 2]) * SQRT_1_6; |
} |
static int generate_dither_noise(DitherContext *c, DitherState *state, |
int min_samples) |
{ |
int i; |
int nb_samples = FFALIGN(min_samples, 16) + 16; |
int buf_samples = nb_samples * |
(c->method == AV_RESAMPLE_DITHER_RECTANGULAR ? 1 : 2); |
unsigned int *noise_buf_ui; |
av_freep(&state->noise_buf); |
state->noise_buf_size = state->noise_buf_ptr = 0; |
state->noise_buf = av_malloc(buf_samples * sizeof(*state->noise_buf)); |
if (!state->noise_buf) |
return AVERROR(ENOMEM); |
state->noise_buf_size = FFALIGN(min_samples, 16); |
noise_buf_ui = (unsigned int *)state->noise_buf; |
av_lfg_init(&state->lfg, state->seed); |
for (i = 0; i < buf_samples; i++) |
noise_buf_ui[i] = av_lfg_get(&state->lfg); |
c->ddsp.dither_int_to_float(state->noise_buf, noise_buf_ui, nb_samples); |
if (c->method == AV_RESAMPLE_DITHER_TRIANGULAR_HP) |
dither_highpass_filter(state->noise_buf, nb_samples); |
return 0; |
} |
static void quantize_triangular_ns(DitherContext *c, DitherState *state, |
int16_t *dst, const float *src, |
int nb_samples) |
{ |
int i, j; |
float *dither = &state->noise_buf[state->noise_buf_ptr]; |
if (state->mute > c->mute_reset_threshold) |
memset(state->dither_a, 0, sizeof(state->dither_a)); |
for (i = 0; i < nb_samples; i++) { |
float err = 0; |
float sample = src[i] * S16_SCALE; |
for (j = 0; j < 4; j++) { |
err += c->ns_coef_b[j] * state->dither_b[j] - |
c->ns_coef_a[j] * state->dither_a[j]; |
} |
for (j = 3; j > 0; j--) { |
state->dither_a[j] = state->dither_a[j - 1]; |
state->dither_b[j] = state->dither_b[j - 1]; |
} |
state->dither_a[0] = err; |
sample -= err; |
if (state->mute > c->mute_dither_threshold) { |
dst[i] = av_clip_int16(lrintf(sample)); |
state->dither_b[0] = 0; |
} else { |
dst[i] = av_clip_int16(lrintf(sample + dither[i])); |
state->dither_b[0] = av_clipf(dst[i] - sample, -1.5f, 1.5f); |
} |
state->mute++; |
if (src[i]) |
state->mute = 0; |
} |
} |
static int convert_samples(DitherContext *c, int16_t **dst, float * const *src, |
int channels, int nb_samples) |
{ |
int ch, ret; |
int aligned_samples = FFALIGN(nb_samples, 16); |
for (ch = 0; ch < channels; ch++) { |
DitherState *state = &c->state[ch]; |
if (state->noise_buf_size < aligned_samples) { |
ret = generate_dither_noise(c, state, nb_samples); |
if (ret < 0) |
return ret; |
} else if (state->noise_buf_size - state->noise_buf_ptr < aligned_samples) { |
state->noise_buf_ptr = 0; |
} |
if (c->method == AV_RESAMPLE_DITHER_TRIANGULAR_NS) { |
quantize_triangular_ns(c, state, dst[ch], src[ch], nb_samples); |
} else { |
c->quantize(dst[ch], src[ch], |
&state->noise_buf[state->noise_buf_ptr], |
FFALIGN(nb_samples, c->samples_align)); |
} |
state->noise_buf_ptr += aligned_samples; |
} |
return 0; |
} |
int ff_convert_dither(DitherContext *c, AudioData *dst, AudioData *src) |
{ |
int ret; |
AudioData *flt_data; |
/* output directly to dst if it is planar */ |
if (dst->sample_fmt == AV_SAMPLE_FMT_S16P) |
c->s16_data = dst; |
else { |
/* make sure s16_data is large enough for the output */ |
ret = ff_audio_data_realloc(c->s16_data, src->nb_samples); |
if (ret < 0) |
return ret; |
} |
if (src->sample_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) { |
/* make sure flt_data is large enough for the input */ |
ret = ff_audio_data_realloc(c->flt_data, src->nb_samples); |
if (ret < 0) |
return ret; |
flt_data = c->flt_data; |
} |
if (src->sample_fmt != AV_SAMPLE_FMT_FLTP) { |
/* convert input samples to fltp and scale to s16 range */ |
ret = ff_audio_convert(c->ac_in, flt_data, src); |
if (ret < 0) |
return ret; |
} else if (c->apply_map) { |
ret = ff_audio_data_copy(flt_data, src, c->ch_map_info); |
if (ret < 0) |
return ret; |
} else { |
flt_data = src; |
} |
/* check alignment and padding constraints */ |
if (c->method != AV_RESAMPLE_DITHER_TRIANGULAR_NS) { |
int ptr_align = FFMIN(flt_data->ptr_align, c->s16_data->ptr_align); |
int samples_align = FFMIN(flt_data->samples_align, c->s16_data->samples_align); |
int aligned_len = FFALIGN(src->nb_samples, c->ddsp.samples_align); |
if (!(ptr_align % c->ddsp.ptr_align) && samples_align >= aligned_len) { |
c->quantize = c->ddsp.quantize; |
c->samples_align = c->ddsp.samples_align; |
} else { |
c->quantize = quantize_c; |
c->samples_align = 1; |
} |
} |
ret = convert_samples(c, (int16_t **)c->s16_data->data, |
(float * const *)flt_data->data, src->channels, |
src->nb_samples); |
if (ret < 0) |
return ret; |
c->s16_data->nb_samples = src->nb_samples; |
/* interleave output to dst if needed */ |
if (dst->sample_fmt == AV_SAMPLE_FMT_S16) { |
ret = ff_audio_convert(c->ac_out, dst, c->s16_data); |
if (ret < 0) |
return ret; |
} else |
c->s16_data = NULL; |
return 0; |
} |
void ff_dither_free(DitherContext **cp) |
{ |
DitherContext *c = *cp; |
int ch; |
if (!c) |
return; |
ff_audio_data_free(&c->flt_data); |
ff_audio_data_free(&c->s16_data); |
ff_audio_convert_free(&c->ac_in); |
ff_audio_convert_free(&c->ac_out); |
for (ch = 0; ch < c->channels; ch++) |
av_free(c->state[ch].noise_buf); |
av_free(c->state); |
av_freep(cp); |
} |
static av_cold void dither_init(DitherDSPContext *ddsp, |
enum AVResampleDitherMethod method) |
{ |
ddsp->quantize = quantize_c; |
ddsp->ptr_align = 1; |
ddsp->samples_align = 1; |
if (method == AV_RESAMPLE_DITHER_RECTANGULAR) |
ddsp->dither_int_to_float = dither_int_to_float_rectangular_c; |
else |
ddsp->dither_int_to_float = dither_int_to_float_triangular_c; |
if (ARCH_X86) |
ff_dither_init_x86(ddsp, method); |
} |
DitherContext *ff_dither_alloc(AVAudioResampleContext *avr, |
enum AVSampleFormat out_fmt, |
enum AVSampleFormat in_fmt, |
int channels, int sample_rate, int apply_map) |
{ |
AVLFG seed_gen; |
DitherContext *c; |
int ch; |
if (av_get_packed_sample_fmt(out_fmt) != AV_SAMPLE_FMT_S16 || |
av_get_bytes_per_sample(in_fmt) <= 2) { |
av_log(avr, AV_LOG_ERROR, "dithering %s to %s is not supported\n", |
av_get_sample_fmt_name(in_fmt), av_get_sample_fmt_name(out_fmt)); |
return NULL; |
} |
c = av_mallocz(sizeof(*c)); |
if (!c) |
return NULL; |
c->apply_map = apply_map; |
if (apply_map) |
c->ch_map_info = &avr->ch_map_info; |
if (avr->dither_method == AV_RESAMPLE_DITHER_TRIANGULAR_NS && |
sample_rate != 48000 && sample_rate != 44100) { |
av_log(avr, AV_LOG_WARNING, "sample rate must be 48000 or 44100 Hz " |
"for triangular_ns dither. using triangular_hp instead.\n"); |
avr->dither_method = AV_RESAMPLE_DITHER_TRIANGULAR_HP; |
} |
c->method = avr->dither_method; |
dither_init(&c->ddsp, c->method); |
if (c->method == AV_RESAMPLE_DITHER_TRIANGULAR_NS) { |
if (sample_rate == 48000) { |
c->ns_coef_b = ns_48_coef_b; |
c->ns_coef_a = ns_48_coef_a; |
} else { |
c->ns_coef_b = ns_44_coef_b; |
c->ns_coef_a = ns_44_coef_a; |
} |
} |
/* Either s16 or s16p output format is allowed, but s16p is used |
internally, so we need to use a temp buffer and interleave if the output |
format is s16 */ |
if (out_fmt != AV_SAMPLE_FMT_S16P) { |
c->s16_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_S16P, |
"dither s16 buffer"); |
if (!c->s16_data) |
goto fail; |
c->ac_out = ff_audio_convert_alloc(avr, out_fmt, AV_SAMPLE_FMT_S16P, |
channels, sample_rate, 0); |
if (!c->ac_out) |
goto fail; |
} |
if (in_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) { |
c->flt_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_FLTP, |
"dither flt buffer"); |
if (!c->flt_data) |
goto fail; |
} |
if (in_fmt != AV_SAMPLE_FMT_FLTP) { |
c->ac_in = ff_audio_convert_alloc(avr, AV_SAMPLE_FMT_FLTP, in_fmt, |
channels, sample_rate, c->apply_map); |
if (!c->ac_in) |
goto fail; |
} |
c->state = av_mallocz(channels * sizeof(*c->state)); |
if (!c->state) |
goto fail; |
c->channels = channels; |
/* calculate thresholds for turning off dithering during periods of |
silence to avoid replacing digital silence with quiet dither noise */ |
c->mute_dither_threshold = lrintf(sample_rate * MUTE_THRESHOLD_SEC); |
c->mute_reset_threshold = c->mute_dither_threshold * 4; |
/* initialize dither states */ |
av_lfg_init(&seed_gen, 0xC0FFEE); |
for (ch = 0; ch < channels; ch++) { |
DitherState *state = &c->state[ch]; |
state->mute = c->mute_reset_threshold + 1; |
state->seed = av_lfg_get(&seed_gen); |
generate_dither_noise(c, state, FFMAX(32768, sample_rate / 2)); |
} |
return c; |
fail: |
ff_dither_free(&c); |
return NULL; |
} |
/contrib/sdk/sources/ffmpeg/libavresample/dither.h |
---|
0,0 → 1,93 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#ifndef AVRESAMPLE_DITHER_H |
#define AVRESAMPLE_DITHER_H |
#include "avresample.h" |
#include "audio_data.h" |
typedef struct DitherContext DitherContext; |
typedef struct DitherDSPContext { |
/** |
* Convert samples from flt to s16 with added dither noise. |
* |
* @param dst destination float array, range -0.5 to 0.5 |
* @param src source int array, range INT_MIN to INT_MAX. |
* @param dither float dither noise array |
* @param len number of samples |
*/ |
void (*quantize)(int16_t *dst, const float *src, float *dither, int len); |
int ptr_align; ///< src and dst constraits for quantize() |
int samples_align; ///< len constraits for quantize() |
/** |
* Convert dither noise from int to float with triangular distribution. |
* |
* @param dst destination float array, range -0.5 to 0.5 |
* constraints: 32-byte aligned |
* @param src0 source int array, range INT_MIN to INT_MAX. |
* the array size is len * 2 |
* constraints: 32-byte aligned |
* @param len number of output noise samples |
* constraints: multiple of 16 |
*/ |
void (*dither_int_to_float)(float *dst, int *src0, int len); |
} DitherDSPContext; |
/** |
* Allocate and initialize a DitherContext. |
* |
* The parameters in the AVAudioResampleContext are used to initialize the |
* DitherContext. |
* |
* @param avr AVAudioResampleContext |
* @return newly-allocated DitherContext |
*/ |
DitherContext *ff_dither_alloc(AVAudioResampleContext *avr, |
enum AVSampleFormat out_fmt, |
enum AVSampleFormat in_fmt, |
int channels, int sample_rate, int apply_map); |
/** |
* Free a DitherContext. |
* |
* @param c DitherContext |
*/ |
void ff_dither_free(DitherContext **c); |
/** |
* Convert audio sample format with dithering. |
* |
* @param c DitherContext |
* @param dst destination audio data |
* @param src source audio data |
* @return 0 if ok, negative AVERROR code on failure |
*/ |
int ff_convert_dither(DitherContext *c, AudioData *dst, AudioData *src); |
/* arch-specific initialization functions */ |
void ff_dither_init_x86(DitherDSPContext *ddsp, |
enum AVResampleDitherMethod method); |
#endif /* AVRESAMPLE_DITHER_H */ |
/contrib/sdk/sources/ffmpeg/libavresample/internal.h |
---|
0,0 → 1,110 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#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" |
typedef struct AudioData AudioData; |
typedef struct AudioConvert AudioConvert; |
typedef struct AudioMix AudioMix; |
typedef struct ResampleContext ResampleContext; |
enum RemapPoint { |
REMAP_NONE, |
REMAP_IN_COPY, |
REMAP_IN_CONVERT, |
REMAP_OUT_COPY, |
REMAP_OUT_CONVERT, |
}; |
typedef struct ChannelMapInfo { |
int channel_map[AVRESAMPLE_MAX_CHANNELS]; /**< source index of each output channel, -1 if not remapped */ |
int do_remap; /**< remap needed */ |
int channel_copy[AVRESAMPLE_MAX_CHANNELS]; /**< dest index to copy from */ |
int do_copy; /**< copy needed */ |
int channel_zero[AVRESAMPLE_MAX_CHANNELS]; /**< dest index to zero */ |
int do_zero; /**< zeroing needed */ |
int input_map[AVRESAMPLE_MAX_CHANNELS]; /**< dest index of each input channel */ |
} ChannelMapInfo; |
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 normalize_mix_level; /**< enable mix level normalization */ |
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 */ |
enum AVResampleFilterType filter_type; /**< resampling filter type */ |
int kaiser_beta; /**< beta value for Kaiser window (only applicable if filter_type == AV_FILTER_TYPE_KAISER) */ |
enum AVResampleDitherMethod dither_method; /**< dither method */ |
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 */ |
int in_copy_needed; /**< input data copy 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 */ |
enum AVMatrixEncoding matrix_encoding; /**< matrixed stereo encoding */ |
/** |
* mix matrix |
* only used if avresample_set_matrix() is called before avresample_open() |
*/ |
double *mix_matrix; |
int use_channel_map; |
enum RemapPoint remap_point; |
ChannelMapInfo ch_map_info; |
}; |
#endif /* AVRESAMPLE_INTERNAL_H */ |
/contrib/sdk/sources/ffmpeg/libavresample/libavresample.v |
---|
0,0 → 1,4 |
LIBAVRESAMPLE_$MAJOR { |
global: av*; |
local: *; |
}; |
/contrib/sdk/sources/ffmpeg/libavresample/options.c |
---|
0,0 → 1,111 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include "libavutil/mathematics.h" |
#include "libavutil/mem.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 avresample_options[] = { |
{ "in_channel_layout", "Input Channel Layout", OFFSET(in_channel_layout), AV_OPT_TYPE_INT64, { .i64 = 0 }, INT64_MIN, INT64_MAX, PARAM }, |
{ "in_sample_fmt", "Input Sample Format", OFFSET(in_sample_fmt), AV_OPT_TYPE_INT, { .i64 = 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, { .i64 = 48000 }, 1, INT_MAX, PARAM }, |
{ "out_channel_layout", "Output Channel Layout", OFFSET(out_channel_layout), AV_OPT_TYPE_INT64, { .i64 = 0 }, INT64_MIN, INT64_MAX, PARAM }, |
{ "out_sample_fmt", "Output Sample Format", OFFSET(out_sample_fmt), AV_OPT_TYPE_INT, { .i64 = 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, { .i64 = 48000 }, 1, INT_MAX, PARAM }, |
{ "internal_sample_fmt", "Internal Sample Format", OFFSET(internal_sample_fmt), AV_OPT_TYPE_INT, { .i64 = AV_SAMPLE_FMT_NONE }, AV_SAMPLE_FMT_NONE, AV_SAMPLE_FMT_NB-1, PARAM, "internal_sample_fmt" }, |
{"u8" , "8-bit unsigned integer", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_U8 }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, |
{"s16", "16-bit signed integer", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S16 }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, |
{"s32", "32-bit signed integer", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S32 }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, |
{"flt", "32-bit float", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_FLT }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, |
{"dbl", "64-bit double", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_DBL }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, |
{"u8p" , "8-bit unsigned integer planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_U8P }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, |
{"s16p", "16-bit signed integer planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S16P }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, |
{"s32p", "32-bit signed integer planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S32P }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, |
{"fltp", "32-bit float planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_FLTP }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, |
{"dblp", "64-bit double planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_DBLP }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, |
{ "mix_coeff_type", "Mixing Coefficient Type", OFFSET(mix_coeff_type), AV_OPT_TYPE_INT, { .i64 = AV_MIX_COEFF_TYPE_FLT }, AV_MIX_COEFF_TYPE_Q8, AV_MIX_COEFF_TYPE_NB-1, PARAM, "mix_coeff_type" }, |
{ "q8", "16-bit 8.8 Fixed-Point", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MIX_COEFF_TYPE_Q8 }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" }, |
{ "q15", "32-bit 17.15 Fixed-Point", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MIX_COEFF_TYPE_Q15 }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" }, |
{ "flt", "Floating-Point", 0, AV_OPT_TYPE_CONST, { .i64 = 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, { .dbl = M_SQRT1_2 }, -32.0, 32.0, PARAM }, |
{ "surround_mix_level", "Surround Mix Level", OFFSET(surround_mix_level), AV_OPT_TYPE_DOUBLE, { .dbl = M_SQRT1_2 }, -32.0, 32.0, PARAM }, |
{ "lfe_mix_level", "LFE Mix Level", OFFSET(lfe_mix_level), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, -32.0, 32.0, PARAM }, |
{ "normalize_mix_level", "Normalize Mix Level", OFFSET(normalize_mix_level), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, PARAM }, |
{ "force_resampling", "Force Resampling", OFFSET(force_resampling), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, PARAM }, |
{ "filter_size", "Resampling Filter Size", OFFSET(filter_size), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 32, /* ??? */ PARAM }, |
{ "phase_shift", "Resampling Phase Shift", OFFSET(phase_shift), AV_OPT_TYPE_INT, { .i64 = 10 }, 0, 30, /* ??? */ PARAM }, |
{ "linear_interp", "Use Linear Interpolation", OFFSET(linear_interp), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, PARAM }, |
{ "cutoff", "Cutoff Frequency Ratio", OFFSET(cutoff), AV_OPT_TYPE_DOUBLE, { .dbl = 0.8 }, 0.0, 1.0, PARAM }, |
/* duplicate option in order to work with avconv */ |
{ "resample_cutoff", "Cutoff Frequency Ratio", OFFSET(cutoff), AV_OPT_TYPE_DOUBLE, { .dbl = 0.8 }, 0.0, 1.0, PARAM }, |
{ "matrix_encoding", "Matrixed Stereo Encoding", OFFSET(matrix_encoding), AV_OPT_TYPE_INT, {.i64 = AV_MATRIX_ENCODING_NONE}, AV_MATRIX_ENCODING_NONE, AV_MATRIX_ENCODING_NB-1, PARAM, "matrix_encoding" }, |
{ "none", "None", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_NONE }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, |
{ "dolby", "Dolby", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DOLBY }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, |
{ "dplii", "Dolby Pro Logic II", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DPLII }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, |
{ "filter_type", "Filter Type", OFFSET(filter_type), AV_OPT_TYPE_INT, { .i64 = AV_RESAMPLE_FILTER_TYPE_KAISER }, AV_RESAMPLE_FILTER_TYPE_CUBIC, AV_RESAMPLE_FILTER_TYPE_KAISER, PARAM, "filter_type" }, |
{ "cubic", "Cubic", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_FILTER_TYPE_CUBIC }, INT_MIN, INT_MAX, PARAM, "filter_type" }, |
{ "blackman_nuttall", "Blackman Nuttall Windowed Sinc", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL }, INT_MIN, INT_MAX, PARAM, "filter_type" }, |
{ "kaiser", "Kaiser Windowed Sinc", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_FILTER_TYPE_KAISER }, INT_MIN, INT_MAX, PARAM, "filter_type" }, |
{ "kaiser_beta", "Kaiser Window Beta", OFFSET(kaiser_beta), AV_OPT_TYPE_INT, { .i64 = 9 }, 2, 16, PARAM }, |
{ "dither_method", "Dither Method", OFFSET(dither_method), AV_OPT_TYPE_INT, { .i64 = AV_RESAMPLE_DITHER_NONE }, 0, AV_RESAMPLE_DITHER_NB-1, PARAM, "dither_method"}, |
{"none", "No Dithering", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_NONE }, INT_MIN, INT_MAX, PARAM, "dither_method"}, |
{"rectangular", "Rectangular Dither", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_RECTANGULAR }, INT_MIN, INT_MAX, PARAM, "dither_method"}, |
{"triangular", "Triangular Dither", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_TRIANGULAR }, INT_MIN, INT_MAX, PARAM, "dither_method"}, |
{"triangular_hp", "Triangular Dither With High Pass", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_TRIANGULAR_HP }, INT_MIN, INT_MAX, PARAM, "dither_method"}, |
{"triangular_ns", "Triangular Dither With Noise Shaping", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_TRIANGULAR_NS }, INT_MIN, INT_MAX, PARAM, "dither_method"}, |
{ NULL }, |
}; |
static const AVClass av_resample_context_class = { |
.class_name = "AVAudioResampleContext", |
.item_name = av_default_item_name, |
.option = avresample_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); |
return avr; |
} |
const AVClass *avresample_get_class(void) |
{ |
return &av_resample_context_class; |
} |
/contrib/sdk/sources/ffmpeg/libavresample/resample.c |
---|
0,0 → 1,469 |
/* |
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include "libavutil/common.h" |
#include "libavutil/libm.h" |
#include "libavutil/log.h" |
#include "internal.h" |
#include "resample.h" |
#include "audio_data.h" |
struct ResampleContext { |
AVAudioResampleContext *avr; |
AudioData *buffer; |
uint8_t *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; |
enum AVResampleFilterType filter_type; |
int kaiser_beta; |
double factor; |
void (*set_filter)(void *filter, double *tab, int phase, int tap_count); |
void (*resample_one)(struct ResampleContext *c, int no_filter, void *dst0, |
int dst_index, const void *src0, int src_size, |
int index, int frac); |
}; |
/* double template */ |
#define CONFIG_RESAMPLE_DBL |
#include "resample_template.c" |
#undef CONFIG_RESAMPLE_DBL |
/* float template */ |
#define CONFIG_RESAMPLE_FLT |
#include "resample_template.c" |
#undef CONFIG_RESAMPLE_FLT |
/* s32 template */ |
#define CONFIG_RESAMPLE_S32 |
#include "resample_template.c" |
#undef CONFIG_RESAMPLE_S32 |
/* s16 template */ |
#include "resample_template.c" |
/* 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. */ |
static int build_filter(ResampleContext *c) |
{ |
int ph, i; |
double x, y, w, factor; |
double *tab; |
int tap_count = c->filter_length; |
int phase_count = 1 << c->phase_shift; |
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 */ |
factor = FFMIN(c->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 (c->filter_type) { |
case AV_RESAMPLE_FILTER_TYPE_CUBIC: { |
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 AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL: |
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; |
case AV_RESAMPLE_FILTER_TYPE_KAISER: |
w = 2.0 * x / (factor * tap_count * M_PI); |
y *= bessel(c->kaiser_beta * 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++) |
tab[i] = tab[i] / norm; |
c->set_filter(c->filter_bank, tab, ph, tap_count); |
} |
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; |
int felem_size; |
if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P && |
avr->internal_sample_fmt != AV_SAMPLE_FMT_S32P && |
avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP && |
avr->internal_sample_fmt != AV_SAMPLE_FMT_DBLP) { |
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_type = avr->filter_type; |
c->kaiser_beta = avr->kaiser_beta; |
switch (avr->internal_sample_fmt) { |
case AV_SAMPLE_FMT_DBLP: |
c->resample_one = resample_one_dbl; |
c->set_filter = set_filter_dbl; |
break; |
case AV_SAMPLE_FMT_FLTP: |
c->resample_one = resample_one_flt; |
c->set_filter = set_filter_flt; |
break; |
case AV_SAMPLE_FMT_S32P: |
c->resample_one = resample_one_s32; |
c->set_filter = set_filter_s32; |
break; |
case AV_SAMPLE_FMT_S16P: |
c->resample_one = resample_one_s16; |
c->set_filter = set_filter_s16; |
break; |
} |
felem_size = av_get_bytes_per_sample(avr->internal_sample_fmt); |
c->filter_bank = av_mallocz(c->filter_length * (phase_count + 1) * felem_size); |
if (!c->filter_bank) |
goto error; |
if (build_filter(c) < 0) |
goto error; |
memcpy(&c->filter_bank[(c->filter_length * phase_count + 1) * felem_size], |
c->filter_bank, (c->filter_length - 1) * felem_size); |
memcpy(&c->filter_bank[c->filter_length * phase_count * felem_size], |
&c->filter_bank[(c->filter_length - 1) * felem_size], felem_size); |
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 (!avr->resample_needed) { |
#if FF_API_RESAMPLE_CLOSE_OPEN |
/* if resampling was not enabled previously, re-initialize the |
AVAudioResampleContext and force resampling */ |
int fifo_samples; |
int restore_matrix = 0; |
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 */ |
if (avr->am) { |
ret = avresample_get_matrix(avr, matrix, AVRESAMPLE_MAX_CHANNELS); |
if (ret < 0) |
goto reinit_fail; |
restore_matrix = 1; |
} |
/* close the AVAudioResampleContext */ |
avresample_close(avr); |
avr->force_resampling = 1; |
/* restore the channel mixing matrix */ |
if (restore_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); |
} |
#else |
av_log(avr, AV_LOG_ERROR, "Unable to set resampling compensation\n"); |
return AVERROR(EINVAL); |
#endif |
} |
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, void *dst, const void *src, |
int *consumed, int src_size, int dst_size, int update_ctx) |
{ |
int dst_index; |
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++) { |
c->resample_one(c, 1, dst, dst_index, src, 0, index2 >> 32, 0); |
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++) { |
int sample_index = index >> c->phase_shift; |
if (sample_index + c->filter_length > src_size || |
-sample_index >= src_size) |
break; |
if (dst) |
c->resample_one(c, 0, dst, dst_index, src, src_size, index, frac); |
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 ch, in_samples, in_leftover, consumed = 0, 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, (void *)dst->data[ch], |
(const void *)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; |
} |
/contrib/sdk/sources/ffmpeg/libavresample/resample.h |
---|
0,0 → 1,67 |
/* |
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#ifndef AVRESAMPLE_RESAMPLE_H |
#define AVRESAMPLE_RESAMPLE_H |
#include "avresample.h" |
#include "internal.h" |
#include "audio_data.h" |
/** |
* 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 |
* @return 0 on success, negative AVERROR code on failure |
*/ |
int ff_audio_resample(ResampleContext *c, AudioData *dst, AudioData *src); |
#endif /* AVRESAMPLE_RESAMPLE_H */ |
/contrib/sdk/sources/ffmpeg/libavresample/resample_template.c |
---|
0,0 → 1,102 |
/* |
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#if defined(CONFIG_RESAMPLE_DBL) |
#define SET_TYPE(func) func ## _dbl |
#define FELEM double |
#define FELEM2 double |
#define FELEML double |
#define OUT(d, v) d = v |
#define DBL_TO_FELEM(d, v) d = v |
#elif defined(CONFIG_RESAMPLE_FLT) |
#define SET_TYPE(func) func ## _flt |
#define FELEM float |
#define FELEM2 float |
#define FELEML float |
#define OUT(d, v) d = v |
#define DBL_TO_FELEM(d, v) d = v |
#elif defined(CONFIG_RESAMPLE_S32) |
#define SET_TYPE(func) func ## _s32 |
#define FELEM int32_t |
#define FELEM2 int64_t |
#define FELEML int64_t |
#define OUT(d, v) d = av_clipl_int32((v + (1 << 29)) >> 30) |
#define DBL_TO_FELEM(d, v) d = av_clipl_int32(llrint(v * (1 << 30))); |
#else |
#define SET_TYPE(func) func ## _s16 |
#define FELEM int16_t |
#define FELEM2 int32_t |
#define FELEML int64_t |
#define OUT(d, v) d = av_clip_int16((v + (1 << 14)) >> 15) |
#define DBL_TO_FELEM(d, v) d = av_clip_int16(lrint(v * (1 << 15))) |
#endif |
static void SET_TYPE(resample_one)(ResampleContext *c, int no_filter, |
void *dst0, int dst_index, const void *src0, |
int src_size, int index, int frac) |
{ |
FELEM *dst = dst0; |
const FELEM *src = src0; |
if (no_filter) { |
dst[dst_index] = src[index]; |
} else { |
int i; |
int sample_index = index >> c->phase_shift; |
FELEM2 val = 0; |
FELEM *filter = ((FELEM *)c->filter_bank) + |
c->filter_length * (index & c->phase_mask); |
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 (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]; |
} |
OUT(dst[dst_index], val); |
} |
} |
static void SET_TYPE(set_filter)(void *filter0, double *tab, int phase, |
int tap_count) |
{ |
int i; |
FELEM *filter = ((FELEM *)filter0) + phase * tap_count; |
for (i = 0; i < tap_count; i++) { |
DBL_TO_FELEM(filter[i], tab[i]); |
} |
} |
#undef SET_TYPE |
#undef FELEM |
#undef FELEM2 |
#undef FELEML |
#undef OUT |
#undef DBL_TO_FELEM |
/contrib/sdk/sources/ffmpeg/libavresample/utils.c |
---|
0,0 → 1,635 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include "libavutil/common.h" |
#include "libavutil/dict.h" |
// #include "libavutil/error.h" |
#include "libavutil/log.h" |
#include "libavutil/mem.h" |
#include "libavutil/opt.h" |
#include "avresample.h" |
#include "internal.h" |
#include "audio_data.h" |
#include "audio_convert.h" |
#include "audio_mix.h" |
#include "resample.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->downmix_needed && (avr->mix_matrix || |
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; |
/* select internal sample format if not specified by the user */ |
if (avr->internal_sample_fmt == AV_SAMPLE_FMT_NONE && |
(avr->mixing_needed || avr->resample_needed)) { |
enum AVSampleFormat in_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt); |
enum AVSampleFormat out_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); |
int max_bps = FFMAX(av_get_bytes_per_sample(in_fmt), |
av_get_bytes_per_sample(out_fmt)); |
if (max_bps <= 2) { |
avr->internal_sample_fmt = AV_SAMPLE_FMT_S16P; |
} else if (avr->mixing_needed) { |
avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; |
} else { |
if (max_bps <= 4) { |
if (in_fmt == AV_SAMPLE_FMT_S32P || |
out_fmt == AV_SAMPLE_FMT_S32P) { |
if (in_fmt == AV_SAMPLE_FMT_FLTP || |
out_fmt == AV_SAMPLE_FMT_FLTP) { |
/* if one is s32 and the other is flt, use dbl */ |
avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; |
} else { |
/* if one is s32 and the other is s32, s16, or u8, use s32 */ |
avr->internal_sample_fmt = AV_SAMPLE_FMT_S32P; |
} |
} else { |
/* if one is flt and the other is flt, s16 or u8, use flt */ |
avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; |
} |
} else { |
/* if either is dbl, use dbl */ |
avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; |
} |
} |
av_log(avr, AV_LOG_DEBUG, "Using %s as internal sample format\n", |
av_get_sample_fmt_name(avr->internal_sample_fmt)); |
} |
/* treat all mono as planar for easier comparison */ |
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); |
/* we may need to add an extra conversion in order to remap channels if |
the output format is not planar */ |
if (avr->use_channel_map && !avr->mixing_needed && !avr->resample_needed && |
!av_sample_fmt_is_planar(avr->out_sample_fmt)) { |
avr->internal_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); |
} |
/* set sample format conversion parameters */ |
if (avr->resample_needed || avr->mixing_needed) |
avr->in_convert_needed = avr->in_sample_fmt != avr->internal_sample_fmt; |
else |
avr->in_convert_needed = avr->use_channel_map && |
!av_sample_fmt_is_planar(avr->out_sample_fmt); |
if (avr->resample_needed || avr->mixing_needed || avr->in_convert_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; |
avr->in_copy_needed = !avr->in_convert_needed && (avr->mixing_needed || |
(avr->use_channel_map && avr->resample_needed)); |
if (avr->use_channel_map) { |
if (avr->in_copy_needed) { |
avr->remap_point = REMAP_IN_COPY; |
av_dlog(avr, "remap channels during in_copy\n"); |
} else if (avr->in_convert_needed) { |
avr->remap_point = REMAP_IN_CONVERT; |
av_dlog(avr, "remap channels during in_convert\n"); |
} else if (avr->out_convert_needed) { |
avr->remap_point = REMAP_OUT_CONVERT; |
av_dlog(avr, "remap channels during out_convert\n"); |
} else { |
avr->remap_point = REMAP_OUT_COPY; |
av_dlog(avr, "remap channels during out_copy\n"); |
} |
#ifdef DEBUG |
{ |
int ch; |
av_dlog(avr, "output map: "); |
if (avr->ch_map_info.do_remap) |
for (ch = 0; ch < avr->in_channels; ch++) |
av_dlog(avr, " % 2d", avr->ch_map_info.channel_map[ch]); |
else |
av_dlog(avr, "n/a"); |
av_dlog(avr, "\n"); |
av_dlog(avr, "copy map: "); |
if (avr->ch_map_info.do_copy) |
for (ch = 0; ch < avr->in_channels; ch++) |
av_dlog(avr, " % 2d", avr->ch_map_info.channel_copy[ch]); |
else |
av_dlog(avr, "n/a"); |
av_dlog(avr, "\n"); |
av_dlog(avr, "zero map: "); |
if (avr->ch_map_info.do_zero) |
for (ch = 0; ch < avr->in_channels; ch++) |
av_dlog(avr, " % 2d", avr->ch_map_info.channel_zero[ch]); |
else |
av_dlog(avr, "n/a"); |
av_dlog(avr, "\n"); |
av_dlog(avr, "input map: "); |
for (ch = 0; ch < avr->in_channels; ch++) |
av_dlog(avr, " % 2d", avr->ch_map_info.input_map[ch]); |
av_dlog(avr, "\n"); |
} |
#endif |
} else |
avr->remap_point = REMAP_NONE; |
/* allocate buffers */ |
if (avr->in_copy_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, |
avr->in_sample_rate, |
avr->remap_point == REMAP_IN_CONVERT); |
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, |
avr->out_sample_rate, |
avr->remap_point == REMAP_OUT_CONVERT); |
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) { |
avr->am = ff_audio_mix_alloc(avr); |
if (!avr->am) { |
ret = AVERROR(ENOMEM); |
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; |
ff_audio_convert_free(&avr->ac_in); |
ff_audio_convert_free(&avr->ac_out); |
ff_audio_resample_free(&avr->resample); |
ff_audio_mix_free(&avr->am); |
av_freep(&avr->mix_matrix); |
avr->use_channel_map = 0; |
} |
void avresample_free(AVAudioResampleContext **avr) |
{ |
if (!*avr) |
return; |
avresample_close(*avr); |
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, |
avr->remap_point == REMAP_OUT_COPY ? |
&avr->ch_map_info : NULL); |
if (ret < 0) |
return ret; |
av_dlog(avr, "[end conversion]\n"); |
return output->nb_samples; |
} |
av_dlog(avr, "[end conversion]\n"); |
return 0; |
} |
int attribute_align_arg avresample_convert(AVAudioResampleContext *avr, |
uint8_t **output, int out_plane_size, |
int out_samples, uint8_t **input, |
int in_plane_size, int in_samples) |
{ |
AudioData input_buffer; |
AudioData output_buffer; |
AudioData *current_buffer; |
int ret, direct_output; |
/* 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 */ |
direct_output = output && av_audio_fifo_size(avr->out_fifo) == 0; |
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 && direct_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, |
avr->remap_point == REMAP_OUT_COPY ? |
&avr->ch_map_info : NULL); |
if (ret < 0) |
return ret; |
current_buffer = &output_buffer; |
} else if (avr->remap_point == REMAP_OUT_COPY && |
(!direct_output || out_samples < in_samples)) { |
/* if remapping channels during output copy, we may need to |
* use an intermediate buffer in order to remap before adding |
* samples to the output fifo */ |
av_dlog(avr, "[copy] %s to out_buffer\n", current_buffer->name); |
ret = ff_audio_data_copy(avr->out_buffer, current_buffer, |
&avr->ch_map_info); |
if (ret < 0) |
return ret; |
current_buffer = avr->out_buffer; |
} else if (avr->in_copy_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); |
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, |
avr->remap_point == REMAP_IN_COPY ? |
&avr->ch_map_info : NULL); |
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; |
if (!avr->out_convert_needed && direct_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); |
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 (direct_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); |
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); |
if (ret < 0) |
return ret; |
current_buffer = avr->out_buffer; |
} |
} |
return handle_buffered_output(avr, output ? &output_buffer : NULL, |
current_buffer); |
} |
int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix, |
int stride) |
{ |
int in_channels, out_channels, i, o; |
if (avr->am) |
return ff_audio_mix_get_matrix(avr->am, matrix, stride); |
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->mix_matrix) { |
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->mix_matrix[o * in_channels + i]; |
return 0; |
} |
int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, |
int stride) |
{ |
int in_channels, out_channels, i, o; |
if (avr->am) |
return ff_audio_mix_set_matrix(avr->am, matrix, stride); |
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->mix_matrix) |
av_freep(&avr->mix_matrix); |
avr->mix_matrix = av_malloc(in_channels * out_channels * |
sizeof(*avr->mix_matrix)); |
if (!avr->mix_matrix) |
return AVERROR(ENOMEM); |
for (o = 0; o < out_channels; o++) |
for (i = 0; i < in_channels; i++) |
avr->mix_matrix[o * in_channels + i] = matrix[o * stride + i]; |
return 0; |
} |
int avresample_set_channel_mapping(AVAudioResampleContext *avr, |
const int *channel_map) |
{ |
ChannelMapInfo *info = &avr->ch_map_info; |
int in_channels, ch, i; |
in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); |
if (in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS) { |
av_log(avr, AV_LOG_ERROR, "Invalid input channel layout\n"); |
return AVERROR(EINVAL); |
} |
memset(info, 0, sizeof(*info)); |
memset(info->input_map, -1, sizeof(info->input_map)); |
for (ch = 0; ch < in_channels; ch++) { |
if (channel_map[ch] >= in_channels) { |
av_log(avr, AV_LOG_ERROR, "Invalid channel map\n"); |
return AVERROR(EINVAL); |
} |
if (channel_map[ch] < 0) { |
info->channel_zero[ch] = 1; |
info->channel_map[ch] = -1; |
info->do_zero = 1; |
} else if (info->input_map[channel_map[ch]] >= 0) { |
info->channel_copy[ch] = info->input_map[channel_map[ch]]; |
info->channel_map[ch] = -1; |
info->do_copy = 1; |
} else { |
info->channel_map[ch] = channel_map[ch]; |
info->input_map[channel_map[ch]] = ch; |
info->do_remap = 1; |
} |
} |
/* Fill-in unmapped input channels with unmapped output channels. |
This is used when remapping during conversion from interleaved to |
planar format. */ |
for (ch = 0, i = 0; ch < in_channels && i < in_channels; ch++, i++) { |
while (ch < in_channels && info->input_map[ch] >= 0) |
ch++; |
while (i < in_channels && info->channel_map[i] >= 0) |
i++; |
if (ch >= in_channels || i >= in_channels) |
break; |
info->input_map[ch] = i; |
} |
avr->use_channel_map = 1; |
return 0; |
} |
int avresample_available(AVAudioResampleContext *avr) |
{ |
return av_audio_fifo_size(avr->out_fifo); |
} |
int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_samples) |
{ |
if (!output) |
return av_audio_fifo_drain(avr->out_fifo, nb_samples); |
return av_audio_fifo_read(avr->out_fifo, (void**)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; |
} |
/contrib/sdk/sources/ffmpeg/libavresample/version.h |
---|
0,0 → 1,52 |
/* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#ifndef AVRESAMPLE_VERSION_H |
#define AVRESAMPLE_VERSION_H |
/** |
* @file |
* @ingroup lavr |
* Libavresample version macros. |
*/ |
#define LIBAVRESAMPLE_VERSION_MAJOR 1 |
#define LIBAVRESAMPLE_VERSION_MINOR 1 |
#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) |
/** |
* FF_API_* defines may be placed below to indicate public API that will be |
* dropped at a future version bump. The defines themselves are not part of |
* the public API and may change, break or disappear at any time. |
*/ |
#ifndef FF_API_RESAMPLE_CLOSE_OPEN |
#define FF_API_RESAMPLE_CLOSE_OPEN (LIBAVRESAMPLE_VERSION_MAJOR < 2) |
#endif |
#endif /* AVRESAMPLE_VERSION_H */ |
/contrib/sdk/sources/ffmpeg/libavresample/x86/Makefile |
---|
0,0 → 1,7 |
OBJS += x86/audio_convert_init.o \ |
x86/audio_mix_init.o \ |
x86/dither_init.o \ |
YASM-OBJS += x86/audio_convert.o \ |
x86/audio_mix.o \ |
x86/dither.o \ |
/contrib/sdk/sources/ffmpeg/libavresample/x86/audio_convert.asm |
---|
0,0 → 1,1261 |
;****************************************************************************** |
;* x86 optimized Format Conversion Utils |
;* Copyright (c) 2008 Loren Merritt |
;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
;* |
;* This file is part of FFmpeg. |
;* |
;* FFmpeg is free software; you can redistribute it and/or |
;* modify it under the terms of the GNU Lesser General Public |
;* License as published by the Free Software Foundation; either |
;* version 2.1 of the License, or (at your option) any later version. |
;* |
;* FFmpeg is distributed in the hope that it will be useful, |
;* but WITHOUT ANY WARRANTY; without even the implied warranty of |
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
;* Lesser General Public License for more details. |
;* |
;* You should have received a copy of the GNU Lesser General Public |
;* License along with FFmpeg; if not, write to the Free Software |
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
;****************************************************************************** |
%include "libavutil/x86/x86util.asm" |
%include "util.asm" |
SECTION_RODATA 32 |
pf_s32_inv_scale: times 8 dd 0x30000000 |
pf_s32_scale: times 8 dd 0x4f000000 |
pf_s32_clip: times 8 dd 0x4effffff |
pf_s16_inv_scale: times 4 dd 0x38000000 |
pf_s16_scale: times 4 dd 0x47000000 |
pb_shuf_unpack_even: db -1, -1, 0, 1, -1, -1, 2, 3, -1, -1, 8, 9, -1, -1, 10, 11 |
pb_shuf_unpack_odd: db -1, -1, 4, 5, -1, -1, 6, 7, -1, -1, 12, 13, -1, -1, 14, 15 |
pb_interleave_words: SHUFFLE_MASK_W 0, 4, 1, 5, 2, 6, 3, 7 |
pb_deinterleave_words: SHUFFLE_MASK_W 0, 2, 4, 6, 1, 3, 5, 7 |
pw_zero_even: times 4 dw 0x0000, 0xffff |
SECTION_TEXT |
;------------------------------------------------------------------------------ |
; void ff_conv_s16_to_s32(int32_t *dst, const int16_t *src, int len); |
;------------------------------------------------------------------------------ |
INIT_XMM sse2 |
cglobal conv_s16_to_s32, 3,3,3, dst, src, len |
lea lenq, [2*lend] |
lea dstq, [dstq+2*lenq] |
add srcq, lenq |
neg lenq |
.loop: |
mova m2, [srcq+lenq] |
pxor m0, m0 |
pxor m1, m1 |
punpcklwd m0, m2 |
punpckhwd m1, m2 |
mova [dstq+2*lenq ], m0 |
mova [dstq+2*lenq+mmsize], m1 |
add lenq, mmsize |
jl .loop |
REP_RET |
;------------------------------------------------------------------------------ |
; void ff_conv_s16_to_flt(float *dst, const int16_t *src, int len); |
;------------------------------------------------------------------------------ |
%macro CONV_S16_TO_FLT 0 |
cglobal conv_s16_to_flt, 3,3,3, dst, src, len |
lea lenq, [2*lend] |
add srcq, lenq |
lea dstq, [dstq + 2*lenq] |
neg lenq |
mova m2, [pf_s16_inv_scale] |
ALIGN 16 |
.loop: |
mova m0, [srcq+lenq] |
S16_TO_S32_SX 0, 1 |
cvtdq2ps m0, m0 |
cvtdq2ps m1, m1 |
mulps m0, m2 |
mulps m1, m2 |
mova [dstq+2*lenq ], m0 |
mova [dstq+2*lenq+mmsize], m1 |
add lenq, mmsize |
jl .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_S16_TO_FLT |
INIT_XMM sse4 |
CONV_S16_TO_FLT |
;------------------------------------------------------------------------------ |
; void ff_conv_s32_to_s16(int16_t *dst, const int32_t *src, int len); |
;------------------------------------------------------------------------------ |
%macro CONV_S32_TO_S16 0 |
cglobal conv_s32_to_s16, 3,3,4, dst, src, len |
lea lenq, [2*lend] |
lea srcq, [srcq+2*lenq] |
add dstq, lenq |
neg lenq |
.loop: |
mova m0, [srcq+2*lenq ] |
mova m1, [srcq+2*lenq+ mmsize] |
mova m2, [srcq+2*lenq+2*mmsize] |
mova m3, [srcq+2*lenq+3*mmsize] |
psrad m0, 16 |
psrad m1, 16 |
psrad m2, 16 |
psrad m3, 16 |
packssdw m0, m1 |
packssdw m2, m3 |
mova [dstq+lenq ], m0 |
mova [dstq+lenq+mmsize], m2 |
add lenq, mmsize*2 |
jl .loop |
%if mmsize == 8 |
emms |
RET |
%else |
REP_RET |
%endif |
%endmacro |
INIT_MMX mmx |
CONV_S32_TO_S16 |
INIT_XMM sse2 |
CONV_S32_TO_S16 |
;------------------------------------------------------------------------------ |
; void ff_conv_s32_to_flt(float *dst, const int32_t *src, int len); |
;------------------------------------------------------------------------------ |
%macro CONV_S32_TO_FLT 0 |
cglobal conv_s32_to_flt, 3,3,3, dst, src, len |
lea lenq, [4*lend] |
add srcq, lenq |
add dstq, lenq |
neg lenq |
mova m0, [pf_s32_inv_scale] |
ALIGN 16 |
.loop: |
cvtdq2ps m1, [srcq+lenq ] |
cvtdq2ps m2, [srcq+lenq+mmsize] |
mulps m1, m1, m0 |
mulps m2, m2, m0 |
mova [dstq+lenq ], m1 |
mova [dstq+lenq+mmsize], m2 |
add lenq, mmsize*2 |
jl .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_S32_TO_FLT |
%if HAVE_AVX_EXTERNAL |
INIT_YMM avx |
CONV_S32_TO_FLT |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_flt_to_s16(int16_t *dst, const float *src, int len); |
;------------------------------------------------------------------------------ |
INIT_XMM sse2 |
cglobal conv_flt_to_s16, 3,3,5, dst, src, len |
lea lenq, [2*lend] |
lea srcq, [srcq+2*lenq] |
add dstq, lenq |
neg lenq |
mova m4, [pf_s16_scale] |
.loop: |
mova m0, [srcq+2*lenq ] |
mova m1, [srcq+2*lenq+1*mmsize] |
mova m2, [srcq+2*lenq+2*mmsize] |
mova m3, [srcq+2*lenq+3*mmsize] |
mulps m0, m4 |
mulps m1, m4 |
mulps m2, m4 |
mulps m3, m4 |
cvtps2dq m0, m0 |
cvtps2dq m1, m1 |
cvtps2dq m2, m2 |
cvtps2dq m3, m3 |
packssdw m0, m1 |
packssdw m2, m3 |
mova [dstq+lenq ], m0 |
mova [dstq+lenq+mmsize], m2 |
add lenq, mmsize*2 |
jl .loop |
REP_RET |
;------------------------------------------------------------------------------ |
; void ff_conv_flt_to_s32(int32_t *dst, const float *src, int len); |
;------------------------------------------------------------------------------ |
%macro CONV_FLT_TO_S32 0 |
cglobal conv_flt_to_s32, 3,3,6, dst, src, len |
lea lenq, [lend*4] |
add srcq, lenq |
add dstq, lenq |
neg lenq |
mova m4, [pf_s32_scale] |
mova m5, [pf_s32_clip] |
.loop: |
mulps m0, m4, [srcq+lenq ] |
mulps m1, m4, [srcq+lenq+1*mmsize] |
mulps m2, m4, [srcq+lenq+2*mmsize] |
mulps m3, m4, [srcq+lenq+3*mmsize] |
minps m0, m0, m5 |
minps m1, m1, m5 |
minps m2, m2, m5 |
minps m3, m3, m5 |
cvtps2dq m0, m0 |
cvtps2dq m1, m1 |
cvtps2dq m2, m2 |
cvtps2dq m3, m3 |
mova [dstq+lenq ], m0 |
mova [dstq+lenq+1*mmsize], m1 |
mova [dstq+lenq+2*mmsize], m2 |
mova [dstq+lenq+3*mmsize], m3 |
add lenq, mmsize*4 |
jl .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_FLT_TO_S32 |
%if HAVE_AVX_EXTERNAL |
INIT_YMM avx |
CONV_FLT_TO_S32 |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_s16p_to_s16_2ch(int16_t *dst, int16_t *const *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_S16P_TO_S16_2CH 0 |
cglobal conv_s16p_to_s16_2ch, 3,4,5, dst, src0, len, src1 |
mov src1q, [src0q+gprsize] |
mov src0q, [src0q ] |
lea lenq, [2*lend] |
add src0q, lenq |
add src1q, lenq |
lea dstq, [dstq+2*lenq] |
neg lenq |
.loop: |
mova m0, [src0q+lenq ] |
mova m1, [src1q+lenq ] |
mova m2, [src0q+lenq+mmsize] |
mova m3, [src1q+lenq+mmsize] |
SBUTTERFLY2 wd, 0, 1, 4 |
SBUTTERFLY2 wd, 2, 3, 4 |
mova [dstq+2*lenq+0*mmsize], m0 |
mova [dstq+2*lenq+1*mmsize], m1 |
mova [dstq+2*lenq+2*mmsize], m2 |
mova [dstq+2*lenq+3*mmsize], m3 |
add lenq, 2*mmsize |
jl .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_S16P_TO_S16_2CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_S16P_TO_S16_2CH |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_s16p_to_s16_6ch(int16_t *dst, int16_t *const *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
;------------------------------------------------------------------------------ |
; NOTE: In the 6-channel functions, len could be used as an index on x86-64 |
; instead of just a counter, which would avoid incrementing the |
; pointers, but the extra complexity and amount of code is not worth |
; the small gain. On x86-32 there are not enough registers to use len |
; as an index without keeping two of the pointers on the stack and |
; loading them in each iteration. |
;------------------------------------------------------------------------------ |
%macro CONV_S16P_TO_S16_6CH 0 |
%if ARCH_X86_64 |
cglobal conv_s16p_to_s16_6ch, 3,8,7, dst, src0, len, src1, src2, src3, src4, src5 |
%else |
cglobal conv_s16p_to_s16_6ch, 2,7,7, dst, src0, src1, src2, src3, src4, src5 |
%define lend dword r2m |
%endif |
mov src1q, [src0q+1*gprsize] |
mov src2q, [src0q+2*gprsize] |
mov src3q, [src0q+3*gprsize] |
mov src4q, [src0q+4*gprsize] |
mov src5q, [src0q+5*gprsize] |
mov src0q, [src0q] |
sub src1q, src0q |
sub src2q, src0q |
sub src3q, src0q |
sub src4q, src0q |
sub src5q, src0q |
.loop: |
%if cpuflag(sse2slow) |
movq m0, [src0q ] ; m0 = 0, 6, 12, 18, x, x, x, x |
movq m1, [src0q+src1q] ; m1 = 1, 7, 13, 19, x, x, x, x |
movq m2, [src0q+src2q] ; m2 = 2, 8, 14, 20, x, x, x, x |
movq m3, [src0q+src3q] ; m3 = 3, 9, 15, 21, x, x, x, x |
movq m4, [src0q+src4q] ; m4 = 4, 10, 16, 22, x, x, x, x |
movq m5, [src0q+src5q] ; m5 = 5, 11, 17, 23, x, x, x, x |
; unpack words: |
punpcklwd m0, m1 ; m0 = 0, 1, 6, 7, 12, 13, 18, 19 |
punpcklwd m2, m3 ; m2 = 4, 5, 10, 11, 16, 17, 22, 23 |
punpcklwd m4, m5 ; m4 = 2, 3, 8, 9, 14, 15, 20, 21 |
; blend dwords |
shufps m1, m0, m2, q2020 ; m1 = 0, 1, 12, 13, 2, 3, 14, 15 |
shufps m0, m4, q2031 ; m0 = 6, 7, 18, 19, 4, 5, 16, 17 |
shufps m2, m4, q3131 ; m2 = 8, 9, 20, 21, 10, 11, 22, 23 |
; shuffle dwords |
pshufd m0, m0, q1302 ; m0 = 4, 5, 6, 7, 16, 17, 18, 19 |
pshufd m1, m1, q3120 ; m1 = 0, 1, 2, 3, 12, 13, 14, 15 |
pshufd m2, m2, q3120 ; m2 = 8, 9, 10, 11, 20, 21, 22, 23 |
movq [dstq+0*mmsize/2], m1 |
movq [dstq+1*mmsize/2], m0 |
movq [dstq+2*mmsize/2], m2 |
movhps [dstq+3*mmsize/2], m1 |
movhps [dstq+4*mmsize/2], m0 |
movhps [dstq+5*mmsize/2], m2 |
add src0q, mmsize/2 |
add dstq, mmsize*3 |
sub lend, mmsize/4 |
%else |
mova m0, [src0q ] ; m0 = 0, 6, 12, 18, 24, 30, 36, 42 |
mova m1, [src0q+src1q] ; m1 = 1, 7, 13, 19, 25, 31, 37, 43 |
mova m2, [src0q+src2q] ; m2 = 2, 8, 14, 20, 26, 32, 38, 44 |
mova m3, [src0q+src3q] ; m3 = 3, 9, 15, 21, 27, 33, 39, 45 |
mova m4, [src0q+src4q] ; m4 = 4, 10, 16, 22, 28, 34, 40, 46 |
mova m5, [src0q+src5q] ; m5 = 5, 11, 17, 23, 29, 35, 41, 47 |
; unpack words: |
SBUTTERFLY2 wd, 0, 1, 6 ; m0 = 0, 1, 6, 7, 12, 13, 18, 19 |
; m1 = 24, 25, 30, 31, 36, 37, 42, 43 |
SBUTTERFLY2 wd, 2, 3, 6 ; m2 = 2, 3, 8, 9, 14, 15, 20, 21 |
; m3 = 26, 27, 32, 33, 38, 39, 44, 45 |
SBUTTERFLY2 wd, 4, 5, 6 ; m4 = 4, 5, 10, 11, 16, 17, 22, 23 |
; m5 = 28, 29, 34, 35, 40, 41, 46, 47 |
; blend dwords |
shufps m6, m0, m2, q2020 ; m6 = 0, 1, 12, 13, 2, 3, 14, 15 |
shufps m0, m4, q2031 ; m0 = 6, 7, 18, 19, 4, 5, 16, 17 |
shufps m2, m4, q3131 ; m2 = 8, 9, 20, 21, 10, 11, 22, 23 |
SWAP 4,6 ; m4 = 0, 1, 12, 13, 2, 3, 14, 15 |
shufps m6, m1, m3, q2020 ; m6 = 24, 25, 36, 37, 26, 27, 38, 39 |
shufps m1, m5, q2031 ; m1 = 30, 31, 42, 43, 28, 29, 40, 41 |
shufps m3, m5, q3131 ; m3 = 32, 33, 44, 45, 34, 35, 46, 47 |
SWAP 5,6 ; m5 = 24, 25, 36, 37, 26, 27, 38, 39 |
; shuffle dwords |
pshufd m0, m0, q1302 ; m0 = 4, 5, 6, 7, 16, 17, 18, 19 |
pshufd m2, m2, q3120 ; m2 = 8, 9, 10, 11, 20, 21, 22, 23 |
pshufd m4, m4, q3120 ; m4 = 0, 1, 2, 3, 12, 13, 14, 15 |
pshufd m1, m1, q1302 ; m1 = 28, 29, 30, 31, 40, 41, 42, 43 |
pshufd m3, m3, q3120 ; m3 = 32, 33, 34, 35, 44, 45, 46, 47 |
pshufd m5, m5, q3120 ; m5 = 24, 25, 26, 27, 36, 37, 38, 39 |
; shuffle qwords |
punpcklqdq m6, m4, m0 ; m6 = 0, 1, 2, 3, 4, 5, 6, 7 |
punpckhqdq m0, m2 ; m0 = 16, 17, 18, 19, 20, 21, 22, 23 |
shufps m2, m4, q3210 ; m2 = 8, 9, 10, 11, 12, 13, 14, 15 |
SWAP 4,6 ; m4 = 0, 1, 2, 3, 4, 5, 6, 7 |
punpcklqdq m6, m5, m1 ; m6 = 24, 25, 26, 27, 28, 29, 30, 31 |
punpckhqdq m1, m3 ; m1 = 40, 41, 42, 43, 44, 45, 46, 47 |
shufps m3, m5, q3210 ; m3 = 32, 33, 34, 35, 36, 37, 38, 39 |
SWAP 5,6 ; m5 = 24, 25, 26, 27, 28, 29, 30, 31 |
mova [dstq+0*mmsize], m4 |
mova [dstq+1*mmsize], m2 |
mova [dstq+2*mmsize], m0 |
mova [dstq+3*mmsize], m5 |
mova [dstq+4*mmsize], m3 |
mova [dstq+5*mmsize], m1 |
add src0q, mmsize |
add dstq, mmsize*6 |
sub lend, mmsize/2 |
%endif |
jg .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_S16P_TO_S16_6CH |
INIT_XMM sse2slow |
CONV_S16P_TO_S16_6CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_S16P_TO_S16_6CH |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_s16p_to_flt_2ch(float *dst, int16_t *const *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_S16P_TO_FLT_2CH 0 |
cglobal conv_s16p_to_flt_2ch, 3,4,6, dst, src0, len, src1 |
lea lenq, [2*lend] |
mov src1q, [src0q+gprsize] |
mov src0q, [src0q ] |
lea dstq, [dstq+4*lenq] |
add src0q, lenq |
add src1q, lenq |
neg lenq |
mova m5, [pf_s32_inv_scale] |
.loop: |
mova m2, [src0q+lenq] ; m2 = 0, 2, 4, 6, 8, 10, 12, 14 |
mova m4, [src1q+lenq] ; m4 = 1, 3, 5, 7, 9, 11, 13, 15 |
SBUTTERFLY2 wd, 2, 4, 3 ; m2 = 0, 1, 2, 3, 4, 5, 6, 7 |
; m4 = 8, 9, 10, 11, 12, 13, 14, 15 |
pxor m3, m3 |
punpcklwd m0, m3, m2 ; m0 = 0, 1, 2, 3 |
punpckhwd m1, m3, m2 ; m1 = 4, 5, 6, 7 |
punpcklwd m2, m3, m4 ; m2 = 8, 9, 10, 11 |
punpckhwd m3, m4 ; m3 = 12, 13, 14, 15 |
cvtdq2ps m0, m0 |
cvtdq2ps m1, m1 |
cvtdq2ps m2, m2 |
cvtdq2ps m3, m3 |
mulps m0, m5 |
mulps m1, m5 |
mulps m2, m5 |
mulps m3, m5 |
mova [dstq+4*lenq ], m0 |
mova [dstq+4*lenq+ mmsize], m1 |
mova [dstq+4*lenq+2*mmsize], m2 |
mova [dstq+4*lenq+3*mmsize], m3 |
add lenq, mmsize |
jl .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_S16P_TO_FLT_2CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_S16P_TO_FLT_2CH |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_s16p_to_flt_6ch(float *dst, int16_t *const *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_S16P_TO_FLT_6CH 0 |
%if ARCH_X86_64 |
cglobal conv_s16p_to_flt_6ch, 3,8,8, dst, src, len, src1, src2, src3, src4, src5 |
%else |
cglobal conv_s16p_to_flt_6ch, 2,7,8, dst, src, src1, src2, src3, src4, src5 |
%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 |
mova m7, [pf_s32_inv_scale] |
%if cpuflag(ssse3) |
%define unpack_even m6 |
mova m6, [pb_shuf_unpack_even] |
%if ARCH_X86_64 |
%define unpack_odd m8 |
mova m8, [pb_shuf_unpack_odd] |
%else |
%define unpack_odd [pb_shuf_unpack_odd] |
%endif |
%endif |
.loop: |
movq m0, [srcq ] ; m0 = 0, 6, 12, 18, x, x, x, x |
movq m1, [srcq+src1q] ; m1 = 1, 7, 13, 19, x, x, x, x |
movq m2, [srcq+src2q] ; m2 = 2, 8, 14, 20, x, x, x, x |
movq m3, [srcq+src3q] ; m3 = 3, 9, 15, 21, x, x, x, x |
movq m4, [srcq+src4q] ; m4 = 4, 10, 16, 22, x, x, x, x |
movq m5, [srcq+src5q] ; m5 = 5, 11, 17, 23, x, x, x, x |
; unpack words: |
punpcklwd m0, m1 ; m0 = 0, 1, 6, 7, 12, 13, 18, 19 |
punpcklwd m2, m3 ; m2 = 2, 3, 8, 9, 14, 15, 20, 21 |
punpcklwd m4, m5 ; m4 = 4, 5, 10, 11, 16, 17, 22, 23 |
; blend dwords |
shufps m1, m4, m0, q3120 ; m1 = 4, 5, 16, 17, 6, 7, 18, 19 |
shufps m0, m2, q2020 ; m0 = 0, 1, 12, 13, 2, 3, 14, 15 |
shufps m2, m4, q3131 ; m2 = 8, 9, 20, 21, 10, 11, 22, 23 |
%if cpuflag(ssse3) |
pshufb m3, m0, unpack_odd ; m3 = 12, 13, 14, 15 |
pshufb m0, unpack_even ; m0 = 0, 1, 2, 3 |
pshufb m4, m1, unpack_odd ; m4 = 16, 17, 18, 19 |
pshufb m1, unpack_even ; m1 = 4, 5, 6, 7 |
pshufb m5, m2, unpack_odd ; m5 = 20, 21, 22, 23 |
pshufb m2, unpack_even ; m2 = 8, 9, 10, 11 |
%else |
; shuffle dwords |
pshufd m0, m0, q3120 ; m0 = 0, 1, 2, 3, 12, 13, 14, 15 |
pshufd m1, m1, q3120 ; m1 = 4, 5, 6, 7, 16, 17, 18, 19 |
pshufd m2, m2, q3120 ; m2 = 8, 9, 10, 11, 20, 21, 22, 23 |
pxor m6, m6 ; convert s16 in m0-m2 to s32 in m0-m5 |
punpcklwd m3, m6, m0 ; m3 = 0, 1, 2, 3 |
punpckhwd m4, m6, m0 ; m4 = 12, 13, 14, 15 |
punpcklwd m0, m6, m1 ; m0 = 4, 5, 6, 7 |
punpckhwd m5, m6, m1 ; m5 = 16, 17, 18, 19 |
punpcklwd m1, m6, m2 ; m1 = 8, 9, 10, 11 |
punpckhwd m6, m2 ; m6 = 20, 21, 22, 23 |
SWAP 6,2,1,0,3,4,5 ; swap registers 3,0,1,4,5,6 to 0,1,2,3,4,5 |
%endif |
cvtdq2ps m0, m0 ; convert s32 to float |
cvtdq2ps m1, m1 |
cvtdq2ps m2, m2 |
cvtdq2ps m3, m3 |
cvtdq2ps m4, m4 |
cvtdq2ps m5, m5 |
mulps m0, m7 ; scale float from s32 range to [-1.0,1.0] |
mulps m1, m7 |
mulps m2, m7 |
mulps m3, m7 |
mulps m4, m7 |
mulps m5, m7 |
mova [dstq ], m0 |
mova [dstq+ mmsize], m1 |
mova [dstq+2*mmsize], m2 |
mova [dstq+3*mmsize], m3 |
mova [dstq+4*mmsize], m4 |
mova [dstq+5*mmsize], m5 |
add srcq, mmsize/2 |
add dstq, mmsize*6 |
sub lend, mmsize/4 |
jg .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_S16P_TO_FLT_6CH |
INIT_XMM ssse3 |
CONV_S16P_TO_FLT_6CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_S16P_TO_FLT_6CH |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_fltp_to_s16_2ch(int16_t *dst, float *const *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_FLTP_TO_S16_2CH 0 |
cglobal conv_fltp_to_s16_2ch, 3,4,3, dst, src0, len, src1 |
lea lenq, [4*lend] |
mov src1q, [src0q+gprsize] |
mov src0q, [src0q ] |
add dstq, lenq |
add src0q, lenq |
add src1q, lenq |
neg lenq |
mova m2, [pf_s16_scale] |
%if cpuflag(ssse3) |
mova m3, [pb_interleave_words] |
%endif |
.loop: |
mulps m0, m2, [src0q+lenq] ; m0 = 0, 2, 4, 6 |
mulps m1, m2, [src1q+lenq] ; m1 = 1, 3, 5, 7 |
cvtps2dq m0, m0 |
cvtps2dq m1, m1 |
%if cpuflag(ssse3) |
packssdw m0, m1 ; m0 = 0, 2, 4, 6, 1, 3, 5, 7 |
pshufb m0, m3 ; m0 = 0, 1, 2, 3, 4, 5, 6, 7 |
%else |
packssdw m0, m0 ; m0 = 0, 2, 4, 6, x, x, x, x |
packssdw m1, m1 ; m1 = 1, 3, 5, 7, x, x, x, x |
punpcklwd m0, m1 ; m0 = 0, 1, 2, 3, 4, 5, 6, 7 |
%endif |
mova [dstq+lenq], m0 |
add lenq, mmsize |
jl .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_FLTP_TO_S16_2CH |
INIT_XMM ssse3 |
CONV_FLTP_TO_S16_2CH |
;------------------------------------------------------------------------------ |
; void ff_conv_fltp_to_s16_6ch(int16_t *dst, float *const *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_FLTP_TO_S16_6CH 0 |
%if ARCH_X86_64 |
cglobal conv_fltp_to_s16_6ch, 3,8,7, dst, src, len, src1, src2, src3, src4, src5 |
%else |
cglobal conv_fltp_to_s16_6ch, 2,7,7, dst, src, src1, src2, src3, src4, src5 |
%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 |
movaps xmm6, [pf_s16_scale] |
.loop: |
%if cpuflag(sse2) |
mulps m0, m6, [srcq ] |
mulps m1, m6, [srcq+src1q] |
mulps m2, m6, [srcq+src2q] |
mulps m3, m6, [srcq+src3q] |
mulps m4, m6, [srcq+src4q] |
mulps m5, m6, [srcq+src5q] |
cvtps2dq m0, m0 |
cvtps2dq m1, m1 |
cvtps2dq m2, m2 |
cvtps2dq m3, m3 |
cvtps2dq m4, m4 |
cvtps2dq m5, m5 |
packssdw m0, m3 ; m0 = 0, 6, 12, 18, 3, 9, 15, 21 |
packssdw m1, m4 ; m1 = 1, 7, 13, 19, 4, 10, 16, 22 |
packssdw m2, m5 ; m2 = 2, 8, 14, 20, 5, 11, 17, 23 |
; unpack words: |
movhlps m3, m0 ; m3 = 3, 9, 15, 21, x, x, x, x |
punpcklwd m0, m1 ; m0 = 0, 1, 6, 7, 12, 13, 18, 19 |
punpckhwd m1, m2 ; m1 = 4, 5, 10, 11, 16, 17, 22, 23 |
punpcklwd m2, m3 ; m2 = 2, 3, 8, 9, 14, 15, 20, 21 |
; blend dwords: |
shufps m3, m0, m2, q2020 ; m3 = 0, 1, 12, 13, 2, 3, 14, 15 |
shufps m0, m1, q2031 ; m0 = 6, 7, 18, 19, 4, 5, 16, 17 |
shufps m2, m1, q3131 ; m2 = 8, 9, 20, 21, 10, 11, 22, 23 |
; shuffle dwords: |
shufps m1, m2, m3, q3120 ; m1 = 8, 9, 10, 11, 12, 13, 14, 15 |
shufps m3, m0, q0220 ; m3 = 0, 1, 2, 3, 4, 5, 6, 7 |
shufps m0, m2, q3113 ; m0 = 16, 17, 18, 19, 20, 21, 22, 23 |
mova [dstq+0*mmsize], m3 |
mova [dstq+1*mmsize], m1 |
mova [dstq+2*mmsize], m0 |
%else ; sse |
movlps xmm0, [srcq ] |
movlps xmm1, [srcq+src1q] |
movlps xmm2, [srcq+src2q] |
movlps xmm3, [srcq+src3q] |
movlps xmm4, [srcq+src4q] |
movlps xmm5, [srcq+src5q] |
mulps xmm0, xmm6 |
mulps xmm1, xmm6 |
mulps xmm2, xmm6 |
mulps xmm3, xmm6 |
mulps xmm4, xmm6 |
mulps xmm5, xmm6 |
cvtps2pi mm0, xmm0 |
cvtps2pi mm1, xmm1 |
cvtps2pi mm2, xmm2 |
cvtps2pi mm3, xmm3 |
cvtps2pi mm4, xmm4 |
cvtps2pi mm5, xmm5 |
packssdw mm0, mm3 ; m0 = 0, 6, 3, 9 |
packssdw mm1, mm4 ; m1 = 1, 7, 4, 10 |
packssdw mm2, mm5 ; m2 = 2, 8, 5, 11 |
; unpack words |
pshufw mm3, mm0, q1032 ; m3 = 3, 9, 0, 6 |
punpcklwd mm0, mm1 ; m0 = 0, 1, 6, 7 |
punpckhwd mm1, mm2 ; m1 = 4, 5, 10, 11 |
punpcklwd mm2, mm3 ; m2 = 2, 3, 8, 9 |
; unpack dwords |
pshufw mm3, mm0, q1032 ; m3 = 6, 7, 0, 1 |
punpckldq mm0, mm2 ; m0 = 0, 1, 2, 3 (final) |
punpckhdq mm2, mm1 ; m2 = 8, 9, 10, 11 (final) |
punpckldq mm1, mm3 ; m1 = 4, 5, 6, 7 (final) |
mova [dstq+0*mmsize], mm0 |
mova [dstq+1*mmsize], mm1 |
mova [dstq+2*mmsize], mm2 |
%endif |
add srcq, mmsize |
add dstq, mmsize*3 |
sub lend, mmsize/4 |
jg .loop |
%if mmsize == 8 |
emms |
RET |
%else |
REP_RET |
%endif |
%endmacro |
INIT_MMX sse |
CONV_FLTP_TO_S16_6CH |
INIT_XMM sse2 |
CONV_FLTP_TO_S16_6CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_FLTP_TO_S16_6CH |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_fltp_to_flt_2ch(float *dst, float *const *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_FLTP_TO_FLT_2CH 0 |
cglobal conv_fltp_to_flt_2ch, 3,4,5, dst, src0, len, src1 |
mov src1q, [src0q+gprsize] |
mov src0q, [src0q] |
lea lenq, [4*lend] |
add src0q, lenq |
add src1q, lenq |
lea dstq, [dstq+2*lenq] |
neg lenq |
.loop: |
mova m0, [src0q+lenq ] |
mova m1, [src1q+lenq ] |
mova m2, [src0q+lenq+mmsize] |
mova m3, [src1q+lenq+mmsize] |
SBUTTERFLYPS 0, 1, 4 |
SBUTTERFLYPS 2, 3, 4 |
mova [dstq+2*lenq+0*mmsize], m0 |
mova [dstq+2*lenq+1*mmsize], m1 |
mova [dstq+2*lenq+2*mmsize], m2 |
mova [dstq+2*lenq+3*mmsize], m3 |
add lenq, 2*mmsize |
jl .loop |
REP_RET |
%endmacro |
INIT_XMM sse |
CONV_FLTP_TO_FLT_2CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_FLTP_TO_FLT_2CH |
%endif |
;----------------------------------------------------------------------------- |
; 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(sse4) |
SBUTTERFLYPS 0, 1, 6 |
SBUTTERFLYPS 2, 3, 6 |
SBUTTERFLYPS 4, 5, 6 |
blendps m6, m4, m0, 1100b |
movlhps m0, m2 |
movhlps m4, m2 |
blendps m2, m5, m1, 1100b |
movlhps m1, m3 |
movhlps m5, m3 |
movaps [dstq ], m0 |
movaps [dstq+16], m6 |
movaps [dstq+32], m4 |
movaps [dstq+48], m1 |
movaps [dstq+64], m2 |
movaps [dstq+80], m5 |
%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 sse4 |
CONV_FLTP_TO_FLT_6CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_FLTP_TO_FLT_6CH |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_s16_to_s16p_2ch(int16_t *const *dst, int16_t *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_S16_TO_S16P_2CH 0 |
cglobal conv_s16_to_s16p_2ch, 3,4,4, dst0, src, len, dst1 |
lea lenq, [2*lend] |
mov dst1q, [dst0q+gprsize] |
mov dst0q, [dst0q ] |
lea srcq, [srcq+2*lenq] |
add dst0q, lenq |
add dst1q, lenq |
neg lenq |
%if cpuflag(ssse3) |
mova m3, [pb_deinterleave_words] |
%endif |
.loop: |
mova m0, [srcq+2*lenq ] ; m0 = 0, 1, 2, 3, 4, 5, 6, 7 |
mova m1, [srcq+2*lenq+mmsize] ; m1 = 8, 9, 10, 11, 12, 13, 14, 15 |
%if cpuflag(ssse3) |
pshufb m0, m3 ; m0 = 0, 2, 4, 6, 1, 3, 5, 7 |
pshufb m1, m3 ; m1 = 8, 10, 12, 14, 9, 11, 13, 15 |
SBUTTERFLY2 qdq, 0, 1, 2 ; m0 = 0, 2, 4, 6, 8, 10, 12, 14 |
; m1 = 1, 3, 5, 7, 9, 11, 13, 15 |
%else ; sse2 |
pshuflw m0, m0, q3120 ; m0 = 0, 2, 1, 3, 4, 5, 6, 7 |
pshufhw m0, m0, q3120 ; m0 = 0, 2, 1, 3, 4, 6, 5, 7 |
pshuflw m1, m1, q3120 ; m1 = 8, 10, 9, 11, 12, 13, 14, 15 |
pshufhw m1, m1, q3120 ; m1 = 8, 10, 9, 11, 12, 14, 13, 15 |
DEINT2_PS 0, 1, 2 ; m0 = 0, 2, 4, 6, 8, 10, 12, 14 |
; m1 = 1, 3, 5, 7, 9, 11, 13, 15 |
%endif |
mova [dst0q+lenq], m0 |
mova [dst1q+lenq], m1 |
add lenq, mmsize |
jl .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_S16_TO_S16P_2CH |
INIT_XMM ssse3 |
CONV_S16_TO_S16P_2CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_S16_TO_S16P_2CH |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_s16_to_s16p_6ch(int16_t *const *dst, int16_t *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_S16_TO_S16P_6CH 0 |
%if ARCH_X86_64 |
cglobal conv_s16_to_s16p_6ch, 3,8,5, dst, src, len, dst1, dst2, dst3, dst4, dst5 |
%else |
cglobal conv_s16_to_s16p_6ch, 2,7,5, dst, src, dst1, dst2, dst3, dst4, dst5 |
%define lend dword r2m |
%endif |
mov dst1q, [dstq+ gprsize] |
mov dst2q, [dstq+2*gprsize] |
mov dst3q, [dstq+3*gprsize] |
mov dst4q, [dstq+4*gprsize] |
mov dst5q, [dstq+5*gprsize] |
mov dstq, [dstq ] |
sub dst1q, dstq |
sub dst2q, dstq |
sub dst3q, dstq |
sub dst4q, dstq |
sub dst5q, dstq |
.loop: |
mova m0, [srcq+0*mmsize] ; m0 = 0, 1, 2, 3, 4, 5, 6, 7 |
mova m3, [srcq+1*mmsize] ; m3 = 8, 9, 10, 11, 12, 13, 14, 15 |
mova m2, [srcq+2*mmsize] ; m2 = 16, 17, 18, 19, 20, 21, 22, 23 |
PALIGNR m1, m3, m0, 12, m4 ; m1 = 6, 7, 8, 9, 10, 11, x, x |
shufps m3, m2, q1032 ; m3 = 12, 13, 14, 15, 16, 17, 18, 19 |
psrldq m2, 4 ; m2 = 18, 19, 20, 21, 22, 23, x, x |
SBUTTERFLY2 wd, 0, 1, 4 ; m0 = 0, 6, 1, 7, 2, 8, 3, 9 |
; m1 = 4, 10, 5, 11, x, x, x, x |
SBUTTERFLY2 wd, 3, 2, 4 ; m3 = 12, 18, 13, 19, 14, 20, 15, 21 |
; m2 = 16, 22, 17, 23, x, x, x, x |
SBUTTERFLY2 dq, 0, 3, 4 ; m0 = 0, 6, 12, 18, 1, 7, 13, 19 |
; m3 = 2, 8, 14, 20, 3, 9, 15, 21 |
punpckldq m1, m2 ; m1 = 4, 10, 16, 22, 5, 11, 17, 23 |
movq [dstq ], m0 |
movhps [dstq+dst1q], m0 |
movq [dstq+dst2q], m3 |
movhps [dstq+dst3q], m3 |
movq [dstq+dst4q], m1 |
movhps [dstq+dst5q], m1 |
add srcq, mmsize*3 |
add dstq, mmsize/2 |
sub lend, mmsize/4 |
jg .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_S16_TO_S16P_6CH |
INIT_XMM ssse3 |
CONV_S16_TO_S16P_6CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_S16_TO_S16P_6CH |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_s16_to_fltp_2ch(float *const *dst, int16_t *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_S16_TO_FLTP_2CH 0 |
cglobal conv_s16_to_fltp_2ch, 3,4,5, dst0, src, len, dst1 |
lea lenq, [4*lend] |
mov dst1q, [dst0q+gprsize] |
mov dst0q, [dst0q ] |
add srcq, lenq |
add dst0q, lenq |
add dst1q, lenq |
neg lenq |
mova m3, [pf_s32_inv_scale] |
mova m4, [pw_zero_even] |
.loop: |
mova m1, [srcq+lenq] |
pslld m0, m1, 16 |
pand m1, m4 |
cvtdq2ps m0, m0 |
cvtdq2ps m1, m1 |
mulps m0, m0, m3 |
mulps m1, m1, m3 |
mova [dst0q+lenq], m0 |
mova [dst1q+lenq], m1 |
add lenq, mmsize |
jl .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_S16_TO_FLTP_2CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_S16_TO_FLTP_2CH |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_s16_to_fltp_6ch(float *const *dst, int16_t *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_S16_TO_FLTP_6CH 0 |
%if ARCH_X86_64 |
cglobal conv_s16_to_fltp_6ch, 3,8,7, dst, src, len, dst1, dst2, dst3, dst4, dst5 |
%else |
cglobal conv_s16_to_fltp_6ch, 2,7,7, dst, src, dst1, dst2, dst3, dst4, dst5 |
%define lend dword r2m |
%endif |
mov dst1q, [dstq+ gprsize] |
mov dst2q, [dstq+2*gprsize] |
mov dst3q, [dstq+3*gprsize] |
mov dst4q, [dstq+4*gprsize] |
mov dst5q, [dstq+5*gprsize] |
mov dstq, [dstq ] |
sub dst1q, dstq |
sub dst2q, dstq |
sub dst3q, dstq |
sub dst4q, dstq |
sub dst5q, dstq |
mova m6, [pf_s16_inv_scale] |
.loop: |
mova m0, [srcq+0*mmsize] ; m0 = 0, 1, 2, 3, 4, 5, 6, 7 |
mova m3, [srcq+1*mmsize] ; m3 = 8, 9, 10, 11, 12, 13, 14, 15 |
mova m2, [srcq+2*mmsize] ; m2 = 16, 17, 18, 19, 20, 21, 22, 23 |
PALIGNR m1, m3, m0, 12, m4 ; m1 = 6, 7, 8, 9, 10, 11, x, x |
shufps m3, m2, q1032 ; m3 = 12, 13, 14, 15, 16, 17, 18, 19 |
psrldq m2, 4 ; m2 = 18, 19, 20, 21, 22, 23, x, x |
SBUTTERFLY2 wd, 0, 1, 4 ; m0 = 0, 6, 1, 7, 2, 8, 3, 9 |
; m1 = 4, 10, 5, 11, x, x, x, x |
SBUTTERFLY2 wd, 3, 2, 4 ; m3 = 12, 18, 13, 19, 14, 20, 15, 21 |
; m2 = 16, 22, 17, 23, x, x, x, x |
SBUTTERFLY2 dq, 0, 3, 4 ; m0 = 0, 6, 12, 18, 1, 7, 13, 19 |
; m3 = 2, 8, 14, 20, 3, 9, 15, 21 |
punpckldq m1, m2 ; m1 = 4, 10, 16, 22, 5, 11, 17, 23 |
S16_TO_S32_SX 0, 2 ; m0 = 0, 6, 12, 18 |
; m2 = 1, 7, 13, 19 |
S16_TO_S32_SX 3, 4 ; m3 = 2, 8, 14, 20 |
; m4 = 3, 9, 15, 21 |
S16_TO_S32_SX 1, 5 ; m1 = 4, 10, 16, 22 |
; m5 = 5, 11, 17, 23 |
SWAP 1,2,3,4 |
cvtdq2ps m0, m0 |
cvtdq2ps m1, m1 |
cvtdq2ps m2, m2 |
cvtdq2ps m3, m3 |
cvtdq2ps m4, m4 |
cvtdq2ps m5, m5 |
mulps m0, m6 |
mulps m1, m6 |
mulps m2, m6 |
mulps m3, m6 |
mulps m4, m6 |
mulps m5, m6 |
mova [dstq ], m0 |
mova [dstq+dst1q], m1 |
mova [dstq+dst2q], m2 |
mova [dstq+dst3q], m3 |
mova [dstq+dst4q], m4 |
mova [dstq+dst5q], m5 |
add srcq, mmsize*3 |
add dstq, mmsize |
sub lend, mmsize/4 |
jg .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_S16_TO_FLTP_6CH |
INIT_XMM ssse3 |
CONV_S16_TO_FLTP_6CH |
INIT_XMM sse4 |
CONV_S16_TO_FLTP_6CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_S16_TO_FLTP_6CH |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_flt_to_s16p_2ch(int16_t *const *dst, float *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_FLT_TO_S16P_2CH 0 |
cglobal conv_flt_to_s16p_2ch, 3,4,6, dst0, src, len, dst1 |
lea lenq, [2*lend] |
mov dst1q, [dst0q+gprsize] |
mov dst0q, [dst0q ] |
lea srcq, [srcq+4*lenq] |
add dst0q, lenq |
add dst1q, lenq |
neg lenq |
mova m5, [pf_s16_scale] |
.loop: |
mova m0, [srcq+4*lenq ] |
mova m1, [srcq+4*lenq+ mmsize] |
mova m2, [srcq+4*lenq+2*mmsize] |
mova m3, [srcq+4*lenq+3*mmsize] |
DEINT2_PS 0, 1, 4 |
DEINT2_PS 2, 3, 4 |
mulps m0, m0, m5 |
mulps m1, m1, m5 |
mulps m2, m2, m5 |
mulps m3, m3, m5 |
cvtps2dq m0, m0 |
cvtps2dq m1, m1 |
cvtps2dq m2, m2 |
cvtps2dq m3, m3 |
packssdw m0, m2 |
packssdw m1, m3 |
mova [dst0q+lenq], m0 |
mova [dst1q+lenq], m1 |
add lenq, mmsize |
jl .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_FLT_TO_S16P_2CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_FLT_TO_S16P_2CH |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_flt_to_s16p_6ch(int16_t *const *dst, float *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_FLT_TO_S16P_6CH 0 |
%if ARCH_X86_64 |
cglobal conv_flt_to_s16p_6ch, 3,8,7, dst, src, len, dst1, dst2, dst3, dst4, dst5 |
%else |
cglobal conv_flt_to_s16p_6ch, 2,7,7, dst, src, dst1, dst2, dst3, dst4, dst5 |
%define lend dword r2m |
%endif |
mov dst1q, [dstq+ gprsize] |
mov dst2q, [dstq+2*gprsize] |
mov dst3q, [dstq+3*gprsize] |
mov dst4q, [dstq+4*gprsize] |
mov dst5q, [dstq+5*gprsize] |
mov dstq, [dstq ] |
sub dst1q, dstq |
sub dst2q, dstq |
sub dst3q, dstq |
sub dst4q, dstq |
sub dst5q, dstq |
mova m6, [pf_s16_scale] |
.loop: |
mulps m0, m6, [srcq+0*mmsize] |
mulps m3, m6, [srcq+1*mmsize] |
mulps m1, m6, [srcq+2*mmsize] |
mulps m4, m6, [srcq+3*mmsize] |
mulps m2, m6, [srcq+4*mmsize] |
mulps m5, m6, [srcq+5*mmsize] |
cvtps2dq m0, m0 |
cvtps2dq m1, m1 |
cvtps2dq m2, m2 |
cvtps2dq m3, m3 |
cvtps2dq m4, m4 |
cvtps2dq m5, m5 |
packssdw m0, m3 ; m0 = 0, 1, 2, 3, 4, 5, 6, 7 |
packssdw m1, m4 ; m1 = 8, 9, 10, 11, 12, 13, 14, 15 |
packssdw m2, m5 ; m2 = 16, 17, 18, 19, 20, 21, 22, 23 |
PALIGNR m3, m1, m0, 12, m4 ; m3 = 6, 7, 8, 9, 10, 11, x, x |
shufps m1, m2, q1032 ; m1 = 12, 13, 14, 15, 16, 17, 18, 19 |
psrldq m2, 4 ; m2 = 18, 19, 20, 21, 22, 23, x, x |
SBUTTERFLY2 wd, 0, 3, 4 ; m0 = 0, 6, 1, 7, 2, 8, 3, 9 |
; m3 = 4, 10, 5, 11, x, x, x, x |
SBUTTERFLY2 wd, 1, 2, 4 ; m1 = 12, 18, 13, 19, 14, 20, 15, 21 |
; m2 = 16, 22, 17, 23, x, x, x, x |
SBUTTERFLY2 dq, 0, 1, 4 ; m0 = 0, 6, 12, 18, 1, 7, 13, 19 |
; m1 = 2, 8, 14, 20, 3, 9, 15, 21 |
punpckldq m3, m2 ; m3 = 4, 10, 16, 22, 5, 11, 17, 23 |
movq [dstq ], m0 |
movhps [dstq+dst1q], m0 |
movq [dstq+dst2q], m1 |
movhps [dstq+dst3q], m1 |
movq [dstq+dst4q], m3 |
movhps [dstq+dst5q], m3 |
add srcq, mmsize*6 |
add dstq, mmsize/2 |
sub lend, mmsize/4 |
jg .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_FLT_TO_S16P_6CH |
INIT_XMM ssse3 |
CONV_FLT_TO_S16P_6CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_FLT_TO_S16P_6CH |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_flt_to_fltp_2ch(float *const *dst, float *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_FLT_TO_FLTP_2CH 0 |
cglobal conv_flt_to_fltp_2ch, 3,4,3, dst0, src, len, dst1 |
lea lenq, [4*lend] |
mov dst1q, [dst0q+gprsize] |
mov dst0q, [dst0q ] |
lea srcq, [srcq+2*lenq] |
add dst0q, lenq |
add dst1q, lenq |
neg lenq |
.loop: |
mova m0, [srcq+2*lenq ] |
mova m1, [srcq+2*lenq+mmsize] |
DEINT2_PS 0, 1, 2 |
mova [dst0q+lenq], m0 |
mova [dst1q+lenq], m1 |
add lenq, mmsize |
jl .loop |
REP_RET |
%endmacro |
INIT_XMM sse |
CONV_FLT_TO_FLTP_2CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_FLT_TO_FLTP_2CH |
%endif |
;------------------------------------------------------------------------------ |
; void ff_conv_flt_to_fltp_6ch(float *const *dst, float *src, int len, |
; int channels); |
;------------------------------------------------------------------------------ |
%macro CONV_FLT_TO_FLTP_6CH 0 |
%if ARCH_X86_64 |
cglobal conv_flt_to_fltp_6ch, 3,8,7, dst, src, len, dst1, dst2, dst3, dst4, dst5 |
%else |
cglobal conv_flt_to_fltp_6ch, 2,7,7, dst, src, dst1, dst2, dst3, dst4, dst5 |
%define lend dword r2m |
%endif |
mov dst1q, [dstq+ gprsize] |
mov dst2q, [dstq+2*gprsize] |
mov dst3q, [dstq+3*gprsize] |
mov dst4q, [dstq+4*gprsize] |
mov dst5q, [dstq+5*gprsize] |
mov dstq, [dstq ] |
sub dst1q, dstq |
sub dst2q, dstq |
sub dst3q, dstq |
sub dst4q, dstq |
sub dst5q, dstq |
.loop: |
mova m0, [srcq+0*mmsize] ; m0 = 0, 1, 2, 3 |
mova m1, [srcq+1*mmsize] ; m1 = 4, 5, 6, 7 |
mova m2, [srcq+2*mmsize] ; m2 = 8, 9, 10, 11 |
mova m3, [srcq+3*mmsize] ; m3 = 12, 13, 14, 15 |
mova m4, [srcq+4*mmsize] ; m4 = 16, 17, 18, 19 |
mova m5, [srcq+5*mmsize] ; m5 = 20, 21, 22, 23 |
SBUTTERFLY2 dq, 0, 3, 6 ; m0 = 0, 12, 1, 13 |
; m3 = 2, 14, 3, 15 |
SBUTTERFLY2 dq, 1, 4, 6 ; m1 = 4, 16, 5, 17 |
; m4 = 6, 18, 7, 19 |
SBUTTERFLY2 dq, 2, 5, 6 ; m2 = 8, 20, 9, 21 |
; m5 = 10, 22, 11, 23 |
SBUTTERFLY2 dq, 0, 4, 6 ; m0 = 0, 6, 12, 18 |
; m4 = 1, 7, 13, 19 |
SBUTTERFLY2 dq, 3, 2, 6 ; m3 = 2, 8, 14, 20 |
; m2 = 3, 9, 15, 21 |
SBUTTERFLY2 dq, 1, 5, 6 ; m1 = 4, 10, 16, 22 |
; m5 = 5, 11, 17, 23 |
mova [dstq ], m0 |
mova [dstq+dst1q], m4 |
mova [dstq+dst2q], m3 |
mova [dstq+dst3q], m2 |
mova [dstq+dst4q], m1 |
mova [dstq+dst5q], m5 |
add srcq, mmsize*6 |
add dstq, mmsize |
sub lend, mmsize/4 |
jg .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
CONV_FLT_TO_FLTP_6CH |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
CONV_FLT_TO_FLTP_6CH |
%endif |
/contrib/sdk/sources/ffmpeg/libavresample/x86/audio_convert_init.c |
---|
0,0 → 1,263 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include "config.h" |
#include "libavutil/cpu.h" |
#include "libavutil/x86/cpu.h" |
#include "libavresample/audio_convert.h" |
/* flat conversions */ |
void ff_conv_s16_to_s32_sse2(int16_t *dst, const int32_t *src, int len); |
void ff_conv_s16_to_flt_sse2(float *dst, const int16_t *src, int len); |
void ff_conv_s16_to_flt_sse4(float *dst, const int16_t *src, int len); |
void ff_conv_s32_to_s16_mmx (int16_t *dst, const int32_t *src, int len); |
void ff_conv_s32_to_s16_sse2(int16_t *dst, const int32_t *src, int len); |
void ff_conv_s32_to_flt_sse2(float *dst, const int32_t *src, int len); |
void ff_conv_s32_to_flt_avx (float *dst, const int32_t *src, int len); |
void ff_conv_flt_to_s16_sse2(int16_t *dst, const float *src, int len); |
void ff_conv_flt_to_s32_sse2(int32_t *dst, const float *src, int len); |
void ff_conv_flt_to_s32_avx (int32_t *dst, const float *src, int len); |
/* interleave conversions */ |
void ff_conv_s16p_to_s16_2ch_sse2(int16_t *dst, int16_t *const *src, |
int len, int channels); |
void ff_conv_s16p_to_s16_2ch_avx (int16_t *dst, int16_t *const *src, |
int len, int channels); |
void ff_conv_s16p_to_s16_6ch_sse2(int16_t *dst, int16_t *const *src, |
int len, int channels); |
void ff_conv_s16p_to_s16_6ch_sse2slow(int16_t *dst, int16_t *const *src, |
int len, int channels); |
void ff_conv_s16p_to_s16_6ch_avx (int16_t *dst, int16_t *const *src, |
int len, int channels); |
void ff_conv_s16p_to_flt_2ch_sse2(float *dst, int16_t *const *src, |
int len, int channels); |
void ff_conv_s16p_to_flt_2ch_avx (float *dst, int16_t *const *src, |
int len, int channels); |
void ff_conv_s16p_to_flt_6ch_sse2 (float *dst, int16_t *const *src, |
int len, int channels); |
void ff_conv_s16p_to_flt_6ch_ssse3(float *dst, int16_t *const *src, |
int len, int channels); |
void ff_conv_s16p_to_flt_6ch_avx (float *dst, int16_t *const *src, |
int len, int channels); |
void ff_conv_fltp_to_s16_2ch_sse2 (int16_t *dst, float *const *src, |
int len, int channels); |
void ff_conv_fltp_to_s16_2ch_ssse3(int16_t *dst, float *const *src, |
int len, int channels); |
void ff_conv_fltp_to_s16_6ch_sse (int16_t *dst, float *const *src, |
int len, int channels); |
void ff_conv_fltp_to_s16_6ch_sse2(int16_t *dst, float *const *src, |
int len, int channels); |
void ff_conv_fltp_to_s16_6ch_avx (int16_t *dst, float *const *src, |
int len, int channels); |
void ff_conv_fltp_to_flt_2ch_sse(float *dst, float *const *src, int len, |
int channels); |
void ff_conv_fltp_to_flt_2ch_avx(float *dst, float *const *src, int len, |
int channels); |
void ff_conv_fltp_to_flt_6ch_mmx (float *dst, float *const *src, int len, |
int channels); |
void ff_conv_fltp_to_flt_6ch_sse4(float *dst, float *const *src, int len, |
int channels); |
void ff_conv_fltp_to_flt_6ch_avx (float *dst, float *const *src, int len, |
int channels); |
/* deinterleave conversions */ |
void ff_conv_s16_to_s16p_2ch_sse2(int16_t *const *dst, int16_t *src, |
int len, int channels); |
void ff_conv_s16_to_s16p_2ch_ssse3(int16_t *const *dst, int16_t *src, |
int len, int channels); |
void ff_conv_s16_to_s16p_2ch_avx (int16_t *const *dst, int16_t *src, |
int len, int channels); |
void ff_conv_s16_to_s16p_6ch_sse2 (int16_t *const *dst, int16_t *src, |
int len, int channels); |
void ff_conv_s16_to_s16p_6ch_ssse3(int16_t *const *dst, int16_t *src, |
int len, int channels); |
void ff_conv_s16_to_s16p_6ch_avx (int16_t *const *dst, int16_t *src, |
int len, int channels); |
void ff_conv_s16_to_fltp_2ch_sse2(float *const *dst, int16_t *src, |
int len, int channels); |
void ff_conv_s16_to_fltp_2ch_avx (float *const *dst, int16_t *src, |
int len, int channels); |
void ff_conv_s16_to_fltp_6ch_sse2 (float *const *dst, int16_t *src, |
int len, int channels); |
void ff_conv_s16_to_fltp_6ch_ssse3(float *const *dst, int16_t *src, |
int len, int channels); |
void ff_conv_s16_to_fltp_6ch_sse4 (float *const *dst, int16_t *src, |
int len, int channels); |
void ff_conv_s16_to_fltp_6ch_avx (float *const *dst, int16_t *src, |
int len, int channels); |
void ff_conv_flt_to_s16p_2ch_sse2(int16_t *const *dst, float *src, |
int len, int channels); |
void ff_conv_flt_to_s16p_2ch_avx (int16_t *const *dst, float *src, |
int len, int channels); |
void ff_conv_flt_to_s16p_6ch_sse2 (int16_t *const *dst, float *src, |
int len, int channels); |
void ff_conv_flt_to_s16p_6ch_ssse3(int16_t *const *dst, float *src, |
int len, int channels); |
void ff_conv_flt_to_s16p_6ch_avx (int16_t *const *dst, float *src, |
int len, int channels); |
void ff_conv_flt_to_fltp_2ch_sse(float *const *dst, float *src, int len, |
int channels); |
void ff_conv_flt_to_fltp_2ch_avx(float *const *dst, float *src, int len, |
int channels); |
void ff_conv_flt_to_fltp_6ch_sse2(float *const *dst, float *src, int len, |
int channels); |
void ff_conv_flt_to_fltp_6ch_avx (float *const *dst, float *src, int len, |
int channels); |
av_cold void ff_audio_convert_init_x86(AudioConvert *ac) |
{ |
int cpu_flags = av_get_cpu_flags(); |
if (EXTERNAL_MMX(cpu_flags)) { |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, |
0, 1, 8, "MMX", ff_conv_s32_to_s16_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 (EXTERNAL_SSE(cpu_flags)) { |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, |
6, 1, 2, "SSE", ff_conv_fltp_to_s16_6ch_sse); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, |
2, 16, 8, "SSE", ff_conv_fltp_to_flt_2ch_sse); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT, |
2, 16, 4, "SSE", ff_conv_flt_to_fltp_2ch_sse); |
} |
if (EXTERNAL_SSE2(cpu_flags)) { |
if (!(cpu_flags & AV_CPU_FLAG_SSE2SLOW)) { |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, |
0, 16, 16, "SSE2", ff_conv_s32_to_s16_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, |
6, 16, 8, "SSE2", ff_conv_s16p_to_s16_6ch_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, |
6, 16, 4, "SSE2", ff_conv_fltp_to_s16_6ch_sse2); |
} else { |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, |
6, 1, 4, "SSE2SLOW", ff_conv_s16p_to_s16_6ch_sse2slow); |
} |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16, |
0, 16, 8, "SSE2", ff_conv_s16_to_s32_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16, |
0, 16, 8, "SSE2", ff_conv_s16_to_flt_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32, |
0, 16, 8, "SSE2", ff_conv_s32_to_flt_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT, |
0, 16, 16, "SSE2", ff_conv_flt_to_s16_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT, |
0, 16, 16, "SSE2", ff_conv_flt_to_s32_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, |
2, 16, 16, "SSE2", ff_conv_s16p_to_s16_2ch_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P, |
2, 16, 8, "SSE2", ff_conv_s16p_to_flt_2ch_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P, |
6, 16, 4, "SSE2", ff_conv_s16p_to_flt_6ch_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, |
2, 16, 4, "SSE2", ff_conv_fltp_to_s16_2ch_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16, |
2, 16, 8, "SSE2", ff_conv_s16_to_s16p_2ch_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16, |
6, 16, 4, "SSE2", ff_conv_s16_to_s16p_6ch_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16, |
2, 16, 8, "SSE2", ff_conv_s16_to_fltp_2ch_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16, |
6, 16, 4, "SSE2", ff_conv_s16_to_fltp_6ch_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT, |
2, 16, 8, "SSE2", ff_conv_flt_to_s16p_2ch_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT, |
6, 16, 4, "SSE2", ff_conv_flt_to_s16p_6ch_sse2); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT, |
6, 16, 4, "SSE2", ff_conv_flt_to_fltp_6ch_sse2); |
} |
if (EXTERNAL_SSSE3(cpu_flags)) { |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P, |
6, 16, 4, "SSSE3", ff_conv_s16p_to_flt_6ch_ssse3); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, |
2, 16, 4, "SSSE3", ff_conv_fltp_to_s16_2ch_ssse3); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16, |
2, 16, 8, "SSSE3", ff_conv_s16_to_s16p_2ch_ssse3); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16, |
6, 16, 4, "SSSE3", ff_conv_s16_to_s16p_6ch_ssse3); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16, |
6, 16, 4, "SSSE3", ff_conv_s16_to_fltp_6ch_ssse3); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT, |
6, 16, 4, "SSSE3", ff_conv_flt_to_s16p_6ch_ssse3); |
} |
if (EXTERNAL_SSE4(cpu_flags)) { |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16, |
0, 16, 8, "SSE4", ff_conv_s16_to_flt_sse4); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, |
6, 16, 4, "SSE4", ff_conv_fltp_to_flt_6ch_sse4); |
} |
if (EXTERNAL_AVX(cpu_flags)) { |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32, |
0, 32, 16, "AVX", ff_conv_s32_to_flt_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT, |
0, 32, 32, "AVX", ff_conv_flt_to_s32_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, |
2, 16, 16, "AVX", ff_conv_s16p_to_s16_2ch_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, |
6, 16, 8, "AVX", ff_conv_s16p_to_s16_6ch_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P, |
2, 16, 8, "AVX", ff_conv_s16p_to_flt_2ch_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P, |
6, 16, 4, "AVX", ff_conv_s16p_to_flt_6ch_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, |
6, 16, 4, "AVX", ff_conv_fltp_to_s16_6ch_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, |
6, 16, 4, "AVX", ff_conv_fltp_to_flt_6ch_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16, |
2, 16, 8, "AVX", ff_conv_s16_to_s16p_2ch_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16, |
6, 16, 4, "AVX", ff_conv_s16_to_s16p_6ch_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16, |
2, 16, 8, "AVX", ff_conv_s16_to_fltp_2ch_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16, |
6, 16, 4, "AVX", ff_conv_s16_to_fltp_6ch_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT, |
2, 16, 8, "AVX", ff_conv_flt_to_s16p_2ch_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT, |
6, 16, 4, "AVX", ff_conv_flt_to_s16p_6ch_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT, |
2, 16, 4, "AVX", ff_conv_flt_to_fltp_2ch_avx); |
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT, |
6, 16, 4, "AVX", ff_conv_flt_to_fltp_6ch_avx); |
} |
} |
/contrib/sdk/sources/ffmpeg/libavresample/x86/audio_mix.asm |
---|
0,0 → 1,511 |
;****************************************************************************** |
;* x86 optimized channel mixing |
;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
;* |
;* This file is part of FFmpeg. |
;* |
;* FFmpeg is free software; you can redistribute it and/or |
;* modify it under the terms of the GNU Lesser General Public |
;* License as published by the Free Software Foundation; either |
;* version 2.1 of the License, or (at your option) any later version. |
;* |
;* FFmpeg is distributed in the hope that it will be useful, |
;* but WITHOUT ANY WARRANTY; without even the implied warranty of |
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
;* Lesser General Public License for more details. |
;* |
;* You should have received a copy of the GNU Lesser General Public |
;* License along with FFmpeg; if not, write to the Free Software |
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
;****************************************************************************** |
%include "libavutil/x86/x86util.asm" |
%include "util.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 |
REP_RET |
%endmacro |
INIT_XMM sse |
MIX_2_TO_1_FLTP_FLT |
%if HAVE_AVX_EXTERNAL |
INIT_YMM avx |
MIX_2_TO_1_FLTP_FLT |
%endif |
;----------------------------------------------------------------------------- |
; void ff_mix_2_to_1_s16p_flt(int16_t **src, float **matrix, int len, |
; int out_ch, int in_ch); |
;----------------------------------------------------------------------------- |
%macro MIX_2_TO_1_S16P_FLT 0 |
cglobal mix_2_to_1_s16p_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: |
mova m0, [srcq ] |
mova m2, [srcq+src1q] |
S16_TO_S32_SX 0, 1 |
S16_TO_S32_SX 2, 3 |
cvtdq2ps m0, m0 |
cvtdq2ps m1, m1 |
cvtdq2ps m2, m2 |
cvtdq2ps m3, m3 |
mulps m0, m4 |
mulps m1, m4 |
mulps m2, m5 |
mulps m3, m5 |
addps m0, m2 |
addps m1, m3 |
cvtps2dq m0, m0 |
cvtps2dq m1, m1 |
packssdw m0, m1 |
mova [srcq], m0 |
add srcq, mmsize |
sub lend, mmsize/2 |
jg .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
MIX_2_TO_1_S16P_FLT |
INIT_XMM sse4 |
MIX_2_TO_1_S16P_FLT |
;----------------------------------------------------------------------------- |
; void ff_mix_2_to_1_s16p_q8(int16_t **src, int16_t **matrix, int len, |
; int out_ch, int in_ch); |
;----------------------------------------------------------------------------- |
INIT_XMM sse2 |
cglobal mix_2_to_1_s16p_q8, 3,4,6, src, matrix, len, src1 |
mov src1q, [srcq+gprsize] |
mov srcq, [srcq] |
sub src1q, srcq |
mov matrixq, [matrixq] |
movd m4, [matrixq] |
movd m5, [matrixq] |
SPLATW m4, m4, 0 |
SPLATW m5, m5, 1 |
pxor m0, m0 |
punpcklwd m4, m0 |
punpcklwd m5, m0 |
ALIGN 16 |
.loop: |
mova m0, [srcq ] |
mova m2, [srcq+src1q] |
punpckhwd m1, m0, m0 |
punpcklwd m0, m0 |
punpckhwd m3, m2, m2 |
punpcklwd m2, m2 |
pmaddwd m0, m4 |
pmaddwd m1, m4 |
pmaddwd m2, m5 |
pmaddwd m3, m5 |
paddd m0, m2 |
paddd m1, m3 |
psrad m0, 8 |
psrad m1, 8 |
packssdw m0, m1 |
mova [srcq], m0 |
add srcq, mmsize |
sub lend, mmsize/2 |
jg .loop |
REP_RET |
;----------------------------------------------------------------------------- |
; void ff_mix_1_to_2_fltp_flt(float **src, float **matrix, int len, |
; int out_ch, int in_ch); |
;----------------------------------------------------------------------------- |
%macro MIX_1_TO_2_FLTP_FLT 0 |
cglobal mix_1_to_2_fltp_flt, 3,5,4, src0, matrix0, len, src1, matrix1 |
mov src1q, [src0q+gprsize] |
mov src0q, [src0q] |
sub src1q, src0q |
mov matrix1q, [matrix0q+gprsize] |
mov matrix0q, [matrix0q] |
VBROADCASTSS m2, [matrix0q] |
VBROADCASTSS m3, [matrix1q] |
ALIGN 16 |
.loop: |
mova m0, [src0q] |
mulps m1, m0, m3 |
mulps m0, m0, m2 |
mova [src0q ], m0 |
mova [src0q+src1q], m1 |
add src0q, mmsize |
sub lend, mmsize/4 |
jg .loop |
REP_RET |
%endmacro |
INIT_XMM sse |
MIX_1_TO_2_FLTP_FLT |
%if HAVE_AVX_EXTERNAL |
INIT_YMM avx |
MIX_1_TO_2_FLTP_FLT |
%endif |
;----------------------------------------------------------------------------- |
; void ff_mix_1_to_2_s16p_flt(int16_t **src, float **matrix, int len, |
; int out_ch, int in_ch); |
;----------------------------------------------------------------------------- |
%macro MIX_1_TO_2_S16P_FLT 0 |
cglobal mix_1_to_2_s16p_flt, 3,5,6, src0, matrix0, len, src1, matrix1 |
mov src1q, [src0q+gprsize] |
mov src0q, [src0q] |
sub src1q, src0q |
mov matrix1q, [matrix0q+gprsize] |
mov matrix0q, [matrix0q] |
VBROADCASTSS m4, [matrix0q] |
VBROADCASTSS m5, [matrix1q] |
ALIGN 16 |
.loop: |
mova m0, [src0q] |
S16_TO_S32_SX 0, 2 |
cvtdq2ps m0, m0 |
cvtdq2ps m2, m2 |
mulps m1, m0, m5 |
mulps m0, m0, m4 |
mulps m3, m2, m5 |
mulps m2, m2, m4 |
cvtps2dq m0, m0 |
cvtps2dq m1, m1 |
cvtps2dq m2, m2 |
cvtps2dq m3, m3 |
packssdw m0, m2 |
packssdw m1, m3 |
mova [src0q ], m0 |
mova [src0q+src1q], m1 |
add src0q, mmsize |
sub lend, mmsize/2 |
jg .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
MIX_1_TO_2_S16P_FLT |
INIT_XMM sse4 |
MIX_1_TO_2_S16P_FLT |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
MIX_1_TO_2_S16P_FLT |
%endif |
;----------------------------------------------------------------------------- |
; void ff_mix_3_8_to_1_2_fltp/s16p_flt(float/int16_t **src, float **matrix, |
; int len, int out_ch, int in_ch); |
;----------------------------------------------------------------------------- |
%macro MIX_3_8_TO_1_2_FLT 3 ; %1 = in channels, %2 = out channels, %3 = s16p or fltp |
; define some names to make the code clearer |
%assign in_channels %1 |
%assign out_channels %2 |
%assign stereo out_channels - 1 |
%ifidn %3, s16p |
%assign is_s16 1 |
%else |
%assign is_s16 0 |
%endif |
; determine how many matrix elements must go on the stack vs. mmregs |
%assign matrix_elements in_channels * out_channels |
%if is_s16 |
%if stereo |
%assign needed_mmregs 7 |
%else |
%assign needed_mmregs 5 |
%endif |
%else |
%if stereo |
%assign needed_mmregs 4 |
%else |
%assign needed_mmregs 3 |
%endif |
%endif |
%assign matrix_elements_mm num_mmregs - needed_mmregs |
%if matrix_elements < matrix_elements_mm |
%assign matrix_elements_mm matrix_elements |
%endif |
%if matrix_elements_mm < matrix_elements |
%assign matrix_elements_stack matrix_elements - matrix_elements_mm |
%else |
%assign matrix_elements_stack 0 |
%endif |
%assign matrix_stack_size matrix_elements_stack * mmsize |
%assign needed_stack_size -1 * matrix_stack_size |
%if ARCH_X86_32 && in_channels >= 7 |
%assign needed_stack_size needed_stack_size - 16 |
%endif |
cglobal mix_%1_to_%2_%3_flt, 3,in_channels+2,needed_mmregs+matrix_elements_mm, needed_stack_size, src0, src1, len, src2, src3, src4, src5, src6, src7 |
; define src pointers on stack if needed |
%if matrix_elements_stack > 0 && ARCH_X86_32 && in_channels >= 7 |
%define src5m [rsp+matrix_stack_size+0] |
%define src6m [rsp+matrix_stack_size+4] |
%define src7m [rsp+matrix_stack_size+8] |
%endif |
; load matrix pointers |
%define matrix0q r1q |
%define matrix1q r3q |
%if stereo |
mov matrix1q, [matrix0q+gprsize] |
%endif |
mov matrix0q, [matrix0q] |
; define matrix coeff names |
%assign %%i 0 |
%assign %%j needed_mmregs |
%rep in_channels |
%if %%i >= matrix_elements_mm |
CAT_XDEFINE mx_stack_0_, %%i, 1 |
CAT_XDEFINE mx_0_, %%i, [rsp+(%%i-matrix_elements_mm)*mmsize] |
%else |
CAT_XDEFINE mx_stack_0_, %%i, 0 |
CAT_XDEFINE mx_0_, %%i, m %+ %%j |
%assign %%j %%j+1 |
%endif |
%assign %%i %%i+1 |
%endrep |
%if stereo |
%assign %%i 0 |
%rep in_channels |
%if in_channels + %%i >= matrix_elements_mm |
CAT_XDEFINE mx_stack_1_, %%i, 1 |
CAT_XDEFINE mx_1_, %%i, [rsp+(in_channels+%%i-matrix_elements_mm)*mmsize] |
%else |
CAT_XDEFINE mx_stack_1_, %%i, 0 |
CAT_XDEFINE mx_1_, %%i, m %+ %%j |
%assign %%j %%j+1 |
%endif |
%assign %%i %%i+1 |
%endrep |
%endif |
; load/splat matrix coeffs |
%assign %%i 0 |
%rep in_channels |
%if mx_stack_0_ %+ %%i |
VBROADCASTSS m0, [matrix0q+4*%%i] |
mova mx_0_ %+ %%i, m0 |
%else |
VBROADCASTSS mx_0_ %+ %%i, [matrix0q+4*%%i] |
%endif |
%if stereo |
%if mx_stack_1_ %+ %%i |
VBROADCASTSS m0, [matrix1q+4*%%i] |
mova mx_1_ %+ %%i, m0 |
%else |
VBROADCASTSS mx_1_ %+ %%i, [matrix1q+4*%%i] |
%endif |
%endif |
%assign %%i %%i+1 |
%endrep |
; load channel pointers to registers as offsets from the first channel pointer |
%if ARCH_X86_64 |
movsxd lenq, r2d |
%endif |
shl lenq, 2-is_s16 |
%assign %%i 1 |
%rep (in_channels - 1) |
%if ARCH_X86_32 && in_channels >= 7 && %%i >= 5 |
mov src5q, [src0q+%%i*gprsize] |
add src5q, lenq |
mov src %+ %%i %+ m, src5q |
%else |
mov src %+ %%i %+ q, [src0q+%%i*gprsize] |
add src %+ %%i %+ q, lenq |
%endif |
%assign %%i %%i+1 |
%endrep |
mov src0q, [src0q] |
add src0q, lenq |
neg lenq |
.loop: |
; for x86-32 with 7-8 channels we do not have enough gp registers for all src |
; pointers, so we have to load some of them from the stack each time |
%define copy_src_from_stack ARCH_X86_32 && in_channels >= 7 && %%i >= 5 |
%if is_s16 |
; mix with s16p input |
mova m0, [src0q+lenq] |
S16_TO_S32_SX 0, 1 |
cvtdq2ps m0, m0 |
cvtdq2ps m1, m1 |
%if stereo |
mulps m2, m0, mx_1_0 |
mulps m3, m1, mx_1_0 |
%endif |
mulps m0, m0, mx_0_0 |
mulps m1, m1, mx_0_0 |
%assign %%i 1 |
%rep (in_channels - 1) |
%if copy_src_from_stack |
%define src_ptr src5q |
%else |
%define src_ptr src %+ %%i %+ q |
%endif |
%if stereo |
%if copy_src_from_stack |
mov src_ptr, src %+ %%i %+ m |
%endif |
mova m4, [src_ptr+lenq] |
S16_TO_S32_SX 4, 5 |
cvtdq2ps m4, m4 |
cvtdq2ps m5, m5 |
FMULADD_PS m2, m4, mx_1_ %+ %%i, m2, m6 |
FMULADD_PS m3, m5, mx_1_ %+ %%i, m3, m6 |
FMULADD_PS m0, m4, mx_0_ %+ %%i, m0, m4 |
FMULADD_PS m1, m5, mx_0_ %+ %%i, m1, m5 |
%else |
%if copy_src_from_stack |
mov src_ptr, src %+ %%i %+ m |
%endif |
mova m2, [src_ptr+lenq] |
S16_TO_S32_SX 2, 3 |
cvtdq2ps m2, m2 |
cvtdq2ps m3, m3 |
FMULADD_PS m0, m2, mx_0_ %+ %%i, m0, m4 |
FMULADD_PS m1, m3, mx_0_ %+ %%i, m1, m4 |
%endif |
%assign %%i %%i+1 |
%endrep |
%if stereo |
cvtps2dq m2, m2 |
cvtps2dq m3, m3 |
packssdw m2, m3 |
mova [src1q+lenq], m2 |
%endif |
cvtps2dq m0, m0 |
cvtps2dq m1, m1 |
packssdw m0, m1 |
mova [src0q+lenq], m0 |
%else |
; mix with fltp input |
%if stereo || mx_stack_0_0 |
mova m0, [src0q+lenq] |
%endif |
%if stereo |
mulps m1, m0, mx_1_0 |
%endif |
%if stereo || mx_stack_0_0 |
mulps m0, m0, mx_0_0 |
%else |
mulps m0, mx_0_0, [src0q+lenq] |
%endif |
%assign %%i 1 |
%rep (in_channels - 1) |
%if copy_src_from_stack |
%define src_ptr src5q |
mov src_ptr, src %+ %%i %+ m |
%else |
%define src_ptr src %+ %%i %+ q |
%endif |
; avoid extra load for mono if matrix is in a mm register |
%if stereo || mx_stack_0_ %+ %%i |
mova m2, [src_ptr+lenq] |
%endif |
%if stereo |
FMULADD_PS m1, m2, mx_1_ %+ %%i, m1, m3 |
%endif |
%if stereo || mx_stack_0_ %+ %%i |
FMULADD_PS m0, m2, mx_0_ %+ %%i, m0, m2 |
%else |
FMULADD_PS m0, mx_0_ %+ %%i, [src_ptr+lenq], m0, m1 |
%endif |
%assign %%i %%i+1 |
%endrep |
mova [src0q+lenq], m0 |
%if stereo |
mova [src1q+lenq], m1 |
%endif |
%endif |
add lenq, mmsize |
jl .loop |
; zero ymm high halves |
%if mmsize == 32 |
vzeroupper |
%endif |
RET |
%endmacro |
%macro MIX_3_8_TO_1_2_FLT_FUNCS 0 |
%assign %%i 3 |
%rep 6 |
INIT_XMM sse |
MIX_3_8_TO_1_2_FLT %%i, 1, fltp |
MIX_3_8_TO_1_2_FLT %%i, 2, fltp |
INIT_XMM sse2 |
MIX_3_8_TO_1_2_FLT %%i, 1, s16p |
MIX_3_8_TO_1_2_FLT %%i, 2, s16p |
INIT_XMM sse4 |
MIX_3_8_TO_1_2_FLT %%i, 1, s16p |
MIX_3_8_TO_1_2_FLT %%i, 2, s16p |
; do not use ymm AVX or FMA4 in x86-32 for 6 or more channels due to stack alignment issues |
%if HAVE_AVX_EXTERNAL |
%if ARCH_X86_64 || %%i < 6 |
INIT_YMM avx |
%else |
INIT_XMM avx |
%endif |
MIX_3_8_TO_1_2_FLT %%i, 1, fltp |
MIX_3_8_TO_1_2_FLT %%i, 2, fltp |
INIT_XMM avx |
MIX_3_8_TO_1_2_FLT %%i, 1, s16p |
MIX_3_8_TO_1_2_FLT %%i, 2, s16p |
%endif |
%if HAVE_FMA4_EXTERNAL |
%if ARCH_X86_64 || %%i < 6 |
INIT_YMM fma4 |
%else |
INIT_XMM fma4 |
%endif |
MIX_3_8_TO_1_2_FLT %%i, 1, fltp |
MIX_3_8_TO_1_2_FLT %%i, 2, fltp |
INIT_XMM fma4 |
MIX_3_8_TO_1_2_FLT %%i, 1, s16p |
MIX_3_8_TO_1_2_FLT %%i, 2, s16p |
%endif |
%assign %%i %%i+1 |
%endrep |
%endmacro |
MIX_3_8_TO_1_2_FLT_FUNCS |
/contrib/sdk/sources/ffmpeg/libavresample/x86/audio_mix_init.c |
---|
0,0 → 1,215 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include "config.h" |
#include "libavutil/cpu.h" |
#include "libavutil/x86/cpu.h" |
#include "libavresample/audio_mix.h" |
void ff_mix_2_to_1_fltp_flt_sse(float **src, float **matrix, int len, |
int out_ch, int in_ch); |
void ff_mix_2_to_1_fltp_flt_avx(float **src, float **matrix, int len, |
int out_ch, int in_ch); |
void ff_mix_2_to_1_s16p_flt_sse2(int16_t **src, float **matrix, int len, |
int out_ch, int in_ch); |
void ff_mix_2_to_1_s16p_flt_sse4(int16_t **src, float **matrix, int len, |
int out_ch, int in_ch); |
void ff_mix_2_to_1_s16p_q8_sse2(int16_t **src, int16_t **matrix, |
int len, int out_ch, int in_ch); |
void ff_mix_1_to_2_fltp_flt_sse(float **src, float **matrix, int len, |
int out_ch, int in_ch); |
void ff_mix_1_to_2_fltp_flt_avx(float **src, float **matrix, int len, |
int out_ch, int in_ch); |
void ff_mix_1_to_2_s16p_flt_sse2(int16_t **src, float **matrix, int len, |
int out_ch, int in_ch); |
void ff_mix_1_to_2_s16p_flt_sse4(int16_t **src, float **matrix, int len, |
int out_ch, int in_ch); |
void ff_mix_1_to_2_s16p_flt_avx (int16_t **src, float **matrix, int len, |
int out_ch, int in_ch); |
#define DEFINE_MIX_3_8_TO_1_2(chan) \ |
void ff_mix_ ## chan ## _to_1_fltp_flt_sse(float **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); \ |
void ff_mix_ ## chan ## _to_2_fltp_flt_sse(float **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); \ |
\ |
void ff_mix_ ## chan ## _to_1_s16p_flt_sse2(int16_t **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); \ |
void ff_mix_ ## chan ## _to_2_s16p_flt_sse2(int16_t **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); \ |
\ |
void ff_mix_ ## chan ## _to_1_s16p_flt_sse4(int16_t **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); \ |
void ff_mix_ ## chan ## _to_2_s16p_flt_sse4(int16_t **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); \ |
\ |
void ff_mix_ ## chan ## _to_1_fltp_flt_avx(float **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); \ |
void ff_mix_ ## chan ## _to_2_fltp_flt_avx(float **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); \ |
\ |
void ff_mix_ ## chan ## _to_1_s16p_flt_avx(int16_t **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); \ |
void ff_mix_ ## chan ## _to_2_s16p_flt_avx(int16_t **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); \ |
\ |
void ff_mix_ ## chan ## _to_1_fltp_flt_fma4(float **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); \ |
void ff_mix_ ## chan ## _to_2_fltp_flt_fma4(float **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); \ |
\ |
void ff_mix_ ## chan ## _to_1_s16p_flt_fma4(int16_t **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); \ |
void ff_mix_ ## chan ## _to_2_s16p_flt_fma4(int16_t **src, \ |
float **matrix, int len, \ |
int out_ch, int in_ch); |
DEFINE_MIX_3_8_TO_1_2(3) |
DEFINE_MIX_3_8_TO_1_2(4) |
DEFINE_MIX_3_8_TO_1_2(5) |
DEFINE_MIX_3_8_TO_1_2(6) |
DEFINE_MIX_3_8_TO_1_2(7) |
DEFINE_MIX_3_8_TO_1_2(8) |
#define SET_MIX_3_8_TO_1_2(chan) \ |
if (EXTERNAL_SSE(cpu_flags)) { \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 1, 16, 4, "SSE", \ |
ff_mix_ ## chan ## _to_1_fltp_flt_sse); \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 2, 16, 4, "SSE", \ |
ff_mix_## chan ##_to_2_fltp_flt_sse); \ |
} \ |
if (EXTERNAL_SSE2(cpu_flags)) { \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 1, 16, 8, "SSE2", \ |
ff_mix_ ## chan ## _to_1_s16p_flt_sse2); \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 2, 16, 8, "SSE2", \ |
ff_mix_ ## chan ## _to_2_s16p_flt_sse2); \ |
} \ |
if (EXTERNAL_SSE4(cpu_flags)) { \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 1, 16, 8, "SSE4", \ |
ff_mix_ ## chan ## _to_1_s16p_flt_sse4); \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 2, 16, 8, "SSE4", \ |
ff_mix_ ## chan ## _to_2_s16p_flt_sse4); \ |
} \ |
if (EXTERNAL_AVX(cpu_flags)) { \ |
int ptr_align = 32; \ |
int smp_align = 8; \ |
if (ARCH_X86_32 || chan >= 6) { \ |
ptr_align = 16; \ |
smp_align = 4; \ |
} \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 1, ptr_align, smp_align, "AVX", \ |
ff_mix_ ## chan ## _to_1_fltp_flt_avx); \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 2, ptr_align, smp_align, "AVX", \ |
ff_mix_ ## chan ## _to_2_fltp_flt_avx); \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 1, 16, 8, "AVX", \ |
ff_mix_ ## chan ## _to_1_s16p_flt_avx); \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 2, 16, 8, "AVX", \ |
ff_mix_ ## chan ## _to_2_s16p_flt_avx); \ |
} \ |
if (EXTERNAL_FMA4(cpu_flags)) { \ |
int ptr_align = 32; \ |
int smp_align = 8; \ |
if (ARCH_X86_32 || chan >= 6) { \ |
ptr_align = 16; \ |
smp_align = 4; \ |
} \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 1, ptr_align, smp_align, "FMA4", \ |
ff_mix_ ## chan ## _to_1_fltp_flt_fma4); \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 2, ptr_align, smp_align, "FMA4", \ |
ff_mix_ ## chan ## _to_2_fltp_flt_fma4); \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 1, 16, 8, "FMA4", \ |
ff_mix_ ## chan ## _to_1_s16p_flt_fma4); \ |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ |
chan, 2, 16, 8, "FMA4", \ |
ff_mix_ ## chan ## _to_2_s16p_flt_fma4); \ |
} |
av_cold void ff_audio_mix_init_x86(AudioMix *am) |
{ |
#if HAVE_YASM |
int cpu_flags = av_get_cpu_flags(); |
if (EXTERNAL_SSE(cpu_flags)) { |
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); |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, |
1, 2, 16, 4, "SSE", ff_mix_1_to_2_fltp_flt_sse); |
} |
if (EXTERNAL_SSE2(cpu_flags)) { |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, |
2, 1, 16, 8, "SSE2", ff_mix_2_to_1_s16p_flt_sse2); |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8, |
2, 1, 16, 8, "SSE2", ff_mix_2_to_1_s16p_q8_sse2); |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, |
1, 2, 16, 8, "SSE2", ff_mix_1_to_2_s16p_flt_sse2); |
} |
if (EXTERNAL_SSE4(cpu_flags)) { |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, |
2, 1, 16, 8, "SSE4", ff_mix_2_to_1_s16p_flt_sse4); |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, |
1, 2, 16, 8, "SSE4", ff_mix_1_to_2_s16p_flt_sse4); |
} |
if (EXTERNAL_AVX(cpu_flags)) { |
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); |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, |
1, 2, 32, 8, "AVX", ff_mix_1_to_2_fltp_flt_avx); |
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, |
1, 2, 16, 8, "AVX", ff_mix_1_to_2_s16p_flt_avx); |
} |
SET_MIX_3_8_TO_1_2(3) |
SET_MIX_3_8_TO_1_2(4) |
SET_MIX_3_8_TO_1_2(5) |
SET_MIX_3_8_TO_1_2(6) |
SET_MIX_3_8_TO_1_2(7) |
SET_MIX_3_8_TO_1_2(8) |
#endif /* HAVE_YASM */ |
} |
/contrib/sdk/sources/ffmpeg/libavresample/x86/dither.asm |
---|
0,0 → 1,117 |
;****************************************************************************** |
;* x86 optimized dithering format conversion |
;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
;* |
;* This file is part of FFmpeg. |
;* |
;* FFmpeg is free software; you can redistribute it and/or |
;* modify it under the terms of the GNU Lesser General Public |
;* License as published by the Free Software Foundation; either |
;* version 2.1 of the License, or (at your option) any later version. |
;* |
;* FFmpeg is distributed in the hope that it will be useful, |
;* but WITHOUT ANY WARRANTY; without even the implied warranty of |
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
;* Lesser General Public License for more details. |
;* |
;* You should have received a copy of the GNU Lesser General Public |
;* License along with FFmpeg; if not, write to the Free Software |
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
;****************************************************************************** |
%include "libavutil/x86/x86util.asm" |
SECTION_RODATA 32 |
; 1.0f / (2.0f * INT32_MAX) |
pf_dither_scale: times 8 dd 2.32830643762e-10 |
pf_s16_scale: times 4 dd 32753.0 |
SECTION_TEXT |
;------------------------------------------------------------------------------ |
; void ff_quantize(int16_t *dst, float *src, float *dither, int len); |
;------------------------------------------------------------------------------ |
INIT_XMM sse2 |
cglobal quantize, 4,4,3, dst, src, dither, len |
lea lenq, [2*lend] |
add dstq, lenq |
lea srcq, [srcq+2*lenq] |
lea ditherq, [ditherq+2*lenq] |
neg lenq |
mova m2, [pf_s16_scale] |
.loop: |
mulps m0, m2, [srcq+2*lenq] |
mulps m1, m2, [srcq+2*lenq+mmsize] |
addps m0, [ditherq+2*lenq] |
addps m1, [ditherq+2*lenq+mmsize] |
cvtps2dq m0, m0 |
cvtps2dq m1, m1 |
packssdw m0, m1 |
mova [dstq+lenq], m0 |
add lenq, mmsize |
jl .loop |
REP_RET |
;------------------------------------------------------------------------------ |
; void ff_dither_int_to_float_rectangular(float *dst, int *src, int len) |
;------------------------------------------------------------------------------ |
%macro DITHER_INT_TO_FLOAT_RECTANGULAR 0 |
cglobal dither_int_to_float_rectangular, 3,3,3, dst, src, len |
lea lenq, [4*lend] |
add srcq, lenq |
add dstq, lenq |
neg lenq |
mova m0, [pf_dither_scale] |
.loop: |
cvtdq2ps m1, [srcq+lenq] |
cvtdq2ps m2, [srcq+lenq+mmsize] |
mulps m1, m1, m0 |
mulps m2, m2, m0 |
mova [dstq+lenq], m1 |
mova [dstq+lenq+mmsize], m2 |
add lenq, 2*mmsize |
jl .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
DITHER_INT_TO_FLOAT_RECTANGULAR |
INIT_YMM avx |
DITHER_INT_TO_FLOAT_RECTANGULAR |
;------------------------------------------------------------------------------ |
; void ff_dither_int_to_float_triangular(float *dst, int *src0, int len) |
;------------------------------------------------------------------------------ |
%macro DITHER_INT_TO_FLOAT_TRIANGULAR 0 |
cglobal dither_int_to_float_triangular, 3,4,5, dst, src0, len, src1 |
lea lenq, [4*lend] |
lea src1q, [src0q+2*lenq] |
add src0q, lenq |
add dstq, lenq |
neg lenq |
mova m0, [pf_dither_scale] |
.loop: |
cvtdq2ps m1, [src0q+lenq] |
cvtdq2ps m2, [src0q+lenq+mmsize] |
cvtdq2ps m3, [src1q+lenq] |
cvtdq2ps m4, [src1q+lenq+mmsize] |
addps m1, m1, m3 |
addps m2, m2, m4 |
mulps m1, m1, m0 |
mulps m2, m2, m0 |
mova [dstq+lenq], m1 |
mova [dstq+lenq+mmsize], m2 |
add lenq, 2*mmsize |
jl .loop |
REP_RET |
%endmacro |
INIT_XMM sse2 |
DITHER_INT_TO_FLOAT_TRIANGULAR |
INIT_YMM avx |
DITHER_INT_TO_FLOAT_TRIANGULAR |
/contrib/sdk/sources/ffmpeg/libavresample/x86/dither_init.c |
---|
0,0 → 1,60 |
/* |
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
* |
* This file is part of FFmpeg. |
* |
* FFmpeg is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2.1 of the License, or (at your option) any later version. |
* |
* FFmpeg is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with FFmpeg; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include "config.h" |
#include "libavutil/cpu.h" |
#include "libavutil/x86/cpu.h" |
#include "libavresample/dither.h" |
void ff_quantize_sse2(int16_t *dst, const float *src, float *dither, int len); |
void ff_dither_int_to_float_rectangular_sse2(float *dst, int *src, int len); |
void ff_dither_int_to_float_rectangular_avx(float *dst, int *src, int len); |
void ff_dither_int_to_float_triangular_sse2(float *dst, int *src0, int len); |
void ff_dither_int_to_float_triangular_avx(float *dst, int *src0, int len); |
av_cold void ff_dither_init_x86(DitherDSPContext *ddsp, |
enum AVResampleDitherMethod method) |
{ |
int cpu_flags = av_get_cpu_flags(); |
if (EXTERNAL_SSE2(cpu_flags)) { |
ddsp->quantize = ff_quantize_sse2; |
ddsp->ptr_align = 16; |
ddsp->samples_align = 8; |
} |
if (method == AV_RESAMPLE_DITHER_RECTANGULAR) { |
if (EXTERNAL_SSE2(cpu_flags)) { |
ddsp->dither_int_to_float = ff_dither_int_to_float_rectangular_sse2; |
} |
if (EXTERNAL_AVX(cpu_flags)) { |
ddsp->dither_int_to_float = ff_dither_int_to_float_rectangular_avx; |
} |
} else { |
if (EXTERNAL_SSE2(cpu_flags)) { |
ddsp->dither_int_to_float = ff_dither_int_to_float_triangular_sse2; |
} |
if (EXTERNAL_AVX(cpu_flags)) { |
ddsp->dither_int_to_float = ff_dither_int_to_float_triangular_avx; |
} |
} |
} |
/contrib/sdk/sources/ffmpeg/libavresample/x86/util.asm |
---|
0,0 → 1,41 |
;****************************************************************************** |
;* x86 utility macros for libavresample |
;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> |
;* |
;* This file is part of FFmpeg. |
;* |
;* FFmpeg is free software; you can redistribute it and/or |
;* modify it under the terms of the GNU Lesser General Public |
;* License as published by the Free Software Foundation; either |
;* version 2.1 of the License, or (at your option) any later version. |
;* |
;* FFmpeg is distributed in the hope that it will be useful, |
;* but WITHOUT ANY WARRANTY; without even the implied warranty of |
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
;* Lesser General Public License for more details. |
;* |
;* You should have received a copy of the GNU Lesser General Public |
;* License along with FFmpeg; if not, write to the Free Software |
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
;****************************************************************************** |
%macro S16_TO_S32_SX 2 ; src/low dst, high dst |
%if cpuflag(sse4) |
pmovsxwd m%2, m%1 |
psrldq m%1, 8 |
pmovsxwd m%1, m%1 |
SWAP %1, %2 |
%else |
mova m%2, m%1 |
punpckhwd m%2, m%2 |
punpcklwd m%1, m%1 |
psrad m%2, 16 |
psrad m%1, 16 |
%endif |
%endmacro |
%macro DEINT2_PS 3 ; src0/even dst, src1/odd dst, temp |
shufps m%3, m%1, m%2, q3131 |
shufps m%1, m%2, q2020 |
SWAP %2,%3 |
%endmacro |