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 ... 
随机推荐
- 转帖:GitBook 从懵逼到入门
			是什么? 在我认识 GitBook 之前,我已经在使用 Git 了,毋容置疑,Git 是目前世界上最先进的分布式版本控制系统. 我认为 Git 不仅是程序员管理代码的工具,它的分布式协作方式同样适 ... 
- 服务器中VirtualBox子网访问
			本人常用的虚拟机软件是VirtualBox,由于笔记本性能,磁盘存储大下限制,以及VirtualBox客户机无法在多个设备间直接方便的使用等原因,我把几个虚拟的系统全部移动到便携式服务器中. 移动之后 ... 
- Mysql不同字符串格式的连表查询
			MySql报错:Error Code: 1267. Illegal mix of collations (utf8_unicode_ci,IMPLICIT) and (utf8_general_ci, ... 
- 查看服务器cpu 核心数
			cpu相关信息所在文件是 /proc/cpuinfo 物理cpu数 # grep "physical id" /proc/cpuinfo | sort | uniq | wc -l ... 
- sqli-labs搭建
			今天使用 phpstudy 搭建了 sqli-labs 练习 SQL 注入平台,其中遇到了两个问题. phpstudy phpstudy 中集成了 Apache.Nginx.PHP.Mysql.php ... 
- ElasticSearch 实现分词全文检索 - id、ids、prefix、fuzzy、wildcard、range、regexp 查询
			目录 ElasticSearch 实现分词全文检索 - 概述 ElasticSearch 实现分词全文检索 - ES.Kibana.IK安装 ElasticSearch 实现分词全文检索 - Rest ... 
- SpringBoot——国际化
			更多内容,前往IT-BLOG 一.Spring 编写国际化时的步骤 [1]编写国际化配置文件:[2]使用 ResourceBundleMessageSource 管理国际化资源文件:[3]在页面使用 ... 
- 安装原版Windows自动安装已经备份的驱动
			安装完Windows10后联网会自动更新驱动,除了自动更新.如果不让新安装的Windows系统自动安装驱动以外,还有自己手动安装驱动的方式.如何在安装系统过程中就让系统自己安装好驱动? 重装系统首先要 ... 
- Go - 高并发抢到红包实现
			// utils.gopackage mainimport ( "fmt" "math/rand" "sync" "time&qu ... 
- go简易tcp/udp连接测试工具
			package main import ( "fmt" "io" "log" "net" "os" ... 
