Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >2023-03-09:用golang调用ffmpeg,将流媒体数据(以RTMP为例)保存成本地文件(以flv为例)。

2023-03-09:用golang调用ffmpeg,将流媒体数据(以RTMP为例)保存成本地文件(以flv为例)。

原创
作者头像
福大大架构师每日一题
发布于 2023-03-09 14:12:00
发布于 2023-03-09 14:12:00
1.3K0
举报

2023-03-09:用golang调用ffmpeg,将流媒体数据(以RTMP为例)保存成本地文件(以flv为例)。

答案2023-03-09:

这是最简单的收流器。本文记录一个最简单的基于FFmpeg的收流器。收流器和推流器的作用正好相反:推流器用于将本地文件以流媒体的形式发送出去,而收流器用于将流媒体内容保存为本地文件。

本文记录的推流器可以将RTMP流媒体保存成为一个本地的FLV文件。由于FFmpeg本身支持很多的流媒体协议和封装格式,所以也支持其它的封装格式和流媒体协议。

使用 github.com/moonfdd/ffmpeg-go 库,收流器的代码写在了这个库里,基于雷霄骅的代码修改。

需要修改代码里的rtmp地址,不然程序会报错。

一、先启动lalserver。lal是go语言开源的流媒体服务器

二、执行命令:

代码语言:shell
AI代码解释
复制
go run ./examples/leixiaohua1020/simplest_ffmpeg_streamer/main.go
go run ./examples/leixiaohua1020/simplest_ffmpeg_receiver/main.go
./lib/ffplay ./out/receive.flv

参考了雷霄骅的基于libx265的视频编码器,代码用golang编写。代码如下:

代码语言:go
AI代码解释
复制
// https://github.com/leixiaohua1020/simplest_ffmpeg_streamer/blob/master/simplest_ffmpeg_receiver/simplest_ffmpeg_receiver.cpp
package main

import (
	"fmt"
	"os"
	"unsafe"

	"github.com/moonfdd/ffmpeg-go/ffcommon"
	"github.com/moonfdd/ffmpeg-go/libavcodec"
	"github.com/moonfdd/ffmpeg-go/libavformat"
	"github.com/moonfdd/ffmpeg-go/libavutil"
)

// '1': Use H.264 Bitstream Filter
const USE_H264BSF = 0

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 h264bsfc *libavcodec.AVBitStreamFilterContext
	in_filename = "rtmp://localhost/publishlive/livestream"
	//in_filename  = "rtp://233.233.233.233:6666";
	//out_filename = "receive.ts";
	//out_filename = "receive.mkv";
	out_filename = "./out/receive.flv"

	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, "", out_filename) //RTMP

	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
	}

	if USE_H264BSF != 0 {
		h264bsfc = libavcodec.AvBitstreamFilterInit("h264_mp4toannexb")
	}

	for {
		var in_stream, out_stream *libavformat.AVStream
		//Get an AVPacket
		ret = ifmt_ctx.AvReadFrame(&pkt)
		if ret < 0 {
			break
		}

		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("Receive %8d video frames from input URL\n", frame_index)
			frame_index++

			if USE_H264BSF != 0 {
				h264bsfc.AvBitstreamFilterFilter(in_stream.Codec, "", &pkt.Data, (*int32)(unsafe.Pointer(&pkt.Size)), pkt.Data, int32(pkt.Size), 0)
			}
		}
		//ret = av_write_frame(ofmt_ctx, &pkt);
		ret = ofmt_ctx.AvInterleavedWriteFrame(&pkt)

		if ret < 0 {
			fmt.Printf("Error muxing packet\n")
			break
		}

		pkt.AvFreePacket()

	}

	if USE_H264BSF != 0 {
		h264bsfc.AvBitstreamFilterClose()
	}

	//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()
}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。
2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。
福大大架构师每日一题
2023/03/05
5800
2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。
2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库。请用go语言将yuv文件编码为h264
2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库。请用go语言将yuv文件编码为h264文件。
福大大架构师每日一题
2023/02/28
7990
2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库。请用go语言将yuv文件编码为h264
FFmpeg流媒体处理-收流与推流
本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10623968.html
叶余
2019/04/19
10.4K1
FFmpeg流媒体处理-收流与推流
FFmpeg封装格式处理4-转封装例程
源码修改自 FFmpeg 4.1 自带的例程 remuxing.c。代码非常简短:
叶余
2019/04/02
1.1K0
FFmpeg封装格式处理4-转封装例程
2022-04-27:用go语言重写ffmpeg的remuxing.c示例。
ffmpeg的remuxing.c是一个用于将多媒体文件从一种容器格式转换为另一种容器格式的命令行工具。它可以将音频、视频和字幕等元素从源文件中提取出来,并按照用户指定的方式重新封装到目标文件中。在本篇文章中,我将对ffmpeg的remuxing.c进行介绍,并讨论其关键功能和技术实现。
福大大架构师每日一题
2023/04/27
3880
2023-03-15:屏幕录制并且显示视频,不要用命令。代码用go语言编写。
使用moonfdd/ffmpeg-go和moonfdd/sdl2-go库来实现屏幕录制并显示视频,大体流程如下:
福大大架构师每日一题
2023/03/15
1.2K0
2023-03-15:屏幕录制并且显示视频,不要用命令。代码用go语言编写。
2023-04-09:使用 Golang 重写的 ffmpeg 示例encode_video.c,实现视频编码并将编码后的数据封装为容器格式,最终写入输出文件。
2023-04-09:使用 Golang 重写的 ffmpeg 示例encode_video.c,实现视频编码并将编码后的数据封装为容器格式,最终写入输出文件。
福大大架构师每日一题
2023/04/09
4550
2023-04-09:使用 Golang 重写的 ffmpeg 示例encode_video.c,实现视频编码并将编码后的数据封装为容器格式,最终写入输出文件。
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
福大大架构师每日一题
2023/04/05
1.6K0
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
2023-03-21:音视频解混合(demuxer)为MP3和H264,用go语言编写。答案2023-03-21:# 步骤1:安
2023-03-21:音视频解混合(demuxer)为MP3和H264,用go语言编写。
福大大架构师每日一题
2023/06/08
2900
2023-03-21:音视频解混合(demuxer)为MP3和H264,用go语言编写。答案2023-03-21:# 步骤1:安
2023-03-03:请用go语言调用ffmpeg,摄像头捕获并编码为h264文件,不管音频。
2023-03-03:请用go语言调用ffmpeg,摄像头捕获并编码为h264文件,不管音频。
福大大架构师每日一题
2023/03/03
4840
2023-03-03:请用go语言调用ffmpeg,摄像头捕获并编码为h264文件,不管音频。
2023-02-23:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420P格式文件。
2023-02-23:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420P格式文件。
福大大架构师每日一题
2023/06/08
2130
2023-02-23:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420P格式文件。
2023-03-12:mp3音频解码为pcm,代码用go语言编写,调用moonfdd/ffmpeg-go库。
2023-03-12:mp3音频解码为pcm,代码用go语言编写,调用moonfdd/ffmpeg-go库。
福大大架构师每日一题
2023/06/08
4270
2023-03-12:mp3音频解码为pcm,代码用go语言编写,调用moonfdd/ffmpeg-go库。
2023-03-19:使用Go语言和FFmpeg库实现pcm编码为mp3。
本文将介绍如何使用Go语言和FFmpeg库实现PCM音频文件编码为MP3格式。我们将使用moonfdd/ffmpeg-go库,并在Windows 10 64位操作系统下完成本次实验。
福大大架构师每日一题
2023/03/19
6710
2023-03-19:使用Go语言和FFmpeg库实现pcm编码为mp3。
2023-03-21:音视频解混合(demuxer)为MP3和H264,用go语言编写。
2023-03-21:音视频解混合(demuxer)为MP3和H264,用go语言编写。
福大大架构师每日一题
2023/03/21
4470
2023-03-21:音视频解混合(demuxer)为MP3和H264,用go语言编写。
2023-03-01:用moonfdd/ffmpeg-go库,将h264文件编码为mp4文件。
2023-03-01:用moonfdd/ffmpeg-go库,将h264文件编码为mp4文件。
福大大架构师每日一题
2023/03/01
6300
2023-03-01:用moonfdd/ffmpeg-go库,将h264文件编码为mp4文件。
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
福大大架构师每日一题
2023/03/17
2K0
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
2023-03-12:mp3音频解码为pcm,代码用go语言编写,调用moonfdd/ffmpeg-go库。
2023-03-12:mp3音频解码为pcm,代码用go语言编写,调用moonfdd/ffmpeg-go库。
福大大架构师每日一题
2023/03/12
4340
2023-03-12:mp3音频解码为pcm,代码用go语言编写,调用moonfdd/ffmpeg-go库。
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
福大大架构师每日一题
2023/06/08
7070
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频
2023-03-24:音视频mp3和h264混合(muxer)编码为mp4,用go语言编写。
2023-03-24:音视频mp3和h264混合(muxer)编码为mp4,用go语言编写。
福大大架构师每日一题
2023/03/24
4800
2023-03-24:音视频mp3和h264混合(muxer)编码为mp4,用go语言编写。
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
福大大架构师每日一题
2023/04/12
5130
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
推荐阅读
2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。
5800
2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库。请用go语言将yuv文件编码为h264
7990
FFmpeg流媒体处理-收流与推流
10.4K1
FFmpeg封装格式处理4-转封装例程
1.1K0
2022-04-27:用go语言重写ffmpeg的remuxing.c示例。
3880
2023-03-15:屏幕录制并且显示视频,不要用命令。代码用go语言编写。
1.2K0
2023-04-09:使用 Golang 重写的 ffmpeg 示例encode_video.c,实现视频编码并将编码后的数据封装为容器格式,最终写入输出文件。
4550
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
1.6K0
2023-03-21:音视频解混合(demuxer)为MP3和H264,用go语言编写。答案2023-03-21:# 步骤1:安
2900
2023-03-03:请用go语言调用ffmpeg,摄像头捕获并编码为h264文件,不管音频。
4840
2023-02-23:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420P格式文件。
2130
2023-03-12:mp3音频解码为pcm,代码用go语言编写,调用moonfdd/ffmpeg-go库。
4270
2023-03-19:使用Go语言和FFmpeg库实现pcm编码为mp3。
6710
2023-03-21:音视频解混合(demuxer)为MP3和H264,用go语言编写。
4470
2023-03-01:用moonfdd/ffmpeg-go库,将h264文件编码为mp4文件。
6300
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
2K0
2023-03-12:mp3音频解码为pcm,代码用go语言编写,调用moonfdd/ffmpeg-go库。
4340
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频
7070
2023-03-24:音视频mp3和h264混合(muxer)编码为mp4,用go语言编写。
4800
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
5130
相关推荐
2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档