1、opencore-amr源码下载

https://sourceforge.net/projects/opencore-amr/files/opencore-amr/

2、opencore-amr编译

交叉编译到arm平台

./configure --host=arm-linux-gnueabihf --prefix='/home/dong/pocdemo/opencore-amr-0.1.3/arm'

make

make install

3、opencore-amr的应用

1) opencore-amr静态库的使用
arm-linux-gnueabihf-g++ -o demo demo.c -I ./opencore-amr/include/opencore-amrnb libpoc.a ./opencore-amr/lib/libopencore-amrnb.a -lpthread

2) opencore-amr动态库的使用
arm-linux-gnueabihf-g++ -o demo demo.c -I ./opencore-amr/include/opencore-amrnb -L ./ -lpoc -L ./opencore-amr/lib -lopencore-amrnb -lpthread

3) opencore-amr静态库动态库混合的使用
arm-linux-gnueabihf-g++ -o demo demo.c -I ./opencore-amr/include/opencore-amrnb -L ./ -lpoc ./opencore-amr/lib/libopencore-amrnb.a -lpthread

4、源码包里的 opencore-amr/test/amrnb-enc-sine.c

编码一段正玄波

/* ------------------------------------------------------------------
* Copyright (C) 2009 Martin Storsjo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/ #include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <interf_enc.h> int main(int argc, char *argv[]) {
int i, j;
void* amr;
FILE* out;
int sample_pos = ; if (argc < ) {
fprintf(stderr, "%s out.amr\n", argv[]);
return ;
} amr = Encoder_Interface_init();
out = fopen(argv[], "wb");
if (!out) {
perror(argv[]);
return ;
} fwrite("#!AMR\n", , , out);
for (i = ; i < ; i++) {
short buf[];
uint8_t outbuf[];
int n;
for (j = ; j < ; j++) {
buf[j] = *sin(**3.141592654*sample_pos/);
sample_pos++;
}
n = Encoder_Interface_Encode(amr, MR475, buf, outbuf, );
fwrite(outbuf, , n, out);
}
fclose(out);
Encoder_Interface_exit(amr); return ;
}

arm-linux-gnueabihf-gcc -o amrnb-enc-sine amrnb-enc-sine.c -I ./opencore-amr/include/opencore-amrnb ./opencore-amr/lib/libopencore-amrnb.a

5、PCM与AMR互转

https://github.com/gansidui/pcm_amr_codec

dong@ubuntu:~/amr/example$ tree
.
├── build_example_amr2pcm_arm.sh
├── build_example_pcm2amr_x86.sh
├── codec
│   ├── amrnb.c
│   ├── amrnb.h
│   ├── audio_format_convert.c
│   ├── audio_format_convert.h
│   └── bs.h
├── dec
├── example_amr2pcm.c
├── example_pcm2amr.c
├── libopencore-amrnb.so.0
├── opencore-amr
│   ├── include
│   │   ├── opencore-amrnb
│   │   │   ├── interf_dec.h
│   │   │   └── interf_enc.h
│   │   └── opencore-amrwb
│   │       ├── dec_if.h
│   │       └── if_rom.h
│   └── lib
│       ├── libopencore-amrnb.a
│       ├── libopencore-amrnb.la
│       ├── libopencore-amrnb.so -> libopencore-amrnb.so.0.0.3
│       ├── libopencore-amrnb.so.0 -> libopencore-amrnb.so.0.0.3
│       ├── libopencore-amrnb.so.0.0.3
│       ├── libopencore-amrwb.a
│       ├── libopencore-amrwb.la
│       ├── libopencore-amrwb.so -> libopencore-amrwb.so.0.0.3
│       ├── libopencore-amrwb.so.0 -> libopencore-amrwb.so.0.0.3
│       ├── libopencore-amrwb.so.0.0.3
│       └── pkgconfig
│           ├── opencore-amrnb.pc
│           └── opencore-amrwb.pc
├── run_dec.sh
├── run_enc.sh
├── test.amr
└── test.amr.pcm

1) gcc可以直接编译

#arm-linux-gnueabihf-gcc example_amr2pcm.c ./codec/audio_format_convert.c ./codec/amrnb.c ./codec/bs.h -o dec -I'./opencore-amr/include/opencore-amrnb' -I'./opencore-amr/include/opencore-amrwb' -I'./codec' ./opencore-amr/lib/libopencore-amrnb.a ./opencore-amr/lib/libopencore-amrwb.a

2) g++和gcc编译需要一点小改动

更改audio_format_convert.h

//#ifdef __cplusplus
//extern "C" {
//#endif

...

...

//#ifdef __cplusplus
//}
//#endif

amrnb.c的第294和368行

int ret = Encoder_Interface_Encode(amrnb_enc, MR475, &samples[offset / sizeof (int16_t)], tmp, amrnb_dtx);

参数mode改成MR475

arm-linux-gnueabihf-g++ example_amr2pcm.c ./codec/audio_format_convert.c ./codec/amrnb.c ./codec/bs.h -o dec -I'./opencore-amr/include/opencore-amrnb' -I'./opencore-amr/include/opencore-amrwb' -I'./codec' ./opencore-amr/lib/libopencore-amrnb.a ./opencore-amr/lib/libopencore-amrwb.a

我的项目整理下编译指令 build.sh

arm-linux-gnueabihf-g++ -o poc_client \
poc_client.c \
./codec/audio_format_convert.c \
./codec/amrnb.c \
./codec/bs.h \
./fifo/app_fifo.c \
./fifo/app_fifo.h \
./list/list.c \
./list/list.h \
-I'./opencore-amr/include/opencore-amrnb' \
-I'./opencore-amr/include/opencore-amrwb' \
-I'./codec' \
./opencore-amr/lib/libopencore-amrnb.a \
./opencore-amr/lib/libopencore-amrwb.a \
./poc/libpoc.a \
-I ./alsa/include -L ./alsa/lib -lasound \
-lpthread

6、alsa播放pcm音频

播放pcm文件

/**alsa play test
*ALSA用户空间编译,ALSA驱动的声卡在用户空间,不宜直接使用
*文件接口中,而应使用alsa-lib
*打开---->设置参数--->读写音频数据 ALSA全部使用alsa-lib中的API
*交叉编译
*export LD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATH
*arm-linux-gcc -o alsa_play alsa_play_test.c -L. -lasound
*需要交叉编译后的libasound.so库的支持
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "alsa/asoundlib.h" int main(int argc, char *argv[])
{
int i;
int ret;
int buf[];
unsigned int val;
int dir=;
char *buffer;
int size;
snd_pcm_uframes_t frames;
snd_pcm_uframes_t periodsize;
snd_pcm_t *playback_handle;//PCM设备句柄pcm.h
snd_pcm_hw_params_t *hw_params;//硬件信息和PCM流配置
if (argc != ) {
printf("error: alsa_play_test [music name]\n");
exit();
}
printf("play song %s by wolf\n", argv[]);
FILE *fp = fopen(argv[], "rb");
if(fp == NULL)
return ;
fseek(fp, , SEEK_SET); //1. 打开PCM,最后一个参数为0意味着标准配置
ret = snd_pcm_open(&playback_handle, "default", SND_PCM_STREAM_PLAYBACK, );
if (ret < ) {
perror("snd_pcm_open");
exit();
} //2. 分配snd_pcm_hw_params_t结构体
ret = snd_pcm_hw_params_malloc(&hw_params);
if (ret < ) {
perror("snd_pcm_hw_params_malloc");
exit();
}
//3. 初始化hw_params
ret = snd_pcm_hw_params_any(playback_handle, hw_params);
if (ret < ) {
perror("snd_pcm_hw_params_any");
exit();
}
//4. 初始化访问权限
ret = snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
if (ret < ) {
perror("snd_pcm_hw_params_set_access");
exit();
}
//5. 初始化采样格式SND_PCM_FORMAT_U8,8位
ret = snd_pcm_hw_params_set_format(playback_handle, hw_params, SND_PCM_FORMAT_U8);
if (ret < ) {
perror("snd_pcm_hw_params_set_format");
exit();
}
//6. 设置采样率,如果硬件不支持我们设置的采样率,将使用最接近的
//val = 44100,有些录音采样频率固定为8KHz val = ;
ret = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, &val, &dir);
if (ret < ) {
perror("snd_pcm_hw_params_set_rate_near");
exit();
}
//7. 设置通道数量
ret = snd_pcm_hw_params_set_channels(playback_handle, hw_params, );
if (ret < ) {
perror("snd_pcm_hw_params_set_channels");
exit();
} /* Set period size to 32 frames. */
frames = ;
periodsize = frames * ;
ret = snd_pcm_hw_params_set_buffer_size_near(playback_handle, hw_params, &periodsize);
if (ret < )
{
printf("Unable to set buffer size %li : %s\n", frames * , snd_strerror(ret)); }
periodsize /= ; ret = snd_pcm_hw_params_set_period_size_near(playback_handle, hw_params, &periodsize, );
if (ret < )
{
printf("Unable to set period size %li : %s\n", periodsize, snd_strerror(ret));
} //8. 设置hw_params
ret = snd_pcm_hw_params(playback_handle, hw_params);
if (ret < ) {
perror("snd_pcm_hw_params");
exit();
} /* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(hw_params, &frames, &dir); size = frames * ; /* 2 bytes/sample, 2 channels */
buffer = (char *) malloc(size);
fprintf(stderr,
"size = %d\n",
size); while ()
{
ret = fread(buffer, , size, fp);
if(ret == )
{
fprintf(stderr, "end of file on input\n");
break;
}
else if (ret != size)
{
}
//9. 写音频数据到PCM设备
while(ret = snd_pcm_writei(playback_handle, buffer, frames)<)
{
usleep();
if (ret == -EPIPE)
{
/* EPIPE means underrun */
fprintf(stderr, "underrun occurred\n");
//完成硬件参数设置,使设备准备好
snd_pcm_prepare(playback_handle);
}
else if (ret < )
{
fprintf(stderr,
"error from writei: %s\n",
snd_strerror(ret));
}
} }
//10. 关闭PCM设备句柄
snd_pcm_close(playback_handle); return ;
}

arm-linux-gnueabihf-gcc -o test test.c -I ./alsa/include -L ./alsa/lib -lasound -lpthread

./test file.pcm

播放pcm缓存

    #include <alsa/asoundlib.h>

    int main()
{
int ret;
snd_pcm_t *pcm_handle;
snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
snd_pcm_hw_params_t *hwparams;
char *pcm_name; pcm_name = strdup("plughw:0,0"); snd_pcm_hw_params_alloca(&hwparams); ret = snd_pcm_open(&pcm_handle, pcm_name, stream, );
if (ret < ) {
printf("snd_pcm_open failed\n");
return(-);
} ret = snd_pcm_hw_params_any(pcm_handle, hwparams);
if (ret < ) {
printf("snd_pcm_hw_params_any failed\n");
return(-);
} int rate = ;
int exact_rate;
int dir;
int periods = ;
snd_pcm_uframes_t periodsize = ; ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED);
if (ret < ) {
printf("snd_pcm_hw_params_set_access failed\n");
return(-);
} ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams,
SND_PCM_FORMAT_S16_LE);
if (ret < ) {
printf("snd_pcm_hw_params_set_format failed\n");
return(-);
} exact_rate = rate;
ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
&exact_rate, );
if (ret < ) {
printf("snd_pcm_hw_params_set_rate_near failed\n");
return(-);
}
if (rate != exact_rate) {
printf("The rate %d Hz is not supported by your hardware\n"
"==> Using %d Hz instead\n", rate, exact_rate);
} ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, );
if (ret < ) {
printf("snd_pcm_hw_params_set_channels failed\n");
return(-);
}
/*
ret = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0);
if (ret < 0) {
printf("snd_pcm_hw_params_set_periods failed\n");
return(-1);
}
*/
ret = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams,
(periodsize * periods) >> );
if (ret < ) {
printf("snd_pcm_hw_params_set_buffer_size failed\n");
return(-);
} ret = snd_pcm_hw_params(pcm_handle, hwparams);
if (ret < ) {
printf("snd_pcm_hw_params failed\n");
return(-);
} unsigned char *data;
int l1, l2;
short s1, s2;
int frames; data = malloc(periodsize);
frames = periodsize >> ; for (l1 = ; l1 < ; l1++) {
for (l2 = ; l2 < frames; l2++) {
s1 = (l2 % ) * - ;
s2 = (l2 % ) * - ;
data[*l2] = (unsigned char)s1;
data[*l2+] = s1 >> ;
data[*l2+] = (unsigned char)s2;
data[*l2+] = s2 >> ;
}
while ((ret = snd_pcm_writei(pcm_handle, data, frames)) < ) {
snd_pcm_prepare(pcm_handle);
printf("<<<<<<<<<<<<<<Buffer Underrun>>>>>>>>>>>>\n");
}
} snd_pcm_drop(pcm_handle);
snd_pcm_drain(pcm_handle); return ;
}

arm-linux-gnueabihf-gcc -o test test.c -I ./alsa/include -L ./alsa/lib -lasound -lpthread

./test

7、alsa采集pcm音频

采集pcm到缓存/文件

/*
read from the default PCM device and writes to standard output for 5 seconds of data
*/ #define ALSA_PCM_NEW_HW_PARAMS_API #include <alsa/asoundlib.h> snd_pcm_t * handle;
snd_pcm_hw_params_t * params;
snd_pcm_uframes_t frames;
char * buffer;
unsigned int val; int alsa_capture_init()
{
int dir;
int rc; /* open PCM device for recording (capture). */
rc = snd_pcm_open(&handle, "default",SND_PCM_STREAM_CAPTURE,);
if( rc < )
{
return -;
}
/* allocate a hardware parameters object */
snd_pcm_hw_params_alloca(&params);
/* fill it with default values. */
snd_pcm_hw_params_any(handle,params);
/* set the desired hardware parameters */
snd_pcm_hw_params_set_access(handle,params,
SND_PCM_ACCESS_RW_INTERLEAVED);
/* signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle,params,
SND_PCM_FORMAT_S16_LE);
/* two channels(stereo) */
snd_pcm_hw_params_set_channels(handle,params,);
/* sampling rate */
val = ;
snd_pcm_hw_params_set_rate_near(handle,params,&val,&dir);
/* set period size */
frames = ;
snd_pcm_hw_params_set_period_size_near(handle,params,&frames,&dir);
/* write parameters to the driver */
rc = snd_pcm_hw_params(handle,params);
if ( rc < )
{
return -;
}
/* use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params,&frames,&dir); /* loop for 5 seconds */
snd_pcm_hw_params_get_period_time(params, &val, &dir); return ;
} int main()
{
long loops;
int ret;
int size;
FILE * out_fd;
out_fd = fopen("out_pcm.raw","wb+"); alsa_capture_init();
loops = / val; /* 2 bytes/sample, 1 channels */
size = frames * ;
buffer = ( char * ) malloc(size); while( loops > )
{
loops--;
ret = snd_pcm_readi(handle,buffer,frames);
if ( ret == -EPIPE )
{
/* EPIPE means overrun */
fprintf(stderr,"overrun occured\n");
snd_pcm_prepare(handle);
}
else if ( ret < )
{
fprintf(stderr,"error from read: %s\n",
snd_strerror(ret));
}
else if ( ret != (int)frames)
{
fprintf(stderr,"short read, read %d frames\n",ret);
} ret = fwrite(buffer, , size, out_fd);
// ret = write(1, buffer, size);
if ( ret != size )
{
fprintf(stderr,"short write: wrote %d bytes\n",ret);
}
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
fclose(out_fd);
}

arm-linux-gnueabihf-gcc -o test test.c -I ./alsa/include -L ./alsa/lib -lasound -lpthread

./test

8、综合应用实例

采集一段PCM格式语音数据 ,转码成AMR格式然后发送至rtp网络

#if 1
int i;
char outbuf[PCM_DATA_LENGTH]; for (i = ; i < *; i++) {
ret = snd_pcm_readi(handle,buffer,frames);
if ( ret == -EPIPE )
{
printf("overrun occured\n");
snd_pcm_prepare(handle);
} buffer_pcm2amr_encode((char*)buffer, PCM_DATA_LENGTH, outbuf); //n = Encoder_Interface_Encode(amr, MR795, buf, outbuf, 0);
amrFrame->m_nFrameLen = ;
amrFrame->m_nFrameCount = ;
amrFrame->m_pFrame = outbuf;
NxZDPttAccess_AmrFrame(snCurCallSessionId, amrFrame);
} #else
//------------------------------------
//sin data test
int i, j;
int sample_pos = ; for (i = ; i < ; i++) {
short buf[];
char outbuf[];
int n;
for (j = ; j < ; j++) {
buf[j] = *sin(**3.141592654*sample_pos/);
sample_pos++;
}
buffer_pcm2amr_encode((char*)buf, , outbuf); //n = Encoder_Interface_Encode(amr, MR515, buf, outbuf, 0);
amrFrame->m_nFrameLen = ;
amrFrame->m_nFrameCount = ;
amrFrame->m_pFrame = outbuf;
NxZDPttAccess_AmrFrame(snCurCallSessionId, amrFrame);
}
//-------------------------------------
#endif

接收一段AMR格式语音数据,转码成PCM格式,然后写入声卡播放

#if 1
int i;
for (i = ; i < pAmrFrame->m_nFrameCount; i++) {
int ret = buffer_amr2pcm_decode(pAmrFrame->m_pFrame + i*pAmrFrame->m_nFrameLen, pAmrFrame->m_nFrameLen, pcm_data_buf);
if(ret > ){
if((ret = snd_pcm_writei(pcm_handle, pcm_data_buf, PCM_DATA_LENGTH/)) < ) {
snd_pcm_prepare(pcm_handle);
printf("<<<<<<<<<<<<<<Buffer Underrun>>>>>>>>>>>>\n");
}
}
} #else
unsigned char *data;
int l1, l2;
short s1, s2;
int frames;
int periodsize = ;
data = (unsigned char*)malloc(periodsize);
frames = periodsize >> ; for (l1 = ; l1 < ; l1++) {
for (l2 = ; l2 < frames; l2++) {
s1 = (l2 % ) * - ;
s2 = (l2 % ) * - ;
data[*l2] = (unsigned char)s1;
data[*l2+] = s1 >> ;
data[*l2+] = (unsigned char)s2;
data[*l2+] = s2 >> ;
}
if((ret = snd_pcm_writei(pcm_handle, data, frames)) < ) {
snd_pcm_prepare(pcm_handle);
printf("<<<<<<<<<<<<<<Buffer Underrun>>>>>>>>>>>>\n");
}
}
#endif

9、拓展

tinyalsa做了很多琐事,省了不少时间,感谢作者。

https://github.com/tinyalsa/tinyalsa

generation-sine-wave

https://github.com/ichgw/generation-sine-wave

https://github.com/moutend/getSineWave

https://github.com/munnellg/SineWave

AMR格式语音采集/编码/转码/解码/播放的更多相关文章

  1. G711格式语音采集/编码/转码/解码/播放

    2019-05-01 语音g711格式和AMR格式类似,应用很简单,很多人已经整理过了,收录于此,以备不时之需,用别人现成的足矣,我们的时间应该用来干更有意义的事. 1.PCM to G711 Fas ...

  2. 如何将微信上传AMR格式语音转化为MP3格式

    1. 服务器安装ffmpeg 2. 执行命令 ffmpeg -i {amr_file_path} -f mp3 -acodec libmp3lame -y {mp3_file_path} public ...

  3. 在java中使用ffmpeg将amr格式的语音转为mp3格式

    ffmpeg是一个非常强大的音视频处理工具,官网是:http://ffmpeg.org/. 由于ffmpeg在windows上和linux系统上的执行文件不一样(Windows上不需要安装ffmpeg ...

  4. 使用X264编码yuv格式的视频帧使用ffmpeg解码h264视频帧

    前面一篇博客介绍在centos上搭建点击打开链接ffmpeg及x264开发环境.以下就来问个样例: 1.利用x264库将YUV格式视频文件编码为h264格式视频文件 2.利用ffmpeh库将h264格 ...

  5. 通过javascript 直接播放amr格式的语言

    前段时间做了个功能(有2.3个月了,突然想起来了,就记录一下),语言播放.一开始觉得很简单~~~ 计划应用的是H5的audio标签,但因为这个标签不支持amr格式的语言,但是手机端传到后台的录音却都是 ...

  6. C# Window Form解决播放amr格式音乐问题

    最近搞一个项目,需要获取微信端语音文件,下载之后发现是AMR格式的录音文件,这下把我搞晕了,C#中的4种播放模式不支持播放AMR,想到都觉得头痛,如何是好?最后找到的方案,其实也简单:windows ...

  7. WebRTC VideoEngine超详细教程(三)——集成X264编码和ffmpeg解码

    转自:http://blog.csdn.net/nonmarking/article/details/47958395 本系列目前共三篇文章,后续还会更新 WebRTC VideoEngine超详细教 ...

  8. 特殊字符url编码以后再解码后出现错误(&not , &cent, &curren, &pound)

    Url编码的原内容是 “&notify_url=xxxx”  经过url编码以后再解码回来  “&not”的部分就变成了“¬” 解决方案:把原文里面待url编码的&符号先替换成 ...

  9. JavaScript中url 传递参数(特殊字符)解决方法及转码解码的介绍

    有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了.下表中列出了一些URL特殊符号及编码   十六进制值 1. + URL 中+号表示空格 %2B 2. 空 ...

随机推荐

  1. Yii 开发过程 tips

    1. 查看DAO 生成的sql 结果(类似TP的 getLastSql): $reto = $edb->createCommand($bsql); echo $reto->text; 2. ...

  2. 【cs229-Lecture5】生成学习算法:1)高斯判别分析(GDA);2)朴素贝叶斯(NB)

    参考: cs229讲义 机器学习(一):生成学习算法Generative Learning algorithms:http://www.cnblogs.com/zjgtan/archive/2013/ ...

  3. 查询sql server 2008所有表和行数

    查询sql server 2008所有表和行数 SELECT a.name, b.rows FROM sysobjects AS a INNER JOIN sysindexes AS b ON a.i ...

  4. android第三方---->android智能机器人的使用

    在网上找了个第三方智能机器人,可以实现聊天语音等功能,比较不错的.今天我们就开始智能机器人聊天的学习,例子中涉及的handler的有关知识和json数据的解析,请参见我的博客:android基础--- ...

  5. DataTable进行排序Asc升序,Desc降序

    DataTable dt = new DataTable(); DataView dv = dt.DefaultView; dv.Sort = "XXX Asc"; dt=dv.T ...

  6. DIV高度自适应及注意问题(转)

    本文和大家重点讨论一下DIV高度自适应及注意问题,主要包括父div高度随子div的高度改变而改变和子div高度随父亲div高度改变而改变两种情况. DIV高度自适应及注意问题 积累了一些经验,总结出一 ...

  7. elementUI Message 独立引入的用法

    同理,Alert,MessageBox, Notification, 也是这样引入 单组件单独引用: import { Message } from 'element-ui'; export defa ...

  8. 第二步 使用Cordova 3.0(及以上版本) 创建安卓项目(2014-6-25)

    参考资料: http://www.cnblogs.com/numtech/p/3233469.html http://blog.sina.com.cn/s/blog_9e245c690101jurr. ...

  9. MYSQL的索引和常见函数

    MySQL的索引 索引机制 MySQL属于关系型数据库,为了提高查询速度,可以创建索引. 索引:由表中的一个或多个字段生成的键组成,这些键存储在数据结构(B树或者hash表中),于是又分为B树索引(I ...

  10. Web Uploader在低版本IE下无法显示Flash的一种情况

    用户反馈在IE 8下无法正常显示Web Uploader控件,并已安装了Flash插件.调试发现在内部抛出了Runtime Error的错误,关键代码如下: Runtime.create = func ...