mirror of https://bitbucket.org/ausocean/av.git
Need to do some testing on my flv stuff next
This commit is contained in:
parent
2bb1d4cfe0
commit
010b252782
56
flv/FLV.go
56
flv/FLV.go
|
@ -7,40 +7,70 @@ import (
|
||||||
const (
|
const (
|
||||||
headerLength = 72
|
headerLength = 72
|
||||||
version = 0x01
|
version = 0x01
|
||||||
|
maxVideoTagSize = 10000
|
||||||
|
maxAudioTagSize = 10000
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
videoTagType = 9
|
||||||
)
|
)
|
||||||
|
|
||||||
type Header struct {
|
type Header struct {
|
||||||
audioFlag bool
|
AudioFlag bool
|
||||||
videoFlag bool
|
VideoFlag bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) toByteSlice() []byte {
|
func (h *Header) toByteSlice() []byte {
|
||||||
output = make([]byte, 0, headerLength)
|
output = make([]byte, 0, headerLength)
|
||||||
output = append(output, []byte{ 0x46, 0x4C, 0x56,
|
output = append(output, []byte{0x46, 0x4C, 0x56,
|
||||||
version,
|
version,
|
||||||
0x00 | tools.boolToByte(h.audioFlag) << 3 | tools.boolToByte(h.videoFlag),
|
0x00 | tools.boolToByte(h.audioFlag)<<3 | tools.boolToByte(h.videoFlag),
|
||||||
0x00, 0x00, 0x00, byte(72),
|
0x00, 0x00, 0x00, byte(72),
|
||||||
}...)
|
}...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type VideoTag struct {
|
type VideoTag struct {
|
||||||
prevTagSize uint32
|
PrevTagSize uint32
|
||||||
tagType uint
|
TagType uint8
|
||||||
dataSize uint32
|
DataSize uint32
|
||||||
timeStamp uint32
|
Timestamp uint32
|
||||||
timestampExtended uint32
|
TimestampExtended uint32
|
||||||
data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *VideoTag) toByteSlice() (output []byte) {
|
func (t *VideoTag) toByteSlice() (output []byte) {
|
||||||
|
output = make([]byte, 0, maxVideoTagSize)
|
||||||
|
output = append(output, []byte{
|
||||||
|
byte(t.prevTagSize >> 24),
|
||||||
|
byte(t.prevTagSize >> 16),
|
||||||
|
byte(t.prevTagSize >> 8),
|
||||||
|
byte(t.prevTagSize),
|
||||||
|
byte(t.tageType),
|
||||||
|
byte(t.dataSize >> 16),
|
||||||
|
byte(t.dataSize >> 8),
|
||||||
|
byte(t.dataSize),
|
||||||
|
byte(t.timeStamp >> 16),
|
||||||
|
byte(t.timeStamp >> 8),
|
||||||
|
byte(t.timeStamp),
|
||||||
|
byte(t.timestampExtended),
|
||||||
|
0x00, 0x00, 0x00,
|
||||||
|
}...)
|
||||||
|
output = append(output, data...)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type AudioTag struct {
|
type AudioTag struct {
|
||||||
|
soundFormat uint8
|
||||||
|
soundRate uint8
|
||||||
|
soundSize uint8
|
||||||
|
soundType uint8
|
||||||
|
data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *AudioTage) toByteSlice() (output []byte) {
|
func (t *AudioTage) toByteSlice() (output []byte) {
|
||||||
|
output = make([]byte, 0, maxAudioTagSize)
|
||||||
|
output = append(output, byte(soundFormat<<4)|byte(soundRate<<2)|byte(soundSize<<1)|byte(soundType))
|
||||||
|
output = append(output, data...)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ type flvGenerator struct {
|
||||||
fps uint
|
fps uint
|
||||||
inputChan chan []byte
|
inputChan chan []byte
|
||||||
outputChan chan []byte
|
outputChan chan []byte
|
||||||
headerChan []
|
header Header
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *flvGenerator)GetInputChan() chan []byte {
|
func (g *flvGenerator)GetInputChan() chan []byte {
|
||||||
|
@ -18,21 +18,23 @@ func (g *flvGenerator)GetOutputChan() chan []byte {
|
||||||
func NewFlvGenerator() (g *flvGenerator) {
|
func NewFlvGenerator() (g *flvGenerator) {
|
||||||
g = new(flvGenerator)
|
g = new(flvGenerator)
|
||||||
g.timestamp = 0
|
g.timestamp = 0
|
||||||
|
g.lastTagSize = 0
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *flvGenerator) Start(){
|
func (g *flvGenerator) Start(){
|
||||||
g.GenHeader()
|
|
||||||
go g.generate()
|
go g.generate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *flvGenerator) GenHeader(){
|
func (g *flvGenerator) GenHeader(){
|
||||||
header = flv.Header{
|
header := flv.Header{
|
||||||
|
AudioFlag: true,
|
||||||
|
VideoFlag: true,
|
||||||
}
|
}
|
||||||
g.outputChan <- header
|
g.outputChan <- header.toByteSlice()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *flvGenerator) GetNextTimestamp() (timestamp uint32){
|
func (g *flvGenerator) getNextTimestamp() (timestamp uint32){
|
||||||
timestamp = g.currentTimestamp
|
timestamp = g.currentTimestamp
|
||||||
g.currentTimeStamp += 100*time.Millisecond() / g.fps
|
g.currentTimeStamp += 100*time.Millisecond() / g.fps
|
||||||
return
|
return
|
||||||
|
@ -43,9 +45,19 @@ func (g *flvGenerator) ResetTimestamp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *tsGenerator) generate() {
|
func (g *tsGenerator) generate() {
|
||||||
|
g.GenHeader()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case videoFrame := <-g.inputChan
|
case videoFrame := <-g.inputChan
|
||||||
|
tag := VideoTage{
|
||||||
|
PrevTagSize: g.lastTagSize,
|
||||||
|
TagType: flv.videoTagType,
|
||||||
|
DataSize: len(videoFrame),
|
||||||
|
Timestamp: g.getNextTimestamp(),
|
||||||
|
TimestampExtended: 0,
|
||||||
|
Data: videoFrame
|
||||||
|
}
|
||||||
|
g.outputChan<-tag.toByteSlice()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zhangpeihao/goflv"
|
|
||||||
rtmp "github.com/zhangpeihao/gortmp"
|
|
||||||
"github.com/zhangpeihao/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
programName = "RtmpPublisher"
|
|
||||||
version = "0.0.1"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
url *string = flag.String("URL", "rtmp://video-center.alivecdn.com/AppName/StreamName?vhost=live.gz-app.com", "The rtmp url to connect.")
|
|
||||||
streamName *string = flag.String("Stream", "camstream", "Stream name to play.")
|
|
||||||
flvFileName *string = flag.String("FLV", "./v_4097.flv", "FLV file to publishs.")
|
|
||||||
)
|
|
||||||
var obConn rtmp.OutboundConn
|
|
||||||
var createStreamChan chan rtmp.OutboundStream
|
|
||||||
var videoDataSize int64
|
|
||||||
var audioDataSize int64
|
|
||||||
var flvFile *flv.File
|
|
||||||
|
|
||||||
var status uint
|
|
||||||
|
|
||||||
func publish(stream rtmp.OutboundStream) {
|
|
||||||
startTs := uint32(0)
|
|
||||||
startAt := time.Now().UnixNano()
|
|
||||||
preTs := uint32(0)
|
|
||||||
for status == rtmp.OUTBOUND_CONN_STATUS_CREATE_STREAM_OK {
|
|
||||||
|
|
||||||
fmt.Printf("@@@@@@@@@@@@@@diff1 header(%+v), startTs: %d\n", header, startTs)
|
|
||||||
if err = stream.PublishData(header.TagType, data, diff1); err != nil {
|
|
||||||
fmt.Println("PublishData() error:", err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
createStreamChan = make(chan rtmp.OutboundStream)
|
|
||||||
testHandler := &TestOutboundConnHandler{}
|
|
||||||
fmt.Println("to dial")
|
|
||||||
fmt.Println("a")
|
|
||||||
var err error
|
|
||||||
obConn, err = rtmp.Dial(*url, testHandler, 100)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Dial error", err)
|
|
||||||
os.Exit(-1)
|
|
||||||
}
|
|
||||||
fmt.Println("b")
|
|
||||||
defer obConn.Close()
|
|
||||||
fmt.Println("to connect")
|
|
||||||
err = obConn.Connect()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Connect error: %s", err.Error())
|
|
||||||
os.Exit(-1)
|
|
||||||
}
|
|
||||||
fmt.Println("c")
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case stream := <-createStreamChan:
|
|
||||||
// Publish
|
|
||||||
stream.Attach(testHandler)
|
|
||||||
err = stream.Publish(*streamName, "live")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Publish error: %s", err.Error())
|
|
||||||
os.Exit(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
case <-time.After(1 * time.Second):
|
|
||||||
fmt.Printf("Audio size: %d bytes; Vedio size: %d bytes\n", audioDataSize, videoDataSize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue