2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。
2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。
答案2023-03-05:
使用 github.com/moonfdd/ffmpeg-go 库。
先启动lal流媒体服务器软件,然后再执行命令:
go run ./examples/leixiaohua1020/simplest_ffmpeg_streamer/main.go
参考了雷霄骅的最简单的基于FFmpeg的推流器(推送RTMP),代码用golang编写。代码如下:
// https://github.com/leixiaohua1020/simplest_ffmpeg_streamer/blob/master/simplest_ffmpeg_streamer/simplest_ffmpeg_streamer.cpp
package main
import (
"fmt"
"os"
"os/exec"
"time"
"github.com/moonfdd/ffmpeg-go/ffcommon"
"github.com/moonfdd/ffmpeg-go/libavcodec"
"github.com/moonfdd/ffmpeg-go/libavformat"
"github.com/moonfdd/ffmpeg-go/libavutil"
)
func main0() (ret ffcommon.FInt) {
var ofmt *libavformat.AVOutputFormat
//Input AVFormatContext and Output AVFormatContext
var ifmt_ctx, ofmt_ctx *libavformat.AVFormatContext
var pkt libavcodec.AVPacket
var in_filename, out_filename string
var i ffcommon.FInt
var videoindex ffcommon.FInt = -1
var frame_index ffcommon.FInt = 0
var start_time ffcommon.FInt64T = 0
var err error
//in_filename = "cuc_ieschool.mov";
//in_filename = "cuc_ieschool.mkv";
//in_filename = "cuc_ieschool.ts";
//in_filename = "cuc_ieschool.mp4";
//in_filename = "cuc_ieschool.h264";
in_filename = "./out/cuc_ieschool.flv" //输入URL(Input file URL)
//in_filename = "shanghai03_p.h264";
_, err = os.Stat(in_filename)
if err != nil {
if os.IsNotExist(err) {
fmt.Println("create flv file")
exec.Command("./lib/ffmpeg", "-i", "./resources/big_buck_bunny.mp4", "-vcodec", "copy", "-acodec", "copy", in_filename).Output()
}
}
out_filename = "rtmp://localhost/publishlive/livestream" //输出 URL(Output URL)[RTMP]
//out_filename = "rtp://233.233.233.233:6666";//输出 URL(Output URL)[UDP]
libavformat.AvRegisterAll()
//Network
libavformat.AvformatNetworkInit()
//Input
ret = libavformat.AvformatOpenInput(&ifmt_ctx, in_filename, nil, nil)
if ret < 0 {
fmt.Printf("Could not open input file.")
goto end
}
ret = ifmt_ctx.AvformatFindStreamInfo(nil)
if ret < 0 {
fmt.Printf("Failed to retrieve input stream information")
goto end
}
for i = 0; i < int32(ifmt_ctx.NbStreams); i++ {
if ifmt_ctx.GetStream(uint32(i)).Codec.CodecType == libavutil.AVMEDIA_TYPE_VIDEO {
videoindex = i
break
}
}
ifmt_ctx.AvDumpFormat(0, in_filename, 0)
//Output
libavformat.AvformatAllocOutputContext2(&ofmt_ctx, nil, "flv", out_filename) //RTMP
//avformat_alloc_output_context2(&ofmt_ctx, NULL, "mpegts", out_filename);//UDP
if ofmt_ctx == nil {
fmt.Printf("Could not create output context\n")
ret = libavutil.AVERROR_UNKNOWN
goto end
}
ofmt = ofmt_ctx.Oformat
for i = 0; i < int32(ifmt_ctx.NbStreams); i++ {
//Create output AVStream according to input AVStream
in_stream := ifmt_ctx.GetStream(uint32(i))
out_stream := ofmt_ctx.AvformatNewStream(in_stream.Codec.Codec)
if out_stream == nil {
fmt.Printf("Failed allocating output stream\n")
ret = libavutil.AVERROR_UNKNOWN
goto end
}
//Copy the settings of AVCodecContext
ret = libavcodec.AvcodecCopyContext(out_stream.Codec, in_stream.Codec)
if ret < 0 {
fmt.Printf("Failed to copy context from input to output stream codec context\n")
goto end
}
out_stream.Codec.CodecTag = 0
if ofmt_ctx.Oformat.Flags&libavformat.AVFMT_GLOBALHEADER != 0 {
out_stream.Codec.Flags |= libavcodec.AV_CODEC_FLAG_GLOBAL_HEADER
}
}
//Dump Format------------------
ofmt_ctx.AvDumpFormat(0, out_filename, 1)
//Open output URL
if ofmt.Flags&libavformat.AVFMT_NOFILE == 0 {
ret = libavformat.AvioOpen(&ofmt_ctx.Pb, out_filename, libavformat.AVIO_FLAG_WRITE)
if ret < 0 {
fmt.Printf("Could not open output URL '%s'", out_filename)
goto end
}
}
//Write file header
ret = ofmt_ctx.AvformatWriteHeader(nil)
if ret < 0 {
fmt.Printf("Error occurred when opening output URL\n")
goto end
}
start_time = libavutil.AvGettime()
for {
var in_stream, out_stream *libavformat.AVStream
//Get an AVPacket
ret = ifmt_ctx.AvReadFrame(&pkt)
if ret < 0 {
break
}
//FIX:No PTS (Example: Raw H.264)
//Simple Write PTS
if pkt.Pts == libavutil.AV_NOPTS_VALUE {
//Write PTS
time_base1 := ifmt_ctx.GetStream(uint32(videoindex)).TimeBase
//Duration between 2 frames (us)
calc_duration := int64(libavutil.AV_TIME_BASE / libavutil.AvQ2d(ifmt_ctx.GetStream(uint32(videoindex)).RFrameRate))
//Parameters
pkt.Pts = int64(float64(frame_index) * float64(calc_duration) / (libavutil.AvQ2d(time_base1) * libavutil.AV_TIME_BASE))
pkt.Dts = pkt.Pts
pkt.Duration = int64(float64(calc_duration) / (libavutil.AvQ2d(time_base1) * libavutil.AV_TIME_BASE))
}
//Important:Delay
if pkt.StreamIndex == uint32(videoindex) {
time_base := ifmt_ctx.GetStream(uint32(videoindex)).TimeBase
time_base_q := libavutil.AVRational{1, libavutil.AV_TIME_BASE}
pts_time := libavutil.AvRescaleQ(pkt.Dts, time_base, time_base_q)
now_time := libavutil.AvGettime() - start_time
if pts_time > now_time {
libavutil.AvUsleep(uint32(pts_time - now_time))
}
}
in_stream = ifmt_ctx.GetStream(pkt.StreamIndex)
out_stream = ofmt_ctx.GetStream(pkt.StreamIndex)
/* copy packet */
//Convert PTS/DTS
pkt.Pts = libavutil.AvRescaleQRnd(pkt.Pts, in_stream.TimeBase, out_stream.TimeBase, libavutil.AV_ROUND_NEAR_INF|libavutil.AV_ROUND_PASS_MINMAX)
pkt.Dts = libavutil.AvRescaleQRnd(pkt.Dts, in_stream.TimeBase, out_stream.TimeBase, libavutil.AV_ROUND_NEAR_INF|libavutil.AV_ROUND_PASS_MINMAX)
pkt.Duration = libavutil.AvRescaleQ(pkt.Duration, in_stream.TimeBase, out_stream.TimeBase)
pkt.Pos = -1
//Print to Screen
if pkt.StreamIndex == uint32(videoindex) {
fmt.Printf("Send %8d video frames to output URL\n", frame_index)
frame_index++
}
//ret = av_write_frame(ofmt_ctx, &pkt);
ret = ofmt_ctx.AvInterleavedWriteFrame(&pkt)
if ret < 0 {
fmt.Printf("Error muxing packet\n")
break
}
pkt.AvFreePacket()
}
//Write file trailer
ofmt_ctx.AvWriteTrailer()
end:
libavformat.AvformatCloseInput(&ifmt_ctx)
/* close output */
if ofmt_ctx != nil && ofmt.Flags&libavformat.AVFMT_NOFILE == 0 {
ofmt_ctx.Pb.AvioClose()
}
ofmt_ctx.AvformatFreeContext()
if ret < 0 && ret != libavutil.AVERROR_EOF {
fmt.Printf("Error occurred.\n")
return -1
}
return 0
}
func main() {
os.Setenv("Path", os.Getenv("Path")+";./lib")
ffcommon.SetAvutilPath("./lib/avutil-56.dll")
ffcommon.SetAvcodecPath("./lib/avcodec-58.dll")
ffcommon.SetAvdevicePath("./lib/avdevice-58.dll")
ffcommon.SetAvfilterPath("./lib/avfilter-56.dll")
ffcommon.SetAvformatPath("./lib/avformat-58.dll")
ffcommon.SetAvpostprocPath("./lib/postproc-55.dll")
ffcommon.SetAvswresamplePath("./lib/swresample-3.dll")
ffcommon.SetAvswscalePath("./lib/swscale-5.dll")
genDir := "./out"
_, err := os.Stat(genDir)
if err != nil {
if os.IsNotExist(err) {
os.Mkdir(genDir, 0777) // Everyone can read write and execute
}
}
go func() {
time.Sleep(1000)
exec.Command("./lib/ffplay.exe", "rtmp://localhost/publishlive/livestream").Output()
if err != nil {
fmt.Println("play err = ", err)
}
}()
main0()
}
2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。的更多相关文章
- ffmpeg推送,EasyDarwin转发,vlc播放 实现整个RTSP直播
部署EasyDarwin流媒体服务器 ffmpeg推送摄像机视频到EasyDarwin VLC播放 第一步:部署EasyDarwin流媒体服务器 EasyDarwin的部署过程我们就不再赘述了,在Ea ...
- git推送本地分支到远程分支
场景 有时候我们开发需要开一个分支,这样可以有效的并行开发. 开分支有两种方式: 一种是在远程开好分支,本地直接拉下来; 一种是本地开好分支,推送到远程. 远程先开好分支然后拉到本地 git chec ...
- iOS 疑难杂症 — — 推送本地国际化 loc-key 本地化失败的问题
声明 欢迎转载,但请保留文章原始出处:) 博客园:http://www.cnblogs.com 农民伯伯: http://over140.cnblogs.com 正文 一.准备 推送本地国际化官方 ...
- git推送本地分支到远端 以及删除远端分支的 命令
git推送本地分支到远端 当前处于master分支,尝试用了git push origin warning: push.default is unset; its implicit value is ...
- Git for Windows之推送本地版本库到远程仓库
Git for Windows之基础环境搭建与基础操作中介绍了Git基本环境的构建与基本的操作.生成了一个本地git版本库,本文将介绍如何将这个版本库推送到远程仓库(码云,github也可以). 1. ...
- git推送本地仓库到github
总结一下,方便后人,也方便自己查阅.直接写步骤 一.本地创建一个文件夹,在里面写项目的文件(* .php/*.js.....). git本地操作: 1 . cd /path/to/project ...
- git 分支管理 推送本地分支到远程分支等
1.创建本地分支 local_branch git branch local_branch 2.创建本地分支local_branch 并切换到local_branch分支 git checkout - ...
- ffmpeg推送RTSP直播流到EasyDarwin报错问题的修复
在之前的博客<ffmpeg推送,EasyDarwin转发,vlc播放 实现整个RTSP直播>中,我们介绍了如何采用ffmpeg进行RTSP推送,实现EasyDarwin直播分发的功能,近期 ...
- EasyCamera海康摄像机向EasyDarwin云平台推送音视频数据的缓存设计
本文转自EasyDarwin团队成员Alex的博客:http://blog.csdn.net/cai6811376 EasyCamera在向EasyDarwin云平台推送音视频数据时,有时一个I帧会很 ...
- git 推送本地项目到远程库
git 推送本地项目到远程库 1@DESKTOP-3H9092J MINGW64 /e/mozq/00store/01/SmartCard_MS $ git init Initialized empt ...
随机推荐
- 使用python来搭建一个简易的文件下载环境以及用droopy来实现一个文件上传环境
ubuntu在安装的时候一般都是自带python环境的,大家可以查看一下查看demo如下 用于共享的命令很简单python2: python -m SimpleHTTPServer 8888pytho ...
- Adams:一种使接触力(力矩等等)失效的方法
1 第一步:点击"运行脚本". 2 第二步:右击选择"仿真脚本",点击"创建". 3 第三步:选择"脚本类型"为&quo ...
- beast加密
Beast: https://github.com/liexusong/php-beast?tdsourcetag=s_pctim_aiomsgbeast-安裝到/root------------- ...
- nvm的下载安装
nvm下载地址:https://github.com/coreybutler/nvm-windows/releases 下载包,双击安装,选取路径, 注意:如果按默认的,安装在c盘的话,那之后的切换版 ...
- 【Airtest相关】收集一些Airtest的介绍
1.项目简介 ui自动化一直是个让人头疼的事,主要是因为系统兼容性难度较大和开发维护成本比较高, 以前使用过appium,通用性比较差,并且开发有一定的基础才行,更难以忍受的是后期的维护成本:然后接触 ...
- conda使用杂记
总纲 https://docs.anaconda.com/anaconda/navigator/ 其中有链接 miniconda https://docs.anaconda.com/anaconda/ ...
- Go语言 :使用简单的 for 迭代语句进行 TDD 驱动测试开发与 benchmark 基准测试
前提准备与运行环境请参考:(新手向)在Linux中使用VScode编写 "Hello,world"程序,并编写测试-Ubuntu20.4 在 Go 中 for 用来循环和迭代, ...
- FutureTask 类
更多内容,前往IT-BLOG 一.什么是 Future和 FutureTask FutureTask 的 Future就源自于它的异步工作机制,如果我们在主线程中直接写一个函数来执行任务,这是同步的任 ...
- mongo操作数据库
1.回顾 2.node + mongodb 2.1 安装mongodb 项目中既可以使用mongodb,但是推荐使用mongoose cnpm i mongoose@4 -S 2.2 连接数据库 一定 ...
- 配置了一台3700X电脑后
众所周知,电脑是生活中必不可少的玩具,最近搞了一套配置.CPU3700X,显卡RX580,内存32GB.敲,这CPU的框框,看见就爽的不得了. As we all know, a comput ...