Skip to content

Commit

Permalink
Merge pull request #77 from OneHeng/opus
Browse files Browse the repository at this point in the history
Opus
  • Loading branch information
ZSC714725 authored Apr 19, 2024
2 parents 3766b20 + 6964ae3 commit 4d25f89
Show file tree
Hide file tree
Showing 15 changed files with 1,255 additions and 140 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,12 @@ srt://127.0.0.1:6001?streamid=test110
## [WebRTC](./document/rtc.md)
(1)支持WHIP推流和WHEP拉流,暂时只支持POST信令

(2)支持H264/G711A/G711U,后续支持opus音频
(2)支持H264/G711A/G711U/OPUS

(3)可以对接OBS、vue-wish

(4) WHEP支持对接Safari HEVC

WHIP推流url
http(s)://127.0.0.1:1290/whip?streamid=test110

Expand All @@ -100,7 +102,7 @@ http(s)://127.0.0.1:1290/whep?streamid=test110
http(s)://127.0.0.1:1290/live/m4s/test110.mp4

## HLS(fmp4/Low Latency)
(1) 支持H264/H265/AAC
(1) 支持H264/H265/AAC/OPUS

拉流url
http(s)://127.0.0.1:1290/live/hls/test110/index.m3u8
Expand Down
40 changes: 36 additions & 4 deletions fmp4/hls/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func (session *HlsSession) OnMsg(msg base.RtmpMsg) {
pts := time.Millisecond*time.Duration(msg.Pts()) - session.startVideoPts
err = session.muxer.WriteH26x(time.Now(), pts, nalus)
if err != nil {
nazalog.Error(err)
nazalog.Error("hls-fmp4 WriteH26x failed, err:", err)
}
}

Expand All @@ -121,7 +121,13 @@ func (session *HlsSession) OnMsg(msg base.RtmpMsg) {
pts := time.Millisecond*time.Duration(msg.Dts()) - session.startAudioPts
err := session.muxer.WriteMPEG4Audio(time.Now(), pts, [][]byte{msg.Payload[2:]})
if err != nil {
nazalog.Error(err)
nazalog.Error("hls-fmp4 WriteMPEG4Audio failed, err:", err)
}
} else if session.audioCodecId == int(base.RtmpSoundFormatOpus) {
pts := time.Millisecond*time.Duration(msg.Dts()) - session.startAudioPts
err := session.muxer.WriteOpus(time.Now(), pts, [][]byte{msg.Payload[1:]})
if err != nil {
nazalog.Error("hls-fmp4 WriteOpus failed, err:", err)
}
}
}
Expand Down Expand Up @@ -151,6 +157,20 @@ func (session *HlsSession) OnMsg(msg base.RtmpMsg) {
}
session.data = append(session.data, frame)
}
} else if session.audioCodecId == int(base.RtmpSoundFormatOpus) {
if !session.audioStartPTSFilled {
session.startAudioPts = time.Millisecond * time.Duration(msg.Dts())
session.audioStartPTSFilled = true
}

pts := time.Millisecond*time.Duration(msg.Dts()) - session.startAudioPts
frame := Frame{
ntp: time.Now(),
pts: pts,
au: [][]byte{msg.Payload[1:]},
codecType: msg.AudioCodecId(),
}
session.data = append(session.data, frame)
} else {
return
}
Expand Down Expand Up @@ -249,6 +269,12 @@ func (session *HlsSession) drain() {
Config: mpegConf,
},
}
} else if session.audioCodecId == int(base.RtmpSoundFormatOpus) {
session.muxer.AudioTrack = &gohlslib.Track{
Codec: &codecs.Opus{
ChannelCount: 1,
},
}
}
}

Expand All @@ -261,13 +287,19 @@ func (session *HlsSession) drain() {
if data.codecType == base.RtmpCodecIdAvc || data.codecType == base.RtmpCodecIdHevc {
err := session.muxer.WriteH26x(data.ntp, data.pts, data.au)
if err != nil {
nazalog.Error(err)
nazalog.Error("hls-fmp4 WriteH26x failed, err:", err)
continue
}
} else if data.codecType == base.RtmpSoundFormatAac {
err := session.muxer.WriteMPEG4Audio(data.ntp, data.pts, data.au)
if err != nil {
nazalog.Error(err)
nazalog.Error("hls-fmp4 WriteMPEG4Audio failed, err:", err)
continue
}
} else if data.codecType == base.RtmpSoundFormatOpus {
err := session.muxer.WriteOpus(data.ntp, data.pts, data.au)
if err != nil {
nazalog.Error("hls-fmp4 WriteMPEG4Audio failed, err:", err)
continue
}
} else {
Expand Down
120 changes: 120 additions & 0 deletions fmp4/muxer/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package muxer

import (
"io"

"github.com/abema/go-mp4"
"github.com/q191201771/naza/pkg/nazalog"
)

type Init struct {
Tracks []*Track
}

func (i *Init) Encode(w io.WriteSeeker) error {
/*
|ftyp|
|moov|
| |mvhd|
| |trak|
| |trak|
| |....|
| |mvex|
| | |trex|
| | |trex|
| | |....|
*/

mw := newMP4Writer(w)

// ftyp box
_, err := mw.writeBox(&mp4.Ftyp{
MajorBrand: [4]byte{'m', 'p', '4', '2'},
MinorVersion: 1,
CompatibleBrands: []mp4.CompatibleBrandElem{
{
CompatibleBrand: [4]byte{'m', 'p', '4', '1'},
},
{
CompatibleBrand: [4]byte{'m', 'p', '4', '2'},
},
{
CompatibleBrand: [4]byte{'i', 's', 'o', 'm'},
},
{
CompatibleBrand: [4]byte{'h', 'l', 's', 'f'},
},
},
})

if err != nil {
nazalog.Error("write ftyp box failed, err:", err)
return err
}

// moov box
_, err = mw.writeBoxStart(&mp4.Moov{})
if err != nil {
nazalog.Error("write moov box failed, err:", err)
return err
}

// mvhd box
_, err = mw.writeBox(&mp4.Mvhd{
Timescale: 1000,
Rate: 65536,
Volume: 256,
Matrix: [9]int32{0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000},
NextTrackID: 4294967295,
})

if err != nil {
nazalog.Error("write mvhd box failed, err:", err)
return err
}

// track box
for _, track := range i.Tracks {
err = track.Encode(mw)
if err != nil {
nazalog.Error("track encode failed, err:", err)
return err
}
}

// mvex box
_, err = mw.writeBoxStart(&mp4.Mvex{})
if err != nil {
nazalog.Error("write mvex box failed, err:", err)
return err
}

// trex box
for _, track := range i.Tracks {
_, err = mw.writeBox(&mp4.Trex{
TrackID: uint32(track.ID),
DefaultSampleDescriptionIndex: 1,
})

if err != nil {
nazalog.Error("write trex box failed, err:", err)
return err
}
}

// </mvex>
err = mw.writeBoxEnd()
if err != nil {
nazalog.Error("write mvex end box failed, err:", err)
return err
}

// </moov>
err = mw.writeBoxEnd()
if err != nil {
nazalog.Error("write moov end box failed, err:", err)
return err
}

return nil
}
83 changes: 83 additions & 0 deletions fmp4/muxer/mp4_writer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package muxer

import (
"io"

"github.com/abema/go-mp4"
)

type mp4Writer struct {
w *mp4.Writer
}

func newMP4Writer(w io.WriteSeeker) *mp4Writer {
return &mp4Writer{
w: mp4.NewWriter(w),
}
}

func (w *mp4Writer) writeBoxStart(box mp4.IImmutableBox) (int, error) {
bi := &mp4.BoxInfo{
Type: box.GetType(),
}
var err error
bi, err = w.w.StartBox(bi)
if err != nil {
return 0, err
}

_, err = mp4.Marshal(w.w, box, mp4.Context{})
if err != nil {
return 0, err
}

return int(bi.Offset), nil
}

func (w *mp4Writer) writeBoxEnd() error {
_, err := w.w.EndBox()
return err
}

func (w *mp4Writer) writeBox(box mp4.IImmutableBox) (int, error) {
off, err := w.writeBoxStart(box)
if err != nil {
return 0, err
}

err = w.writeBoxEnd()
if err != nil {
return 0, err
}

return off, nil
}

func (w *mp4Writer) rewriteBox(off int, box mp4.IImmutableBox) error {
prevOff, err := w.w.Seek(0, io.SeekCurrent)
if err != nil {
return err
}

_, err = w.w.Seek(int64(off), io.SeekStart)
if err != nil {
return err
}

_, err = w.writeBoxStart(box)
if err != nil {
return err
}

err = w.writeBoxEnd()
if err != nil {
return err
}

_, err = w.w.Seek(prevOff, io.SeekStart)
if err != nil {
return err
}

return nil
}
Loading

0 comments on commit 4d25f89

Please sign in to comment.