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语言编写。的更多相关文章

  1. ffmpeg推送,EasyDarwin转发,vlc播放 实现整个RTSP直播

    部署EasyDarwin流媒体服务器 ffmpeg推送摄像机视频到EasyDarwin VLC播放 第一步:部署EasyDarwin流媒体服务器 EasyDarwin的部署过程我们就不再赘述了,在Ea ...

  2. git推送本地分支到远程分支

    场景 有时候我们开发需要开一个分支,这样可以有效的并行开发. 开分支有两种方式: 一种是在远程开好分支,本地直接拉下来; 一种是本地开好分支,推送到远程. 远程先开好分支然后拉到本地 git chec ...

  3. iOS 疑难杂症 — — 推送本地国际化 loc-key 本地化失败的问题

    声明  欢迎转载,但请保留文章原始出处:)  博客园:http://www.cnblogs.com 农民伯伯: http://over140.cnblogs.com 正文 一.准备 推送本地国际化官方 ...

  4. git推送本地分支到远端 以及删除远端分支的 命令

    git推送本地分支到远端 当前处于master分支,尝试用了git push origin warning: push.default is unset; its implicit value is ...

  5. Git for Windows之推送本地版本库到远程仓库

    Git for Windows之基础环境搭建与基础操作中介绍了Git基本环境的构建与基本的操作.生成了一个本地git版本库,本文将介绍如何将这个版本库推送到远程仓库(码云,github也可以). 1. ...

  6. git推送本地仓库到github

    总结一下,方便后人,也方便自己查阅.直接写步骤 一.本地创建一个文件夹,在里面写项目的文件(* .php/*.js.....). git本地操作: 1 .  cd  /path/to/project  ...

  7. git 分支管理 推送本地分支到远程分支等

    1.创建本地分支 local_branch git branch local_branch 2.创建本地分支local_branch 并切换到local_branch分支 git checkout - ...

  8. ffmpeg推送RTSP直播流到EasyDarwin报错问题的修复

    在之前的博客<ffmpeg推送,EasyDarwin转发,vlc播放 实现整个RTSP直播>中,我们介绍了如何采用ffmpeg进行RTSP推送,实现EasyDarwin直播分发的功能,近期 ...

  9. EasyCamera海康摄像机向EasyDarwin云平台推送音视频数据的缓存设计

    本文转自EasyDarwin团队成员Alex的博客:http://blog.csdn.net/cai6811376 EasyCamera在向EasyDarwin云平台推送音视频数据时,有时一个I帧会很 ...

  10. git 推送本地项目到远程库

    git 推送本地项目到远程库 1@DESKTOP-3H9092J MINGW64 /e/mozq/00store/01/SmartCard_MS $ git init Initialized empt ...

随机推荐

  1. centos 开启关闭网卡(禁用网卡)

    说明我之前在工作中使用的服务器很多都是多网卡服务器,他可以使用不同的网卡连接不同的网段,但是,由于个别情况突发,有时候可能需要关闭某些网卡,禁止它们访问到网络,也就是需要关闭网卡.步骤1.查看有哪些网 ...

  2. POI设置单元格下拉框

    一.导出 Excel 单元格设置下拉框 日常开发中,导出基础数据为模版,填充信息后导入时,有时候会要求某些导入项应该为下拉框选择,一个是为了规范数据,也可以简化填充. 1.1 单元格下拉框选项总字符较 ...

  3. JS判断数据类型的4种方法

    4种判断方法分别是: typeof instanceof prototype属性 constructor属性 可判断的类型对比如下图: 实践代码如下: 1 // 构造函数名方法 2 function ...

  4. Xamarin.Android 利用作业计划程序实现ImageSwitcher图片自动定时轮播

    在开发android程序时,遇到一个问题,ImageSwitcher只支持手动的切换图片,不支持自动定时的切换.因为xamarin的资料很少,官方也没有相应的教程,所以想到这个方法,利用job程序来实 ...

  5. Python学习笔记--数据输出

    数据输出 输出为Python对象 collect算子 具体实现: reduce算子 具体实现: take算子 具体实现: count算子 具体实现: 输出到文件中 saveAsTextFile算子 具 ...

  6. 使用Nginx实现本地目录映射

    如果文件是存储在服务器的某个位置,想提供pdf.jpg.png.mp4这些文件的预览功能,可以使用Nginx做虚拟映射,防止他人知道该文件的绝对路径. 如果想预览office文件,先将office文件 ...

  7. 11.8 消除闪烁(2)(harib08h)

    ps:看书比较急,有错误的地方欢迎指正,不细致的地方我会持续的修改 11.8 消除闪烁(2)(harib08h) 11.7 消除闪烁(1)(harib08g)存在的问题: 鼠标放在计时器上会有 闪烁, ...

  8. 孙勇男:实时视频 SDK 黑盒测试架构丨Dev for Dev 专栏

    Dev for Dev 专栏全称为 Developer for Developer,该专栏是声网与 RTC 开发者社区共同发起的开发者互动创新实践活动.透过工程师视角的技术分享.交流碰撞.项目共建等多 ...

  9. diyudio 3886 功放机鉴赏

  10. WebSocket服务器

    //创建websocket 服务器  ws_server.php //https://wiki.swoole.com/wiki/page/479.html //创建websocket服务器对象,监听0 ...