Merged in single-frame-h264 (pull request #108)

av: allow for single h264 frame streaming

Approved-by: kortschak <dan@kortschak.io>
This commit is contained in:
Saxon Milton 2019-01-16 05:28:20 +00:00
commit a76be1fd5b
2 changed files with 34 additions and 19 deletions

View File

@ -30,10 +30,10 @@ LICENSE
package rtmp package rtmp
import ( import (
"bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
"runtime" "runtime"
"testing" "testing"
"time" "time"
@ -203,25 +203,27 @@ func TestFromFrame(t *testing.T) {
t.Errorf("Session.Open failed with error: %v", err) t.Errorf("Session.Open failed with error: %v", err)
} }
b, err := ioutil.ReadFile(filepath.Join(testDataDir, "AusOcean_logo_1080p.h264")) testFrame := os.Getenv("RTMP_TEST_FRAME")
b, err := ioutil.ReadFile(testFrame)
if err != nil { if err != nil {
t.Errorf("ReadFile failed with error: %v", err) t.Errorf("ReadFile failed with error: %v", err)
} }
// Pass RTMP session, true for audio, true for video, and 25 FPS const noOfFrames = 1000
// ToDo: fix this. Although we can encode the file and YouTube videoData := make([]byte, 0, noOfFrames*len(b))
// doesn't complain, YouTube doesn't play it (even when we for i := 0; i < noOfFrames; i++ {
// send 1 minute's worth). videoData = append(videoData, b...)
flvEncoder, err := flv.NewEncoder(s, true, true, 25)
if err != nil {
t.Fatalf("failed to create encoder: %v", err)
} }
for i := 0; i < 25; i++ {
err := flvEncoder.Encode(b) const frameRate = 25
if err != nil { rs := &rtmpSender{s: s}
t.Errorf("Encoding failed with error: %v", err) flvEncoder, err := flv.NewEncoder(rs, true, true, frameRate)
} if err != nil {
time.Sleep(time.Millisecond / 25) // rate limit to 1/25s t.Errorf("Failed to create flv encoder with error: %v", err)
}
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() err = s.Close()
@ -230,6 +232,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. // TestFromFile tests streaming from an video file comprising raw H.264.
// The test file is supplied via the RTMP_TEST_FILE environment variable. // The test file is supplied via the RTMP_TEST_FILE environment variable.
func TestFromFile(t *testing.T) { func TestFromFile(t *testing.T) {

View File

@ -117,12 +117,13 @@ outer:
// http://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.264-200305-S!!PDF-E&type=items // 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 // Table 7-1 NAL unit type codes
const ( const (
nonIdrPic = 1 nonIdrPic = 1
idrPic = 5 idrPic = 5
paramSet = 8 suppEnhInfo = 6
paramSet = 8
) )
switch nalTyp := b & 0x1f; nalTyp { switch nalTyp := b & 0x1f; nalTyp {
case nonIdrPic, idrPic, paramSet: case nonIdrPic, idrPic, paramSet, suppEnhInfo:
writeOut = true writeOut = true
} }
} }