parse_test.go (4433B)
1 package m3u8 2 3 import ( 4 "fmt" 5 "os" 6 "path" 7 "path/filepath" 8 "reflect" 9 "strings" 10 "testing" 11 "time" 12 ) 13 14 func ExampleEncode() { 15 p := &Playlist{ 16 Version: 7, 17 Segments: []Segment{ 18 {URI: "001.ts", Duration: 4 * time.Second}, 19 }, 20 21 TargetDuration: 4 * time.Second, 22 Sequence: 0, 23 Type: PlaylistEvent, 24 } 25 26 sb := &strings.Builder{} 27 _ = Encode(sb, p) 28 29 fmt.Println(sb) 30 31 // Output: #EXTM3U 32 // #EXT-X-VERSION:7 33 // #EXT-X-PLAYLIST-TYPE:EVENT 34 // #EXT-X-TARGETDURATION:4 35 // #EXT-X-MEDIA-SEQUENCE:0 36 // #EXTINF:4.000 37 // 001.ts 38 } 39 40 func ExampleDecode() { 41 s := ` 42 #EXTM3U 43 #EXT-X-STREAM-INF:BANDWIDTH=1280000,RESOLUTION=640x360,HDCP-LEVEL=NONE 44 url_0/low.m3u8 45 #EXT-X-STREAM-INF:BANDWIDTH=2560000,RESOLUTION=1280x720,HDCP-LEVEL=NONE 46 url_0/mid.m3u8 47 #EXT-X-STREAM-INF:BANDWIDTH=7680000,RESOLUTION=1920x1080,HDCP-LEVEL=NONE 48 url_0/high.m3u8` 49 50 p, err := Decode(strings.NewReader(s)) 51 if err != nil { 52 // handle error 53 } 54 for _, v := range p.Variants { 55 fmt.Printf("%s %dp@%dkbps\n", v.URI, v.Resolution[1], v.Bandwidth/1e3) 56 } 57 // Output: 58 // url_0/low.m3u8 360p@1280kbps 59 // url_0/mid.m3u8 720p@2560kbps 60 // url_0/high.m3u8 1080p@7680kbps 61 } 62 63 func TestDecode(t *testing.T) { 64 names, err := filepath.Glob("testdata/*.m3u8") 65 if err != nil { 66 t.Fatal(err) 67 } 68 for _, name := range names { 69 t.Run(path.Base(name), func(t *testing.T) { 70 f, err := os.Open(name) 71 if err != nil { 72 t.Fatal(err) 73 } 74 defer f.Close() 75 _, err = Decode(f) 76 if err != nil { 77 t.Fatal(err) 78 } 79 }) 80 } 81 } 82 83 func TestVariant(t *testing.T) { 84 f, err := os.Open("testdata/master.m3u8") 85 if err != nil { 86 t.Fatal(err) 87 } 88 defer f.Close() 89 plist, err := Decode(f) 90 if err != nil { 91 t.Fatalf("read playlist: %v", err) 92 } 93 want := []Variant{ 94 { 95 Bandwidth: 1280000, 96 Video: "low", 97 HDCP: HDCPType0, 98 URI: "low/main/audio-video.m3u8", 99 }, 100 { 101 Bandwidth: 2560000, 102 Video: "mid", 103 HDCP: HDCPType1, 104 URI: "mid/main/audio-video.m3u8", 105 }, 106 { 107 Bandwidth: 7680000, 108 Video: "hi", 109 URI: "hi/main/audio-video.m3u8", 110 }, 111 { 112 Bandwidth: 65000, 113 Codecs: []string{"mp4a.40.5"}, 114 HDCP: HDCPNone, 115 URI: "main/audio-only.m3u8", 116 }, 117 } 118 for i, got := range plist.Variants { 119 if !reflect.DeepEqual(got, want[i]) { 120 t.Errorf("variant %d: got %v, want %v", i, got, want) 121 } 122 } 123 } 124 125 func TestParseDuration(t *testing.T) { 126 want := 9967000 * time.Microsecond 127 it := item{typ: itemNumber, val: "9.967"} 128 dur, err := parseSegmentDuration(it.val) 129 if err != nil { 130 t.Fatal(err) 131 } 132 if dur != want { 133 t.Errorf("parseSegmentDuration(%s) = %s, want %s", it, dur, want) 134 } 135 } 136 137 func TestParseByteRange(t *testing.T) { 138 var tests = []struct { 139 in string 140 want ByteRange 141 valid bool 142 }{ 143 {"27@46", ByteRange{27, 46}, true}, 144 {"69", ByteRange{69}, true}, 145 {"732@", ByteRange{0, 0}, false}, 146 {"@", ByteRange{0, 0}, false}, 147 } 148 for _, tt := range tests { 149 t.Run(tt.in, func(t *testing.T) { 150 r, err := parseByteRange(tt.in) 151 if err != nil && tt.valid { 152 t.Fatalf("parseByteRange(%s): %v", tt.in, err) 153 } else if err == nil && !tt.valid { 154 t.Fatalf("parseByteRange(%s): nil error on invalid byte range", tt.in) 155 } 156 if r != tt.want { 157 t.Errorf("parseByteRange(%s) = %v, want %v", tt.in, r, tt.want) 158 } 159 }) 160 } 161 } 162 163 // Tests that we parse floats and integers of different precisions ok. 164 func TestFrameRate(t *testing.T) { 165 f, err := os.Open("testdata/frame_rate.m3u8") 166 if err != nil { 167 t.Fatal(err) 168 } 169 defer f.Close() 170 plist, err := Decode(f) 171 if err != nil { 172 t.Fatal(err) 173 } 174 rates := []float32{24, 25, 29.97, 30, 23.976, 60} 175 for i, v := range plist.Variants { 176 if v.FrameRate != rates[i] { 177 t.Errorf("want %f, got %f", rates[i], v.FrameRate) 178 } 179 } 180 } 181 182 func TestParseSequence(t *testing.T) { 183 f, err := os.Open("testdata/sequence.m3u8") 184 if err != nil { 185 t.Fatal(err) 186 } 187 defer f.Close() 188 plist, err := Decode(f) 189 if err != nil { 190 t.Fatal(err) 191 } 192 if plist.Sequence != 91240 { 193 t.Errorf("want %d, got %d", 91240, plist.Sequence) 194 } 195 } 196 197 func TestResolution(t *testing.T) { 198 var tests = []struct { 199 name string 200 s string 201 }{ 202 {"double x", "1280xx720"}, 203 {"missing x", "1280720"}, 204 {"missing height", "1280x"}, 205 {"negative", "-1x-1"}, 206 {"decimal", "10.69x20"}, 207 } 208 209 for _, tt := range tests { 210 _, err := parseResolution(tt.s) 211 if err == nil { 212 t.Errorf("parse resolution %q (%s): no error", tt.s, tt.name) 213 continue 214 } 215 } 216 }