汽车导购
fwrite(大疆无人机喊话器Opus裸流编码)

基于大疆上云API,使用喊话器控件,进行含喊话,但上云API不直接支持,需要自己根据喊话器要求的参数进行编码为Opus裸流,写此目的是让其他人遇到该问题的人避坑。

官方文档中,参数如下图

大疆无人机喊话器Opus裸流编码nerror="javascript:errorimg.call(this);">

但是根据该参数进行编码,得到的Opus裸流文件,与大疆-司空2上得到的裸流文件,是其大小的0.5倍,且编码之后得到的文件,喊话器不能正常播放声音,且大疆SDK技术论坛上的客户支撑,感觉也很”官方“回复,使用官方提供的这些参数,在实现过程中也发现一些不合理之处,且根据官方参数,自己选用的一个文件进行编码,不可能得到大疆司空2生成的裸流文件那么大,后怀疑官方参数有误,经过尝试,将编码参数16kps改为了32kps编码之后得到的opus裸流文件,就可以正常通过喊话器进行播放了,附带转码C代码(直接gcc编译该c文件,生成可执行文件),然后,将输入的pcm文件,与输出的目标opus文件的绝对地址作为参数即可转码,也存在基于python的实现,但是底层也会调用该opus库,如果有需要可以私发。

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <opus/opus.h>// 需要自行安装opus依赖,可通过apt 命令进行安装#define SAMPLE_RATE 16000#define CHANNELS 1#define BITERATE 32000#define frame_SIZE 40#define MAX_frame_BYTES 160int pcm_opus_raw(const char *pcm_path, const char *opus_path) {	// 1. 打开PCM文件(读二进制)和Opus裸流文件(写二进制)	FILE *pcm_fp = fopen(pcm_path, "rb");	FILE *opus_fp = fopen(opus_path, "wb");	if (!pcm_fp || !opus_fp) {		perror("File open failed");		return -1;	}	// 2. 初始化Opus编码器	int error;	OpusEncoder *encoder = opus_encoder_create(SAMPLE_RATE, CHANNELS, OPUS_APPLICATION_VOIP, &error);	if (error != OPUS_OK) {		fprintf(stderr, "Encoder create failed: %s\n", opus_strerror(error));		return -1;	}	// 3. 设置编码器参数	opus_encoder_ctl(encoder, OPUS_SET_BITRATE(BITERATE));	opus_encoder_ctl(encoder, OPUS_SET_EXPERT_frame_DURATION(frame_SIZE));	opus_encoder_ctl(encoder, OPUS_SET_VBR(0));	opus_encoder_ctl(encoder, OPUS_SET_COMPLEXITY(0));	// 4. 计算单帧采样点数和字节数(16bit 有符号整数)	const int frame_samples = SAMPLE_RATE * frame_SIZE / 1000;	const int frame_bytes = frame_samples * CHANNELS * sizeof(opus_int16);	opus_int16 *pcm_frame = (opus_int16 *)malloc(frame_bytes);	if (!pcm_frame) {		perror("Malloc failed");		return -1;	}	// 5. 分帧编码主循环	unsigned char opus_buf[MAX_frame_BYTES];	size_t read_bytes;	while ((read_bytes = fread(pcm_frame, 1, frame_bytes, pcm_fp)) == frame_bytes) {		// 编码 PCM 帧为 Opus 包		int encode_len = opus_encode(			encoder, pcm_frame, frame_samples,			opus_buf, MAX_frame_BYTES		);        if (encode_len < 0) {            fprintf(stderr, "Encode failed: %s\n", opus_strerror(encode_len));            break;        }        // 写入 Opus 裸流        fwrite(opus_buf, 1, encode_len, opus_fp);	}	// 6. 资源释放	free(pcm_frame);	opus_encoder_destroy(encoder);	fclose(pcm_fp);	fclose(opus_fp);	printf("Encode success! Output: %s\n", opus_path);	return 0;}int main(int argc, char *argv[]) {	if (argc != 3) {		fprintf(stderr, "Usage: %s <input.pcm> <output.opus>\n", argv[0]);		return -1;	}	const char *pcm_path = argv[1];	const char *opus_path = argv[2];	return pcm_opus_raw(pcm_path, opus_path);}

顶一下()     踩一下()

热门推荐

发表评论
0评