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

FFmpeg随机出现av_interleaved_write_frame(): Broken pipe错误的解决咨询

如何避免FFmpeg转码时的Broken pipe错误并提升稳定性

我用FFmpeg将文件或流中的音频数据转换为PCM,再转成特殊OGG/OPUS格式推流至专用设备,转码过程在独立线程中运行。有时转换正常,但多数情况下会在转码刚启动时失败。已尝试修改缓冲区大小,但无任何改善。请问如何避免Broken pipe错误并提升转码稳定性?

报错信息

av_interleaved_write_frame(): Broken pipe
Error writing trailer of pipe:: Broken pipe
Stopped ffmpeg with error code=256...

相关代码

FILE *ffmpeg_decode_audio_start_skip(const char *input_source, size_t skip_seconds)
{
    char ffmpeg_command[1024];
    snprintf(ffmpeg_command, sizeof(ffmpeg_command), "ffmpeg -i \"%s\" -f s16le -acodec pcm_s16le -ar 48000 -ac 2 -ss %" PRIuSIZE " -", input_source, skip_seconds);

    FILE *ffmpeg_pipe = NULL;

    ffmpeg_pipe = osPopen(ffmpeg_command, "r");
    if (ffmpeg_pipe == NULL)
    {
        return ffmpeg_pipe;
    }
    return ffmpeg_pipe;
}

error_t ffmpeg_stream(char *source, char *target_taf, size_t skip_seconds, bool_t *active)
{
    FILE *ffmpeg_pipe = NULL;
    error_t error = NO_ERROR;
    ffmpeg_pipe = ffmpeg_decode_audio_start_skip(source, skip_seconds);
    if (ffmpeg_pipe == NULL)
    {
        return -1;
    }

    //toniefile_t *taf = [...]

    int16_t sample_buffer[2 * 4096];
    size_t samples = sizeof(sample_buffer) / sizeof(uint16_t);
    size_t blocks_read = 0;

    *active = true;
    while (*active)
    {
        error = ffmpeg_decode_audio(ffmpeg_pipe, sample_buffer, samples, &blocks_read);
        if (error != NO_ERROR && error != ERROR_END_OF_STREAM)
        {
            break;
        }
        else if (error == ERROR_END_OF_STREAM)
        {
            error = NO_ERROR;
            break;
        }
        //toniefile_encode(taf, sample_buffer, blocks_read / 2);
    }

    ffmpeg_decode_audio_end(ffmpeg_pipe, error);
    //toniefile_close(taf);

    return error;
}

error_t ffmpeg_decode_audio(FILE *ffmpeg_pipe, int16_t *buffer, size_t size, size_t *blocks_read)
{
    if (ffmpeg_pipe == NULL)
        return ERROR_ABORTED;

    *blocks_read = 0;
    size_t chunk_size = 4096;
    while (*blocks_read < size)
    {
        size_t remaining_samples = size - *blocks_read;
        size_t samples_to_read = (remaining_samples < chunk_size) ? remaining_samples : chunk_size;

        size_t read = fread(&buffer[*blocks_read], sizeof(int16_t), samples_to_read, ffmpeg_pipe);

        if (read == 0)
        {
            if (*blocks_read > 0)
            {
                return NO_ERROR;
            }
            else
            {
                return ERROR_END_OF_STREAM; // End of audio data
            }
        }
        *blocks_read += read;
    }
    return NO_ERROR;
}

问题分析与解决方案

1. 核心问题根源

Broken pipe错误本质是FFmpeg进程向管道写入数据时,读取端(你的应用)已经提前关闭,或者读取速度跟不上写入速度,导致管道被系统中断。结合你的代码,主要有几个触发点:FFmpeg输出干扰、管道读取逻辑僵化、进程退出时资源清理不彻底、推流端异常未同步。

2. 针对性修复

(1)优化FFmpeg命令参数

给FFmpeg添加IO优化和输出控制参数,避免日志混入PCM数据,同时提升管道写入稳定性:

snprintf(ffmpeg_command, sizeof(ffmpeg_command), 
        "ffmpeg -hide_banner -loglevel error -i \"%s\" -f s16le -acodec pcm_s16le -ar 48000 -ac 2 -ss %" PRIuSIZE " -avioflags direct -", 
        input_source, skip_seconds);
  • -hide_banner -loglevel error:关闭冗余日志输出,防止非PCM数据混入管道,干扰读取逻辑
  • -avioflags direct:优化IO路径,减少缓冲延迟,降低管道阻塞概率

(2)修改管道读取逻辑,避免强制读满

当前ffmpeg_decode_audio强制读满缓冲区才返回,若FFmpeg输出速度慢或推流端处理不及时,会导致FFmpeg写管道阻塞。改成允许读取部分数据就返回:

error_t ffmpeg_decode_audio(FILE *ffmpeg_pipe, int16_t *buffer, size_t size, size_t *blocks_read)
{
    if (ffmpeg_pipe == NULL)
        return ERROR_ABORTED;

    *blocks_read = 0;
    size_t chunk_size = 4096;
    // 单次读取,不强制填满缓冲区
    size_t read = fread(buffer, sizeof(int16_t), min(size, chunk_size), ffmpeg_pipe);
    
    if (read == 0)
    {
        if (feof(ffmpeg_pipe))
        {
            return ERROR_END_OF_STREAM;
        }
        else
        {
            return ERROR_ABORTED; // 管道异常
        }
    }
    *blocks_read = read;
    return NO_ERROR;
}

(3)完善进程退出时的资源清理

用pclose替代fclose关闭管道,确保等待FFmpeg进程正常退出,避免僵尸进程,同时让FFmpeg能正确写入trailer:

void ffmpeg_decode_audio_end(FILE *ffmpeg_pipe, error_t error)
{
    if (ffmpeg_pipe)
    {
        // pclose会等待子进程结束并回收资源
        pclose(ffmpeg_pipe);
    }
}

(4)同步推流端错误状态

如果推流到专用设备时出现连接失败或异常,toniefile_encode需要及时返回错误,你要在主循环中检测到错误后立即设置*active = false,让读取端停止读取,避免FFmpeg持续写无效管道:

// 在ffmpeg_stream的循环中补充:
error = toniefile_encode(taf, sample_buffer, blocks_read / 2);
if (error != NO_ERROR)
{
    *active = false;
    break;
}

(5)添加FFmpeg进程状态检查

在读取管道的循环中,定期检查FFmpeg子进程是否意外终止(比如用waitpid配合WNOHANG),如果进程已退出,直接终止读取流程:

// 示例:在ffmpeg_decode_audio中添加进程状态检查(需根据平台适配)
#include <sys/wait.h>

pid_t ffmpeg_pid = ...; // 保存osPopen返回的子进程ID
int status;
if (waitpid(ffmpeg_pid, &status, WNOHANG) != 0)
{
    return ERROR_ABORTED;
}

3. 调试建议

  • 临时将FFmpeg日志级别改为-loglevel debug并输出到文件,查看启动阶段的详细错误,排查输入源是否正常、参数是否合法
  • 先用本地音频文件测试,排除流源不稳定的影响

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 09:44:51