fix: amr_decoder 支持 audio/pcm 直通跳过 ffmpeg
Browse files
src/router/xtc_recognize/amr_decoder.py
CHANGED
|
@@ -17,6 +17,7 @@ async def decode_to_pcm_s16le(
|
|
| 17 |
duration_sec: int = 3,
|
| 18 |
sample_rate: int = 8000,
|
| 19 |
channels: int = 1,
|
|
|
|
| 20 |
) -> bytes:
|
| 21 |
"""把任意音频(amr/mp3/wav/m4a 等)转成 8kHz 单声道 PCM s16le。
|
| 22 |
|
|
@@ -25,6 +26,7 @@ async def decode_to_pcm_s16le(
|
|
| 25 |
duration_sec: 截取时长(秒),默认 3
|
| 26 |
sample_rate: 采样率,默认 8000(网易云 shazam_v2 要求)
|
| 27 |
channels: 声道数,默认 1
|
|
|
|
| 28 |
|
| 29 |
Returns:
|
| 30 |
PCM s16le 字节流
|
|
@@ -32,6 +34,11 @@ async def decode_to_pcm_s16le(
|
|
| 32 |
Raises:
|
| 33 |
RuntimeError: ffmpeg 失败
|
| 34 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
args = [
|
| 36 |
"ffmpeg",
|
| 37 |
"-i", "pipe:0",
|
|
@@ -42,7 +49,7 @@ async def decode_to_pcm_s16le(
|
|
| 42 |
"-t", str(duration_sec),
|
| 43 |
"pipe:1",
|
| 44 |
]
|
| 45 |
-
logger.info("[amr-decoder] ffmpeg start, input=%d bytes", len(audio_bytes))
|
| 46 |
|
| 47 |
proc = await asyncio.create_subprocess_exec(
|
| 48 |
*args,
|
|
|
|
| 17 |
duration_sec: int = 3,
|
| 18 |
sample_rate: int = 8000,
|
| 19 |
channels: int = 1,
|
| 20 |
+
mime: str = "",
|
| 21 |
) -> bytes:
|
| 22 |
"""把任意音频(amr/mp3/wav/m4a 等)转成 8kHz 单声道 PCM s16le。
|
| 23 |
|
|
|
|
| 26 |
duration_sec: 截取时长(秒),默认 3
|
| 27 |
sample_rate: 采样率,默认 8000(网易云 shazam_v2 要求)
|
| 28 |
channels: 声道数,默认 1
|
| 29 |
+
mime: MIME 类型。若为 audio/pcm 则视为已是 PCM s16le 直接截断返回
|
| 30 |
|
| 31 |
Returns:
|
| 32 |
PCM s16le 字节流
|
|
|
|
| 34 |
Raises:
|
| 35 |
RuntimeError: ffmpeg 失败
|
| 36 |
"""
|
| 37 |
+
# 裸 PCM 直通(便于测试 / 手表若直接录 PCM 也支持)
|
| 38 |
+
if mime in ("audio/pcm", "audio/x-pcm", "application/pcm"):
|
| 39 |
+
needed = sample_rate * channels * 2 * duration_sec
|
| 40 |
+
return audio_bytes[:needed]
|
| 41 |
+
|
| 42 |
args = [
|
| 43 |
"ffmpeg",
|
| 44 |
"-i", "pipe:0",
|
|
|
|
| 49 |
"-t", str(duration_sec),
|
| 50 |
"pipe:1",
|
| 51 |
]
|
| 52 |
+
logger.info("[amr-decoder] ffmpeg start, input=%d bytes mime=%s", len(audio_bytes), mime)
|
| 53 |
|
| 54 |
proc = await asyncio.create_subprocess_exec(
|
| 55 |
*args,
|
src/router/xtc_recognize/recognize.py
CHANGED
|
@@ -33,7 +33,7 @@ async def recognize_from_audio(
|
|
| 33 |
)
|
| 34 |
|
| 35 |
# 1) 转码
|
| 36 |
-
pcm = await decode_to_pcm_s16le(audio_bytes, duration_sec=duration)
|
| 37 |
|
| 38 |
# 2) 指纹
|
| 39 |
fp = await generate_fp(pcm)
|
|
|
|
| 33 |
)
|
| 34 |
|
| 35 |
# 1) 转码
|
| 36 |
+
pcm = await decode_to_pcm_s16le(audio_bytes, duration_sec=duration, mime=mime)
|
| 37 |
|
| 38 |
# 2) 指纹
|
| 39 |
fp = await generate_fp(pcm)
|