目次
序文
最近、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\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, 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\n", infos)
}
mp4info := demuxer.GetMp4Info()
fmt.Printf("%+v\n", 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 スリープする必要があるのはなぜですか? 読み取り速度が比較的速く、プッシュが速すぎるため、フレーム レートに応じて調整できます。
以下の結果:
rtmp onstatus code:NetStream.Publish.Start ,level ストリームの公開を開始しました。,describe:%!s(MISSING)
パブリッシュの準備ができました
ファイルの読み取り開始
[{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 8461648 828601953 825520237] 期間:299990 タイムスケール:1000 CreateTime:0 ModifyTime:0}
画面を引っ張る:
このコードは主に単純なストリーミングであり、ビデオ フレームの処理はあまりありません。
必要に応じて、他の画像処理ライブラリを自分で統合できます。
リアルタイムのビデオ処理とプッシュ機能を実現できます。
要約する
最近、カーネギーの「人間性の弱さ」を読んで多くのことを学びました。
共有:
人生で最も重要なことは、稼いだお金を投資することではなく、誰でもできることです。本当に重要なのは、損失からどのように利益を得るかです。これには、人々の優れた知恵と劣った愚かさを示すために、知恵が必要です。——「人間性の弱さ」