resample.c 6.85 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1 2
/*
 * Sample rate convertion for both audio and video
3
 * Copyright (c) 2000 Fabrice Bellard.
Fabrice Bellard's avatar
Fabrice Bellard committed
4
 *
5 6 7 8
 * 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 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
9
 *
10
 * This library is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Fabrice Bellard's avatar
Fabrice Bellard committed
14
 *
15 16 17
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Fabrice Bellard's avatar
Fabrice Bellard committed
18
 */
Michael Niedermayer's avatar
Michael Niedermayer committed
19 20 21 22 23 24

/**
 * @file resample.c
 * Sample rate convertion for both audio and video.
 */

Fabrice Bellard's avatar
Fabrice Bellard committed
25
#include "avcodec.h"
26

27
struct AVResampleContext;
Fabrice Bellard's avatar
Fabrice Bellard committed
28 29

struct ReSampleContext {
30 31 32
    struct AVResampleContext *resample_context;
    short *temp[2];
    int temp_len;
Fabrice Bellard's avatar
Fabrice Bellard committed
33 34 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
    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++;
    }
}

110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
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 */
    }
}

Fabrice Bellard's avatar
Fabrice Bellard committed
127 128 129 130 131
ReSampleContext *audio_resample_init(int output_channels, int input_channels, 
                                      int output_rate, int input_rate)
{
    ReSampleContext *s;
    
132 133
    if ( input_channels > 2)
      {
134
	av_log(NULL, AV_LOG_ERROR, "Resampling with input channels greater than 2 unsupported.");
135 136
	return NULL;
      }
Fabrice Bellard's avatar
Fabrice Bellard committed
137 138 139

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

    s->ratio = (float)output_rate / (float)input_rate;
    
    s->input_channels = input_channels;
    s->output_channels = output_channels;
    
    s->filter_channels = s->input_channels;
    if (s->output_channels < s->filter_channels)
        s->filter_channels = s->output_channels;

154 155 156 157 158 159 160 161
/*
 * 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;

162
    s->resample_context= av_resample_init(output_rate, input_rate, 16, 10, 0, 1.0);
163
    
Fabrice Bellard's avatar
Fabrice Bellard committed
164 165 166 167 168 169 170 171
    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
172 173
    short *bufin[2];
    short *bufout[2];
Fabrice Bellard's avatar
Fabrice Bellard committed
174
    short *buftmp2[2], *buftmp3[2];
Fabrice Bellard's avatar
Fabrice Bellard committed
175
    int lenout;
Fabrice Bellard's avatar
Fabrice Bellard committed
176

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

Fabrice Bellard's avatar
Fabrice Bellard committed
183
    /* XXX: move those malloc to resample init code */
184 185 186 187 188
    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;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
189 190 191
    
    /* make some zoom to avoid round pb */
    lenout= (int)(nb_samples * s->ratio) + 16;
192 193
    bufout[0]= (short*) av_malloc( lenout * sizeof(short) );
    bufout[1]= (short*) av_malloc( lenout * sizeof(short) );
Fabrice Bellard's avatar
Fabrice Bellard committed
194

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

211 212
    nb_samples += s->temp_len;

Fabrice Bellard's avatar
Fabrice Bellard committed
213 214 215
    /* resample each channel */
    nb_samples1 = 0; /* avoid warning */
    for(i=0;i<s->filter_channels;i++) {
216 217 218 219 220 221 222
        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
223 224 225 226 227 228
    }

    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);
229 230
    } else if (s->output_channels == 6) {
        ac3_5p1_mux(output, buftmp3[0], buftmp3[1], nb_samples1);
Fabrice Bellard's avatar
Fabrice Bellard committed
231 232
    }

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

236 237
    av_free(bufout[0]);
    av_free(bufout[1]);
Fabrice Bellard's avatar
Fabrice Bellard committed
238 239 240 241 242
    return nb_samples1;
}

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