使用libopus解码原始音频时遭遇UnicodeDecodeError问题求助
解决libopus解码时的UnicodeDecodeError问题
问题概述
尝试用libopus解码一段5秒的连续原始音频数据,过程中将初始为str类型的数据转成列表后,执行代码:
bytelist = [x.decode('utf-8')for x in new_list]
收到错误:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf9 in position 4: invalid start byte
涉及的二进制音频数据片段如下:
b'\x00Z\x15\x02\xf9\x15q\x9d1$\xd2\xde:\xb44\xaf\x8d_4\xbe\xe5\x02\x1f\x87\xe1\x84x\xb1\xcb\x13;XY+\x9b\xd8\xeb\xc1\nG\xe9\x1b\xba\x12\xe4\x9d\xaa4\xce\xa0r\xd5\xcf\x00\xa6\xaa2\x17nGw\xc3Sm\t\xe8\x1c\xc2\xb5&+\xe8}++h\xa1\x1c\x1e\x9e)\xbb\x08\xa9\xd5\x960\x17\xb1\xb4\xa8*\x90x\xd8jK\x99:\xc7\xb7\x8d\xc2\xc0t\x80' b'\x01ZH\x81\x8c\x97jA\xfeb\xecg\xc2P\r9"\xe9\x8e\xaa-k\xef\xe6b2@\xdc\x1e\xb4\xe8\xd3\xbc4\xb4aU\xf1\xccG\xbb\xf0:>\x93p\xd0\x18`?\x9f\x1c\xa3\xf2\'\x8a\xf3\x07\xe7:\xe3\x1a\xc5XbG\xc0\x89\xfb)d\xba\xcf\x8b0\x03HmR\x9b;I\xff\xbcw!5\x93\x9b\xdb\x0e\x13fH\xde\xa5\x93\xb7\x8b\n}\x19\x0b\xd2\xd0\xd9\xa1j7s\xda\x84\x85\xe0%\xfb\x07\xa5U\x08\x84\xfdg:\^\xd5\xb6\xe6\xdbV\xff\xff(' b'\x02Z7\x03\x0e\xe77\x17\xe3\xff\x9d\xb3\xe5\xa3\xcd\x84X\xcb\x00~\x88\xc0T<\xa3\xe8\xd3\x02\xe8Cs\xef\x15\x10\x07\x9c\xd1\xea\x96\x94\xe7\x9d\x9cE\xf41~\xfb\xbfo\n\xa2\x15\xbb\x9ex\x910\x03\x0fw^U\\P\x1ey\x006W\xcb[\x1a{\xb9\xf8\xacO\xf7\xeb\xffo\x14;\xa0\xa9X\xe6{*\xac\xa9\x14\x96\xc4\xdaq\x80\x0eC^\xd4w\xe2?\xfd\xa2\x0fCk\xe8\xe3\x02\x0b3\xd3' b"\x03Z8\x03\x0e\xa5\x9b\xb3\x1bV\x84\xc5\xc3\x0c5\x06\xf0\x10\x9f\x00\x87N\xdd\xb9\x8e\xe3\x1e\xaenj\xb8>\xb76\x80ndwZ\xa11\x0c\n\xe1\xeaz'\x8d\x81E\xaf\x81\xb4\xf9\xb4\xfb3v\xd9\x02\xd4\xca\x11]J\x18\x93\x95\x01\xbc\xbb\xce\x8d\xd1#\x9cg\x19,& p\x12\x058\x86~A\xbb>p\xec/T9\xa0\xa6\x9eND\x81\x13\xe2\xa8z\xb3\x18|M \xb2\xd8\x94/\xdcr\x01\x82\x84" b'\x04Z8\x02\xd5a\xc0Y\xa6\xc3\t\x19t\x0f]\xd3q\x06\xfe\x91\x80\xd5\x92\xd5N\xf4f_\xd4\x05(DjcshX\xc9\x0c\xa9\xc3\x94!\xdbI\xe8\x84\x1b\xe6\x91~9dY@\x115\xba\x91\x02\xd5oL\x1d\xc4\xe1+\x9e~K\x88\xd8o\xc1m\x7f\xf3\xbfKN\xc1\n\xee/k\x93p\xfe\xfb\xb4\x8d\xa5\xfc\xb9\xdd1\x9b\xa4"\xc1\xed4\x1e\xa4\x8b\xc4\x95'
错误原因
核心问题是错误地将二进制音频数据转换为字符串:
- 在
stream_receive函数中,执行了DATA = str(msg.data),把二进制(bytes)类型的音频数据强制转成字符串,这会破坏原始二进制结构——音频字节并非合法的UTF-8字符序列。 - 后续尝试对这些被破坏的字符串执行
decode('utf-8'),自然会触发解码错误:音频数据本质是二进制流,不是文本,不需要也不能用UTF-8解码。
修复步骤
1. 修正stream_receive函数,保留原始二进制数据
直接将提取后的音频bytes存入new_list,不要转成字符串:
async def stream_receive(ws): await ws.receive_str() global new_list new_list = [] # 初始化列表存储音频bytes async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: data = json.loads(msg.data) if data["command"] == "on_stream_stop": print("Stream stopped") return False elif msg.type == aiohttp.WSMsgType.BINARY: audio_byte = msg.data[8:] # 提取纯音频数据 print("audio_byte type:", type(audio_byte)) # 应为bytes类型 new_list.append(audio_byte) # 直接存入bytes,不转字符串
2. 移除错误的UTF-8解码步骤
解码libopus时,直接使用new_list中的原始bytes数据,不需要额外解码:
# 替换原错误的bytelist生成代码 # bytelist = [x.decode('utf-8')for x in new_list] # 删除这行 audio_frames = new_list # 直接用bytes列表作为opus帧 # 后续libopus解码示例(伪代码) import opuslib decoder = opuslib.Decoder(sample_rate=48000, channels=1) pcm_data = b'' for frame in audio_frames: pcm_data += decoder.decode(frame)
3. 修正初始化流程中的数据处理
确保new_list在函数内正确初始化,避免未定义的问题:
await asyncio.wait_for(authenticate(ws, username, password, token, channel), WS_TIMEOUT_SEC) print(f"User {username} has been authenticated on {channel} channel") print("Wait for response") stream_id = 1 print("Receiving started") await asyncio.gather(stream_receive(ws)) print("Receiving ended") print("") for idx, frame in enumerate(new_list): print(f"Frame {idx}:", frame, "\n") print("Data received successfully") await asyncio.wait_for(stream_stop(ws, stream_id), WS_TIMEOUT_SEC)
关键总结
- 音频数据是二进制流,必须以
bytes类型处理,禁止转成字符串后再解码。 - 只在处理文本消息(如JSON指令)时使用字符串转换,二进制消息直接操作原始bytes。
内容的提问来源于stack exchange,提问作者Ayush Pradhan
相关产品推荐
相关产品推荐

