Skip to content

Commit

Permalink
FLV: Support HEVC(12) and OPUS(13)
Browse files Browse the repository at this point in the history
  • Loading branch information
winlinvip committed Jan 16, 2019
1 parent c8e50af commit 4a46189
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 25 deletions.
35 changes: 22 additions & 13 deletions flv/flv.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ func (v *AudioSamplingRate) From(a aac.SampleRateIndex) {

// The audio codec id, FLV named it the SoundFormat.
// Refer to @doc video_file_format_spec_v10.pdf, @page 76, @section E.4.2 Audio Tags
// It's 4bits, that is 0-16.
type AudioCodec uint8

const (
Expand All @@ -365,7 +366,8 @@ const (
AudioCodecAAC // 10 = AAC
AudioCodecSpeex // 11 = Speex
AudioCodecUndefined12
AudioCodecUndefined13
// For FLV, it's undefined, we define it as Opus for WebRTC.
AudioCodecOpus // 13 = Opus
AudioCodecMP3In8kHz // 14 = MP3 8 kHz
AudioCodecDeviceSpecific // 15 = Device-specific sound
AudioCodecForbidden
Expand Down Expand Up @@ -395,6 +397,8 @@ func (v AudioCodec) String() string {
return "AAC"
case AudioCodecSpeex:
return "Speex"
case AudioCodecOpus:
return "Opus"
case AudioCodecMP3In8kHz:
return "MP3(8kHz)"
case AudioCodecDeviceSpecific:
Expand Down Expand Up @@ -432,15 +436,14 @@ func NewAudioPackager() (AudioPackager, error) {
}

func (v *audioPackager) Encode(frame *AudioFrame) (tag []byte, err error) {
audioTagHeader := []byte{
byte(frame.SoundFormat)<<4 | byte(frame.SoundRate)<<2 | byte(frame.SoundSize)<<1 | byte(frame.SoundType),
}

if frame.SoundFormat == AudioCodecAAC {
return append([]byte{
byte(frame.SoundFormat)<<4 | byte(frame.SoundRate)<<2 | byte(frame.SoundSize)<<1 | byte(frame.SoundType),
byte(frame.Trait),
}, frame.Raw...), nil
return append(append(audioTagHeader, byte(frame.Trait)), frame.Raw...), nil
} else {
return append([]byte{
byte(frame.SoundFormat)<<4 | byte(frame.SoundRate)<<2 | byte(frame.SoundSize)<<1 | byte(frame.SoundType),
}, frame.Raw...), nil
return append(audioTagHeader, frame.Raw...), nil
}
}

Expand Down Expand Up @@ -501,6 +504,7 @@ func (v VideoFrameType) String() string {

// The video codec id.
// Refer to @doc video_file_format_spec_v10.pdf, @page 78, @section E.4.3 Video Tags
// It's 4bits, that is 0-16.
type VideoCodec uint8

const (
Expand All @@ -511,6 +515,8 @@ const (
VideoCodecOn2VP6Alpha // 5 = On2 VP6 with alpha channel
VideoCodecScreen2 // 6 = Screen video version 2
VideoCodecAVC // 7 = AVC
// See page 79 at @doc https://github.com/CDN-Union/H265/blob/master/Document/video_file_format_spec_v10_1_ksyun_20170615.doc
VideoCodecHEVC VideoCodec = 12 // 12 = HEVC
)

func (v VideoCodec) String() string {
Expand All @@ -527,19 +533,22 @@ func (v VideoCodec) String() string {
return "Screen2"
case VideoCodecAVC:
return "AVC"
case VideoCodecHEVC:
return "HEVC"
default:
return "Forbidden"
}
}

// The video AVC frame trait, whethere sequence header or not.
// Refer to @doc video_file_format_spec_v10.pdf, @page 78, @section E.4.3 Video Tags
// If AVC or HEVC, it's 8bits.
type VideoFrameTrait uint8

const (
VideoFrameTraitSequenceHeader VideoFrameTrait = iota // 0 = AVC sequence header
VideoFrameTraitNALU // 1 = AVC NALU
VideoFrameTraitSequenceEOF // 2 = AVC end of sequence (lower level NALU sequence ender is
VideoFrameTraitSequenceHeader VideoFrameTrait = iota // 0 = AVC/HEVC sequence header
VideoFrameTraitNALU // 1 = AVC/HEVC NALU
VideoFrameTraitSequenceEOF // 2 = AVC/HEVC end of sequence (lower level NALU sequence ender is
VideoFrameTraitForbidden
)

Expand Down Expand Up @@ -596,7 +605,7 @@ func (v *videoPackager) Decode(tag []byte) (frame *VideoFrame, err error) {
frame.FrameType = VideoFrameType(byte(p[0]>>4) & 0x0f)
frame.CodecID = VideoCodec(byte(p[0]) & 0x0f)

if frame.CodecID == VideoCodecAVC {
if frame.CodecID == VideoCodecAVC || frame.CodecID == VideoCodecHEVC {
frame.Trait = VideoFrameTrait(p[1])
frame.CTS = int32(uint32(p[2])<<16 | uint32(p[3])<<8 | uint32(p[4]))
frame.Raw = tag[5:]
Expand All @@ -608,7 +617,7 @@ func (v *videoPackager) Decode(tag []byte) (frame *VideoFrame, err error) {
}

func (v videoPackager) Encode(frame *VideoFrame) (tag []byte, err error) {
if frame.CodecID == VideoCodecAVC {
if frame.CodecID == VideoCodecAVC || frame.CodecID == VideoCodecHEVC {
return append([]byte{
byte(frame.FrameType)<<4 | byte(frame.CodecID), byte(frame.Trait),
byte(frame.CTS >> 16), byte(frame.CTS >> 8), byte(frame.CTS),
Expand Down
4 changes: 2 additions & 2 deletions https/crypto/ocsp/ocsp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ func TestOCSPDecode(t *testing.T) {
}

if !reflect.DeepEqual(resp.ThisUpdate, expected.ThisUpdate) {
t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, expected.ThisUpdate)
t.Errorf("resp.ThisUpdate: got %v, want %v", resp.ThisUpdate, expected.ThisUpdate)
}

if !reflect.DeepEqual(resp.NextUpdate, expected.NextUpdate) {
t.Errorf("resp.NextUpdate: got %d, want %d", resp.NextUpdate, expected.NextUpdate)
t.Errorf("resp.NextUpdate: got %v, want %v", resp.NextUpdate, expected.NextUpdate)
}

if resp.Status != expected.Status {
Expand Down
20 changes: 10 additions & 10 deletions kxps/kxps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,55 +60,55 @@ func TestKxps_Rps10s(t *testing.T) {
kxps := newKxps(nil, s)

if err := kxps.doSample(time.Unix(0, 0)); err != nil {
t.Errorf("sample failed, err is", err)
t.Errorf("sample failed, err is %+v", err)
} else if kxps.Xps10s() != 0 || kxps.Xps30s() != 0 || kxps.Xps300s() != 0 {
t.Errorf("sample invalid, 10s=%v, 30s=%v, 300s=%v", kxps.Xps10s(), kxps.Xps30s(), kxps.Xps300s())
}

s.s = 10
if err := kxps.doSample(time.Unix(10, 0)); err != nil {
t.Errorf("sample failed, err is", err)
t.Errorf("sample failed, err is %+v", err)
} else if kxps.Xps10s() != 0 || kxps.Xps30s() != 0 || kxps.Xps300s() != 0 {
t.Errorf("sample invalid, 10s=%v, 30s=%v, 300s=%v", kxps.Xps10s(), kxps.Xps30s(), kxps.Xps300s())
}

s.s = 20
if err := kxps.doSample(time.Unix(20, 0)); err != nil {
t.Errorf("sample failed, err is", err)
t.Errorf("sample failed, err is %+v", err)
} else if kxps.Xps10s() != 10.0/10.0 || kxps.Xps30s() != 0 || kxps.Xps300s() != 0 {
t.Errorf("sample invalid, 10s=%v, 30s=%v, 300s=%v", kxps.Xps10s(), kxps.Xps30s(), kxps.Xps300s())
} else if err := kxps.doSample(time.Unix(30, 0)); err != nil {
t.Errorf("sample failed, err is", err)
t.Errorf("sample failed, err is %+v", err)
} else if kxps.Xps10s() != 0 || kxps.Xps30s() != 0 || kxps.Xps300s() != 0 {
t.Errorf("sample invalid, 10s=%v, 30s=%v, 300s=%v", kxps.Xps10s(), kxps.Xps30s(), kxps.Xps300s())
}

s.s = 30
if err := kxps.doSample(time.Unix(40, 0)); err != nil {
t.Errorf("sample failed, err is", err)
t.Errorf("sample failed, err is %+v", err)
} else if kxps.Xps10s() != 10.0/10.0 || kxps.Xps30s() != 20.0/30.0 || kxps.Xps300s() != 0 {
t.Errorf("sample invalid, 10s=%v, 30s=%v, 300s=%v", kxps.Xps10s(), kxps.Xps30s(), kxps.Xps300s())
} else if err := kxps.doSample(time.Unix(50, 0)); err != nil {
t.Errorf("sample failed, err is", err)
t.Errorf("sample failed, err is %+v", err)
} else if kxps.Xps10s() != 0 || kxps.Xps30s() != 20.0/30.0 || kxps.Xps300s() != 0 {
t.Errorf("sample invalid, 10s=%v, 30s=%v, 300s=%v", kxps.Xps10s(), kxps.Xps30s(), kxps.Xps300s())
}

s.s = 40
if err := kxps.doSample(time.Unix(310, 0)); err != nil {
t.Errorf("sample failed, err is", err)
t.Errorf("sample failed, err is %+v", err)
} else if kxps.Xps10s() != 10.0/10.0 || kxps.Xps30s() != 10.0/30.0 || kxps.Xps300s() != 30.0/300.0 {
t.Errorf("sample invalid, 10s=%v, 30s=%v, 300s=%v", kxps.Xps10s(), kxps.Xps30s(), kxps.Xps300s())
} else if err := kxps.doSample(time.Unix(320, 0)); err != nil {
t.Errorf("sample failed, err is", err)
t.Errorf("sample failed, err is %+v", err)
} else if kxps.Xps10s() != 0 || kxps.Xps30s() != 10.0/30.0 || kxps.Xps300s() != 30.0/300.0 {
t.Errorf("sample invalid, 10s=%v, 30s=%v, 300s=%v", kxps.Xps10s(), kxps.Xps30s(), kxps.Xps300s())
} else if err := kxps.doSample(time.Unix(340, 0)); err != nil {
t.Errorf("sample failed, err is", err)
t.Errorf("sample failed, err is %+v", err)
} else if kxps.Xps10s() != 0 || kxps.Xps30s() != 0 || kxps.Xps300s() != 30.0/300.0 {
t.Errorf("sample invalid, 10s=%v, 30s=%v, 300s=%v", kxps.Xps10s(), kxps.Xps30s(), kxps.Xps300s())
} else if err := kxps.doSample(time.Unix(610, 0)); err != nil {
t.Errorf("sample failed, err is", err)
t.Errorf("sample failed, err is %+v", err)
} else if kxps.Xps10s() != 0 || kxps.Xps30s() != 0 || kxps.Xps300s() != 0 {
t.Errorf("sample invalid, 10s=%v, 30s=%v, 300s=%v", kxps.Xps10s(), kxps.Xps30s(), kxps.Xps300s())
}
Expand Down

0 comments on commit 4a46189

Please sign in to comment.