github.com/pion/webrtc/v4@v4.0.1/pkg/media/ivfreader/ivfreader_test.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 package ivfreader 5 6 import ( 7 "bytes" 8 "io" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 ) 13 14 // buildIVFContainer takes frames and prepends valid IVF file header 15 func buildIVFContainer(frames ...*[]byte) *bytes.Buffer { 16 // Valid IVF file header taken from: https://github.com/webmproject/... 17 // vp8-test-vectors/blob/master/vp80-00-comprehensive-001.ivf 18 // Video Image Width - 176 19 // Video Image Height - 144 20 // Frame Rate Rate - 30000 21 // Frame Rate Scale - 1000 22 // Video Length in Frames - 29 23 // BitRate: 64.01 kb/s 24 ivf := []byte{ 25 0x44, 0x4b, 0x49, 0x46, 0x00, 0x00, 0x20, 0x00, 26 0x56, 0x50, 0x38, 0x30, 0xb0, 0x00, 0x90, 0x00, 27 0x30, 0x75, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 28 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 29 } 30 31 for f := range frames { 32 ivf = append(ivf, *frames[f]...) 33 } 34 35 return bytes.NewBuffer(ivf) 36 } 37 38 func TestIVFReader_ParseValidFileHeader(t *testing.T) { 39 assert := assert.New(t) 40 ivf := buildIVFContainer(&[]byte{}) 41 42 reader, header, err := NewWith(ivf) 43 assert.Nil(err, "IVFReader should be created") 44 assert.NotNil(reader, "Reader shouldn't be nil") 45 assert.NotNil(header, "Header shouldn't be nil") 46 47 assert.Equal("DKIF", header.signature, "signature is 'DKIF'") 48 assert.Equal(uint16(0), header.version, "version should be 0") 49 assert.Equal("VP80", header.FourCC, "FourCC should be 'VP80'") 50 assert.Equal(uint16(176), header.Width, "width should be 176") 51 assert.Equal(uint16(144), header.Height, "height should be 144") 52 assert.Equal(uint32(30000), header.TimebaseDenominator, "timebase denominator should be 30000") 53 assert.Equal(uint32(1000), header.TimebaseNumerator, "timebase numerator should be 1000") 54 assert.Equal(uint32(29), header.NumFrames, "number of frames should be 29") 55 assert.Equal(uint32(0), header.unused, "bytes should be unused") 56 } 57 58 func TestIVFReader_ParseValidFrames(t *testing.T) { 59 assert := assert.New(t) 60 61 // Frame Length - 4 62 // Timestamp - None 63 // Frame Payload - 0xDEADBEEF 64 validFrame1 := []byte{ 65 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 66 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 67 } 68 69 // Frame Length - 12 70 // Timestamp - None 71 // Frame Payload - 0xDEADBEEFDEADBEEF 72 validFrame2 := []byte{ 73 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 74 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 75 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 76 } 77 78 ivf := buildIVFContainer(&validFrame1, &validFrame2) 79 reader, _, err := NewWith(ivf) 80 assert.Nil(err, "IVFReader should be created") 81 assert.NotNil(reader, "Reader shouldn't be nil") 82 83 // Parse Frame #1 84 payload, header, err := reader.ParseNextFrame() 85 86 assert.Nil(err, "Should have parsed frame #1 without error") 87 assert.Equal(uint32(4), header.FrameSize, "Frame header frameSize should be 4") 88 assert.Equal(4, len(payload), "Payload should be length 4") 89 assert.Equal( 90 payload, 91 []byte{ 92 0xDE, 0xAD, 0xBE, 0xEF, 93 }, 94 "Payload value should be 0xDEADBEEF") 95 assert.Equal(int64(ivfFrameHeaderSize+ivfFileHeaderSize+header.FrameSize), reader.bytesReadSuccesfully) 96 previousBytesRead := reader.bytesReadSuccesfully 97 98 // Parse Frame #2 99 payload, header, err = reader.ParseNextFrame() 100 101 assert.Nil(err, "Should have parsed frame #2 without error") 102 assert.Equal(uint32(12), header.FrameSize, "Frame header frameSize should be 4") 103 assert.Equal(12, len(payload), "Payload should be length 12") 104 assert.Equal( 105 payload, 106 []byte{ 107 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 108 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 109 }, 110 "Payload value should be 0xDEADBEEFDEADBEEF") 111 assert.Equal(int64(ivfFrameHeaderSize+header.FrameSize)+previousBytesRead, reader.bytesReadSuccesfully) 112 } 113 114 func TestIVFReader_ParseIncompleteFrameHeader(t *testing.T) { 115 assert := assert.New(t) 116 117 // frame with 11-byte header (missing 1 byte) 118 incompleteFrame := []byte{ 119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 120 0x00, 0x00, 0x00, 121 } 122 123 ivf := buildIVFContainer(&incompleteFrame) 124 reader, _, err := NewWith(ivf) 125 assert.Nil(err, "IVFReader should be created") 126 assert.NotNil(reader, "Reader shouldn't be nil") 127 128 // Parse Frame #1 129 payload, header, err := reader.ParseNextFrame() 130 131 assert.Nil(payload, "Payload should be nil") 132 assert.Nil(header, "Incomplete header should be nil") 133 assert.Equal(errIncompleteFrameHeader, err) 134 } 135 136 func TestIVFReader_ParseIncompleteFramePayload(t *testing.T) { 137 assert := assert.New(t) 138 139 // frame with header defining frameSize of 4 140 // but only 2 bytes available (missing 2 bytes) 141 incompleteFrame := []byte{ 142 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 143 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 144 } 145 146 ivf := buildIVFContainer(&incompleteFrame) 147 reader, _, err := NewWith(ivf) 148 assert.Nil(err, "IVFReader should be created") 149 assert.NotNil(reader, "Reader shouldn't be nil") 150 151 // Parse Frame #1 152 payload, header, err := reader.ParseNextFrame() 153 154 assert.Nil(payload, "Incomplete payload should be nil") 155 assert.Nil(header, "Header should be nil") 156 assert.Equal(errIncompleteFrameData, err) 157 } 158 159 func TestIVFReader_EOFWhenNoFramesLeft(t *testing.T) { 160 assert := assert.New(t) 161 162 ivf := buildIVFContainer(&[]byte{}) 163 reader, _, err := NewWith(ivf) 164 assert.Nil(err, "IVFReader should be created") 165 assert.NotNil(reader, "Reader shouldn't be nil") 166 167 _, _, err = reader.ParseNextFrame() 168 169 assert.Equal(io.EOF, err) 170 }