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 255int F_wav_fmt = 1;long read_header(FILE *);
int write_header(long, FILE *);#define BLOCK_SIZE 160main(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 1long
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/decoding3  * 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/or9  * modify it under the terms of the GNU Lesser General Public10  * License as published by the Free Software Foundation; either11  * 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 of15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU16  * Lesser General Public License for more details.17  *18  * You should have received a copy of the GNU Lesser General Public19  * License along with FFmpeg; if not, write to the Free Software20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA21  */22 23 /**24  * @file25  * Interface to libgsm for gsm encoding/decoding26  */27 28 // The idiosyncrasies of GSM-in-WAV are explained at http://kbs.cs.tu-berlin.de/~jutta/toast.html29 30 #include "config.h"31 #if HAVE_GSM_H32 #include <gsm.h>33 #else34 #include <gsm/gsm.h>35 #endif36 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_ENCODER119 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 #endif131 #if CONFIG_LIBGSM_MS_ENCODER132 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 #endif144 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_DECODER228 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 #endif241 #if CONFIG_LIBGSM_MS_DECODER242 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

GSM6.10转码与wav文件保存相关推荐

  1. C#文字转语音,实时播放以及mp3,wav文件保存

    源码下载地址:https://download.csdn.net/download/horseroll/10500847 无积分付费下载地址:https://download.csdn.net/dow ...

  2. 安卓Android开发:使用AudioRecord录音、将录音保存为wav文件、使用AudioTrack保存录音

    一.使用AudioRrecord录音 1.1声明 首先需要声明一个AudioRecord类的实例.之所以需要事先声明,是因为在本例中,录音的启动和结束被封装在两个不同的方法里.而通常来讲," ...

  3. VC++初步实现保存数据为音频WAV文件

    先行基本知识见此 https://blog.csdn.net/bcbobo21cn/article/details/109087252 win7, vc6:新建一个对话框工程:添加一个文本框:为文本框 ...

  4. 解决使用 AVAudioRecorder 录音保存 .WAV 文件遇到的问题

    问题背景 App 实现录音保存音频文件,并实现本地语音识别匹配功能. 通过网络请求上传通过语音匹配的音频文件. 服务器接收到文件并进行语音识别,使用的是第三方微软语音识别,只支持 PCM 数据源的 W ...

  5. 用python实现语音的分割并保存为.wav文件

    功能描述   因为在研究使用openSMILE提取特征时,需要对语音进行分割,我找了很多方法,都无法实现自己想要效果,语音自己实现了语音分割并保存的代码,我测试了一下,可以达到自己想要的结果,因此写一 ...

  6. Python音频处理:创建一个正弦波并保存为wav文件

    Python音频处理:创建一个正弦波并保存为wav文件 0. 预备知识 0.1 数字信号基础 0.2 声学概念基础 1. 创建一个正弦波 2. 保存为wav文件 0. 预备知识 0.1 数字信号基础 ...

  7. ffmpeg提取mp4文件中的音频,保存为wav文件

    如题,一个命令行即可: ffmpeg -i 123.mp4 -acodec pcm_s16le -f s16le -ac 1 -ar 16000 -f wav 123.wav 这样就生成了一个wav文 ...

  8. 【数据压缩】WAV文件和AVI文件格式分析

    一.WAV文件和AVI文件格式简介 WAV的英文全称是Waveform Audio File Format ,它采用 RIFF (Resource Interchange File Format)文件 ...

  9. AVI文件格式简介与WAV文件分析

    AVI文件格式简介与WAV文件分析 AVI文件格式(回答问题) 所有AVI文件至少包含2个必须的LIST Chunk和一个索引Chunk Chunk: LIST Chunk: 小端:数据的低位保存在内 ...

最新文章

  1. dll的概念、dll导出类(转)
  2. 厦门计算机高级职称,2021年厦门工程师职称属于哪种职称?
  3. java操作mongodb_Java操作MongoDB
  4. java短横线转驼峰_Java后端常备的开发规范
  5. ipad连接电脑_这些应用让iPad生产力分分钟UP
  6. 陌陌估值1亿美元:一个用户10美元,贵吗?
  7. 面试官:怎么改进哈希算法实现负载均衡的扩展性和容错性?我:...
  8. CTS(10)---谷歌CTS测试之Verify简介
  9. c#类属性和实例属性_C#中类的序列化及反序列化简要分析
  10. mac 图形化安装mysql,mac安装mysql图形化工具?
  11. mpls 保留标签值_浅析MPLS多协议标签交换的发展历程
  12. 页脚保持在未满屏页面的底部
  13. 【渝粤教育】国家开放大学2018年春季 0100-22T程序设计基础 参考试题
  14. 22.哈希表(HashTable)
  15. 项目开发-文档-软件需求规格说明书模板文档命名规则及格式要求(免费下载链接)
  16. lightblue使用教程_使用LightBlue Bean和IFTTT自动化LIFX灯
  17. laravel 下载文件
  18. beanshell断言_jmeter BeanShell断言(一)
  19. 【干货】Excel中的换行符,这几种用法你会哪些?
  20. 西安交大计算机考研分数线2020院线,西安交大考研分数线2020院线_全国硕士研究生招生考试网...

热门文章

  1. 四种色彩模式ARGB_8888、ARGB_4444、 RGB_565、 ALPHA_8的区别
  2. 不经一番彻骨寒,怎得梅花扑鼻香
  3. caffe-ristretto:定点举例
  4. wangeditor富文本编辑器使用过程中遇到的问题以及解决办法
  5. redis数据类型介绍
  6. Xcode The 'Apple Push Notification' feature is only available to users enrolled in Apple Develo.
  7. 腾讯云服务器系统盘空间不足问题
  8. React学习二(组件详解)
  9. linux 下动态链接库的创建与使用——dlopen,dlsym
  10. 什么是微信商城?如何微商城?