Live video on the AT Protocol
1package media
2
3import (
4 "context"
5 "fmt"
6 "io"
7
8 "github.com/livepeer/lpms/ffmpeg"
9 "golang.org/x/sync/errgroup"
10)
11
12func (mm *MediaManager) SegmentToMKV(ctx context.Context, user string, rendition string, w io.Writer) error {
13 muxer := ffmpeg.ComponentOptions{
14 Name: "matroska",
15 }
16 return mm.SegmentToStream(ctx, user, rendition, muxer, w)
17}
18
19func (mm *MediaManager) SegmentToMP4(ctx context.Context, user string, rendition string, w io.Writer) error {
20 muxer := ffmpeg.ComponentOptions{
21 Name: "mp4",
22 Opts: map[string]string{
23 "movflags": "frag_keyframe+empty_moov",
24 },
25 }
26 return mm.SegmentToStream(ctx, user, rendition, muxer, w)
27}
28
29func (mm *MediaManager) SegmentToStream(ctx context.Context, user string, rendition string, muxer ffmpeg.ComponentOptions, w io.Writer) error {
30 tc := ffmpeg.NewTranscoder()
31 defer tc.StopTranscoder()
32 ourl, or, odone, err := mm.HTTPPipe()
33 if err != nil {
34 return err
35 }
36 defer odone()
37 iname := fmt.Sprintf("%s/playback/%s/%s/concat", mm.cli.OwnInternalURL(), user, rendition)
38 in := &ffmpeg.TranscodeOptionsIn{
39 Fname: iname,
40 Transmuxing: true,
41 Profile: ffmpeg.VideoProfile{},
42 Loop: -1,
43 Demuxer: ffmpeg.ComponentOptions{
44 Name: "concat",
45 Opts: map[string]string{
46 "safe": "0",
47 "protocol_whitelist": "file,http,https,tcp,tls",
48 },
49 },
50 }
51 out := []ffmpeg.TranscodeOptions{
52 {
53 Oname: ourl,
54 VideoEncoder: ffmpeg.ComponentOptions{
55 Name: "copy",
56 },
57 AudioEncoder: ffmpeg.ComponentOptions{
58 Name: "copy",
59 },
60 Profile: ffmpeg.VideoProfile{Format: ffmpeg.FormatNone},
61 Muxer: muxer,
62 },
63 }
64 g, _ := errgroup.WithContext(ctx)
65 g.Go(func() error {
66 <-ctx.Done()
67 or.Close()
68 return nil
69 })
70 g.Go(func() error {
71 _, err := tc.Transcode(in, out)
72 tc.StopTranscoder()
73 return err
74 })
75 g.Go(func() error {
76 _, err := io.Copy(w, or)
77 return err
78 })
79 return g.Wait()
80}