Git Product home page Git Product logo

gortmp's Introduction

GoRTMP Build Status

======

RTMP protocol implementation.

Spec:

Todo:

  • Inbound side

Examples:

// To connect FMS server
obConn, err := rtmp.Dial(url, handler, 100)

// To connect
err = obConn.Connect()

// When new stream created, handler event OnStreamCreated() would been called
func (handler *TestOutboundConnHandler) OnStreamCreated(stream rtmp.OutboundStream) {
	// To play
	err = stream.Play(*streamName, nil, nil, nil)
	// Or publish
	err = stream.Publish(*streamName, "live")
}

// To publish data
stream.PublishAudioData(data, deltaTimestamp)
// or
stream.PublishVideoData(data, deltaTimestamp)
// or
stream.PublishData(tagHeader.TagType, data, deltaTimestamp)

// You can close stream by
stream.Close()

// You can close connection by
obConn.Close()

gortmp's People

Contributors

daozhao avatar hy05190134 avatar zhangpeihao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gortmp's Issues

Can not publish flv to youtube

Seems not receive onPublishStart

Here is log.
to dial
to connect
Audio size: 0 bytes; Vedio size: 0 bytes
status: 3, err:
ReceviedRtmpCommand: &{IsFlex:false Name:_result TransactionID:1 Objects:[map[fmsVer:FMS/3,5,3,824 capabilities:127 mode:1] map[level:status code:NetConnection.Connect.Success description:Connection succeeded. objectEncoding:0 data:map[version:3,5,3,824]]]}
ReceviedRtmpCommand: &{IsFlex:false Name:onBWDone TransactionID:0 Objects:[]}
Audio size: 0 bytes; Vedio size: 0 bytes
status: 5, err:
Stream created: 1
ReceviedRtmpCommand: &{IsFlex:false Name:_result TransactionID:2 Objects:[ 1]}
Publish
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes

How to create a an outboundstream ?

Hello, I'm wondering how it's possible to create an outbound stream ? In particular in the rtmp_publisher demo, how can I send an outboundstream into the createOutboundStreamChan ? Perhaps I can give more details on what I want to do. I want to create to simply create a connection to an rtmp url and send data to it, is this possible using the publisher demo, and if so how can I create a stream to use stream.PublishData ?? What is stream?

Regards,
Saxon

Socks4/5 support

Perhaps Socks 4/5 proxy support could be a nice addition to this Go package?

Just a suggestion, feel free to add the "enhancement" label.

Publish rtmp stream fails [rtmp to rtmp]

I am using rtmp_player to read a rtmp stream and publish it to another RTMP server using rtmp_publish

What to pass as argument to stream.PublishData(tagHeader.TagType, data, deltaTimestamp) ?

I receive the rtmp stream with Message struct from OnReceived(rconn rtmp.Conn, message *rtmp.Message)

type Message struct {
	ChunkStreamID     uint32
	Timestamp         uint32
	Size              uint32
	Type              uint8
	StreamID          uint32
	Buf               *bytes.Buffer
	IsInbound         bool
	AbsoluteTimestamp uint32
}

When I publish directly with stream.PublishData(msg.Type,msg.Buf.Bytes(),msg.Timestamp)

The rtmp stream is automatically closed just after the stream is accepted.

Simple steps to reproduce this : (I am doing it live by establishing a tcp socket and forwarding the packets, the same behavior is exhibited when I save to file and use the file to publish)

./player -URL rtmp://188.138.17.8:1935/albuk -Stream albuk.stream -DumpFLV ./demo.flv

./publish -URL rtmp://myserver:1935/<path>/ -Stream <name> -FLV ./demo.flv
I get the following output

to dial
a
b
to connect
c
@@@@@@@@@@@@@status: 3, err: <nil>
ReceviedRtmpCommand: &{IsFlex:false Name:_result TransactionID:1 Objects:[map[fmsVer:FMS/3,0,1,123 capabilities:31] map[code:NetConnection.Connect.Success description:Connection succeeded. objectEncoding:0 level:status]]}
@@@@@@@@@@@@@status: 5, err: <nil>
Stream created: 1
ReceviedRtmpCommand: &{IsFlex:false Name:_result TransactionID:2 Objects:[<nil> 1]}
1
2
3
3333@@@@@@@@@@@@@@diff1 header(&{TagType:18 DataSize:40 Timestamp:0}), startTs: 0
18 40 0 0
3333@@@@@@@@@@@@@@diff1 header(&{TagType:9 DataSize:44 Timestamp:0}), startTs: 0
9 44 0 0
3333@@@@@@@@@@@@@@diff1 header(&{TagType:9 DataSize:2 Timestamp:0}), startTs: 0
9 2 0 0
3333@@@@@@@@@@@@@@diff1 header(&{TagType:9 DataSize:23332 Timestamp:0}), startTs: 0
9 23332 0 0
3333@@@@@@@@@@@@@@diff1 header(&{TagType:9 DataSize:55 Timestamp:0}), startTs: 0
9 55 0 0
3333@@@@@@@@@@@@@@diff1 header(&{TagType:9 DataSize:5658 Timestamp:0}), startTs: 0
9 5658 0 0
3333@@@@@@@@@@@@@@diff1 header(&{TagType:9 DataSize:120 Timestamp:0}), startTs: 0
9 120 0 0
3333@@@@@@@@@@@@@@diff1 header(&{TagType:9 DataSize:5334 Timestamp:0}), startTs: 0
9 5334 0 0
.
.
.
9 47 200 204
8 554 209 213
9 7857 220 224
8 555 231 235
@@@@@@@@@@@@@status: 0, err: <nil>
@@@@@@@@@@@@@Closed
Audio size: 6494 bytes; Vedio size: 380281 bytes
Audio size: 6494 bytes; Vedio size: 380281 bytes

There is no video stream running.

rtmp receive bytes are always 0 from a live stream

rtmp:rtmp://188.138.17.8:1935/albuk/albuk.stream stream:stream_name flv:./video_dump
to dial
@@@@@@@@@@@@@status: 1, err: <nil>
obConn: &{url:rtmp://188.138.17.8:1935/albuk/albuk.stream rtmpURL:{protocol:rtmp host:188.138.17.8 port:1935 app:albuk instanceName:albuk.stream} status:1 err:<nil> handler:0x7760b0 conn:0xc42000a900 transactions:map[] streams:map[]}
obConn.URL(): rtmp://188.138.17.8:1935/albuk/albuk.stream
to connect
@@@@@@@@@@@@@status: 3, err: <nil>
ReceviedCommand: &{IsFlex:false Name:_result TransactionID:1 Objects:[map[capabilities:31 mode:1 fmsVer:FMS/3,5,7,7009] map[objectEncoding:0 level:status code:NetConnection.Connect.Success description:Connection succeeded. data:map[version:3,5,7,7009] clientid:9.77161e+06]]}
@@@@@@@@@@@@@status: 5, err: <nil>
Stream created: 1
ReceviedCommand: &{IsFlex:false Name:_result TransactionID:2 Objects:[<nil> 1]}
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes

Am I running or setting it up wrong?

Send RPC command to server

I cant input zhongwen, so I will ask in English.
I want to send command to FMS.
But I have noticed that the outboundconnection.Call is unimplemented.

Can you give me some advice.
By the way , thank you for this library. It help me a lot.

The real request looks like this.

image

can not real push data to wowza

I have already created a stream to wowza, but use OutboundStream.PublishVideoData or OutboundStream.PublishAudioData can not real push data to wowza. Stream status is active but Bytes In is 0. There is no err return.

What can I do for check this error.

rtmp publish panic

$ ./rtmp_publisher -FLV test.flv -Stream test -URL "rtmp://ossrs.net:1935/live"

to dial
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x50 pc=0x2068]

goroutine 1 [running]:
panic(0x1c19a0, 0xc4200140c0)
/usr/local/Cellar/go/1.7/libexec/src/runtime/panic.go:500 +0x1a1
main.(*TestOutboundConnHandler).OnStatus(0x2f7050, 0x2c4b40, 0xc420098280)
/Users/xxx/go/src/github.com/zhangpeihao/gortmp/demo/publisher/rtmp_publisher.go:38 +0x28
github.com/zhangpeihao/gortmp.Dial(0x7fff5fbffa69, 0x1a, 0x2c3ee0, 0x2f7050, 0x64, 0x0, 0x0, 0x3c, 0x15180)
/Users/xxx/go/src/github.com/zhangpeihao/gortmp/outboundconn.go:109 +0x604
main.main()
/Users/xxx/go/src/github.com/zhangpeihao/gortmp/demo/publisher/rtmp_publisher.go:138 +0x226

publish 时, 碰到 音频和视频解码步骤不一致, 只听到音频, 看不到视频

header.Timestamp: 5408, now: 1472553720757848290
diff1: 5408
== publishdata: 8 5408
diff1: 5440
== publishdata: 8 5440
diff1: 5472
== publishdata: 8 5472
diff1: 5504
== publishdata: 8 5504
header.Timestamp: 5536, now: 1472553720886429117
diff1: 5536
== publishdata: 8 5536
== diff1
diff1: 0
== publishdata: 9 0
diff1: 5568
== publishdata: 8 5568
diff1: 5600
== publishdata: 8 5600
diff1: 5632
== publishdata: 8 5632
header.Timestamp: 5664, now: 1472553721016424239
Audio size: 284381 bytes; Vedio size: 1713772 bytes
diff1: 68
== publishdata: 9 68
diff1: 5664
== publishdata: 8 5664
diff1: 5696
== publishdata: 8 5696
diff1: 5728
== publishdata: 8 5728
diff1: 168
== publishdata: 9 168
diff1: 5760
== publishdata: 8 5760

Segfault

Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0x7ffff701a700 (LWP 627)] 0x00000000005c5429 in github.com/zhangpeihao/log.(*Logger).ModulePrintf (logger=0x0, module=0x0, level=4, format=..., v=...) at /home/president/go/src/github.com/zhangpeihao/log/log.go:335 335

Output from gdb, trying to connect.

runtime error: invalid memory address or nil pointer dereference

Output from execution.

画面卡顿

用rtmp client拉取海康RTMP视频流时,画面卡顿,局域网之内,同时MIN_BUFFER_LENGTH也调大了,也依然有停顿的感觉,尤其是视频画面里面动作幅度比较快的情况下,请问要在哪里进行调整?

Connection reset by peer from wowza server

一開始的Handshake都有成功,但送資料給wowza server一段時間後,就會
connection reset by peer 的錯誤出現。
我們去解讀封包,發現rtmp的封包都是unknown type,不知道是不是那邊資料有送錯?
照理說應該可以知道是video type or audio type.

Smart proxy

Is it possible to make "smart" proxy?
If user connects to live stream and proxy have already clients on that stream it won't make new connection to master server but server the same data.
So if client 1 connects to live/stream1, proxy connects to master.server.org/live/stream1, then client 2 connects to live/stream1 and proxy just fanouts packets to clients 1 and 2 without making 2nd connection to master server.

Let me know how if it's easy. I'm newbie in Go :(

Is there any way of accessing flv container?

Great job on this library!

I was looking for something similar to rtmpdump link from mplayer where we could programatically access containers in rtmp and your library looks promising.

One thing that's not clear:
Is there any way of accessing the flv container from an rtmp stream using this library?

I see you've got the outboundStream struct in outboundstream.go link

Is there any way of accessing the underlying flv container?

Optional logging

Now can't run without logging into file.
Is it possible to make

func InitLogger(l *log.Logger) {
optional or add support of Go's built-in log.Logger?
Thank you )

Project dead ?

Is the project dead ? seemed very useful and promising

demo can't get video type and audio type

Hi, When i run rtmp_play.go demo, i can't get the video type and audio type.
Output is like:

@@@@@@@@@@@@@status: 1, err:
connect message in package &gortmp.Message{ChunkStreamID:0x3, Timestamp:0x0, Size:0xd5, Type:0x14, StreamID:0x0, Buf:(*bytes.Buffer)(0xc4200a83f0), IsInbound:false, AbsoluteTimestamp:0x0}@@@@@@@@@@@@@status: 3, err:
ReceviedCommand: &{IsFlex:false Name:_result TransactionID:1 Objects:[map[fmsVer:FMS/3,0,1,123 capabilities:31 mode:1] map[version:3,5,1,516 level:status code:NetConnection.Connect.Success description:Connection succeeded. objectEncoding:0 data:0]]}
ReceviedCommand: &{IsFlex:false Name:onBWDone TransactionID:0 Objects:[]}
@@@@@@@@@@@@@status: 5, err:
ReceviedCommand: &{IsFlex:false Name:_result TransactionID:2 Objects:[ 1]}
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes
@@@@@@@@@@@@@status: 0, err:
@@@@@@@@@@@@@closed

player的demo 无法正常获取数据

用player 的那个demo 做测试, 发现每次只能收获前面两次数据:
发现最后是conn.br.ReadByte()无数据, 我的测试视频源应该是没问题的, 用LVC 能正常播放.
想请教一下, 什么情况可能造成这个问题?

具体停止的位置,

ReadBaseHeader 这个方法中:

b, err = ReadByteFromNetwork(rbuf) 这里卡住了

另外有一个疑问, 我第二次收到的command 正确么? 请帮忙看看, 谢谢

=====以下是运行的log====

to dial
obConn: &{url:rtmp://XXX:1935/myapp/tt_friends?vhost=tt rtmpURL:{protocol:rtmp host:XXX port:1935 app:myapp instanceName:tt_friends?vhost=tt} status:1 err:?reflect.Value? handler:0x7a1e90 conn:0xc208080100 transactions:map[] streams:map[]}
obConn.URL(): rtmp://XXXX:1935/myapp/tt_friends?vhost=tt
to connect
sendLoop here
sendLoop here
conn.br:
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
read header 01 2
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
read header 01 5
conn.br:
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
read header 01 2
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
read header 01 6
conn.br:
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
read header 01 2
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
read header 01 1
conn.br:
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
read header 01 3
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
read header 01 20
@@@@@@@@@@@@@status: 3, err:
ReceviedCommand: &{IsFlex:false Name:_result TransactionID:1 Objects:[map[fmsVer:FMS/3,0,1,123 capabilities:31] map[code:NetConnection.Connect.Success description:Connection succeeded. objectEncoding:0 data:map[server_pid:7253 stream_id:14485083201515715713 server_ip:100.69.198.197 server_name:e100069198197.zmf] level:status]]}
conn.br:
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
sendLoop here
sendLoop here
read header 01 3
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
read header 01 20
@@@@@@@@@@@@@status: 5, err:
Stream created: 1
ReceviedCommand: &{IsFlex:false Name:_result TransactionID:2 Objects:[ 1]}
conn.br:
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
play here &{1 0xc2080520a0 8 ?reflect.Value? 0}
sendLoop here
sendLoop here
read header 01 5
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
read header 01 20
OnReceived
conn.br:
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
read header 01 5
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
read header 01 18
OnReceived
conn.br:
func ReadByteFromNetwork(r Reader) (b byte, err error)
read header 0:
Audio size: 0 bytes; Vedio size: 0 bytes
sendLoop here
Audio size: 0 bytes; Vedio size: 0 bytes
sendLoop here
Audio size: 0 bytes; Vedio size: 0 bytes
sendLoop here
Audio size: 0 bytes; Vedio size: 0 bytes
sendLoop here

What is the server used for?

I tried the demo, start the server then make the publisher connect it, but it doesn't work.

If I make the publisher connect my FMS, it works.

Does the gortmp mush be used with FMS or any other rtmp-server?

If so, what is the server used for?

is it thread safe in the use of play?

I use rtmp client to check the edge ip whether can be fetch data?

func DetectRtmp(vip string) bool {
rtmpName := "rtmp://" + vip + "/uplive.b0.upaiyun.com/live"
streamName := "jiqiang"

//fmt.Printf("%s\n", rtmp_name)
createStreamChan := make(chan rtmp.OutboundStream)
var audioSize int64 = 0
var videoSize int64 = 0
testHandler := &TestOutboundConnHandler{createStreamChan, &audioSize, &videoSize}
//tcp dial
obConn, err := rtmp.Dial(rtmpName, testHandler, 100)
if err != nil {
    //fmt.Printf("%s dial fail, err: %s\n", vip, err.Error())
    return false
}
defer obConn.Close()

//rtmp conn
if err = obConn.Connect(); err != nil {
    //fmt.Printf("%s conn fail, err: %s\n", vip, err.Error())
    return false
}

flag := true
count := 0
for {
    select {
    case stream := <-createStreamChan:
        // Play
        err = stream.Play(streamName, nil, nil, nil)
        if err != nil {
            //fmt.Printf("Play error: %s", err.Error())
            flag = false
        }
        // Set Buffer Length

    case <-time.After(1 * time.Second):
        if audioSize > 0 || videoSize > 0 {
            //fmt.Printf("Audio size: %d bytes; Vedio size: %d bytes\n", audioSize, videoSize)
        } else {
            count += 1
        }
    }

    if count > delay || !flag {
        flag = false
        break
    } else if audioSize > 0 || videoSize > 0 {
        break
    }
}

return flag

}

func Check() {
res := make(map[string]bool)
var wg sync.WaitGroup
var mutex = &sync.Mutex{}

for name, ip := range edgeList {
    wg.Add(1)
    // one go routine to handle one check
    go func(name string, ip string) {
        defer wg.Done()
        mutex.Lock()
        res[name] = false
        mutex.Unlock()
        v := DetectRtmp(ip)
        if !v {
            v = DetectRtmp(ip)
        }
        mutex.Lock()
        res[name] = v
        mutex.Unlock()
    }(name, ip)
}

wg.Wait()

fmt.Println("handle all vips")
gMutex.Lock()
for k, v := range res {
    gRes[k] = v
}
gMutex.Unlock()

}

WARNING: DATA RACE
Write by goroutine 420:
github.com/zhangpeihao/gortmp.(_conn).Close()
/root/yang/gopath/src/github.com/zhangpeihao/gortmp/conn.go:444 +0x3a
github.com/zhangpeihao/gortmp.(_outboundConn).Close.func1()
/root/yang/gopath/src/github.com/zhangpeihao/gortmp/outboundconn.go:249 +0x70

Previous read by goroutine 73:
github.com/zhangpeihao/gortmp.(*conn).sendLoop()
/root/yang/gopath/src/github.com/zhangpeihao/gortmp/conn.go:241 +0x79

Goroutine 420 (running) created at:
github.com/zhangpeihao/gortmp.(*outboundConn).Close()
/root/yang/gopath/src/github.com/zhangpeihao/gortmp/outboundconn.go:250 +0x15c
main.DetectRtmp()
/root/yang/upsrs/upsrs_api/check/server/check_srs_edge_server.go:101 +0x4c3
main.Check.func1()
/root/yang/upsrs/upsrs_api/check/server/check_srs_edge_server.go:117 +0xca

Goroutine 73 (running) created at:
github.com/zhangpeihao/gortmp.NewConn()
/root/yang/gopath/src/github.com/zhangpeihao/gortmp/conn.go:148 +0x71c
github.com/zhangpeihao/gortmp.Dial()
/root/yang/gopath/src/github.com/zhangpeihao/gortmp/outboundconn.go:109 +0xabd
main.DetectRtmp()
/root/yang/upsrs/upsrs_api/check/server/check_srs_edge_server.go:59 +0x25a
main.Check.func1()
/root/yang/upsrs/upsrs_api/check/server/check_srs_edge_server.go:117 +0xca

Publish-er demo to Twitch

Thanks for the lovely repo.

I had a go at using the ./publisher to stream to Twitch (https://www.twitch.tv/)

./publisher --FLV file.flv --URL rtmp://live.twitch.tv/app/[key]

this gives a message

to dial                                                                                                                  
a
b
to connect
c
@@@@@@@@@@@@@status: 3, err: <nil>
ReceviedRtmpCommand: &{IsFlex:false Name:_result TransactionID:1 Objects:[map[capabilities:31 mode:1 fmsVer:FMS/3,5,7,7009
] map[description:Connection accepted. data:map[string:3,5,7,7009] objectEncoding:0 level:status code:NetConnection.Connec
t.Success]]}
@@@@@@@@@@@@@status: 5, err: <nil>
Stream created: 1
ReceviedRtmpCommand: &{IsFlex:false Name:_result TransactionID:2 Objects:[<nil> 1]}
Audio size: 0 bytes; Vedio size: 0 bytes
Audio size: 0 bytes; Vedio size: 0 bytes

looks like the OnPublishStart callback does not get called

i have verified the file.flv with ffmpeg ( ffmpeg -re -i file.flv -c copy -f flv rtmp://live.twitch.tv/[...]) and it works correctly

the file was generated with ffmpeg

 ffmpeg -i input.mkv -c:v libx264 -preset medium -maxrate 3000k -bufsize 6000k -vf "scale=1280:-1,format=yuv420p" -g 50 -c:a aac -b:a 128k -ac 2 -ar 44100 file.flv

it feels like a problem with RTMP

best to my knowledge Twitch should be accessible from China

thanks for the great repo and your effort, and would be very cool if this worked with Twitch!

May I contact you?

May I contact you?I wish to pay for some features if possbile. :)
my email:yqf0215%gmail.com.
Thank you very much. Your programe is very good ! 👍

不能多个vlc同时播放

使用vlc播放视频流,每次只能有一个能播放,其余的会停止,请问怎么才能让多个vlc同时播放?

rtmp_player example is broken

Heya,

Cool package, i'm looking into recording rtmp and tried the rtmp_player, but it seams the example is broken ? Any chance you could update it ?

defines.go文件中GetTimestamp()函数的问题

  1. 下面rtmp_specification_1.0.pdf文件中关于timestamp的描述。

Because timestamps are 32 bits long, they roll over every 49 days, 17 hours, 2 minutes and 47.296 seconds. Because streams are allowed to run continuously, potentially for years on end, an RTMP application SHOULD use serial number arithmetic [RFC1982] when processing timestamps, and SHOULD be capable of handling wraparound. For example, an application assumes that all adjacent timestamps are within 2^31 - 1 milliseconds of each other, so 10000 comes after 4000000000, and 3000000000 comes before 4000000000.

上面的描述说明了的timestamp是32的无符号整数所表示的毫秒,由于该值最大只能表示不到50天的时间戳,所以需要对时间戳做环绕式处理。
2. defines.go文件中GetTimestamp的实现

466 // Get timestamp
467 func GetTimestamp() uint32 {
468     //return uint32(0)
469     return uint32(time.Now().UnixNano()/int64(1000000)) % MAX_TIMESTAMP
470 }

该函数取系统当前时间(毫秒)作为时间戳,然后与 MAX_TIMESTAMP取模,这样也确实实现的环绕处理, 但是我看到MAX_TIMESTAMP的定义如下:

278     MAX_TIMESTAMP                       = uint32(2000000000)  

正确的定义该值应该是32位无符号整数的最大值+1, 即0x100000000,defines.go文件对该值的定义的显然不对。
3. defines.go文件的第469行有一种更简单的改写方式, 如下:

469     return uint32(time.Now().UnixNano()/int64(1000000))

超过32位无符号整数的部分会被自然溢出,我们强制转换得到溢出后剩下的部分,即实现了环绕,也相当于对0x100000000做取模操作。

Connect issues

I'm trying to connect to a Tinychat server, and sending the room as the first connection parameter, without success.

func main() {
    l := log.NewStderrLogger()
    l.SetMainLevel(4)
    defer l.Close()
    rtmp.InitLogger(l)
    handler := &ConnHandler{}
    obConn, err := rtmp.Dial("rtmp://host:port/tinyconf", handler, 100)
    if err != nil {
        fmt.Printf("Conn err: %s\n", err)
        os.Exit(1)
    }
    defer obConn.Close()

    err = obConn.Connect("ROOM", "none", "show", "tinychat")
    if err != nil {
        fmt.Printf("Conn err: %s\n", err)
        os.Exit(1)
    }
    for {
    }
}

Output:

2015/05/04 14:21:03 Handshake() FMS version is 0.0.0.0
2015/05/04 14:21:03 Buffer(signatureResp):
09 0c ef 72 3e 06 5a af  8b 47 cf 21 1c dc 96 e3 
ff 41 3c b8 61 84 fb 50  c1 06 6a 60 3a 83 f4 53 


2015/05/04 14:21:03 Handshake OK
2015/05/04 14:21:03 Message(connect){CID: 3, Type: 20, Timestamp: 0, Size: 244, StreamID: 0, IsInbound: false, AbsoluteTimestamp: 0}

Any ideas?

demo里server无法接收ffmpeg的推流

运行demo的server后,执行命令ffmpeg -re -i test.mp4 -c copy -f flv rtmp://localhost/app
就一直停留在那,不会继续跑下去了?不知道为何,下面是log的信息:

2016/09/01 23:28:21 ######## Profiles #######
--- contention:
cycles/second=2261009062
goroutine profile: total 4
1 @ 0x55ce18 0x55cbf3 0x558484 0x4bbc3d 0x4bbab9 0x4bb2e4 0x4b9bc2 0x401a7b 0x4308b0 0x4601e1
#   0x55ce18    runtime/pprof.writeRuntimeProfile+0xb8          /home/bao/go/src/runtime/pprof/pprof.go:545
#   0x55cbf3    runtime/pprof.writeGoroutine+0x93           /home/bao/go/src/runtime/pprof/pprof.go:507
#   0x558484    runtime/pprof.(*Profile).WriteTo+0xd4           /home/bao/go/src/runtime/pprof/pprof.go:236
#   0x4bbc3d    github.com/zhangpeihao/log.(*Logger).DumpProf+0x13d /home/bao/gowork/src/github.com/zhangpeihao/log/log.go:146
#   0x4bbab9    github.com/zhangpeihao/log.(*Logger).DumpHeader+0x109   /home/bao/gowork/src/github.com/zhangpeihao/log/log.go:137
#   0x4bb2e4    github.com/zhangpeihao/log.NewLoggerWithHeader+0x1704   /home/bao/gowork/src/github.com/zhangpeihao/log/log.go:116
#   0x4b9bc2    github.com/zhangpeihao/log.NewLogger+0xa2       /home/bao/gowork/src/github.com/zhangpeihao/log/log.go:55
#   0x401a7b    main.main+0xab                      /home/bao/bao/program/go/gortmp-master/demo/server/server.go:95
#   0x4308b0    runtime.main+0x2b0                  /home/bao/go/src/runtime/proc.go:188

1 @ 0x4601e1

1 @ 0x41104e 0x443892 0x47ee78 0x4601e1
#   0x443892    os/signal.signal_recv+0x132 /home/bao/go/src/runtime/sigqueue.go:116
#   0x47ee78    os/signal.loop+0x18     /home/bao/go/src/os/signal/signal_unix.go:22

1 @ 0x430c93 0x43f767 0x43ecc2 0x4be721 0x4601e1
#   0x4be721    github.com/zhangpeihao/log.(*Logger).counterDump+0x1721 /home/bao/gowork/src/github.com/zhangpeihao/log/log.go:360

heap profile: 0: 0 [0: 0] @ heap/1048576

# runtime.MemStats
# Alloc = 155936
# TotalAlloc = 155936
# Sys = 1937408
# Lookups = 7
# Mallocs = 648
# Frees = 68
# HeapAlloc = 155936
# HeapSys = 688128
# HeapIdle = 98304
# HeapInuse = 589824
# HeapReleased = 0
# HeapObjects = 580
# Stack = 360448 / 360448
# MSpan = 8280 / 16384
# MCache = 4800 / 16384
# BuckHashSys = 2184
# NextGC = 4194304
# PauseNs = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
# NumGC = 0
# EnableGC = true
# DebugGC = false
threadcreate profile: total 8
8 @

######## Heap #######
heap profile: 0: 0 [0: 0] @ heap/1048576

# runtime.MemStats
# Alloc = 195664
# TotalAlloc = 195664
# Sys = 1937408
# Lookups = 7
# Mallocs = 742
# Frees = 98
# HeapAlloc = 195664
# HeapSys = 688128
# HeapIdle = 40960
# HeapInuse = 647168
# HeapReleased = 0
# HeapObjects = 644
# Stack = 360448 / 360448
# MSpan = 8640 / 16384
# MCache = 4800 / 16384
# BuckHashSys = 2184
# NextGC = 4194304
# PauseNs = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
# NumGC = 0
# EnableGC = true
# DebugGC = false
######## End #######
2016/09/01 23:28:21 Start listen...
2016/09/01 23:28:31 Handshake begin
2016/09/01 23:28:31 SHandshake() Flash player version is 9.0.124.2
2016/09/01 23:28:31 SHandshake() scheme = 0
2016/09/01 23:28:31 Buffer(SHandshake signatureResp):
b1 87 a0 e7 00 12 fc da  28 93 2b 6b a6 b9 c7 59 
5b 11 33 7d ce 58 f2 70  5a 91 f6 bd 4b b6 b8 f6 


2016/09/01 23:28:31 New stream 1 csi: 3, fmt: 0
2016/09/01 23:28:31 New stream 2 csi: 3, fmt: 0, header: &{Fmt:0 ChunkStreamID:3 Timestamp:0 MessageLength:137 MessageTypeID:20 MessageStreamID:0 ExtendedTimestamp:0}
2016/09/01 23:28:31 Unfinish message(remain: 137, chunksize: 128)
2016/09/01 23:28:31 Message(<<<){CID: 3, Type: 20, Timestamp: 0, Size: 137, StreamID: 0, IsInbound: true, AbsoluteTimestamp: 0}
2016/09/01 23:28:31 conn::invokeCommand()
2016/09/01 23:28:31 Command{IsFlex: false, Name: connect, TransactionID: 1, Objects: [map[app:app type:nonprivate flashVer:FMLE/3.0 (compatible; Lavf57.48.101) tcUrl:rtmp://localhost:1935/app]]}
2016/09/01 23:28:31 inboundConn::onConnect
2016/09/01 23:28:31 conn::SetWindowAcknowledgementSize
2016/09/01 23:28:31 conn::SetPeerBandwidth
2016/09/01 23:28:31 conn::SetChunkSize(size: 4096)
2016/09/01 23:28:31 Message(sendConnectResult){CID: 3, Type: 20, Timestamp: 0, Size: 165, StreamID: 0, IsInbound: false, AbsoluteTimestamp: 0}
2016/09/01 23:28:31 OutboundChunkStream::NewOutboundHeader() header: &{Fmt:0 ChunkStreamID:2 Timestamp:0 MessageLength:4 MessageTypeID:5 MessageStreamID:0 ExtendedTimestamp:0}
2016/09/01 23:28:31 OutboundChunkStream::NewOutboundHeader() header: &{Fmt:1 ChunkStreamID:2 Timestamp:0 MessageLength:5 MessageTypeID:6 MessageStreamID:0 ExtendedTimestamp:0}
2016/09/01 23:28:31 OutboundChunkStream::NewOutboundHeader() header: &{Fmt:1 ChunkStreamID:2 Timestamp:0 MessageLength:4 MessageTypeID:1 MessageStreamID:0 ExtendedTimestamp:0}
2016/09/01 23:28:31 OutboundChunkStream::NewOutboundHeader() header: &{Fmt:0 ChunkStreamID:3 Timestamp:0 MessageLength:165 MessageTypeID:20 MessageStreamID:0 ExtendedTimestamp:0}
2016/09/01 23:28:31 New stream 1 csi: 2, fmt: 0
2016/09/01 23:28:31 New stream 2 csi: 2, fmt: 0, header: &{Fmt:0 ChunkStreamID:2 Timestamp:0 MessageLength:4 MessageTypeID:1 MessageStreamID:0 ExtendedTimestamp:0}
2016/09/01 23:28:31 Message(<<<){CID: 2, Type: 1, Timestamp: 0, Size: 4, StreamID: 0, IsInbound: true, AbsoluteTimestamp: 0}
2016/09/01 23:28:31 conn::invokeSetChunkSize() conn.inChunkSize = 4096
2016/09/01 23:28:31 Message(<<<){CID: 3, Type: 20, Timestamp: 0, Size: 29, StreamID: 0, IsInbound: true, AbsoluteTimestamp: 0}
2016/09/01 23:28:31 conn::invokeCommand()
2016/09/01 23:28:31 Command{IsFlex: false, Name: releaseStream, TransactionID: 2, Objects: [<nil> ]}
2016/09/01 23:28:31 inboundConn::ReceivedRtmpCommand: &{IsFlex:false Name:releaseStream TransactionID:2 Objects:[<nil> ]}
2016/09/01 23:28:31 Message(<<<){CID: 3, Type: 20, Timestamp: 0, Size: 25, StreamID: 0, IsInbound: true, AbsoluteTimestamp: 0}
2016/09/01 23:28:31 conn::invokeCommand()
2016/09/01 23:28:31 Command{IsFlex: false, Name: FCPublish, TransactionID: 3, Objects: [<nil> ]}
2016/09/01 23:28:31 inboundConn::ReceivedRtmpCommand: &{IsFlex:false Name:FCPublish TransactionID:3 Objects:[<nil> ]}
2016/09/01 23:28:31 Message(<<<){CID: 3, Type: 20, Timestamp: 0, Size: 25, StreamID: 0, IsInbound: true, AbsoluteTimestamp: 0}
2016/09/01 23:28:31 conn::invokeCommand()
2016/09/01 23:28:31 Command{IsFlex: false, Name: createStream, TransactionID: 4, Objects: [<nil>]}
2016/09/01 23:28:31 inboundConn::onCreateStream
2016/09/01 23:28:31 index: 0, newChunkStreamID: 8
2016/09/01 23:28:31 Message(sendCreateStreamSuccessResult){CID: 3, Type: 20, Timestamp: 0, Size: 29, StreamID: 0, IsInbound: false, AbsoluteTimestamp: 0}
2016/09/01 23:28:31 OutboundChunkStream::NewOutboundHeader() header: &{Fmt:1 ChunkStreamID:3 Timestamp:0 MessageLength:29 MessageTypeID:20 MessageStreamID:0 ExtendedTimestamp:0}
2016/09/01 23:28:31 New stream 1 csi: 8, fmt: 0
2016/09/01 23:28:31 New stream 2 csi: 8, fmt: 0, header: &{Fmt:0 ChunkStreamID:8 Timestamp:0 MessageLength:30 MessageTypeID:20 MessageStreamID:1 ExtendedTimestamp:0}
2016/09/01 23:28:31 Message(<<<){CID: 8, Type: 20, Timestamp: 0, Size: 30, StreamID: 1, IsInbound: true, AbsoluteTimestamp: 0}

vlc卡顿

按照demo/server, 建立的rtmp服务器用vlc播放卡顿!
尝试把 if diff1 > diff2+100 { 改为 if diff1 > diff2 { 有所改善, 但依旧卡的不行

How to publish MetaData(eg: subtitle) with each video frame?

Hi,
I publish one text string after each video frame use message type id 18 (0x13) for AMF3 encoding, but make the stream closed. And I have tried message type id 15 (0x0f) for AMF0 encoding, it made the stream closed too.

the codes i make in demo/publisher as following:

	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
	}
	if header.TagType == flv.VIDEO_TAG {
		subTitleHeader := *header
		subTitleHeader.TagType = byte(0x13)
		subTitle := fmt.Sprintf("+++ video frame Timestamp:%d +++\n", subTitleHeader.Timestamp)
		subTitleData := make([]byte, len(subTitle)+1)
		subTitleHeader.DataSize = uint32(len(subTitle))
		copy(subTitleData, subTitle[:])
		subTitleData[len(subTitle)] = 0x00
			if err = stream.PublishData(subTitleHeader.TagType, subTitleData, diff1); err != nil {
				fmt.Println("PublishData() subtitle error:", err)
				break
			}
	}

The error logs I got:
ray@TF:/md/gows/src/github.com/falconray0704/gortmp/demo/publisher$ ./rtmp_publisher -URL "rtmp://10.1.51.20:1935/myapp/" -Stream cv -FLV "/md/videos/aWalkToUnionSquare.flv"
to dial
a
b
to connect
c
@@@@@@@@@@@@@status: 3, err:
ReceviedRtmpCommand: &{IsFlex:false Name:_result TransactionID:1 Objects:[map[fmsVer:FMS/3,0,1,123 capabilities:31] map[level:status code:NetConnection.Connect.Success description:Connection succeeded. objectEncoding:0]]}
@@@@@@@@@@@@@status: 5, err:
Stream created: 1
ReceviedRtmpCommand: &{IsFlex:false Name:_result TransactionID:2 Objects:[ 1]}
1
2
3
@@@@@@@@@@@@@@Diff1 header(&{TagType:18 DataSize:372 Timestamp:0}), startTs: 0
@@@@@@@@@@@@@@Diff1 header(&{TagType:18 DataSize:372 Timestamp:0}), startTs: 0
@@@@@@@@@@@@@@Diff1 header(&{TagType:8 DataSize:418 Timestamp:0}), startTs: 0
@@@@@@@@@@@@@@Diff1 header(&{TagType:8 DataSize:418 Timestamp:0}), startTs: 0
@@@@@@@@@@@@@@Diff1 header(&{TagType:9 DataSize:180804 Timestamp:25}), startTs: 25
@@@@@@@@@@@@@@Diff1 header(&{TagType:9 DataSize:180804 Timestamp:25}), startTs: 25
@@@@@@@@@@@@@@Diff1 header(&{TagType:8 DataSize:419 Timestamp:26}), startTs: 25
@@@@@@@@@@@@@@Diff1 header(&{TagType:8 DataSize:419 Timestamp:52}), startTs: 25
@@@@@@@@@@@@@@Diff1 header(&{TagType:9 DataSize:216201 Timestamp:59}), startTs: 25
@@@@@@@@@@@@@@Diff1 header(&{TagType:8 DataSize:419 Timestamp:78}), startTs: 25
@@@@@@@@@@@@@@Diff1 header(&{TagType:9 DataSize:64624 Timestamp:94}), startTs: 25
@@@@@@@@@@@@@@Diff1 header(&{TagType:8 DataSize:419 Timestamp:104}), startTs: 25
@@@@@@@@@@@@@@Diff1 header(&{TagType:9 DataSize:43542 Timestamp:128}), startTs: 25
@@@@@@@@@@@@@status: 0, err:
@@@@@@@@@@@@@closed
Audio size: 2094 bytes; Vedio size: 505171 bytes
Audio size: 2094 bytes; Vedio size: 505171 bytes
^C
ray@TF:/md/gows/src/github.com/falconray0704/gortmp/demo/publisher$

Actually I want to streaming subtitle for each video frame with the same timestamp.
Which way could I make it?

Thanks.

请问如何基于go和rtmp传输音频文件

RT,我是个编程萌新,看了半天大神的代码还是不得其法,所以实在不得以做了伸手,请问该如何基于go和rtmp传输音频文件,麻烦了,谢谢。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.