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