如何解决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
相关产品推荐
相关产品推荐

