当前位置: 首页 > 工具软件 > Speex > 使用案例 >

语音编码解码speex,c代码iOS和Android平台。

鲁博雅
2023-12-01

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

例如:一致ya'suo


提示:以下是本篇文章正文内容,下面案例可供参考

一、ios代码

#include <stdio.h> //是预处理器指令,告诉 C 编译器在实际编译之前要包含 stdio.h 文件。
#include <float.h>
#include <stdlib.h>
#include <string.h>
#include <speex/speex.h>

#define ENCODE 1
#define PROJECT_PATH "SpeexCode"
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))

#define IN_PCM(a) strcat(a,"/file/input.pcm")
#define OUT_SPX(a) strcat(a,"/file/out.spx")
#define OUT_PCM(a) strcat(a,"/file/out.pcm")



// 编码  inputLen 输入长度 
void encode(char* IN_PCM,char* OUT_SPX,int mode,int quality,int dataLen,int bufferLen)
{
	
	// char *inFile;
	// FILE *fin;
	FILE *fin = NULL, *fout = NULL;

	short in[dataLen/2];
	char cbits[200];
	int nbBytes;
	/*Holds the state of the encoder*/
	void *ptr_state;
	/*Holds bits so they can be read and written to by the Speex routines*/
	// SpeexBits ptr_bits;
	SpeexBits ptr_bits;
	// SpeexBits *ptr_bits = new SpeexBits;
	int i, tmp;

	/*Create a new encoder state in narrowband mode*/
	if (0 == mode) {
		ptr_state = speex_encoder_init(&speex_nb_mode);
	} else {
		ptr_state = speex_encoder_init(&speex_wb_mode);
	}
	speex_encoder_ctl(ptr_state, SPEEX_SET_QUALITY, &quality);

	// inFile = argv[1];
	fin = fopen(IN_PCM, "rb");
	fout = fopen(OUT_SPX, "wb");
	// fin = fopen(inFile, "r");

	/*Initialization of the structure that holds the bits*/
	speex_bits_init(&ptr_bits);
	int count = 0;
	while (1)
	{
		count++;
		/*Read a 16 bits/sample audio frame*/
		fread(in, sizeof(short), 640, fin);
		// fread(in, sizeof(short), 320, fin);
		// fread(in, sizeof(char), 1280, fin);
		if (feof(fin))
			break;

		int frameSize = 0;
		speex_encoder_ctl(ptr_state, SPEEX_GET_FRAME_SIZE, &frameSize);
		int shortDataLen = dataLen / 2;

		// char *tmpBuffer = new char[bufferLen];
		char *tmpBuffer = (char * ) malloc(bufferLen);
		
		int writeLen = 0;

		for (int i = 0; i < shortDataLen; i += frameSize) {

			spx_int16_t *dataInt16 = (spx_int16_t *) &in;

			speex_bits_reset(&ptr_bits);
			
			speex_encode_int(ptr_state, &dataInt16[i], &ptr_bits);
			writeLen += speex_bits_write(&ptr_bits, &tmpBuffer[writeLen], bufferLen);
		}
	
		fwrite(tmpBuffer, 1, writeLen, fout);
		free(tmpBuffer);
		tmpBuffer = NULL;
	}

	/*Destroy the encoder state*/
	speex_encoder_destroy(ptr_state);
	/*Destroy the bit-packing struct*/
	speex_bits_destroy(&ptr_bits);
	fclose(fin);
	fclose(fout);
}

// 解码
void decode(char* IN_SPX,char* OUT_PCM,int mode,int quality,int dataLen,int bufferLen)
{
	char *outFile;
	FILE *fout,*fin;
	char cbits[200];
	/*Holds the state of the decoder*/
	void *ptr_state;
	/*Holds bits so they can be read and written to by the Speex routines*/
	SpeexBits ptr_bits;
	// SpeexBits *ptr_bits = new SpeexBits;
	int i, tmp;
	int encFrameBytes = 0;
	
	int enc_nb_frame_nbytes_of_quality[11] = {6, 10, 15, 20, 20, 28, 28, 38, 38, 46, 62};

	int enc_wb_frame_nbytes_of_quality[11] = {10, 15, 20, 25, 32, 42, 52, 60, 70, 86, 106};

	/*Create a new decoder state in narrowband mode*/
	if (0 == mode) {
		ptr_state = speex_decoder_init(&speex_nb_mode);
		encFrameBytes = enc_nb_frame_nbytes_of_quality[quality];
	} else {
		ptr_state = speex_decoder_init(&speex_wb_mode);
		encFrameBytes = enc_wb_frame_nbytes_of_quality[quality];
	}

	/*Set the perceptual enhancement on*/
	// tmp = 7;
	speex_decoder_ctl(ptr_state, SPEEX_SET_ENH, &quality);

	fin = fopen(IN_SPX, "rb");
	fout = fopen(OUT_PCM, "wb");

	/*Initialization of the structure that holds the bits*/
	speex_bits_init(&ptr_bits);
	while (1)
	{
		// fread(&encFrameBytes, sizeof(int), 1, fin);
		fread(cbits,1, encFrameBytes, fin);
		// fprintf(stderr, "encFrameBytes: %d\n,dataLen=%d\n", encFrameBytes,dataLen);
		if (feof(fin))
			break;
		
		if (dataLen % encFrameBytes != 0) {
			fprintf(stderr, "encFrameBytes: %s\n", "编码出错");
		}

		int readBytes = 0;
		int frameSize = 0;
		int writeOffset = 0;

		speex_decoder_ctl(ptr_state, SPEEX_GET_FRAME_SIZE, &frameSize);

		short *frame = (short * ) malloc(frameSize);
		// short *frame = new short[frameSize];
		fprintf(stderr, "frameSize=%d\n", frameSize);
		while (readBytes != dataLen) {
			fprintf(stderr, "readBytes=%d,dataLen=%d\n", readBytes,dataLen);
			speex_bits_read_from(&ptr_bits, &cbits[readBytes], encFrameBytes);
			readBytes += encFrameBytes;

			int ret = speex_decode_int(ptr_state, &ptr_bits, frame);
			if (0 == ret) {
				if (writeOffset < bufferLen) {
					writeOffset += frameSize * 2;
					fprintf(stderr, "writeOffset=%d\n", writeOffset);
					// fwrite(frame, sizeof(char), frameSize, fout);
					fwrite(frame, sizeof(short), frameSize, fout);
				} else {
					break;
				}
			} else {
				fprintf(stderr, "编码出错decode, ret==: %d\n", ret);
			}
		}
		// frame = NULL;
		free(frame);
		frame = NULL;
	}

	/*Destroy the decoder state*/
	speex_decoder_destroy(ptr_state);
	/*Destroy the bit-stream truct*/
	speex_bits_destroy(&ptr_bits);
	fclose(fout);
}

int main(int argc, char **argv){


	int quality = 7;
	int mode = 1;
	int dataLen = 60;
	int inputLen = 1280;
	if(ENCODE==0){
		encode("/SpeexCode/file/input.pcm","/SpeexCode/file/out.spx",mode,quality,inputLen,inputLen);
	}else{
		decode("/SpeexCode/file/out.spx","/SpeexCode/file/out.pcm",mode,quality,dataLen,inputLen);
	}

	return 0;
}

上面是c的代码 ios平台可以直接使用。

二、Android代码

1.引入库

 下面是Android jni里面代码。

//
// Created by huang on 2019/9/23.
//

#include "../../../com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec.h"
#include "src/arch.h"

#include <speex/speex.h>
#include <android/log.h>
#include <stdlib.h>

#undef TAG
#define TAG "SpeexCodec_Jni"

#define METHOD_SET_HANDLES "setHandles"


// nb模式下,各quality下每帧(640bytes,320个short)压缩后字节数
int enc_nb_frame_nbytes_of_quality[11] = {6, 10, 15, 20, 20, 28, 28, 38, 38, 46, 62};

// wb模式下,各quality下每帧(640bytes,320个short)压缩后字节数
int enc_wb_frame_nbytes_of_quality[11] = {10, 15, 20, 25, 32, 42, 52, 60, 70, 86, 106};

void* getHandle(JNIEnv *pEnv, jbyteArray handle)
{
    char* handleChar = (char*) pEnv->GetByteArrayElements(handle, JNI_FALSE);
    void* st = NULL;
    if (sizeof(st) == 8) {
        st = (SpeexBits*) (*((unsigned long long*) handleChar));
    } else {
        st = (SpeexBits*) (*((unsigned long*) handleChar));
    }

    pEnv->ReleaseByteArrayElements(handle, (jbyte*) handleChar, JNI_FALSE);

    return st;
}

/*
 * Class:     com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec
 * Method:    init_native
 * Signature: (IIII)I
 */
JNIEXPORT jint JNICALL Java_com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec_init_1native
        (JNIEnv *pEnv, jobject thiz, jint codec, jint sampleRate, jint mode, jint quality)
{
    jmethodID setHandlesMethod = pEnv->GetMethodID(pEnv->GetObjectClass(thiz), METHOD_SET_HANDLES, "([B[B)V");
    if (NULL == setHandlesMethod) {
        __android_log_print(ANDROID_LOG_ERROR, TAG, "cannot find method %s with signature %s in Java class",
                            METHOD_SET_HANDLES, "(JJ)V");
        return -1;
    }

    void* state = NULL;
    SpeexBits* bits = new SpeexBits;
    int tmp = quality;

    if (com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec_CODEC_ENCODE == codec) {
        if (com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec_MODE_NB == mode) {
            state = speex_encoder_init(&speex_nb_mode);
        } else {
            state = speex_encoder_init(&speex_wb_mode);
        }

        if (NULL == state) {
            if (NULL != bits) {
                delete bits;
            }
            return -1;
        }

        speex_encoder_ctl(state, SPEEX_SET_QUALITY, &tmp);
    } else {
        if (com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec_MODE_NB == mode) {
            state = speex_decoder_init(&speex_nb_mode);
        } else {
            state = speex_decoder_init(&speex_wb_mode);
        }

        if (NULL == state) {
            if (NULL != bits) {
                delete bits;
            }
            return -1;
        }

        tmp = 1;
        speex_decoder_ctl(state, SPEEX_SET_ENH, &tmp);
    }

    speex_bits_init(bits);

    int len = sizeof(state);
    jbyteArray stateArray = pEnv->NewByteArray(len);
    jbyteArray bitsArray = pEnv->NewByteArray(len);

    pEnv->SetByteArrayRegion(stateArray, 0, len, (jbyte*) &state);
    pEnv->SetByteArrayRegion(bitsArray, 0, len, (jbyte*) &bits);

    pEnv->CallVoidMethod(thiz, setHandlesMethod, stateArray, bitsArray);

    return 0;
}

/*
 * Class:     com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec
 * Method:    encode_native
 * Signature: ([BI[BI)I
 */
JNIEXPORT jint JNICALL Java_com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec_encode_1native
        (JNIEnv *pEnv, jobject thiz, jbyteArray state, jbyteArray speex_bits, jbyteArray data, jint dataLen,
                jbyteArray buffer, jint bufferLen)
{
    void* ptr_state = (void*) getHandle(pEnv, state);
    SpeexBits* ptr_bits = (SpeexBits*) getHandle(pEnv, speex_bits);

    int frameSize = 0;
    speex_encoder_ctl(ptr_state, SPEEX_GET_FRAME_SIZE, &frameSize);

    int shortDataLen = dataLen / 2;
    if (shortDataLen % frameSize != 0) {
        __android_log_print(ANDROID_LOG_ERROR, TAG, "dataLen must be multiple of %d", frameSize);
        return -1;
    }

    char* dataChars = (char*) pEnv->GetByteArrayElements(data, JNI_FALSE);
    spx_int16_t* dataInt16 = (spx_int16_t*) dataChars;
    char* tmpBuffer = new char[bufferLen];

    int writeLen = 0;
    for (int i = 0; i < shortDataLen; i += frameSize) {
        speex_bits_reset(ptr_bits);
        speex_encode_int(ptr_state, &dataInt16[i], ptr_bits);

        writeLen += speex_bits_write(ptr_bits, &tmpBuffer[writeLen], bufferLen);
    }

    delete[] tmpBuffer;

    pEnv->ReleaseByteArrayElements(data, (jbyte*) dataChars, JNI_FALSE);
    pEnv->SetByteArrayRegion(buffer, 0, writeLen, (jbyte*) tmpBuffer);

    return writeLen;
}

/*
 * Class:     com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec
 * Method:    decode_native
 * Signature: (II[BI[BIII)I
 */
JNIEXPORT jint JNICALL Java_com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec_decode_1native
        (JNIEnv *pEnv, jobject thiz, jbyteArray state, jbyteArray speex_bits, jbyteArray data, jint dataLen,
         jbyteArray buffer, jint bufferLen, jint mode, jint quality)
{
    void* ptr_state = (void*) getHandle(pEnv, state);
    SpeexBits* ptr_bits = (SpeexBits*) getHandle(pEnv, speex_bits);

    int encFrameBytes = 0;
    if (com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec_MODE_NB == mode) {
        encFrameBytes = enc_nb_frame_nbytes_of_quality[quality];
    } else {
        encFrameBytes = enc_wb_frame_nbytes_of_quality[quality];
    }

    if (dataLen % encFrameBytes != 0) {
        __android_log_print(ANDROID_LOG_ERROR, TAG, "dataLen must be multiple of %d", encFrameBytes);
        return -1;
    }

    char* dataChars = (char*) pEnv->GetByteArrayElements(data, JNI_FALSE);
    int readBytes = 0;
    int frameSize = 0;
    int writeOffset = 0;

    speex_decoder_ctl(ptr_state, SPEEX_GET_FRAME_SIZE, &frameSize);
    short* frame = new short[frameSize];

    while (readBytes != dataLen) {
        speex_bits_read_from(ptr_bits, &dataChars[readBytes], encFrameBytes);
        readBytes += encFrameBytes;

        int ret = speex_decode_int(ptr_state, ptr_bits, frame);
        if (0 == ret) {
            if (writeOffset < bufferLen) {
                pEnv->SetByteArrayRegion(buffer, writeOffset, frameSize * 2, (jbyte *) frame);
                writeOffset += frameSize * 2;
            } else {
                __android_log_print(ANDROID_LOG_ERROR, TAG, "buffer length is not enough");
                break;
            }
        } else {
            __android_log_print(ANDROID_LOG_ERROR, TAG, "decode, ret=%d", ret);

            pEnv->ReleaseByteArrayElements(data, (jbyte*) dataChars, JNI_FALSE);
            return ret;
        }
    }

    delete[] frame;

    pEnv->ReleaseByteArrayElements(data, (jbyte*) dataChars, JNI_FALSE);

    return writeOffset;
}

/*
 * Class:     com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec
 * Method:    destroy_native
 * Signature: (III)V
 */
JNIEXPORT void JNICALL Java_com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec_destroy_1native
        (JNIEnv *pEnv, jobject thiz, jint codec, jbyteArray state, jbyteArray bits)
{
    void* st = getHandle(pEnv, state);
    void* pBits = getHandle(pEnv, bits);

    if (com_iflytek_cyber_evs_sdk_codec_audio_speex_SpeexCodec_CODEC_ENCODE == codec) {
        speex_encoder_destroy((void*) st);
    } else {
        speex_decoder_destroy((void*) st);
    }

    speex_bits_destroy((SpeexBits*) pBits);
    delete (SpeexBits*) pBits;
}

总结

参考资料
https://blog.csdn.net/TYJJXSJ/article/details/43604247
https://speex.org/
https://github.com/iFLYOS-OPEN/SDK-EVS-Android

QQ:772973779

 类似资料: