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