Skip to content

Commit

Permalink
add opus utilities (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
aler9 authored Jul 26, 2023
1 parent a15745c commit efccece
Show file tree
Hide file tree
Showing 30 changed files with 147 additions and 10 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ Definitions and functions shared between [gortsplib](https://github.com/bluenvir
* [ITU-T Rec. T-871, JPEG File Interchange Format](https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-T.871-201105-I!!PDF-E&type=items)
* [ITU-T Rec. H.264 (08/2021)](https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.264-202108-I!!PDF-E&type=items)
* [ITU-T Rec. H.265 (08/2021)](https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.265-202108-I!!PDF-E&type=items)
* ISO 11172-3, Coding of moving pictures and associated audio
* ISO 13818-3, Generic Coding of Moving Pictures and Associated Audio: Audio
* ISO 14496-3, Coding of audio-visual objects, part 3, Audio
* [AV1 Bitstream & Decoding Process](https://aomediacodec.github.io/av1-spec/av1-spec.pdf)
* [RFC6716, Definition of the Opus Audio Codec](https://datatracker.ietf.org/doc/html/rfc6716)

## Links

Related projects
## Related projects

* [MediaMTX](https://github.com/bluenviron/mediamtx)
* [gortsplib](https://github.com/bluenviron/gortsplib)
Expand Down
1 change: 1 addition & 0 deletions pkg/codecs/av1/bitstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ func obuRemoveSize(h *OBUHeader, sizeN int, ob []byte) []byte {

// BitstreamUnmarshal extracts OBUs from a bitstream.
// Optionally, it also removes the size field from OBUs.
// Specification: https://aomediacodec.github.io/av1-spec/#low-overhead-bitstream-format
func BitstreamUnmarshal(bs []byte, removeSizeField bool) ([][]byte, error) {
var ret [][]byte

Expand Down
28 changes: 28 additions & 0 deletions pkg/codecs/av1/contains_key_frame_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package av1

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestContainsKeyFrame(t *testing.T) {
for _, ca := range []struct {
name string
byts []byte
}{
{
"sequence header",
[]byte{
0x0a, 0x0e, 0x00, 0x00, 0x00, 0x4a, 0xab, 0xbf,
0xc3, 0x77, 0x6b, 0xe4, 0x40, 0x40, 0x40, 0x41,
},
},
} {
t.Run(ca.name, func(t *testing.T) {
ok, err := ContainsKeyFrame([][]byte{ca.byts})
require.NoError(t, err)
require.Equal(t, true, ok)
})
}
}
2 changes: 2 additions & 0 deletions pkg/codecs/av1/leb128.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
)

// LEB128Unmarshal decodes an unsigned integer from the LEB128 format.
// Specification: https://aomediacodec.github.io/av1-spec/#leb128
func LEB128Unmarshal(buf []byte) (uint, int, error) {
v := uint(0)
n := 0
Expand All @@ -30,6 +31,7 @@ func LEB128Unmarshal(buf []byte) (uint, int, error) {
}

// LEB128Marshal encodes an unsigned integer with the LEB128 format.
// Specification: https://aomediacodec.github.io/av1-spec/#leb128
func LEB128Marshal(v uint) []byte {
var out []byte

Expand Down
1 change: 1 addition & 0 deletions pkg/codecs/av1/obu_header.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const (
)

// OBUHeader is a OBU header.
// Specification: https://aomediacodec.github.io/av1-spec/#obu-header-syntax
type OBUHeader struct {
Type OBUType
HasSize bool
Expand Down
2 changes: 1 addition & 1 deletion pkg/codecs/av1/obu_header_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestOBUHeaderUnmarshal(t *testing.T) {
0xc3, 0x77, 0x6b, 0xe4, 0x40, 0x40, 0x40, 0x41,
},
OBUHeader{
Type: 1,
Type: OBUTypeSequenceHeader,
HasSize: true,
},
},
Expand Down
2 changes: 2 additions & 0 deletions pkg/codecs/h264/annexb.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
)

// AnnexBUnmarshal decodes NALUs from the Annex-B stream format.
// Specification: ITU-T Rec. H.264, Annex B
func AnnexBUnmarshal(byts []byte) ([][]byte, error) {
bl := len(byts)
initZeroCount := 0
Expand Down Expand Up @@ -121,6 +122,7 @@ func annexBMarshalSize(nalus [][]byte) int {
}

// AnnexBMarshal encodes NALUs into the Annex-B stream format.
// Specification: ITU-T Rec. H.264, Annex B
func AnnexBMarshal(nalus [][]byte) ([]byte, error) {
buf := make([]byte, annexBMarshalSize(nalus))
pos := 0
Expand Down
2 changes: 2 additions & 0 deletions pkg/codecs/h264/avcc.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
)

// AVCCUnmarshal decodes NALUs from the AVCC stream format.
// Specification: ?
func AVCCUnmarshal(buf []byte) ([][]byte, error) {
bl := len(buf)
pos := 0
Expand Down Expand Up @@ -55,6 +56,7 @@ func avccMarshalSize(nalus [][]byte) int {
}

// AVCCMarshal encodes NALUs into the AVCC stream format.
// Specification: ?
func AVCCMarshal(nalus [][]byte) ([]byte, error) {
buf := make([]byte, avccMarshalSize(nalus))
pos := 0
Expand Down
1 change: 1 addition & 0 deletions pkg/codecs/h264/emulation_prevention.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package h264

// EmulationPreventionRemove removes emulation prevention bytes from a NALU.
// Specification: ITU-T Rec. H.264, 7.4.1 NAL unit semantics
func EmulationPreventionRemove(nalu []byte) []byte {
// 0x00 0x00 0x03 0x00 -> 0x00 0x00 0x00
// 0x00 0x00 0x03 0x01 -> 0x00 0x00 0x01
Expand Down
2 changes: 1 addition & 1 deletion pkg/codecs/h264/idrpresent.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package h264

// IDRPresent check if there's an IDR inside provided NALUs.
// IDRPresent check whether there's an IDR inside provided NALUs.
func IDRPresent(nalus [][]byte) bool {
for _, nalu := range nalus {
typ := NALUType(nalu[0] & 0x1F)
Expand Down
1 change: 1 addition & 0 deletions pkg/codecs/h264/nalu_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
)

// NALUType is the type of a NALU.
// Specification: ITU-T Rec. H.264, Table 7-1
type NALUType uint8

// NALU types.
Expand Down
1 change: 1 addition & 0 deletions pkg/codecs/h264/sps.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ func (c *SPS_FrameCropping) unmarshal(buf []byte, pos *int) error {
}

// SPS is a H264 sequence parameter set.
// Specification: ITU-T Rec. H.264, 7.3.2.1.1
type SPS struct {
ProfileIdc uint8
ConstraintSet0Flag bool
Expand Down
1 change: 1 addition & 0 deletions pkg/codecs/h265/nalu_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
)

// NALUType is the type of a NALU.
// Specification: ITU-T Rec. H.265, Table 7-1
type NALUType uint8

// NALU types.
Expand Down
1 change: 1 addition & 0 deletions pkg/codecs/h265/pps.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
)

// PPS is a H265 picture parameter set.
// Specification: ITU-T Rec. H.265, 7.3.2.3.1
type PPS struct {
ID uint32
SPSID uint32
Expand Down
1 change: 1 addition & 0 deletions pkg/codecs/h265/sps.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ func (r *SPS_ShortTermRefPicSet) unmarshal(buf []byte, pos *int, stRpsIdx uint32
}

// SPS is a H265 sequence parameter set.
// Specification: ITU-T Rec. H.265, 7.3.2.2.1
type SPS struct {
VPSID uint8
MaxSubLayersMinus1 uint8
Expand Down
2 changes: 1 addition & 1 deletion pkg/codecs/jpeg/jpeg.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Package jpeg contains JPEG/JFIF markers.
// Package jpeg contains utilities to work with the JPEG codec.
package jpeg

// standard JPEG markers.
Expand Down
1 change: 1 addition & 0 deletions pkg/codecs/mpeg2audio/frame_header.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const (
)

// FrameHeader is the header of a MPEG-1/2 audio frame.
// Specification: ISO 11172-3, 2.4.1.3
type FrameHeader struct {
MPEG2 bool
Layer uint8
Expand Down
3 changes: 2 additions & 1 deletion pkg/codecs/mpeg4audio/adts.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import (
"fmt"
)

// ADTSPacket is an ADTS frame, as defined in ISO 14496-3.
// ADTSPacket is an ADTS frame.
// Specification: ISO 14496-3, Table 1.A.5
type ADTSPacket struct {
Type ObjectType
SampleRate int
Expand Down
3 changes: 2 additions & 1 deletion pkg/codecs/mpeg4audio/audio_specific_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import (
// Config is an alias for AudioSpecificConfig.
type Config = AudioSpecificConfig

// AudioSpecificConfig is an AudioSpecificConfig as defined in ISO 14496-3.
// AudioSpecificConfig is an AudioSpecificConfig.
// Specification: ISO 14496-3, 1.6.2.1
type AudioSpecificConfig struct {
Type ObjectType
SampleRate int
Expand Down
1 change: 1 addition & 0 deletions pkg/codecs/mpeg4audio/object_type.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mpeg4audio

// ObjectType is a MPEG-4 Audio object type.
// Specification: ISO 14496-3, Table 1.17
type ObjectType int

// supported types.
Expand Down
3 changes: 2 additions & 1 deletion pkg/codecs/mpeg4audio/stream_mux_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ type StreamMuxConfigProgram struct {
Layers []*StreamMuxConfigLayer
}

// StreamMuxConfig is a StreamMuxConfig as defined in ISO 14496-3.
// StreamMuxConfig is a StreamMuxConfig.
// Specification: ISO 14496-3, Table 1.42
type StreamMuxConfig struct {
NumSubFrames uint
Programs []*StreamMuxConfigProgram
Expand Down
2 changes: 2 additions & 0 deletions pkg/codecs/opus/opus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package opus contains utilities to work with the Opus codec.
package opus
44 changes: 44 additions & 0 deletions pkg/codecs/opus/packet_duration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package opus

import (
"time"
)

var frameSizes = [32]int{
480, 960, 1920, 2880, // Silk NB
480, 960, 1920, 2880, // Silk MB
480, 960, 1920, 2880, // Silk WB
480, 960, // Hybrid SWB
480, 960, // Hybrid FB
120, 240, 480, 960, // CELT NB
120, 240, 480, 960, // CELT NB
120, 240, 480, 960, // CELT NB
120, 240, 480, 960, // CELT NB
}

// PacketDuration returns the duration of an Opus packet.
// Specification: RFC6716, 3.1
func PacketDuration(pkt []byte) time.Duration {
if len(pkt) == 0 {
return 0
}

frameDuration := frameSizes[pkt[0]>>3]

frameCount := 0
switch pkt[0] & 3 {
case 0:
frameCount = 1
case 1:
frameCount = 2
case 2:
frameCount = 2
case 3:
if len(pkt) < 2 {
return 0
}
frameCount = int(pkt[1] & 63)
}

return (time.Duration(frameDuration) * time.Duration(frameCount) * time.Millisecond) / 48
}
34 changes: 34 additions & 0 deletions pkg/codecs/opus/packet_duration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package opus

import (
"testing"
"time"

"github.com/stretchr/testify/require"
)

var casesPacketDuration = []struct {
name string
byts []byte
duration time.Duration
}{
{
"aa",
[]byte{1},
20 * time.Millisecond,
},
}

func TestPacketDuration(t *testing.T) {
for _, ca := range casesPacketDuration {
t.Run(ca.name, func(t *testing.T) {
require.Equal(t, ca.duration, PacketDuration(ca.byts))
})
}
}

func FuzzPacketDuration(f *testing.F) {
f.Fuzz(func(t *testing.T, b []byte) {
PacketDuration(b)
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("2")
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("70")
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("0")
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("1")
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("")
2 changes: 1 addition & 1 deletion pkg/formats/mpegts/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type CodecH265 struct{}
func (*CodecH265) isCodec() {
}

// CodecMPEG4Audio is a MPEG4-Audio codec.
// CodecMPEG4Audio is a MPEG-4 Audio codec.
type CodecMPEG4Audio struct {
mpeg4audio.Config
}
Expand Down

0 comments on commit efccece

Please sign in to comment.