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 range streamplaceTestCount {
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 require.NoError(t, err)
70
71 // Convert MP4 to MPEG-TS
72 _, err = MP4ToMPEGTS(context.Background(), bytes.NewReader(bs), &buf)
73 require.ErrorContains(t, err, "This file is invalid and cannot be played")
74}
75
76// func TestNoRealtime(t *testing.T) {
77// gst.Init(nil)
78
79// // Open input file
80// inputFile, err := os.Open(getFixture("5sec.mp4"))
81// require.NoError(t, err)
82// defer inputFile.Close()
83
84// // Create a buffer for output
85// tsBuf := bytes.Buffer{}
86
87// // Convert MP4 to MPEG-TS
88// start := time.Now()
89// dur, err := MP4ToMPEGTS(context.Background(), inputFile, &tsBuf)
90// require.NoError(t, err)
91// require.Greater(t, dur, int64(0), "Duration should be greater than 0")
92// elapsed := time.Since(start)
93// require.Less(t, elapsed, 4*time.Second, "MP4 to MPEG-TS conversion should take less than 4 seconds")
94// require.Greater(t, tsBuf.Len(), 0, "MPEG-TS buffer should not be empty")
95
96// // Convert back to MP4
97// mp4Buf := bytes.Buffer{}
98// start = time.Now()
99// err = MPEGTSToMP4(context.Background(), bytes.NewReader(tsBuf.Bytes()), &mp4Buf)
100// require.NoError(t, err)
101// elapsed = time.Since(start)
102// require.Less(t, elapsed, 4*time.Second, "MPEG-TS to MP4 conversion should take less than 4 seconds")
103// require.Greater(t, mp4Buf.Len(), 0, "MP4 buffer should not be empty")
104// }
105
106func TestMPEGTSToMP4(t *testing.T) {
107 ignore := goleak.IgnoreCurrent()
108 defer goleak.VerifyNone(t, ignore)
109 before := getLeakCount(t)
110 defer checkGStreamerLeaks(t, before)
111
112 // Open input file
113 inputFile, err := os.Open(getFixture("sample-segment.mpegts"))
114 require.NoError(t, err)
115 defer inputFile.Close()
116 bs, err := io.ReadAll(inputFile)
117 require.NoError(t, err)
118 // Create temporary output file
119 buf := bytes.Buffer{}
120
121 g, _ := errgroup.WithContext(context.Background())
122 for i := 0; i < streamplaceTestCount; i++ {
123 g.Go(func() error {
124 return MPEGTSToMP4(context.Background(), bytes.NewReader(bs), &buf)
125 })
126 }
127 err = g.Wait()
128 // Convert MPEG-TS to MP4
129
130 require.NoError(t, err)
131 require.Greater(t, buf.Len(), 0, "Output file should not be empty")
132}
133
134func TestMP4ToMPEGTSVideoMP4Audio(t *testing.T) {
135 ignore := goleak.IgnoreCurrent()
136 defer goleak.VerifyNone(t, ignore)
137 before := getLeakCount(t)
138 defer checkGStreamerLeaks(t, before)
139
140 // Open input file
141 inputFile, err := os.Open(getFixture("5sec.mp4"))
142 require.NoError(t, err)
143 defer inputFile.Close()
144
145 // Create buffers for output
146 videoBuf := bytes.Buffer{}
147 audioBuf := bytes.Buffer{}
148
149 // Split MP4 into MPEG-TS video and MP4 audio
150 start := time.Now()
151 err = MP4ToMPEGTSVideoMP4Audio(context.Background(), inputFile, &videoBuf, &audioBuf)
152 require.NoError(t, err)
153 elapsed := time.Since(start)
154 require.Less(t, elapsed, 4*time.Second, "MP4 to MPEG-TS/MP4 conversion should take less than 4 seconds")
155
156 // Verify outputs
157 require.Greater(t, videoBuf.Len(), 0, "Video buffer should not be empty")
158 require.Greater(t, audioBuf.Len(), 0, "Audio buffer should not be empty")
159
160 // Join video and audio back together
161 buf := bytes.Buffer{}
162 start = time.Now()
163 err = MPEGTSVideoMP4AudioToMP4(context.Background(), &videoBuf, &audioBuf, &buf)
164 require.NoError(t, err)
165 require.Greater(t, buf.Len(), 0, "Output buffer should not be empty")
166 elapsed = time.Since(start)
167 require.Less(t, elapsed, 4*time.Second, "MPEG-TS/MP4 to MP4 conversion should take less than 4 seconds")
168}