From 10860e4e48ad392dc4d4d66fa856dd49943ac94e Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 11 Jan 2019 17:20:56 +1030 Subject: [PATCH 1/5] lex: modified h264 lexer to consider nal type 6 packets, i.e. sei packets, which seem important fro repeating single frames --- rtmp/rtmp_test.go | 26 +++++++++++++------------- stream/lex/lex.go | 3 ++- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/rtmp/rtmp_test.go b/rtmp/rtmp_test.go index 01dad10f..094457ac 100644 --- a/rtmp/rtmp_test.go +++ b/rtmp/rtmp_test.go @@ -30,10 +30,10 @@ LICENSE package rtmp import ( + "bytes" "fmt" "io/ioutil" "os" - "path/filepath" "runtime" "testing" "time" @@ -171,24 +171,24 @@ func TestFromFrame(t *testing.T) { t.Errorf("Session.Open failed with error: %v", err) } - b, err := ioutil.ReadFile(filepath.Join(testDataDir, "AusOcean_logo_1080p.h264")) + // TODO: don't hard code this path + b, err := ioutil.ReadFile("/home/saxon/Desktop/singleframe.h264") if err != nil { t.Errorf("ReadFile failed with error: %v", err) } - // Pass RTMP session, true for audio, true for video, and 25 FPS - // ToDo: fix this. Although we can encode the file and YouTube - // doesn't complain, YouTube doesn't play it (even when we - // send 1 minute's worth). - flvEncoder := flv.NewEncoder(s, true, true, 25) - for i := 0; i < 25; i++ { - err := flvEncoder.Encode(b) - if err != nil { - t.Errorf("Encoding failed with error: %v", err) - } - time.Sleep(time.Millisecond / 25) // rate limit to 1/25s + const noOfFrames = 1000 + videoData := make([]byte, 0, noOfFrames*len(b)) + for i := 0; i < noOfFrames; i++ { + videoData = append(videoData, b...) } + const frameRate = 25 + flvEncoder := flv.NewEncoder(s, true, true, frameRate) + err = lex.H264(flvEncoder, bytes.NewReader(videoData), time.Second/time.Duration(frameRate)) + if err != nil { + t.Errorf("Lexing failed with error: %v", err) + } err = s.Close() if err != nil { t.Errorf("Session.Close failed with error: %v", err) diff --git a/stream/lex/lex.go b/stream/lex/lex.go index 115915c3..e48d72d1 100644 --- a/stream/lex/lex.go +++ b/stream/lex/lex.go @@ -120,9 +120,10 @@ outer: nonIdrPic = 1 idrPic = 5 paramSet = 8 + sei = 6 ) switch nalTyp := b & 0x1f; nalTyp { - case nonIdrPic, idrPic, paramSet: + case nonIdrPic, idrPic, paramSet, sei: writeOut = true } } From b63c55ae48ef46962ed16f17b72aeadd345fbccb Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 11 Jan 2019 18:09:32 +1030 Subject: [PATCH 2/5] flv: fixed NewEncoder so that we still create encoder even if the HeaderByte write fails --- rtmp/rtmp_test.go | 2 +- stream/flv/encoder.go | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/rtmp/rtmp_test.go b/rtmp/rtmp_test.go index 6585c96f..3efbdec8 100644 --- a/rtmp/rtmp_test.go +++ b/rtmp/rtmp_test.go @@ -185,7 +185,7 @@ func TestFromFrame(t *testing.T) { const frameRate = 25 flvEncoder, err := flv.NewEncoder(s, true, true, frameRate) - if err != nil { + if err != nil && err != errTinyPacket { t.Errorf("Failed to create flv encoder with error: %v", err) } err = lex.H264(flvEncoder, bytes.NewReader(videoData), time.Second/time.Duration(frameRate)) diff --git a/stream/flv/encoder.go b/stream/flv/encoder.go index 46d0eacb..4772a151 100644 --- a/stream/flv/encoder.go +++ b/stream/flv/encoder.go @@ -73,9 +73,6 @@ func NewEncoder(dst io.Writer, audio, video bool, fps int) (*Encoder, error) { video: video, } _, err := dst.Write(e.HeaderBytes()) - if err != nil { - return nil, err - } return &e, err } From 61c1ff6ee4d22469514f70000e87a45b61ea0309 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 11 Jan 2019 18:19:58 +1030 Subject: [PATCH 3/5] rtmp: got handle errors that should stop the encoding with a middle man rtmpSender --- rtmp/rtmp_test.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/rtmp/rtmp_test.go b/rtmp/rtmp_test.go index 3efbdec8..06b1979a 100644 --- a/rtmp/rtmp_test.go +++ b/rtmp/rtmp_test.go @@ -184,8 +184,9 @@ func TestFromFrame(t *testing.T) { } const frameRate = 25 - flvEncoder, err := flv.NewEncoder(s, true, true, frameRate) - if err != nil && err != errTinyPacket { + rs := &rtmpSender{s: s} + flvEncoder, err := flv.NewEncoder(rs, true, true, frameRate) + if err != nil { t.Errorf("Failed to create flv encoder with error: %v", err) } err = lex.H264(flvEncoder, bytes.NewReader(videoData), time.Second/time.Duration(frameRate)) @@ -198,6 +199,18 @@ func TestFromFrame(t *testing.T) { } } +type rtmpSender struct { + s *Session +} + +func (rs *rtmpSender) Write(p []byte) (int, error) { + n, err := rs.s.Write(p) + if err != errTinyPacket && err != nil { + return 0, err + } + return n, nil +} + // TestFromFile tests streaming from an video file comprising raw H.264. // The test file is supplied via the RTMP_TEST_FILE environment variable. func TestFromFile(t *testing.T) { From 27081e1ea95312040375b81f14375b9eb349cd27 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 11 Jan 2019 23:39:49 +1030 Subject: [PATCH 4/5] flv: added back dans NewEncoder write fail code --- stream/flv/encoder.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stream/flv/encoder.go b/stream/flv/encoder.go index 4772a151..46d0eacb 100644 --- a/stream/flv/encoder.go +++ b/stream/flv/encoder.go @@ -73,6 +73,9 @@ func NewEncoder(dst io.Writer, audio, video bool, fps int) (*Encoder, error) { video: video, } _, err := dst.Write(e.HeaderBytes()) + if err != nil { + return nil, err + } return &e, err } From 1e1a6bf0ebae0054015410db3964455f62443a16 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 11 Jan 2019 23:43:54 +1030 Subject: [PATCH 5/5] rtmp: re-added blank line in rtmp_test.go and renamed sei to suppEnhInfo --- rtmp/rtmp_test.go | 1 + stream/lex/lex.go | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/rtmp/rtmp_test.go b/rtmp/rtmp_test.go index 06b1979a..531b7b2c 100644 --- a/rtmp/rtmp_test.go +++ b/rtmp/rtmp_test.go @@ -193,6 +193,7 @@ func TestFromFrame(t *testing.T) { if err != nil { t.Errorf("Lexing failed with error: %v", err) } + err = s.Close() if err != nil { t.Errorf("Session.Close failed with error: %v", err) diff --git a/stream/lex/lex.go b/stream/lex/lex.go index e48d72d1..a6275799 100644 --- a/stream/lex/lex.go +++ b/stream/lex/lex.go @@ -117,13 +117,13 @@ outer: // http://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.264-200305-S!!PDF-E&type=items // Table 7-1 NAL unit type codes const ( - nonIdrPic = 1 - idrPic = 5 - paramSet = 8 - sei = 6 + nonIdrPic = 1 + idrPic = 5 + suppEnhInfo = 6 + paramSet = 8 ) switch nalTyp := b & 0x1f; nalTyp { - case nonIdrPic, idrPic, paramSet, sei: + case nonIdrPic, idrPic, paramSet, suppEnhInfo: writeOut = true } }