/contrib/sdk/sources/ffmpeg/libswresample/Makefile |
---|
0,0 → 1,18 |
include $(SUBDIR)../config.mak |
NAME = swresample |
FFLIBS = avutil |
HEADERS = swresample.h \ |
version.h \ |
OBJS = audioconvert.o \ |
dither.o \ |
rematrix.o \ |
resample.o \ |
swresample.o \ |
OBJS-$(CONFIG_LIBSOXR) += soxr_resample.o |
OBJS-$(CONFIG_SHARED) += log2_tab.o |
TESTPROGS = swresample |
/contrib/sdk/sources/ffmpeg/libswresample/arm/Makefile |
---|
0,0 → 1,2 |
OBJS += arm/audio_convert_init.o |
NEON-OBJS += arm/audio_convert_neon.o |
/contrib/sdk/sources/ffmpeg/libswresample/arm/audio_convert_init.c |
---|
0,0 → 1,67 |
/* |
* This file is part of libswresample. |
* |
* libswresample 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. |
* |
* libswresample 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 libswresample; 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 "libswresample/swresample_internal.h" |
#include "libswresample/audioconvert.h" |
void swri_oldapi_conv_flt_to_s16_neon(int16_t *dst, const float *src, int len); |
void swri_oldapi_conv_fltp_to_s16_2ch_neon(int16_t *dst, float *const *src, int len, int channels); |
void swri_oldapi_conv_fltp_to_s16_nch_neon(int16_t *dst, float *const *src, int len, int channels); |
static void conv_flt_to_s16_neon(uint8_t **dst, const uint8_t **src, int len){ |
swri_oldapi_conv_flt_to_s16_neon((int16_t*)*dst, (const float*)*src, len); |
} |
static void conv_fltp_to_s16_2ch_neon(uint8_t **dst, const uint8_t **src, int len){ |
swri_oldapi_conv_fltp_to_s16_2ch_neon((int16_t*)*dst, (float *const*)src, len, 2); |
} |
static void conv_fltp_to_s16_nch_neon(uint8_t **dst, const uint8_t **src, int len){ |
int channels; |
for(channels=3; channels<SWR_CH_MAX && src[channels]; channels++) |
; |
swri_oldapi_conv_fltp_to_s16_nch_neon((int16_t*)*dst, (float *const*)src, len, channels); |
} |
av_cold void swri_audio_convert_init_arm(struct AudioConvert *ac, |
enum AVSampleFormat out_fmt, |
enum AVSampleFormat in_fmt, |
int channels) |
{ |
int cpu_flags = av_get_cpu_flags(); |
ac->simd_f= NULL; |
if (have_neon(cpu_flags)) { |
if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLTP) |
ac->simd_f = conv_flt_to_s16_neon; |
if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels == 2) |
ac->simd_f = conv_fltp_to_s16_2ch_neon; |
if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels > 2) |
ac->simd_f = conv_fltp_to_s16_nch_neon; |
if(ac->simd_f) |
ac->in_simd_align_mask = ac->out_simd_align_mask = 15; |
} |
} |
/contrib/sdk/sources/ffmpeg/libswresample/arm/audio_convert_neon.S |
---|
0,0 → 1,363 |
/* |
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com> |
* |
* This file is part of libswresample. |
* |
* libswresample 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. |
* |
* libswresample 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 libswresample; 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 swri_oldapi_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 swri_oldapi_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 swri_oldapi_conv_fltp_to_s16_nch_neon, export=1 |
cmp r3, #2 |
itt lt |
ldrlt r1, [r1] |
blt swri_oldapi_conv_flt_to_s16_neon |
beq swri_oldapi_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/libswresample/audioconvert.c |
---|
0,0 → 1,224 |
/* |
* audio conversion |
* Copyright (c) 2006 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 |
*/ |
/** |
* @file |
* audio conversion |
* @author Michael Niedermayer <michaelni@gmx.at> |
*/ |
#include "libavutil/avstring.h" |
#include "libavutil/avassert.h" |
#include "libavutil/libm.h" |
#include "libavutil/samplefmt.h" |
#include "audioconvert.h" |
#define CONV_FUNC_NAME(dst_fmt, src_fmt) conv_ ## src_fmt ## _to_ ## dst_fmt |
//FIXME rounding ? |
#define CONV_FUNC(ofmt, otype, ifmt, expr)\ |
static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end)\ |
{\ |
uint8_t *end2 = end - 3*os;\ |
while(po < end2){\ |
*(otype*)po = expr; pi += is; po += os;\ |
*(otype*)po = expr; pi += is; po += os;\ |
*(otype*)po = expr; pi += is; po += os;\ |
*(otype*)po = expr; pi += is; po += os;\ |
}\ |
while(po < end){\ |
*(otype*)po = expr; pi += is; po += os;\ |
}\ |
} |
//FIXME put things below under ifdefs so we do not waste space for cases no codec will need |
CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_U8 , *(const uint8_t*)pi) |
CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<8) |
CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<24) |
CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0f/ (1<<7))) |
CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7))) |
CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S16, (*(const int16_t*)pi>>8) + 0x80) |
CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi) |
CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi<<16) |
CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0f/ (1<<15))) |
CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15))) |
CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S32, (*(const int32_t*)pi>>24) + 0x80) |
CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi>>16) |
CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi) |
CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0f/ (1U<<31))) |
CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31))) |
CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8( lrintf(*(const float*)pi * (1<<7)) + 0x80)) |
CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16( lrintf(*(const float*)pi * (1<<15)))) |
CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float*)pi * (1U<<31)))) |
CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_FLT, *(const float*)pi) |
CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_FLT, *(const float*)pi) |
CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8( lrint(*(const double*)pi * (1<<7)) + 0x80)) |
CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16( lrint(*(const double*)pi * (1<<15)))) |
CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double*)pi * (1U<<31)))) |
CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_DBL, *(const double*)pi) |
CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_DBL, *(const double*)pi) |
#define FMT_PAIR_FUNC(out, in) [out + AV_SAMPLE_FMT_NB*in] = CONV_FUNC_NAME(out, in) |
static conv_func_type * const fmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB*AV_SAMPLE_FMT_NB] = { |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_U8 ), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8 ), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8 ), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8 ), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8 ), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_S16), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_S32), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_FLT), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_DBL), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL), |
FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL), |
}; |
static void cpy1(uint8_t **dst, const uint8_t **src, int len){ |
memcpy(*dst, *src, len); |
} |
static void cpy2(uint8_t **dst, const uint8_t **src, int len){ |
memcpy(*dst, *src, 2*len); |
} |
static void cpy4(uint8_t **dst, const uint8_t **src, int len){ |
memcpy(*dst, *src, 4*len); |
} |
static void cpy8(uint8_t **dst, const uint8_t **src, int len){ |
memcpy(*dst, *src, 8*len); |
} |
AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, |
enum AVSampleFormat in_fmt, |
int channels, const int *ch_map, |
int flags) |
{ |
AudioConvert *ctx; |
conv_func_type *f = fmt_pair_to_conv_functions[av_get_packed_sample_fmt(out_fmt) + AV_SAMPLE_FMT_NB*av_get_packed_sample_fmt(in_fmt)]; |
if (!f) |
return NULL; |
ctx = av_mallocz(sizeof(*ctx)); |
if (!ctx) |
return NULL; |
if(channels == 1){ |
in_fmt = av_get_planar_sample_fmt( in_fmt); |
out_fmt = av_get_planar_sample_fmt(out_fmt); |
} |
ctx->channels = channels; |
ctx->conv_f = f; |
ctx->ch_map = ch_map; |
if (in_fmt == AV_SAMPLE_FMT_U8 || in_fmt == AV_SAMPLE_FMT_U8P) |
memset(ctx->silence, 0x80, sizeof(ctx->silence)); |
if(out_fmt == in_fmt && !ch_map) { |
switch(av_get_bytes_per_sample(in_fmt)){ |
case 1:ctx->simd_f = cpy1; break; |
case 2:ctx->simd_f = cpy2; break; |
case 4:ctx->simd_f = cpy4; break; |
case 8:ctx->simd_f = cpy8; break; |
} |
} |
if(HAVE_YASM && HAVE_MMX) swri_audio_convert_init_x86(ctx, out_fmt, in_fmt, channels); |
if(ARCH_ARM) swri_audio_convert_init_arm(ctx, out_fmt, in_fmt, channels); |
return ctx; |
} |
void swri_audio_convert_free(AudioConvert **ctx) |
{ |
av_freep(ctx); |
} |
int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len) |
{ |
int ch; |
int off=0; |
const int os= (out->planar ? 1 :out->ch_count) *out->bps; |
unsigned misaligned = 0; |
av_assert0(ctx->channels == out->ch_count); |
if (ctx->in_simd_align_mask) { |
int planes = in->planar ? in->ch_count : 1; |
unsigned m = 0; |
for (ch = 0; ch < planes; ch++) |
m |= (intptr_t)in->ch[ch]; |
misaligned |= m & ctx->in_simd_align_mask; |
} |
if (ctx->out_simd_align_mask) { |
int planes = out->planar ? out->ch_count : 1; |
unsigned m = 0; |
for (ch = 0; ch < planes; ch++) |
m |= (intptr_t)out->ch[ch]; |
misaligned |= m & ctx->out_simd_align_mask; |
} |
//FIXME optimize common cases |
if(ctx->simd_f && !ctx->ch_map && !misaligned){ |
off = len&~15; |
av_assert1(off>=0); |
av_assert1(off<=len); |
av_assert2(ctx->channels == SWR_CH_MAX || !in->ch[ctx->channels]); |
if(off>0){ |
if(out->planar == in->planar){ |
int planes = out->planar ? out->ch_count : 1; |
for(ch=0; ch<planes; ch++){ |
ctx->simd_f(out->ch+ch, (const uint8_t **)in->ch+ch, off * (out->planar ? 1 :out->ch_count)); |
} |
}else{ |
ctx->simd_f(out->ch, (const uint8_t **)in->ch, off); |
} |
} |
if(off == len) |
return 0; |
} |
for(ch=0; ch<ctx->channels; ch++){ |
const int ich= ctx->ch_map ? ctx->ch_map[ch] : ch; |
const int is= ich < 0 ? 0 : (in->planar ? 1 : in->ch_count) * in->bps; |
const uint8_t *pi= ich < 0 ? ctx->silence : in->ch[ich]; |
uint8_t *po= out->ch[ch]; |
uint8_t *end= po + os*len; |
if(!po) |
continue; |
ctx->conv_f(po+off*os, pi+off*is, is, os, end); |
} |
return 0; |
} |
/contrib/sdk/sources/ffmpeg/libswresample/audioconvert.h |
---|
0,0 → 1,78 |
/* |
* audio conversion |
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> |
* Copyright (c) 2008 Peter Ross |
* |
* 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 SWR_AUDIOCONVERT_H |
#define SWR_AUDIOCONVERT_H |
/** |
* @file |
* Audio format conversion routines |
*/ |
#include "swresample_internal.h" |
#include "libavutil/cpu.h" |
typedef void (conv_func_type)(uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end); |
typedef void (simd_func_type)(uint8_t **dst, const uint8_t **src, int len); |
typedef struct AudioConvert { |
int channels; |
int in_simd_align_mask; |
int out_simd_align_mask; |
conv_func_type *conv_f; |
simd_func_type *simd_f; |
const int *ch_map; |
uint8_t silence[8]; ///< silence input sample |
}AudioConvert; |
/** |
* Create an audio sample format converter context |
* @param out_fmt Output sample format |
* @param in_fmt Input sample format |
* @param channels Number of channels |
* @param flags See AV_CPU_FLAG_xx |
* @param ch_map list of the channels id to pick from the source stream, NULL |
* if all channels must be selected |
* @return NULL on error |
*/ |
AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, |
enum AVSampleFormat in_fmt, |
int channels, const int *ch_map, |
int flags); |
/** |
* Free audio sample format converter context. |
* and set the pointer to NULL |
*/ |
void swri_audio_convert_free(AudioConvert **ctx); |
/** |
* Convert between audio sample formats |
* @param[in] out array of output buffers for each channel. set to NULL to ignore processing of the given channel. |
* @param[in] in array of input buffers for each channel |
* @param len length of audio frame size (measured in samples) |
*/ |
int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len); |
#endif /* AUDIOCONVERT_H */ |
/contrib/sdk/sources/ffmpeg/libswresample/dither.c |
---|
0,0 → 1,148 |
/* |
* Copyright (C) 2012-2013 Michael Niedermayer (michaelni@gmx.at) |
* |
* This file is part of libswresample |
* |
* libswresample 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. |
* |
* libswresample 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 libswresample; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include "libavutil/avassert.h" |
#include "swresample_internal.h" |
#include "noise_shaping_data.c" |
void swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSampleFormat noise_fmt) { |
double scale = s->dither.noise_scale; |
#define TMP_EXTRA 2 |
double *tmp = av_malloc((len + TMP_EXTRA) * sizeof(double)); |
int i; |
for(i=0; i<len + TMP_EXTRA; i++){ |
double v; |
seed = seed* 1664525 + 1013904223; |
switch(s->dither.method){ |
case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break; |
default: |
av_assert0(s->dither.method < SWR_DITHER_NB); |
v = ((double)seed) / UINT_MAX; |
seed = seed*1664525 + 1013904223; |
v-= ((double)seed) / UINT_MAX; |
break; |
} |
tmp[i] = v; |
} |
for(i=0; i<len; i++){ |
double v; |
switch(s->dither.method){ |
default: |
av_assert0(s->dither.method < SWR_DITHER_NB); |
v = tmp[i]; |
break; |
case SWR_DITHER_TRIANGULAR_HIGHPASS : |
v = (- tmp[i] + 2*tmp[i+1] - tmp[i+2]) / sqrt(6); |
break; |
} |
v*= scale; |
switch(noise_fmt){ |
case AV_SAMPLE_FMT_S16P: ((int16_t*)dst)[i] = v; break; |
case AV_SAMPLE_FMT_S32P: ((int32_t*)dst)[i] = v; break; |
case AV_SAMPLE_FMT_FLTP: ((float *)dst)[i] = v; break; |
case AV_SAMPLE_FMT_DBLP: ((double *)dst)[i] = v; break; |
default: av_assert0(0); |
} |
} |
av_free(tmp); |
} |
int swri_dither_init(SwrContext *s, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt) |
{ |
int i; |
double scale = 0; |
if (s->dither.method > SWR_DITHER_TRIANGULAR_HIGHPASS && s->dither.method <= SWR_DITHER_NS) |
return AVERROR(EINVAL); |
out_fmt = av_get_packed_sample_fmt(out_fmt); |
in_fmt = av_get_packed_sample_fmt( in_fmt); |
if(in_fmt == AV_SAMPLE_FMT_FLT || in_fmt == AV_SAMPLE_FMT_DBL){ |
if(out_fmt == AV_SAMPLE_FMT_S32) scale = 1.0/(1L<<31); |
if(out_fmt == AV_SAMPLE_FMT_S16) scale = 1.0/(1L<<15); |
if(out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1.0/(1L<< 7); |
} |
if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S32 && (s->dither.output_sample_bits&31)) scale = 1; |
if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S16) scale = 1L<<16; |
if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<24; |
if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<8; |
scale *= s->dither.scale; |
if (out_fmt == AV_SAMPLE_FMT_S32 && s->dither.output_sample_bits) |
scale *= 1<<(32-s->dither.output_sample_bits); |
s->dither.ns_pos = 0; |
s->dither.noise_scale= scale; |
s->dither.ns_scale = scale; |
s->dither.ns_scale_1 = scale ? 1/scale : 0; |
memset(s->dither.ns_errors, 0, sizeof(s->dither.ns_errors)); |
for (i=0; filters[i].coefs; i++) { |
const filter_t *f = &filters[i]; |
if (fabs(s->out_sample_rate - f->rate) / f->rate <= .05 && f->name == s->dither.method) { |
int j; |
s->dither.ns_taps = f->len; |
for (j=0; j<f->len; j++) |
s->dither.ns_coeffs[j] = f->coefs[j]; |
s->dither.ns_scale_1 *= 1 - exp(f->gain_cB * M_LN10 * 0.005) * 2 / (1<<(8*av_get_bytes_per_sample(out_fmt))); |
break; |
} |
} |
if (!filters[i].coefs && s->dither.method > SWR_DITHER_NS) { |
av_log(s, AV_LOG_WARNING, "Requested noise shaping dither not available at this sampling rate, using triangular hp dither\n"); |
s->dither.method = SWR_DITHER_TRIANGULAR_HIGHPASS; |
} |
av_assert0(!s->preout.count); |
s->dither.noise = s->preout; |
s->dither.temp = s->preout; |
if (s->dither.method > SWR_DITHER_NS) { |
s->dither.noise.bps = 4; |
s->dither.noise.fmt = AV_SAMPLE_FMT_FLTP; |
s->dither.noise_scale = 1; |
} |
return 0; |
} |
#define TEMPLATE_DITHER_S16 |
#include "dither_template.c" |
#undef TEMPLATE_DITHER_S16 |
#define TEMPLATE_DITHER_S32 |
#include "dither_template.c" |
#undef TEMPLATE_DITHER_S32 |
#define TEMPLATE_DITHER_FLT |
#include "dither_template.c" |
#undef TEMPLATE_DITHER_FLT |
#define TEMPLATE_DITHER_DBL |
#include "dither_template.c" |
#undef TEMPLATE_DITHER_DBL |
/contrib/sdk/sources/ffmpeg/libswresample/dither_template.c |
---|
0,0 → 1,67 |
#if defined(TEMPLATE_DITHER_DBL) |
# define RENAME(N) N ## _double |
# define DELEM double |
# define CLIP(v) |
#elif defined(TEMPLATE_DITHER_FLT) |
# define RENAME(N) N ## _float |
# define DELEM float |
# define CLIP(v) |
#elif defined(TEMPLATE_DITHER_S32) |
# define RENAME(N) N ## _int32 |
# define DELEM int32_t |
# define CLIP(v) v = FFMAX(FFMIN(v, INT32_MAX), INT32_MIN) |
#elif defined(TEMPLATE_DITHER_S16) |
# define RENAME(N) N ## _int16 |
# define DELEM int16_t |
# define CLIP(v) v = FFMAX(FFMIN(v, INT16_MAX), INT16_MIN) |
#else |
ERROR |
#endif |
void RENAME(swri_noise_shaping)(SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count){ |
int pos = s->dither.ns_pos; |
int i, j, ch; |
int taps = s->dither.ns_taps; |
float S = s->dither.ns_scale; |
float S_1 = s->dither.ns_scale_1; |
av_assert2((taps&3) != 2); |
av_assert2((taps&3) != 3 || s->dither.ns_coeffs[taps] == 0); |
for (ch=0; ch<srcs->ch_count; ch++) { |
const float *noise = ((const float *)noises->ch[ch]) + s->dither.noise_pos; |
const DELEM *src = (const DELEM*)srcs->ch[ch]; |
DELEM *dst = (DELEM*)dsts->ch[ch]; |
float *ns_errors = s->dither.ns_errors[ch]; |
const float *ns_coeffs = s->dither.ns_coeffs; |
pos = s->dither.ns_pos; |
for (i=0; i<count; i++) { |
double d1, d = src[i]*S_1; |
for(j=0; j<taps-2; j+=4) { |
d -= ns_coeffs[j ] * ns_errors[pos + j ] |
+ns_coeffs[j + 1] * ns_errors[pos + j + 1] |
+ns_coeffs[j + 2] * ns_errors[pos + j + 2] |
+ns_coeffs[j + 3] * ns_errors[pos + j + 3]; |
} |
if(j < taps) |
d -= ns_coeffs[j] * ns_errors[pos + j]; |
pos = pos ? pos - 1 : taps - 1; |
d1 = rint(d + noise[i]); |
ns_errors[pos + taps] = ns_errors[pos] = d1 - d; |
d1 *= S; |
CLIP(d1); |
dst[i] = d1; |
} |
} |
s->dither.ns_pos = pos; |
} |
#undef RENAME |
#undef DELEM |
#undef CLIP |
/contrib/sdk/sources/ffmpeg/libswresample/libswresample.pc |
---|
0,0 → 1,14 |
prefix=/usr/local |
exec_prefix=${prefix} |
libdir=${prefix}/lib |
includedir=${prefix}/include |
Name: libswresample |
Description: FFmpeg audio resampling library |
Version: 0.17.104 |
Requires: |
Requires.private: libavutil = 52.48.101 |
Conflicts: |
Libs: -L${libdir} -lswresample |
Libs.private: -lm |
Cflags: -I${includedir} |
/contrib/sdk/sources/ffmpeg/libswresample/libswresample.v |
---|
0,0 → 1,4 |
LIBSWRESAMPLE_$MAJOR { |
global: swr_*; ff_*; swresample_*; |
local: *; |
}; |
/contrib/sdk/sources/ffmpeg/libswresample/libswresample.ver |
---|
0,0 → 1,4 |
LIBSWRESAMPLE_0 { |
global: swr_*; ff_*; swresample_*; |
local: *; |
}; |
/contrib/sdk/sources/ffmpeg/libswresample/log2_tab.c |
---|
0,0 → 1,0 |
#include "libavutil/log2_tab.c" |
/contrib/sdk/sources/ffmpeg/libswresample/noise_shaping_data.c |
---|
0,0 → 1,224 |
/* Effect: dither/noise-shape Copyright (c) 2008-9 robs@users.sourceforge.net |
* |
* This library 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. |
* |
* This library 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 this library; if not, write to the Free Software Foundation, |
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
typedef struct { |
int rate; |
enum {fir, iir} type; |
size_t len; |
int gain_cB; /* Chosen so clips are few if any, but not guaranteed none. */ |
double const * coefs; |
enum SwrDitherType name; |
} filter_t; |
static double const lip44[] = {2.033, -2.165, 1.959, -1.590, .6149}; |
static double const fwe44[] = { |
2.412, -3.370, 3.937, -4.174, 3.353, -2.205, 1.281, -.569, .0847}; |
static double const mew44[] = { |
1.662, -1.263, .4827, -.2913, .1268, -.1124, .03252, -.01265, -.03524}; |
static double const iew44[] = { |
2.847, -4.685, 6.214, -7.184, 6.639, -5.032, 3.263, -1.632, .4191}; |
static double const ges44[] = { |
2.2061, -.4706, -.2534, -.6214, 1.0587, .0676, -.6054, -.2738}; |
static double const ges48[] = { |
2.2374, -.7339, -.1251, -.6033, .903, .0116, -.5853, -.2571}; |
static double const shi48[] = { |
2.8720729351043701172, -5.0413231849670410156, 6.2442994117736816406, |
-5.8483986854553222656, 3.7067542076110839844, -1.0495119094848632812, |
-1.1830236911773681641, 2.1126792430877685547, -1.9094531536102294922, |
0.99913084506988525391, -0.17090806365013122559, -0.32615602016448974609, |
0.39127644896507263184, -0.26876461505889892578, 0.097676105797290802002, |
-0.023473845794796943665, |
}; |
static double const shi44[] = { |
2.6773197650909423828, -4.8308925628662109375, 6.570110321044921875, |
-7.4572014808654785156, 6.7263274192810058594, -4.8481650352478027344, |
2.0412089824676513672, 0.7006359100341796875, -2.9537565708160400391, |
4.0800385475158691406, -4.1845216751098632812, 3.3311812877655029297, |
-2.1179926395416259766, 0.879302978515625, -0.031759146600961685181, |
-0.42382788658142089844, 0.47882103919982910156, -0.35490813851356506348, |
0.17496839165687561035, -0.060908168554306030273, |
}; |
static double const shi38[] = { |
1.6335992813110351562, -2.2615492343902587891, 2.4077029228210449219, |
-2.6341717243194580078, 2.1440362930297851562, -1.8153258562088012695, |
1.0816224813461303711, -0.70302653312683105469, 0.15991993248462677002, |
0.041549518704414367676, -0.29416576027870178223, 0.2518316805362701416, |
-0.27766478061676025391, 0.15785403549671173096, -0.10165894031524658203, |
0.016833892092108726501, |
}; |
static double const shi32[] = |
{ /* dmaker 32000: bestmax=4.99659 (inverted) */ |
0.82118552923202515, |
-1.0063692331314087, |
0.62341964244842529, |
-1.0447187423706055, |
0.64532512426376343, |
-0.87615132331848145, |
0.52219754457473755, |
-0.67434263229370117, |
0.44954317808151245, |
-0.52557498216629028, |
0.34567299485206604, |
-0.39618203043937683, |
0.26791760325431824, |
-0.28936097025871277, |
0.1883765310049057, |
-0.19097308814525604, |
0.10431359708309174, |
-0.10633844882249832, |
0.046832218766212463, |
-0.039653312414884567, |
}; |
static double const shi22[] = |
{ /* dmaker 22050: bestmax=5.77762 (inverted) */ |
0.056581053882837296, |
-0.56956905126571655, |
-0.40727734565734863, |
-0.33870288729667664, |
-0.29810553789138794, |
-0.19039161503314972, |
-0.16510021686553955, |
-0.13468159735202789, |
-0.096633769571781158, |
-0.081049129366874695, |
-0.064953058958053589, |
-0.054459091275930405, |
-0.043378707021474838, |
-0.03660014271736145, |
-0.026256965473294258, |
-0.018786206841468811, |
-0.013387725688517094, |
-0.0090983230620622635, |
-0.0026585909072309732, |
-0.00042083300650119781, |
}; |
static double const shi16[] = |
{ /* dmaker 16000: bestmax=5.97128 (inverted) */ |
-0.37251132726669312, |
-0.81423574686050415, |
-0.55010956525802612, |
-0.47405767440795898, |
-0.32624706625938416, |
-0.3161766529083252, |
-0.2286367267370224, |
-0.22916607558727264, |
-0.19565616548061371, |
-0.18160104751586914, |
-0.15423151850700378, |
-0.14104481041431427, |
-0.11844276636838913, |
-0.097583092749118805, |
-0.076493598520755768, |
-0.068106919527053833, |
-0.041881654411554337, |
-0.036922425031661987, |
-0.019364040344953537, |
-0.014994367957115173, |
}; |
static double const shi11[] = |
{ /* dmaker 11025: bestmax=5.9406 (inverted) */ |
-0.9264228343963623, |
-0.98695987462997437, |
-0.631156325340271, |
-0.51966935396194458, |
-0.39738872647285461, |
-0.35679301619529724, |
-0.29720726609230042, |
-0.26310476660728455, |
-0.21719355881214142, |
-0.18561814725399017, |
-0.15404847264289856, |
-0.12687471508979797, |
-0.10339745879173279, |
-0.083688631653785706, |
-0.05875682458281517, |
-0.046893671154975891, |
-0.027950936928391457, |
-0.020740609616041183, |
-0.009366452693939209, |
-0.0060260160826146603, |
}; |
static double const shi08[] = |
{ /* dmaker 8000: bestmax=5.56234 (inverted) */ |
-1.202863335609436, |
-0.94103097915649414, |
-0.67878556251525879, |
-0.57650017738342285, |
-0.50004476308822632, |
-0.44349345564842224, |
-0.37833768129348755, |
-0.34028723835945129, |
-0.29413089156150818, |
-0.24994957447052002, |
-0.21715600788593292, |
-0.18792112171649933, |
-0.15268312394618988, |
-0.12135542929172516, |
-0.099610626697540283, |
-0.075273610651493073, |
-0.048787496984004974, |
-0.042586319148540497, |
-0.028991291299462318, |
-0.011869125068187714, |
}; |
static double const shl48[] = { |
2.3925774097442626953, -3.4350297451019287109, 3.1853709220886230469, |
-1.8117271661758422852, -0.20124770700931549072, 1.4759907722473144531, |
-1.7210904359817504883, 0.97746700048446655273, -0.13790138065814971924, |
-0.38185903429985046387, 0.27421241998672485352, 0.066584214568138122559, |
-0.35223302245140075684, 0.37672343850135803223, -0.23964276909828186035, |
0.068674825131893157959, |
}; |
static double const shl44[] = { |
2.0833916664123535156, -3.0418450832366943359, 3.2047898769378662109, |
-2.7571926116943359375, 1.4978630542755126953, -0.3427594602108001709, |
-0.71733748912811279297, 1.0737057924270629883, -1.0225815773010253906, |
0.56649994850158691406, -0.20968692004680633545, -0.065378531813621520996, |
0.10322438180446624756, -0.067442022264003753662, -0.00495197344571352005, |
0, |
}; |
static double const shh44[] = { |
3.0259189605712890625, -6.0268716812133789062, 9.195003509521484375, |
-11.824929237365722656, 12.767142295837402344, -11.917946815490722656, |
9.1739168167114257812, -5.3712320327758789062, 1.1393624544143676758, |
2.4484779834747314453, -4.9719839096069335938, 6.0392003059387207031, |
-5.9359521865844726562, 4.903278350830078125, -3.5527443885803222656, |
2.1909697055816650391, -1.1672389507293701172, 0.4903914332389831543, |
-0.16519790887832641602, 0.023217858746647834778, |
}; |
static const filter_t filters[] = { |
{44100, fir, 5, 210, lip44, SWR_DITHER_NS_LIPSHITZ}, |
{46000, fir, 9, 276, fwe44, SWR_DITHER_NS_F_WEIGHTED}, |
{46000, fir, 9, 160, mew44, SWR_DITHER_NS_MODIFIED_E_WEIGHTED}, |
{46000, fir, 9, 321, iew44, SWR_DITHER_NS_IMPROVED_E_WEIGHTED}, |
// {48000, iir, 4, 220, ges48, SWR_DITHER_NS_GESEMANN}, |
// {44100, iir, 4, 230, ges44, SWR_DITHER_NS_GESEMANN}, |
{48000, fir, 16, 301, shi48, SWR_DITHER_NS_SHIBATA}, |
{44100, fir, 20, 333, shi44, SWR_DITHER_NS_SHIBATA}, |
{37800, fir, 16, 240, shi38, SWR_DITHER_NS_SHIBATA}, |
{32000, fir, 20, 240/*TBD*/, shi32, SWR_DITHER_NS_SHIBATA}, |
{22050, fir, 20, 240/*TBD*/, shi22, SWR_DITHER_NS_SHIBATA}, |
{16000, fir, 20, 240/*TBD*/, shi16, SWR_DITHER_NS_SHIBATA}, |
{11025, fir, 20, 240/*TBD*/, shi11, SWR_DITHER_NS_SHIBATA}, |
{ 8000, fir, 20, 240/*TBD*/, shi08, SWR_DITHER_NS_SHIBATA}, |
{48000, fir, 16, 250, shl48, SWR_DITHER_NS_LOW_SHIBATA}, |
{44100, fir, 15, 250, shl44, SWR_DITHER_NS_LOW_SHIBATA}, |
{44100, fir, 20, 383, shh44, SWR_DITHER_NS_HIGH_SHIBATA}, |
{ 0, fir, 0, 0, NULL, SWR_DITHER_NONE}, |
}; |
/contrib/sdk/sources/ffmpeg/libswresample/rematrix.c |
---|
0,0 → 1,500 |
/* |
* Copyright (C) 2011-2012 Michael Niedermayer (michaelni@gmx.at) |
* |
* This file is part of libswresample |
* |
* libswresample 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. |
* |
* libswresample 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 libswresample; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include "swresample_internal.h" |
#include "libavutil/avassert.h" |
#include "libavutil/channel_layout.h" |
#define TEMPLATE_REMATRIX_FLT |
#include "rematrix_template.c" |
#undef TEMPLATE_REMATRIX_FLT |
#define TEMPLATE_REMATRIX_DBL |
#include "rematrix_template.c" |
#undef TEMPLATE_REMATRIX_DBL |
#define TEMPLATE_REMATRIX_S16 |
#include "rematrix_template.c" |
#undef TEMPLATE_REMATRIX_S16 |
#define TEMPLATE_REMATRIX_S32 |
#include "rematrix_template.c" |
#undef TEMPLATE_REMATRIX_S32 |
#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 |
int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride) |
{ |
int nb_in, nb_out, in, out; |
if (!s || s->in_convert) // s needs to be allocated but not initialized |
return AVERROR(EINVAL); |
memset(s->matrix, 0, sizeof(s->matrix)); |
nb_in = av_get_channel_layout_nb_channels(s->in_ch_layout); |
nb_out = av_get_channel_layout_nb_channels(s->out_ch_layout); |
for (out = 0; out < nb_out; out++) { |
for (in = 0; in < nb_in; in++) |
s->matrix[out][in] = matrix[in]; |
matrix += stride; |
} |
s->rematrix_custom = 1; |
return 0; |
} |
static int even(int64_t layout){ |
if(!layout) return 1; |
if(layout&(layout-1)) return 1; |
return 0; |
} |
static int clean_layout(SwrContext *s, int64_t layout){ |
if(layout && layout != AV_CH_FRONT_CENTER && !(layout&(layout-1))) { |
char buf[128]; |
av_get_channel_layout_string(buf, sizeof(buf), -1, layout); |
av_log(s, AV_LOG_VERBOSE, "Treating %s as mono\n", buf); |
return AV_CH_FRONT_CENTER; |
} |
return layout; |
} |
static int sane_layout(int64_t layout){ |
if(!(layout & AV_CH_LAYOUT_SURROUND)) // at least 1 front speaker |
return 0; |
if(!even(layout & (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT))) // no asymetric front |
return 0; |
if(!even(layout & (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT))) // no asymetric side |
return 0; |
if(!even(layout & (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT))) |
return 0; |
if(!even(layout & (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER))) |
return 0; |
if(av_get_channel_layout_nb_channels(layout) >= SWR_CH_MAX) |
return 0; |
return 1; |
} |
av_cold static int auto_matrix(SwrContext *s) |
{ |
int i, j, out_i; |
double matrix[64][64]={{0}}; |
int64_t unaccounted, in_ch_layout, out_ch_layout; |
double maxcoef=0; |
char buf[128]; |
const int matrix_encoding = s->matrix_encoding; |
float maxval; |
in_ch_layout = clean_layout(s, s->in_ch_layout); |
out_ch_layout = clean_layout(s, s->out_ch_layout); |
if( out_ch_layout == AV_CH_LAYOUT_STEREO_DOWNMIX |
&& (in_ch_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == 0 |
) |
out_ch_layout = AV_CH_LAYOUT_STEREO; |
if(!sane_layout(in_ch_layout)){ |
av_get_channel_layout_string(buf, sizeof(buf), -1, s->in_ch_layout); |
av_log(s, AV_LOG_ERROR, "Input channel layout '%s' is not supported\n", buf); |
return AVERROR(EINVAL); |
} |
if(!sane_layout(out_ch_layout)){ |
av_get_channel_layout_string(buf, sizeof(buf), -1, s->out_ch_layout); |
av_log(s, AV_LOG_ERROR, "Output channel layout '%s' is not supported\n", buf); |
return AVERROR(EINVAL); |
} |
memset(s->matrix, 0, sizeof(s->matrix)); |
for(i=0; i<64; i++){ |
if(in_ch_layout & out_ch_layout & (1ULL<<i)) |
matrix[i][i]= 1.0; |
} |
unaccounted= in_ch_layout & ~out_ch_layout; |
//FIXME implement dolby surround |
//FIXME implement full ac3 |
if(unaccounted & AV_CH_FRONT_CENTER){ |
if((out_ch_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO){ |
if(in_ch_layout & AV_CH_LAYOUT_STEREO) { |
matrix[ FRONT_LEFT][FRONT_CENTER]+= s->clev; |
matrix[FRONT_RIGHT][FRONT_CENTER]+= s->clev; |
} else { |
matrix[ FRONT_LEFT][FRONT_CENTER]+= M_SQRT1_2; |
matrix[FRONT_RIGHT][FRONT_CENTER]+= M_SQRT1_2; |
} |
}else |
av_assert0(0); |
} |
if(unaccounted & AV_CH_LAYOUT_STEREO){ |
if(out_ch_layout & AV_CH_FRONT_CENTER){ |
matrix[FRONT_CENTER][ FRONT_LEFT]+= M_SQRT1_2; |
matrix[FRONT_CENTER][FRONT_RIGHT]+= M_SQRT1_2; |
if(in_ch_layout & AV_CH_FRONT_CENTER) |
matrix[FRONT_CENTER][ FRONT_CENTER] = s->clev*sqrt(2); |
}else |
av_assert0(0); |
} |
if(unaccounted & AV_CH_BACK_CENTER){ |
if(out_ch_layout & AV_CH_BACK_LEFT){ |
matrix[ BACK_LEFT][BACK_CENTER]+= M_SQRT1_2; |
matrix[BACK_RIGHT][BACK_CENTER]+= M_SQRT1_2; |
}else if(out_ch_layout & AV_CH_SIDE_LEFT){ |
matrix[ SIDE_LEFT][BACK_CENTER]+= M_SQRT1_2; |
matrix[SIDE_RIGHT][BACK_CENTER]+= M_SQRT1_2; |
}else if(out_ch_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] -= s->slev * M_SQRT1_2; |
matrix[FRONT_RIGHT][BACK_CENTER] += s->slev * M_SQRT1_2; |
} else { |
matrix[FRONT_LEFT ][BACK_CENTER] -= s->slev; |
matrix[FRONT_RIGHT][BACK_CENTER] += s->slev; |
} |
} else { |
matrix[ FRONT_LEFT][BACK_CENTER]+= s->slev*M_SQRT1_2; |
matrix[FRONT_RIGHT][BACK_CENTER]+= s->slev*M_SQRT1_2; |
} |
}else if(out_ch_layout & AV_CH_FRONT_CENTER){ |
matrix[ FRONT_CENTER][BACK_CENTER]+= s->slev*M_SQRT1_2; |
}else |
av_assert0(0); |
} |
if(unaccounted & AV_CH_BACK_LEFT){ |
if(out_ch_layout & AV_CH_BACK_CENTER){ |
matrix[BACK_CENTER][ BACK_LEFT]+= M_SQRT1_2; |
matrix[BACK_CENTER][BACK_RIGHT]+= M_SQRT1_2; |
}else if(out_ch_layout & AV_CH_SIDE_LEFT){ |
if(in_ch_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_ch_layout & AV_CH_FRONT_LEFT){ |
if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { |
matrix[FRONT_LEFT ][BACK_LEFT ] -= s->slev * M_SQRT1_2; |
matrix[FRONT_LEFT ][BACK_RIGHT] -= s->slev * M_SQRT1_2; |
matrix[FRONT_RIGHT][BACK_LEFT ] += s->slev * M_SQRT1_2; |
matrix[FRONT_RIGHT][BACK_RIGHT] += s->slev * M_SQRT1_2; |
} else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { |
matrix[FRONT_LEFT ][BACK_LEFT ] -= s->slev * SQRT3_2; |
matrix[FRONT_LEFT ][BACK_RIGHT] -= s->slev * M_SQRT1_2; |
matrix[FRONT_RIGHT][BACK_LEFT ] += s->slev * M_SQRT1_2; |
matrix[FRONT_RIGHT][BACK_RIGHT] += s->slev * SQRT3_2; |
} else { |
matrix[ FRONT_LEFT][ BACK_LEFT] += s->slev; |
matrix[FRONT_RIGHT][BACK_RIGHT] += s->slev; |
} |
}else if(out_ch_layout & AV_CH_FRONT_CENTER){ |
matrix[ FRONT_CENTER][BACK_LEFT ]+= s->slev*M_SQRT1_2; |
matrix[ FRONT_CENTER][BACK_RIGHT]+= s->slev*M_SQRT1_2; |
}else |
av_assert0(0); |
} |
if(unaccounted & AV_CH_SIDE_LEFT){ |
if(out_ch_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_ch_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_ch_layout & AV_CH_BACK_CENTER){ |
matrix[BACK_CENTER][ SIDE_LEFT]+= M_SQRT1_2; |
matrix[BACK_CENTER][SIDE_RIGHT]+= M_SQRT1_2; |
}else if(out_ch_layout & AV_CH_FRONT_LEFT){ |
if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { |
matrix[FRONT_LEFT ][SIDE_LEFT ] -= s->slev * M_SQRT1_2; |
matrix[FRONT_LEFT ][SIDE_RIGHT] -= s->slev * M_SQRT1_2; |
matrix[FRONT_RIGHT][SIDE_LEFT ] += s->slev * M_SQRT1_2; |
matrix[FRONT_RIGHT][SIDE_RIGHT] += s->slev * M_SQRT1_2; |
} else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { |
matrix[FRONT_LEFT ][SIDE_LEFT ] -= s->slev * SQRT3_2; |
matrix[FRONT_LEFT ][SIDE_RIGHT] -= s->slev * M_SQRT1_2; |
matrix[FRONT_RIGHT][SIDE_LEFT ] += s->slev * M_SQRT1_2; |
matrix[FRONT_RIGHT][SIDE_RIGHT] += s->slev * SQRT3_2; |
} else { |
matrix[ FRONT_LEFT][ SIDE_LEFT] += s->slev; |
matrix[FRONT_RIGHT][SIDE_RIGHT] += s->slev; |
} |
}else if(out_ch_layout & AV_CH_FRONT_CENTER){ |
matrix[ FRONT_CENTER][SIDE_LEFT ]+= s->slev*M_SQRT1_2; |
matrix[ FRONT_CENTER][SIDE_RIGHT]+= s->slev*M_SQRT1_2; |
}else |
av_assert0(0); |
} |
if(unaccounted & AV_CH_FRONT_LEFT_OF_CENTER){ |
if(out_ch_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_ch_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 |
av_assert0(0); |
} |
/* mix LFE into front left/right or center */ |
if (unaccounted & AV_CH_LOW_FREQUENCY) { |
if (out_ch_layout & AV_CH_FRONT_CENTER) { |
matrix[FRONT_CENTER][LOW_FREQUENCY] += s->lfe_mix_level; |
} else if (out_ch_layout & AV_CH_FRONT_LEFT) { |
matrix[FRONT_LEFT ][LOW_FREQUENCY] += s->lfe_mix_level * M_SQRT1_2; |
matrix[FRONT_RIGHT][LOW_FREQUENCY] += s->lfe_mix_level * M_SQRT1_2; |
} else |
av_assert0(0); |
} |
for(out_i=i=0; i<64; i++){ |
double sum=0; |
int in_i=0; |
for(j=0; j<64; j++){ |
s->matrix[out_i][in_i]= matrix[i][j]; |
if(matrix[i][j]){ |
sum += fabs(matrix[i][j]); |
} |
if(in_ch_layout & (1ULL<<j)) |
in_i++; |
} |
maxcoef= FFMAX(maxcoef, sum); |
if(out_ch_layout & (1ULL<<i)) |
out_i++; |
} |
if(s->rematrix_volume < 0) |
maxcoef = -s->rematrix_volume; |
if (s->rematrix_maxval > 0) { |
maxval = s->rematrix_maxval; |
} else if ( av_get_packed_sample_fmt(s->out_sample_fmt) < AV_SAMPLE_FMT_FLT |
|| av_get_packed_sample_fmt(s->int_sample_fmt) < AV_SAMPLE_FMT_FLT) { |
maxval = 1.0; |
} else |
maxval = INT_MAX; |
if(maxcoef > maxval || s->rematrix_volume < 0){ |
maxcoef /= maxval; |
for(i=0; i<SWR_CH_MAX; i++) |
for(j=0; j<SWR_CH_MAX; j++){ |
s->matrix[i][j] /= maxcoef; |
} |
} |
if(s->rematrix_volume > 0){ |
for(i=0; i<SWR_CH_MAX; i++) |
for(j=0; j<SWR_CH_MAX; j++){ |
s->matrix[i][j] *= s->rematrix_volume; |
} |
} |
for(i=0; i<av_get_channel_layout_nb_channels(out_ch_layout); i++){ |
for(j=0; j<av_get_channel_layout_nb_channels(in_ch_layout); j++){ |
av_log(NULL, AV_LOG_DEBUG, "%f ", s->matrix[i][j]); |
} |
av_log(NULL, AV_LOG_DEBUG, "\n"); |
} |
return 0; |
} |
av_cold int swri_rematrix_init(SwrContext *s){ |
int i, j; |
int nb_in = av_get_channel_layout_nb_channels(s->in_ch_layout); |
int nb_out = av_get_channel_layout_nb_channels(s->out_ch_layout); |
s->mix_any_f = NULL; |
if (!s->rematrix_custom) { |
int r = auto_matrix(s); |
if (r) |
return r; |
} |
if (s->midbuf.fmt == AV_SAMPLE_FMT_S16P){ |
s->native_matrix = av_calloc(nb_in * nb_out, sizeof(int)); |
s->native_one = av_mallocz(sizeof(int)); |
for (i = 0; i < nb_out; i++) |
for (j = 0; j < nb_in; j++) |
((int*)s->native_matrix)[i * nb_in + j] = lrintf(s->matrix[i][j] * 32768); |
*((int*)s->native_one) = 32768; |
s->mix_1_1_f = (mix_1_1_func_type*)copy_s16; |
s->mix_2_1_f = (mix_2_1_func_type*)sum2_s16; |
s->mix_any_f = (mix_any_func_type*)get_mix_any_func_s16(s); |
}else if(s->midbuf.fmt == AV_SAMPLE_FMT_FLTP){ |
s->native_matrix = av_calloc(nb_in * nb_out, sizeof(float)); |
s->native_one = av_mallocz(sizeof(float)); |
for (i = 0; i < nb_out; i++) |
for (j = 0; j < nb_in; j++) |
((float*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j]; |
*((float*)s->native_one) = 1.0; |
s->mix_1_1_f = (mix_1_1_func_type*)copy_float; |
s->mix_2_1_f = (mix_2_1_func_type*)sum2_float; |
s->mix_any_f = (mix_any_func_type*)get_mix_any_func_float(s); |
}else if(s->midbuf.fmt == AV_SAMPLE_FMT_DBLP){ |
s->native_matrix = av_calloc(nb_in * nb_out, sizeof(double)); |
s->native_one = av_mallocz(sizeof(double)); |
for (i = 0; i < nb_out; i++) |
for (j = 0; j < nb_in; j++) |
((double*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j]; |
*((double*)s->native_one) = 1.0; |
s->mix_1_1_f = (mix_1_1_func_type*)copy_double; |
s->mix_2_1_f = (mix_2_1_func_type*)sum2_double; |
s->mix_any_f = (mix_any_func_type*)get_mix_any_func_double(s); |
}else if(s->midbuf.fmt == AV_SAMPLE_FMT_S32P){ |
// Only for dithering currently |
// s->native_matrix = av_calloc(nb_in * nb_out, sizeof(double)); |
s->native_one = av_mallocz(sizeof(int)); |
// for (i = 0; i < nb_out; i++) |
// for (j = 0; j < nb_in; j++) |
// ((double*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j]; |
*((int*)s->native_one) = 32768; |
s->mix_1_1_f = (mix_1_1_func_type*)copy_s32; |
s->mix_2_1_f = (mix_2_1_func_type*)sum2_s32; |
s->mix_any_f = (mix_any_func_type*)get_mix_any_func_s32(s); |
}else |
av_assert0(0); |
//FIXME quantize for integeres |
for (i = 0; i < SWR_CH_MAX; i++) { |
int ch_in=0; |
for (j = 0; j < SWR_CH_MAX; j++) { |
s->matrix32[i][j]= lrintf(s->matrix[i][j] * 32768); |
if(s->matrix[i][j]) |
s->matrix_ch[i][++ch_in]= j; |
} |
s->matrix_ch[i][0]= ch_in; |
} |
if(HAVE_YASM && HAVE_MMX) swri_rematrix_init_x86(s); |
return 0; |
} |
av_cold void swri_rematrix_free(SwrContext *s){ |
av_freep(&s->native_matrix); |
av_freep(&s->native_one); |
av_freep(&s->native_simd_matrix); |
av_freep(&s->native_simd_one); |
} |
int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy){ |
int out_i, in_i, i, j; |
int len1 = 0; |
int off = 0; |
if(s->mix_any_f) { |
s->mix_any_f(out->ch, (const uint8_t **)in->ch, s->native_matrix, len); |
return 0; |
} |
if(s->mix_2_1_simd || s->mix_1_1_simd){ |
len1= len&~15; |
off = len1 * out->bps; |
} |
av_assert0(out->ch_count == av_get_channel_layout_nb_channels(s->out_ch_layout)); |
av_assert0(in ->ch_count == av_get_channel_layout_nb_channels(s-> in_ch_layout)); |
for(out_i=0; out_i<out->ch_count; out_i++){ |
switch(s->matrix_ch[out_i][0]){ |
case 0: |
if(mustcopy) |
memset(out->ch[out_i], 0, len * av_get_bytes_per_sample(s->int_sample_fmt)); |
break; |
case 1: |
in_i= s->matrix_ch[out_i][1]; |
if(s->matrix[out_i][in_i]!=1.0){ |
if(s->mix_1_1_simd && len1) |
s->mix_1_1_simd(out->ch[out_i] , in->ch[in_i] , s->native_simd_matrix, in->ch_count*out_i + in_i, len1); |
if(len != len1) |
s->mix_1_1_f (out->ch[out_i]+off, in->ch[in_i]+off, s->native_matrix, in->ch_count*out_i + in_i, len-len1); |
}else if(mustcopy){ |
memcpy(out->ch[out_i], in->ch[in_i], len*out->bps); |
}else{ |
out->ch[out_i]= in->ch[in_i]; |
} |
break; |
case 2: { |
int in_i1 = s->matrix_ch[out_i][1]; |
int in_i2 = s->matrix_ch[out_i][2]; |
if(s->mix_2_1_simd && len1) |
s->mix_2_1_simd(out->ch[out_i] , in->ch[in_i1] , in->ch[in_i2] , s->native_simd_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len1); |
else |
s->mix_2_1_f (out->ch[out_i] , in->ch[in_i1] , in->ch[in_i2] , s->native_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len1); |
if(len != len1) |
s->mix_2_1_f (out->ch[out_i]+off, in->ch[in_i1]+off, in->ch[in_i2]+off, s->native_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len-len1); |
break;} |
default: |
if(s->int_sample_fmt == AV_SAMPLE_FMT_FLTP){ |
for(i=0; i<len; i++){ |
float v=0; |
for(j=0; j<s->matrix_ch[out_i][0]; j++){ |
in_i= s->matrix_ch[out_i][1+j]; |
v+= ((float*)in->ch[in_i])[i] * s->matrix[out_i][in_i]; |
} |
((float*)out->ch[out_i])[i]= v; |
} |
}else if(s->int_sample_fmt == AV_SAMPLE_FMT_DBLP){ |
for(i=0; i<len; i++){ |
double v=0; |
for(j=0; j<s->matrix_ch[out_i][0]; j++){ |
in_i= s->matrix_ch[out_i][1+j]; |
v+= ((double*)in->ch[in_i])[i] * s->matrix[out_i][in_i]; |
} |
((double*)out->ch[out_i])[i]= v; |
} |
}else{ |
for(i=0; i<len; i++){ |
int v=0; |
for(j=0; j<s->matrix_ch[out_i][0]; j++){ |
in_i= s->matrix_ch[out_i][1+j]; |
v+= ((int16_t*)in->ch[in_i])[i] * s->matrix32[out_i][in_i]; |
} |
((int16_t*)out->ch[out_i])[i]= (v + 16384)>>15; |
} |
} |
} |
} |
return 0; |
} |
/contrib/sdk/sources/ffmpeg/libswresample/rematrix_template.c |
---|
0,0 → 1,106 |
/* |
* Copyright (C) 2011-2012 Michael Niedermayer (michaelni@gmx.at) |
* |
* This file is part of libswresample |
* |
* libswresample 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. |
* |
* libswresample 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 libswresample; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#if defined(TEMPLATE_REMATRIX_FLT) |
# define R(x) x |
# define SAMPLE float |
# define COEFF float |
# define INTER float |
# define RENAME(x) x ## _float |
#elif defined(TEMPLATE_REMATRIX_DBL) |
# define R(x) x |
# define SAMPLE double |
# define COEFF double |
# define INTER double |
# define RENAME(x) x ## _double |
#elif defined(TEMPLATE_REMATRIX_S16) |
# define R(x) (((x) + 16384)>>15) |
# define SAMPLE int16_t |
# define COEFF int |
# define INTER int |
# define RENAME(x) x ## _s16 |
#elif defined(TEMPLATE_REMATRIX_S32) |
# define R(x) (((x) + 16384)>>15) |
# define SAMPLE int32_t |
# define COEFF int |
# define INTER int64_t |
# define RENAME(x) x ## _s32 |
#endif |
typedef void (RENAME(mix_any_func_type))(SAMPLE **out, const SAMPLE **in1, COEFF *coeffp, integer len); |
static void RENAME(sum2)(SAMPLE *out, const SAMPLE *in1, const SAMPLE *in2, COEFF *coeffp, integer index1, integer index2, integer len){ |
int i; |
INTER coeff1 = coeffp[index1]; |
INTER coeff2 = coeffp[index2]; |
for(i=0; i<len; i++) |
out[i] = R(coeff1*in1[i] + coeff2*in2[i]); |
} |
static void RENAME(copy)(SAMPLE *out, const SAMPLE *in, COEFF *coeffp, integer index, integer len){ |
int i; |
INTER coeff = coeffp[index]; |
for(i=0; i<len; i++) |
out[i] = R(coeff*in[i]); |
} |
static void RENAME(mix6to2)(SAMPLE **out, const SAMPLE **in, COEFF *coeffp, integer len){ |
int i; |
for(i=0; i<len; i++) { |
INTER t = in[2][i]*(INTER)coeffp[0*6+2] + in[3][i]*(INTER)coeffp[0*6+3]; |
out[0][i] = R(t + in[0][i]*(INTER)coeffp[0*6+0] + in[4][i]*(INTER)coeffp[0*6+4]); |
out[1][i] = R(t + in[1][i]*(INTER)coeffp[1*6+1] + in[5][i]*(INTER)coeffp[1*6+5]); |
} |
} |
static void RENAME(mix8to2)(SAMPLE **out, const SAMPLE **in, COEFF *coeffp, integer len){ |
int i; |
for(i=0; i<len; i++) { |
INTER t = in[2][i]*(INTER)coeffp[0*8+2] + in[3][i]*(INTER)coeffp[0*8+3]; |
out[0][i] = R(t + in[0][i]*(INTER)coeffp[0*8+0] + in[4][i]*(INTER)coeffp[0*8+4] + in[6][i]*(INTER)coeffp[0*8+6]); |
out[1][i] = R(t + in[1][i]*(INTER)coeffp[1*8+1] + in[5][i]*(INTER)coeffp[1*8+5] + in[7][i]*(INTER)coeffp[1*8+7]); |
} |
} |
static RENAME(mix_any_func_type) *RENAME(get_mix_any_func)(SwrContext *s){ |
if( s->out_ch_layout == AV_CH_LAYOUT_STEREO && (s->in_ch_layout == AV_CH_LAYOUT_5POINT1 || s->in_ch_layout == AV_CH_LAYOUT_5POINT1_BACK) |
&& s->matrix[0][2] == s->matrix[1][2] && s->matrix[0][3] == s->matrix[1][3] |
&& !s->matrix[0][1] && !s->matrix[0][5] && !s->matrix[1][0] && !s->matrix[1][4] |
) |
return RENAME(mix6to2); |
if( s->out_ch_layout == AV_CH_LAYOUT_STEREO && s->in_ch_layout == AV_CH_LAYOUT_7POINT1 |
&& s->matrix[0][2] == s->matrix[1][2] && s->matrix[0][3] == s->matrix[1][3] |
&& !s->matrix[0][1] && !s->matrix[0][5] && !s->matrix[1][0] && !s->matrix[1][4] |
&& !s->matrix[0][7] && !s->matrix[1][6] |
) |
return RENAME(mix8to2); |
return NULL; |
} |
#undef R |
#undef SAMPLE |
#undef COEFF |
#undef INTER |
#undef RENAME |
/contrib/sdk/sources/ffmpeg/libswresample/resample.c |
---|
0,0 → 1,372 |
/* |
* audio resampling |
* Copyright (c) 2004-2012 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 |
*/ |
/** |
* @file |
* audio resampling |
* @author Michael Niedermayer <michaelni@gmx.at> |
*/ |
#include "libavutil/log.h" |
#include "libavutil/avassert.h" |
#include "swresample_internal.h" |
typedef struct ResampleContext { |
const AVClass *av_class; |
uint8_t *filter_bank; |
int filter_length; |
int filter_alloc; |
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 SwrFilterType filter_type; |
int kaiser_beta; |
double factor; |
enum AVSampleFormat format; |
int felem_size; |
int filter_shift; |
} ResampleContext; |
/** |
* 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; |
static const double inv[100]={ |
1.0/( 1* 1), 1.0/( 2* 2), 1.0/( 3* 3), 1.0/( 4* 4), 1.0/( 5* 5), 1.0/( 6* 6), 1.0/( 7* 7), 1.0/( 8* 8), 1.0/( 9* 9), 1.0/(10*10), |
1.0/(11*11), 1.0/(12*12), 1.0/(13*13), 1.0/(14*14), 1.0/(15*15), 1.0/(16*16), 1.0/(17*17), 1.0/(18*18), 1.0/(19*19), 1.0/(20*20), |
1.0/(21*21), 1.0/(22*22), 1.0/(23*23), 1.0/(24*24), 1.0/(25*25), 1.0/(26*26), 1.0/(27*27), 1.0/(28*28), 1.0/(29*29), 1.0/(30*30), |
1.0/(31*31), 1.0/(32*32), 1.0/(33*33), 1.0/(34*34), 1.0/(35*35), 1.0/(36*36), 1.0/(37*37), 1.0/(38*38), 1.0/(39*39), 1.0/(40*40), |
1.0/(41*41), 1.0/(42*42), 1.0/(43*43), 1.0/(44*44), 1.0/(45*45), 1.0/(46*46), 1.0/(47*47), 1.0/(48*48), 1.0/(49*49), 1.0/(50*50), |
1.0/(51*51), 1.0/(52*52), 1.0/(53*53), 1.0/(54*54), 1.0/(55*55), 1.0/(56*56), 1.0/(57*57), 1.0/(58*58), 1.0/(59*59), 1.0/(60*60), |
1.0/(61*61), 1.0/(62*62), 1.0/(63*63), 1.0/(64*64), 1.0/(65*65), 1.0/(66*66), 1.0/(67*67), 1.0/(68*68), 1.0/(69*69), 1.0/(70*70), |
1.0/(71*71), 1.0/(72*72), 1.0/(73*73), 1.0/(74*74), 1.0/(75*75), 1.0/(76*76), 1.0/(77*77), 1.0/(78*78), 1.0/(79*79), 1.0/(80*80), |
1.0/(81*81), 1.0/(82*82), 1.0/(83*83), 1.0/(84*84), 1.0/(85*85), 1.0/(86*86), 1.0/(87*87), 1.0/(88*88), 1.0/(89*89), 1.0/(90*90), |
1.0/(91*91), 1.0/(92*92), 1.0/(93*93), 1.0/(94*94), 1.0/(95*95), 1.0/(96*96), 1.0/(97*97), 1.0/(98*98), 1.0/(99*99), 1.0/(10000) |
}; |
x= x*x/4; |
for(i=0; v != lastv; i++){ |
lastv=v; |
t *= x*inv[i]; |
v += t; |
av_assert2(i<99); |
} |
return v; |
} |
/** |
* builds a polyphase filterbank. |
* @param factor resampling factor |
* @param scale wanted sum of coefficients for each filter |
* @param filter_type filter type |
* @param kaiser_beta kaiser window beta |
* @return 0 on success, negative on error |
*/ |
static int build_filter(ResampleContext *c, void *filter, double factor, int tap_count, int alloc, int phase_count, int scale, |
int filter_type, int kaiser_beta){ |
int ph, i; |
double x, y, w; |
double *tab = av_malloc(tap_count * sizeof(*tab)); |
const int center= (tap_count-1)/2; |
if (!tab) |
return AVERROR(ENOMEM); |
/* if upsampling, only need to interpolate, no filter */ |
if (factor > 1.0) |
factor = 1.0; |
for(ph=0;ph<phase_count;ph++) { |
double norm = 0; |
for(i=0;i<tap_count;i++) { |
x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor; |
if (x == 0) y = 1.0; |
else y = sin(x) / x; |
switch(filter_type){ |
case SWR_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 SWR_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 SWR_FILTER_TYPE_KAISER: |
w = 2.0*x / (factor*tap_count*M_PI); |
y *= bessel(kaiser_beta*sqrt(FFMAX(1-w*w, 0))); |
break; |
default: |
av_assert0(0); |
} |
tab[i] = y; |
norm += y; |
} |
/* normalize so that an uniform color remains the same */ |
switch(c->format){ |
case AV_SAMPLE_FMT_S16P: |
for(i=0;i<tap_count;i++) |
((int16_t*)filter)[ph * alloc + i] = av_clip(lrintf(tab[i] * scale / norm), INT16_MIN, INT16_MAX); |
break; |
case AV_SAMPLE_FMT_S32P: |
for(i=0;i<tap_count;i++) |
((int32_t*)filter)[ph * alloc + i] = av_clipl_int32(llrint(tab[i] * scale / norm)); |
break; |
case AV_SAMPLE_FMT_FLTP: |
for(i=0;i<tap_count;i++) |
((float*)filter)[ph * alloc + i] = tab[i] * scale / norm; |
break; |
case AV_SAMPLE_FMT_DBLP: |
for(i=0;i<tap_count;i++) |
((double*)filter)[ph * alloc + i] = tab[i] * scale / norm; |
break; |
} |
} |
#if 0 |
{ |
#define LEN 1024 |
int j,k; |
double sine[LEN + tap_count]; |
double filtered[LEN]; |
double maxff=-2, minff=2, maxsf=-2, minsf=2; |
for(i=0; i<LEN; i++){ |
double ss=0, sf=0, ff=0; |
for(j=0; j<LEN+tap_count; j++) |
sine[j]= cos(i*j*M_PI/LEN); |
for(j=0; j<LEN; j++){ |
double sum=0; |
ph=0; |
for(k=0; k<tap_count; k++) |
sum += filter[ph * tap_count + k] * sine[k+j]; |
filtered[j]= sum / (1<<FILTER_SHIFT); |
ss+= sine[j + center] * sine[j + center]; |
ff+= filtered[j] * filtered[j]; |
sf+= sine[j + center] * filtered[j]; |
} |
ss= sqrt(2*ss/LEN); |
ff= sqrt(2*ff/LEN); |
sf= 2*sf/LEN; |
maxff= FFMAX(maxff, ff); |
minff= FFMIN(minff, ff); |
maxsf= FFMAX(maxsf, sf); |
minsf= FFMIN(minsf, sf); |
if(i%11==0){ |
av_log(NULL, AV_LOG_ERROR, "i:%4d ss:%f ff:%13.6e-%13.6e sf:%13.6e-%13.6e\n", i, ss, maxff, minff, maxsf, minsf); |
minff=minsf= 2; |
maxff=maxsf= -2; |
} |
} |
} |
#endif |
av_free(tab); |
return 0; |
} |
static ResampleContext *resample_init(ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, |
double cutoff0, enum AVSampleFormat format, enum SwrFilterType filter_type, int kaiser_beta, |
double precision, int cheby){ |
double cutoff = cutoff0? cutoff0 : 0.97; |
double factor= FFMIN(out_rate * cutoff / in_rate, 1.0); |
int phase_count= 1<<phase_shift; |
if (!c || c->phase_shift != phase_shift || c->linear!=linear || c->factor != factor |
|| c->filter_length != FFMAX((int)ceil(filter_size/factor), 1) || c->format != format |
|| c->filter_type != filter_type || c->kaiser_beta != kaiser_beta) { |
c = av_mallocz(sizeof(*c)); |
if (!c) |
return NULL; |
c->format= format; |
c->felem_size= av_get_bytes_per_sample(c->format); |
switch(c->format){ |
case AV_SAMPLE_FMT_S16P: |
c->filter_shift = 15; |
break; |
case AV_SAMPLE_FMT_S32P: |
c->filter_shift = 30; |
break; |
case AV_SAMPLE_FMT_FLTP: |
case AV_SAMPLE_FMT_DBLP: |
c->filter_shift = 0; |
break; |
default: |
av_log(NULL, AV_LOG_ERROR, "Unsupported sample format\n"); |
av_assert0(0); |
} |
c->phase_shift = phase_shift; |
c->phase_mask = phase_count - 1; |
c->linear = linear; |
c->factor = factor; |
c->filter_length = FFMAX((int)ceil(filter_size/factor), 1); |
c->filter_alloc = FFALIGN(c->filter_length, 8); |
c->filter_bank = av_calloc(c->filter_alloc, (phase_count+1)*c->felem_size); |
c->filter_type = filter_type; |
c->kaiser_beta = kaiser_beta; |
if (!c->filter_bank) |
goto error; |
if (build_filter(c, (void*)c->filter_bank, factor, c->filter_length, c->filter_alloc, phase_count, 1<<c->filter_shift, filter_type, kaiser_beta)) |
goto error; |
memcpy(c->filter_bank + (c->filter_alloc*phase_count+1)*c->felem_size, c->filter_bank, (c->filter_alloc-1)*c->felem_size); |
memcpy(c->filter_bank + (c->filter_alloc*phase_count )*c->felem_size, c->filter_bank + (c->filter_alloc - 1)*c->felem_size, c->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; |
return c; |
error: |
av_freep(&c->filter_bank); |
av_free(c); |
return NULL; |
} |
static void resample_free(ResampleContext **c){ |
if(!*c) |
return; |
av_freep(&(*c)->filter_bank); |
av_freep(c); |
} |
static int set_compensation(ResampleContext *c, int sample_delta, int compensation_distance){ |
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; |
} |
#define TEMPLATE_RESAMPLE_S16 |
#include "resample_template.c" |
#undef TEMPLATE_RESAMPLE_S16 |
#define TEMPLATE_RESAMPLE_S32 |
#include "resample_template.c" |
#undef TEMPLATE_RESAMPLE_S32 |
#define TEMPLATE_RESAMPLE_FLT |
#include "resample_template.c" |
#undef TEMPLATE_RESAMPLE_FLT |
#define TEMPLATE_RESAMPLE_DBL |
#include "resample_template.c" |
#undef TEMPLATE_RESAMPLE_DBL |
// XXX FIXME the whole C loop should be written in asm so this x86 specific code here isnt needed |
#if HAVE_MMXEXT_INLINE |
#include "x86/resample_mmx.h" |
#define TEMPLATE_RESAMPLE_S16_MMX2 |
#include "resample_template.c" |
#undef TEMPLATE_RESAMPLE_S16_MMX2 |
#if HAVE_SSSE3_INLINE |
#define TEMPLATE_RESAMPLE_S16_SSSE3 |
#include "resample_template.c" |
#undef TEMPLATE_RESAMPLE_S16_SSSE3 |
#endif |
#endif // HAVE_MMXEXT_INLINE |
static int multiple_resample(ResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed){ |
int i, ret= -1; |
int av_unused mm_flags = av_get_cpu_flags(); |
int need_emms= 0; |
for(i=0; i<dst->ch_count; i++){ |
#if HAVE_MMXEXT_INLINE |
#if HAVE_SSSE3_INLINE |
if(c->format == AV_SAMPLE_FMT_S16P && (mm_flags&AV_CPU_FLAG_SSSE3)) ret= swri_resample_int16_ssse3(c, (int16_t*)dst->ch[i], (const int16_t*)src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count); |
else |
#endif |
if(c->format == AV_SAMPLE_FMT_S16P && (mm_flags&AV_CPU_FLAG_MMX2 )){ |
ret= swri_resample_int16_mmx2 (c, (int16_t*)dst->ch[i], (const int16_t*)src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count); |
need_emms= 1; |
} else |
#endif |
if(c->format == AV_SAMPLE_FMT_S16P) ret= swri_resample_int16(c, (int16_t*)dst->ch[i], (const int16_t*)src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count); |
else if(c->format == AV_SAMPLE_FMT_S32P) ret= swri_resample_int32(c, (int32_t*)dst->ch[i], (const int32_t*)src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count); |
else if(c->format == AV_SAMPLE_FMT_FLTP) ret= swri_resample_float(c, (float *)dst->ch[i], (const float *)src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count); |
else if(c->format == AV_SAMPLE_FMT_DBLP) ret= swri_resample_double(c,(double *)dst->ch[i], (const double *)src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count); |
} |
if(need_emms) |
emms_c(); |
return ret; |
} |
static int64_t get_delay(struct SwrContext *s, int64_t base){ |
ResampleContext *c = s->resample; |
int64_t num = s->in_buffer_count - (c->filter_length-1)/2; |
num <<= c->phase_shift; |
num -= c->index; |
num *= c->src_incr; |
num -= c->frac; |
return av_rescale(num, base, s->in_sample_rate*(int64_t)c->src_incr << c->phase_shift); |
} |
static int resample_flush(struct SwrContext *s) { |
AudioData *a= &s->in_buffer; |
int i, j, ret; |
if((ret = swri_realloc_audio(a, s->in_buffer_index + 2*s->in_buffer_count)) < 0) |
return ret; |
av_assert0(a->planar); |
for(i=0; i<a->ch_count; i++){ |
for(j=0; j<s->in_buffer_count; j++){ |
memcpy(a->ch[i] + (s->in_buffer_index+s->in_buffer_count+j )*a->bps, |
a->ch[i] + (s->in_buffer_index+s->in_buffer_count-j-1)*a->bps, a->bps); |
} |
} |
s->in_buffer_count += (s->in_buffer_count+1)/2; |
return 0; |
} |
struct Resampler const swri_resampler={ |
resample_init, |
resample_free, |
multiple_resample, |
resample_flush, |
set_compensation, |
get_delay, |
}; |
/contrib/sdk/sources/ffmpeg/libswresample/resample_template.c |
---|
0,0 → 1,211 |
/* |
* audio resampling |
* Copyright (c) 2004-2012 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 |
*/ |
/** |
* @file |
* audio resampling |
* @author Michael Niedermayer <michaelni@gmx.at> |
*/ |
#if defined(TEMPLATE_RESAMPLE_DBL) |
# define RENAME(N) N ## _double |
# define FILTER_SHIFT 0 |
# define DELEM double |
# define FELEM double |
# define FELEM2 double |
# define FELEML double |
# define OUT(d, v) d = v |
#elif defined(TEMPLATE_RESAMPLE_FLT) |
# define RENAME(N) N ## _float |
# define FILTER_SHIFT 0 |
# define DELEM float |
# define FELEM float |
# define FELEM2 float |
# define FELEML float |
# define OUT(d, v) d = v |
#elif defined(TEMPLATE_RESAMPLE_S32) |
# define RENAME(N) N ## _int32 |
# define FILTER_SHIFT 30 |
# define DELEM int32_t |
# define FELEM int32_t |
# define FELEM2 int64_t |
# define FELEML int64_t |
# define FELEM_MAX INT32_MAX |
# define FELEM_MIN INT32_MIN |
# define OUT(d, v) v = (v + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT;\ |
d = (uint64_t)(v + 0x80000000) > 0xFFFFFFFF ? (v>>63) ^ 0x7FFFFFFF : v |
#elif defined(TEMPLATE_RESAMPLE_S16) \ |
|| defined(TEMPLATE_RESAMPLE_S16_MMX2) \ |
|| defined(TEMPLATE_RESAMPLE_S16_SSSE3) |
# define FILTER_SHIFT 15 |
# define DELEM int16_t |
# define FELEM int16_t |
# define FELEM2 int32_t |
# define FELEML int64_t |
# define FELEM_MAX INT16_MAX |
# define FELEM_MIN INT16_MIN |
# define OUT(d, v) v = (v + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT;\ |
d = (unsigned)(v + 32768) > 65535 ? (v>>31) ^ 32767 : v |
# if defined(TEMPLATE_RESAMPLE_S16) |
# define RENAME(N) N ## _int16 |
# elif defined(TEMPLATE_RESAMPLE_S16_MMX2) |
# define COMMON_CORE COMMON_CORE_INT16_MMX2 |
# define RENAME(N) N ## _int16_mmx2 |
# elif defined(TEMPLATE_RESAMPLE_S16_SSSE3) |
# define COMMON_CORE COMMON_CORE_INT16_SSSE3 |
# define RENAME(N) N ## _int16_ssse3 |
# endif |
#endif |
int RENAME(swri_resample)(ResampleContext *c, DELEM *dst, const DELEM *src, int *consumed, int src_size, int dst_size, int update_ctx){ |
int dst_index, i; |
int index= c->index; |
int frac= c->frac; |
int dst_incr_frac= c->dst_incr % c->src_incr; |
int dst_incr= c->dst_incr / c->src_incr; |
int compensation_distance= c->compensation_distance; |
av_assert1(c->filter_shift == FILTER_SHIFT); |
av_assert1(c->felem_size == sizeof(FELEM)); |
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); |
for(dst_index=0; dst_index < dst_size; dst_index++){ |
dst[dst_index] = src[index2>>32]; |
index2 += incr; |
} |
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; |
av_assert2(index >= 0); |
*consumed= index >> c->phase_shift; |
index &= c->phase_mask; |
}else if(compensation_distance == 0 && !c->linear && index >= 0){ |
int sample_index = 0; |
for(dst_index=0; dst_index < dst_size; dst_index++){ |
FELEM *filter; |
sample_index += index >> c->phase_shift; |
index &= c->phase_mask; |
filter= ((FELEM*)c->filter_bank) + c->filter_alloc*index; |
if(sample_index + c->filter_length > src_size){ |
break; |
}else{ |
#ifdef COMMON_CORE |
COMMON_CORE |
#else |
FELEM2 val=0; |
for(i=0; i<c->filter_length; i++){ |
val += src[sample_index + i] * (FELEM2)filter[i]; |
} |
OUT(dst[dst_index], val); |
#endif |
} |
frac += dst_incr_frac; |
index += dst_incr; |
if(frac >= c->src_incr){ |
frac -= c->src_incr; |
index++; |
} |
} |
*consumed = sample_index; |
}else{ |
int sample_index = 0; |
for(dst_index=0; dst_index < dst_size; dst_index++){ |
FELEM *filter; |
FELEM2 val=0; |
sample_index += index >> c->phase_shift; |
index &= c->phase_mask; |
filter = ((FELEM*)c->filter_bank) + c->filter_alloc*index; |
if(sample_index + c->filter_length > src_size || -sample_index >= src_size){ |
break; |
}else if(sample_index < 0){ |
for(i=0; i<c->filter_length; i++) |
val += src[FFABS(sample_index + i)] * (FELEM2)filter[i]; |
}else if(c->linear){ |
FELEM2 v2=0; |
for(i=0; i<c->filter_length; i++){ |
val += src[sample_index + i] * (FELEM2)filter[i]; |
v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_alloc]; |
} |
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); |
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; |
} |
} |
*consumed= FFMAX(sample_index, 0); |
index += FFMIN(sample_index, 0) << c->phase_shift; |
if(compensation_distance){ |
compensation_distance -= dst_index; |
av_assert1(compensation_distance > 0); |
} |
} |
if(update_ctx){ |
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; |
} |
#undef COMMON_CORE |
#undef RENAME |
#undef FILTER_SHIFT |
#undef DELEM |
#undef FELEM |
#undef FELEM2 |
#undef FELEML |
#undef FELEM_MAX |
#undef FELEM_MIN |
#undef OUT |
/contrib/sdk/sources/ffmpeg/libswresample/soxr_resample.c |
---|
0,0 → 1,93 |
/* |
* audio resampling with soxr |
* Copyright (c) 2012 Rob Sykes <robs@users.sourceforge.net> |
* |
* 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 |
* audio resampling with soxr |
*/ |
#include "libavutil/log.h" |
#include "swresample_internal.h" |
#include <soxr.h> |
static struct ResampleContext *create(struct ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, |
double cutoff, enum AVSampleFormat format, enum SwrFilterType filter_type, int kaiser_beta, double precision, int cheby){ |
soxr_error_t error; |
soxr_datatype_t type = |
format == AV_SAMPLE_FMT_S16P? SOXR_INT16_S : |
format == AV_SAMPLE_FMT_S16 ? SOXR_INT16_I : |
format == AV_SAMPLE_FMT_S32P? SOXR_INT32_S : |
format == AV_SAMPLE_FMT_S32 ? SOXR_INT32_I : |
format == AV_SAMPLE_FMT_FLTP? SOXR_FLOAT32_S : |
format == AV_SAMPLE_FMT_FLT ? SOXR_FLOAT32_I : |
format == AV_SAMPLE_FMT_DBLP? SOXR_FLOAT64_S : |
format == AV_SAMPLE_FMT_DBL ? SOXR_FLOAT64_I : (soxr_datatype_t)-1; |
soxr_io_spec_t io_spec = soxr_io_spec(type, type); |
soxr_quality_spec_t q_spec = soxr_quality_spec((int)((precision-2)/4), (SOXR_HI_PREC_CLOCK|SOXR_ROLLOFF_NONE)*!!cheby); |
q_spec.precision = linear? 0 : precision; |
#if !defined SOXR_VERSION /* Deprecated @ March 2013: */ |
q_spec.bw_pc = cutoff? FFMAX(FFMIN(cutoff,.995),.8)*100 : q_spec.bw_pc; |
#else |
q_spec.passband_end = cutoff? FFMAX(FFMIN(cutoff,.995),.8) : q_spec.passband_end; |
#endif |
soxr_delete((soxr_t)c); |
c = (struct ResampleContext *) |
soxr_create(in_rate, out_rate, 0, &error, &io_spec, &q_spec, 0); |
if (!c) |
av_log(NULL, AV_LOG_ERROR, "soxr_create: %s\n", error); |
return c; |
} |
static void destroy(struct ResampleContext * *c){ |
soxr_delete((soxr_t)*c); |
*c = NULL; |
} |
static int flush(struct SwrContext *s){ |
soxr_process((soxr_t)s->resample, NULL, 0, NULL, NULL, 0, NULL); |
return 0; |
} |
static int process( |
struct ResampleContext * c, AudioData *dst, int dst_size, |
AudioData *src, int src_size, int *consumed){ |
size_t idone, odone; |
soxr_error_t error = soxr_set_error((soxr_t)c, soxr_set_num_channels((soxr_t)c, src->ch_count)); |
error = soxr_process((soxr_t)c, src->ch, (size_t)src_size, |
&idone, dst->ch, (size_t)dst_size, &odone); |
*consumed = (int)idone; |
return error? -1 : odone; |
} |
static int64_t get_delay(struct SwrContext *s, int64_t base){ |
double delay_s = soxr_delay((soxr_t)s->resample) / s->out_sample_rate; |
return (int64_t)(delay_s * base + .5); |
} |
struct Resampler const soxr_resampler={ |
create, destroy, process, flush, NULL /* set_compensation */, get_delay, |
}; |
/contrib/sdk/sources/ffmpeg/libswresample/swresample-0.def |
---|
0,0 → 1,93 |
EXPORTS |
ff_float_to_int16_a_sse2 DATA |
ff_float_to_int16_u_sse2 DATA |
ff_float_to_int32_a_sse2 DATA |
ff_float_to_int32_u_sse2 DATA |
ff_int16_to_float_a_sse2 DATA |
ff_int16_to_float_u_sse2 DATA |
ff_int16_to_int32_a_mmx DATA |
ff_int16_to_int32_a_sse2 DATA |
ff_int16_to_int32_u_mmx DATA |
ff_int16_to_int32_u_sse2 DATA |
ff_int32_to_float_a_sse2 DATA |
ff_int32_to_float_u_sse2 DATA |
ff_int32_to_int16_a_mmx DATA |
ff_int32_to_int16_a_sse2 DATA |
ff_int32_to_int16_u_mmx DATA |
ff_int32_to_int16_u_sse2 DATA |
ff_log2_tab DATA |
ff_mix_1_1_a_float_sse DATA |
ff_mix_1_1_a_int16_mmx DATA |
ff_mix_1_1_a_int16_sse2 DATA |
ff_mix_1_1_u_float_sse DATA |
ff_mix_1_1_u_int16_mmx DATA |
ff_mix_1_1_u_int16_sse2 DATA |
ff_mix_2_1_a_float_sse DATA |
ff_mix_2_1_a_int16_mmx DATA |
ff_mix_2_1_a_int16_sse2 DATA |
ff_mix_2_1_u_float_sse DATA |
ff_mix_2_1_u_int16_mmx DATA |
ff_mix_2_1_u_int16_sse2 DATA |
ff_pack_2ch_float_to_int16_a_sse2 DATA |
ff_pack_2ch_float_to_int16_u_sse2 DATA |
ff_pack_2ch_float_to_int32_a_sse2 DATA |
ff_pack_2ch_float_to_int32_u_sse2 DATA |
ff_pack_2ch_int16_to_float_a_sse2 DATA |
ff_pack_2ch_int16_to_float_u_sse2 DATA |
ff_pack_2ch_int16_to_int16_a_sse2 DATA |
ff_pack_2ch_int16_to_int16_u_sse2 DATA |
ff_pack_2ch_int16_to_int32_a_sse2 DATA |
ff_pack_2ch_int16_to_int32_u_sse2 DATA |
ff_pack_2ch_int32_to_float_a_sse2 DATA |
ff_pack_2ch_int32_to_float_u_sse2 DATA |
ff_pack_2ch_int32_to_int16_a_sse2 DATA |
ff_pack_2ch_int32_to_int16_u_sse2 DATA |
ff_pack_2ch_int32_to_int32_a_sse2 DATA |
ff_pack_2ch_int32_to_int32_u_sse2 DATA |
ff_pack_6ch_float_to_float_a_mmx DATA |
ff_pack_6ch_float_to_float_a_sse4 DATA |
ff_pack_6ch_float_to_float_u_mmx DATA |
ff_pack_6ch_float_to_float_u_sse4 DATA |
ff_pack_6ch_float_to_int32_a_sse4 DATA |
ff_pack_6ch_float_to_int32_u_sse4 DATA |
ff_pack_6ch_int32_to_float_a_sse4 DATA |
ff_pack_6ch_int32_to_float_u_sse4 DATA |
ff_resample_int16_rounder DATA |
ff_unpack_2ch_float_to_int16_a_sse2 DATA |
ff_unpack_2ch_float_to_int16_u_sse2 DATA |
ff_unpack_2ch_float_to_int32_a_sse2 DATA |
ff_unpack_2ch_float_to_int32_u_sse2 DATA |
ff_unpack_2ch_int16_to_float_a_sse2 DATA |
ff_unpack_2ch_int16_to_float_a_ssse3 DATA |
ff_unpack_2ch_int16_to_float_u_sse2 DATA |
ff_unpack_2ch_int16_to_float_u_ssse3 DATA |
ff_unpack_2ch_int16_to_int16_a_sse2 DATA |
ff_unpack_2ch_int16_to_int16_a_ssse3 DATA |
ff_unpack_2ch_int16_to_int16_u_sse2 DATA |
ff_unpack_2ch_int16_to_int16_u_ssse3 DATA |
ff_unpack_2ch_int16_to_int32_a_sse2 DATA |
ff_unpack_2ch_int16_to_int32_a_ssse3 DATA |
ff_unpack_2ch_int16_to_int32_u_sse2 DATA |
ff_unpack_2ch_int16_to_int32_u_ssse3 DATA |
ff_unpack_2ch_int32_to_float_a_sse2 DATA |
ff_unpack_2ch_int32_to_float_u_sse2 DATA |
ff_unpack_2ch_int32_to_int16_a_sse2 DATA |
ff_unpack_2ch_int32_to_int16_u_sse2 DATA |
ff_unpack_2ch_int32_to_int32_a_sse2 DATA |
ff_unpack_2ch_int32_to_int32_u_sse2 DATA |
swr_alloc |
swr_alloc_set_opts |
swr_convert |
swr_drop_output |
swr_free |
swr_get_class |
swr_get_delay |
swr_init |
swr_inject_silence |
swr_next_pts |
swr_set_channel_mapping |
swr_set_compensation |
swr_set_matrix |
swresample_configuration |
swresample_license |
swresample_version |
/contrib/sdk/sources/ffmpeg/libswresample/swresample-0.orig.def |
---|
0,0 → 1,93 |
EXPORTS |
ff_float_to_int16_a_sse2 @1 DATA |
ff_float_to_int16_u_sse2 @2 DATA |
ff_float_to_int32_a_sse2 @3 DATA |
ff_float_to_int32_u_sse2 @4 DATA |
ff_int16_to_float_a_sse2 @5 DATA |
ff_int16_to_float_u_sse2 @6 DATA |
ff_int16_to_int32_a_mmx @7 DATA |
ff_int16_to_int32_a_sse2 @8 DATA |
ff_int16_to_int32_u_mmx @9 DATA |
ff_int16_to_int32_u_sse2 @10 DATA |
ff_int32_to_float_a_sse2 @11 DATA |
ff_int32_to_float_u_sse2 @12 DATA |
ff_int32_to_int16_a_mmx @13 DATA |
ff_int32_to_int16_a_sse2 @14 DATA |
ff_int32_to_int16_u_mmx @15 DATA |
ff_int32_to_int16_u_sse2 @16 DATA |
ff_log2_tab @17 DATA |
ff_mix_1_1_a_float_sse @18 DATA |
ff_mix_1_1_a_int16_mmx @19 DATA |
ff_mix_1_1_a_int16_sse2 @20 DATA |
ff_mix_1_1_u_float_sse @21 DATA |
ff_mix_1_1_u_int16_mmx @22 DATA |
ff_mix_1_1_u_int16_sse2 @23 DATA |
ff_mix_2_1_a_float_sse @24 DATA |
ff_mix_2_1_a_int16_mmx @25 DATA |
ff_mix_2_1_a_int16_sse2 @26 DATA |
ff_mix_2_1_u_float_sse @27 DATA |
ff_mix_2_1_u_int16_mmx @28 DATA |
ff_mix_2_1_u_int16_sse2 @29 DATA |
ff_pack_2ch_float_to_int16_a_sse2 @30 DATA |
ff_pack_2ch_float_to_int16_u_sse2 @31 DATA |
ff_pack_2ch_float_to_int32_a_sse2 @32 DATA |
ff_pack_2ch_float_to_int32_u_sse2 @33 DATA |
ff_pack_2ch_int16_to_float_a_sse2 @34 DATA |
ff_pack_2ch_int16_to_float_u_sse2 @35 DATA |
ff_pack_2ch_int16_to_int16_a_sse2 @36 DATA |
ff_pack_2ch_int16_to_int16_u_sse2 @37 DATA |
ff_pack_2ch_int16_to_int32_a_sse2 @38 DATA |
ff_pack_2ch_int16_to_int32_u_sse2 @39 DATA |
ff_pack_2ch_int32_to_float_a_sse2 @40 DATA |
ff_pack_2ch_int32_to_float_u_sse2 @41 DATA |
ff_pack_2ch_int32_to_int16_a_sse2 @42 DATA |
ff_pack_2ch_int32_to_int16_u_sse2 @43 DATA |
ff_pack_2ch_int32_to_int32_a_sse2 @44 DATA |
ff_pack_2ch_int32_to_int32_u_sse2 @45 DATA |
ff_pack_6ch_float_to_float_a_mmx @46 DATA |
ff_pack_6ch_float_to_float_a_sse4 @47 DATA |
ff_pack_6ch_float_to_float_u_mmx @48 DATA |
ff_pack_6ch_float_to_float_u_sse4 @49 DATA |
ff_pack_6ch_float_to_int32_a_sse4 @50 DATA |
ff_pack_6ch_float_to_int32_u_sse4 @51 DATA |
ff_pack_6ch_int32_to_float_a_sse4 @52 DATA |
ff_pack_6ch_int32_to_float_u_sse4 @53 DATA |
ff_resample_int16_rounder @54 DATA |
ff_unpack_2ch_float_to_int16_a_sse2 @55 DATA |
ff_unpack_2ch_float_to_int16_u_sse2 @56 DATA |
ff_unpack_2ch_float_to_int32_a_sse2 @57 DATA |
ff_unpack_2ch_float_to_int32_u_sse2 @58 DATA |
ff_unpack_2ch_int16_to_float_a_sse2 @59 DATA |
ff_unpack_2ch_int16_to_float_a_ssse3 @60 DATA |
ff_unpack_2ch_int16_to_float_u_sse2 @61 DATA |
ff_unpack_2ch_int16_to_float_u_ssse3 @62 DATA |
ff_unpack_2ch_int16_to_int16_a_sse2 @63 DATA |
ff_unpack_2ch_int16_to_int16_a_ssse3 @64 DATA |
ff_unpack_2ch_int16_to_int16_u_sse2 @65 DATA |
ff_unpack_2ch_int16_to_int16_u_ssse3 @66 DATA |
ff_unpack_2ch_int16_to_int32_a_sse2 @67 DATA |
ff_unpack_2ch_int16_to_int32_a_ssse3 @68 DATA |
ff_unpack_2ch_int16_to_int32_u_sse2 @69 DATA |
ff_unpack_2ch_int16_to_int32_u_ssse3 @70 DATA |
ff_unpack_2ch_int32_to_float_a_sse2 @71 DATA |
ff_unpack_2ch_int32_to_float_u_sse2 @72 DATA |
ff_unpack_2ch_int32_to_int16_a_sse2 @73 DATA |
ff_unpack_2ch_int32_to_int16_u_sse2 @74 DATA |
ff_unpack_2ch_int32_to_int32_a_sse2 @75 DATA |
ff_unpack_2ch_int32_to_int32_u_sse2 @76 DATA |
swr_alloc @77 |
swr_alloc_set_opts @78 |
swr_convert @79 |
swr_drop_output @80 |
swr_free @81 |
swr_get_class @82 |
swr_get_delay @83 |
swr_init @84 |
swr_inject_silence @85 |
swr_next_pts @86 |
swr_set_channel_mapping @87 |
swr_set_compensation @88 |
swr_set_matrix @89 |
swresample_configuration @90 |
swresample_license @91 |
swresample_version @92 |
/contrib/sdk/sources/ffmpeg/libswresample/swresample-test.c |
---|
0,0 → 1,414 |
/* |
* Copyright (C) 2011-2012 Michael Niedermayer (michaelni@gmx.at) |
* Copyright (c) 2002 Fabrice Bellard |
* |
* This file is part of libswresample |
* |
* libswresample is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or |
* (at your option) any later version. |
* |
* libswresample 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 General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with libswresample; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include "libavutil/avassert.h" |
#include "libavutil/channel_layout.h" |
#include "libavutil/common.h" |
#include "libavutil/opt.h" |
#include "swresample.h" |
#undef time |
#include "time.h" |
#undef fprintf |
#define SAMPLES 1000 |
#define ASSERT_LEVEL 2 |
static double get(uint8_t *a[], int ch, int index, int ch_count, enum AVSampleFormat f){ |
const uint8_t *p; |
if(av_sample_fmt_is_planar(f)){ |
f= av_get_alt_sample_fmt(f, 0); |
p= a[ch]; |
}else{ |
p= a[0]; |
index= ch + index*ch_count; |
} |
switch(f){ |
case AV_SAMPLE_FMT_U8 : return ((const uint8_t*)p)[index]/127.0-1.0; |
case AV_SAMPLE_FMT_S16: return ((const int16_t*)p)[index]/32767.0; |
case AV_SAMPLE_FMT_S32: return ((const int32_t*)p)[index]/2147483647.0; |
case AV_SAMPLE_FMT_FLT: return ((const float *)p)[index]; |
case AV_SAMPLE_FMT_DBL: return ((const double *)p)[index]; |
default: av_assert0(0); |
} |
} |
static void set(uint8_t *a[], int ch, int index, int ch_count, enum AVSampleFormat f, double v){ |
uint8_t *p; |
if(av_sample_fmt_is_planar(f)){ |
f= av_get_alt_sample_fmt(f, 0); |
p= a[ch]; |
}else{ |
p= a[0]; |
index= ch + index*ch_count; |
} |
switch(f){ |
case AV_SAMPLE_FMT_U8 : ((uint8_t*)p)[index]= av_clip_uint8 (lrint((v+1.0)*127)); break; |
case AV_SAMPLE_FMT_S16: ((int16_t*)p)[index]= av_clip_int16 (lrint(v*32767)); break; |
case AV_SAMPLE_FMT_S32: ((int32_t*)p)[index]= av_clipl_int32(llrint(v*2147483647)); break; |
case AV_SAMPLE_FMT_FLT: ((float *)p)[index]= v; break; |
case AV_SAMPLE_FMT_DBL: ((double *)p)[index]= v; break; |
default: av_assert2(0); |
} |
} |
static void shift(uint8_t *a[], int index, int ch_count, enum AVSampleFormat f){ |
int ch; |
if(av_sample_fmt_is_planar(f)){ |
f= av_get_alt_sample_fmt(f, 0); |
for(ch= 0; ch<ch_count; ch++) |
a[ch] += index*av_get_bytes_per_sample(f); |
}else{ |
a[0] += index*ch_count*av_get_bytes_per_sample(f); |
} |
} |
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[] = { |
8000, |
11025, |
16000, |
22050, |
32000, |
48000, |
}; |
uint64_t layouts[]={ |
AV_CH_LAYOUT_MONO , |
AV_CH_LAYOUT_STEREO , |
AV_CH_LAYOUT_2_1 , |
AV_CH_LAYOUT_SURROUND , |
AV_CH_LAYOUT_4POINT0 , |
AV_CH_LAYOUT_2_2 , |
AV_CH_LAYOUT_QUAD , |
AV_CH_LAYOUT_5POINT0 , |
AV_CH_LAYOUT_5POINT1 , |
AV_CH_LAYOUT_5POINT0_BACK , |
AV_CH_LAYOUT_5POINT1_BACK , |
AV_CH_LAYOUT_7POINT0 , |
AV_CH_LAYOUT_7POINT1 , |
AV_CH_LAYOUT_7POINT1_WIDE , |
}; |
static void setup_array(uint8_t *out[SWR_CH_MAX], uint8_t *in, enum AVSampleFormat format, int samples){ |
if(av_sample_fmt_is_planar(format)){ |
int i; |
int plane_size= av_get_bytes_per_sample(format&0xFF)*samples; |
format&=0xFF; |
for(i=0; i<SWR_CH_MAX; i++){ |
out[i]= in + i*plane_size; |
} |
}else{ |
out[0]= in; |
} |
} |
static int cmp(const int *a, const int *b){ |
return *a - *b; |
} |
static void audiogen(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[SWR_CH_MAX]; |
double tabf2[SWR_CH_MAX]; |
double taba[SWR_CH_MAX]; |
unsigned static rnd; |
#define PUT_SAMPLE set(data, ch, k, channels, sample_fmt, v); |
#define uint_rand(x) (x = x * 1664525 + 1013904223) |
#define dbl_rand(x) (uint_rand(x)*2.0 / (double)UINT_MAX - 1) |
k = 0; |
/* 1 second of single freq sinus at 1000 Hz */ |
a = 0; |
for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { |
v = sin(a) * 0.30; |
for (ch = 0; ch < channels; ch++) |
PUT_SAMPLE |
a += M_PI * 1000.0 * 2.0 / sample_rate; |
} |
/* 1 second of varing frequency between 100 and 10000 Hz */ |
a = 0; |
for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { |
v = sin(a) * 0.30; |
for (ch = 0; ch < channels; ch++) |
PUT_SAMPLE |
f = 100.0 + (((10000.0 - 100.0) * i) / sample_rate); |
a += M_PI * f * 2.0 / sample_rate; |
} |
/* 0.5 second of low amplitude white noise */ |
for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) { |
v = dbl_rand(rnd) * 0.30; |
for (ch = 0; ch < channels; ch++) |
PUT_SAMPLE |
} |
/* 0.5 second of high amplitude white noise */ |
for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) { |
v = dbl_rand(rnd); |
for (ch = 0; ch < channels; ch++) |
PUT_SAMPLE |
} |
/* 1 second of unrelated ramps for each channel */ |
for (ch = 0; ch < channels; ch++) { |
taba[ch] = 0; |
tabf1[ch] = 100 + uint_rand(rnd) % 5000; |
tabf2[ch] = 100 + uint_rand(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; |
} |
} |
} |
int main(int argc, char **argv){ |
int in_sample_rate, out_sample_rate, ch ,i, flush_count; |
uint64_t in_ch_layout, out_ch_layout; |
enum AVSampleFormat in_sample_fmt, out_sample_fmt; |
uint8_t array_in[SAMPLES*8*8]; |
uint8_t array_mid[SAMPLES*8*8*3]; |
uint8_t array_out[SAMPLES*8*8+100]; |
uint8_t *ain[SWR_CH_MAX]; |
uint8_t *aout[SWR_CH_MAX]; |
uint8_t *amid[SWR_CH_MAX]; |
int flush_i=0; |
int mode; |
int num_tests = 10000; |
uint32_t seed = 0; |
uint32_t rand_seed = 0; |
int remaining_tests[FF_ARRAY_ELEMS(rates) * FF_ARRAY_ELEMS(layouts) * FF_ARRAY_ELEMS(formats) * FF_ARRAY_ELEMS(layouts) * FF_ARRAY_ELEMS(formats)]; |
int max_tests = FF_ARRAY_ELEMS(remaining_tests); |
int test; |
int specific_test= -1; |
struct SwrContext * forw_ctx= NULL; |
struct SwrContext *backw_ctx= NULL; |
if (argc > 1) { |
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { |
av_log(NULL, AV_LOG_INFO, "Usage: swresample-test [<num_tests>[ <test>]] \n" |
"num_tests Default is %d\n", num_tests); |
return 0; |
} |
num_tests = strtol(argv[1], NULL, 0); |
if(num_tests < 0) { |
num_tests = -num_tests; |
rand_seed = time(0); |
} |
if(num_tests<= 0 || num_tests>max_tests) |
num_tests = max_tests; |
if(argc > 2) { |
specific_test = strtol(argv[1], NULL, 0); |
} |
} |
for(i=0; i<max_tests; i++) |
remaining_tests[i] = i; |
for(test=0; test<num_tests; test++){ |
unsigned r; |
uint_rand(seed); |
r = (seed * (uint64_t)(max_tests - test)) >>32; |
FFSWAP(int, remaining_tests[r], remaining_tests[max_tests - test - 1]); |
} |
qsort(remaining_tests + max_tests - num_tests, num_tests, sizeof(remaining_tests[0]), (void*)cmp); |
in_sample_rate=16000; |
for(test=0; test<num_tests; test++){ |
char in_layout_string[256]; |
char out_layout_string[256]; |
unsigned vector= remaining_tests[max_tests - test - 1]; |
int in_ch_count; |
int out_count, mid_count, out_ch_count; |
in_ch_layout = layouts[vector % FF_ARRAY_ELEMS(layouts)]; vector /= FF_ARRAY_ELEMS(layouts); |
out_ch_layout = layouts[vector % FF_ARRAY_ELEMS(layouts)]; vector /= FF_ARRAY_ELEMS(layouts); |
in_sample_fmt = formats[vector % FF_ARRAY_ELEMS(formats)]; vector /= FF_ARRAY_ELEMS(formats); |
out_sample_fmt = formats[vector % FF_ARRAY_ELEMS(formats)]; vector /= FF_ARRAY_ELEMS(formats); |
out_sample_rate = rates [vector % FF_ARRAY_ELEMS(rates )]; vector /= FF_ARRAY_ELEMS(rates); |
av_assert0(!vector); |
if(specific_test == 0){ |
if(out_sample_rate != in_sample_rate || in_ch_layout != out_ch_layout) |
continue; |
} |
in_ch_count= av_get_channel_layout_nb_channels(in_ch_layout); |
out_ch_count= av_get_channel_layout_nb_channels(out_ch_layout); |
av_get_channel_layout_string( in_layout_string, sizeof( in_layout_string), in_ch_count, in_ch_layout); |
av_get_channel_layout_string(out_layout_string, sizeof(out_layout_string), out_ch_count, out_ch_layout); |
fprintf(stderr, "TEST: %s->%s, rate:%5d->%5d, fmt:%s->%s\n", |
in_layout_string, out_layout_string, |
in_sample_rate, out_sample_rate, |
av_get_sample_fmt_name(in_sample_fmt), av_get_sample_fmt_name(out_sample_fmt)); |
forw_ctx = swr_alloc_set_opts(forw_ctx, out_ch_layout, out_sample_fmt, out_sample_rate, |
in_ch_layout, in_sample_fmt, in_sample_rate, |
0, 0); |
backw_ctx = swr_alloc_set_opts(backw_ctx, in_ch_layout, in_sample_fmt, in_sample_rate, |
out_ch_layout, out_sample_fmt, out_sample_rate, |
0, 0); |
if(!forw_ctx) { |
fprintf(stderr, "Failed to init forw_cts\n"); |
return 1; |
} |
if(!backw_ctx) { |
fprintf(stderr, "Failed to init backw_ctx\n"); |
return 1; |
} |
if(swr_init( forw_ctx) < 0) |
fprintf(stderr, "swr_init(->) failed\n"); |
if(swr_init(backw_ctx) < 0) |
fprintf(stderr, "swr_init(<-) failed\n"); |
//FIXME test planar |
setup_array(ain , array_in , in_sample_fmt, SAMPLES); |
setup_array(amid, array_mid, out_sample_fmt, 3*SAMPLES); |
setup_array(aout, array_out, in_sample_fmt , SAMPLES); |
#if 0 |
for(ch=0; ch<in_ch_count; ch++){ |
for(i=0; i<SAMPLES; i++) |
set(ain, ch, i, in_ch_count, in_sample_fmt, sin(i*i*3/SAMPLES)); |
} |
#else |
audiogen(ain, in_sample_fmt, in_ch_count, SAMPLES/6+1, SAMPLES); |
#endif |
mode = uint_rand(rand_seed) % 3; |
if(mode==0 /*|| out_sample_rate == in_sample_rate*/) { |
mid_count= swr_convert(forw_ctx, amid, 3*SAMPLES, (const uint8_t **)ain, SAMPLES); |
} else if(mode==1){ |
mid_count= swr_convert(forw_ctx, amid, 0, (const uint8_t **)ain, SAMPLES); |
mid_count+=swr_convert(forw_ctx, amid, 3*SAMPLES, (const uint8_t **)ain, 0); |
} else { |
int tmp_count; |
mid_count= swr_convert(forw_ctx, amid, 0, (const uint8_t **)ain, 1); |
av_assert0(mid_count==0); |
shift(ain, 1, in_ch_count, in_sample_fmt); |
mid_count+=swr_convert(forw_ctx, amid, 3*SAMPLES, (const uint8_t **)ain, 0); |
shift(amid, mid_count, out_ch_count, out_sample_fmt); tmp_count = mid_count; |
mid_count+=swr_convert(forw_ctx, amid, 2, (const uint8_t **)ain, 2); |
shift(amid, mid_count-tmp_count, out_ch_count, out_sample_fmt); tmp_count = mid_count; |
shift(ain, 2, in_ch_count, in_sample_fmt); |
mid_count+=swr_convert(forw_ctx, amid, 1, (const uint8_t **)ain, SAMPLES-3); |
shift(amid, mid_count-tmp_count, out_ch_count, out_sample_fmt); tmp_count = mid_count; |
shift(ain, -3, in_ch_count, in_sample_fmt); |
mid_count+=swr_convert(forw_ctx, amid, 3*SAMPLES, (const uint8_t **)ain, 0); |
shift(amid, -tmp_count, out_ch_count, out_sample_fmt); |
} |
out_count= swr_convert(backw_ctx,aout, SAMPLES, (const uint8_t **)amid, mid_count); |
for(ch=0; ch<in_ch_count; ch++){ |
double sse, maxdiff=0; |
double sum_a= 0; |
double sum_b= 0; |
double sum_aa= 0; |
double sum_bb= 0; |
double sum_ab= 0; |
for(i=0; i<out_count; i++){ |
double a= get(ain , ch, i, in_ch_count, in_sample_fmt); |
double b= get(aout, ch, i, in_ch_count, in_sample_fmt); |
sum_a += a; |
sum_b += b; |
sum_aa+= a*a; |
sum_bb+= b*b; |
sum_ab+= a*b; |
maxdiff= FFMAX(maxdiff, FFABS(a-b)); |
} |
sse= sum_aa + sum_bb - 2*sum_ab; |
if(sse < 0 && sse > -0.00001) sse=0; //fix rounding error |
fprintf(stderr, "[e:%f c:%f max:%f] len:%5d\n", out_count ? sqrt(sse/out_count) : 0, sum_ab/(sqrt(sum_aa*sum_bb)), maxdiff, out_count); |
} |
flush_i++; |
flush_i%=21; |
flush_count = swr_convert(backw_ctx,aout, flush_i, 0, 0); |
shift(aout, flush_i, in_ch_count, in_sample_fmt); |
flush_count+= swr_convert(backw_ctx,aout, SAMPLES-flush_i, 0, 0); |
shift(aout, -flush_i, in_ch_count, in_sample_fmt); |
if(flush_count){ |
for(ch=0; ch<in_ch_count; ch++){ |
double sse, maxdiff=0; |
double sum_a= 0; |
double sum_b= 0; |
double sum_aa= 0; |
double sum_bb= 0; |
double sum_ab= 0; |
for(i=0; i<flush_count; i++){ |
double a= get(ain , ch, i+out_count, in_ch_count, in_sample_fmt); |
double b= get(aout, ch, i, in_ch_count, in_sample_fmt); |
sum_a += a; |
sum_b += b; |
sum_aa+= a*a; |
sum_bb+= b*b; |
sum_ab+= a*b; |
maxdiff= FFMAX(maxdiff, FFABS(a-b)); |
} |
sse= sum_aa + sum_bb - 2*sum_ab; |
if(sse < 0 && sse > -0.00001) sse=0; //fix rounding error |
fprintf(stderr, "[e:%f c:%f max:%f] len:%5d F:%3d\n", sqrt(sse/flush_count), sum_ab/(sqrt(sum_aa*sum_bb)), maxdiff, flush_count, flush_i); |
} |
} |
fprintf(stderr, "\n"); |
} |
return 0; |
} |
/contrib/sdk/sources/ffmpeg/libswresample/swresample.c |
---|
0,0 → 1,934 |
/* |
* Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at) |
* |
* This file is part of libswresample |
* |
* libswresample 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. |
* |
* libswresample 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 libswresample; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include "libavutil/opt.h" |
#include "swresample_internal.h" |
#include "audioconvert.h" |
#include "libavutil/avassert.h" |
#include "libavutil/channel_layout.h" |
#include <float.h> |
#define C30DB M_SQRT2 |
#define C15DB 1.189207115 |
#define C__0DB 1.0 |
#define C_15DB 0.840896415 |
#define C_30DB M_SQRT1_2 |
#define C_45DB 0.594603558 |
#define C_60DB 0.5 |
#define ALIGN 32 |
//TODO split options array out? |
#define OFFSET(x) offsetof(SwrContext,x) |
#define PARAM AV_OPT_FLAG_AUDIO_PARAM |
static const AVOption options[]={ |
{"ich" , "set input channel count" , OFFSET( in.ch_count ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_CH_MAX, PARAM}, |
{"in_channel_count" , "set input channel count" , OFFSET( in.ch_count ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_CH_MAX, PARAM}, |
{"och" , "set output channel count" , OFFSET(out.ch_count ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_CH_MAX, PARAM}, |
{"out_channel_count" , "set output channel count" , OFFSET(out.ch_count ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_CH_MAX, PARAM}, |
{"uch" , "set used channel count" , OFFSET(used_ch_count ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_CH_MAX, PARAM}, |
{"used_channel_count" , "set used channel count" , OFFSET(used_ch_count ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_CH_MAX, PARAM}, |
{"isr" , "set input sample rate" , OFFSET( in_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM}, |
{"in_sample_rate" , "set input sample rate" , OFFSET( in_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM}, |
{"osr" , "set output sample rate" , OFFSET(out_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM}, |
{"out_sample_rate" , "set output sample rate" , OFFSET(out_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM}, |
{"isf" , "set input sample format" , OFFSET( in_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , AV_SAMPLE_FMT_NB-1, PARAM}, |
{"in_sample_fmt" , "set input sample format" , OFFSET( in_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , AV_SAMPLE_FMT_NB-1, PARAM}, |
{"osf" , "set output sample format" , OFFSET(out_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , AV_SAMPLE_FMT_NB-1, PARAM}, |
{"out_sample_fmt" , "set output sample format" , OFFSET(out_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , AV_SAMPLE_FMT_NB-1, PARAM}, |
{"tsf" , "set internal sample format" , OFFSET(int_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , AV_SAMPLE_FMT_NB-1, PARAM}, |
{"internal_sample_fmt" , "set internal sample format" , OFFSET(int_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , AV_SAMPLE_FMT_NB-1, PARAM}, |
{"icl" , "set input channel layout" , OFFSET( in_ch_layout ), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"}, |
{"in_channel_layout" , "set input channel layout" , OFFSET( in_ch_layout ), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"}, |
{"ocl" , "set output channel layout" , OFFSET(out_ch_layout ), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"}, |
{"out_channel_layout" , "set output channel layout" , OFFSET(out_ch_layout ), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"}, |
{"clev" , "set center mix level" , OFFSET(clev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM}, |
{"center_mix_level" , "set center mix level" , OFFSET(clev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM}, |
{"slev" , "set surround mix level" , OFFSET(slev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM}, |
{"surround_mix_level" , "set surround mix Level" , OFFSET(slev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM}, |
{"lfe_mix_level" , "set LFE mix level" , OFFSET(lfe_mix_level ), AV_OPT_TYPE_FLOAT, {.dbl=0 }, -32 , 32 , PARAM}, |
{"rmvol" , "set rematrix volume" , OFFSET(rematrix_volume), AV_OPT_TYPE_FLOAT, {.dbl=1.0 }, -1000 , 1000 , PARAM}, |
{"rematrix_volume" , "set rematrix volume" , OFFSET(rematrix_volume), AV_OPT_TYPE_FLOAT, {.dbl=1.0 }, -1000 , 1000 , PARAM}, |
{"rematrix_maxval" , "set rematrix maxval" , OFFSET(rematrix_maxval), AV_OPT_TYPE_FLOAT, {.dbl=0.0 }, 0 , 1000 , PARAM}, |
{"flags" , "set flags" , OFFSET(flags ), AV_OPT_TYPE_FLAGS, {.i64=0 }, 0 , UINT_MAX , PARAM, "flags"}, |
{"swr_flags" , "set flags" , OFFSET(flags ), AV_OPT_TYPE_FLAGS, {.i64=0 }, 0 , UINT_MAX , PARAM, "flags"}, |
{"res" , "force resampling" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_FLAG_RESAMPLE }, INT_MIN, INT_MAX , PARAM, "flags"}, |
{"dither_scale" , "set dither scale" , OFFSET(dither.scale ), AV_OPT_TYPE_FLOAT, {.dbl=1 }, 0 , INT_MAX , PARAM}, |
{"dither_method" , "set dither method" , OFFSET(dither.method ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_DITHER_NB-1, PARAM, "dither_method"}, |
{"rectangular" , "select rectangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_RECTANGULAR}, INT_MIN, INT_MAX , PARAM, "dither_method"}, |
{"triangular" , "select triangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR }, INT_MIN, INT_MAX , PARAM, "dither_method"}, |
{"triangular_hp" , "select triangular dither with high pass" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR_HIGHPASS }, INT_MIN, INT_MAX, PARAM, "dither_method"}, |
{"lipshitz" , "select lipshitz noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_LIPSHITZ}, INT_MIN, INT_MAX, PARAM, "dither_method"}, |
{"shibata" , "select shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_SHIBATA }, INT_MIN, INT_MAX, PARAM, "dither_method"}, |
{"low_shibata" , "select low shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_LOW_SHIBATA }, INT_MIN, INT_MAX, PARAM, "dither_method"}, |
{"high_shibata" , "select high shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_HIGH_SHIBATA }, INT_MIN, INT_MAX, PARAM, "dither_method"}, |
{"f_weighted" , "select f-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_F_WEIGHTED }, INT_MIN, INT_MAX, PARAM, "dither_method"}, |
{"modified_e_weighted" , "select modified-e-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_MODIFIED_E_WEIGHTED }, INT_MIN, INT_MAX, PARAM, "dither_method"}, |
{"improved_e_weighted" , "select improved-e-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_IMPROVED_E_WEIGHTED }, INT_MIN, INT_MAX, PARAM, "dither_method"}, |
{"filter_size" , "set swr resampling filter size", OFFSET(filter_size) , AV_OPT_TYPE_INT , {.i64=32 }, 0 , INT_MAX , PARAM }, |
{"phase_shift" , "set swr resampling phase shift", OFFSET(phase_shift) , AV_OPT_TYPE_INT , {.i64=10 }, 0 , 24 , PARAM }, |
{"linear_interp" , "enable linear interpolation" , OFFSET(linear_interp) , AV_OPT_TYPE_INT , {.i64=0 }, 0 , 1 , PARAM }, |
{"cutoff" , "set cutoff frequency ratio" , OFFSET(cutoff) , AV_OPT_TYPE_DOUBLE,{.dbl=0. }, 0 , 1 , PARAM }, |
/* duplicate option in order to work with avconv */ |
{"resample_cutoff" , "set cutoff frequency ratio" , OFFSET(cutoff) , AV_OPT_TYPE_DOUBLE,{.dbl=0. }, 0 , 1 , PARAM }, |
{"resampler" , "set resampling Engine" , OFFSET(engine) , AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_ENGINE_NB-1, PARAM, "resampler"}, |
{"swr" , "select SW Resampler" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_ENGINE_SWR }, INT_MIN, INT_MAX , PARAM, "resampler"}, |
{"soxr" , "select SoX Resampler" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_ENGINE_SOXR }, INT_MIN, INT_MAX , PARAM, "resampler"}, |
{"precision" , "set soxr resampling precision (in bits)" |
, OFFSET(precision) , AV_OPT_TYPE_DOUBLE,{.dbl=20.0 }, 15.0 , 33.0 , PARAM }, |
{"cheby" , "enable soxr Chebyshev passband & higher-precision irrational ratio approximation" |
, OFFSET(cheby) , AV_OPT_TYPE_INT , {.i64=0 }, 0 , 1 , PARAM }, |
{"min_comp" , "set minimum difference between timestamps and audio data (in seconds) below which no timestamp compensation of either kind is applied" |
, OFFSET(min_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=FLT_MAX }, 0 , FLT_MAX , PARAM }, |
{"min_hard_comp" , "set minimum difference between timestamps and audio data (in seconds) to trigger padding/trimming the data." |
, OFFSET(min_hard_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=0.1 }, 0 , INT_MAX , PARAM }, |
{"comp_duration" , "set duration (in seconds) over which data is stretched/squeezed to make it match the timestamps." |
, OFFSET(soft_compensation_duration),AV_OPT_TYPE_FLOAT ,{.dbl=1 }, 0 , INT_MAX , PARAM }, |
{"max_soft_comp" , "set maximum factor by which data is stretched/squeezed to make it match the timestamps." |
, OFFSET(max_soft_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=0 }, INT_MIN, INT_MAX , PARAM }, |
{"async" , "simplified 1 parameter audio timestamp matching, 0(disabled), 1(filling and trimming), >1(maximum stretch/squeeze in samples per second)" |
, OFFSET(async) , AV_OPT_TYPE_FLOAT ,{.dbl=0 }, INT_MIN, INT_MAX , PARAM }, |
{"first_pts" , "Assume the first pts should be this value (in samples)." |
, OFFSET(firstpts_in_samples), AV_OPT_TYPE_INT64 ,{.i64=AV_NOPTS_VALUE }, INT64_MIN,INT64_MAX, PARAM }, |
{ "matrix_encoding" , "set 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", "select none", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_NONE }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, |
{ "dolby", "select Dolby", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DOLBY }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, |
{ "dplii", "select Dolby Pro Logic II", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DPLII }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, |
{ "filter_type" , "select swr filter type" , OFFSET(filter_type) , AV_OPT_TYPE_INT , { .i64 = SWR_FILTER_TYPE_KAISER }, SWR_FILTER_TYPE_CUBIC, SWR_FILTER_TYPE_KAISER, PARAM, "filter_type" }, |
{ "cubic" , "select cubic" , 0 , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_CUBIC }, INT_MIN, INT_MAX, PARAM, "filter_type" }, |
{ "blackman_nuttall", "select Blackman Nuttall Windowed Sinc", 0 , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_BLACKMAN_NUTTALL }, INT_MIN, INT_MAX, PARAM, "filter_type" }, |
{ "kaiser" , "select Kaiser Windowed Sinc" , 0 , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_KAISER }, INT_MIN, INT_MAX, PARAM, "filter_type" }, |
{ "kaiser_beta" , "set swr Kaiser Window Beta" , OFFSET(kaiser_beta) , AV_OPT_TYPE_INT , {.i64=9 }, 2 , 16 , PARAM }, |
{ "output_sample_bits" , "set swr number of output sample bits", OFFSET(dither.output_sample_bits), AV_OPT_TYPE_INT , {.i64=0 }, 0 , 64 , PARAM }, |
{0} |
}; |
static const char* context_to_name(void* ptr) { |
return "SWR"; |
} |
static const AVClass av_class = { |
.class_name = "SWResampler", |
.item_name = context_to_name, |
.option = options, |
.version = LIBAVUTIL_VERSION_INT, |
.log_level_offset_offset = OFFSET(log_level_offset), |
.parent_log_context_offset = OFFSET(log_ctx), |
.category = AV_CLASS_CATEGORY_SWRESAMPLER, |
}; |
unsigned swresample_version(void) |
{ |
av_assert0(LIBSWRESAMPLE_VERSION_MICRO >= 100); |
return LIBSWRESAMPLE_VERSION_INT; |
} |
const char *swresample_configuration(void) |
{ |
return FFMPEG_CONFIGURATION; |
} |
const char *swresample_license(void) |
{ |
#define LICENSE_PREFIX "libswresample license: " |
return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; |
} |
int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map){ |
if(!s || s->in_convert) // s needs to be allocated but not initialized |
return AVERROR(EINVAL); |
s->channel_map = channel_map; |
return 0; |
} |
const AVClass *swr_get_class(void) |
{ |
return &av_class; |
} |
av_cold struct SwrContext *swr_alloc(void){ |
SwrContext *s= av_mallocz(sizeof(SwrContext)); |
if(s){ |
s->av_class= &av_class; |
av_opt_set_defaults(s); |
} |
return s; |
} |
struct SwrContext *swr_alloc_set_opts(struct SwrContext *s, |
int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, |
int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, |
int log_offset, void *log_ctx){ |
if(!s) s= swr_alloc(); |
if(!s) return NULL; |
s->log_level_offset= log_offset; |
s->log_ctx= log_ctx; |
av_opt_set_int(s, "ocl", out_ch_layout, 0); |
av_opt_set_int(s, "osf", out_sample_fmt, 0); |
av_opt_set_int(s, "osr", out_sample_rate, 0); |
av_opt_set_int(s, "icl", in_ch_layout, 0); |
av_opt_set_int(s, "isf", in_sample_fmt, 0); |
av_opt_set_int(s, "isr", in_sample_rate, 0); |
av_opt_set_int(s, "tsf", AV_SAMPLE_FMT_NONE, 0); |
av_opt_set_int(s, "ich", av_get_channel_layout_nb_channels(s-> in_ch_layout), 0); |
av_opt_set_int(s, "och", av_get_channel_layout_nb_channels(s->out_ch_layout), 0); |
av_opt_set_int(s, "uch", 0, 0); |
return s; |
} |
static void set_audiodata_fmt(AudioData *a, enum AVSampleFormat fmt){ |
a->fmt = fmt; |
a->bps = av_get_bytes_per_sample(fmt); |
a->planar= av_sample_fmt_is_planar(fmt); |
} |
static void free_temp(AudioData *a){ |
av_free(a->data); |
memset(a, 0, sizeof(*a)); |
} |
av_cold void swr_free(SwrContext **ss){ |
SwrContext *s= *ss; |
if(s){ |
free_temp(&s->postin); |
free_temp(&s->midbuf); |
free_temp(&s->preout); |
free_temp(&s->in_buffer); |
free_temp(&s->silence); |
free_temp(&s->drop_temp); |
free_temp(&s->dither.noise); |
free_temp(&s->dither.temp); |
swri_audio_convert_free(&s-> in_convert); |
swri_audio_convert_free(&s->out_convert); |
swri_audio_convert_free(&s->full_convert); |
if (s->resampler) |
s->resampler->free(&s->resample); |
swri_rematrix_free(s); |
} |
av_freep(ss); |
} |
av_cold int swr_init(struct SwrContext *s){ |
int ret; |
s->in_buffer_index= 0; |
s->in_buffer_count= 0; |
s->resample_in_constraint= 0; |
free_temp(&s->postin); |
free_temp(&s->midbuf); |
free_temp(&s->preout); |
free_temp(&s->in_buffer); |
free_temp(&s->silence); |
free_temp(&s->drop_temp); |
free_temp(&s->dither.noise); |
free_temp(&s->dither.temp); |
memset(s->in.ch, 0, sizeof(s->in.ch)); |
memset(s->out.ch, 0, sizeof(s->out.ch)); |
swri_audio_convert_free(&s-> in_convert); |
swri_audio_convert_free(&s->out_convert); |
swri_audio_convert_free(&s->full_convert); |
swri_rematrix_free(s); |
s->flushed = 0; |
if(s-> in_sample_fmt >= AV_SAMPLE_FMT_NB){ |
av_log(s, AV_LOG_ERROR, "Requested input sample format %d is invalid\n", s->in_sample_fmt); |
return AVERROR(EINVAL); |
} |
if(s->out_sample_fmt >= AV_SAMPLE_FMT_NB){ |
av_log(s, AV_LOG_ERROR, "Requested output sample format %d is invalid\n", s->out_sample_fmt); |
return AVERROR(EINVAL); |
} |
if(av_get_channel_layout_nb_channels(s-> in_ch_layout) > SWR_CH_MAX) { |
av_log(s, AV_LOG_WARNING, "Input channel layout 0x%"PRIx64" is invalid or unsupported.\n", s-> in_ch_layout); |
s->in_ch_layout = 0; |
} |
if(av_get_channel_layout_nb_channels(s->out_ch_layout) > SWR_CH_MAX) { |
av_log(s, AV_LOG_WARNING, "Output channel layout 0x%"PRIx64" is invalid or unsupported.\n", s->out_ch_layout); |
s->out_ch_layout = 0; |
} |
switch(s->engine){ |
#if CONFIG_LIBSOXR |
extern struct Resampler const soxr_resampler; |
case SWR_ENGINE_SOXR: s->resampler = &soxr_resampler; break; |
#endif |
case SWR_ENGINE_SWR : s->resampler = &swri_resampler; break; |
default: |
av_log(s, AV_LOG_ERROR, "Requested resampling engine is unavailable\n"); |
return AVERROR(EINVAL); |
} |
if(!s->used_ch_count) |
s->used_ch_count= s->in.ch_count; |
if(s->used_ch_count && s-> in_ch_layout && s->used_ch_count != av_get_channel_layout_nb_channels(s-> in_ch_layout)){ |
av_log(s, AV_LOG_WARNING, "Input channel layout has a different number of channels than the number of used channels, ignoring layout\n"); |
s-> in_ch_layout= 0; |
} |
if(!s-> in_ch_layout) |
s-> in_ch_layout= av_get_default_channel_layout(s->used_ch_count); |
if(!s->out_ch_layout) |
s->out_ch_layout= av_get_default_channel_layout(s->out.ch_count); |
s->rematrix= s->out_ch_layout !=s->in_ch_layout || s->rematrix_volume!=1.0 || |
s->rematrix_custom; |
if(s->int_sample_fmt == AV_SAMPLE_FMT_NONE){ |
if(av_get_planar_sample_fmt(s->in_sample_fmt) <= AV_SAMPLE_FMT_S16P){ |
s->int_sample_fmt= AV_SAMPLE_FMT_S16P; |
}else if( av_get_planar_sample_fmt(s-> in_sample_fmt) == AV_SAMPLE_FMT_S32P |
&& av_get_planar_sample_fmt(s->out_sample_fmt) == AV_SAMPLE_FMT_S32P |
&& !s->rematrix |
&& s->engine != SWR_ENGINE_SOXR){ |
s->int_sample_fmt= AV_SAMPLE_FMT_S32P; |
}else if(av_get_planar_sample_fmt(s->in_sample_fmt) <= AV_SAMPLE_FMT_FLTP){ |
s->int_sample_fmt= AV_SAMPLE_FMT_FLTP; |
}else{ |
av_log(s, AV_LOG_DEBUG, "Using double precision mode\n"); |
s->int_sample_fmt= AV_SAMPLE_FMT_DBLP; |
} |
} |
if( s->int_sample_fmt != AV_SAMPLE_FMT_S16P |
&&s->int_sample_fmt != AV_SAMPLE_FMT_S32P |
&&s->int_sample_fmt != AV_SAMPLE_FMT_FLTP |
&&s->int_sample_fmt != AV_SAMPLE_FMT_DBLP){ |
av_log(s, AV_LOG_ERROR, "Requested sample format %s is not supported internally, S16/S32/FLT/DBL is supported\n", av_get_sample_fmt_name(s->int_sample_fmt)); |
return AVERROR(EINVAL); |
} |
set_audiodata_fmt(&s-> in, s-> in_sample_fmt); |
set_audiodata_fmt(&s->out, s->out_sample_fmt); |
if (s->firstpts_in_samples != AV_NOPTS_VALUE) { |
if (!s->async && s->min_compensation >= FLT_MAX/2) |
s->async = 1; |
s->firstpts = |
s->outpts = s->firstpts_in_samples * s->out_sample_rate; |
} else |
s->firstpts = AV_NOPTS_VALUE; |
if (s->async) { |
if (s->min_compensation >= FLT_MAX/2) |
s->min_compensation = 0.001; |
if (s->async > 1.0001) { |
s->max_soft_compensation = s->async / (double) s->in_sample_rate; |
} |
} |
if (s->out_sample_rate!=s->in_sample_rate || (s->flags & SWR_FLAG_RESAMPLE)){ |
s->resample = s->resampler->init(s->resample, s->out_sample_rate, s->in_sample_rate, s->filter_size, s->phase_shift, s->linear_interp, s->cutoff, s->int_sample_fmt, s->filter_type, s->kaiser_beta, s->precision, s->cheby); |
}else |
s->resampler->free(&s->resample); |
if( s->int_sample_fmt != AV_SAMPLE_FMT_S16P |
&& s->int_sample_fmt != AV_SAMPLE_FMT_S32P |
&& s->int_sample_fmt != AV_SAMPLE_FMT_FLTP |
&& s->int_sample_fmt != AV_SAMPLE_FMT_DBLP |
&& s->resample){ |
av_log(s, AV_LOG_ERROR, "Resampling only supported with internal s16/s32/flt/dbl\n"); |
return -1; |
} |
#define RSC 1 //FIXME finetune |
if(!s-> in.ch_count) |
s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout); |
if(!s->used_ch_count) |
s->used_ch_count= s->in.ch_count; |
if(!s->out.ch_count) |
s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout); |
if(!s-> in.ch_count){ |
av_assert0(!s->in_ch_layout); |
av_log(s, AV_LOG_ERROR, "Input channel count and layout are unset\n"); |
return -1; |
} |
if ((!s->out_ch_layout || !s->in_ch_layout) && s->used_ch_count != s->out.ch_count && !s->rematrix_custom) { |
char l1[1024], l2[1024]; |
av_get_channel_layout_string(l1, sizeof(l1), s-> in.ch_count, s-> in_ch_layout); |
av_get_channel_layout_string(l2, sizeof(l2), s->out.ch_count, s->out_ch_layout); |
av_log(s, AV_LOG_ERROR, "Rematrix is needed between %s and %s " |
"but there is not enough information to do it\n", l1, l2); |
return -1; |
} |
av_assert0(s->used_ch_count); |
av_assert0(s->out.ch_count); |
s->resample_first= RSC*s->out.ch_count/s->in.ch_count - RSC < s->out_sample_rate/(float)s-> in_sample_rate - 1.0; |
s->in_buffer= s->in; |
s->silence = s->in; |
s->drop_temp= s->out; |
if(!s->resample && !s->rematrix && !s->channel_map && !s->dither.method){ |
s->full_convert = swri_audio_convert_alloc(s->out_sample_fmt, |
s-> in_sample_fmt, s-> in.ch_count, NULL, 0); |
return 0; |
} |
s->in_convert = swri_audio_convert_alloc(s->int_sample_fmt, |
s-> in_sample_fmt, s->used_ch_count, s->channel_map, 0); |
s->out_convert= swri_audio_convert_alloc(s->out_sample_fmt, |
s->int_sample_fmt, s->out.ch_count, NULL, 0); |
if (!s->in_convert || !s->out_convert) |
return AVERROR(ENOMEM); |
s->postin= s->in; |
s->preout= s->out; |
s->midbuf= s->in; |
if(s->channel_map){ |
s->postin.ch_count= |
s->midbuf.ch_count= s->used_ch_count; |
if(s->resample) |
s->in_buffer.ch_count= s->used_ch_count; |
} |
if(!s->resample_first){ |
s->midbuf.ch_count= s->out.ch_count; |
if(s->resample) |
s->in_buffer.ch_count = s->out.ch_count; |
} |
set_audiodata_fmt(&s->postin, s->int_sample_fmt); |
set_audiodata_fmt(&s->midbuf, s->int_sample_fmt); |
set_audiodata_fmt(&s->preout, s->int_sample_fmt); |
if(s->resample){ |
set_audiodata_fmt(&s->in_buffer, s->int_sample_fmt); |
} |
if ((ret = swri_dither_init(s, s->out_sample_fmt, s->int_sample_fmt)) < 0) |
return ret; |
if(s->rematrix || s->dither.method) |
return swri_rematrix_init(s); |
return 0; |
} |
int swri_realloc_audio(AudioData *a, int count){ |
int i, countb; |
AudioData old; |
if(count < 0 || count > INT_MAX/2/a->bps/a->ch_count) |
return AVERROR(EINVAL); |
if(a->count >= count) |
return 0; |
count*=2; |
countb= FFALIGN(count*a->bps, ALIGN); |
old= *a; |
av_assert0(a->bps); |
av_assert0(a->ch_count); |
a->data= av_mallocz(countb*a->ch_count); |
if(!a->data) |
return AVERROR(ENOMEM); |
for(i=0; i<a->ch_count; i++){ |
a->ch[i]= a->data + i*(a->planar ? countb : a->bps); |
if(a->planar) memcpy(a->ch[i], old.ch[i], a->count*a->bps); |
} |
if(!a->planar) memcpy(a->ch[0], old.ch[0], a->count*a->ch_count*a->bps); |
av_freep(&old.data); |
a->count= count; |
return 1; |
} |
static void copy(AudioData *out, AudioData *in, |
int count){ |
av_assert0(out->planar == in->planar); |
av_assert0(out->bps == in->bps); |
av_assert0(out->ch_count == in->ch_count); |
if(out->planar){ |
int ch; |
for(ch=0; ch<out->ch_count; ch++) |
memcpy(out->ch[ch], in->ch[ch], count*out->bps); |
}else |
memcpy(out->ch[0], in->ch[0], count*out->ch_count*out->bps); |
} |
static void fill_audiodata(AudioData *out, uint8_t *in_arg [SWR_CH_MAX]){ |
int i; |
if(!in_arg){ |
memset(out->ch, 0, sizeof(out->ch)); |
}else if(out->planar){ |
for(i=0; i<out->ch_count; i++) |
out->ch[i]= in_arg[i]; |
}else{ |
for(i=0; i<out->ch_count; i++) |
out->ch[i]= in_arg[0] + i*out->bps; |
} |
} |
static void reversefill_audiodata(AudioData *out, uint8_t *in_arg [SWR_CH_MAX]){ |
int i; |
if(out->planar){ |
for(i=0; i<out->ch_count; i++) |
in_arg[i]= out->ch[i]; |
}else{ |
in_arg[0]= out->ch[0]; |
} |
} |
/** |
* |
* out may be equal in. |
*/ |
static void buf_set(AudioData *out, AudioData *in, int count){ |
int ch; |
if(in->planar){ |
for(ch=0; ch<out->ch_count; ch++) |
out->ch[ch]= in->ch[ch] + count*out->bps; |
}else{ |
for(ch=out->ch_count-1; ch>=0; ch--) |
out->ch[ch]= in->ch[0] + (ch + count*out->ch_count) * out->bps; |
} |
} |
/** |
* |
* @return number of samples output per channel |
*/ |
static int resample(SwrContext *s, AudioData *out_param, int out_count, |
const AudioData * in_param, int in_count){ |
AudioData in, out, tmp; |
int ret_sum=0; |
int border=0; |
av_assert1(s->in_buffer.ch_count == in_param->ch_count); |
av_assert1(s->in_buffer.planar == in_param->planar); |
av_assert1(s->in_buffer.fmt == in_param->fmt); |
tmp=out=*out_param; |
in = *in_param; |
do{ |
int ret, size, consumed; |
if(!s->resample_in_constraint && s->in_buffer_count){ |
buf_set(&tmp, &s->in_buffer, s->in_buffer_index); |
ret= s->resampler->multiple_resample(s->resample, &out, out_count, &tmp, s->in_buffer_count, &consumed); |
out_count -= ret; |
ret_sum += ret; |
buf_set(&out, &out, ret); |
s->in_buffer_count -= consumed; |
s->in_buffer_index += consumed; |
if(!in_count) |
break; |
if(s->in_buffer_count <= border){ |
buf_set(&in, &in, -s->in_buffer_count); |
in_count += s->in_buffer_count; |
s->in_buffer_count=0; |
s->in_buffer_index=0; |
border = 0; |
} |
} |
if((s->flushed || in_count) && !s->in_buffer_count){ |
s->in_buffer_index=0; |
ret= s->resampler->multiple_resample(s->resample, &out, out_count, &in, in_count, &consumed); |
out_count -= ret; |
ret_sum += ret; |
buf_set(&out, &out, ret); |
in_count -= consumed; |
buf_set(&in, &in, consumed); |
} |
//TODO is this check sane considering the advanced copy avoidance below |
size= s->in_buffer_index + s->in_buffer_count + in_count; |
if( size > s->in_buffer.count |
&& s->in_buffer_count + in_count <= s->in_buffer_index){ |
buf_set(&tmp, &s->in_buffer, s->in_buffer_index); |
copy(&s->in_buffer, &tmp, s->in_buffer_count); |
s->in_buffer_index=0; |
}else |
if((ret=swri_realloc_audio(&s->in_buffer, size)) < 0) |
return ret; |
if(in_count){ |
int count= in_count; |
if(s->in_buffer_count && s->in_buffer_count+2 < count && out_count) count= s->in_buffer_count+2; |
buf_set(&tmp, &s->in_buffer, s->in_buffer_index + s->in_buffer_count); |
copy(&tmp, &in, /*in_*/count); |
s->in_buffer_count += count; |
in_count -= count; |
border += count; |
buf_set(&in, &in, count); |
s->resample_in_constraint= 0; |
if(s->in_buffer_count != count || in_count) |
continue; |
} |
break; |
}while(1); |
s->resample_in_constraint= !!out_count; |
return ret_sum; |
} |
static int swr_convert_internal(struct SwrContext *s, AudioData *out, int out_count, |
AudioData *in , int in_count){ |
AudioData *postin, *midbuf, *preout; |
int ret/*, in_max*/; |
AudioData preout_tmp, midbuf_tmp; |
if(s->full_convert){ |
av_assert0(!s->resample); |
swri_audio_convert(s->full_convert, out, in, in_count); |
return out_count; |
} |
// in_max= out_count*(int64_t)s->in_sample_rate / s->out_sample_rate + resample_filter_taps; |
// in_count= FFMIN(in_count, in_in + 2 - s->hist_buffer_count); |
if((ret=swri_realloc_audio(&s->postin, in_count))<0) |
return ret; |
if(s->resample_first){ |
av_assert0(s->midbuf.ch_count == s->used_ch_count); |
if((ret=swri_realloc_audio(&s->midbuf, out_count))<0) |
return ret; |
}else{ |
av_assert0(s->midbuf.ch_count == s->out.ch_count); |
if((ret=swri_realloc_audio(&s->midbuf, in_count))<0) |
return ret; |
} |
if((ret=swri_realloc_audio(&s->preout, out_count))<0) |
return ret; |
postin= &s->postin; |
midbuf_tmp= s->midbuf; |
midbuf= &midbuf_tmp; |
preout_tmp= s->preout; |
preout= &preout_tmp; |
if(s->int_sample_fmt == s-> in_sample_fmt && s->in.planar && !s->channel_map) |
postin= in; |
if(s->resample_first ? !s->resample : !s->rematrix) |
midbuf= postin; |
if(s->resample_first ? !s->rematrix : !s->resample) |
preout= midbuf; |
if(s->int_sample_fmt == s->out_sample_fmt && s->out.planar |
&& !(s->out_sample_fmt==AV_SAMPLE_FMT_S32P && (s->dither.output_sample_bits&31))){ |
if(preout==in){ |
out_count= FFMIN(out_count, in_count); //TODO check at the end if this is needed or redundant |
av_assert0(s->in.planar); //we only support planar internally so it has to be, we support copying non planar though |
copy(out, in, out_count); |
return out_count; |
} |
else if(preout==postin) preout= midbuf= postin= out; |
else if(preout==midbuf) preout= midbuf= out; |
else preout= out; |
} |
if(in != postin){ |
swri_audio_convert(s->in_convert, postin, in, in_count); |
} |
if(s->resample_first){ |
if(postin != midbuf) |
out_count= resample(s, midbuf, out_count, postin, in_count); |
if(midbuf != preout) |
swri_rematrix(s, preout, midbuf, out_count, preout==out); |
}else{ |
if(postin != midbuf) |
swri_rematrix(s, midbuf, postin, in_count, midbuf==out); |
if(midbuf != preout) |
out_count= resample(s, preout, out_count, midbuf, in_count); |
} |
if(preout != out && out_count){ |
AudioData *conv_src = preout; |
if(s->dither.method){ |
int ch; |
int dither_count= FFMAX(out_count, 1<<16); |
if (preout == in) { |
conv_src = &s->dither.temp; |
if((ret=swri_realloc_audio(&s->dither.temp, dither_count))<0) |
return ret; |
} |
if((ret=swri_realloc_audio(&s->dither.noise, dither_count))<0) |
return ret; |
if(ret) |
for(ch=0; ch<s->dither.noise.ch_count; ch++) |
swri_get_dither(s, s->dither.noise.ch[ch], s->dither.noise.count, 12345678913579<<ch, s->dither.noise.fmt); |
av_assert0(s->dither.noise.ch_count == preout->ch_count); |
if(s->dither.noise_pos + out_count > s->dither.noise.count) |
s->dither.noise_pos = 0; |
if (s->dither.method < SWR_DITHER_NS){ |
if (s->mix_2_1_simd) { |
int len1= out_count&~15; |
int off = len1 * preout->bps; |
if(len1) |
for(ch=0; ch<preout->ch_count; ch++) |
s->mix_2_1_simd(conv_src->ch[ch], preout->ch[ch], s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos, s->native_simd_one, 0, 0, len1); |
if(out_count != len1) |
for(ch=0; ch<preout->ch_count; ch++) |
s->mix_2_1_f(conv_src->ch[ch] + off, preout->ch[ch] + off, s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos + off + len1, s->native_one, 0, 0, out_count - len1); |
} else { |
for(ch=0; ch<preout->ch_count; ch++) |
s->mix_2_1_f(conv_src->ch[ch], preout->ch[ch], s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos, s->native_one, 0, 0, out_count); |
} |
} else { |
switch(s->int_sample_fmt) { |
case AV_SAMPLE_FMT_S16P :swri_noise_shaping_int16(s, conv_src, preout, &s->dither.noise, out_count); break; |
case AV_SAMPLE_FMT_S32P :swri_noise_shaping_int32(s, conv_src, preout, &s->dither.noise, out_count); break; |
case AV_SAMPLE_FMT_FLTP :swri_noise_shaping_float(s, conv_src, preout, &s->dither.noise, out_count); break; |
case AV_SAMPLE_FMT_DBLP :swri_noise_shaping_double(s,conv_src, preout, &s->dither.noise, out_count); break; |
} |
} |
s->dither.noise_pos += out_count; |
} |
//FIXME packed doesn't need more than 1 chan here! |
swri_audio_convert(s->out_convert, out, conv_src, out_count); |
} |
return out_count; |
} |
int swr_convert(struct SwrContext *s, uint8_t *out_arg[SWR_CH_MAX], int out_count, |
const uint8_t *in_arg [SWR_CH_MAX], int in_count){ |
AudioData * in= &s->in; |
AudioData *out= &s->out; |
while(s->drop_output > 0){ |
int ret; |
uint8_t *tmp_arg[SWR_CH_MAX]; |
#define MAX_DROP_STEP 16384 |
if((ret=swri_realloc_audio(&s->drop_temp, FFMIN(s->drop_output, MAX_DROP_STEP)))<0) |
return ret; |
reversefill_audiodata(&s->drop_temp, tmp_arg); |
s->drop_output *= -1; //FIXME find a less hackish solution |
ret = swr_convert(s, tmp_arg, FFMIN(-s->drop_output, MAX_DROP_STEP), in_arg, in_count); //FIXME optimize but this is as good as never called so maybe it doesn't matter |
s->drop_output *= -1; |
in_count = 0; |
if(ret>0) { |
s->drop_output -= ret; |
continue; |
} |
if(s->drop_output || !out_arg) |
return 0; |
} |
if(!in_arg){ |
if(s->resample){ |
if (!s->flushed) |
s->resampler->flush(s); |
s->resample_in_constraint = 0; |
s->flushed = 1; |
}else if(!s->in_buffer_count){ |
return 0; |
} |
}else |
fill_audiodata(in , (void*)in_arg); |
fill_audiodata(out, out_arg); |
if(s->resample){ |
int ret = swr_convert_internal(s, out, out_count, in, in_count); |
if(ret>0 && !s->drop_output) |
s->outpts += ret * (int64_t)s->in_sample_rate; |
return ret; |
}else{ |
AudioData tmp= *in; |
int ret2=0; |
int ret, size; |
size = FFMIN(out_count, s->in_buffer_count); |
if(size){ |
buf_set(&tmp, &s->in_buffer, s->in_buffer_index); |
ret= swr_convert_internal(s, out, size, &tmp, size); |
if(ret<0) |
return ret; |
ret2= ret; |
s->in_buffer_count -= ret; |
s->in_buffer_index += ret; |
buf_set(out, out, ret); |
out_count -= ret; |
if(!s->in_buffer_count) |
s->in_buffer_index = 0; |
} |
if(in_count){ |
size= s->in_buffer_index + s->in_buffer_count + in_count - out_count; |
if(in_count > out_count) { //FIXME move after swr_convert_internal |
if( size > s->in_buffer.count |
&& s->in_buffer_count + in_count - out_count <= s->in_buffer_index){ |
buf_set(&tmp, &s->in_buffer, s->in_buffer_index); |
copy(&s->in_buffer, &tmp, s->in_buffer_count); |
s->in_buffer_index=0; |
}else |
if((ret=swri_realloc_audio(&s->in_buffer, size)) < 0) |
return ret; |
} |
if(out_count){ |
size = FFMIN(in_count, out_count); |
ret= swr_convert_internal(s, out, size, in, size); |
if(ret<0) |
return ret; |
buf_set(in, in, ret); |
in_count -= ret; |
ret2 += ret; |
} |
if(in_count){ |
buf_set(&tmp, &s->in_buffer, s->in_buffer_index + s->in_buffer_count); |
copy(&tmp, in, in_count); |
s->in_buffer_count += in_count; |
} |
} |
if(ret2>0 && !s->drop_output) |
s->outpts += ret2 * (int64_t)s->in_sample_rate; |
return ret2; |
} |
} |
int swr_drop_output(struct SwrContext *s, int count){ |
s->drop_output += count; |
if(s->drop_output <= 0) |
return 0; |
av_log(s, AV_LOG_VERBOSE, "discarding %d audio samples\n", count); |
return swr_convert(s, NULL, s->drop_output, NULL, 0); |
} |
int swr_inject_silence(struct SwrContext *s, int count){ |
int ret, i; |
uint8_t *tmp_arg[SWR_CH_MAX]; |
if(count <= 0) |
return 0; |
#define MAX_SILENCE_STEP 16384 |
while (count > MAX_SILENCE_STEP) { |
if ((ret = swr_inject_silence(s, MAX_SILENCE_STEP)) < 0) |
return ret; |
count -= MAX_SILENCE_STEP; |
} |
if((ret=swri_realloc_audio(&s->silence, count))<0) |
return ret; |
if(s->silence.planar) for(i=0; i<s->silence.ch_count; i++) { |
memset(s->silence.ch[i], s->silence.bps==1 ? 0x80 : 0, count*s->silence.bps); |
} else |
memset(s->silence.ch[0], s->silence.bps==1 ? 0x80 : 0, count*s->silence.bps*s->silence.ch_count); |
reversefill_audiodata(&s->silence, tmp_arg); |
av_log(s, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", count); |
ret = swr_convert(s, NULL, 0, (const uint8_t**)tmp_arg, count); |
return ret; |
} |
int64_t swr_get_delay(struct SwrContext *s, int64_t base){ |
if (s->resampler && s->resample){ |
return s->resampler->get_delay(s, base); |
}else{ |
return (s->in_buffer_count*base + (s->in_sample_rate>>1))/ s->in_sample_rate; |
} |
} |
int swr_set_compensation(struct SwrContext *s, int sample_delta, int compensation_distance){ |
int ret; |
if (!s || compensation_distance < 0) |
return AVERROR(EINVAL); |
if (!compensation_distance && sample_delta) |
return AVERROR(EINVAL); |
if (!s->resample) { |
s->flags |= SWR_FLAG_RESAMPLE; |
ret = swr_init(s); |
if (ret < 0) |
return ret; |
} |
if (!s->resampler->set_compensation){ |
return AVERROR(EINVAL); |
}else{ |
return s->resampler->set_compensation(s->resample, sample_delta, compensation_distance); |
} |
} |
int64_t swr_next_pts(struct SwrContext *s, int64_t pts){ |
if(pts == INT64_MIN) |
return s->outpts; |
if (s->firstpts == AV_NOPTS_VALUE) |
s->outpts = s->firstpts = pts; |
if(s->min_compensation >= FLT_MAX) { |
return (s->outpts = pts - swr_get_delay(s, s->in_sample_rate * (int64_t)s->out_sample_rate)); |
} else { |
int64_t delta = pts - swr_get_delay(s, s->in_sample_rate * (int64_t)s->out_sample_rate) - s->outpts + s->drop_output*(int64_t)s->in_sample_rate; |
double fdelta = delta /(double)(s->in_sample_rate * (int64_t)s->out_sample_rate); |
if(fabs(fdelta) > s->min_compensation) { |
if(s->outpts == s->firstpts || fabs(fdelta) > s->min_hard_compensation){ |
int ret; |
if(delta > 0) ret = swr_inject_silence(s, delta / s->out_sample_rate); |
else ret = swr_drop_output (s, -delta / s-> in_sample_rate); |
if(ret<0){ |
av_log(s, AV_LOG_ERROR, "Failed to compensate for timestamp delta of %f\n", fdelta); |
} |
} else if(s->soft_compensation_duration && s->max_soft_compensation) { |
int duration = s->out_sample_rate * s->soft_compensation_duration; |
double max_soft_compensation = s->max_soft_compensation / (s->max_soft_compensation < 0 ? -s->in_sample_rate : 1); |
int comp = av_clipf(fdelta, -max_soft_compensation, max_soft_compensation) * duration ; |
av_log(s, AV_LOG_VERBOSE, "compensating audio timestamp drift:%f compensation:%d in:%d\n", fdelta, comp, duration); |
swr_set_compensation(s, comp, duration); |
} |
} |
return s->outpts; |
} |
} |
/contrib/sdk/sources/ffmpeg/libswresample/swresample.h |
---|
0,0 → 1,311 |
/* |
* Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at) |
* |
* This file is part of libswresample |
* |
* libswresample 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. |
* |
* libswresample 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 libswresample; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#ifndef SWRESAMPLE_SWRESAMPLE_H |
#define SWRESAMPLE_SWRESAMPLE_H |
/** |
* @file |
* @ingroup lswr |
* libswresample public header |
*/ |
/** |
* @defgroup lswr Libswresample |
* @{ |
* |
* Libswresample (lswr) is a library that handles audio resampling, sample |
* format conversion and mixing. |
* |
* Interaction with lswr is done through SwrContext, which is |
* allocated with swr_alloc() or swr_alloc_set_opts(). 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 |
* SwrContext *swr = swr_alloc(); |
* av_opt_set_channel_layout(swr, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0); |
* av_opt_set_channel_layout(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); |
* av_opt_set_int(swr, "in_sample_rate", 48000, 0); |
* av_opt_set_int(swr, "out_sample_rate", 44100, 0); |
* av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); |
* av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); |
* @endcode |
* |
* Once all values have been set, it must be initialized with swr_init(). If |
* you need to change the conversion parameters, you can change the parameters |
* as described above, or by using swr_alloc_set_opts(), then call swr_init() |
* again. |
* |
* The conversion itself is done by repeatedly calling swr_convert(). |
* Note that the samples may get buffered in swr if you provide insufficient |
* output space or if sample rate conversion is done, which requires "future" |
* samples. Samples that do not require future input can be retrieved at any |
* time by using swr_convert() (in_count can be set to 0). |
* At the end of conversion the resampling buffer can be flushed by calling |
* swr_convert() with NULL in and 0 in_count. |
* |
* The delay between input and output, can at any time be found by using |
* swr_get_delay(). |
* |
* 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_samples; |
* |
* while (get_input(&input, &in_samples)) { |
* uint8_t *output; |
* int out_samples = av_rescale_rnd(swr_get_delay(swr, 48000) + |
* in_samples, 44100, 48000, AV_ROUND_UP); |
* av_samples_alloc(&output, NULL, 2, out_samples, |
* AV_SAMPLE_FMT_S16, 0); |
* out_samples = swr_convert(swr, &output, out_samples, |
* input, in_samples); |
* handle_output(output, out_samples); |
* av_freep(&output); |
* } |
* @endcode |
* |
* When the conversion is finished, the conversion |
* context and everything associated with it must be freed with swr_free(). |
* There will be no memory leak if the data is not completely flushed before |
* swr_free(). |
*/ |
#include <stdint.h> |
#include "libavutil/samplefmt.h" |
#include "libswresample/version.h" |
#if LIBSWRESAMPLE_VERSION_MAJOR < 1 |
#define SWR_CH_MAX 32 ///< Maximum number of channels |
#endif |
#define SWR_FLAG_RESAMPLE 1 ///< Force resampling even if equal sample rate |
//TODO use int resample ? |
//long term TODO can we enable this dynamically? |
enum SwrDitherType { |
SWR_DITHER_NONE = 0, |
SWR_DITHER_RECTANGULAR, |
SWR_DITHER_TRIANGULAR, |
SWR_DITHER_TRIANGULAR_HIGHPASS, |
SWR_DITHER_NS = 64, ///< not part of API/ABI |
SWR_DITHER_NS_LIPSHITZ, |
SWR_DITHER_NS_F_WEIGHTED, |
SWR_DITHER_NS_MODIFIED_E_WEIGHTED, |
SWR_DITHER_NS_IMPROVED_E_WEIGHTED, |
SWR_DITHER_NS_SHIBATA, |
SWR_DITHER_NS_LOW_SHIBATA, |
SWR_DITHER_NS_HIGH_SHIBATA, |
SWR_DITHER_NB, ///< not part of API/ABI |
}; |
/** Resampling Engines */ |
enum SwrEngine { |
SWR_ENGINE_SWR, /**< SW Resampler */ |
SWR_ENGINE_SOXR, /**< SoX Resampler */ |
SWR_ENGINE_NB, ///< not part of API/ABI |
}; |
/** Resampling Filter Types */ |
enum SwrFilterType { |
SWR_FILTER_TYPE_CUBIC, /**< Cubic */ |
SWR_FILTER_TYPE_BLACKMAN_NUTTALL, /**< Blackman Nuttall Windowed Sinc */ |
SWR_FILTER_TYPE_KAISER, /**< Kaiser Windowed Sinc */ |
}; |
typedef struct SwrContext SwrContext; |
/** |
* Get the AVClass for swrContext. It can be used in combination with |
* AV_OPT_SEARCH_FAKE_OBJ for examining options. |
* |
* @see av_opt_find(). |
*/ |
const AVClass *swr_get_class(void); |
/** |
* Allocate SwrContext. |
* |
* If you use this function you will need to set the parameters (manually or |
* with swr_alloc_set_opts()) before calling swr_init(). |
* |
* @see swr_alloc_set_opts(), swr_init(), swr_free() |
* @return NULL on error, allocated context otherwise |
*/ |
struct SwrContext *swr_alloc(void); |
/** |
* Initialize context after user parameters have been set. |
* |
* @return AVERROR error code in case of failure. |
*/ |
int swr_init(struct SwrContext *s); |
/** |
* Allocate SwrContext if needed and set/reset common parameters. |
* |
* This function does not require s to be allocated with swr_alloc(). On the |
* other hand, swr_alloc() can use swr_alloc_set_opts() to set the parameters |
* on the allocated context. |
* |
* @param s Swr context, can be NULL |
* @param out_ch_layout output channel layout (AV_CH_LAYOUT_*) |
* @param out_sample_fmt output sample format (AV_SAMPLE_FMT_*). |
* @param out_sample_rate output sample rate (frequency in Hz) |
* @param in_ch_layout input channel layout (AV_CH_LAYOUT_*) |
* @param in_sample_fmt input sample format (AV_SAMPLE_FMT_*). |
* @param in_sample_rate input sample rate (frequency in Hz) |
* @param log_offset logging level offset |
* @param log_ctx parent logging context, can be NULL |
* |
* @see swr_init(), swr_free() |
* @return NULL on error, allocated context otherwise |
*/ |
struct SwrContext *swr_alloc_set_opts(struct SwrContext *s, |
int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, |
int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, |
int log_offset, void *log_ctx); |
/** |
* Free the given SwrContext and set the pointer to NULL. |
*/ |
void swr_free(struct SwrContext **s); |
/** |
* Convert audio. |
* |
* in and in_count can be set to 0 to flush the last few samples out at the |
* end. |
* |
* If more input is provided than output space then the input will be buffered. |
* You can avoid this buffering by providing more output space than input. |
* Convertion will run directly without copying whenever possible. |
* |
* @param s allocated Swr context, with parameters set |
* @param out output buffers, only the first one need be set in case of packed audio |
* @param out_count amount of space available for output in samples per channel |
* @param in input buffers, only the first one need to be set in case of packed audio |
* @param in_count number of input samples available in one channel |
* |
* @return number of samples output per channel, negative value on error |
*/ |
int swr_convert(struct SwrContext *s, uint8_t **out, int out_count, |
const uint8_t **in , int in_count); |
/** |
* Convert the next timestamp from input to output |
* timestamps are in 1/(in_sample_rate * out_sample_rate) units. |
* |
* @note There are 2 slightly differently behaving modes. |
* First is when automatic timestamp compensation is not used, (min_compensation >= FLT_MAX) |
* in this case timestamps will be passed through with delays compensated |
* Second is when automatic timestamp compensation is used, (min_compensation < FLT_MAX) |
* in this case the output timestamps will match output sample numbers |
* |
* @param pts timestamp for the next input sample, INT64_MIN if unknown |
* @return the output timestamp for the next output sample |
*/ |
int64_t swr_next_pts(struct SwrContext *s, int64_t pts); |
/** |
* Activate resampling compensation. |
*/ |
int swr_set_compensation(struct SwrContext *s, int sample_delta, int compensation_distance); |
/** |
* Set a customized input channel mapping. |
* |
* @param s allocated Swr context, not yet initialized |
* @param channel_map customized input channel mapping (array of channel |
* indexes, -1 for a muted channel) |
* @return AVERROR error code in case of failure. |
*/ |
int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map); |
/** |
* Set a customized remix matrix. |
* |
* @param s allocated Swr context, not yet initialized |
* @param matrix remix coefficients; matrix[i + stride * o] is |
* the weight of input channel i in output channel o |
* @param stride offset between lines of the matrix |
* @return AVERROR error code in case of failure. |
*/ |
int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride); |
/** |
* Drops the specified number of output samples. |
*/ |
int swr_drop_output(struct SwrContext *s, int count); |
/** |
* Injects the specified number of silence samples. |
*/ |
int swr_inject_silence(struct SwrContext *s, int count); |
/** |
* Gets the delay the next input sample will experience relative to the next output sample. |
* |
* Swresample can buffer data if more input has been provided than available |
* output space, also converting between sample rates needs a delay. |
* This function returns the sum of all such delays. |
* The exact delay is not necessarily an integer value in either input or |
* output sample rate. Especially when downsampling by a large value, the |
* output sample rate may be a poor choice to represent the delay, similarly |
* for upsampling and the input sample rate. |
* |
* @param s swr context |
* @param base timebase in which the returned delay will be |
* if its set to 1 the returned delay is in seconds |
* if its set to 1000 the returned delay is in milli seconds |
* if its set to the input sample rate then the returned delay is in input samples |
* if its set to the output sample rate then the returned delay is in output samples |
* an exact rounding free delay can be found by using LCM(in_sample_rate, out_sample_rate) |
* @returns the delay in 1/base units. |
*/ |
int64_t swr_get_delay(struct SwrContext *s, int64_t base); |
/** |
* Return the LIBSWRESAMPLE_VERSION_INT constant. |
*/ |
unsigned swresample_version(void); |
/** |
* Return the swr build-time configuration. |
*/ |
const char *swresample_configuration(void); |
/** |
* Return the swr license. |
*/ |
const char *swresample_license(void); |
/** |
* @} |
*/ |
#endif /* SWRESAMPLE_SWRESAMPLE_H */ |
/contrib/sdk/sources/ffmpeg/libswresample/swresample.lib |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/contrib/sdk/sources/ffmpeg/libswresample/swresample_internal.h |
---|
0,0 → 1,199 |
/* |
* Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at) |
* |
* This file is part of libswresample |
* |
* libswresample 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. |
* |
* libswresample 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 libswresample; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#ifndef SWR_INTERNAL_H |
#define SWR_INTERNAL_H |
#include "swresample.h" |
#include "libavutil/channel_layout.h" |
#include "config.h" |
#define SQRT3_2 1.22474487139158904909 /* sqrt(3/2) */ |
#define NS_TAPS 20 |
#if ARCH_X86_64 |
typedef int64_t integer; |
#else |
typedef int integer; |
#endif |
typedef void (mix_1_1_func_type)(void *out, const void *in, void *coeffp, integer index, integer len); |
typedef void (mix_2_1_func_type)(void *out, const void *in1, const void *in2, void *coeffp, integer index1, integer index2, integer len); |
typedef void (mix_any_func_type)(uint8_t **out, const uint8_t **in1, void *coeffp, integer len); |
typedef struct AudioData{ |
uint8_t *ch[SWR_CH_MAX]; ///< samples buffer per channel |
uint8_t *data; ///< samples buffer |
int ch_count; ///< number of channels |
int bps; ///< bytes per sample |
int count; ///< number of samples |
int planar; ///< 1 if planar audio, 0 otherwise |
enum AVSampleFormat fmt; ///< sample format |
} AudioData; |
struct DitherContext { |
enum SwrDitherType method; |
int noise_pos; |
float scale; |
float noise_scale; ///< Noise scale |
int ns_taps; ///< Noise shaping dither taps |
float ns_scale; ///< Noise shaping dither scale |
float ns_scale_1; ///< Noise shaping dither scale^-1 |
int ns_pos; ///< Noise shaping dither position |
float ns_coeffs[NS_TAPS]; ///< Noise shaping filter coefficients |
float ns_errors[SWR_CH_MAX][2*NS_TAPS]; |
AudioData noise; ///< noise used for dithering |
AudioData temp; ///< temporary storage when writing into the input buffer isnt possible |
int output_sample_bits; ///< the number of used output bits, needed to scale dither correctly |
}; |
struct SwrContext { |
const AVClass *av_class; ///< AVClass used for AVOption and av_log() |
int log_level_offset; ///< logging level offset |
void *log_ctx; ///< parent logging context |
enum AVSampleFormat in_sample_fmt; ///< input sample format |
enum AVSampleFormat int_sample_fmt; ///< internal sample format (AV_SAMPLE_FMT_FLTP or AV_SAMPLE_FMT_S16P) |
enum AVSampleFormat out_sample_fmt; ///< output sample format |
int64_t in_ch_layout; ///< input channel layout |
int64_t out_ch_layout; ///< output channel layout |
int in_sample_rate; ///< input sample rate |
int out_sample_rate; ///< output sample rate |
int flags; ///< miscellaneous flags such as SWR_FLAG_RESAMPLE |
float slev; ///< surround mixing level |
float clev; ///< center mixing level |
float lfe_mix_level; ///< LFE mixing level |
float rematrix_volume; ///< rematrixing volume coefficient |
float rematrix_maxval; ///< maximum value for rematrixing output |
enum AVMatrixEncoding matrix_encoding; /**< matrixed stereo encoding */ |
const int *channel_map; ///< channel index (or -1 if muted channel) map |
int used_ch_count; ///< number of used input channels (mapped channel count if channel_map, otherwise in.ch_count) |
enum SwrEngine engine; |
struct DitherContext dither; |
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 (swr: 6dB point; soxr: 0dB point). 1.0 corresponds to half the output sample rate */ |
enum SwrFilterType filter_type; /**< swr resampling filter type */ |
int kaiser_beta; /**< swr beta value for Kaiser window (only applicable if filter_type == AV_FILTER_TYPE_KAISER) */ |
double precision; /**< soxr resampling precision (in bits) */ |
int cheby; /**< soxr: if 1 then passband rolloff will be none (Chebyshev) & irrational ratio approximation precision will be higher */ |
float min_compensation; ///< swr minimum below which no compensation will happen |
float min_hard_compensation; ///< swr minimum below which no silence inject / sample drop will happen |
float soft_compensation_duration; ///< swr duration over which soft compensation is applied |
float max_soft_compensation; ///< swr maximum soft compensation in seconds over soft_compensation_duration |
float async; ///< swr simple 1 parameter async, similar to ffmpegs -async |
int64_t firstpts_in_samples; ///< swr first pts in samples |
int resample_first; ///< 1 if resampling must come first, 0 if rematrixing |
int rematrix; ///< flag to indicate if rematrixing is needed (basically if input and output layouts mismatch) |
int rematrix_custom; ///< flag to indicate that a custom matrix has been defined |
AudioData in; ///< input audio data |
AudioData postin; ///< post-input audio data: used for rematrix/resample |
AudioData midbuf; ///< intermediate audio data (postin/preout) |
AudioData preout; ///< pre-output audio data: used for rematrix/resample |
AudioData out; ///< converted output audio data |
AudioData in_buffer; ///< cached audio data (convert and resample purpose) |
AudioData silence; ///< temporary with silence |
AudioData drop_temp; ///< temporary used to discard output |
int in_buffer_index; ///< cached buffer position |
int in_buffer_count; ///< cached buffer length |
int resample_in_constraint; ///< 1 if the input end was reach before the output end, 0 otherwise |
int flushed; ///< 1 if data is to be flushed and no further input is expected |
int64_t outpts; ///< output PTS |
int64_t firstpts; ///< first PTS |
int drop_output; ///< number of output samples to drop |
struct AudioConvert *in_convert; ///< input conversion context |
struct AudioConvert *out_convert; ///< output conversion context |
struct AudioConvert *full_convert; ///< full conversion context (single conversion for input and output) |
struct ResampleContext *resample; ///< resampling context |
struct Resampler const *resampler; ///< resampler virtual function table |
float matrix[SWR_CH_MAX][SWR_CH_MAX]; ///< floating point rematrixing coefficients |
uint8_t *native_matrix; |
uint8_t *native_one; |
uint8_t *native_simd_one; |
uint8_t *native_simd_matrix; |
int32_t matrix32[SWR_CH_MAX][SWR_CH_MAX]; ///< 17.15 fixed point rematrixing coefficients |
uint8_t matrix_ch[SWR_CH_MAX][SWR_CH_MAX+1]; ///< Lists of input channels per output channel that have non zero rematrixing coefficients |
mix_1_1_func_type *mix_1_1_f; |
mix_1_1_func_type *mix_1_1_simd; |
mix_2_1_func_type *mix_2_1_f; |
mix_2_1_func_type *mix_2_1_simd; |
mix_any_func_type *mix_any_f; |
/* TODO: callbacks for ASM optimizations */ |
}; |
typedef struct ResampleContext * (* resample_init_func)(struct ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, |
double cutoff, enum AVSampleFormat format, enum SwrFilterType filter_type, int kaiser_beta, double precision, int cheby); |
typedef void (* resample_free_func)(struct ResampleContext **c); |
typedef int (* multiple_resample_func)(struct ResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed); |
typedef int (* resample_flush_func)(struct SwrContext *c); |
typedef int (* set_compensation_func)(struct ResampleContext *c, int sample_delta, int compensation_distance); |
typedef int64_t (* get_delay_func)(struct SwrContext *s, int64_t base); |
struct Resampler { |
resample_init_func init; |
resample_free_func free; |
multiple_resample_func multiple_resample; |
resample_flush_func flush; |
set_compensation_func set_compensation; |
get_delay_func get_delay; |
}; |
extern struct Resampler const swri_resampler; |
int swri_realloc_audio(AudioData *a, int count); |
int swri_resample_int16(struct ResampleContext *c, int16_t *dst, const int16_t *src, int *consumed, int src_size, int dst_size, int update_ctx); |
int swri_resample_int32(struct ResampleContext *c, int32_t *dst, const int32_t *src, int *consumed, int src_size, int dst_size, int update_ctx); |
int swri_resample_float(struct ResampleContext *c, float *dst, const float *src, int *consumed, int src_size, int dst_size, int update_ctx); |
int swri_resample_double(struct ResampleContext *c,double *dst, const double *src, int *consumed, int src_size, int dst_size, int update_ctx); |
void swri_noise_shaping_int16 (SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count); |
void swri_noise_shaping_int32 (SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count); |
void swri_noise_shaping_float (SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count); |
void swri_noise_shaping_double(SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count); |
int swri_rematrix_init(SwrContext *s); |
void swri_rematrix_free(SwrContext *s); |
int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy); |
void swri_rematrix_init_x86(struct SwrContext *s); |
void swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSampleFormat noise_fmt); |
int swri_dither_init(SwrContext *s, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt); |
void swri_audio_convert_init_arm(struct AudioConvert *ac, |
enum AVSampleFormat out_fmt, |
enum AVSampleFormat in_fmt, |
int channels); |
void swri_audio_convert_init_x86(struct AudioConvert *ac, |
enum AVSampleFormat out_fmt, |
enum AVSampleFormat in_fmt, |
int channels); |
#endif |
/contrib/sdk/sources/ffmpeg/libswresample/version.h |
---|
0,0 → 1,45 |
/* |
* Version macros. |
* |
* This file is part of libswresample |
* |
* libswresample 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. |
* |
* libswresample 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 libswresample; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#ifndef SWR_VERSION_H |
#define SWR_VERSION_H |
/** |
* @file |
* Libswresample version macros |
*/ |
#include "libavutil/avutil.h" |
#define LIBSWRESAMPLE_VERSION_MAJOR 0 |
#define LIBSWRESAMPLE_VERSION_MINOR 17 |
#define LIBSWRESAMPLE_VERSION_MICRO 104 |
#define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ |
LIBSWRESAMPLE_VERSION_MINOR, \ |
LIBSWRESAMPLE_VERSION_MICRO) |
#define LIBSWRESAMPLE_VERSION AV_VERSION(LIBSWRESAMPLE_VERSION_MAJOR, \ |
LIBSWRESAMPLE_VERSION_MINOR, \ |
LIBSWRESAMPLE_VERSION_MICRO) |
#define LIBSWRESAMPLE_BUILD LIBSWRESAMPLE_VERSION_INT |
#define LIBSWRESAMPLE_IDENT "SwR" AV_STRINGIFY(LIBSWRESAMPLE_VERSION) |
#endif /* SWR_VERSION_H */ |
/contrib/sdk/sources/ffmpeg/libswresample/x86/Makefile |
---|
0,0 → 1,3 |
YASM-OBJS += x86/swresample_x86.o\ |
x86/audio_convert.o\ |
x86/rematrix.o\ |
/contrib/sdk/sources/ffmpeg/libswresample/x86/audio_convert.asm |
---|
0,0 → 1,465 |
;****************************************************************************** |
;* Copyright (c) 2012 Michael Niedermayer |
;* |
;* 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 |
flt2pm31: times 8 dd 4.6566129e-10 |
flt2p31 : times 8 dd 2147483648.0 |
flt2p15 : times 8 dd 32768.0 |
word_unpack_shuf : db 0, 1, 4, 5, 8, 9,12,13, 2, 3, 6, 7,10,11,14,15 |
SECTION .text |
;to, from, a/u, log2_outsize, log_intsize, const |
%macro PACK_2CH 5-7 |
cglobal pack_2ch_%2_to_%1_%3, 3, 4, 6, dst, src, len, src2 |
mov src2q , [srcq+gprsize] |
mov srcq , [srcq] |
mov dstq , [dstq] |
%ifidn %3, a |
test dstq, mmsize-1 |
jne pack_2ch_%2_to_%1_u_int %+ SUFFIX |
test srcq, mmsize-1 |
jne pack_2ch_%2_to_%1_u_int %+ SUFFIX |
test src2q, mmsize-1 |
jne pack_2ch_%2_to_%1_u_int %+ SUFFIX |
%else |
pack_2ch_%2_to_%1_u_int %+ SUFFIX |
%endif |
lea srcq , [srcq + (1<<%5)*lenq] |
lea src2q, [src2q + (1<<%5)*lenq] |
lea dstq , [dstq + (2<<%4)*lenq] |
neg lenq |
%7 m0,m1,m2,m3,m4,m5 |
.next: |
%if %4 >= %5 |
mov%3 m0, [ srcq +(1<<%5)*lenq] |
mova m1, m0 |
mov%3 m2, [ src2q+(1<<%5)*lenq] |
%if %5 == 1 |
punpcklwd m0, m2 |
punpckhwd m1, m2 |
%else |
punpckldq m0, m2 |
punpckhdq m1, m2 |
%endif |
%6 m0,m1,m2,m3,m4,m5 |
%else |
mov%3 m0, [ srcq +(1<<%5)*lenq] |
mov%3 m1, [mmsize + srcq +(1<<%5)*lenq] |
mov%3 m2, [ src2q+(1<<%5)*lenq] |
mov%3 m3, [mmsize + src2q+(1<<%5)*lenq] |
%6 m0,m1,m2,m3,m4,m5 |
mova m2, m0 |
punpcklwd m0, m1 |
punpckhwd m2, m1 |
SWAP 1,2 |
%endif |
mov%3 [ dstq+(2<<%4)*lenq], m0 |
mov%3 [ mmsize + dstq+(2<<%4)*lenq], m1 |
%if %4 > %5 |
mov%3 [2*mmsize + dstq+(2<<%4)*lenq], m2 |
mov%3 [3*mmsize + dstq+(2<<%4)*lenq], m3 |
add lenq, 4*mmsize/(2<<%4) |
%else |
add lenq, 2*mmsize/(2<<%4) |
%endif |
jl .next |
REP_RET |
%endmacro |
%macro UNPACK_2CH 5-7 |
cglobal unpack_2ch_%2_to_%1_%3, 3, 4, 7, dst, src, len, dst2 |
mov dst2q , [dstq+gprsize] |
mov srcq , [srcq] |
mov dstq , [dstq] |
%ifidn %3, a |
test dstq, mmsize-1 |
jne unpack_2ch_%2_to_%1_u_int %+ SUFFIX |
test srcq, mmsize-1 |
jne unpack_2ch_%2_to_%1_u_int %+ SUFFIX |
test dst2q, mmsize-1 |
jne unpack_2ch_%2_to_%1_u_int %+ SUFFIX |
%else |
unpack_2ch_%2_to_%1_u_int %+ SUFFIX |
%endif |
lea srcq , [srcq + (2<<%5)*lenq] |
lea dstq , [dstq + (1<<%4)*lenq] |
lea dst2q, [dst2q + (1<<%4)*lenq] |
neg lenq |
%7 m0,m1,m2,m3,m4,m5 |
mova m6, [word_unpack_shuf] |
.next: |
mov%3 m0, [ srcq +(2<<%5)*lenq] |
mov%3 m2, [ mmsize + srcq +(2<<%5)*lenq] |
%if %5 == 1 |
%ifidn SUFFIX, _ssse3 |
pshufb m0, m6 |
mova m1, m0 |
pshufb m2, m6 |
punpcklqdq m0,m2 |
punpckhqdq m1,m2 |
%else |
mova m1, m0 |
punpcklwd m0,m2 |
punpckhwd m1,m2 |
mova m2, m0 |
punpcklwd m0,m1 |
punpckhwd m2,m1 |
mova m1, m0 |
punpcklwd m0,m2 |
punpckhwd m1,m2 |
%endif |
%else |
mova m1, m0 |
shufps m0, m2, 10001000b |
shufps m1, m2, 11011101b |
%endif |
%if %4 < %5 |
mov%3 m2, [2*mmsize + srcq +(2<<%5)*lenq] |
mova m3, m2 |
mov%3 m4, [3*mmsize + srcq +(2<<%5)*lenq] |
shufps m2, m4, 10001000b |
shufps m3, m4, 11011101b |
SWAP 1,2 |
%endif |
%6 m0,m1,m2,m3,m4,m5 |
mov%3 [ dstq+(1<<%4)*lenq], m0 |
%if %4 > %5 |
mov%3 [ dst2q+(1<<%4)*lenq], m2 |
mov%3 [ mmsize + dstq+(1<<%4)*lenq], m1 |
mov%3 [ mmsize + dst2q+(1<<%4)*lenq], m3 |
add lenq, 2*mmsize/(1<<%4) |
%else |
mov%3 [ dst2q+(1<<%4)*lenq], m1 |
add lenq, mmsize/(1<<%4) |
%endif |
jl .next |
REP_RET |
%endmacro |
%macro CONV 5-7 |
cglobal %2_to_%1_%3, 3, 3, 6, dst, src, len |
mov srcq , [srcq] |
mov dstq , [dstq] |
%ifidn %3, a |
test dstq, mmsize-1 |
jne %2_to_%1_u_int %+ SUFFIX |
test srcq, mmsize-1 |
jne %2_to_%1_u_int %+ SUFFIX |
%else |
%2_to_%1_u_int %+ SUFFIX |
%endif |
lea srcq , [srcq + (1<<%5)*lenq] |
lea dstq , [dstq + (1<<%4)*lenq] |
neg lenq |
%7 m0,m1,m2,m3,m4,m5 |
.next: |
mov%3 m0, [ srcq +(1<<%5)*lenq] |
mov%3 m1, [ mmsize + srcq +(1<<%5)*lenq] |
%if %4 < %5 |
mov%3 m2, [2*mmsize + srcq +(1<<%5)*lenq] |
mov%3 m3, [3*mmsize + srcq +(1<<%5)*lenq] |
%endif |
%6 m0,m1,m2,m3,m4,m5 |
mov%3 [ dstq+(1<<%4)*lenq], m0 |
mov%3 [ mmsize + dstq+(1<<%4)*lenq], m1 |
%if %4 > %5 |
mov%3 [2*mmsize + dstq+(1<<%4)*lenq], m2 |
mov%3 [3*mmsize + dstq+(1<<%4)*lenq], m3 |
add lenq, 4*mmsize/(1<<%4) |
%else |
add lenq, 2*mmsize/(1<<%4) |
%endif |
jl .next |
%if mmsize == 8 |
emms |
RET |
%else |
REP_RET |
%endif |
%endmacro |
%macro PACK_6CH 5-7 |
cglobal pack_6ch_%2_to_%1_%3, 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] |
mov dstq, [dstq] |
%ifidn %3, a |
test dstq, mmsize-1 |
jne pack_6ch_%2_to_%1_u_int %+ SUFFIX |
test srcq, mmsize-1 |
jne pack_6ch_%2_to_%1_u_int %+ SUFFIX |
test src2q, mmsize-1 |
jne pack_6ch_%2_to_%1_u_int %+ SUFFIX |
test src3q, mmsize-1 |
jne pack_6ch_%2_to_%1_u_int %+ SUFFIX |
test src4q, mmsize-1 |
jne pack_6ch_%2_to_%1_u_int %+ SUFFIX |
test src5q, mmsize-1 |
jne pack_6ch_%2_to_%1_u_int %+ SUFFIX |
%else |
pack_6ch_%2_to_%1_u_int %+ SUFFIX |
%endif |
sub src1q, srcq |
sub src2q, srcq |
sub src3q, srcq |
sub src4q, srcq |
sub src5q, srcq |
.loop: |
mov%3 m0, [srcq ] |
mov%3 m1, [srcq+src1q] |
mov%3 m2, [srcq+src2q] |
mov%3 m3, [srcq+src3q] |
mov%3 m4, [srcq+src4q] |
mov%3 m5, [srcq+src5q] |
%7 x,x,x,x,m7,x |
%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 |
%6 m0,m6,x,x,m7,m3 |
%6 m4,m1,x,x,m7,m3 |
%6 m2,m5,x,x,m7,m3 |
mov %+ %3 %+ ps [dstq ], m0 |
mov %+ %3 %+ ps [dstq+16], m6 |
mov %+ %3 %+ ps [dstq+32], m4 |
mov %+ %3 %+ ps [dstq+48], m1 |
mov %+ %3 %+ ps [dstq+64], m2 |
mov %+ %3 %+ ps [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 |
%macro INT16_TO_INT32_N 6 |
pxor m2, m2 |
pxor m3, m3 |
punpcklwd m2, m1 |
punpckhwd m3, m1 |
SWAP 4,0 |
pxor m0, m0 |
pxor m1, m1 |
punpcklwd m0, m4 |
punpckhwd m1, m4 |
%endmacro |
%macro INT32_TO_INT16_N 6 |
psrad m0, 16 |
psrad m1, 16 |
psrad m2, 16 |
psrad m3, 16 |
packssdw m0, m1 |
packssdw m2, m3 |
SWAP 1,2 |
%endmacro |
%macro INT32_TO_FLOAT_INIT 6 |
mova %5, [flt2pm31] |
%endmacro |
%macro INT32_TO_FLOAT_N 6 |
cvtdq2ps %1, %1 |
cvtdq2ps %2, %2 |
mulps %1, %1, %5 |
mulps %2, %2, %5 |
%endmacro |
%macro FLOAT_TO_INT32_INIT 6 |
mova %5, [flt2p31] |
%endmacro |
%macro FLOAT_TO_INT32_N 6 |
mulps %1, %5 |
mulps %2, %5 |
cvtps2dq %6, %1 |
cmpnltps %1, %5 |
paddd %1, %6 |
cvtps2dq %6, %2 |
cmpnltps %2, %5 |
paddd %2, %6 |
%endmacro |
%macro INT16_TO_FLOAT_INIT 6 |
mova m5, [flt2pm31] |
%endmacro |
%macro INT16_TO_FLOAT_N 6 |
INT16_TO_INT32_N %1,%2,%3,%4,%5,%6 |
cvtdq2ps m0, m0 |
cvtdq2ps m1, m1 |
cvtdq2ps m2, m2 |
cvtdq2ps m3, m3 |
mulps m0, m0, m5 |
mulps m1, m1, m5 |
mulps m2, m2, m5 |
mulps m3, m3, m5 |
%endmacro |
%macro FLOAT_TO_INT16_INIT 6 |
mova m5, [flt2p15] |
%endmacro |
%macro FLOAT_TO_INT16_N 6 |
mulps m0, m5 |
mulps m1, m5 |
mulps m2, m5 |
mulps m3, m5 |
cvtps2dq m0, m0 |
cvtps2dq m1, m1 |
packssdw m0, m1 |
cvtps2dq m1, m2 |
cvtps2dq m3, m3 |
packssdw m1, m3 |
%endmacro |
%macro NOP_N 0-6 |
%endmacro |
INIT_MMX mmx |
CONV int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N |
CONV int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N |
CONV int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N |
CONV int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N |
PACK_6CH float, float, u, 2, 2, NOP_N, NOP_N |
PACK_6CH float, float, a, 2, 2, NOP_N, NOP_N |
INIT_XMM sse2 |
CONV int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N |
CONV int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N |
CONV int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N |
CONV int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N |
PACK_2CH int16, int16, u, 1, 1, NOP_N, NOP_N |
PACK_2CH int16, int16, a, 1, 1, NOP_N, NOP_N |
PACK_2CH int32, int32, u, 2, 2, NOP_N, NOP_N |
PACK_2CH int32, int32, a, 2, 2, NOP_N, NOP_N |
PACK_2CH int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N |
PACK_2CH int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N |
PACK_2CH int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N |
PACK_2CH int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N |
UNPACK_2CH int16, int16, u, 1, 1, NOP_N, NOP_N |
UNPACK_2CH int16, int16, a, 1, 1, NOP_N, NOP_N |
UNPACK_2CH int32, int32, u, 2, 2, NOP_N, NOP_N |
UNPACK_2CH int32, int32, a, 2, 2, NOP_N, NOP_N |
UNPACK_2CH int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N |
UNPACK_2CH int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N |
UNPACK_2CH int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N |
UNPACK_2CH int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N |
CONV float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT |
CONV float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT |
CONV int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT |
CONV int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT |
CONV float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT |
CONV float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT |
CONV int16, float, u, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT |
CONV int16, float, a, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT |
PACK_2CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT |
PACK_2CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT |
PACK_2CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT |
PACK_2CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT |
PACK_2CH float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT |
PACK_2CH float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT |
PACK_2CH int16, float, u, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT |
PACK_2CH int16, float, a, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT |
UNPACK_2CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT |
UNPACK_2CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT |
UNPACK_2CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT |
UNPACK_2CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT |
UNPACK_2CH float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT |
UNPACK_2CH float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT |
UNPACK_2CH int16, float, u, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT |
UNPACK_2CH int16, float, a, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT |
INIT_XMM ssse3 |
UNPACK_2CH int16, int16, u, 1, 1, NOP_N, NOP_N |
UNPACK_2CH int16, int16, a, 1, 1, NOP_N, NOP_N |
UNPACK_2CH int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N |
UNPACK_2CH int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N |
UNPACK_2CH float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT |
UNPACK_2CH float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT |
INIT_XMM sse4 |
PACK_6CH float, float, u, 2, 2, NOP_N, NOP_N |
PACK_6CH float, float, a, 2, 2, NOP_N, NOP_N |
PACK_6CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT |
PACK_6CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT |
PACK_6CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT |
PACK_6CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT |
%if HAVE_AVX_EXTERNAL |
INIT_XMM avx |
PACK_6CH float, float, u, 2, 2, NOP_N, NOP_N |
PACK_6CH float, float, a, 2, 2, NOP_N, NOP_N |
PACK_6CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT |
PACK_6CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT |
PACK_6CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT |
PACK_6CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT |
INIT_YMM avx |
CONV float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT |
CONV float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT |
%endif |
/contrib/sdk/sources/ffmpeg/libswresample/x86/rematrix.asm |
---|
0,0 → 1,250 |
;****************************************************************************** |
;* Copyright (c) 2012 Michael Niedermayer |
;* |
;* 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 |
dw1: times 8 dd 1 |
w1 : times 16 dw 1 |
SECTION .text |
%macro MIX2_FLT 1 |
cglobal mix_2_1_%1_float, 7, 7, 6, out, in1, in2, coeffp, index1, index2, len |
%ifidn %1, a |
test in1q, mmsize-1 |
jne mix_2_1_float_u_int %+ SUFFIX |
test in2q, mmsize-1 |
jne mix_2_1_float_u_int %+ SUFFIX |
test outq, mmsize-1 |
jne mix_2_1_float_u_int %+ SUFFIX |
%else |
mix_2_1_float_u_int %+ SUFFIX |
%endif |
VBROADCASTSS m4, [coeffpq + 4*index1q] |
VBROADCASTSS m5, [coeffpq + 4*index2q] |
shl lend , 2 |
add in1q , lenq |
add in2q , lenq |
add outq , lenq |
neg lenq |
.next: |
%ifidn %1, a |
mulps m0, m4, [in1q + lenq ] |
mulps m1, m5, [in2q + lenq ] |
mulps m2, m4, [in1q + lenq + mmsize] |
mulps m3, m5, [in2q + lenq + mmsize] |
%else |
movu m0, [in1q + lenq ] |
movu m1, [in2q + lenq ] |
movu m2, [in1q + lenq + mmsize] |
movu m3, [in2q + lenq + mmsize] |
mulps m0, m0, m4 |
mulps m1, m1, m5 |
mulps m2, m2, m4 |
mulps m3, m3, m5 |
%endif |
addps m0, m0, m1 |
addps m2, m2, m3 |
mov%1 [outq + lenq ], m0 |
mov%1 [outq + lenq + mmsize], m2 |
add lenq, mmsize*2 |
jl .next |
REP_RET |
%endmacro |
%macro MIX1_FLT 1 |
cglobal mix_1_1_%1_float, 5, 5, 3, out, in, coeffp, index, len |
%ifidn %1, a |
test inq, mmsize-1 |
jne mix_1_1_float_u_int %+ SUFFIX |
test outq, mmsize-1 |
jne mix_1_1_float_u_int %+ SUFFIX |
%else |
mix_1_1_float_u_int %+ SUFFIX |
%endif |
VBROADCASTSS m2, [coeffpq + 4*indexq] |
shl lenq , 2 |
add inq , lenq |
add outq , lenq |
neg lenq |
.next: |
%ifidn %1, a |
mulps m0, m2, [inq + lenq ] |
mulps m1, m2, [inq + lenq + mmsize] |
%else |
movu m0, [inq + lenq ] |
movu m1, [inq + lenq + mmsize] |
mulps m0, m0, m2 |
mulps m1, m1, m2 |
%endif |
mov%1 [outq + lenq ], m0 |
mov%1 [outq + lenq + mmsize], m1 |
add lenq, mmsize*2 |
jl .next |
REP_RET |
%endmacro |
%macro MIX1_INT16 1 |
cglobal mix_1_1_%1_int16, 5, 5, 6, out, in, coeffp, index, len |
%ifidn %1, a |
test inq, mmsize-1 |
jne mix_1_1_int16_u_int %+ SUFFIX |
test outq, mmsize-1 |
jne mix_1_1_int16_u_int %+ SUFFIX |
%else |
mix_1_1_int16_u_int %+ SUFFIX |
%endif |
movd m4, [coeffpq + 4*indexq] |
SPLATW m5, m4 |
psllq m4, 32 |
psrlq m4, 48 |
mova m0, [w1] |
psllw m0, m4 |
psrlw m0, 1 |
punpcklwd m5, m0 |
add lenq , lenq |
add inq , lenq |
add outq , lenq |
neg lenq |
.next: |
mov%1 m0, [inq + lenq ] |
mov%1 m2, [inq + lenq + mmsize] |
mova m1, m0 |
mova m3, m2 |
punpcklwd m0, [w1] |
punpckhwd m1, [w1] |
punpcklwd m2, [w1] |
punpckhwd m3, [w1] |
pmaddwd m0, m5 |
pmaddwd m1, m5 |
pmaddwd m2, m5 |
pmaddwd m3, m5 |
psrad m0, m4 |
psrad m1, m4 |
psrad m2, m4 |
psrad m3, m4 |
packssdw m0, m1 |
packssdw m2, m3 |
mov%1 [outq + lenq ], m0 |
mov%1 [outq + lenq + mmsize], m2 |
add lenq, mmsize*2 |
jl .next |
%if mmsize == 8 |
emms |
RET |
%else |
REP_RET |
%endif |
%endmacro |
%macro MIX2_INT16 1 |
cglobal mix_2_1_%1_int16, 7, 7, 8, out, in1, in2, coeffp, index1, index2, len |
%ifidn %1, a |
test in1q, mmsize-1 |
jne mix_2_1_int16_u_int %+ SUFFIX |
test in2q, mmsize-1 |
jne mix_2_1_int16_u_int %+ SUFFIX |
test outq, mmsize-1 |
jne mix_2_1_int16_u_int %+ SUFFIX |
%else |
mix_2_1_int16_u_int %+ SUFFIX |
%endif |
movd m4, [coeffpq + 4*index1q] |
movd m6, [coeffpq + 4*index2q] |
SPLATW m5, m4 |
SPLATW m6, m6 |
psllq m4, 32 |
psrlq m4, 48 |
mova m7, [dw1] |
pslld m7, m4 |
psrld m7, 1 |
punpcklwd m5, m6 |
add lend , lend |
add in1q , lenq |
add in2q , lenq |
add outq , lenq |
neg lenq |
.next: |
mov%1 m0, [in1q + lenq ] |
mov%1 m2, [in2q + lenq ] |
mova m1, m0 |
punpcklwd m0, m2 |
punpckhwd m1, m2 |
mov%1 m2, [in1q + lenq + mmsize] |
mov%1 m6, [in2q + lenq + mmsize] |
mova m3, m2 |
punpcklwd m2, m6 |
punpckhwd m3, m6 |
pmaddwd m0, m5 |
pmaddwd m1, m5 |
pmaddwd m2, m5 |
pmaddwd m3, m5 |
paddd m0, m7 |
paddd m1, m7 |
paddd m2, m7 |
paddd m3, m7 |
psrad m0, m4 |
psrad m1, m4 |
psrad m2, m4 |
psrad m3, m4 |
packssdw m0, m1 |
packssdw m2, m3 |
mov%1 [outq + lenq ], m0 |
mov%1 [outq + lenq + mmsize], m2 |
add lenq, mmsize*2 |
jl .next |
%if mmsize == 8 |
emms |
RET |
%else |
REP_RET |
%endif |
%endmacro |
INIT_MMX mmx |
MIX1_INT16 u |
MIX1_INT16 a |
MIX2_INT16 u |
MIX2_INT16 a |
INIT_XMM sse |
MIX2_FLT u |
MIX2_FLT a |
MIX1_FLT u |
MIX1_FLT a |
INIT_XMM sse2 |
MIX1_INT16 u |
MIX1_INT16 a |
MIX2_INT16 u |
MIX2_INT16 a |
%if HAVE_AVX_EXTERNAL |
INIT_YMM avx |
MIX2_FLT u |
MIX2_FLT a |
MIX1_FLT u |
MIX1_FLT a |
%endif |
/contrib/sdk/sources/ffmpeg/libswresample/x86/resample_mmx.h |
---|
0,0 → 1,70 |
/* |
* Copyright (c) 2012 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 |
*/ |
#include "libavutil/x86/asm.h" |
#include "libavutil/cpu.h" |
#include "libswresample/swresample_internal.h" |
int swri_resample_int16_mmx2 (struct ResampleContext *c, int16_t *dst, const int16_t *src, int *consumed, int src_size, int dst_size, int update_ctx); |
int swri_resample_int16_ssse3(struct ResampleContext *c, int16_t *dst, const int16_t *src, int *consumed, int src_size, int dst_size, int update_ctx); |
DECLARE_ALIGNED(16, const uint64_t, ff_resample_int16_rounder)[2] = { 0x0000000000004000ULL, 0x0000000000000000ULL}; |
#define COMMON_CORE_INT16_MMX2 \ |
x86_reg len= -2*c->filter_length;\ |
__asm__ volatile(\ |
"movq "MANGLE(ff_resample_int16_rounder)", %%mm0 \n\t"\ |
"1: \n\t"\ |
"movq (%1, %0), %%mm1 \n\t"\ |
"pmaddwd (%2, %0), %%mm1 \n\t"\ |
"paddd %%mm1, %%mm0 \n\t"\ |
"add $8, %0 \n\t"\ |
" js 1b \n\t"\ |
"pshufw $0x0E, %%mm0, %%mm1 \n\t"\ |
"paddd %%mm1, %%mm0 \n\t"\ |
"psrad $15, %%mm0 \n\t"\ |
"packssdw %%mm0, %%mm0 \n\t"\ |
"movd %%mm0, (%3) \n\t"\ |
: "+r" (len)\ |
: "r" (((uint8_t*)(src+sample_index))-len),\ |
"r" (((uint8_t*)filter)-len),\ |
"r" (dst+dst_index)\ |
); |
#define COMMON_CORE_INT16_SSSE3 \ |
x86_reg len= -2*c->filter_length;\ |
__asm__ volatile(\ |
"movdqa "MANGLE(ff_resample_int16_rounder)", %%xmm0 \n\t"\ |
"1: \n\t"\ |
"movdqu (%1, %0), %%xmm1 \n\t"\ |
"pmaddwd (%2, %0), %%xmm1 \n\t"\ |
"paddd %%xmm1, %%xmm0 \n\t"\ |
"add $16, %0 \n\t"\ |
" js 1b \n\t"\ |
"phaddd %%xmm0, %%xmm0 \n\t"\ |
"phaddd %%xmm0, %%xmm0 \n\t"\ |
"psrad $15, %%xmm0 \n\t"\ |
"packssdw %%xmm0, %%xmm0 \n\t"\ |
"movd %%xmm0, (%3) \n\t"\ |
: "+r" (len)\ |
: "r" (((uint8_t*)(src+sample_index))-len),\ |
"r" (((uint8_t*)filter)-len),\ |
"r" (dst+dst_index)\ |
); |
/contrib/sdk/sources/ffmpeg/libswresample/x86/swresample_x86.c |
---|
0,0 → 1,200 |
/* |
* Copyright (C) 2012 Michael Niedermayer (michaelni@gmx.at) |
* |
* This file is part of libswresample |
* |
* libswresample 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. |
* |
* libswresample 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 libswresample; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
*/ |
#include "libswresample/swresample_internal.h" |
#include "libswresample/audioconvert.h" |
#define PROTO(pre, in, out, cap) void ff ## pre ## _ ##in## _to_ ##out## _a_ ##cap(uint8_t **dst, const uint8_t **src, int len); |
#define PROTO2(pre, out, cap) PROTO(pre, int16, out, cap) PROTO(pre, int32, out, cap) PROTO(pre, float, out, cap) |
#define PROTO3(pre, cap) PROTO2(pre, int16, cap) PROTO2(pre, int32, cap) PROTO2(pre, float, cap) |
#define PROTO4(pre) PROTO3(pre, mmx) PROTO3(pre, sse) PROTO3(pre, sse2) PROTO3(pre, ssse3) PROTO3(pre, sse4) PROTO3(pre, avx) |
PROTO4() |
PROTO4(_pack_2ch) |
PROTO4(_pack_6ch) |
PROTO4(_unpack_2ch) |
av_cold void swri_audio_convert_init_x86(struct AudioConvert *ac, |
enum AVSampleFormat out_fmt, |
enum AVSampleFormat in_fmt, |
int channels){ |
int mm_flags = av_get_cpu_flags(); |
ac->simd_f= NULL; |
//FIXME add memcpy case |
#define MULTI_CAPS_FUNC(flag, cap) \ |
if (mm_flags & flag) {\ |
if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S16 || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S16P)\ |
ac->simd_f = ff_int16_to_int32_a_ ## cap;\ |
if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_S32 || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_S32P)\ |
ac->simd_f = ff_int32_to_int16_a_ ## cap;\ |
} |
MULTI_CAPS_FUNC(AV_CPU_FLAG_MMX, mmx) |
MULTI_CAPS_FUNC(AV_CPU_FLAG_SSE2, sse2) |
if(mm_flags & AV_CPU_FLAG_MMX) { |
if(channels == 6) { |
if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P) |
ac->simd_f = ff_pack_6ch_float_to_float_a_mmx; |
} |
} |
if(mm_flags & AV_CPU_FLAG_SSE2) { |
if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32 || out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32P) |
ac->simd_f = ff_int32_to_float_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S16 || out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S16P) |
ac->simd_f = ff_int16_to_float_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLTP) |
ac->simd_f = ff_float_to_int32_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLTP) |
ac->simd_f = ff_float_to_int16_a_sse2; |
if(channels == 2) { |
if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P) |
ac->simd_f = ff_pack_2ch_int32_to_int32_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_S16P) |
ac->simd_f = ff_pack_2ch_int16_to_int16_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S16P) |
ac->simd_f = ff_pack_2ch_int16_to_int32_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_S32P) |
ac->simd_f = ff_pack_2ch_int32_to_int16_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S32) |
ac->simd_f = ff_unpack_2ch_int32_to_int32_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_S16) |
ac->simd_f = ff_unpack_2ch_int16_to_int16_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S16) |
ac->simd_f = ff_unpack_2ch_int16_to_int32_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_S32) |
ac->simd_f = ff_unpack_2ch_int32_to_int16_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P) |
ac->simd_f = ff_pack_2ch_int32_to_float_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP) |
ac->simd_f = ff_pack_2ch_float_to_int32_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S16P) |
ac->simd_f = ff_pack_2ch_int16_to_float_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP) |
ac->simd_f = ff_pack_2ch_float_to_int16_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32) |
ac->simd_f = ff_unpack_2ch_int32_to_float_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLT) |
ac->simd_f = ff_unpack_2ch_float_to_int32_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S16) |
ac->simd_f = ff_unpack_2ch_int16_to_float_a_sse2; |
if( out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLT) |
ac->simd_f = ff_unpack_2ch_float_to_int16_a_sse2; |
} |
} |
if(mm_flags & AV_CPU_FLAG_SSSE3) { |
if(channels == 2) { |
if( out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_S16) |
ac->simd_f = ff_unpack_2ch_int16_to_int16_a_ssse3; |
if( out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S16) |
ac->simd_f = ff_unpack_2ch_int16_to_int32_a_ssse3; |
if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S16) |
ac->simd_f = ff_unpack_2ch_int16_to_float_a_ssse3; |
} |
} |
if(mm_flags & AV_CPU_FLAG_SSE4) { |
if(channels == 6) { |
if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P) |
ac->simd_f = ff_pack_6ch_float_to_float_a_sse4; |
if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P) |
ac->simd_f = ff_pack_6ch_int32_to_float_a_sse4; |
if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP) |
ac->simd_f = ff_pack_6ch_float_to_int32_a_sse4; |
} |
} |
if(HAVE_AVX_EXTERNAL && mm_flags & AV_CPU_FLAG_AVX) { |
if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32 || out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32P) |
ac->simd_f = ff_int32_to_float_a_avx; |
if(channels == 6) { |
if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P) |
ac->simd_f = ff_pack_6ch_float_to_float_a_avx; |
if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P) |
ac->simd_f = ff_pack_6ch_int32_to_float_a_avx; |
if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP) |
ac->simd_f = ff_pack_6ch_float_to_int32_a_avx; |
} |
} |
} |
#define D(type, simd) \ |
mix_1_1_func_type ff_mix_1_1_a_## type ## _ ## simd;\ |
mix_2_1_func_type ff_mix_2_1_a_## type ## _ ## simd; |
D(float, sse) |
D(float, avx) |
D(int16, mmx) |
D(int16, sse2) |
av_cold void swri_rematrix_init_x86(struct SwrContext *s){ |
int mm_flags = av_get_cpu_flags(); |
int nb_in = av_get_channel_layout_nb_channels(s->in_ch_layout); |
int nb_out = av_get_channel_layout_nb_channels(s->out_ch_layout); |
int num = nb_in * nb_out; |
int i,j; |
s->mix_1_1_simd = NULL; |
s->mix_2_1_simd = NULL; |
if (s->midbuf.fmt == AV_SAMPLE_FMT_S16P){ |
if(mm_flags & AV_CPU_FLAG_MMX) { |
s->mix_1_1_simd = ff_mix_1_1_a_int16_mmx; |
s->mix_2_1_simd = ff_mix_2_1_a_int16_mmx; |
} |
if(mm_flags & AV_CPU_FLAG_SSE2) { |
s->mix_1_1_simd = ff_mix_1_1_a_int16_sse2; |
s->mix_2_1_simd = ff_mix_2_1_a_int16_sse2; |
} |
s->native_simd_matrix = av_mallocz(2 * num * sizeof(int16_t)); |
s->native_simd_one = av_mallocz(2 * sizeof(int16_t)); |
for(i=0; i<nb_out; i++){ |
int sh = 0; |
for(j=0; j<nb_in; j++) |
sh = FFMAX(sh, FFABS(((int*)s->native_matrix)[i * nb_in + j])); |
sh = FFMAX(av_log2(sh) - 14, 0); |
for(j=0; j<nb_in; j++) { |
((int16_t*)s->native_simd_matrix)[2*(i * nb_in + j)+1] = 15 - sh; |
((int16_t*)s->native_simd_matrix)[2*(i * nb_in + j)] = |
((((int*)s->native_matrix)[i * nb_in + j]) + (1<<sh>>1)) >> sh; |
} |
} |
((int16_t*)s->native_simd_one)[1] = 14; |
((int16_t*)s->native_simd_one)[0] = 16384; |
} else if(s->midbuf.fmt == AV_SAMPLE_FMT_FLTP){ |
if(mm_flags & AV_CPU_FLAG_SSE) { |
s->mix_1_1_simd = ff_mix_1_1_a_float_sse; |
s->mix_2_1_simd = ff_mix_2_1_a_float_sse; |
} |
if(HAVE_AVX_EXTERNAL && mm_flags & AV_CPU_FLAG_AVX) { |
s->mix_1_1_simd = ff_mix_1_1_a_float_avx; |
s->mix_2_1_simd = ff_mix_2_1_a_float_avx; |
} |
s->native_simd_matrix = av_mallocz(num * sizeof(float)); |
memcpy(s->native_simd_matrix, s->native_matrix, num * sizeof(float)); |
s->native_simd_one = av_mallocz(sizeof(float)); |
memcpy(s->native_simd_one, s->native_one, sizeof(float)); |
} |
} |