管道输入出错时如何让程序返回

Posted

技术标签:

【中文标题】管道输入出错时如何让程序返回【英文标题】:How to have program return when error on piped input 【发布时间】:2020-02-19 19:52:21 【问题描述】:

我目前有这个功能,通过 ffmpeg 管道 youtubedl 命令,然后将 ffmpeg 的输出管道传输到 HTTP 客户端。

func pipeThruFfmpegToMp3(vi *VideoInfo, rw web.ResponseWriter) error 
    var ffmpeg *exec.Cmd
        ffmpeg = exec.Command("ffmpeg", "-i", "-","-acodec", "libmp3lame","-f", "mp3","-")
    

    youtube := exec.Command("youtube-dl", "-f", "137", "video_url", "-o", "-")

    var ytbuf, ffbuf bytes.Buffer
    youtube.Stderr = &ytbuf
    ffmpeg.Stderr = &ffbuf

    audio, err := youtube.StdoutPipe()
    if err != nil 
        log.Printf("pipeThruFfmpegToMp3: %v\n", err)
        return err
    

    ffmpeg.Stdin = audio
    ffmpeg.Stdout = rw

    // Headers sent, no turning back now
    rw.Header().Set("Content-Type", "audio/mpeg")
    rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment;filename=\"%s.mp3\"", vi.GetSlug()))
    rw.Flush()

    youtube.Start()
    ffmpeg.Start()
    ffmpeg.Wait()
    youtube.Wait()

    // check ytvbuf, ytbuf, ffbuf for stderr errors

    if ffbuf.Len() != 0 
        log.Printf("pipeThruFfmpegToMp3: %v\n", ffbuf.String())
    

    if ytbuf.Len() != 0 
        log.Printf("pipeThruYouTubeDLToMp3: %v\n", ytbuf.String())
    

    return nil

问题是,当youtubedl出错时,它会发送一个0kb的文件,而不是返回错误而不发送文件。

那么,如果 youtubedl 出错返回而不是继续发送,我可以解决这个问题吗?

【问题讨论】:

不直接通过管道传输到客户端,不。您必须在 RAM 中缓冲输出以确定它是否是错误,并基于此发送错误响应或发送有效负载响应。 @Adrian 如果 ffmpeg 出错以避免发送 0kb,它将无法返回错误?如果我必须缓冲,最低限度是多少,我将如何做到这一点? @Adrian 我想具体来说,因为 youtube-dl 会立即出错或与 ffmpeg 一样工作,我只是觉得必须有一种方法来解决它 你可以,你只需要缓冲它而不是直接管道到客户端。 ***.com/questions/18935446/… 【参考方案1】:

我通过将 Start()Wait() 替换为 CombinedOutput() 来完成这项工作

var ffbuf bytes.Buffer
ffmpeg.Stderr = &ffbuf

audio, err := youtube.Output()
if err != nil 
    log.Printf("pipeThruFfmpegToMp3: %v\n", err)
    return err


ffmpeg.Stdin = bytes.NewReader(audio)

【讨论】:

您现在在 audio 字节切片中拥有整个 youtube 视频,这很有可能会耗尽内存。 @ShangjianDing 我把CombinedOutput()改成了Output() 这并不能解决问题。请参阅Output() 的函数签名,即func (c *Cmd) Output() ([]byte, error)。那里的[]byte 意味着它将与CombinedOutput() 做同样的事情【参考方案2】:

不丢弃youtube-dl返回的错误码怎么样?

改变

youtube.Wait()

err = youtube.Wait()
if err != nil 
    log.Printf("youtube-dl failed: %v\n", err)
    return err

更多详情请参阅documentation on Go's wait() API。

【讨论】:

以上是关于管道输入出错时如何让程序返回的主要内容,如果未能解决你的问题,请参考以下文章

加载管道程序集时出错

从共享文件夹导入 Angular 自定义管道时出错

从管道读取时出错

使用命名管道 WCF 服务时通信对象出错

尝试使用管道和网格搜索运行随机森林分类器时出错

无法从 Objective C 插件返回到 Ionic/Cordova 应用程序时出错