resample.c 6.89 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1
/*
Diego Biurrun's avatar
Diego Biurrun committed
2
 * samplerate conversion for both audio and video
3
 * Copyright (c) 2000 Fabrice Bellard.
Fabrice Bellard's avatar
Fabrice Bellard committed
4
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Fabrice Bellard's avatar
Fabrice Bellard committed
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Fabrice Bellard's avatar
Fabrice Bellard committed
20
 */
Michael Niedermayer's avatar
Michael Niedermayer committed
21 22 23

/**
 * @file resample.c
Diego Biurrun's avatar
Diego Biurrun committed
24
 * samplerate conversion for both audio and video
Michael Niedermayer's avatar
Michael Niedermayer committed
25 26
 */

Fabrice Bellard's avatar
Fabrice Bellard committed
27
#include "avcodec.h"
28

29
struct AVResampleContext;
Fabrice Bellard's avatar
Fabrice Bellard committed
30 31

struct ReSampleContext {
32 33 34
    struct AVResampleContext *resample_context;
    short *temp[2];
    int temp_len;
Fabrice Bellard's avatar
Fabrice Bellard committed
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
    float ratio;
    /* channel convert */
    int input_channels, output_channels, filter_channels;
};

/* n1: number of samples */
static void stereo_to_mono(short *output, short *input, int n1)
{
    short *p, *q;
    int n = n1;

    p = input;
    q = output;
    while (n >= 4) {
        q[0] = (p[0] + p[1]) >> 1;
        q[1] = (p[2] + p[3]) >> 1;
        q[2] = (p[4] + p[5]) >> 1;
        q[3] = (p[6] + p[7]) >> 1;
        q += 4;
        p += 8;
        n -= 4;
    }
    while (n > 0) {
        q[0] = (p[0] + p[1]) >> 1;
        q++;
        p += 2;
        n--;
    }
}

/* n1: number of samples */
static void mono_to_stereo(short *output, short *input, int n1)
{
    short *p, *q;
    int n = n1;
    int v;

    p = input;
    q = output;
    while (n >= 4) {
        v = p[0]; q[0] = v; q[1] = v;
        v = p[1]; q[2] = v; q[3] = v;
        v = p[2]; q[4] = v; q[5] = v;
        v = p[3]; q[6] = v; q[7] = v;
        q += 8;
        p += 4;
        n -= 4;
    }
    while (n > 0) {
        v = p[0]; q[0] = v; q[1] = v;
        q += 2;
        p += 1;
        n--;
    }
}

/* XXX: should use more abstract 'N' channels system */
static void stereo_split(short *output1, short *output2, short *input, int n)
{
    int i;

    for(i=0;i<n;i++) {
        *output1++ = *input++;
        *output2++ = *input++;
    }
}

static void stereo_mux(short *output, short *input1, short *input2, int n)
{
    int i;

    for(i=0;i<n;i++) {
        *output++ = *input1++;
        *output++ = *input2++;
    }
}

112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
static void ac3_5p1_mux(short *output, short *input1, short *input2, int n)
{
    int i;
    short l,r;

    for(i=0;i<n;i++) {
      l=*input1++;
      r=*input2++;
      *output++ = l;           /* left */
      *output++ = (l/2)+(r/2); /* center */
      *output++ = r;           /* right */
      *output++ = 0;           /* left surround */
      *output++ = 0;           /* right surroud */
      *output++ = 0;           /* low freq */
    }
}

129
ReSampleContext *audio_resample_init(int output_channels, int input_channels,
Fabrice Bellard's avatar
Fabrice Bellard committed
130 131 132
                                      int output_rate, int input_rate)
{
    ReSampleContext *s;
133

134 135
    if ( input_channels > 2)
      {
136 137
        av_log(NULL, AV_LOG_ERROR, "Resampling with input channels greater than 2 unsupported.");
        return NULL;
138
      }
Fabrice Bellard's avatar
Fabrice Bellard committed
139 140 141

    s = av_mallocz(sizeof(ReSampleContext));
    if (!s)
142
      {
143 144
        av_log(NULL, AV_LOG_ERROR, "Can't allocate memory for resample context.");
        return NULL;
145
      }
Fabrice Bellard's avatar
Fabrice Bellard committed
146 147

    s->ratio = (float)output_rate / (float)input_rate;
148

Fabrice Bellard's avatar
Fabrice Bellard committed
149 150
    s->input_channels = input_channels;
    s->output_channels = output_channels;
151

Fabrice Bellard's avatar
Fabrice Bellard committed
152 153 154 155
    s->filter_channels = s->input_channels;
    if (s->output_channels < s->filter_channels)
        s->filter_channels = s->output_channels;

156 157 158 159 160 161 162 163
/*
 * ac3 output is the only case where filter_channels could be greater than 2.
 * input channels can't be greater than 2, so resample the 2 channels and then
 * expand to 6 channels after the resampling.
 */
    if(s->filter_channels>2)
      s->filter_channels = 2;

164 165
#define TAPS 16
    s->resample_context= av_resample_init(output_rate, input_rate, TAPS, 10, 0, 0.8);
166

Fabrice Bellard's avatar
Fabrice Bellard committed
167 168 169 170 171 172 173 174
    return s;
}

/* resample audio. 'nb_samples' is the number of input samples */
/* XXX: optimize it ! */
int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples)
{
    int i, nb_samples1;
Fabrice Bellard's avatar
Fabrice Bellard committed
175 176
    short *bufin[2];
    short *bufout[2];
Fabrice Bellard's avatar
Fabrice Bellard committed
177
    short *buftmp2[2], *buftmp3[2];
Fabrice Bellard's avatar
Fabrice Bellard committed
178
    int lenout;
Fabrice Bellard's avatar
Fabrice Bellard committed
179

180
    if (s->input_channels == s->output_channels && s->ratio == 1.0 && 0) {
Fabrice Bellard's avatar
Fabrice Bellard committed
181 182 183 184 185
        /* nothing to do */
        memcpy(output, input, nb_samples * s->input_channels * sizeof(short));
        return nb_samples;
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
186
    /* XXX: move those malloc to resample init code */
187 188 189 190 191
    for(i=0; i<s->filter_channels; i++){
        bufin[i]= (short*) av_malloc( (nb_samples + s->temp_len) * sizeof(short) );
        memcpy(bufin[i], s->temp[i], s->temp_len * sizeof(short));
        buftmp2[i] = bufin[i] + s->temp_len;
    }
192

Fabrice Bellard's avatar
Fabrice Bellard committed
193
    /* make some zoom to avoid round pb */
194
    lenout= (int)(4*nb_samples * s->ratio) + 16;
195 196
    bufout[0]= (short*) av_malloc( lenout * sizeof(short) );
    bufout[1]= (short*) av_malloc( lenout * sizeof(short) );
Fabrice Bellard's avatar
Fabrice Bellard committed
197

Fabrice Bellard's avatar
Fabrice Bellard committed
198 199 200 201
    if (s->input_channels == 2 &&
        s->output_channels == 1) {
        buftmp3[0] = output;
        stereo_to_mono(buftmp2[0], input, nb_samples);
202
    } else if (s->output_channels >= 2 && s->input_channels == 1) {
Fabrice Bellard's avatar
Fabrice Bellard committed
203
        buftmp3[0] = bufout[0];
204
        memcpy(buftmp2[0], input, nb_samples*sizeof(short));
205
    } else if (s->output_channels >= 2) {
Fabrice Bellard's avatar
Fabrice Bellard committed
206 207 208 209 210
        buftmp3[0] = bufout[0];
        buftmp3[1] = bufout[1];
        stereo_split(buftmp2[0], buftmp2[1], input, nb_samples);
    } else {
        buftmp3[0] = output;
211
        memcpy(buftmp2[0], input, nb_samples*sizeof(short));
Fabrice Bellard's avatar
Fabrice Bellard committed
212 213
    }

214 215
    nb_samples += s->temp_len;

Fabrice Bellard's avatar
Fabrice Bellard committed
216 217 218
    /* resample each channel */
    nb_samples1 = 0; /* avoid warning */
    for(i=0;i<s->filter_channels;i++) {
219 220 221 222 223 224 225
        int consumed;
        int is_last= i+1 == s->filter_channels;

        nb_samples1 = av_resample(s->resample_context, buftmp3[i], bufin[i], &consumed, nb_samples, lenout, is_last);
        s->temp_len= nb_samples - consumed;
        s->temp[i]= av_realloc(s->temp[i], s->temp_len*sizeof(short));
        memcpy(s->temp[i], bufin[i] + consumed, s->temp_len*sizeof(short));
Fabrice Bellard's avatar
Fabrice Bellard committed
226 227 228 229 230 231
    }

    if (s->output_channels == 2 && s->input_channels == 1) {
        mono_to_stereo(output, buftmp3[0], nb_samples1);
    } else if (s->output_channels == 2) {
        stereo_mux(output, buftmp3[0], buftmp3[1], nb_samples1);
232 233
    } else if (s->output_channels == 6) {
        ac3_5p1_mux(output, buftmp3[0], buftmp3[1], nb_samples1);
Fabrice Bellard's avatar
Fabrice Bellard committed
234 235
    }

Michael Niedermayer's avatar
Michael Niedermayer committed
236 237
    for(i=0; i<s->filter_channels; i++)
        av_free(bufin[i]);
Fabrice Bellard's avatar
Fabrice Bellard committed
238

239 240
    av_free(bufout[0]);
    av_free(bufout[1]);
Fabrice Bellard's avatar
Fabrice Bellard committed
241 242 243 244 245
    return nb_samples1;
}

void audio_resample_close(ReSampleContext *s)
{
246 247 248
    av_resample_close(s->resample_context);
    av_freep(&s->temp[0]);
    av_freep(&s->temp[1]);
249
    av_free(s);
Fabrice Bellard's avatar
Fabrice Bellard committed
250
}