github.com/pion/webrtc/v4@v4.0.1/pkg/media/ivfwriter/ivfwriter_test.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 package ivfwriter 5 6 import ( 7 "bytes" 8 "encoding/binary" 9 "io" 10 "testing" 11 12 "github.com/pion/rtp" 13 "github.com/pion/rtp/codecs" 14 "github.com/stretchr/testify/assert" 15 ) 16 17 type ivfWriterPacketTest struct { 18 buffer io.Writer 19 message string 20 messageClose string 21 packet *rtp.Packet 22 writer *IVFWriter 23 err error 24 closeErr error 25 } 26 27 func TestIVFWriter_Basic(t *testing.T) { 28 assert := assert.New(t) 29 addPacketTestCase := []ivfWriterPacketTest{ 30 { 31 buffer: &bytes.Buffer{}, 32 message: "IVFWriter shouldn't be able to write something to a closed file", 33 messageClose: "IVFWriter should be able to close an already closed file", 34 packet: nil, 35 err: errFileNotOpened, 36 closeErr: nil, 37 }, 38 { 39 buffer: &bytes.Buffer{}, 40 message: "IVFWriter shouldn't be able to write something an empty packet", 41 messageClose: "IVFWriter should be able to close the file", 42 packet: &rtp.Packet{}, 43 err: errInvalidNilPacket, 44 closeErr: nil, 45 }, 46 { 47 buffer: nil, 48 message: "IVFWriter shouldn't be able to write something to a closed file", 49 messageClose: "IVFWriter should be able to close an already closed file", 50 packet: nil, 51 err: errFileNotOpened, 52 closeErr: nil, 53 }, 54 } 55 56 // First test case has a 'nil' file descriptor 57 writer, err := NewWith(addPacketTestCase[0].buffer) 58 assert.Nil(err, "IVFWriter should be created") 59 assert.NotNil(writer, "Writer shouldn't be nil") 60 assert.False(writer.seenKeyFrame, "Writer's seenKeyFrame should initialize false") 61 assert.Equal(uint64(0), writer.count, "Writer's packet count should initialize 0") 62 err = writer.Close() 63 assert.Nil(err, "IVFWriter should be able to close the stream") 64 writer.ioWriter = nil 65 addPacketTestCase[0].writer = writer 66 67 // Second test tries to write an empty packet 68 writer, err = NewWith(addPacketTestCase[1].buffer) 69 assert.Nil(err, "IVFWriter should be created") 70 assert.NotNil(writer, "Writer shouldn't be nil") 71 assert.False(writer.seenKeyFrame, "Writer's seenKeyFrame should initialize false") 72 assert.Equal(uint64(0), writer.count, "Writer's packet count should initialize 0") 73 addPacketTestCase[1].writer = writer 74 75 // Fourth test tries to write to a nil stream 76 writer, err = NewWith(addPacketTestCase[2].buffer) 77 assert.NotNil(err, "IVFWriter shouldn't be created") 78 assert.Nil(writer, "Writer should be nil") 79 addPacketTestCase[2].writer = writer 80 } 81 82 func TestIVFWriter_VP8(t *testing.T) { 83 // Construct valid packet 84 rawValidPkt := []byte{ 85 0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 86 0x27, 0x82, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x98, 0x36, 0xbe, 0x89, 0x9e, 87 } 88 89 validPacket := &rtp.Packet{ 90 Header: rtp.Header{ 91 Marker: true, 92 Extension: true, 93 ExtensionProfile: 1, 94 Version: 2, 95 PayloadType: 96, 96 SequenceNumber: 27023, 97 Timestamp: 3653407706, 98 SSRC: 476325762, 99 CSRC: []uint32{}, 100 }, 101 Payload: rawValidPkt[20:], 102 } 103 assert.NoError(t, validPacket.SetExtension(0, []byte{0xFF, 0xFF, 0xFF, 0xFF})) 104 105 // Construct mid partition packet 106 rawMidPartPkt := []byte{ 107 0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 108 0x27, 0x82, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x88, 0x36, 0xbe, 0x89, 0x9e, 109 } 110 111 midPartPacket := &rtp.Packet{ 112 Header: rtp.Header{ 113 Marker: true, 114 Extension: true, 115 ExtensionProfile: 1, 116 Version: 2, 117 PayloadType: 96, 118 SequenceNumber: 27023, 119 Timestamp: 3653407706, 120 SSRC: 476325762, 121 CSRC: []uint32{}, 122 }, 123 Payload: rawMidPartPkt[20:], 124 } 125 assert.NoError(t, midPartPacket.SetExtension(0, []byte{0xFF, 0xFF, 0xFF, 0xFF})) 126 127 // Construct keyframe packet 128 rawKeyframePkt := []byte{ 129 0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 130 0x27, 0x82, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x98, 0x36, 0xbe, 0x88, 0x9e, 131 } 132 133 keyframePacket := &rtp.Packet{ 134 Header: rtp.Header{ 135 Marker: true, 136 Extension: true, 137 ExtensionProfile: 1, 138 Version: 2, 139 PayloadType: 96, 140 SequenceNumber: 27023, 141 Timestamp: 3653407706, 142 SSRC: 476325762, 143 CSRC: []uint32{}, 144 }, 145 Payload: rawKeyframePkt[20:], 146 } 147 assert.NoError(t, keyframePacket.SetExtension(0, []byte{0xFF, 0xFF, 0xFF, 0xFF})) 148 149 assert := assert.New(t) 150 151 // Check valid packet parameters 152 vp8Packet := codecs.VP8Packet{} 153 _, err := vp8Packet.Unmarshal(validPacket.Payload) 154 assert.Nil(err, "Packet did not process") 155 assert.Equal(uint8(1), vp8Packet.S, "Start packet S value should be 1") 156 assert.Equal(uint8(1), vp8Packet.Payload[0]&0x01, "Non Keyframe packet P value should be 1") 157 158 // Check mid partition packet parameters 159 vp8Packet = codecs.VP8Packet{} 160 _, err = vp8Packet.Unmarshal(midPartPacket.Payload) 161 assert.Nil(err, "Packet did not process") 162 assert.Equal(uint8(0), vp8Packet.S, "Mid Partition packet S value should be 0") 163 assert.Equal(uint8(1), vp8Packet.Payload[0]&0x01, "Non Keyframe packet P value should be 1") 164 165 // Check keyframe packet parameters 166 vp8Packet = codecs.VP8Packet{} 167 _, err = vp8Packet.Unmarshal(keyframePacket.Payload) 168 assert.Nil(err, "Packet did not process") 169 assert.Equal(uint8(1), vp8Packet.S, "Start packet S value should be 1") 170 assert.Equal(uint8(0), vp8Packet.Payload[0]&0x01, "Keyframe packet P value should be 0") 171 172 // The linter misbehave and thinks this code is the same as the tests in oggwriter_test 173 // nolint:dupl 174 addPacketTestCase := []ivfWriterPacketTest{ 175 { 176 buffer: &bytes.Buffer{}, 177 message: "IVFWriter should be able to write an IVF packet", 178 messageClose: "IVFWriter should be able to close the file", 179 packet: validPacket, 180 err: nil, 181 closeErr: nil, 182 }, 183 { 184 buffer: &bytes.Buffer{}, 185 message: "IVFWriter should be able to write a Keframe IVF packet", 186 messageClose: "IVFWriter should be able to close the file", 187 packet: keyframePacket, 188 err: nil, 189 closeErr: nil, 190 }, 191 } 192 193 // first test tries to write a valid VP8 packet 194 writer, err := NewWith(addPacketTestCase[0].buffer, WithCodec(mimeTypeVP8)) 195 assert.Nil(err, "IVFWriter should be created") 196 assert.NotNil(writer, "Writer shouldn't be nil") 197 assert.False(writer.seenKeyFrame, "Writer's seenKeyFrame should initialize false") 198 assert.Equal(uint64(0), writer.count, "Writer's packet count should initialize 0") 199 addPacketTestCase[0].writer = writer 200 201 // second test tries to write a keyframe packet 202 writer, err = NewWith(addPacketTestCase[1].buffer) 203 assert.Nil(err, "IVFWriter should be created") 204 assert.NotNil(writer, "Writer shouldn't be nil") 205 assert.False(writer.seenKeyFrame, "Writer's seenKeyFrame should initialize false") 206 assert.Equal(uint64(0), writer.count, "Writer's packet count should initialize 0") 207 addPacketTestCase[1].writer = writer 208 209 for _, t := range addPacketTestCase { 210 if t.writer != nil { 211 res := t.writer.WriteRTP(t.packet) 212 assert.Equal(res, t.err, t.message) 213 } 214 } 215 216 // Third test tries to write a valid VP8 packet - No Keyframe 217 assert.False(addPacketTestCase[0].writer.seenKeyFrame, "Writer's seenKeyFrame should remain false") 218 assert.Equal(uint64(0), addPacketTestCase[0].writer.count, "Writer's packet count should remain 0") 219 assert.Equal(nil, addPacketTestCase[0].writer.WriteRTP(midPartPacket), "Write packet failed") // add a mid partition packet 220 assert.Equal(uint64(0), addPacketTestCase[0].writer.count, "Writer's packet count should remain 0") 221 222 // Fifth test tries to write a keyframe packet 223 assert.True(addPacketTestCase[1].writer.seenKeyFrame, "Writer's seenKeyFrame should now be true") 224 assert.Equal(uint64(1), addPacketTestCase[1].writer.count, "Writer's packet count should now be 1") 225 assert.Equal(nil, addPacketTestCase[1].writer.WriteRTP(midPartPacket), "Write packet failed") // add a mid partition packet 226 assert.Equal(uint64(1), addPacketTestCase[1].writer.count, "Writer's packet count should remain 1") 227 assert.Equal(nil, addPacketTestCase[1].writer.WriteRTP(validPacket), "Write packet failed") // add a valid packet 228 assert.Equal(uint64(2), addPacketTestCase[1].writer.count, "Writer's packet count should now be 2") 229 230 for _, t := range addPacketTestCase { 231 if t.writer != nil { 232 res := t.writer.Close() 233 assert.Equal(res, t.closeErr, t.messageClose) 234 } 235 } 236 } 237 238 func TestIVFWriter_EmptyPayload(t *testing.T) { 239 buffer := &bytes.Buffer{} 240 241 writer, err := NewWith(buffer) 242 assert.NoError(t, err) 243 244 assert.NoError(t, writer.WriteRTP(&rtp.Packet{Payload: []byte{}})) 245 } 246 247 func TestIVFWriter_Errors(t *testing.T) { 248 // Creating a Writer with AV1 and VP8 249 _, err := NewWith(&bytes.Buffer{}, WithCodec(mimeTypeAV1), WithCodec(mimeTypeAV1)) 250 assert.ErrorIs(t, err, errCodecAlreadySet) 251 252 // Creating a Writer with Invalid Codec 253 _, err = NewWith(&bytes.Buffer{}, WithCodec("")) 254 assert.ErrorIs(t, err, errNoSuchCodec) 255 } 256 257 func TestIVFWriter_AV1(t *testing.T) { 258 t.Run("Unfragmented", func(t *testing.T) { 259 buffer := &bytes.Buffer{} 260 261 expectedTimestamp := uint32(3653407706) 262 263 // the timestamp is an uint32, 4 bytes from offset 36 264 expectedPayloadWithTimestamp := []byte{ 265 0x44, 0x4b, 0x49, 0x46, 0x0, 0x0, 0x20, 266 0x0, 0x41, 0x56, 0x30, 0x31, 0x80, 0x2, 267 0xe0, 0x1, 0x1e, 0x0, 0x0, 0x0, 0x1, 0x0, 268 0x0, 0x0, 0x84, 0x3, 0x0, 0x0, 0x0, 0x0, 269 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xda, 0x93, 0xc2, 270 0xd9, 0x0, 0x0, 0x0, 0x0, 0xff, 271 } 272 273 writer, err := NewWith(buffer, WithCodec(mimeTypeAV1)) 274 assert.NoError(t, err) 275 276 assert.NoError(t, writer.WriteRTP(&rtp.Packet{Header: rtp.Header{Timestamp: expectedTimestamp}, Payload: []byte{0x00, 0x01, 0xFF}})) 277 assert.NoError(t, writer.Close()) 278 assert.Equal(t, expectedPayloadWithTimestamp, buffer.Bytes()) 279 assert.Equal(t, expectedTimestamp, binary.LittleEndian.Uint32(expectedPayloadWithTimestamp[36:40])) 280 }) 281 282 t.Run("Fragmented", func(t *testing.T) { 283 buffer := &bytes.Buffer{} 284 285 writer, err := NewWith(buffer, WithCodec(mimeTypeAV1)) 286 assert.NoError(t, err) 287 288 for _, p := range [][]byte{{0x40, 0x02, 0x00, 0x01}, {0xc0, 0x02, 0x02, 0x03}, {0xc0, 0x02, 0x04, 0x04}} { 289 assert.NoError(t, writer.WriteRTP(&rtp.Packet{Payload: p})) 290 assert.Equal(t, buffer.Bytes(), []byte{ 291 0x44, 0x4b, 0x49, 0x46, 0x0, 292 0x0, 0x20, 0x0, 0x41, 0x56, 0x30, 293 0x31, 0x80, 0x2, 0xe0, 0x1, 0x1e, 294 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 295 0x0, 0x84, 0x3, 0x0, 0x0, 0x0, 0x0, 296 0x0, 0x0, 297 }) 298 } 299 assert.NoError(t, writer.WriteRTP(&rtp.Packet{Payload: []byte{0x80, 0x01, 0x05}})) 300 assert.Equal(t, buffer.Bytes(), []byte{ 301 0x44, 0x4b, 0x49, 0x46, 0x0, 0x0, 0x20, 0x0, 0x41, 0x56, 0x30, 0x31, 0x80, 302 0x2, 0xe0, 0x1, 0x1e, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x84, 0x3, 0x0, 0x0, 303 0x0, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 304 0x0, 0x1, 0x2, 0x3, 0x4, 0x4, 0x5, 305 }) 306 assert.NoError(t, writer.Close()) 307 }) 308 }