GSM6.10转码与wav文件保存

1、编码说明

gsm6.10编码:

        gsm6.10是GSM通信网络的标准编码方式,才有8KHZ采样率,每20ms生成一个语音包,每个样本可以分为13位A率或者14位u率的16位PCM编码,每个采样生成的数据量为8000×20/1000×16=2560bits的原始数据,通过gsm编码器压缩为260bits的GSM帧,压缩后的数据率为1625byte,相当于13kbps,由于260位(32.5byte)的gsm帧不是8位的整数倍,因此编码器输出的GSM帧为264位的线性PCM码,即33个byte。

        采样频率为8 kHz、每个样本为16位的未压缩的话音数据率为128 kbps,使用GSM压缩后的数据率为: (264bit×8000样本/s) / 160样本 = 13.2 kbps。GSM的压缩比:128:13.2 = 9.7,近似于10:1。

2、wav文件头部封装信息:

         编码包括了两方面内容,一是按一定格式存储数据,二是采用一定的算法压缩数据。WAV格式对音频流的编码没有硬性规定,支持非压缩的PCM(Puls Code Modulation)脉冲编码调制格式,还支持压缩型的微软自适应分脉冲编码调制Microsoft ADPCM(Adaptive Differential Puls Code Modulation)、国际电报联盟(International Telegraph Union)制定的语音压缩标准ITUG.711 a-law、ITU G.711-law、IMA ADPCM、ITU G.723 ADPCM (Yamaha)、GSM 6.10、ITU G.721 ADPCM编码和其它压缩算法。MP3编码同样也可以运用在WAV中,只要安装相应的Decode,就可以播放WAV中的MP3音乐。

参考:参考WAV文件格式说明

3、编解码参考代码库:

        gsm6.10编码每个为33byte,两个为66byte,在写入到wav中时需要将其中一个去掉一个byte,合并为65byte,同时需要设定GSM_OPT_WAV49格式,才能满足;

        gsm6.10编码直接转换为rtp数据包时,字节截断的过程。

gsm编解码库

wav文件测试文件

4、gsm6.10转换为wav文件的参考代码:

 

gsm转为wav文件参考代码

/* makewave.c -- Read Sun .au and write GSM-containing MS wave file */

/*
 *  Copyright (C) 1996 Jeffrey Chilton
 *
 *  Permission is granted to anyone to make or distribute copies of
 *  this program, in any medium, provided that the copyright notice
 *  and permission notice are preserved, and that the distributor
 *  grants the recipient permission for further redistribution as
 *  permitted by this notice.
 *  
 *  Author's E-mail address:  jwc@chilton.com
 *  
 */

#include <stdio.h>

#include "gsm.h"

extern unsigned short MuLaw_Linear[];

#define MULAW_ZERO 255

int F_wav_fmt = 1;

long read_header(FILE *);
int write_header(long, FILE *);

#define BLOCK_SIZE 160

main(argc, argv)
int argc;
char *argv[];
{
    register int i;
    FILE *sfp;
    FILE *dfp;
    gsm handle;
    long samples;
    long data_size;
    long total_out;
    unsigned char mulaw[2 * BLOCK_SIZE];
    gsm_signal linear[2 * BLOCK_SIZE];
    gsm_frame frame;                          
    int	out_size;
    int rc;

    if (argc != 2)
    {
	fprintf(stderr, "usage: %s <.au file>\n", argv[0]);
	exit(1);
    }
 
    sfp = fopen(argv[1], "r");
    if (!sfp)
    {
	perror("open fails");
	exit(1);
    }

    /* Read .au file header info and calulate output size */

    samples = read_header(sfp);
    data_size = ((samples + (2 * BLOCK_SIZE - 1)) / (2 * BLOCK_SIZE));
    data_size *= 2 * sizeof (frame) - 1;

/*
fprintf(stderr, "samples from header: 0x%x\n", samples);
fprintf(stderr, "calculated data size: 0x%x\n", data_size);
*/

    dfp = stdout;

    /* Create the GSM codec object and option it for wave framing */

    handle = gsm_create();
    if (!handle)
    {
	perror("cannot create gsm codec");
	exit(1);
    }

    (void )gsm_option(handle, GSM_OPT_WAV49, &F_wav_fmt);

    /* Write the .wav file header */

    rc = write_header(data_size, dfp);
    if (rc)
    {
	perror("error writing header");
	exit(1);
    }

    /* Compress the audio */

    total_out = 0;
    while (samples > 0)
    {
	/* Read two frames worth of samples and convert to linear */

	rc = fread(mulaw, (size_t )1, sizeof (mulaw), sfp);
	if (rc < 0)
	{
	    perror("error reading input");
	    exit(1);
	}
	samples -= rc;
	if (rc < sizeof (mulaw))
	{
	    memset((char *)mulaw + rc, MULAW_ZERO, sizeof (mulaw) - rc);
	}
	for (i = 0; i < sizeof (mulaw); i++)
	{
	    linear[i] = MuLaw_Linear[mulaw[i]];
	}

	/* Encode the even half and write short (32-byte) frame */

	gsm_encode(handle, &linear[0], frame);
	out_size = sizeof (frame) - 1;
	rc = fwrite(frame, (size_t )1, out_size, dfp);
	if (rc != out_size)
	{
	    perror("error writing output");
	    exit(1);
	}
	total_out += rc;

	/* Encode the odd half and write long (33-byte) frame */

	gsm_encode(handle, &linear[160], frame);
	out_size = sizeof (frame);
	rc = fwrite(frame, (size_t )1, out_size, dfp);
	if (rc != out_size)
	{
	    perror("error writing output");
	    exit(1);
	}
	total_out += rc;
    }

    /* Pad output to even number of bytes */

    if (total_out & 0x1)
    {
	frame[0] = 0x00;
	rc = fwrite(frame, (size_t )1, 1, dfp);
	if (rc != 1)
	{
	    perror("error writing output");
	    exit(1);
	}
	total_out += rc;
    }

/*
fprintf(stderr, "total bytes written: 0x%lx\n", total_out);
*/

    /* Clean up */

    gsm_destroy(handle);
                                                                             
}

/* read_header - read Sun .au file header */

static long
getlong(fp)
FILE *fp;
{
    long  l;

    l = 0;
    l = (l << 8) | 0xFF & getc(fp);
    l = (l << 8) | 0xFF & getc(fp);
    l = (l << 8) | 0xFF & getc(fp);
    l = (l << 8) | 0xFF & getc(fp);

    return l;

}

#define	AU_FILE_MAGIC 0x2e736e64
#define	AU_FILE_MULAW_8 1
#define SAMPLE_RATE 8000
#define SAMPLE_CHANNELS 1

long
read_header(fp)
FILE *fp;
{
    long magic;
    long header_size;
    long data_size;
    long code;
    long rate;
    long n_chan;
    int rc;

    magic = getlong(fp);
    if (magic != AU_FILE_MAGIC)
    {
	fprintf(stderr, "input is not an audio file\n");
	rc = -1;
	goto out;
    }

    header_size = getlong(fp);
    data_size = getlong(fp);
    code = getlong(fp);
    rate = getlong(fp);
    n_chan = getlong(fp);

    header_size -= 24;
    while (header_size)
    {
	(void )getc(fp);
	header_size--;
    }

    if (code != AU_FILE_MULAW_8 ||
	rate != SAMPLE_RATE ||
	n_chan != SAMPLE_CHANNELS)
    {
	fprintf(stderr, "input must by mu-law 8KHz mono\n");
	rc = 01;
	goto out;
    }

    rc = data_size;

out:

    return rc;

}

unsigned short MuLaw_Linear[] = {
    33280, 34308, 35336, 36364, 37393, 38421, 39449, 40477,
    41505, 42534, 43562, 44590, 45618, 46647, 47675, 48703,
    49474, 49988, 50503, 51017, 51531, 52045, 52559, 53073,
    53587, 54101, 54616, 55130, 55644, 56158, 56672, 57186,
    57572, 57829, 58086, 58343, 58600, 58857, 59114, 59371,
    59628, 59885, 60142, 60399, 60656, 60913, 61171, 61428,
    61620, 61749, 61877, 62006, 62134, 62263, 62392, 62520,
    62649, 62777, 62906, 63034, 63163, 63291, 63420, 63548,
    63645, 63709, 63773, 63838, 63902, 63966, 64030, 64095,
    64159, 64223, 64287, 64352, 64416, 64480, 64544, 64609,
    64657, 64689, 64721, 64753, 64785, 64818, 64850, 64882,
    64914, 64946, 64978, 65010, 65042, 65075, 65107, 65139,
    65163, 65179, 65195, 65211, 65227, 65243, 65259, 65275,
    65291, 65308, 65324, 65340, 65356, 65372, 65388, 65404,
    65416, 65424, 65432, 65440, 65448, 65456, 65464, 65472,
    65480, 65488, 65496, 65504, 65512, 65520, 65528,     0,
    32256, 31228, 30200, 29172, 28143, 27115, 26087, 25059,
    24031, 23002, 21974, 20946, 19918, 18889, 17861, 16833,
    16062, 15548, 15033, 14519, 14005, 13491, 12977, 12463,
    11949, 11435, 10920, 10406,  9892,  9378,  8864,  8350,
     7964,  7707,  7450,  7193,  6936,  6679,  6422,  6165, 
     5908,  5651,  5394,  5137,  4880,  4623,  4365,  4108, 
     3916,  3787,  3659,  3530,  3402,  3273,  3144,  3016, 
     2887,  2759,  2630,  2502,  2373,  2245,  2116,  1988, 
     1891,  1827,  1763,  1698,  1634,  1570,  1506,  1441, 
     1377,  1313,  1249,  1184,  1120,  1056,   992,   927, 
      879,   847,   815,   783,   751,   718,   686,   654,
      622,   590,   558,   526,   494,   461,   429,   397,
      373,   357,   341,   325,   309,   293,   277,   261,
      245,   228,   212,   196,   180,   164,   148,   132,
      120,   112,   104,    96,    88,    80,    72,    64,
       56,    48,    40,    32,    24,    16,    8,      0
    };

/* write_header - write (approximation of) MS wave file header */

static int
fputlong(x, fp)
long x;
FILE *fp;
{
    return fputc(x & 0xFF, fp) == EOF ||
	fputc((x >> 8) & 0xFF, fp) == EOF ||
	fputc((x >> 16) & 0xFF, fp) == EOF ||
	fputc((x >> 24) & 0xFF, fp) == EOF;
}

static int
fputshort(x, fp)
short x;
FILE *fp;
{
    return fputc(x & 0xFF, fp) == EOF ||
	fputc((x >> 8) & 0xFF, fp) == EOF;
}

#define WAVE_HS 20
#define FACT_HS 4

#define GSM_FMT 49		/* Format code number		*/
#define N_CHAN 1		/* Number of channels (mono)	*/
#define SAMP_FREQ 8000		/* Uncompressed samples/second	*/
#define BYTE_FREQ 1625		/* Compressed bytes/second	*/
#define X_1 65			/* Unknown format-specific 	*/
#define X_2 2			/* Unknown format-specific 	*/
#define X_3 320			/* Unknown format-specific 	*/

#define Y_1 20160		/* Unknown "fact" value		*/

int 
write_header(data_size, fp)
long data_size;
FILE *fp;
{
    unsigned short s;
    int rc;

    rc = 0;
    rc |= fputs("RIFF", fp) == EOF;
    rc |= fputlong(52 + ((data_size + 1) & ~0x1), fp);

    rc |= fputs("WAVEfmt ", fp) == EOF;
    rc |= fputlong(WAVE_HS, fp);
    rc |= fputshort(GSM_FMT, fp);
    rc |= fputshort(N_CHAN, fp);
    rc |= fputlong(SAMP_FREQ, fp);
    rc |= fputlong(BYTE_FREQ, fp);
    rc |= fputlong(X_1, fp);
    rc |= fputshort(X_2, fp);
    rc |= fputshort(X_3, fp);

    rc |= fputs("fact", fp) == EOF;
    rc |= fputlong(FACT_HS, fp);
    rc |= fputlong(Y_1, fp);

    rc |= fputs("data", fp) == EOF;
    rc |= fputlong(data_size, fp);

    return rc;
}



gsm6.10的wav文件解码到pcm16参考代码

/*
    2  * Interface to libgsm for gsm encoding/decoding
    3  * Copyright (c) 2005 Alban Bedel <albeu@free.fr>
    4  * Copyright (c) 2006, 2007 Michel Bardiaux <mbardiaux@mediaxim.be>
    5  *
    6  * This file is part of FFmpeg.
    7  *
    8  * FFmpeg is free software; you can redistribute it and/or
    9  * modify it under the terms of the GNU Lesser General Public
   10  * License as published by the Free Software Foundation; either
   11  * version 2.1 of the License, or (at your option) any later version.
   12  *
   13  * FFmpeg is distributed in the hope that it will be useful,
   14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   16  * Lesser General Public License for more details.
   17  *
   18  * You should have received a copy of the GNU Lesser General Public
   19  * License along with FFmpeg; if not, write to the Free Software
   20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   21  */
   22 
   23 /**
   24  * @file
   25  * Interface to libgsm for gsm encoding/decoding
   26  */
   27 
   28 // The idiosyncrasies of GSM-in-WAV are explained at http://kbs.cs.tu-berlin.de/~jutta/toast.html
   29 
   30 #include "config.h"
   31 #if HAVE_GSM_H
   32 #include <gsm.h>
   33 #else
   34 #include <gsm/gsm.h>
   35 #endif
   36 
   37 #include "libavutil/channel_layout.h"
   38 #include "libavutil/common.h"
   39 #include "avcodec.h"
   40 #include "internal.h"
   41 #include "gsm.h"
   42 
   43 static av_cold int libgsm_encode_close(AVCodecContext *avctx) {
   44     gsm_destroy(avctx->priv_data);
   45     avctx->priv_data = NULL;
   46     return 0;
   47 }
   48 
   49 static av_cold int libgsm_encode_init(AVCodecContext *avctx) {
   50     if (avctx->channels > 1) {
   51         av_log(avctx, AV_LOG_ERROR, "Mono required for GSM, got %d channels\n",
   52                avctx->channels);
   53         return -1;
   54     }
   55 
   56     if (avctx->sample_rate != 8000) {
   57         av_log(avctx, AV_LOG_ERROR, "Sample rate 8000Hz required for GSM, got %dHz\n",
   58                avctx->sample_rate);
   59         if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL)
   60             return -1;
   61     }
   62     if (avctx->bit_rate != 13000 /* Official */ &&
   63         avctx->bit_rate != 13200 /* Very common */ &&
   64         avctx->bit_rate != 0 /* Unknown; a.o. mov does not set bitrate when decoding */ ) {
   65         av_log(avctx, AV_LOG_ERROR, "Bitrate 13000bps required for GSM, got %dbps\n",
   66                avctx->bit_rate);
   67         if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL)
   68             return -1;
   69     }
   70 
   71     avctx->priv_data = gsm_create();
   72     if (!avctx->priv_data)
   73         goto error;
   74 
   75     switch(avctx->codec_id) {
   76     case AV_CODEC_ID_GSM:
   77         avctx->frame_size = GSM_FRAME_SIZE;
   78         avctx->block_align = GSM_BLOCK_SIZE;
   79         break;
   80     case AV_CODEC_ID_GSM_MS: {
   81         int one = 1;
   82         gsm_option(avctx->priv_data, GSM_OPT_WAV49, &one);
   83         avctx->frame_size = 2*GSM_FRAME_SIZE;
   84         avctx->block_align = GSM_MS_BLOCK_SIZE;
   85         }
   86     }
   87 
   88     return 0;
   89 error:
   90     libgsm_encode_close(avctx);
   91     return -1;
   92 }
   93 
   94 static int libgsm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
   95                                const AVFrame *frame, int *got_packet_ptr)
   96 {
   97     int ret;
   98     gsm_signal *samples = (gsm_signal *)frame->data[0];
   99     struct gsm_state *state = avctx->priv_data;
  100 
  101     if ((ret = ff_alloc_packet2(avctx, avpkt, avctx->block_align)) < 0)
  102         return ret;
  103 
  104     switch(avctx->codec_id) {
  105     case AV_CODEC_ID_GSM:
  106         gsm_encode(state, samples, avpkt->data);
  107         break;
  108     case AV_CODEC_ID_GSM_MS:
  109         gsm_encode(state, samples,                  avpkt->data);
  110         gsm_encode(state, samples + GSM_FRAME_SIZE, avpkt->data + 32);
  111     }
  112 
  113     *got_packet_ptr = 1;
  114     return 0;
  115 }
  116 
  117 
  118 #if CONFIG_LIBGSM_ENCODER
  119 AVCodec ff_libgsm_encoder = {
  120     .name           = "libgsm",
  121     .long_name      = NULL_IF_CONFIG_SMALL("libgsm GSM"),
  122     .type           = AVMEDIA_TYPE_AUDIO,
  123     .id             = AV_CODEC_ID_GSM,
  124     .init           = libgsm_encode_init,
  125     .encode2        = libgsm_encode_frame,
  126     .close          = libgsm_encode_close,
  127     .sample_fmts    = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
  128                                                      AV_SAMPLE_FMT_NONE },
  129 };
  130 #endif
  131 #if CONFIG_LIBGSM_MS_ENCODER
  132 AVCodec ff_libgsm_ms_encoder = {
  133     .name           = "libgsm_ms",
  134     .long_name      = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"),
  135     .type           = AVMEDIA_TYPE_AUDIO,
  136     .id             = AV_CODEC_ID_GSM_MS,
  137     .init           = libgsm_encode_init,
  138     .encode2        = libgsm_encode_frame,
  139     .close          = libgsm_encode_close,
  140     .sample_fmts    = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
  141                                                      AV_SAMPLE_FMT_NONE },
  142 };
  143 #endif
  144 
  145 typedef struct LibGSMDecodeContext {
  146     struct gsm_state *state;
  147 } LibGSMDecodeContext;
  148 
  149 static av_cold int libgsm_decode_init(AVCodecContext *avctx) {
  150     LibGSMDecodeContext *s = avctx->priv_data;
  151 
  152     avctx->channels       = 1;
  153     avctx->channel_layout = AV_CH_LAYOUT_MONO;
  154     if (!avctx->sample_rate)
  155         avctx->sample_rate = 8000;
  156     avctx->sample_fmt     = AV_SAMPLE_FMT_S16;
  157 
  158     s->state = gsm_create();
  159 
  160     switch(avctx->codec_id) {
  161     case AV_CODEC_ID_GSM:
  162         avctx->frame_size  = GSM_FRAME_SIZE;
  163         avctx->block_align = GSM_BLOCK_SIZE;
  164         break;
  165     case AV_CODEC_ID_GSM_MS: {
  166         int one = 1;
  167         gsm_option(s->state, GSM_OPT_WAV49, &one);
  168         avctx->frame_size  = 2 * GSM_FRAME_SIZE;
  169         avctx->block_align = GSM_MS_BLOCK_SIZE;
  170         }
  171     }
  172 
  173     return 0;
  174 }
  175 
  176 static av_cold int libgsm_decode_close(AVCodecContext *avctx) {
  177     LibGSMDecodeContext *s = avctx->priv_data;
  178 
  179     gsm_destroy(s->state);
  180     s->state = NULL;
  181     return 0;
  182 }
  183 
  184 static int libgsm_decode_frame(AVCodecContext *avctx, void *data,
  185                                int *got_frame_ptr, AVPacket *avpkt)
  186 {
  187     int i, ret;
  188     LibGSMDecodeContext *s = avctx->priv_data;
  189     AVFrame *frame         = data;
  190     uint8_t *buf = avpkt->data;
  191     int buf_size = avpkt->size;
  192     int16_t *samples;
  193 
  194     if (buf_size < avctx->block_align) {
  195         av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
  196         return AVERROR_INVALIDDATA;
  197     }
  198 
  199     /* get output buffer */
  200     frame->nb_samples = avctx->frame_size;
  201     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
  202         return ret;
  203     samples = (int16_t *)frame->data[0];
  204 
  205     for (i = 0; i < avctx->frame_size / GSM_FRAME_SIZE; i++) {
  206         if ((ret = gsm_decode(s->state, buf, samples)) < 0)
  207             return -1;
  208         buf     += GSM_BLOCK_SIZE;
  209         samples += GSM_FRAME_SIZE;
  210     }
  211 
  212     *got_frame_ptr = 1;
  213 
  214     return avctx->block_align;
  215 }
  216 
  217 static void libgsm_flush(AVCodecContext *avctx) {
  218     LibGSMDecodeContext *s = avctx->priv_data;
  219     int one = 1;
  220 
  221     gsm_destroy(s->state);
  222     s->state = gsm_create();
  223     if (avctx->codec_id == AV_CODEC_ID_GSM_MS)
  224         gsm_option(s->state, GSM_OPT_WAV49, &one);
  225 }
  226 
  227 #if CONFIG_LIBGSM_DECODER
  228 AVCodec ff_libgsm_decoder = {
  229     .name           = "libgsm",
  230     .long_name      = NULL_IF_CONFIG_SMALL("libgsm GSM"),
  231     .type           = AVMEDIA_TYPE_AUDIO,
  232     .id             = AV_CODEC_ID_GSM,
  233     .priv_data_size = sizeof(LibGSMDecodeContext),
  234     .init           = libgsm_decode_init,
  235     .close          = libgsm_decode_close,
  236     .decode         = libgsm_decode_frame,
  237     .flush          = libgsm_flush,
  238     .capabilities   = CODEC_CAP_DR1,
  239 };
  240 #endif
  241 #if CONFIG_LIBGSM_MS_DECODER
  242 AVCodec ff_libgsm_ms_decoder = {
  243     .name           = "libgsm_ms",
  244     .long_name      = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"),
  245     .type           = AVMEDIA_TYPE_AUDIO,
  246     .id             = AV_CODEC_ID_GSM_MS,
  247     .priv_data_size = sizeof(LibGSMDecodeContext),
  248     .init           = libgsm_decode_init,
  249     .close          = libgsm_decode_close,
  250     .decode         = libgsm_decode_frame,
  251     .flush          = libgsm_flush,
  252     .capabilities   = CODEC_CAP_DR1,
  253 };
  254 #endif

5、转码验证工具

Adobe Audition CS6

WaveCN 2.0.0.5

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值