目录
前言
最近研究golang定制化开发音视频处理的时候,试着将mp4推送服务。定制化开发下面分享一下代码,定制化开发大家有需要可以研究一下,按照自己的需求改改。
环境
需要安装:github.com/yapingcat/gomedia
代码
代码如下:
- package main
-
- import (
- "fmt"
- "github.com/yapingcat/gomedia/go-codec"
- "github.com/yapingcat/gomedia/go-mp4"
- "github.com/yapingcat/gomedia/go-rtmp"
- "io"
- "net"
- "os"
- "time"
- )
-
- func main() {
- var (
- mp4Path = "./data/movie1.mp4"
- rtmpUrl = "rtmp://192.168.5.97:1935/live/home"
- )
- c, err := net.Dial("tcp4", "192.168.5.97:1935")
- if err != nil {
- fmt.Println(err)
- }
- cli := rtmp.NewRtmpClient(rtmp.WithComplexHandshake(),
- rtmp.WithComplexHandshakeSchema(rtmp.HANDSHAKE_COMPLEX_SCHEMA1),
- rtmp.WithEnablePublish())
- cli.OnError(func(code, describe string) {
- fmt.Printf("rtmp code:%s ,describe:%s\", code, describe)
- })
- isReady := make(chan struct{})
- cli.OnStatus(func(code, level, describe string) {
- fmt.Printf("rtmp onstatus code:%s ,level %s ,describe:%s\", code, 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")
- PushRtmp(mp4Path, cli)
- }()
-
- cli.Start(rtmpUrl)
- buf := make([]byte, 4096)
- n := 0
- for err == nil {
- n, err = c.Read(buf)
- if err != nil {
- continue
- }
- cli.Input(buf[:n])
- }
- fmt.Println(err)
- }
-
- func PushRtmp(fileName string, cli *rtmp.RtmpClient) {
- mp4File, err := os.Open(fileName)
- if err != nil {
- fmt.Println(err)
- return
- }
- defer mp4File.Close()
- demuxer := mp4.CreateMp4Demuxer(mp4File)
- if infos, err := demuxer.ReadHead(); err != nil && err != io.EOF {
- fmt.Println(err)
- } else {
- fmt.Printf("%+v\", infos)
- }
- mp4info := demuxer.GetMp4Info()
- fmt.Printf("%+v\", mp4info)
- for {
- pkg, err := demuxer.ReadPacket()
- if err != nil {
- fmt.Println(err)
- break
- }
- if pkg.Cid == mp4.MP4_CODEC_H264 {
- time.Sleep(30 * time.Millisecond)
- cli.WriteVideo(codec.CODECID_VIDEO_H264, pkg.Data, uint32(pkg.Pts), uint32(pkg.Dts))
- } else if pkg.Cid == mp4.MP4_CODEC_AAC {
- cli.WriteAudio(codec.CODECID_AUDIO_AAC, pkg.Data, uint32(pkg.Pts), uint32(pkg.Dts))
- } else if pkg.Cid == mp4.MP4_CODEC_MP3 {
- cli.WriteAudio(codec.CODECID_AUDIO_MP3, pkg.Data, uint32(pkg.Pts), uint32(pkg.Dts))
- }
- }
- }
代码说明:
1、如果是其他格式的话,可以按照库里其他格式构建。
2、为什么在视频帧推送要睡30ms,可以按照调整,因为读取的速度比较快,会推太快。
执行结果:
onstatus code:NetStream.Publish.Start ,level Started publishing stream. ,describe:%!s(MISSING)
ready for publish
start to read file
[{Duration:299925 TrackId:1 Cid:1 Height:1080 Width:1920 SampleRate:0 SampleSize:0 ChannelCount:0 Timescale:24000 StartDts:0 EndDts:299882} {Duration:299990 TrackId:2 Cid:102 Height:0 Width:0 SampleRate:48000 SampleSize:16 ChannelCount:2 Timescale:48000 StartDts:0 EndDts:299968}]
{MajorBrand:1836020585 MinorVersion:512 CompatibleBrands:[1836020585 846164841 828601953 825520237] Duration:299990 Timescale:1000 CreateTime:0 ModifyTime:0}
拉流画面:
这个代码主要只是简单的推流,没有太多对视频帧的处理。
如果有需要的话,可以自己集成一些其他的图像处理的库。
可以实现实时的视频处理并推送的功能。
总结
最近在读卡耐基的《人性的弱点》,收获很多。
分享:
人生最重要的不是以你的所得投资,任何人都可以这样做。真正重要的是如何从损失中获利。这才需要智慧,才能显示出人的上智下愚。——《人性的弱点》