NAL units may have unlimited trailing zeroes
When a NAL unit had trailing zeroes that were split across pushes to the H264Stream, the parser would go into an infinite loop. Instead, make sure we never advance the parser beyond the current push and advance the sync point to a valid position before starting processing. Add HTML-HLS dependencies to the example page.
Showing
3 changed files
with
55 additions
and
5 deletions
... | @@ -34,6 +34,9 @@ | ... | @@ -34,6 +34,9 @@ |
34 | <script src="node_modules/pkcs7/dist/pkcs7.unpad.js"></script> | 34 | <script src="node_modules/pkcs7/dist/pkcs7.unpad.js"></script> |
35 | <script src="src/decrypter.js"></script> | 35 | <script src="src/decrypter.js"></script> |
36 | 36 | ||
37 | <script src="../src/mp4-generator.js"></script> | ||
38 | <script src="../src/transmuxer.js"></script> | ||
39 | |||
37 | <script src="src/bin-utils.js"></script> | 40 | <script src="src/bin-utils.js"></script> |
38 | 41 | ||
39 | <!-- example MPEG2-TS segments --> | 42 | <!-- example MPEG2-TS segments --> | ... | ... |
... | @@ -522,8 +522,8 @@ AudioSegmentStream.prototype = new videojs.Hls.Stream(); | ... | @@ -522,8 +522,8 @@ AudioSegmentStream.prototype = new videojs.Hls.Stream(); |
522 | */ | 522 | */ |
523 | NalByteStream = function() { | 523 | NalByteStream = function() { |
524 | var | 524 | var |
525 | i = 6, | ||
526 | syncPoint = 1, | 525 | syncPoint = 1, |
526 | i, | ||
527 | buffer; | 527 | buffer; |
528 | NalByteStream.prototype.init.call(this); | 528 | NalByteStream.prototype.init.call(this); |
529 | 529 | ||
... | @@ -548,6 +548,16 @@ NalByteStream = function() { | ... | @@ -548,6 +548,16 @@ NalByteStream = function() { |
548 | // or this: | 548 | // or this: |
549 | // 0 0 1 .. NAL .. 0 0 0 | 549 | // 0 0 1 .. NAL .. 0 0 0 |
550 | // ^ sync point ^ i | 550 | // ^ sync point ^ i |
551 | |||
552 | // advance the sync point to a NAL start, if necessary | ||
553 | for (; syncPoint < buffer.byteLength - 3; syncPoint++) { | ||
554 | if (buffer[syncPoint + 2] === 1) { | ||
555 | // the sync point is properly aligned | ||
556 | i = syncPoint + 5; | ||
557 | break; | ||
558 | } | ||
559 | } | ||
560 | |||
551 | while (i < buffer.byteLength) { | 561 | while (i < buffer.byteLength) { |
552 | // look at the current byte to determine if we've hit the end of | 562 | // look at the current byte to determine if we've hit the end of |
553 | // a NAL unit boundary | 563 | // a NAL unit boundary |
... | @@ -568,7 +578,7 @@ NalByteStream = function() { | ... | @@ -568,7 +578,7 @@ NalByteStream = function() { |
568 | // drop trailing zeroes | 578 | // drop trailing zeroes |
569 | do { | 579 | do { |
570 | i++; | 580 | i++; |
571 | } while (buffer[i] !== 1); | 581 | } while (buffer[i] !== 1 && i < buffer.length); |
572 | syncPoint = i - 2; | 582 | syncPoint = i - 2; |
573 | i += 3; | 583 | i += 3; |
574 | break; | 584 | break; | ... | ... |
... | @@ -741,23 +741,60 @@ test('unpacks nal units from byte streams split across pushes', function() { | ... | @@ -741,23 +741,60 @@ test('unpacks nal units from byte streams split across pushes', function() { |
741 | type: 'video', | 741 | type: 'video', |
742 | data: new Uint8Array([ | 742 | data: new Uint8Array([ |
743 | 0x00, 0x00, 0x00, 0x01, | 743 | 0x00, 0x00, 0x00, 0x01, |
744 | 0x09]) | 744 | 0x09, 0x07, 0x06, 0x05, |
745 | 0x04 | ||
746 | ]) | ||
745 | }); | 747 | }); |
746 | ok(!data, 'buffers NAL units across events'); | 748 | ok(!data, 'buffers NAL units across events'); |
747 | 749 | ||
748 | h264Stream.push({ | 750 | h264Stream.push({ |
749 | type: 'video', | 751 | type: 'video', |
750 | data: new Uint8Array([ | 752 | data: new Uint8Array([ |
751 | 0x07, | 753 | 0x03, 0x02, 0x01, |
752 | 0x00, 0x00, 0x01 | 754 | 0x00, 0x00, 0x01 |
753 | ]) | 755 | ]) |
754 | }); | 756 | }); |
755 | ok(data, 'generated a data event'); | 757 | ok(data, 'generated a data event'); |
756 | equal(data.nalUnitType, 'access_unit_delimiter_rbsp', 'identified an access unit delimiter'); | 758 | equal(data.nalUnitType, 'access_unit_delimiter_rbsp', 'identified an access unit delimiter'); |
757 | equal(data.data.length, 2, 'calculated nal unit length'); | 759 | equal(data.data.length, 8, 'calculated nal unit length'); |
758 | equal(data.data[1], 7, 'read a payload byte'); | 760 | equal(data.data[1], 7, 'read a payload byte'); |
759 | }); | 761 | }); |
760 | 762 | ||
763 | test('buffers nal unit trailing zeros across pushes', function() { | ||
764 | var data = []; | ||
765 | h264Stream.on('data', function(event) { | ||
766 | data.push(event); | ||
767 | }); | ||
768 | |||
769 | // lots of zeros after the nal, stretching into the next push | ||
770 | h264Stream.push({ | ||
771 | type: 'video', | ||
772 | data: new Uint8Array([ | ||
773 | 0x00, 0x00, 0x00, 0x01, | ||
774 | 0x09, 0x07, 0x00, 0x00, | ||
775 | 0x00, 0x00, 0x00, 0x00, | ||
776 | 0x00, 0x00, 0x00, 0x00, | ||
777 | 0x00 | ||
778 | ]) | ||
779 | }); | ||
780 | equal(data.length, 1, 'delivered the first nal'); | ||
781 | |||
782 | h264Stream.push({ | ||
783 | type: 'video', | ||
784 | data: new Uint8Array([ | ||
785 | 0x00, 0x00, | ||
786 | 0x00, 0x00, 0x01, | ||
787 | 0x09, 0x06, | ||
788 | 0x00, 0x00, 0x01 | ||
789 | ]) | ||
790 | }); | ||
791 | equal(data.length, 2, 'generated data events'); | ||
792 | equal(data[0].data.length, 2, 'ignored trailing zeros'); | ||
793 | equal(data[0].data[0], 0x09, 'found the first nal start'); | ||
794 | equal(data[1].data.length, 2, 'found the following nal start'); | ||
795 | equal(data[1].data[0], 0x09, 'found the second nal start'); | ||
796 | }); | ||
797 | |||
761 | test('unpacks nal units from byte streams with split sync points', function() { | 798 | test('unpacks nal units from byte streams with split sync points', function() { |
762 | var data; | 799 | var data; |
763 | h264Stream.on('data', function(event) { | 800 | h264Stream.on('data', function(event) { | ... | ... |
-
Please register or sign in to post a comment