You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决PHP中FFmpeg的av_interleaved_write_frame()管道破裂错误

PHP中FFmpeg流式音频转Google Cloud Speech-to-Text遇到的问题

我在PHP中使用FFmpeg将网络音频流转换后传输到Google Cloud Speech-to-Text时遇到错误,返回av_interleaved_write_frame(): Broken pipe。尝试过延迟脚本、参考Python方案都没用。

FFmpeg输出信息

built with gcc 8 (GCC)
  cpudetect
  libavutil      56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100
Input #0, mp3, from 'https://npr-ice.streamguys1.com/live.mp3':
  Metadata:
    icy-br          : 96
    icy-description : NPR Program Stream
    icy-genre       : News and Talk
    icy-name        : NPR Program Stream
    icy-pub         : 0
    StreamTitle     :
  Duration: N/A, start: 0.000000, bitrate: 96 kb/s
    Stream #0:0: Audio: mp3, 32000 Hz, stereo, fltp, 96 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (mp3 (mp3float) -> pcm_s16le (native))
Press [q] to stop, [?] for help
Output #0, s16le, to 'pipe:':
  Metadata:
    icy-br          : 96
    icy-description : NPR Program Stream
    icy-genre       : News and Talk
    icy-name        : NPR Program Stream
    icy-pub         : 0
    StreamTitle     :
    encoder         : Lavf58.29.100
    Stream #0:0: Audio: pcm_s16le, 16000 Hz, mono, s16, 256 kb/s
    Metadata:
      encoder         : Lavc58.54.100 pcm_s16le
**av_interleaved_write_frame(): Broken pipe** 256.0kbits/s speed=1.02x
**Error writing trailer of pipe:: Broken pipe**
size=      54kB time=00:00:01.76 bitrate= 250.8kbits/s speed=0.465x
video:0kB audio:55kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
Conversion failed!

初始PHP代码

require_once 'vendor/autoload.php';
    
$projectId = "xxx-45512";
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . __DIR__ . '/xxx-45512-be3eb805f1d7.json');

// Database connection
$pdo = new PDO('mysql:host=localhost;dbname=', '', '');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$url = "https://npr-ice.streamguys1.com/live.mp3";

$ffmpegCmd = "ffmpeg -re -i $url -acodec pcm_s16le -ac 1 -ar 16000 -f s16le -";

$fp = popen($ffmpegCmd, "r");
if (!$fp) {
    die("Failed to open FFmpeg stream.");
}
sleep(5);

try {
    $client = new SpeechClient(['transport' => 'grpc', 'credentials' => json_decode(file_get_contents(getenv('GOOGLE_APPLICATION_CREDENTIALS')), true)]);
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage(); 
    exit;
}

$recognitionConfig = new RecognitionConfig([
    'auto_decoding_config' => new AutoDetectDecodingConfig(),
    'language_codes' => ['en-US'],
    'model' => 'long',
]);

$streamingConfig = new StreamingRecognitionConfig([
    'config' => $recognitionConfig,
]);

$configRequest = new StreamingRecognizeRequest([
    'recognizer' => "projects/$projectId/locations/global/recognizers/_",
    'streaming_config' => $streamingConfig,
]);


function streamAudio($fp)
{
    while (!feof($fp)) {
        yield fread($fp, 4096);
    }
}

$responses = $client->streamingRecognize([
'requests' => (function () use ($configRequest, $fp) {
        yield $configRequest; // Send initial config
        foreach (streamAudio($fp) as $audioChunk) {
            yield new StreamingRecognizeRequest(['audio' => $audioChunk]);
        }
    })()
]);

foreach ($responses as $response) {
    foreach ($response->getResults() as $result) {
        $transcript = $result->getAlternatives()[0]->getTranscript();

        // Insert into the database
        $stmt = $pdo->prepare("INSERT INTO transcriptions (transcript) VALUES (:transcript)");
        $stmt->execute(['transcript' => $transcript]);
    }
}


pclose($fp);
$client->close();

更新:

调试后Broken pipe错误消失,流可以运行,但音频无法转录并存入数据库,关闭流时出现新错误:

No grpc-status found in response trailers

更新后的代码

$handle = popen($ffmpegCommand, "r");

try {
    $client = new SpeechClient(['transport' => 'grpc', 'credentials' => json_decode(file_get_contents(getenv('GOOGLE_APPLICATION_CREDENTIALS')), true)]);
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage(); 
    exit;
}

try {
$recognitionConfig = (new RecognitionConfig())
    ->setAutoDecodingConfig(new AutoDetectDecodingConfig())
    ->setLanguageCodes(['en-US'], ['en-UK'])
    ->setModel('long');
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage(); 
    exit;
}

try {
    $streamConfig = (new StreamingRecognitionConfig())
    ->setConfig($recognitionConfig);
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage();
    exit;
}
try {
    $configRequest = (new StreamingRecognizeRequest())
    ->setRecognizer("projects/$projectId/locations/global/recognizers/_")
    ->setStreamingConfig($streamConfig);
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage(); 
    exit;
}

$stream = $client->streamingRecognize();
$stream->write($configRequest);

mysqli_query($conn, "INSERT INTO transcriptions (transcript) VALUES ('bef')");

while (!feof($handle)) {
    $chunk = fread($handle, 25600);
    // printf('chunk: ' . $chunk);
    if ($chunk !== false) {
        try {
            $request = (new StreamingRecognizeRequest())
                    ->setAudio($chunk);
                $stream->write($request);
        } catch (Exception $e) {
            printf('Errorc: ' . $e->getMessage());
        }
    }
}


$insr = json_encode($stream);
mysqli_query($conn, "INSERT INTO transcriptions (transcript) VALUES ('$insr')");

foreach ($stream->read() as $response) {
    mysqli_query($conn, "INSERT INTO transcriptions (transcript) VALUES ('loop1')");
    foreach ($response->getResults() as $result) {
        mysqli_query($conn, "INSERT INTO transcriptions (transcript) VALUES ('loop2')");
        foreach ($result->getAlternatives() as $alternative) {
            $trans = $alternative->getTranscript();
            mysqli_query($conn, "INSERT INTO transcriptions (transcript) VALUES ('$trans')");
        }
    }
}

pclose($handle);
$stream->close();
$client->close();

内容的提问来源于stack exchange,提问作者Adekunle Adeyeye

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 14:25:52