定制化开发Go语学习笔记 - 实现将mp4通过rtmp推送流媒体服务

目录


前言

最近研究golang定制化开发音视频处理的时候,试着将mp4推送服务。定制化开发下面分享一下代码,定制化开发大家有需要可以研究一下,按照自己的需求改改。

环境

需要安装:github.com/yapingcat/gomedia

代码

代码如下:

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/yapingcat/gomedia/go-codec"
  5. "github.com/yapingcat/gomedia/go-mp4"
  6. "github.com/yapingcat/gomedia/go-rtmp"
  7. "io"
  8. "net"
  9. "os"
  10. "time"
  11. )
  12. func main() {
  13. var (
  14. mp4Path = "./data/movie1.mp4"
  15. rtmpUrl = "rtmp://192.168.5.97:1935/live/home"
  16. )
  17. c, err := net.Dial("tcp4", "192.168.5.97:1935")
  18. if err != nil {
  19. fmt.Println(err)
  20. }
  21. cli := rtmp.NewRtmpClient(rtmp.WithComplexHandshake(),
  22. rtmp.WithComplexHandshakeSchema(rtmp.HANDSHAKE_COMPLEX_SCHEMA1),
  23. rtmp.WithEnablePublish())
  24. cli.OnError(func(code, describe string) {
  25. fmt.Printf("rtmp code:%s ,describe:%s\", code, describe)
  26. })
  27. isReady := make(chan struct{})
  28. cli.OnStatus(func(code, level, describe string) {
  29. fmt.Printf("rtmp onstatus code:%s ,level %s ,describe:%s\", code, describe)
  30. })
  31. cli.OnStateChange(func(newState rtmp.RtmpState) {
  32. if newState == rtmp.STATE_RTMP_PUBLISH_START {
  33. fmt.Println("ready for publish")
  34. close(isReady)
  35. }
  36. })
  37. cli.SetOutput(func(bytes []byte) error {
  38. _, err := c.Write(bytes)
  39. return err
  40. })
  41. go func() {
  42. <-isReady
  43. fmt.Println("start to read file")
  44. PushRtmp(mp4Path, cli)
  45. }()
  46. cli.Start(rtmpUrl)
  47. buf := make([]byte, 4096)
  48. n := 0
  49. for err == nil {
  50. n, err = c.Read(buf)
  51. if err != nil {
  52. continue
  53. }
  54. cli.Input(buf[:n])
  55. }
  56. fmt.Println(err)
  57. }
  58. func PushRtmp(fileName string, cli *rtmp.RtmpClient) {
  59. mp4File, err := os.Open(fileName)
  60. if err != nil {
  61. fmt.Println(err)
  62. return
  63. }
  64. defer mp4File.Close()
  65. demuxer := mp4.CreateMp4Demuxer(mp4File)
  66. if infos, err := demuxer.ReadHead(); err != nil && err != io.EOF {
  67. fmt.Println(err)
  68. } else {
  69. fmt.Printf("%+v\", infos)
  70. }
  71. mp4info := demuxer.GetMp4Info()
  72. fmt.Printf("%+v\", mp4info)
  73. for {
  74. pkg, err := demuxer.ReadPacket()
  75. if err != nil {
  76. fmt.Println(err)
  77. break
  78. }
  79. if pkg.Cid == mp4.MP4_CODEC_H264 {
  80. time.Sleep(30 * time.Millisecond)
  81. cli.WriteVideo(codec.CODECID_VIDEO_H264, pkg.Data, uint32(pkg.Pts), uint32(pkg.Dts))
  82. } else if pkg.Cid == mp4.MP4_CODEC_AAC {
  83. cli.WriteAudio(codec.CODECID_AUDIO_AAC, pkg.Data, uint32(pkg.Pts), uint32(pkg.Dts))
  84. } else if pkg.Cid == mp4.MP4_CODEC_MP3 {
  85. cli.WriteAudio(codec.CODECID_AUDIO_MP3, pkg.Data, uint32(pkg.Pts), uint32(pkg.Dts))
  86. }
  87. }
  88. }

代码说明:

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}

拉流画面:

这个代码主要只是简单的推流,没有太多对视频帧的处理。

如果有需要的话,可以自己集成一些其他的图像处理的库。

可以实现实时的视频处理并推送的功能。

总结

最近在读卡耐基的《人性的弱点》,收获很多。

分享:

        人生最重要的不是以你的所得投资,任何人都可以这样做。真正重要的是如何从损失中获利。这才需要智慧,才能显示出人的上智下愚。——《人性的弱点》

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发