mpeg-ts: speed up initialization

stop scanning for parameters that are not strictly necessary for track
identification.
This commit is contained in:
aler9
2026-02-15 13:31:48 +01:00
parent 367141b8a9
commit 127fe27890
10 changed files with 212 additions and 207 deletions
+2 -2
View File
@@ -36,7 +36,7 @@ Go ≥ 1.24 is required.
|ISO 14496-1, Coding of audio-visual objects, Part 1, Systems|formats / fMP4|
|ISO 14496-12, Coding of audio-visual objects, Part 12, ISO base media file format|formats / fMP4|
|ISO 14496-14, Coding of audio-visual objects, Part 14, MP4 file format|formats / fMP4|
|ISO 14496-15, Coding of audio-visual objects, Part 15, Advanced Video Coding (AVC) file format|formats / fMP4 + H264 / H265|
|ISO 14496-15, Coding of audio-visual objects, Part 15, Advanced Video Coding (AVC) file format|formats / fMP4 + H264, H265|
|[VP9 Codec ISO Media File Format Binding](https://www.webmproject.org/vp9/mp4/)|formats / fMP4 + VP9|
|[AV1 Codec ISO Media File Format Binding](https://aomediacodec.github.io/av1-isobmff)|formats / fMP4 + AV1|
|[Opus in MP4/ISOBMFF](https://opus-codec.org/docs/opus_in_isobmff.html)|formats / fMP4 + Opus|
@@ -45,7 +45,7 @@ Go ≥ 1.24 is required.
|[ETSI TS Opus 0.1.3-draft, Opus Interactive Audio Codec Transport Multiplexing Standard](https://opus-codec.org/docs/ETSI_TS_opus-v0.1.3-draft.pdf)|formats / MPEG-TS + Opus|
|[MISB ST 1402, MPEG-2 Transport Stream for Class 1/Class 2 Motion Imagery, Audio and Metadata](https://nsgreg.nga.mil/doc/view?i=4273)|formats / MPEG-TS + KLV|
|[ETSI EN 300 743, Digital Video Broadcasting (DVB), Subtitling systems](https://www.etsi.org/deliver/etsi_en/300700_300799/300743/01.06.01_20/en_300743v010601a.pdf)|formats / MPEG-TS + DVB subtitles|
|[ETSI EN 300 468, Digital Video Broadcasting (DVB), Specification for Service Information (SI) in DVB systems](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.17.01_20/en_300468v011701a.pdf)|formats / MPEG-TS + DVB subtitles|
|[ETSI EN 300 468, Digital Video Broadcasting (DVB), Specification for Service Information (SI) in DVB systems](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.17.01_20/en_300468v011701a.pdf)|formats / MPEG-TS + DVB subtitles, AC-3, E-AC-3|
## Related projects
+18 -1
View File
@@ -2,8 +2,25 @@ package codecs
// AC3 is an AC-3 codec.
// Specification: ISO 13818-1
// Specification: ETSI EN 300 468
type AC3 struct {
SampleRate int
// Full service flag.
FullService bool
// Channels coding.
// 0=1-2ch
// 1=mono
// 2=2ch stereo
// 3=2ch surround
// 4=multichannel mono
// 5=multichannel stereo
// 6=multichannel surround
ChannelsCoding uint8
// Deprecated: not filled and not used anymore.
SampleRate int
// Deprecated: not filled and not used anymore.
ChannelCount int
}
+18 -1
View File
@@ -2,8 +2,25 @@ package codecs
// EAC3 is an Enhanced AC-3 (Dolby Digital Plus) codec.
// Specification: ETSI TS 102 366 V1.4.1, Annex E
// Specification: ETSI EN 300 468
type EAC3 struct {
SampleRate int
// Full service flag.
FullService bool
// Channels coding.
// 0=1-2ch
// 1=mono
// 2=2ch stereo
// 3=2ch surround
// 4=multichannel mono
// 5=multichannel stereo
// 6=multichannel surround
ChannelsCoding uint8
// Deprecated: not filled anymore.
SampleRate int
// Deprecated: not filled anymore.
ChannelCount int
}
+1
View File
@@ -7,6 +7,7 @@ import (
// MPEG4Audio is a MPEG-4 Audio codec.
// Specification: ISO 13818-1
type MPEG4Audio struct {
// Deprecated: not filled anymore.
mpeg4audio.Config
}
+27 -1
View File
@@ -32,8 +32,13 @@ type ReaderOnDataMPEGxVideoFunc func(pts int64, frame []byte) error
type ReaderOnDataOpusFunc func(pts int64, packets [][]byte) error
// ReaderOnDataMPEG4AudioFunc is the prototype of the callback passed to OnDataMPEG4Audio.
//
// Deprecated: replaced by ReaderOnDataMPEG4Audio2Func.
type ReaderOnDataMPEG4AudioFunc func(pts int64, aus [][]byte) error
// ReaderOnDataMPEG4Audio2Func is the prototype of the callback passed to OnDataMPEG4Audio2.
type ReaderOnDataMPEG4Audio2Func func(pts int64, packets mpeg4audio.ADTSPackets) error
// ReaderOnDataMPEG4AudioLATMFunc is the prototype of the callback passed to OnDataMPEG4AudioLATM.
type ReaderOnDataMPEG4AudioLATMFunc func(pts int64, els [][]byte) error
@@ -205,7 +210,7 @@ func (r *Reader) Initialize() error {
for i, es := range pmt.ElementaryStreams {
var track Track
err = track.unmarshal(dem, es)
err = track.unmarshal(es)
if err != nil {
return err
}
@@ -331,6 +336,8 @@ func (r *Reader) OnDataOpus(track *Track, cb ReaderOnDataOpusFunc) {
}
// OnDataMPEG4Audio sets a callback that is called when data from an MPEG-4 Audio track is received.
//
// Deprecated: replaced by OnDataMPEG4Audio2.
func (r *Reader) OnDataMPEG4Audio(track *Track, cb ReaderOnDataMPEG4AudioFunc) {
r.onData[track.PID] = func(pts int64, dts int64, data []byte) error {
if pts != dts {
@@ -354,6 +361,25 @@ func (r *Reader) OnDataMPEG4Audio(track *Track, cb ReaderOnDataMPEG4AudioFunc) {
}
}
// OnDataMPEG4Audio2 sets a callback that is called when data from an MPEG-4 Audio track is received.
func (r *Reader) OnDataMPEG4Audio2(track *Track, cb ReaderOnDataMPEG4Audio2Func) {
r.onData[track.PID] = func(pts int64, dts int64, data []byte) error {
if pts != dts {
r.onDecodeError(fmt.Errorf("PTS is not equal to DTS"))
return nil
}
var pkts mpeg4audio.ADTSPackets
err := pkts.Unmarshal(data)
if err != nil {
r.onDecodeError(fmt.Errorf("invalid ADTS: %w", err))
return nil
}
return cb(pts, pkts)
}
}
// OnDataMPEG4AudioLATM sets a callback that is called when data from an MPEG-4 Audio LATM track is received.
func (r *Reader) OnDataMPEG4AudioLATM(track *Track, cb ReaderOnDataMPEG4AudioLATMFunc) {
r.onData[track.PID] = func(pts int64, dts int64, data []byte) error {
+40 -32
View File
@@ -41,7 +41,7 @@ var testH264SPS = []byte{
type sample struct {
pts int64
dts int64
data [][]byte
data any
}
var casesReadWriter = []struct {
@@ -255,7 +255,7 @@ var casesReadWriter = []struct {
{
30 * 90000,
30 * 90000,
[][]byte{{0, 0, 1, 0xb3}},
[]byte{0, 0, 1, 0xb3},
},
},
[]*astits.Packet{
@@ -315,7 +315,7 @@ var casesReadWriter = []struct {
{
30 * 90000,
30 * 90000,
[][]byte{{0, 0, 1, 0xb8, 1, 2, 3, 4}},
[]byte{0, 0, 1, 0xb8, 1, 2, 3, 4},
},
},
[]*astits.Packet{
@@ -482,21 +482,29 @@ var casesReadWriter = []struct {
{
"mpeg-4 audio",
&Track{
PID: 257,
Codec: &codecs.MPEG4Audio{
Config: mpeg4audio.AudioSpecificConfig{
Type: 2,
SampleRate: 48000,
ChannelConfig: 2,
ChannelCount: 2,
},
},
PID: 257,
Codec: &codecs.MPEG4Audio{},
},
[]sample{
{
30 * 90000,
30 * 90000,
[][]byte{{3}, {2}},
mpeg4audio.ADTSPackets{
{
Type: 2,
SampleRate: 48000,
ChannelConfig: 2,
ChannelCount: 2,
AU: []byte{3},
},
{
Type: 2,
SampleRate: 48000,
ChannelConfig: 2,
ChannelCount: 2,
AU: []byte{2},
},
},
},
},
[]*astits.Packet{
@@ -739,15 +747,15 @@ var casesReadWriter = []struct {
&Track{
PID: 257,
Codec: &codecs.AC3{
SampleRate: 48000,
ChannelCount: 1,
FullService: true,
ChannelsCoding: 2,
},
},
[]sample{
{
30 * 90000,
30 * 90000,
[][]byte{{
[]byte{
0x0b, 0x77, 0x47, 0x11, 0x0c, 0x40, 0x2f, 0x84,
0x2b, 0xc1, 0x07, 0x7a, 0xb0, 0xfa, 0xbb, 0xea,
0xef, 0x9f, 0x57, 0x7c, 0xf9, 0xf3, 0xf7, 0xcf,
@@ -796,7 +804,7 @@ var casesReadWriter = []struct {
0x9e, 0x8e, 0x04, 0x02, 0xae, 0x65, 0x87, 0x5c,
0x4e, 0x72, 0xfd, 0x3c, 0x01, 0x86, 0xfe, 0x56,
0x59, 0x74, 0x44, 0x3a, 0x40, 0x00, 0xec, 0xfc,
}},
},
},
},
[]*astits.Packet{
@@ -926,8 +934,8 @@ var casesReadWriter = []struct {
&Track{
PID: 257,
Codec: &codecs.EAC3{
SampleRate: 48000,
ChannelCount: 2,
FullService: true,
ChannelsCoding: 2,
},
},
[]sample{
@@ -938,9 +946,9 @@ var casesReadWriter = []struct {
// strmtyp=0, substreamid=0, frmsiz=63 (128 bytes)
// fscod=0 (48kHz), numblkscod=3 (6 blocks)
// acmod=2 (stereo), lfeon=0, bsid=16
[][]byte{append([]byte{
append([]byte{
0x0b, 0x77, 0x00, 0x3f, 0x34, 0x80,
}, bytes.Repeat([]byte{0x00}, 122)...)},
}, bytes.Repeat([]byte{0x00}, 122)...),
},
},
[]*astits.Packet{
@@ -1008,7 +1016,7 @@ var casesReadWriter = []struct {
{
30 * 90000,
30 * 90000,
[][]byte{{1, 2, 3}},
[]byte{1, 2, 3},
},
},
[]*astits.Packet{
@@ -1086,7 +1094,7 @@ var casesReadWriter = []struct {
{
30 * 90000,
30 * 90000,
[][]byte{{1, 2, 3}},
[]byte{1, 2, 3},
},
},
[]*astits.Packet{
@@ -1179,7 +1187,7 @@ func TestReader(t *testing.T) {
case *codecs.MPEG4Video:
r.OnDataMPEGxVideo(ca.track, func(pts int64, frame []byte) error {
require.Equal(t, ca.samples[i].pts, pts)
require.Equal(t, ca.samples[i].data[0], frame)
require.Equal(t, ca.samples[i].data.([]byte), frame)
i++
return nil
})
@@ -1187,7 +1195,7 @@ func TestReader(t *testing.T) {
case *codecs.MPEG1Video:
r.OnDataMPEGxVideo(ca.track, func(pts int64, frame []byte) error {
require.Equal(t, ca.samples[i].pts, pts)
require.Equal(t, ca.samples[i].data[0], frame)
require.Equal(t, ca.samples[i].data.([]byte), frame)
i++
return nil
})
@@ -1201,9 +1209,9 @@ func TestReader(t *testing.T) {
})
case *codecs.MPEG4Audio:
r.OnDataMPEG4Audio(ca.track, func(pts int64, aus [][]byte) error {
r.OnDataMPEG4Audio2(ca.track, func(pts int64, packets mpeg4audio.ADTSPackets) error {
require.Equal(t, ca.samples[i].pts, pts)
require.Equal(t, ca.samples[i].data, aus)
require.Equal(t, ca.samples[i].data.(mpeg4audio.ADTSPackets), packets)
i++
return nil
})
@@ -1227,7 +1235,7 @@ func TestReader(t *testing.T) {
case *codecs.AC3:
r.OnDataAC3(ca.track, func(pts int64, frame []byte) error {
require.Equal(t, ca.samples[i].pts, pts)
require.Equal(t, ca.samples[i].data[0], frame)
require.Equal(t, ca.samples[i].data.([]byte), frame)
i++
return nil
})
@@ -1235,7 +1243,7 @@ func TestReader(t *testing.T) {
case *codecs.EAC3:
r.OnDataEAC3(ca.track, func(pts int64, frame []byte) error {
require.Equal(t, ca.samples[i].pts, pts)
require.Equal(t, ca.samples[i].data[0], frame)
require.Equal(t, ca.samples[i].data.([]byte), frame)
i++
return nil
})
@@ -1243,7 +1251,7 @@ func TestReader(t *testing.T) {
case *codecs.KLV:
r.OnDataKLV(ca.track, func(pts int64, frame []byte) error {
require.Equal(t, ca.samples[i].pts, pts)
require.Equal(t, ca.samples[i].data[0], frame)
require.Equal(t, ca.samples[i].data.([]byte), frame)
i++
return nil
})
@@ -1251,7 +1259,7 @@ func TestReader(t *testing.T) {
case *codecs.DVBSubtitle:
r.OnDataDVBSubtitle(ca.track, func(pts int64, data []byte) error {
require.Equal(t, ca.samples[i].pts, pts)
require.Equal(t, ca.samples[i].data[0], data)
require.Equal(t, ca.samples[i].data.([]byte), data)
i++
return nil
})
@@ -1663,7 +1671,7 @@ func TestReaderDecodeErrors(t *testing.T) {
})
case "mpeg-4 audio pts != dts", "mpeg-4 audio invalid":
r.OnDataMPEG4Audio(r.Tracks()[0], func(_ int64, _ [][]byte) error {
r.OnDataMPEG4Audio2(r.Tracks()[0], func(_ int64, _ mpeg4audio.ADTSPackets) error {
return nil
})
+74 -147
View File
@@ -4,9 +4,6 @@ import (
"fmt"
"github.com/asticode/go-astits"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/ac3"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/eac3"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/mpeg4audio"
"github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts/codecs"
)
@@ -23,79 +20,29 @@ const (
metadataApplicationFormatStillImageOnDemand = 0x0103
)
func findMPEG4AudioConfig(dem *robustDemuxer, pid uint16) (*mpeg4audio.AudioSpecificConfig, error) {
for {
data, err := dem.nextData()
if err != nil {
return nil, err
}
if data.PES == nil || data.PID != pid {
continue
}
var adtsPkts mpeg4audio.ADTSPackets
err = adtsPkts.Unmarshal(data.PES.Data)
if err != nil {
return nil, fmt.Errorf("unable to decode ADTS: %w", err)
}
pkt := adtsPkts[0]
return &mpeg4audio.AudioSpecificConfig{
Type: pkt.Type,
SampleRate: pkt.SampleRate,
ChannelConfig: pkt.ChannelConfig,
ChannelCount: pkt.ChannelCount, //nolint:staticcheck
}, nil
func boolToUint8(v bool) uint8 {
if v {
return 1
}
return 0
}
func findAC3Parameters(dem *robustDemuxer, pid uint16) (int, int, error) {
for {
data, err := dem.nextData()
if err != nil {
return 0, 0, err
func findAC3Descriptor(descriptors []*astits.Descriptor) *astits.DescriptorAC3 {
for _, sd := range descriptors {
if sd.Tag == astits.DescriptorTagAC3 && sd.AC3 != nil {
return sd.AC3
}
if data.PES == nil || data.PID != pid {
continue
}
var syncInfo ac3.SyncInfo
err = syncInfo.Unmarshal(data.PES.Data)
if err != nil {
return 0, 0, fmt.Errorf("invalid AC-3 frame: %w", err)
}
var bsi ac3.BSI
err = bsi.Unmarshal(data.PES.Data[5:])
if err != nil {
return 0, 0, fmt.Errorf("invalid AC-3 frame: %w", err)
}
return syncInfo.SampleRate(), bsi.ChannelCount(), nil
}
return nil
}
func findEAC3Parameters(dem *robustDemuxer, pid uint16) (int, int, error) {
for {
data, err := dem.nextData()
if err != nil {
return 0, 0, err
func findEAC3Descriptor(descriptors []*astits.Descriptor) *astits.DescriptorEnhancedAC3 {
for _, sd := range descriptors {
if sd.Tag == astits.DescriptorTagEnhancedAC3 && sd.EnhancedAC3 != nil {
return sd.EnhancedAC3
}
if data.PES == nil || data.PID != pid {
continue
}
var syncInfo eac3.SyncInfo
err = syncInfo.Unmarshal(data.PES.Data)
if err != nil {
return 0, 0, fmt.Errorf("invalid E-AC-3 frame: %w", err)
}
return syncInfo.SampleRate(), syncInfo.ChannelCount(), nil
}
return nil
}
func findRegistrationIdentifier(descriptors []*astits.Descriptor) (uint32, bool) {
@@ -161,7 +108,7 @@ func findOpusChannelCount(descriptors []*astits.Descriptor) int {
return 0
}
func findCodec(dem *robustDemuxer, es *astits.PMTElementaryStream) (codecs.Codec, error) {
func findCodec(es *astits.PMTElementaryStream) (codecs.Codec, error) {
switch es.StreamType {
// video
@@ -180,14 +127,7 @@ func findCodec(dem *robustDemuxer, es *astits.PMTElementaryStream) (codecs.Codec
// audio
case astits.StreamTypeAACAudio:
conf, err := findMPEG4AudioConfig(dem, es.ElementaryPID)
if err != nil {
return nil, err
}
return &codecs.MPEG4Audio{
Config: *conf,
}, nil
return &codecs.MPEG4Audio{}, nil
case astits.StreamTypeAACLATMAudio:
return &codecs.MPEG4AudioLATM{}, nil
@@ -196,25 +136,33 @@ func findCodec(dem *robustDemuxer, es *astits.PMTElementaryStream) (codecs.Codec
return &codecs.MPEG1Audio{}, nil
case astits.StreamTypeAC3Audio:
sampleRate, channelCount, err := findAC3Parameters(dem, es.ElementaryPID)
if err != nil {
return nil, err
var fullService bool
var channelCoding uint8
desc := findAC3Descriptor(es.ElementaryStreamDescriptors)
if desc != nil {
fullService = (desc.ComponentType & 0b1) != 0
channelCoding = (desc.ComponentType >> 1) & 0b111
}
return &codecs.AC3{
SampleRate: sampleRate,
ChannelCount: channelCount,
FullService: fullService,
ChannelsCoding: channelCoding,
}, nil
case astits.StreamTypeEAC3Audio:
sampleRate, channelCount, err := findEAC3Parameters(dem, es.ElementaryPID)
if err != nil {
return nil, err
var fullService bool
var channelCoding uint8
desc := findEAC3Descriptor(es.ElementaryStreamDescriptors)
if desc != nil {
fullService = (desc.ComponentType & 0b1) != 0
channelCoding = (desc.ComponentType >> 1) & 0b111
}
return &codecs.EAC3{
SampleRate: sampleRate,
ChannelCount: channelCount,
FullService: fullService,
ChannelsCoding: channelCoding,
}, nil
// other
@@ -255,63 +203,6 @@ func findCodec(dem *robustDemuxer, es *astits.PMTElementaryStream) (codecs.Codec
return &codecs.Unsupported{}, nil
}
// ac3ComponentType builds the DVB component_type byte for AC-3.
// Per ETSI EN 300 468, the AC3 descriptor uses a similar format to E-AC-3.
func ac3ComponentType(channels int, fullService bool) uint8 {
var ct uint8
// Set full_service_flag (bit 0)
if fullService {
ct |= 0x01
}
// Encode channel configuration in bits 3-1
switch {
case channels <= 2:
ct |= (0x02 << 1) // 2ch stereo
case channels <= 4:
ct |= (0x05 << 1) // multichannel stereo
default:
ct |= (0x06 << 1) // multichannel surround (5.1, etc.)
}
return ct
}
// componentTypeFromConfig builds the DVB component_type byte.
// Per ETSI EN 300 468, table D.1:
// Bits 7-4: service_type_flag (0=complete main, 1=music/effects, etc.)
// Bits 3-1: number_of_channels mapping
// Bit 0: full_service_flag
//
// For E-AC-3, the component_type encodes channel configuration:
//
// 0x00-0x3F: Full service, complete main
// Bits 2-0 encode channel config: 0=mono/stereo, 1=mono, 2=stereo, 3=2ch, etc.
func eac3ComponentType(channels int, fullService bool) uint8 {
// Start with full service, complete main audio (bits 7-4 = 0000)
var ct uint8
// Set full_service_flag (bit 0)
if fullService {
ct |= 0x01
}
// Encode channel configuration in bits 3-1 (number_of_channels)
// Per EN 300 468: 0=1-2ch, 1=mono, 2=2ch stereo, 3=2ch surround,
// 4=multichannel mono, 5=multichannel stereo, 6=multichannel surround
switch {
case channels <= 2:
ct |= (0x02 << 1) // 2ch stereo
case channels <= 4:
ct |= (0x05 << 1) // multichannel stereo
default:
ct |= (0x06 << 1) // multichannel surround (5.1, 7.1, etc.)
}
return ct
}
// Track is a MPEG-TS track.
type Track struct {
PID uint16
@@ -380,6 +271,24 @@ func (t Track) marshal() (*astits.PMTElementaryStream, error) {
}, nil
case *codecs.AC3:
var componentType uint8
if c.ChannelCount != 0 { //nolint:staticcheck
var channelCoding uint8
switch c.ChannelCount { //nolint:staticcheck
case 1:
channelCoding = 1
case 2:
channelCoding = 2
case 3, 4:
channelCoding = 5
default:
channelCoding = 6
}
componentType = channelCoding<<1 | boolToUint8(c.FullService)
} else {
componentType = c.ChannelsCoding&0b111<<1 | boolToUint8(c.FullService)
}
return &astits.PMTElementaryStream{
ElementaryPID: t.PID,
StreamType: astits.StreamTypeAC3Audio,
@@ -391,7 +300,7 @@ func (t Track) marshal() (*astits.PMTElementaryStream, error) {
Tag: astits.DescriptorTagAC3,
AC3: &astits.DescriptorAC3{
HasComponentType: true,
ComponentType: ac3ComponentType(c.ChannelCount, true),
ComponentType: componentType,
// BSID for standard AC-3 (not E-AC-3)
HasBSID: true,
BSID: 8,
@@ -401,6 +310,24 @@ func (t Track) marshal() (*astits.PMTElementaryStream, error) {
}, nil
case *codecs.EAC3:
var componentType uint8
if c.ChannelCount != 0 { //nolint:staticcheck
var channelCoding uint8
switch c.ChannelCount { //nolint:staticcheck
case 1:
channelCoding = 1
case 2:
channelCoding = 2
case 3, 4:
channelCoding = 5
default:
channelCoding = 6
}
componentType = channelCoding<<1 | boolToUint8(c.FullService)
} else {
componentType = c.ChannelsCoding&0b111<<1 | boolToUint8(c.FullService)
}
return &astits.PMTElementaryStream{
ElementaryPID: t.PID,
StreamType: astits.StreamTypeEAC3Audio,
@@ -412,7 +339,7 @@ func (t Track) marshal() (*astits.PMTElementaryStream, error) {
Tag: astits.DescriptorTagEnhancedAC3,
EnhancedAC3: &astits.DescriptorEnhancedAC3{
HasComponentType: true,
ComponentType: eac3ComponentType(c.ChannelCount, true),
ComponentType: componentType,
// BSID=16 indicates E-AC-3
HasBSID: true,
BSID: 16,
@@ -528,10 +455,10 @@ func (t Track) marshal() (*astits.PMTElementaryStream, error) {
}
}
func (t *Track) unmarshal(dem *robustDemuxer, es *astits.PMTElementaryStream) error {
func (t *Track) unmarshal(es *astits.PMTElementaryStream) error {
t.PID = es.ElementaryPID
codec, err := findCodec(dem, es)
codec, err := findCodec(es)
if err != nil {
return err
}
+3 -11
View File
@@ -7,7 +7,6 @@ import (
"github.com/stretchr/testify/require"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/mpeg4audio"
"github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts/codecs"
)
@@ -623,15 +622,8 @@ func TestTrackUnmarshalExternal(t *testing.T) {
0x00, 0x00, 0x00, 0x38,
},
&Track{
PID: 256,
Codec: &codecs.MPEG4Audio{
Config: mpeg4audio.AudioSpecificConfig{
Type: 2,
SampleRate: 48000,
ChannelConfig: 2,
ChannelCount: 2,
},
},
PID: 256,
Codec: &codecs.MPEG4Audio{},
},
},
{
@@ -702,7 +694,7 @@ func TestTrackUnmarshalExternal(t *testing.T) {
require.NoError(t, err)
var track Track
err = track.unmarshal(dem, pmt.ElementaryStreams[0])
err = track.unmarshal(pmt.ElementaryStreams[0])
require.NoError(t, err)
require.Equal(t, ca.track, &track)
})
+16
View File
@@ -218,6 +218,8 @@ func (w *Writer) WriteOpus(
}
// WriteMPEG4Audio writes MPEG-4 Audio access units.
//
// Deprecated: use WriteMPEG4Audio2.
func (w *Writer) WriteMPEG4Audio(
track *Track,
pts int64,
@@ -245,6 +247,20 @@ func (w *Writer) WriteMPEG4Audio(
return w.writeAudio(track, pts, enc)
}
// WriteMPEG4Audio2 writes MPEG-4 Audio ADTS packets.
func (w *Writer) WriteMPEG4Audio2(
track *Track,
pts int64,
packets mpeg4audio.ADTSPackets,
) error {
enc, err := packets.Marshal()
if err != nil {
return err
}
return w.writeAudio(track, pts, enc)
}
// WriteMPEG4AudioLATM writes MPEG-4 Audio LATM audioMuxElements.
func (w *Writer) WriteMPEG4AudioLATM(
track *Track,
+13 -12
View File
@@ -9,6 +9,7 @@ import (
"testing"
"github.com/asticode/go-astits"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/mpeg4audio"
"github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts/codecs"
"github.com/stretchr/testify/require"
)
@@ -24,40 +25,40 @@ func TestWriter(t *testing.T) {
switch ca.track.Codec.(type) {
case *codecs.H265:
err = w.WriteH265(ca.track, sample.pts, sample.dts, sample.data)
err = w.WriteH265(ca.track, sample.pts, sample.dts, sample.data.([][]byte))
case *codecs.H264:
err = w.WriteH264(ca.track, sample.pts, sample.dts, sample.data)
err = w.WriteH264(ca.track, sample.pts, sample.dts, sample.data.([][]byte))
case *codecs.MPEG4Video:
err = w.WriteMPEG4Video(ca.track, sample.pts, sample.data[0])
err = w.WriteMPEG4Video(ca.track, sample.pts, sample.data.([]byte))
case *codecs.MPEG1Video:
err = w.WriteMPEG1Video(ca.track, sample.pts, sample.data[0])
err = w.WriteMPEG1Video(ca.track, sample.pts, sample.data.([]byte))
case *codecs.Opus:
err = w.WriteOpus(ca.track, sample.pts, sample.data)
err = w.WriteOpus(ca.track, sample.pts, sample.data.([][]byte))
case *codecs.MPEG4Audio:
err = w.WriteMPEG4Audio(ca.track, sample.pts, sample.data)
err = w.WriteMPEG4Audio2(ca.track, sample.pts, sample.data.(mpeg4audio.ADTSPackets))
case *codecs.MPEG4AudioLATM:
err = w.WriteMPEG4AudioLATM(ca.track, sample.pts, sample.data)
err = w.WriteMPEG4AudioLATM(ca.track, sample.pts, sample.data.([][]byte))
case *codecs.MPEG1Audio:
err = w.WriteMPEG1Audio(ca.track, sample.pts, sample.data)
err = w.WriteMPEG1Audio(ca.track, sample.pts, sample.data.([][]byte))
case *codecs.AC3:
err = w.WriteAC3(ca.track, sample.pts, sample.data[0])
err = w.WriteAC3(ca.track, sample.pts, sample.data.([]byte))
case *codecs.EAC3:
err = w.WriteEAC3(ca.track, sample.pts, sample.data[0])
err = w.WriteEAC3(ca.track, sample.pts, sample.data.([]byte))
case *codecs.KLV:
err = w.WriteKLV(ca.track, sample.pts, sample.data[0])
err = w.WriteKLV(ca.track, sample.pts, sample.data.([]byte))
case *codecs.DVBSubtitle:
err = w.WriteDVBSubtitle(ca.track, sample.pts, sample.data[0])
err = w.WriteDVBSubtitle(ca.track, sample.pts, sample.data.([]byte))
default:
panic("unexpected")