audioconvert.c 8.43 KB
Newer Older
1
/*
Michael Niedermayer's avatar
Michael Niedermayer committed
2
 * audio conversion
3 4
 * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
 *
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.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13 14 15 16 17
 * 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
18
 * License along with FFmpeg; if not, write to the Free Software
19 20 21 22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
23
 * @file libavcodec/audioconvert.c
Michael Niedermayer's avatar
Michael Niedermayer committed
24
 * audio conversion
25 26 27
 * @author Michael Niedermayer <michaelni@gmx.at>
 */

28
#include "libavutil/avstring.h"
29
#include "avcodec.h"
30 31 32 33 34 35 36 37 38 39 40 41
#include "audioconvert.h"

typedef struct SampleFmtInfo {
    const char *name;
    int bits;
} SampleFmtInfo;

/** this table gives more information about formats */
static const SampleFmtInfo sample_fmt_info[SAMPLE_FMT_NB] = {
    [SAMPLE_FMT_U8]  = { .name = "u8",  .bits = 8 },
    [SAMPLE_FMT_S16] = { .name = "s16", .bits = 16 },
    [SAMPLE_FMT_S32] = { .name = "s32", .bits = 32 },
Peter Ross's avatar
Peter Ross committed
42 43
    [SAMPLE_FMT_FLT] = { .name = "flt", .bits = 32 },
    [SAMPLE_FMT_DBL] = { .name = "dbl", .bits = 64 },
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
};

const char *avcodec_get_sample_fmt_name(int sample_fmt)
{
    if (sample_fmt < 0 || sample_fmt >= SAMPLE_FMT_NB)
        return NULL;
    return sample_fmt_info[sample_fmt].name;
}

enum SampleFormat avcodec_get_sample_fmt(const char* name)
{
    int i;

    for (i=0; i < SAMPLE_FMT_NB; i++)
        if (!strcmp(sample_fmt_info[i].name, name))
            return i;
    return SAMPLE_FMT_NONE;
}

void avcodec_sample_fmt_string (char *buf, int buf_size, int sample_fmt)
{
    /* print header */
    if (sample_fmt < 0)
        snprintf (buf, buf_size, "name  " " depth");
    else if (sample_fmt < SAMPLE_FMT_NB) {
        SampleFmtInfo info= sample_fmt_info[sample_fmt];
        snprintf (buf, buf_size, "%-6s" "   %2d ", info.name, info.bits);
    }
}
73

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
static const char* const channel_names[]={
    "FL", "FR", "FC", "LFE", "BL",  "BR",  "FLC", "FRC",
    "BC", "SL", "SR", "TC",  "TFL", "TFC", "TFR", "TBL",
    "TBC", "TBR",
    [29] = "DL",
    [30] = "DR",
};

const char *get_channel_name(int channel_id)
{
    if (channel_id<0 || channel_id>=FF_ARRAY_ELEMS(channel_names))
        return NULL;
    return channel_names[channel_id];
}

int64_t avcodec_guess_channel_layout(int nb_channels, enum CodecID codec_id, const char *fmt_name)
{
    switch(nb_channels) {
92 93 94 95 96 97 98
    case 1: return CH_LAYOUT_MONO;
    case 2: return CH_LAYOUT_STEREO;
    case 3: return CH_LAYOUT_SURROUND;
    case 4: return CH_LAYOUT_QUAD;
    case 5: return CH_LAYOUT_5POINT0;
    case 6: return CH_LAYOUT_5POINT1;
    case 8: return CH_LAYOUT_7POINT1;
99 100 101 102 103 104 105 106
    default: return 0;
    }
}

static const struct {
    const char *name;
    int         nb_channels;
    int64_t     layout;
Carl Eugen Hoyos's avatar
Carl Eugen Hoyos committed
107
} channel_layout_map[] = {
108 109 110 111 112 113 114 115 116 117
    { "mono",        1,  CH_LAYOUT_MONO },
    { "stereo",      2,  CH_LAYOUT_STEREO },
    { "surround",    3,  CH_LAYOUT_SURROUND },
    { "quad",        4,  CH_LAYOUT_QUAD },
    { "5.0",         5,  CH_LAYOUT_5POINT0 },
    { "5.1",         6,  CH_LAYOUT_5POINT1 },
    { "5.1+downmix", 8,  CH_LAYOUT_5POINT1|CH_LAYOUT_STEREO_DOWNMIX, },
    { "7.1",         8,  CH_LAYOUT_7POINT1 },
    { "7.1(wide)",   8,  CH_LAYOUT_7POINT1_WIDE },
    { "7.1+downmix", 10, CH_LAYOUT_7POINT1|CH_LAYOUT_STEREO_DOWNMIX, },
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    { 0 }
};

void avcodec_get_channel_layout_string(char *buf, int buf_size, int nb_channels, int64_t channel_layout)
{
    int i;

    if (channel_layout==0)
        channel_layout = avcodec_guess_channel_layout(nb_channels, CODEC_ID_NONE, NULL);

    for (i=0; channel_layout_map[i].name; i++)
        if (nb_channels    == channel_layout_map[i].nb_channels &&
            channel_layout == channel_layout_map[i].layout) {
            snprintf(buf, buf_size, channel_layout_map[i].name);
            return;
        }

    snprintf(buf, buf_size, "%d channels", nb_channels);
    if (channel_layout) {
        int i,ch;
        av_strlcat(buf, " (", buf_size);
        for(i=0,ch=0; i<64; i++) {
            if ((channel_layout & (1L<<i))) {
                const char *name = get_channel_name(i);
                if (name) {
                    if (ch>0) av_strlcat(buf, "|", buf_size);
                    av_strlcat(buf, name, buf_size);
                }
                ch++;
            }
        }
        av_strlcat(buf, ")", buf_size);
    }
}

153 154 155 156 157 158 159
struct AVAudioConvert {
    int in_channels, out_channels;
    int fmt_pair;
};

AVAudioConvert *av_audio_convert_alloc(enum SampleFormat out_fmt, int out_channels,
                                       enum SampleFormat in_fmt, int in_channels,
160
                                       const float *matrix, int flags)
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
{
    AVAudioConvert *ctx;
    if (in_channels!=out_channels)
        return NULL;  /* FIXME: not supported */
    ctx = av_malloc(sizeof(AVAudioConvert));
    if (!ctx)
        return NULL;
    ctx->in_channels = in_channels;
    ctx->out_channels = out_channels;
    ctx->fmt_pair = out_fmt + SAMPLE_FMT_NB*in_fmt;
    return ctx;
}

void av_audio_convert_free(AVAudioConvert *ctx)
{
    av_free(ctx);
}

int av_audio_convert(AVAudioConvert *ctx,
                           void * const out[6], const int out_stride[6],
                     const void * const  in[6], const int  in_stride[6], int len)
{
183 184 185 186
    int ch;

    //FIXME optimize common cases

187 188 189
    for(ch=0; ch<ctx->out_channels; ch++){
        const int is=  in_stride[ch];
        const int os= out_stride[ch];
190
        const uint8_t *pi=  in[ch];
191
        uint8_t *po= out[ch];
192
        uint8_t *end= po + os*len;
193 194 195 196
        if(!out[ch])
            continue;

#define CONV(ofmt, otype, ifmt, expr)\
197
if(ctx->fmt_pair == ofmt + SAMPLE_FMT_NB*ifmt){\
198 199 200 201 202
    do{\
        *(otype*)po = expr; pi += is; po += os;\
    }while(po < end);\
}

Diego Biurrun's avatar
Diego Biurrun committed
203 204
//FIXME put things below under ifdefs so we do not waste space for cases no codec will need
//FIXME rounding and clipping ?
205

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
             CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_U8 ,  *(const uint8_t*)pi)
        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<8)
        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<24)
        else CONV(SAMPLE_FMT_FLT, float  , SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7)))
        else CONV(SAMPLE_FMT_DBL, double , SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7)))
        else CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_S16, (*(const int16_t*)pi>>8) + 0x80)
        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_S16,  *(const int16_t*)pi)
        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_S16,  *(const int16_t*)pi<<16)
        else CONV(SAMPLE_FMT_FLT, float  , SAMPLE_FMT_S16,  *(const int16_t*)pi*(1.0 / (1<<15)))
        else CONV(SAMPLE_FMT_DBL, double , SAMPLE_FMT_S16,  *(const int16_t*)pi*(1.0 / (1<<15)))
        else CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_S32, (*(const int32_t*)pi>>24) + 0x80)
        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_S32,  *(const int32_t*)pi>>16)
        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_S32,  *(const int32_t*)pi)
        else CONV(SAMPLE_FMT_FLT, float  , SAMPLE_FMT_S32,  *(const int32_t*)pi*(1.0 / (1<<31)))
        else CONV(SAMPLE_FMT_DBL, double , SAMPLE_FMT_S32,  *(const int32_t*)pi*(1.0 / (1<<31)))
        else CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_FLT, lrintf(*(const float*)pi * (1<<7)) + 0x80)
        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_FLT, lrintf(*(const float*)pi * (1<<15)))
        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_FLT, lrintf(*(const float*)pi * (1<<31)))
        else CONV(SAMPLE_FMT_FLT, float  , SAMPLE_FMT_FLT, *(const float*)pi)
        else CONV(SAMPLE_FMT_DBL, double , SAMPLE_FMT_FLT, *(const float*)pi)
        else CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_DBL, lrint(*(const double*)pi * (1<<7)) + 0x80)
        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_DBL, lrint(*(const double*)pi * (1<<15)))
        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_DBL, lrint(*(const double*)pi * (1<<31)))
        else CONV(SAMPLE_FMT_FLT, float  , SAMPLE_FMT_DBL, *(const double*)pi)
        else CONV(SAMPLE_FMT_DBL, double , SAMPLE_FMT_DBL, *(const double*)pi)
231 232 233 234
        else return -1;
    }
    return 0;
}