github.com/bluenviron/mediacommon@v1.9.3/pkg/formats/mpegts/reader_test.go (about) 1 //nolint:dupl 2 package mpegts 3 4 import ( 5 "bytes" 6 "context" 7 "errors" 8 "testing" 9 10 "github.com/asticode/go-astits" 11 "github.com/stretchr/testify/require" 12 13 "github.com/bluenviron/mediacommon/pkg/codecs/h265" 14 "github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio" 15 ) 16 17 var testH265SPS = []byte{ 18 0x42, 0x01, 0x01, 0x02, 0x20, 0x00, 0x00, 0x03, 19 0x00, 0xb0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 20 0x00, 0x7b, 0xa0, 0x07, 0x82, 0x00, 0x88, 0x7d, 21 0xb6, 0x71, 0x8b, 0x92, 0x44, 0x80, 0x53, 0x88, 22 0x88, 0x92, 0xcf, 0x24, 0xa6, 0x92, 0x72, 0xc9, 23 0x12, 0x49, 0x22, 0xdc, 0x91, 0xaa, 0x48, 0xfc, 24 0xa2, 0x23, 0xff, 0x00, 0x01, 0x00, 0x01, 0x6a, 25 0x02, 0x02, 0x02, 0x01, 26 } 27 28 var testH265PPS = []byte{ 29 0x44, 0x01, 0xc0, 0x25, 0x2f, 0x05, 0x32, 0x40, 30 } 31 32 var testH264SPS = []byte{ 33 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02, 34 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, 35 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, 0xc9, 36 0x20, 37 } 38 39 type sample struct { 40 pts int64 41 dts int64 42 data [][]byte 43 } 44 45 var casesReadWriter = []struct { 46 name string 47 track *Track 48 samples []sample 49 packets []*astits.Packet 50 }{ 51 { 52 "h265", 53 &Track{ 54 PID: 257, 55 Codec: &CodecH265{}, 56 }, 57 []sample{ 58 { 59 30 * 90000, 60 30 * 90000, 61 [][]byte{ 62 testH265SPS, // SPS 63 testH265PPS, // PPS 64 {byte(h265.NALUType_CRA_NUT) << 1}, 65 }, 66 }, 67 { 68 30*90000 + 2*90000, 69 30*90000 + 1*90000, 70 [][]byte{ 71 {byte(h265.NALUType_TRAIL_N) << 1}, 72 }, 73 }, 74 }, 75 []*astits.Packet{ 76 { // PMT 77 Header: astits.PacketHeader{ 78 HasPayload: true, 79 PayloadUnitStartIndicator: true, 80 PID: 0, 81 }, 82 Payload: append([]byte{ 83 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, 84 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, 85 0x78, 86 }, bytes.Repeat([]byte{0xff}, 167)...), 87 }, 88 { // PAT 89 Header: astits.PacketHeader{ 90 HasPayload: true, 91 PayloadUnitStartIndicator: true, 92 PID: 4096, 93 }, 94 Payload: append([]byte{ 95 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 96 0x00, 0xe1, 0x01, 0xf0, 0x00, 0x24, 0xe1, 0x01, 97 0xf0, 0x00, 0x75, 0x79, 0x1e, 0xaa, 98 }, bytes.Repeat([]byte{0xff}, 162)...), 99 }, 100 { // PES 101 AdaptationField: &astits.PacketAdaptationField{ 102 Length: 88, 103 StuffingLength: 81, 104 RandomAccessIndicator: true, 105 HasPCR: true, 106 PCR: &astits.ClockReference{Base: 2691000}, 107 }, 108 Header: astits.PacketHeader{ 109 HasAdaptationField: true, 110 HasPayload: true, 111 PayloadUnitStartIndicator: true, 112 PID: 257, 113 }, 114 Payload: []byte{ 115 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x80, 116 0x05, 0x21, 0x00, 0xa5, 0x65, 0xc1, 0x00, 0x00, 117 0x00, 0x01, 0x42, 0x01, 0x01, 0x02, 0x20, 0x00, 118 0x00, 0x03, 0x00, 0xb0, 0x00, 0x00, 0x03, 0x00, 119 0x00, 0x03, 0x00, 0x7b, 0xa0, 0x07, 0x82, 0x00, 120 0x88, 0x7d, 0xb6, 0x71, 0x8b, 0x92, 0x44, 0x80, 121 0x53, 0x88, 0x88, 0x92, 0xcf, 0x24, 0xa6, 0x92, 122 0x72, 0xc9, 0x12, 0x49, 0x22, 0xdc, 0x91, 0xaa, 123 0x48, 0xfc, 0xa2, 0x23, 0xff, 0x00, 0x01, 0x00, 124 0x01, 0x6a, 0x02, 0x02, 0x02, 0x01, 0x00, 0x00, 125 0x00, 0x01, 0x44, 0x01, 0xc0, 0x25, 0x2f, 0x05, 126 0x32, 0x40, 0x00, 0x00, 0x00, 0x01, 0x2a, 127 }, 128 }, 129 { // PES 130 AdaptationField: &astits.PacketAdaptationField{ 131 Length: 159, 132 StuffingLength: 158, 133 }, 134 Header: astits.PacketHeader{ 135 ContinuityCounter: 1, 136 HasAdaptationField: true, 137 HasPayload: true, 138 PayloadUnitStartIndicator: true, 139 PID: 257, 140 }, 141 Payload: []byte{ 142 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0xc0, 143 0x0a, 0x31, 0x00, 0xaf, 0xe4, 0x01, 0x11, 0x00, 144 0xab, 0x24, 0xe1, 0x00, 0x00, 0x00, 0x01, 0x00, 145 }, 146 }, 147 }, 148 }, 149 { 150 "h264", 151 &Track{ 152 PID: 256, 153 Codec: &CodecH264{}, 154 }, 155 []sample{ 156 { 157 30 * 90000, 158 30 * 90000, 159 [][]byte{ 160 testH264SPS, // SPS 161 {8}, // PPS 162 {5}, // IDR 163 }, 164 }, 165 { 166 30*90000 + 2*90000, 167 30*90000 + 1*90000, 168 [][]byte{ 169 {1}, // non-IDR 170 }, 171 }, 172 }, 173 []*astits.Packet{ 174 { // PMT 175 Header: astits.PacketHeader{ 176 HasPayload: true, 177 PayloadUnitStartIndicator: true, 178 PID: 0, 179 }, 180 Payload: append([]byte{ 181 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, 182 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, 183 0x78, 184 }, bytes.Repeat([]byte{0xff}, 167)...), 185 }, 186 { // PAT 187 Header: astits.PacketHeader{ 188 HasPayload: true, 189 PayloadUnitStartIndicator: true, 190 PID: 4096, 191 }, 192 Payload: append([]byte{ 193 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 194 0x00, 0xe1, 0x00, 0xf0, 0x00, 0x1b, 0xe1, 0x00, 195 0xf0, 0x00, 0x15, 0xbd, 0x4d, 0x56, 196 }, bytes.Repeat([]byte{0xff}, 162)...), 197 }, 198 { // PES 199 AdaptationField: &astits.PacketAdaptationField{ 200 Length: 130, 201 StuffingLength: 123, 202 RandomAccessIndicator: true, 203 HasPCR: true, 204 PCR: &astits.ClockReference{Base: 2691000}, 205 }, 206 Header: astits.PacketHeader{ 207 HasAdaptationField: true, 208 HasPayload: true, 209 PayloadUnitStartIndicator: true, 210 PID: 256, 211 }, 212 Payload: []byte{ 213 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x80, 214 0x05, 0x21, 0x00, 0xa5, 0x65, 0xc1, 0x00, 0x00, 215 0x00, 0x01, 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 216 0x78, 0x02, 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 217 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 218 0x60, 0xc9, 0x20, 0x00, 0x00, 0x00, 0x01, 0x08, 219 0x00, 0x00, 0x00, 0x01, 0x05, 220 }, 221 }, 222 { // PES 223 AdaptationField: &astits.PacketAdaptationField{ 224 Length: 159, 225 StuffingLength: 158, 226 }, 227 Header: astits.PacketHeader{ 228 ContinuityCounter: 1, 229 HasAdaptationField: true, 230 HasPayload: true, 231 PayloadUnitStartIndicator: true, 232 PID: 256, 233 }, 234 Payload: []byte{ 235 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0xc0, 236 0x0a, 0x31, 0x00, 0xaf, 0xe4, 0x01, 0x11, 0x00, 237 0xab, 0x24, 0xe1, 0x00, 0x00, 0x00, 0x01, 0x01, 238 }, 239 }, 240 }, 241 }, 242 { 243 "mpeg-4 video", 244 &Track{ 245 PID: 257, 246 Codec: &CodecMPEG4Video{}, 247 }, 248 []sample{ 249 { 250 30 * 90000, 251 30 * 90000, 252 [][]byte{{0, 0, 1, 0xb3}}, 253 }, 254 }, 255 []*astits.Packet{ 256 { // PMT 257 Header: astits.PacketHeader{ 258 HasPayload: true, 259 PayloadUnitStartIndicator: true, 260 PID: 0, 261 }, 262 Payload: append([]byte{ 263 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, 264 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, 265 0x78, 266 }, bytes.Repeat([]byte{0xff}, 167)...), 267 }, 268 { // PAT 269 Header: astits.PacketHeader{ 270 HasPayload: true, 271 PayloadUnitStartIndicator: true, 272 PID: 4096, 273 }, 274 Payload: append([]byte{ 275 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 276 0x00, 0xe1, 0x01, 0xf0, 0x00, 0x10, 0xe1, 0x01, 277 0xf0, 0x00, 0xd5, 0x3a, 0x92, 0x8a, 278 }, bytes.Repeat([]byte{0xff}, 162)...), 279 }, 280 { // PES 281 AdaptationField: &astits.PacketAdaptationField{ 282 Length: 165, 283 StuffingLength: 158, 284 RandomAccessIndicator: true, 285 HasPCR: true, 286 PCR: &astits.ClockReference{Base: 2691000}, 287 }, 288 Header: astits.PacketHeader{ 289 HasAdaptationField: true, 290 HasPayload: true, 291 PayloadUnitStartIndicator: true, 292 PID: 257, 293 }, 294 Payload: []byte{ 295 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x80, 296 0x05, 0x21, 0x00, 0xa5, 0x65, 0xc1, 0x00, 0x00, 297 0x01, 0xb3, 298 }, 299 }, 300 }, 301 }, 302 { 303 "mpeg-1 video", 304 &Track{ 305 PID: 257, 306 Codec: &CodecMPEG1Video{}, 307 }, 308 []sample{ 309 { 310 30 * 90000, 311 30 * 90000, 312 [][]byte{{0, 0, 1, 0xb8, 1, 2, 3, 4}}, 313 }, 314 }, 315 []*astits.Packet{ 316 { // PMT 317 Header: astits.PacketHeader{ 318 HasPayload: true, 319 PayloadUnitStartIndicator: true, 320 PID: 0, 321 }, 322 Payload: append([]byte{ 323 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, 324 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, 325 0x78, 326 }, bytes.Repeat([]byte{0xff}, 167)...), 327 }, 328 { // PAT 329 Header: astits.PacketHeader{ 330 HasPayload: true, 331 PayloadUnitStartIndicator: true, 332 PID: 4096, 333 }, 334 Payload: append([]byte{ 335 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 336 0x00, 0xe1, 0x01, 0xf0, 0x00, 0x02, 0xe1, 0x01, 337 0xf0, 0x00, 0xc4, 0xf2, 0x53, 0x9c, 338 }, bytes.Repeat([]byte{0xff}, 162)...), 339 }, 340 { // PES 341 AdaptationField: &astits.PacketAdaptationField{ 342 Length: 161, 343 StuffingLength: 154, 344 RandomAccessIndicator: true, 345 HasPCR: true, 346 PCR: &astits.ClockReference{Base: 2691000}, 347 }, 348 Header: astits.PacketHeader{ 349 HasAdaptationField: true, 350 HasPayload: true, 351 PayloadUnitStartIndicator: true, 352 PID: 257, 353 }, 354 Payload: []byte{ 355 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x80, 356 0x05, 0x21, 0x00, 0xa5, 0x65, 0xc1, 0x00, 0x00, 357 0x01, 0xb8, 0x01, 0x02, 0x03, 0x04, 358 }, 359 }, 360 }, 361 }, 362 { 363 "opus", 364 &Track{ 365 PID: 257, 366 Codec: &CodecOpus{ 367 ChannelCount: 2, 368 }, 369 }, 370 []sample{ 371 { 372 30 * 90000, 373 30 * 90000, 374 [][]byte{{3}, {2}}, 375 }, 376 { 377 30*90000 + 2*90000, 378 30 * 90000, 379 [][]byte{{1}}, 380 }, 381 }, 382 []*astits.Packet{ 383 { // PMT 384 Header: astits.PacketHeader{ 385 HasPayload: true, 386 PayloadUnitStartIndicator: true, 387 PID: 0, 388 }, 389 Payload: append([]byte{ 390 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, 391 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, 392 0x78, 393 }, bytes.Repeat([]byte{0xff}, 167)...), 394 }, 395 { // PAT 396 Header: astits.PacketHeader{ 397 HasPayload: true, 398 PayloadUnitStartIndicator: true, 399 PID: 4096, 400 }, 401 Payload: append([]byte{ 402 0x00, 0x02, 0xb0, 0x1c, 0x00, 0x01, 0xc1, 0x00, 403 0x00, 0xe1, 0x01, 0xf0, 0x00, 0x06, 0xe1, 0x01, 404 0xf0, 0x0a, 0x05, 0x04, 0x4f, 0x70, 0x75, 0x73, 405 0x7f, 0x02, 0x80, 0x02, 0xcc, 0x21, 0x3d, 0x58, 406 }, bytes.Repeat([]byte{0xff}, 152)...), 407 }, 408 { // PES 409 AdaptationField: &astits.PacketAdaptationField{ 410 Length: 161, 411 StuffingLength: 154, 412 HasPCR: true, 413 PCR: &astits.ClockReference{Base: 2691000}, 414 RandomAccessIndicator: true, 415 }, 416 Header: astits.PacketHeader{ 417 HasAdaptationField: true, 418 HasPayload: true, 419 PayloadUnitStartIndicator: true, 420 PID: 257, 421 }, 422 Payload: []byte{ 423 0x00, 0x00, 0x01, 0xc0, 0x00, 0x10, 0x80, 0x80, 424 0x05, 0x21, 0x00, 0xa5, 0x65, 0xc1, 0x7f, 0xe0, 425 0x01, 0x03, 0x7f, 0xe0, 0x01, 0x02, 426 }, 427 }, 428 { // PMT 429 Header: astits.PacketHeader{ 430 ContinuityCounter: 1, 431 HasPayload: true, 432 PayloadUnitStartIndicator: true, 433 PID: 0, 434 }, 435 Payload: append([]byte{ 436 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, 437 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, 438 0x78, 439 }, bytes.Repeat([]byte{0xff}, 167)...), 440 }, 441 { // PAT 442 Header: astits.PacketHeader{ 443 ContinuityCounter: 1, 444 HasPayload: true, 445 PayloadUnitStartIndicator: true, 446 PID: 4096, 447 }, 448 Payload: append([]byte{ 449 0x00, 0x02, 0xb0, 0x1c, 0x00, 0x01, 0xc1, 0x00, 450 0x00, 0xe1, 0x01, 0xf0, 0x00, 0x06, 0xe1, 0x01, 451 0xf0, 0x0a, 0x05, 0x04, 0x4f, 0x70, 0x75, 0x73, 452 0x7f, 0x02, 0x80, 0x02, 0xcc, 0x21, 0x3d, 0x58, 453 }, bytes.Repeat([]byte{0xff}, 152)...), 454 }, 455 { // PES 456 AdaptationField: &astits.PacketAdaptationField{ 457 Length: 165, 458 StuffingLength: 164, 459 RandomAccessIndicator: true, 460 }, 461 Header: astits.PacketHeader{ 462 ContinuityCounter: 1, 463 HasAdaptationField: true, 464 HasPayload: true, 465 PayloadUnitStartIndicator: true, 466 PID: 257, 467 }, 468 Payload: []byte{ 469 0x00, 0x00, 0x01, 0xc0, 0x00, 0x0c, 0x80, 0x80, 470 0x05, 0x21, 0x00, 0xaf, 0xe4, 0x01, 0x7f, 0xe0, 471 0x01, 0x01, 472 }, 473 }, 474 }, 475 }, 476 { 477 "mpeg-4 audio", 478 &Track{ 479 PID: 257, 480 Codec: &CodecMPEG4Audio{ 481 Config: mpeg4audio.AudioSpecificConfig{ 482 Type: 2, 483 SampleRate: 48000, 484 ChannelCount: 2, 485 }, 486 }, 487 }, 488 []sample{ 489 { 490 30 * 90000, 491 30 * 90000, 492 [][]byte{{3}, {2}}, 493 }, 494 }, 495 []*astits.Packet{ 496 { // PMT 497 Header: astits.PacketHeader{ 498 HasPayload: true, 499 PayloadUnitStartIndicator: true, 500 PID: 0, 501 }, 502 Payload: append([]byte{ 503 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, 504 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, 505 0x78, 506 }, bytes.Repeat([]byte{0xff}, 167)...), 507 }, 508 { // PAT 509 Header: astits.PacketHeader{ 510 HasPayload: true, 511 PayloadUnitStartIndicator: true, 512 PID: 4096, 513 }, 514 Payload: append([]byte{ 515 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 516 0x00, 0xe1, 0x01, 0xf0, 0x00, 0x0f, 0xe1, 0x01, 517 0xf0, 0x00, 0xec, 0xe2, 0xb0, 0x94, 518 }, bytes.Repeat([]byte{0xff}, 162)...), 519 }, 520 { // PES 521 AdaptationField: &astits.PacketAdaptationField{ 522 Length: 153, 523 StuffingLength: 146, 524 HasPCR: true, 525 PCR: &astits.ClockReference{Base: 2691000}, 526 RandomAccessIndicator: true, 527 }, 528 Header: astits.PacketHeader{ 529 HasAdaptationField: true, 530 HasPayload: true, 531 PayloadUnitStartIndicator: true, 532 PID: 257, 533 }, 534 Payload: []byte{ 535 0x00, 0x00, 0x01, 0xc0, 0x00, 0x18, 0x80, 0x80, 536 0x05, 0x21, 0x00, 0xa5, 0x65, 0xc1, 0xff, 0xf1, 537 0x4c, 0x80, 0x01, 0x1f, 0xfc, 0x03, 0xff, 0xf1, 538 0x4c, 0x80, 0x01, 0x1f, 0xfc, 0x02, 539 }, 540 }, 541 }, 542 }, 543 { 544 "mpeg-1 audio", 545 &Track{ 546 PID: 257, 547 Codec: &CodecMPEG1Audio{}, 548 }, 549 []sample{ 550 { 551 30 * 90000, 552 30 * 90000, 553 [][]byte{{ 554 0xff, 0xfa, 0x52, 0x04, 0xa9, 0xbe, 0xe4, 0x8f, 555 0xf0, 0xfd, 0x02, 0xdc, 0x80, 0x00, 0x30, 0x00, 556 0x22, 0xc1, 0x5b, 0x90, 0x14, 0x23, 0x24, 0x05, 557 0x58, 0x3f, 0x72, 0x02, 0x84, 0xc4, 0xc0, 0xc5, 558 0x07, 0xae, 0x40, 0x21, 0xbc, 0x98, 0x90, 0xfa, 559 0x3a, 0x2d, 0xda, 0x07, 0xe1, 0x4d, 0xa9, 0x9a, 560 0xb8, 0xa2, 0x3b, 0x20, 0xc1, 0xc1, 0xba, 0x08, 561 0x94, 0x30, 0x8b, 0xc5, 0x69, 0x51, 0x95, 0xd5, 562 0xd7, 0x42, 0x91, 0x65, 0x09, 0xfb, 0x7e, 0x7e, 563 0xd9, 0xcf, 0x7f, 0x77, 0x45, 0x03, 0x8d, 0x5c, 564 0xcd, 0x52, 0x82, 0x19, 0xbc, 0x94, 0x8c, 0x78, 565 0x13, 0xe0, 0x94, 0xc2, 0x96, 0x62, 0x82, 0x20, 566 0xb9, 0xf1, 0x3a, 0x05, 0xfa, 0x94, 0x06, 0xbd, 567 0xf6, 0x67, 0xa3, 0xca, 0xa5, 0x3a, 0xd5, 0xb5, 568 0x34, 0xa9, 0xe8, 0x7e, 0x9f, 0x2f, 0x53, 0xde, 569 0x8b, 0xd6, 0x3c, 0x2f, 0x2d, 0xb4, 0x56, 0x0c, 570 0xc5, 0x3e, 0x7a, 0xa7, 0x81, 0x5c, 0x35, 0x60, 571 0xb3, 0x0c, 0x28, 0x2c, 0x08, 0x06, 0xc0, 0xe0, 572 0x3c, 0x0a, 0xfa, 0x1a, 0x6f, 0x43, 0x55, 0xbe, 573 0x05, 0x5a, 0x53, 0xae, 0xcb, 0x74, 0xa9, 0xe8, 574 0x7e, 0x9f, 0x2f, 0x53, 0xde, 0x8b, 0xd6, 0x20, 575 0x36, 0xce, 0xcb, 0xcd, 0x95, 0x15, 0x08, 0xaa, 576 0x82, 0x13, 0x51, 0x48, 0xc1, 0x09, 0x28, 0x46, 577 0x11, 0x0b, 0x3b, 0x41, 0x34, 0x50, 0x24, 0x18, 578 0xa7, 0x72, 0x88, 0x99, 0x49, 0x17, 0x63, 0xac, 579 0xa7, 0x98, 0x7e, 0x81, 0x7b, 0x13, 0x9d, 0x7f, 580 0xd3, 581 }}, 582 }, 583 }, 584 []*astits.Packet{ 585 { // PMT 586 Header: astits.PacketHeader{ 587 HasPayload: true, 588 PayloadUnitStartIndicator: true, 589 PID: 0, 590 }, 591 Payload: append([]byte{ 592 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, 593 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, 594 0x78, 595 }, bytes.Repeat([]byte{0xff}, 167)...), 596 }, 597 { // PAT 598 Header: astits.PacketHeader{ 599 HasPayload: true, 600 PayloadUnitStartIndicator: true, 601 PID: 4096, 602 }, 603 Payload: append([]byte{ 604 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 605 0x00, 0xe1, 0x01, 0xf0, 0x00, 0x03, 0xe1, 0x01, 606 0xf0, 0x00, 0x8d, 0xff, 0x34, 0x11, 607 }, bytes.Repeat([]byte{0xff}, 162)...), 608 }, 609 { // PES 610 AdaptationField: &astits.PacketAdaptationField{ 611 Length: 7, 612 HasPCR: true, 613 PCR: &astits.ClockReference{Base: 2691000}, 614 RandomAccessIndicator: true, 615 }, 616 Header: astits.PacketHeader{ 617 HasAdaptationField: true, 618 HasPayload: true, 619 PayloadUnitStartIndicator: true, 620 PID: 257, 621 }, 622 Payload: []byte{ 623 0x00, 0x00, 0x01, 0xc0, 0x00, 0xd9, 0x80, 0x80, 624 0x05, 0x21, 0x00, 0xa5, 0x65, 0xc1, 0xff, 0xfa, 625 0x52, 0x04, 0xa9, 0xbe, 0xe4, 0x8f, 0xf0, 0xfd, 626 0x02, 0xdc, 0x80, 0x00, 0x30, 0x00, 0x22, 0xc1, 627 0x5b, 0x90, 0x14, 0x23, 0x24, 0x05, 0x58, 0x3f, 628 0x72, 0x02, 0x84, 0xc4, 0xc0, 0xc5, 0x07, 0xae, 629 0x40, 0x21, 0xbc, 0x98, 0x90, 0xfa, 0x3a, 0x2d, 630 0xda, 0x07, 0xe1, 0x4d, 0xa9, 0x9a, 0xb8, 0xa2, 631 0x3b, 0x20, 0xc1, 0xc1, 0xba, 0x08, 0x94, 0x30, 632 0x8b, 0xc5, 0x69, 0x51, 0x95, 0xd5, 0xd7, 0x42, 633 0x91, 0x65, 0x09, 0xfb, 0x7e, 0x7e, 0xd9, 0xcf, 634 0x7f, 0x77, 0x45, 0x03, 0x8d, 0x5c, 0xcd, 0x52, 635 0x82, 0x19, 0xbc, 0x94, 0x8c, 0x78, 0x13, 0xe0, 636 0x94, 0xc2, 0x96, 0x62, 0x82, 0x20, 0xb9, 0xf1, 637 0x3a, 0x05, 0xfa, 0x94, 0x06, 0xbd, 0xf6, 0x67, 638 0xa3, 0xca, 0xa5, 0x3a, 0xd5, 0xb5, 0x34, 0xa9, 639 0xe8, 0x7e, 0x9f, 0x2f, 0x53, 0xde, 0x8b, 0xd6, 640 0x3c, 0x2f, 0x2d, 0xb4, 0x56, 0x0c, 0xc5, 0x3e, 641 0x7a, 0xa7, 0x81, 0x5c, 0x35, 0x60, 0xb3, 0x0c, 642 0x28, 0x2c, 0x08, 0x06, 0xc0, 0xe0, 0x3c, 0x0a, 643 0xfa, 0x1a, 0x6f, 0x43, 0x55, 0xbe, 0x05, 0x5a, 644 0x53, 0xae, 0xcb, 0x74, 0xa9, 0xe8, 0x7e, 0x9f, 645 }, 646 }, 647 { // PES 648 AdaptationField: &astits.PacketAdaptationField{ 649 Length: 136, 650 StuffingLength: 135, 651 }, 652 Header: astits.PacketHeader{ 653 ContinuityCounter: 1, 654 HasAdaptationField: true, 655 HasPayload: true, 656 PayloadUnitStartIndicator: false, 657 PID: 257, 658 }, 659 Payload: []byte{ 660 0x2f, 0x53, 0xde, 0x8b, 0xd6, 0x20, 0x36, 0xce, 661 0xcb, 0xcd, 0x95, 0x15, 0x08, 0xaa, 0x82, 0x13, 662 0x51, 0x48, 0xc1, 0x09, 0x28, 0x46, 0x11, 0x0b, 663 0x3b, 0x41, 0x34, 0x50, 0x24, 0x18, 0xa7, 0x72, 664 0x88, 0x99, 0x49, 0x17, 0x63, 0xac, 0xa7, 0x98, 665 0x7e, 0x81, 0x7b, 0x13, 0x9d, 0x7f, 0xd3, 666 }, 667 }, 668 }, 669 }, 670 { 671 "ac-3", 672 &Track{ 673 PID: 257, 674 Codec: &CodecAC3{ 675 SampleRate: 48000, 676 ChannelCount: 1, 677 }, 678 }, 679 []sample{ 680 { 681 30 * 90000, 682 30 * 90000, 683 [][]byte{{ 684 0x0b, 0x77, 0x47, 0x11, 0x0c, 0x40, 0x2f, 0x84, 685 0x2b, 0xc1, 0x07, 0x7a, 0xb0, 0xfa, 0xbb, 0xea, 686 0xef, 0x9f, 0x57, 0x7c, 0xf9, 0xf3, 0xf7, 0xcf, 687 0x9f, 0x3e, 0x32, 0xfe, 0xd5, 0xc1, 0x50, 0xde, 688 0xc5, 0x1e, 0x73, 0xd2, 0x6c, 0xa6, 0x94, 0x46, 689 0x4e, 0x92, 0x8c, 0x0f, 0xb9, 0xcf, 0xad, 0x07, 690 0x54, 0x4a, 0x2e, 0xf3, 0x7d, 0x07, 0x2e, 0xa4, 691 0x2f, 0xba, 0xbf, 0x39, 0xb5, 0xc9, 0x92, 0xa6, 692 0xe1, 0xb4, 0x70, 0xc5, 0xc4, 0xb5, 0xe6, 0x5d, 693 0x0f, 0xa8, 0x71, 0xa4, 0xcc, 0xc5, 0xbc, 0x75, 694 0x67, 0x92, 0x52, 0x4f, 0x7e, 0x62, 0x1c, 0xa9, 695 0xd9, 0xb5, 0x19, 0x6a, 0xd7, 0xb0, 0x44, 0x92, 696 0x30, 0x3b, 0xf7, 0x61, 0xd6, 0x49, 0x96, 0x66, 697 0x98, 0x28, 0x1a, 0x95, 0xa9, 0x42, 0xad, 0xb7, 698 0x50, 0x90, 0xad, 0x1c, 0x34, 0x80, 0xe2, 0xef, 699 0xcd, 0x41, 0x0b, 0xf0, 0x9d, 0x57, 0x62, 0x78, 700 0xfd, 0xc6, 0xc2, 0x19, 0x9e, 0x26, 0x31, 0xca, 701 0x1e, 0x75, 0xb1, 0x7a, 0x8e, 0xb5, 0x51, 0x3a, 702 0xfe, 0xe4, 0xf1, 0x0b, 0x4f, 0x14, 0x90, 0xdb, 703 0x9f, 0x44, 0x50, 0xbb, 0xef, 0x74, 0x00, 0x8c, 704 0x1f, 0x97, 0xa1, 0xa2, 0xfa, 0x72, 0x16, 0x47, 705 0xc6, 0xc0, 0xe5, 0xfe, 0x67, 0x03, 0x9c, 0xfe, 706 0x62, 0x01, 0xa1, 0x00, 0x5d, 0xff, 0xa5, 0x03, 707 0x59, 0xfa, 0xa8, 0x25, 0x5f, 0x6b, 0x83, 0x51, 708 0xf2, 0xc0, 0x44, 0xff, 0x2d, 0x05, 0x4b, 0xee, 709 0xe0, 0x54, 0x9e, 0xae, 0x86, 0x45, 0xf3, 0xbd, 710 0x0e, 0x42, 0xf2, 0xbf, 0x0f, 0x7f, 0xc6, 0x09, 711 0x07, 0xdc, 0x22, 0x11, 0x77, 0xbe, 0x31, 0x27, 712 0x5b, 0xa4, 0x13, 0x47, 0x07, 0x32, 0x9f, 0x1f, 713 0xcb, 0xb0, 0xdf, 0x3e, 0x7d, 0x0d, 0xf3, 0xe7, 714 0xcf, 0x9f, 0x3e, 0xae, 0xf9, 0xf3, 0xe7, 0xcf, 715 0x9f, 0x3e, 0x85, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, 716 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f, 717 0x53, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 718 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 719 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 720 0xe7, 0xcf, 0x9f, 0x3e, 0x00, 0x46, 0x28, 0x26, 721 0x20, 0x4a, 0x5a, 0xc0, 0x8a, 0xc5, 0xae, 0xa0, 722 0x55, 0x78, 0x82, 0x7a, 0x38, 0x10, 0x09, 0xc9, 723 0xb8, 0x0c, 0xfa, 0x5b, 0xc9, 0xd2, 0xec, 0x44, 724 0x25, 0xf8, 0x20, 0xf2, 0xc8, 0x8a, 0xe9, 0x40, 725 0x18, 0x06, 0xc6, 0x2b, 0xc8, 0xed, 0x8f, 0x33, 726 0x09, 0x92, 0x28, 0x1e, 0xc4, 0x24, 0xd8, 0x33, 727 0xa5, 0x00, 0xf5, 0xea, 0x18, 0xfa, 0x90, 0x97, 728 0x97, 0xe8, 0x39, 0x6a, 0xcf, 0xf1, 0xdd, 0xff, 729 0x9e, 0x8e, 0x04, 0x02, 0xae, 0x65, 0x87, 0x5c, 730 0x4e, 0x72, 0xfd, 0x3c, 0x01, 0x86, 0xfe, 0x56, 731 0x59, 0x74, 0x44, 0x3a, 0x40, 0x00, 0xec, 0xfc, 732 }}, 733 }, 734 }, 735 []*astits.Packet{ 736 { // PMT 737 Header: astits.PacketHeader{ 738 HasPayload: true, 739 PayloadUnitStartIndicator: true, 740 PID: 0, 741 }, 742 Payload: append([]byte{ 743 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, 744 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, 745 0x78, 746 }, bytes.Repeat([]byte{0xff}, 167)...), 747 }, 748 { // PAT 749 Header: astits.PacketHeader{ 750 HasPayload: true, 751 PayloadUnitStartIndicator: true, 752 PID: 4096, 753 }, 754 Payload: append([]byte{ 755 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 756 0x00, 0xe1, 0x01, 0xf0, 0x00, 0x81, 0xe1, 0x01, 757 0xf0, 0x00, 0x12, 0x71, 0xfd, 0xb7, 758 }, bytes.Repeat([]byte{0xff}, 162)...), 759 }, 760 { // PES 761 AdaptationField: &astits.PacketAdaptationField{ 762 Length: 7, 763 HasPCR: true, 764 PCR: &astits.ClockReference{Base: 2691000}, 765 RandomAccessIndicator: true, 766 }, 767 Header: astits.PacketHeader{ 768 HasAdaptationField: true, 769 HasPayload: true, 770 PayloadUnitStartIndicator: true, 771 PID: 257, 772 }, 773 Payload: []byte{ 774 0x00, 0x00, 0x01, 0xc0, 0x01, 0x88, 0x80, 0x80, 775 0x05, 0x21, 0x00, 0xa5, 0x65, 0xc1, 0x0b, 0x77, 776 0x47, 0x11, 0x0c, 0x40, 0x2f, 0x84, 0x2b, 0xc1, 777 0x07, 0x7a, 0xb0, 0xfa, 0xbb, 0xea, 0xef, 0x9f, 778 0x57, 0x7c, 0xf9, 0xf3, 0xf7, 0xcf, 0x9f, 0x3e, 779 0x32, 0xfe, 0xd5, 0xc1, 0x50, 0xde, 0xc5, 0x1e, 780 0x73, 0xd2, 0x6c, 0xa6, 0x94, 0x46, 0x4e, 0x92, 781 0x8c, 0x0f, 0xb9, 0xcf, 0xad, 0x07, 0x54, 0x4a, 782 0x2e, 0xf3, 0x7d, 0x07, 0x2e, 0xa4, 0x2f, 0xba, 783 0xbf, 0x39, 0xb5, 0xc9, 0x92, 0xa6, 0xe1, 0xb4, 784 0x70, 0xc5, 0xc4, 0xb5, 0xe6, 0x5d, 0x0f, 0xa8, 785 0x71, 0xa4, 0xcc, 0xc5, 0xbc, 0x75, 0x67, 0x92, 786 0x52, 0x4f, 0x7e, 0x62, 0x1c, 0xa9, 0xd9, 0xb5, 787 0x19, 0x6a, 0xd7, 0xb0, 0x44, 0x92, 0x30, 0x3b, 788 0xf7, 0x61, 0xd6, 0x49, 0x96, 0x66, 0x98, 0x28, 789 0x1a, 0x95, 0xa9, 0x42, 0xad, 0xb7, 0x50, 0x90, 790 0xad, 0x1c, 0x34, 0x80, 0xe2, 0xef, 0xcd, 0x41, 791 0x0b, 0xf0, 0x9d, 0x57, 0x62, 0x78, 0xfd, 0xc6, 792 0xc2, 0x19, 0x9e, 0x26, 0x31, 0xca, 0x1e, 0x75, 793 0xb1, 0x7a, 0x8e, 0xb5, 0x51, 0x3a, 0xfe, 0xe4, 794 0xf1, 0x0b, 0x4f, 0x14, 0x90, 0xdb, 0x9f, 0x44, 795 0x50, 0xbb, 0xef, 0x74, 0x00, 0x8c, 0x1f, 0x97, 796 }, 797 }, 798 { // PES 799 Header: astits.PacketHeader{ 800 ContinuityCounter: 1, 801 HasPayload: true, 802 PayloadUnitStartIndicator: false, 803 PID: 257, 804 }, 805 Payload: []byte{ 806 0xa1, 0xa2, 0xfa, 0x72, 0x16, 0x47, 0xc6, 0xc0, 807 0xe5, 0xfe, 0x67, 0x03, 0x9c, 0xfe, 0x62, 0x01, 808 0xa1, 0x00, 0x5d, 0xff, 0xa5, 0x03, 0x59, 0xfa, 809 0xa8, 0x25, 0x5f, 0x6b, 0x83, 0x51, 0xf2, 0xc0, 810 0x44, 0xff, 0x2d, 0x05, 0x4b, 0xee, 0xe0, 0x54, 811 0x9e, 0xae, 0x86, 0x45, 0xf3, 0xbd, 0x0e, 0x42, 812 0xf2, 0xbf, 0x0f, 0x7f, 0xc6, 0x09, 0x07, 0xdc, 813 0x22, 0x11, 0x77, 0xbe, 0x31, 0x27, 0x5b, 0xa4, 814 0x13, 0x47, 0x07, 0x32, 0x9f, 0x1f, 0xcb, 0xb0, 815 0xdf, 0x3e, 0x7d, 0x0d, 0xf3, 0xe7, 0xcf, 0x9f, 816 0x3e, 0xae, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 817 0x85, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 818 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f, 0x53, 0x5d, 819 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 820 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 821 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 822 0x9f, 0x3e, 0x00, 0x46, 0x28, 0x26, 0x20, 0x4a, 823 0x5a, 0xc0, 0x8a, 0xc5, 0xae, 0xa0, 0x55, 0x78, 824 0x82, 0x7a, 0x38, 0x10, 0x09, 0xc9, 0xb8, 0x0c, 825 0xfa, 0x5b, 0xc9, 0xd2, 0xec, 0x44, 0x25, 0xf8, 826 0x20, 0xf2, 0xc8, 0x8a, 0xe9, 0x40, 0x18, 0x06, 827 0xc6, 0x2b, 0xc8, 0xed, 0x8f, 0x33, 0x09, 0x92, 828 0x28, 0x1e, 0xc4, 0x24, 0xd8, 0x33, 0xa5, 0x00, 829 }, 830 }, 831 { // PES 832 AdaptationField: &astits.PacketAdaptationField{ 833 Length: 145, 834 StuffingLength: 144, 835 }, 836 Header: astits.PacketHeader{ 837 ContinuityCounter: 2, 838 HasAdaptationField: true, 839 HasPayload: true, 840 PayloadUnitStartIndicator: false, 841 PID: 257, 842 }, 843 Payload: []byte{ 844 0xf5, 0xea, 0x18, 0xfa, 0x90, 0x97, 0x97, 0xe8, 845 0x39, 0x6a, 0xcf, 0xf1, 0xdd, 0xff, 0x9e, 0x8e, 846 0x04, 0x02, 0xae, 0x65, 0x87, 0x5c, 0x4e, 0x72, 847 0xfd, 0x3c, 0x01, 0x86, 0xfe, 0x56, 0x59, 0x74, 848 0x44, 0x3a, 0x40, 0x00, 0xec, 0xfc, 849 }, 850 }, 851 }, 852 }, 853 } 854 855 func TestReader(t *testing.T) { 856 for _, ca := range casesReadWriter { 857 t.Run(ca.name, func(t *testing.T) { 858 var buf bytes.Buffer 859 mux := astits.NewMuxer(context.Background(), &buf) 860 861 for _, packet := range ca.packets { 862 _, err := mux.WritePacket(packet) 863 require.NoError(t, err) 864 } 865 866 r, err := NewReader(&buf) 867 require.NoError(t, err) 868 require.Equal(t, ca.track, r.Tracks()[0]) 869 870 i := 0 871 872 switch ca.track.Codec.(type) { 873 case *CodecH265, *CodecH264: 874 r.OnDataH26x(ca.track, func(pts int64, dts int64, au [][]byte) error { 875 require.Equal(t, ca.samples[i].pts, pts) 876 require.Equal(t, ca.samples[i].dts, dts) 877 require.Equal(t, ca.samples[i].data, au) 878 i++ 879 return nil 880 }) 881 882 case *CodecMPEG4Video: 883 r.OnDataMPEGxVideo(ca.track, func(pts int64, frame []byte) error { 884 require.Equal(t, ca.samples[i].pts, pts) 885 require.Equal(t, ca.samples[i].data[0], frame) 886 i++ 887 return nil 888 }) 889 890 case *CodecMPEG1Video: 891 r.OnDataMPEGxVideo(ca.track, func(pts int64, frame []byte) error { 892 require.Equal(t, ca.samples[i].pts, pts) 893 require.Equal(t, ca.samples[i].data[0], frame) 894 i++ 895 return nil 896 }) 897 898 case *CodecOpus: 899 r.OnDataOpus(ca.track, func(pts int64, packets [][]byte) error { 900 require.Equal(t, ca.samples[i].pts, pts) 901 require.Equal(t, ca.samples[i].data, packets) 902 i++ 903 return nil 904 }) 905 906 case *CodecMPEG4Audio: 907 r.OnDataMPEG4Audio(ca.track, func(pts int64, aus [][]byte) error { 908 require.Equal(t, ca.samples[i].pts, pts) 909 require.Equal(t, ca.samples[i].data, aus) 910 i++ 911 return nil 912 }) 913 914 case *CodecMPEG1Audio: 915 r.OnDataMPEG1Audio(ca.track, func(pts int64, frames [][]byte) error { 916 require.Equal(t, ca.samples[i].pts, pts) 917 require.Equal(t, ca.samples[i].data, frames) 918 i++ 919 return nil 920 }) 921 922 case *CodecAC3: 923 r.OnDataAC3(ca.track, func(pts int64, frame []byte) error { 924 require.Equal(t, ca.samples[i].pts, pts) 925 require.Equal(t, ca.samples[i].data[0], frame) 926 i++ 927 return nil 928 }) 929 930 default: 931 t.Errorf("unexpected") 932 } 933 934 for { 935 err := r.Read() 936 if errors.Is(err, astits.ErrNoMorePackets) { 937 break 938 } 939 require.NoError(t, err) 940 } 941 942 require.Equal(t, len(ca.samples), i) 943 }) 944 } 945 } 946 947 func TestReaderDecodeErrors(t *testing.T) { 948 for _, ca := range []string{ 949 "missing pts", 950 "h26x invalid avcc", 951 "opus pts != dts", 952 "opus invalid au", 953 "mpeg-4 audio pts != dts", 954 "mpeg-4 audio invalid", 955 "mpeg-1 audio pts != dts", 956 "ac-3 pts != dts", 957 "garbage", 958 } { 959 t.Run(ca, func(t *testing.T) { 960 var buf bytes.Buffer 961 mux := astits.NewMuxer(context.Background(), &buf) 962 963 switch ca { 964 case "missing pts", "h26x invalid avcc", "garbage": 965 err := mux.AddElementaryStream(astits.PMTElementaryStream{ 966 ElementaryPID: 123, 967 StreamType: astits.StreamTypeH264Video, 968 }) 969 require.NoError(t, err) 970 971 case "opus pts != dts", "opus invalid au": 972 err := mux.AddElementaryStream(astits.PMTElementaryStream{ 973 ElementaryPID: 123, 974 StreamType: astits.StreamTypePrivateData, 975 ElementaryStreamDescriptors: []*astits.Descriptor{ 976 { 977 Length: 4, 978 Tag: astits.DescriptorTagRegistration, 979 Registration: &astits.DescriptorRegistration{ 980 FormatIdentifier: opusIdentifier, 981 }, 982 }, 983 { 984 Length: 2, 985 Tag: astits.DescriptorTagExtension, 986 Extension: &astits.DescriptorExtension{ 987 Tag: 0x80, 988 Unknown: &[]uint8{2}, 989 }, 990 }, 991 }, 992 }) 993 require.NoError(t, err) 994 995 case "mpeg-4 audio pts != dts", "mpeg-4 audio invalid": 996 err := mux.AddElementaryStream(astits.PMTElementaryStream{ 997 ElementaryPID: 123, 998 StreamType: astits.StreamTypeAACAudio, 999 }) 1000 require.NoError(t, err) 1001 1002 case "mpeg-1 audio pts != dts": 1003 err := mux.AddElementaryStream(astits.PMTElementaryStream{ 1004 ElementaryPID: 123, 1005 StreamType: astits.StreamTypeMPEG1Audio, 1006 }) 1007 require.NoError(t, err) 1008 1009 case "ac-3 pts != dts": 1010 err := mux.AddElementaryStream(astits.PMTElementaryStream{ 1011 ElementaryPID: 123, 1012 StreamType: astits.StreamTypeAC3Audio, 1013 }) 1014 require.NoError(t, err) 1015 } 1016 1017 mux.SetPCRPID(123) 1018 1019 switch ca { 1020 case "missing pts": 1021 _, err := mux.WriteData(&astits.MuxerData{ 1022 PID: 123, 1023 PES: &astits.PESData{ 1024 Header: &astits.PESHeader{ 1025 OptionalHeader: &astits.PESOptionalHeader{ 1026 MarkerBits: 2, 1027 PTSDTSIndicator: astits.PTSDTSIndicatorNoPTSOrDTS, 1028 }, 1029 StreamID: streamIDVideo, 1030 }, 1031 Data: []byte{1, 2, 3, 4}, 1032 }, 1033 }) 1034 require.NoError(t, err) 1035 1036 case "h26x invalid avcc", "opus invalid au": 1037 _, err := mux.WriteData(&astits.MuxerData{ 1038 PID: 123, 1039 PES: &astits.PESData{ 1040 Header: &astits.PESHeader{ 1041 OptionalHeader: &astits.PESOptionalHeader{ 1042 MarkerBits: 2, 1043 PTSDTSIndicator: astits.PTSDTSIndicatorOnlyPTS, 1044 PTS: &astits.ClockReference{Base: 90000}, 1045 }, 1046 StreamID: streamIDVideo, 1047 }, 1048 Data: []byte{1, 2, 3, 4}, 1049 }, 1050 }) 1051 require.NoError(t, err) 1052 1053 case "opus pts != dts", "mpeg-1 audio pts != dts": 1054 _, err := mux.WriteData(&astits.MuxerData{ 1055 PID: 123, 1056 PES: &astits.PESData{ 1057 Header: &astits.PESHeader{ 1058 OptionalHeader: &astits.PESOptionalHeader{ 1059 MarkerBits: 2, 1060 PTSDTSIndicator: astits.PTSDTSIndicatorBothPresent, 1061 PTS: &astits.ClockReference{Base: 90000}, 1062 DTS: &astits.ClockReference{Base: 180000}, 1063 }, 1064 StreamID: streamIDVideo, 1065 }, 1066 Data: []byte{1, 2, 3, 4}, 1067 }, 1068 }) 1069 require.NoError(t, err) 1070 1071 case "mpeg-4 audio pts != dts": 1072 data, _ := mpeg4audio.ADTSPackets{{ 1073 Type: mpeg4audio.ObjectTypeAACLC, 1074 SampleRate: 44100, 1075 ChannelCount: 1, 1076 AU: []byte{1, 2, 3, 4}, 1077 }}.Marshal() 1078 1079 _, err := mux.WriteData(&astits.MuxerData{ 1080 PID: 123, 1081 PES: &astits.PESData{ 1082 Header: &astits.PESHeader{ 1083 OptionalHeader: &astits.PESOptionalHeader{ 1084 MarkerBits: 2, 1085 PTSDTSIndicator: astits.PTSDTSIndicatorBothPresent, 1086 PTS: &astits.ClockReference{Base: 90000}, 1087 DTS: &astits.ClockReference{Base: 180000}, 1088 }, 1089 StreamID: streamIDVideo, 1090 }, 1091 Data: data, 1092 }, 1093 }) 1094 require.NoError(t, err) 1095 1096 _, err = mux.WriteData(&astits.MuxerData{ 1097 PID: 123, 1098 PES: &astits.PESData{ 1099 Header: &astits.PESHeader{ 1100 OptionalHeader: &astits.PESOptionalHeader{ 1101 MarkerBits: 2, 1102 PTSDTSIndicator: astits.PTSDTSIndicatorBothPresent, 1103 PTS: &astits.ClockReference{Base: 90000}, 1104 DTS: &astits.ClockReference{Base: 180000}, 1105 }, 1106 StreamID: streamIDVideo, 1107 }, 1108 Data: []byte{1, 2, 3, 4}, 1109 }, 1110 }) 1111 require.NoError(t, err) 1112 1113 case "mpeg-4 audio invalid": 1114 data, _ := mpeg4audio.ADTSPackets{{ 1115 Type: mpeg4audio.ObjectTypeAACLC, 1116 SampleRate: 44100, 1117 ChannelCount: 1, 1118 AU: []byte{1, 2, 3, 4}, 1119 }}.Marshal() 1120 1121 _, err := mux.WriteData(&astits.MuxerData{ 1122 PID: 123, 1123 PES: &astits.PESData{ 1124 Header: &astits.PESHeader{ 1125 OptionalHeader: &astits.PESOptionalHeader{ 1126 MarkerBits: 2, 1127 PTSDTSIndicator: astits.PTSDTSIndicatorOnlyPTS, 1128 PTS: &astits.ClockReference{Base: 90000}, 1129 }, 1130 StreamID: streamIDVideo, 1131 }, 1132 Data: data, 1133 }, 1134 }) 1135 require.NoError(t, err) 1136 1137 _, err = mux.WriteData(&astits.MuxerData{ 1138 PID: 123, 1139 PES: &astits.PESData{ 1140 Header: &astits.PESHeader{ 1141 OptionalHeader: &astits.PESOptionalHeader{ 1142 MarkerBits: 2, 1143 PTSDTSIndicator: astits.PTSDTSIndicatorOnlyPTS, 1144 PTS: &astits.ClockReference{Base: 90000}, 1145 }, 1146 StreamID: streamIDVideo, 1147 }, 1148 Data: []byte{1, 2, 3, 4}, 1149 }, 1150 }) 1151 require.NoError(t, err) 1152 1153 case "ac-3 pts != dts": 1154 _, err := mux.WriteData(&astits.MuxerData{ 1155 PID: 123, 1156 PES: &astits.PESData{ 1157 Header: &astits.PESHeader{ 1158 OptionalHeader: &astits.PESOptionalHeader{ 1159 MarkerBits: 2, 1160 PTSDTSIndicator: astits.PTSDTSIndicatorBothPresent, 1161 PTS: &astits.ClockReference{Base: 90000}, 1162 DTS: &astits.ClockReference{Base: 180000}, 1163 }, 1164 StreamID: streamIDVideo, 1165 }, 1166 Data: []byte{ 1167 0x0b, 0x77, 0x47, 0x11, 0x0c, 0x40, 0x2f, 0x84, 1168 0x2b, 0xc1, 0x07, 0x7a, 0xb0, 0xfa, 0xbb, 0xea, 1169 0xef, 0x9f, 0x57, 0x7c, 0xf9, 0xf3, 0xf7, 0xcf, 1170 0x9f, 0x3e, 0x32, 0xfe, 0xd5, 0xc1, 0x50, 0xde, 1171 0xc5, 0x1e, 0x73, 0xd2, 0x6c, 0xa6, 0x94, 0x46, 1172 }, 1173 }, 1174 }) 1175 require.NoError(t, err) 1176 1177 _, err = mux.WriteData(&astits.MuxerData{ 1178 PID: 123, 1179 PES: &astits.PESData{ 1180 Header: &astits.PESHeader{ 1181 OptionalHeader: &astits.PESOptionalHeader{ 1182 MarkerBits: 2, 1183 PTSDTSIndicator: astits.PTSDTSIndicatorBothPresent, 1184 PTS: &astits.ClockReference{Base: 90000}, 1185 DTS: &astits.ClockReference{Base: 180000}, 1186 }, 1187 StreamID: streamIDVideo, 1188 }, 1189 Data: []byte{1, 2, 3, 4}, 1190 }, 1191 }) 1192 require.NoError(t, err) 1193 1194 case "garbage": 1195 _, err := mux.WriteData(&astits.MuxerData{ 1196 PID: 123, 1197 PES: &astits.PESData{ 1198 Header: &astits.PESHeader{ 1199 OptionalHeader: &astits.PESOptionalHeader{ 1200 MarkerBits: 2, 1201 PTSDTSIndicator: astits.PTSDTSIndicatorOnlyPTS, 1202 PTS: &astits.ClockReference{Base: 90000}, 1203 }, 1204 StreamID: streamIDVideo, 1205 }, 1206 Data: []byte{0, 0, 0, 1, 1, 2, 3, 4}, 1207 }, 1208 }) 1209 require.NoError(t, err) 1210 1211 buf.Write(bytes.Repeat([]byte{1, 2, 3, 4}, 188/4)) 1212 1213 _, err = mux.WriteData(&astits.MuxerData{ 1214 PID: 123, 1215 PES: &astits.PESData{ 1216 Header: &astits.PESHeader{ 1217 OptionalHeader: &astits.PESOptionalHeader{ 1218 MarkerBits: 2, 1219 PTSDTSIndicator: astits.PTSDTSIndicatorOnlyPTS, 1220 PTS: &astits.ClockReference{Base: 90000}, 1221 }, 1222 StreamID: streamIDVideo, 1223 }, 1224 Data: []byte{0, 0, 0, 1, 1, 2, 3, 4}, 1225 }, 1226 }) 1227 require.NoError(t, err) 1228 } 1229 1230 r, err := NewReader(bytes.NewReader(buf.Bytes())) 1231 require.NoError(t, err) 1232 1233 dataRecv := false 1234 1235 switch ca { 1236 case "missing pts", "h26x invalid avcc": 1237 r.OnDataH26x(r.Tracks()[0], func(_, _ int64, _ [][]byte) error { 1238 return nil 1239 }) 1240 1241 case "opus pts != dts", "opus invalid au": 1242 r.OnDataOpus(r.Tracks()[0], func(_ int64, _ [][]byte) error { 1243 return nil 1244 }) 1245 1246 case "mpeg-4 audio pts != dts", "mpeg-4 audio invalid": 1247 r.OnDataMPEG4Audio(r.Tracks()[0], func(_ int64, _ [][]byte) error { 1248 return nil 1249 }) 1250 1251 case "mpeg-1 audio pts != dts": 1252 r.OnDataMPEG1Audio(r.Tracks()[0], func(_ int64, _ [][]byte) error { 1253 return nil 1254 }) 1255 1256 case "ac-3 pts != dts": 1257 r.OnDataAC3(r.Tracks()[0], func(_ int64, _ []byte) error { 1258 return nil 1259 }) 1260 1261 case "garbage": 1262 counter := 0 1263 r.OnDataH26x(r.Tracks()[0], func(_, _ int64, _ [][]byte) error { 1264 counter++ 1265 if counter == 2 { 1266 dataRecv = true 1267 } 1268 return nil 1269 }) 1270 } 1271 1272 decodeErrRecv := false 1273 1274 r.OnDecodeError(func(err error) { 1275 switch ca { 1276 case "missing pts": 1277 require.EqualError(t, err, "PTS is missing") 1278 1279 case "h26x invalid avcc": 1280 require.EqualError(t, err, "initial delimiter not found") 1281 1282 case "opus pts != dts", "mpeg-4 audio pts != dts", "mpeg-1 audio pts != dts", "ac-3 pts != dts": 1283 require.EqualError(t, err, "PTS is not equal to DTS") 1284 1285 case "opus invalid au": 1286 require.EqualError(t, err, "invalid control header: invalid prefix") 1287 1288 case "mpeg-4 audio invalid": 1289 require.EqualError(t, err, "invalid ADTS: invalid length") 1290 1291 case "garbage": 1292 require.EqualError(t, err, "astits: fetching next packet failed:"+ 1293 " astits: fetching next packet from buffer failed:"+ 1294 " astits: building packet failed: astits: packet must start with a sync byte") 1295 } 1296 decodeErrRecv = true 1297 }) 1298 1299 for { 1300 err := r.Read() 1301 if err != nil { 1302 require.Equal(t, astits.ErrNoMorePackets, err) 1303 break 1304 } 1305 } 1306 1307 require.Equal(t, true, decodeErrRecv) 1308 1309 if ca == "garbage" { 1310 require.Equal(t, true, dataRecv) 1311 } 1312 }) 1313 } 1314 } 1315 1316 func FuzzReader(f *testing.F) { 1317 for _, ca := range casesReadWriter { 1318 var buf bytes.Buffer 1319 mux := astits.NewMuxer(context.Background(), &buf) 1320 for _, pkt := range ca.packets { 1321 mux.WritePacket(pkt) //nolint:errcheck 1322 } 1323 f.Add(buf.Bytes()) 1324 } 1325 1326 f.Add([]byte{ 1327 0x47, 0x40, 0x00, 0x10, 0x00, 0x00, 0xb0, 0x0d, 1328 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x01, 0xf0, 1329 0x00, 0x71, 0x10, 0xd8, 0x78, 0xff, 0xff, 0xff, 1330 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1331 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1332 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1333 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1334 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1335 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1336 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1337 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1338 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1339 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1340 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1341 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1342 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1343 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1344 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1345 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1346 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1347 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1348 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1349 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1350 0xff, 0xff, 0xff, 0xff, 0x47, 0x50, 0x00, 0x10, 1351 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 1352 0x00, 0xe1, 0x00, 0xf0, 0x00, 0x06, 0xe1, 0x00, 1353 0xf0, 0x00, 0xbe, 0x7f, 0xa0, 0x52, 0xff, 0xff, 1354 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1355 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1356 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1357 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1358 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1359 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1360 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1361 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1362 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1363 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1364 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1365 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1366 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1367 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1368 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1369 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1370 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1371 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1372 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1373 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1374 }) 1375 1376 f.Add([]byte{ 1377 0x47, 0x40, 0x00, 0x10, 0x00, 0x00, 0xb0, 0x0d, 1378 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x01, 0xf0, 1379 0x00, 0x71, 0x10, 0xd8, 0x78, 0xff, 0xff, 0xff, 1380 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1381 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1382 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1383 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1384 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1385 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1386 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1387 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1388 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1389 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1390 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1391 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1392 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1393 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1394 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1395 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1396 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1397 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1398 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1399 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1400 0xff, 0xff, 0xff, 0xff, 0x47, 0x50, 0x00, 0x10, 1401 0x00, 0x02, 0xb0, 0x18, 0x00, 0x01, 0xc1, 0x00, 1402 0x00, 0xe1, 0x00, 0xf0, 0x00, 0x06, 0xe1, 0x00, 1403 0xf0, 0x06, 0x05, 0x04, 0x4f, 0x70, 0x75, 0x73, 1404 0xc7, 0x15, 0x35, 0x31, 0xff, 0xff, 0xff, 0xff, 1405 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1406 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1407 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1408 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1409 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1410 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1411 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1412 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1413 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1414 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1415 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1416 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1417 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1418 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1419 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1420 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1421 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1422 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1423 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1424 }) 1425 1426 f.Fuzz(func(_ *testing.T, b []byte) { 1427 NewReader(bytes.NewReader(b)) //nolint:errcheck 1428 }) 1429 }