9.24. virtual_enc虚拟源编码
概述
pcm数据通过虚拟源编码成想要的格式(例如:mp3、amr、ogg、opus、jla、spx、aac等)数据
9.24.1. 应用示例
apps/demo/demo_DevKitBoard/include/demo_config.h
打开#define USE_VIRTUAL_ENC_TEST
宏使用,例程文件为apps/common/example/audio/virtual_enc/main.c
该例子中以文件
4.pcm
作为输入数据,进行virtual_enc, 输出mp3数据到out_file.mp3
文件保存
9.24.2. 例子流程
开启编码服务和注册编码服务事件回调函数
等待SD卡挂载,打开输入文件和创建输出文件
设置编码参数,请求打开编码器
编码结束,关闭编码器和编码服务
9.24.3. 关键过程说明
1.注册编码服务事件回调函数
//线程接收编码服务回调消息队列方式
/*static void server_back()
{
while(1){
int msg[32];
os_time_dly(2);
os_taskq_pend("taskq",msg,ARRAY_SIZE(msg));
}
}*/
//2.开启编码服务和注册编码服务回调
if (!__this->enc_server) {
__this->enc_server = server_open("audio_server", "enc");
if (!__this->enc_server) {
return -1;
}
//a.将编码服务回调函数注册到“app_core”消息队列 常用方式
server_register_event_handler_to_task(__this->enc_server, NULL, enc_server_server_event_handler, "app_core");
//b.将编码服务回调函数注册到创建的线程中接收消息队列
/* thread_fork("server_back", 10, 1024, 32, NULL, server_back, NULL); */
/* server_register_event_handler_to_task(__this->enc_server, NULL, enc_server_server_event_handler,"server_back"); */
} else {
return -1;
}
2.设置编码参数,请求打开编码器
req.enc.read_input = enc_server_read_input; //用于虚拟采样源”virtual”编码时的数据读取操作读输入buf及其长度,返回负值自动停止编码并回调编码结束的事件
req.enc.vfs_ops = &enc_server_vfs_ops; //编码后数据在fwrite回调中输出
req.enc.vir_data_wait = 1; //等待数据编码完成才进行下一帧数据编码,数据完整
//3.设置编码参数,请求打开编码器
union audio_req req = {0};
req.enc.cmd = AUDIO_ENC_OPEN;
req.enc.channel = 2;
req.enc.volume = 100;
req.enc.output_buf = NULL;
req.enc.output_buf_len = 3200 * 8;
req.enc.sample_rate = 16000;
req.enc.format = "mp3";
req.enc.frame_size = 3200; //frame_size为read_input的len
req.enc.sample_source = "virtual";
req.enc.read_input = enc_server_read_input; //用于虚拟采样源"virtual"编码时的数据读取操作读输入buf及其长度,返回负值自动停止编码并回调编码结束的事件
req.enc.vfs_ops = &enc_server_vfs_ops; //编码后数据在fwrite回调中输出
req.enc.vir_data_wait = 1; //等待数据编码完成才进行下一帧数据编码,数据完整
/* req.enc.no_header = 1; */
/* req.enc.bitrate = 16000; */
err = server_request(__this->enc_server, AUDIO_REQ_ENC, &req); //请求编码器
//编码虚拟源输入
static u32 enc_server_read_input(u8 *buf, u32 len)
{
int rlen;
if (__this->in_file) {
rlen = fread(buf, len, 1, __this->in_file);
if (rlen == len) {
return rlen;
} else {
fclose(__this->in_file);
__this->in_file = NULL;
return rlen;
}
} else {
return -1; //read_input返回-1表示输入数据完成,没有数据输入,让编码服务发结束消息出来AUDIO_SERVER_EVENT_END去进行结束编码的操作
}
}
开启编码请求后会自动调用enc_server_read_input输入函数,其中参数len为编码参数中设置的frame_size为设置的需要输入的数据长度,buf为需要输入给编码器的数据,返回值为实际输入数据长度,当设置返回负数时,virtual_enc获取到编码结束事件
除了在read_input数据输入获取编码结束事件,也可以在编码参数中增加req.enc.msec 设置编码时长(单位ms)
上述两种方式的去获取到编码结束编码 AUDIO_SERVER_EVENT_END,在事件中调用去结束编码服务一系列操作
想要获取到编码结束事件,一定要在上面注册编码服务回调中将编码服务回调函数enc_server_server_event_handler注册
//关闭virtual编码操作
static enc_server_test_close(void)
{
puts("--------enc_server_test_close---------");
union audio_req req = {0};
if (__this->enc_server) {
req.enc.cmd = AUDIO_ENC_CLOSE;
server_request(__this->enc_server, AUDIO_REQ_ENC, &req);
server_close(__this->enc_server);
__this->enc_server = NULL;
}
if (__this->out_file) {
fclose(__this->out_file);
__this->out_file = NULL;
}
}
//编码服务注册的回调函数
static void enc_server_server_event_handler(void *priv, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_SERVER_EVENT_ERR:
case AUDIO_SERVER_EVENT_END:
printf("VIRTUAL_AUDIO_SERVER_EVENT_END");
enc_server_test_close();
break;
case AUDIO_SERVER_EVENT_SPEAK_START:
printf("speak start ! \n");
break;
case AUDIO_SERVER_EVENT_SPEAK_STOP:
printf("speak stop ! \n");
break;
default:
break;
}
}