Windows音频开发中遇到的编码问题与解决过程

一旦在开发过程中遇到编码问题,保证你一天的心情将会糟糕透顶, 一个文件编码就能影响你一天的工作。为了总结经验,特地将整个过程重现一遍。

整个工程是基于Visual Studio 2022开发的Qt工程。

根据向导创建完成后,没有去查看文件的编码,就直接开干。刚开始遇见了一个小问题,运行过程中发现窗口标题居然是乱码。我也没去深究,想到这个很简单嘛,使用QString::fromLocal8Bit()函数就能解决问题。

将代码

this->setWindowTitle("录音");

修改为

this->setWindowTitle(QString::fromLocal8Bit("录音"));

之后,窗口标题乱码问题确实解决了。

 然后,继续编写核心代码,使用FFmpeg打开音频输入设备。

引入头文件库文件

extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>

#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avdevice.lib")
#pragma comment(lib,"avformat.lib")

}

编写如下逻辑,感觉良好。

avdevice_register_all();

AVFormatContext* context = nullptr;
const AVInputFormat* format = av_find_input_format("dshow");
char device[] = "audio=麦克风阵列 (Realtek High Definition Audio)";

int ret = avformat_open_input(&context, device, format, nullptr);
if (ret < 0) {
	qDebug() << "无法打开音频输入设备";
	return;
}

QFile file("./my.pcm");
file.open(QIODevice::WriteOnly);
if (!file.isOpen())
{
	qDebug() << "文件打开失败";
	return;
}

AVPacket packet;
int count = 10;
while (--count > 0 && av_read_frame(context, &packet) == 0)
{
	file.write((const char*)packet.data, packet.size);
}

file.close();
avformat_close_input(&context);

可是,在运行过程中发现不是那么回事。首先在

qDebug() << "文件打开失败";

这行代码,就发现一个非常奇怪的问题,居然编译不通过

于是我不管三七二十一,直接将它注释掉,编译通过。

当时的我一脸懵逼,还以为是Qt与Visual Studio集成出现的兼容性问题,不能使用qDebug()进行调试程序。把

qDebug() << "文件打开失败";

这行代码注释掉之后,继续调试程序。此时,发现控制台出现很多乱码,而且从输出信息上面看到:

程序无法找到音频设备,但是从另一个侧面,我是能够获取到该设备信息的。

通过命令行,输入如下命令可以获取音频输入设备信息。

 ffmpeg -list_devices true -f dshow -i dummy

这行代码

int ret = avformat_open_input(&context, device, format, nullptr); 

的返回值总是-5。好像真的没有什么头绪了哟。通过不断的思考和查找解决方案,说是“音频输入设备名称中含有中文,需要进行编码转换”,将ANSI编码转换为UTF-8编码就可以了。

 我尝试着这种解决方案,加入了如下的转换函数

std::string AnsiToUTF8(const char* _ansi, int _ansi_len)
{
	std::string str_utf8("");
	wchar_t* pUnicode = NULL;
	BYTE* pUtfData = NULL;
	do
	{
		int unicodeNeed = MultiByteToWideChar(CP_ACP, 0, _ansi, _ansi_len, NULL, 0);
		pUnicode = new wchar_t[unicodeNeed + 1];
		memset(pUnicode, 0, (unicodeNeed + 1) * sizeof(wchar_t));
		int unicodeDone = MultiByteToWideChar(CP_ACP, 0, _ansi, _ansi_len, (LPWSTR)pUnicode, unicodeNeed);

		if (unicodeDone != unicodeNeed)
		{
			break;
		}

		int utfNeed = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)pUnicode, unicodeDone, (char*)pUtfData, 0, NULL, NULL);
		pUtfData = new BYTE[utfNeed + 1];
		memset(pUtfData, 0, utfNeed + 1);
		int utfDone = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)pUnicode, unicodeDone, (char*)pUtfData, utfNeed, NULL, NULL);

		if (utfNeed != utfDone)
		{
			break;
		}
		str_utf8.assign((char*)pUtfData);
	} while (false);

	if (pUnicode)
	{
		delete[] pUnicode;
	}
	if (pUtfData)
	{
		delete[] pUtfData;
	}

	return str_utf8;
}

该函数需要引入头文件

#include <Windows.h>

,然后在使用函数

avformat_open_input(&context, device, format, nullptr);

打开音频输入设备之前,调用AnsiToUTF8函数,进行编码转换。经过尝试,果然可以。

std::string result = AnsiToUTF8(device, sizeof(device));
int ret = avformat_open_input(&context, result.c_str(), format, nullptr);

突然,好像什么都明白了一样。转过去查看了一下该程序文件的编码,吓了一跳,原来就是这该死的编码在作怪。

 终于明白了整个问题的原委。于是我索性将它更改为UTF-8编码


此时,运行程序再次出现乱码。

 不过这时的我已不再像之前那样恐慌了,我将这行代码

this->setWindowTitle(QString::fromLocal8Bit("录音"));

修改为

this->setWindowTitle("录音");

同时,将之前引入的转换ANSI编码为UTF-8编码的那部分代码去掉。因为已不再需要它的帮助了。完成后再次运行测试,完美解决问题。

最后,我重新回过头来发现,原来之前报的那个错误其实就已经告诉我了,程序文件的编码与函数调用需要的编码不一致,导致无法找到音频输入设备的错误。现在也明白了为什么

qDebug() << "文件打开失败";

这行代码会导致编译失败的问题。经过我仔细的分析与调试,原来"文件打开失败"这句话中的“”和“”这两个中文字符在GB2312编码下与ANSI编码发生冲突

 

我总结了一下,作为程序员的我们还是得多思考为什么多总结经验教训。不然有一天确实是会被程序世界现实世界一起联合给“打败”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值