Live video on the AT Protocol
1package media
2
3import (
4 "bytes"
5 "context"
6 "io"
7 "os"
8 "testing"
9 "time"
10
11 "github.com/stretchr/testify/require"
12 "go.uber.org/goleak"
13 "golang.org/x/sync/errgroup"
14)
15
16func TestMP4ToMPEGTS(t *testing.T) {
17 ignore := goleak.IgnoreCurrent()
18 defer goleak.VerifyNone(t, ignore)
19 before := getLeakCount(t)
20 defer checkGStreamerLeaks(t, before)
21
22 for _, file := range []string{"sample-segment.mp4", "short-video.mp4"} {
23 // Open input file
24 inputFile, err := os.Open(getFixture(file))
25 require.NoError(t, err)
26 defer inputFile.Close()
27
28 // Create a buffer for output
29 buf := bytes.Buffer{}
30
31 bs, err := io.ReadAll(inputFile)
32 require.NoError(t, err)
33 // Create temporary output file
34
35 g, _ := errgroup.WithContext(context.Background())
36 for i := 0; i < streamplaceTestCount; i++ {
37 g.Go(func() error {
38 _, err := MP4ToMPEGTS(context.Background(), bytes.NewReader(bs), &buf)
39 return err
40 })
41 }
42 err = g.Wait()
43 require.NoError(t, err)
44 // Convert MPEG-TS to MP4
45
46 // Convert MP4 to MPEG-TS
47 dur, err := MP4ToMPEGTS(context.Background(), bytes.NewReader(bs), &buf)
48 require.NoError(t, err)
49 require.Greater(t, dur, int64(0), "Duration should be greater than 0")
50
51 // Verify buffer has content
52 require.Greater(t, buf.Len(), 0, "Output buffer should not be empty")
53 }
54}
55
56func TestMP4ToMPEGTSInvalid(t *testing.T) {
57 ignore := goleak.IgnoreCurrent()
58 defer goleak.VerifyNone(t, ignore)
59 before := getLeakCount(t)
60 defer checkGStreamerLeaks(t, before)
61
62 inputFile, err := os.Open(getFixture("sample-segment.mpegts"))
63 require.NoError(t, err)
64 defer inputFile.Close()
65
66 buf := bytes.Buffer{}
67
68 bs, err := io.ReadAll(inputFile)
69
70 // Convert MP4 to MPEG-TS
71 _, err = MP4ToMPEGTS(context.Background(), bytes.NewReader(bs), &buf)
72 require.ErrorContains(t, err, "This file is invalid and cannot be played")
73}
74
75// func TestNoRealtime(t *testing.T) {
76// gst.Init(nil)
77
78// // Open input file
79// inputFile, err := os.Open(getFixture("5sec.mp4"))
80// require.NoError(t, err)
81// defer inputFile.Close()
82
83// // Create a buffer for output
84// tsBuf := bytes.Buffer{}
85
86// // Convert MP4 to MPEG-TS
87// start := time.Now()
88// dur, err := MP4ToMPEGTS(context.Background(), inputFile, &tsBuf)
89// require.NoError(t, err)
90// require.Greater(t, dur, int64(0), "Duration should be greater than 0")
91// elapsed := time.Since(start)
92// require.Less(t, elapsed, 4*time.Second, "MP4 to MPEG-TS conversion should take less than 4 seconds")
93// require.Greater(t, tsBuf.Len(), 0, "MPEG-TS buffer should not be empty")
94
95// // Convert back to MP4
96// mp4Buf := bytes.Buffer{}
97// start = time.Now()
98// err = MPEGTSToMP4(context.Background(), bytes.NewReader(tsBuf.Bytes()), &mp4Buf)
99// require.NoError(t, err)
100// elapsed = time.Since(start)
101// require.Less(t, elapsed, 4*time.Second, "MPEG-TS to MP4 conversion should take less than 4 seconds")
102// require.Greater(t, mp4Buf.Len(), 0, "MP4 buffer should not be empty")
103// }
104
105func TestMPEGTSToMP4(t *testing.T) {
106 ignore := goleak.IgnoreCurrent()
107 defer goleak.VerifyNone(t, ignore)
108 before := getLeakCount(t)
109 defer checkGStreamerLeaks(t, before)
110
111 // Open input file
112 inputFile, err := os.Open(getFixture("sample-segment.mpegts"))
113 require.NoError(t, err)
114 defer inputFile.Close()
115 bs, err := io.ReadAll(inputFile)
116 require.NoError(t, err)
117 // Create temporary output file
118 buf := bytes.Buffer{}
119
120 g, _ := errgroup.WithContext(context.Background())
121 for i := 0; i < streamplaceTestCount; i++ {
122 g.Go(func() error {
123 return MPEGTSToMP4(context.Background(), bytes.NewReader(bs), &buf)
124 })
125 }
126 err = g.Wait()
127 // Convert MPEG-TS to MP4
128
129 require.NoError(t, err)
130 require.Greater(t, buf.Len(), 0, "Output file should not be empty")
131}
132
133func TestMP4ToMPEGTSVideoMP4Audio(t *testing.T) {
134 ignore := goleak.IgnoreCurrent()
135 defer goleak.VerifyNone(t, ignore)
136 before := getLeakCount(t)
137 defer checkGStreamerLeaks(t, before)
138
139 // Open input file
140 inputFile, err := os.Open(getFixture("5sec.mp4"))
141 require.NoError(t, err)
142 defer inputFile.Close()
143
144 // Create buffers for output
145 videoBuf := bytes.Buffer{}
146 audioBuf := bytes.Buffer{}
147
148 // Split MP4 into MPEG-TS video and MP4 audio
149 start := time.Now()
150 err = MP4ToMPEGTSVideoMP4Audio(context.Background(), inputFile, &videoBuf, &audioBuf)
151 require.NoError(t, err)
152 elapsed := time.Since(start)
153 require.Less(t, elapsed, 4*time.Second, "MP4 to MPEG-TS/MP4 conversion should take less than 4 seconds")
154
155 // Verify outputs
156 require.Greater(t, videoBuf.Len(), 0, "Video buffer should not be empty")
157 require.Greater(t, audioBuf.Len(), 0, "Audio buffer should not be empty")
158
159 // Join video and audio back together
160 buf := bytes.Buffer{}
161 start = time.Now()
162 err = MPEGTSVideoMP4AudioToMP4(context.Background(), &videoBuf, &audioBuf, &buf)
163 require.NoError(t, err)
164 require.Greater(t, buf.Len(), 0, "Output buffer should not be empty")
165 elapsed = time.Since(start)
166 require.Less(t, elapsed, 4*time.Second, "MPEG-TS/MP4 to MP4 conversion should take less than 4 seconds")
167}