如何用FFmpeg合并LINEAR16编码音频并转换格式?
合并LINEAR16编码音频并转码的PHP实现方案
问题背景
使用Google Text-to-Speech PHP客户端生成LINEAR16编码的音频片段,尝试直接拼接字节内容后音频损坏无法播放,原生PHP解析字节转格式也失败,需要用FFmpeg实现片段合并并转换编码。
为什么直接拼接无效?
Google TTS返回的LINEAR16编码音频带有WAV文件头,每个片段都包含独立的文件头信息,直接拼接会导致最终文件存在多个无效的头结构,播放器无法正确识别。
用FFmpeg实现的步骤
- 将每个TTS返回的音频片段保存为独立的临时WAV文件
- 使用FFmpeg的
concat demuxer合并所有临时文件(Google TTS的LINEAR16默认是16kHz单声道,所有片段参数一致,无需额外调整) - 将合并后的音频转换为目标编码(比如MP3)
- 清理临时文件
PHP代码实现
<?php // 初始化Google TTS客户端 $client = new TextToSpeechClient(); $synthesisInputText = new SynthesisInput(); $audioConfig = new AudioConfig(); $audioConfig->setAudioEncoding(AudioEncoding::LINEAR16); $voice = new VoiceSelectionParams(); $voice->setLanguageCode('en-US'); $voice->setName('en-US-Neural2-A'); // 创建临时目录存放音频片段 $tempDir = sys_get_temp_dir() . '/tts_audio_fragments'; mkdir($tempDir, 0777, true); $tempFiles = []; foreach($txt_array as $k => $txt) { $synthesisInputText->setText($txt); $response = $client->synthesizeSpeech($synthesisInputText, $voice, $audioConfig); $media = $response->getAudioContent(); // 保存为临时WAV文件 $tempFile = $tempDir . "/fragment_{$k}.wav"; file_put_contents($tempFile, $media); $tempFiles[] = "file '" . addslashes($tempFile) . "'"; } // 生成FFmpeg的concat列表文件 $concatList = $tempDir . '/concat_list.txt'; file_put_contents($concatList, implode("\n", $tempFiles)); // 执行FFmpeg命令:合并并转成MP3 $outputFile = 'final_audio.mp3'; $ffmpegCmd = "ffmpeg -f concat -safe 0 -i {$concatList} -c:a libmp3lame {$outputFile}"; exec($ffmpegCmd, $output, $returnVar); // 检查命令执行结果 if ($returnVar !== 0) { die("FFmpeg执行失败:" . implode("\n", $output)); } // 清理临时文件和目录 foreach($tempFiles as $fileLine) { $file = trim(str_replace("file '", "", str_replace("'", "", $fileLine))); unlink($file); } unlink($concatList); rmdir($tempDir); echo "音频合并完成,输出文件:{$outputFile}"; ?>
注意事项
- 确保服务器环境已安装FFmpeg,且PHP的
exec函数未被禁用 - 如果需要转成其他编码,修改FFmpeg命令中的
-c:a参数(比如转成AAC用-c:a aac) - 临时文件目录要确保有读写权限
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

