github.com/bluenviron/mediacommon@v1.9.3/pkg/formats/fmp4/parts_test.go (about)

     1  package fmp4
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  
     7  	"github.com/bluenviron/mediacommon/pkg/formats/fmp4/seekablebuffer"
     8  	"github.com/stretchr/testify/require"
     9  )
    10  
    11  var casesParts = []struct {
    12  	name  string
    13  	parts Parts
    14  	enc   []byte
    15  }{
    16  	{
    17  		"single part",
    18  		Parts{{
    19  			SequenceNumber: 4,
    20  			Tracks: []*PartTrack{
    21  				{
    22  					ID:       256,
    23  					BaseTime: 90000,
    24  					Samples: []*PartSample{
    25  						{
    26  							Duration:        30,
    27  							PTSOffset:       0,
    28  							IsNonSyncSample: false,
    29  							Payload:         []byte{1, 2},
    30  						},
    31  						{
    32  							Duration:        60,
    33  							PTSOffset:       15,
    34  							IsNonSyncSample: true,
    35  							Payload:         []byte{3, 4},
    36  						},
    37  					},
    38  				},
    39  				{
    40  					ID:       257,
    41  					BaseTime: 44100,
    42  					Samples: []*PartSample{
    43  						{
    44  							Duration: 30,
    45  							Payload:  []byte{5, 6},
    46  						},
    47  						{
    48  							Duration: 30,
    49  							Payload:  []byte{7, 8},
    50  						},
    51  					},
    52  				},
    53  			},
    54  		}},
    55  		[]byte{
    56  			0x00, 0x00, 0x00, 0xc8, 0x6d, 0x6f, 0x6f, 0x66,
    57  			0x00, 0x00, 0x00, 0x10, 0x6d, 0x66, 0x68, 0x64,
    58  			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
    59  			0x00, 0x00, 0x00, 0x60, 0x74, 0x72, 0x61, 0x66,
    60  			0x00, 0x00, 0x00, 0x10, 0x74, 0x66, 0x68, 0x64,
    61  			0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
    62  			0x00, 0x00, 0x00, 0x14, 0x74, 0x66, 0x64, 0x74,
    63  			0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    64  			0x00, 0x01, 0x5f, 0x90, 0x00, 0x00, 0x00, 0x34,
    65  			0x74, 0x72, 0x75, 0x6e, 0x01, 0x00, 0x0f, 0x01,
    66  			0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xd0,
    67  			0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02,
    68  			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    69  			0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x02,
    70  			0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f,
    71  			0x00, 0x00, 0x00, 0x50, 0x74, 0x72, 0x61, 0x66,
    72  			0x00, 0x00, 0x00, 0x10, 0x74, 0x66, 0x68, 0x64,
    73  			0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
    74  			0x00, 0x00, 0x00, 0x14, 0x74, 0x66, 0x64, 0x74,
    75  			0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    76  			0x00, 0x00, 0xac, 0x44, 0x00, 0x00, 0x00, 0x24,
    77  			0x74, 0x72, 0x75, 0x6e, 0x01, 0x00, 0x03, 0x01,
    78  			0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xd4,
    79  			0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02,
    80  			0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02,
    81  			0x00, 0x00, 0x00, 0x10, 0x6d, 0x64, 0x61, 0x74,
    82  			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
    83  		},
    84  	},
    85  	{
    86  		"concatenated parts",
    87  		Parts{
    88  			{
    89  				SequenceNumber: 4,
    90  				Tracks: []*PartTrack{
    91  					{
    92  						ID:       100,
    93  						BaseTime: 90000,
    94  						Samples: []*PartSample{
    95  							{
    96  								Duration:        30,
    97  								PTSOffset:       0,
    98  								IsNonSyncSample: false,
    99  								Payload:         []byte{1, 2},
   100  							},
   101  						},
   102  					},
   103  				},
   104  			},
   105  			{
   106  				SequenceNumber: 4,
   107  				Tracks: []*PartTrack{
   108  					{
   109  						ID:       100,
   110  						BaseTime: 180000,
   111  						Samples: []*PartSample{
   112  							{
   113  								Duration:        30,
   114  								PTSOffset:       0,
   115  								IsNonSyncSample: false,
   116  								Payload:         []byte{3, 4},
   117  							},
   118  						},
   119  					},
   120  				},
   121  			},
   122  		},
   123  		[]byte{
   124  			0x00, 0x00, 0x00, 0x60, 0x6d, 0x6f, 0x6f, 0x66,
   125  			0x00, 0x00, 0x00, 0x10, 0x6d, 0x66, 0x68, 0x64,
   126  			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
   127  			0x00, 0x00, 0x00, 0x48, 0x74, 0x72, 0x61, 0x66,
   128  			0x00, 0x00, 0x00, 0x10, 0x74, 0x66, 0x68, 0x64,
   129  			0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64,
   130  			0x00, 0x00, 0x00, 0x14, 0x74, 0x66, 0x64, 0x74,
   131  			0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   132  			0x00, 0x01, 0x5f, 0x90, 0x00, 0x00, 0x00, 0x1c,
   133  			0x74, 0x72, 0x75, 0x6e, 0x01, 0x00, 0x03, 0x01,
   134  			0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x68,
   135  			0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02,
   136  			0x00, 0x00, 0x00, 0x0a, 0x6d, 0x64, 0x61, 0x74,
   137  			0x01, 0x02, 0x00, 0x00, 0x00, 0x60, 0x6d, 0x6f,
   138  			0x6f, 0x66, 0x00, 0x00, 0x00, 0x10, 0x6d, 0x66,
   139  			0x68, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   140  			0x00, 0x04, 0x00, 0x00, 0x00, 0x48, 0x74, 0x72,
   141  			0x61, 0x66, 0x00, 0x00, 0x00, 0x10, 0x74, 0x66,
   142  			0x68, 0x64, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
   143  			0x00, 0x64, 0x00, 0x00, 0x00, 0x14, 0x74, 0x66,
   144  			0x64, 0x74, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
   145  			0x00, 0x00, 0x00, 0x02, 0xbf, 0x20, 0x00, 0x00,
   146  			0x00, 0x1c, 0x74, 0x72, 0x75, 0x6e, 0x01, 0x00,
   147  			0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
   148  			0x00, 0x68, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
   149  			0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x6d, 0x64,
   150  			0x61, 0x74, 0x03, 0x04,
   151  		},
   152  	},
   153  }
   154  
   155  func TestPartsMarshal(t *testing.T) {
   156  	for _, ca := range casesParts {
   157  		t.Run(ca.name, func(t *testing.T) {
   158  			var buf seekablebuffer.Buffer
   159  			err := ca.parts.Marshal(&buf)
   160  			require.NoError(t, err)
   161  			require.Equal(t, ca.enc, buf.Bytes())
   162  		})
   163  	}
   164  }
   165  
   166  func TestPartsUnmarshal(t *testing.T) {
   167  	for _, ca := range casesParts {
   168  		t.Run(ca.name, func(t *testing.T) {
   169  			var parts Parts
   170  			err := parts.Unmarshal(ca.enc)
   171  			require.NoError(t, err)
   172  			require.Equal(t, ca.parts, parts)
   173  		})
   174  	}
   175  }
   176  
   177  func FuzzPartsUnmarshal(f *testing.F) {
   178  	for _, ca := range casesParts {
   179  		f.Add(ca.enc)
   180  	}
   181  
   182  	f.Fuzz(func(_ *testing.T, b []byte) {
   183  		var parts Parts
   184  		parts.Unmarshal(b) //nolint:errcheck
   185  	})
   186  }
   187  
   188  func BenchmarkPartsUnmarshal(b *testing.B) {
   189  	for i := 0; i < b.N; i++ {
   190  		for _, ca := range casesParts {
   191  			var parts Parts
   192  			parts.Unmarshal(ca.enc) //nolint:errcheck
   193  		}
   194  	}
   195  }
   196  
   197  func BenchmarkPartsMarshal(b *testing.B) {
   198  	parts := Parts{{
   199  		Tracks: []*PartTrack{{
   200  			ID:      1,
   201  			Samples: make([]*PartSample, 10000),
   202  		}},
   203  	}}
   204  
   205  	for i := 0; i < 10000; i++ {
   206  		parts[0].Tracks[0].Samples[i] = &PartSample{
   207  			Duration: 90000,
   208  			Payload:  bytes.Repeat([]byte{1}, 16),
   209  		}
   210  	}
   211  
   212  	for i := 0; i < b.N; i++ {
   213  		var buf seekablebuffer.Buffer
   214  		parts.Marshal(&buf) //nolint:errcheck
   215  	}
   216  }