-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
关于动态加载mp4视频推流到rtmp,切换卡顿的问题 #120
Comments
还有 示例中的,time.Sleep(20 * time.Millisecond) 是否和帧率有关? |
经过测试,我发现,1.mp4 切换 2.mp4 一直到5.mp4 过程中并没有卡顿。 目前遇到的问题是,当推流到2.mp4之后,会出现音画不同步的现象。这个如何处理呢 |
如果可以,按照帧率推送 |
mp4文件提供一下? |
可以 ,我先贴上代码,我一直在想是不是adjust方法的问题,但是不太了解这个纠正机制。 package main
import (
"fmt"
"io"
"net"
"os"
"time"
"github.com/yapingcat/gomedia/go-codec"
"github.com/yapingcat/gomedia/go-mp4"
"github.com/yapingcat/gomedia/go-rtmp"
)
type TimestampAdjust struct {
lastTimeStamp int64
adjust_timestamp int64
}
func newTimestampAdjust() *TimestampAdjust {
return &TimestampAdjust{
lastTimeStamp: -1,
adjust_timestamp: 0,
}
}
// timestamp in millisecond
func (adjust *TimestampAdjust) adjust(timestamp int64) int64 {
if adjust.lastTimeStamp == -1 {
adjust.adjust_timestamp = timestamp
adjust.lastTimeStamp = timestamp
return adjust.adjust_timestamp
}
delta := timestamp - adjust.lastTimeStamp
if delta < -1000 || delta > 1000 {
adjust.adjust_timestamp = adjust.adjust_timestamp + 1
} else {
adjust.adjust_timestamp = adjust.adjust_timestamp + delta
}
adjust.lastTimeStamp = timestamp
return adjust.adjust_timestamp
}
var video_pts_adjust *TimestampAdjust = newTimestampAdjust()
var video_dts_adjust *TimestampAdjust = newTimestampAdjust()
var audio_ts_adjust *TimestampAdjust = newTimestampAdjust()
// Will push the last file under mp4sPath to the specified rtmp server
func main() {
var (
mp4Path = "/Users/nicole/work/go/src/song/" //like ./mp4/
rtmpUrl = "rtmp://127.0.0.1:1935/live/test110" //like rtmp://127.0.0.1:1935/live/test110
)
c, err := net.Dial("tcp4", "127.0.0.1:1935") // like 127.0.0.1:1935
if err != nil {
fmt.Println("ininin", err)
}
cli := rtmp.NewRtmpClient(rtmp.WithComplexHandshake(),
rtmp.WithComplexHandshakeSchema(rtmp.HANDSHAKE_COMPLEX_SCHEMA0),
rtmp.WithEnablePublish())
cli.OnError(func(code, describe string) {
fmt.Printf("rtmp code:%s ,describe:%s\n", code, describe)
})
isReady := make(chan struct{})
cli.OnStatus(func(code, level, describe string) {
fmt.Printf("rtmp onstatus code:%s ,level %s ,describe:%s\n", code, level, describe)
})
cli.OnStateChange(func(newState rtmp.RtmpState) {
if newState == rtmp.STATE_RTMP_PUBLISH_START {
fmt.Println("ready for publish")
close(isReady)
}
})
cli.SetOutput(func(bytes []byte) error {
_, err := c.Write(bytes)
return err
})
go func() {
<-isReady
fmt.Println("start to read file")
next := 1
for {
filees, err := os.ReadDir(mp4Path)
if err != nil {
fmt.Println("===============end")
fmt.Println(err)
return
}
for k, _ := range filees {
nextName := fmt.Sprintf("s%v.mp4", next)
if filees[k].Name() == nextName {
fmt.Printf("----------found !!!! %v\n", nextName)
PushRtmp(mp4Path+filees[k].Name(), cli)
next++
} else {
// 直接循环推送。
next = 1
}
}
}
}()
cli.Start(rtmpUrl)
buf := make([]byte, 4096)
n := 0
for err == nil {
n, err = c.Read(buf)
if err != nil {
continue
}
fmt.Println("read byte", n)
cli.Input(buf[:n])
}
fmt.Println(err)
}
func PushRtmp(fileName string, cli *rtmp.RtmpClient) {
mp4File, err := os.Open(fileName)
if err != nil {
fmt.Printf("nilerr:%v\n", err)
return
}
defer mp4File.Close()
demuxer := mp4.CreateMp4Demuxer(mp4File)
if infos, err := demuxer.ReadHead(); err != nil && err != io.EOF {
fmt.Printf("err:%v\n", err)
} else {
fmt.Printf("infos: %+v\n", infos)
}
mp4info := demuxer.GetMp4Info()
fmt.Printf("%+v\n", mp4info)
// var video_pts_adjust *TimestampAdjust = newTimestampAdjust()
// var video_dts_adjust *TimestampAdjust = newTimestampAdjust()
// var audio_ts_adjust *TimestampAdjust = newTimestampAdjust()
for {
pkg, err := demuxer.ReadPacket()
if err != nil {
fmt.Println("demuxerr:%v\n", err)
break
}
//fmt.Println("end:%v\n", err)
if pkg.Cid == mp4.MP4_CODEC_H264 {
time.Sleep(20 * time.Millisecond)
pts := video_pts_adjust.adjust(int64(pkg.Pts))
dts := video_dts_adjust.adjust(int64(pkg.Dts))
cli.WriteVideo(codec.CODECID_VIDEO_H264, pkg.Data, uint32(pts), uint32(dts))
} else if pkg.Cid == mp4.MP4_CODEC_AAC {
pts := audio_ts_adjust.adjust(int64(pkg.Pts))
cli.WriteAudio(codec.CODECID_AUDIO_AAC, pkg.Data, uint32(pts), uint32(pts))
} else if pkg.Cid == mp4.MP4_CODEC_MP3 {
pts := audio_ts_adjust.adjust(int64(pkg.Pts))
cli.WriteAudio(codec.CODECID_AUDIO_MP3, pkg.Data, uint32(pts), uint32(pts))
}
}
}
|
如以上我的代码和视频文件,关于示例代码我只改了 读取files那一部分,把文件下到本地的song目录,可以看一下,循环推流后,观看直播过了第一个之后就开始陆续就不同步了。 |
这些视频文件,video和audio的duration 并不相等,有几百毫秒的差距,而且存在B 帧 |
谢谢,这几个视频是我从一个视频用ffmpeg直接切10秒做的一个demo,正常来讲,如果每一个视频 的video和audio ,duration相等的话,用这段代码是没有问题的吗 |
切片的时候,需要重新编码,不要编码B帧 |
好的。 我大概着了一些资料 ,用 重新编码视频 不要b帧可以使用这个命令吧? 我先试试 |
请问这个库里面有推流清晰度的选项吗 |
没有,这个库只是做文件容器格式的转换, |
我看到您 最近提交的示例代码1b855b02fa0d0b53d2ca9d9a1382ce08914905bd,
我本人在做一个动态生成mp4视频,然后按顺序推流,相当于一边生成一边推流,我看我可以直接改一下接收的代码就能实现,但是感觉上这个做不到无缝?
The text was updated successfully, but these errors were encountered: