package stream import ( "io" "os" "sync" ) // pipeReader bridges io.Reader to a file descriptor that can be used as FFmpeg input type pipeReader struct { r io.Reader pr *io.PipeReader pw *io.PipeWriter f *os.File err error mu sync.Mutex } // newPipeReader creates a new pipe reader that bridges io.Reader to a pipe func newPipeReader(r io.Reader) (*pipeReader, error) { pr, pw := io.Pipe() return &pipeReader{ r: r, pr: pr, pw: pw, }, nil } // start begins copying data from the underlying reader to the pipe in background func (p *pipeReader) start() { go func() { buf := make([]byte, 32768) for { n, err := p.r.Read(buf) if n > 0 { _, writeErr := p.pw.Write(buf[:n]) if writeErr != nil { p.mu.Lock() p.err = writeErr p.mu.Unlock() p.pw.CloseWithError(writeErr) return } } if err != nil { p.pw.CloseWithError(err) return } } }() } // Read implements io.Reader func (p *pipeReader) Read(data []byte) (n int, err error) { return p.pr.Read(data) } // Close closes the pipe func (p *pipeReader) Close() error { err := p.pr.Close() p.pw.Close() return err } // Error returns any error that occurred during reading func (p *pipeReader) Error() error { p.mu.Lock() defer p.mu.Unlock() return p.err }