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  }