当前位置:   article > 正文

2023-03-03:请用go语言调用ffmpeg,摄像头捕获并编码为h264文件,不管音频。_go ffmpeg

go ffmpeg

2023-03-03:请用go语言调用ffmpeg,摄像头捕获并编码为h264文件,不管音频。

答案2023-03-03:

使用 github.com/moonfdd/ffmpeg-go 库。

先用如下命令,获取摄像头的名称。此摄像头名称是"Full HD webcam",你们需要修改代码,把名称给改了。

./lib/ffmpeg -list_devices true -f dshow -i dummy
  • 1

在这里插入图片描述

代码命令如下:

go run ./examples/a14.video_encode_camera2h264/main.go
  • 1

参考了14:摄像头捕获并编码为h264,代码用golang编写。代码如下:

package main

import (
	"fmt"
	"os"
	"os/exec"
	"time"
	"unsafe"

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

func main() {
	// ./lib/ffmpeg -list_devices true -f dshow -i dummy
	// ./lib/ffplay -f dshow -i video="Full HD webcam"
	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
		}
	}

	// frame_index := 0 //统计帧数
	// inVStreamIndex := -1
	// outVStreamIndex := -1 //输入输出视频流在文件中的索引位置
	// inVFileName := "./out/result.h264"
	// outFileName := "./out/result.mp4"

	//是否存在h264文件
	// _, err = os.Stat(inVFileName)
	// if err != nil {
	// 	if os.IsNotExist(err) {
	// 		fmt.Println("create h264 file")
	// 		exec.Command("./lib/ffmpeg", "-i", "./resources/big_buck_bunny.mp4", "-vcodec", "copy", "-an", inVFileName, "-y").CombinedOutput()
	// 	}
	// }
	ret := int32(0)
	libavdevice.AvdeviceRegisterAll()
	inFmtCtx := libavformat.AvformatAllocContext()
	var inCodecCtx *libavcodec.AVCodecContext
	var inCodec *libavcodec.AVCodec
	inPkt := libavcodec.AvPacketAlloc()
	srcFrame := libavutil.AvFrameAlloc()
	yuvFrame := libavutil.AvFrameAlloc()

	//打开输出文件,并填充fmtCtx数据
	outFmtCtx := libavformat.AvformatAllocContext()
	var outFmt *libavformat.AVOutputFormat
	var outCodecCtx *libavcodec.AVCodecContext
	var outCodec *libavcodec.AVCodec
	var outVStream *libavformat.AVStream
	outPkt := libavcodec.AvPacketAlloc()
	var img_ctx *libswscale.SwsContext
	inVideoStreamIndex := -1

	for {
		/解码器部分//
		//打开摄像头
		inFmt := libavformat.AvFindInputFormat("dshow")
		if libavformat.AvformatOpenInput(&inFmtCtx, "video=Full HD webcam", inFmt, nil) < 0 {
			fmt.Printf("Cannot open camera.\n")
			return
		}
		if inFmtCtx.AvformatFindStreamInfo(nil) < 0 {
			fmt.Printf("Cannot find any stream in file.\n")
			return
		}

		for i := 0; i < int(inFmtCtx.NbStreams); i++ {
			if inFmtCtx.GetStream(uint32(i)).Codecpar.CodecType == libavutil.AVMEDIA_TYPE_VIDEO {
				inVideoStreamIndex = i
				break
			}
		}

		if inVideoStreamIndex == -1 {
			fmt.Printf("Cannot find video stream in file.\n")
			return
		}

		inVideoCodecPara := inFmtCtx.GetStream(uint32(inVideoStreamIndex)).Codecpar
		inCodec = libavcodec.AvcodecFindDecoder(inVideoCodecPara.CodecId)
		if inCodec == nil {
			fmt.Printf("Cannot find valid video decoder.\n")
			return
		}
		inCodecCtx = inCodec.AvcodecAllocContext3()
		if inCodecCtx == nil {
			fmt.Printf("Cannot alloc valid decode codec context.\n")
			return
		}
		if inCodecCtx.AvcodecParametersToContext(inVideoCodecPara) < 0 {
			fmt.Printf("Cannot initialize parameters.\n")
			return
		}

		if inCodecCtx.AvcodecOpen2(inCodec, nil) < 0 {
			fmt.Printf("Cannot open codec.\n")
			return
		}

		img_ctx = libswscale.SwsGetContext(inCodecCtx.Width,
			inCodecCtx.Height,
			inCodecCtx.PixFmt,
			inCodecCtx.Width,
			inCodecCtx.Height,
			libavutil.AV_PIX_FMT_YUV420P,
			libswscale.SWS_BICUBIC,
			nil, nil, nil)

		numBytes := libavutil.AvImageGetBufferSize(libavutil.AV_PIX_FMT_YUV420P,
			inCodecCtx.Width,
			inCodecCtx.Height, 1)

		out_buffer := libavutil.AvMalloc(uint64(numBytes))

		ret = libavutil.AvImageFillArrays((*[4]*ffcommon.FUint8T)(unsafe.Pointer(&yuvFrame.Data)),
			(*[4]ffcommon.FInt)(unsafe.Pointer(&yuvFrame.Linesize)),
			(*ffcommon.FUint8T)(unsafe.Pointer(out_buffer)),
			libavutil.AV_PIX_FMT_YUV420P,
			inCodecCtx.Width,
			inCodecCtx.Height,
			1)
		if ret < 0 {
			fmt.Printf("Fill arrays failed.\n")
			return
		}
		//解码器部分结束/

		//编码器部分开始/
		outFile := "./out/result14.h264"
		if libavformat.AvformatAllocOutputContext2(&outFmtCtx, nil, "", outFile) < 0 {
			fmt.Printf("Cannot alloc output file context.\n")
			return
		}
		outFmt = outFmtCtx.Oformat

		//打开输出文件
		if libavformat.AvioOpen(&outFmtCtx.Pb, outFile, libavformat.AVIO_FLAG_READ_WRITE) < 0 {
			fmt.Printf("output file open failed.\n")
			return
		}

		//创建h264视频流,并设置参数
		outVStream = outFmtCtx.AvformatNewStream(outCodec)
		if outVStream == nil {
			fmt.Printf("create new video stream fialed.\n")
			return
		}
		outVStream.TimeBase.Den = 30
		outVStream.TimeBase.Num = 1

		//编码参数相关
		outCodecPara := outFmtCtx.GetStream(uint32(outVStream.Index)).Codecpar
		outCodecPara.CodecType = libavutil.AVMEDIA_TYPE_VIDEO
		outCodecPara.CodecId = outFmt.VideoCodec
		outCodecPara.Width = 480
		outCodecPara.Height = 360
		outCodecPara.BitRate = 110000

		//查找编码器
		outCodec = libavcodec.AvcodecFindEncoder(outFmt.VideoCodec)
		if outCodec == nil {
			fmt.Printf("Cannot find any encoder.\n")
			return
		}

		//设置编码器内容
		outCodecCtx = outCodec.AvcodecAllocContext3()
		outCodecCtx.AvcodecParametersToContext(outCodecPara)
		if outCodecCtx == nil {
			fmt.Printf("Cannot alloc output codec content.\n")
			return
		}
		outCodecCtx.CodecId = outFmt.VideoCodec
		outCodecCtx.CodecType = libavutil.AVMEDIA_TYPE_VIDEO
		outCodecCtx.PixFmt = libavutil.AV_PIX_FMT_YUV420P
		outCodecCtx.Width = inCodecCtx.Width
		outCodecCtx.Height = inCodecCtx.Height
		outCodecCtx.TimeBase.Num = 1
		outCodecCtx.TimeBase.Den = 30
		outCodecCtx.BitRate = 110000
		outCodecCtx.GopSize = 10

		if outCodecCtx.CodecId == libavcodec.AV_CODEC_ID_H264 {
			outCodecCtx.Qmin = 10
			outCodecCtx.Qmax = 51
			outCodecCtx.Qcompress = 0.6
		} else if outCodecCtx.CodecId == libavcodec.AV_CODEC_ID_MPEG2VIDEO {
			outCodecCtx.MaxBFrames = 2
		} else if outCodecCtx.CodecId == libavcodec.AV_CODEC_ID_MPEG1VIDEO {
			outCodecCtx.MbDecision = 2
		}

		//打开编码器
		if outCodecCtx.AvcodecOpen2(outCodec, nil) < 0 {
			fmt.Printf("Open encoder failed.\n")
			return
		}
		///编码器部分结束

		///编解码部分//
		yuvFrame.Format = outCodecCtx.PixFmt
		yuvFrame.Width = outCodecCtx.Width
		yuvFrame.Height = outCodecCtx.Height

		ret = outFmtCtx.AvformatWriteHeader(nil)

		count := 0
		for inFmtCtx.AvReadFrame(inPkt) >= 0 && count < 50 {
			if inPkt.StreamIndex == uint32(inVideoStreamIndex) {
				if inCodecCtx.AvcodecSendPacket(inPkt) >= 0 {
					ret = inCodecCtx.AvcodecReceiveFrame(srcFrame)
					for ret >= 0 {
						if ret == -libavutil.EAGAIN || ret == libavutil.AVERROR_EOF {
							break
						} else if ret < 0 {
							fmt.Printf("Error during decoding\n")
							return
						}
						img_ctx.SwsScale((**byte)(unsafe.Pointer(&srcFrame.Data)),
							(*int32)(unsafe.Pointer(&srcFrame.Linesize)),
							0, uint32(inCodecCtx.Height),
							(**byte)(unsafe.Pointer(&yuvFrame.Data)), (*int32)(unsafe.Pointer(&yuvFrame.Linesize)))

						yuvFrame.Pts = srcFrame.Pts
						//encode
						if outCodecCtx.AvcodecSendFrame(yuvFrame) >= 0 {
							if outCodecCtx.AvcodecReceivePacket(outPkt) >= 0 {
								fmt.Printf("encode one frame.\n")
								count++
								outPkt.StreamIndex = uint32(outVStream.Index)
								outPkt.AvPacketRescaleTs(outCodecCtx.TimeBase,
									outVStream.TimeBase)
								outPkt.Pos = -1
								outFmtCtx.AvInterleavedWriteFrame(outPkt)
								outPkt.AvPacketUnref()
							}
						}
						// usleep(1000*24);
						time.Sleep(time.Millisecond * 24)
						ret = inCodecCtx.AvcodecReceiveFrame(srcFrame)
					}
				}
				inPkt.AvPacketUnref()
			}
		}
		ret = flush_encoder(outFmtCtx, outCodecCtx, int(outVStream.Index))
		if ret < 0 {
			fmt.Printf("flushing encoder failed.\n")
			return
		}
		outFmtCtx.AvWriteTrailer()
		编解码部分结束
		break
	}
	///内存释放部分/
	libavcodec.AvPacketFree(&inPkt)
	libavcodec.AvcodecFreeContext(&inCodecCtx)
	inCodecCtx.AvcodecClose()
	libavformat.AvformatCloseInput(&inFmtCtx)
	libavutil.AvFrameFree(&srcFrame)
	libavutil.AvFrameFree(&yuvFrame)

	libavcodec.AvPacketFree(&outPkt)
	libavcodec.AvcodecFreeContext(&outCodecCtx)
	outCodecCtx.AvcodecClose()
	libavformat.AvformatCloseInput(&outFmtCtx)

	fmt.Println("-----------------------------------------")
	_, err = exec.Command("./lib/ffplay.exe", "./out/result14.h264").Output()
	if err != nil {
		fmt.Println("play err = ", err)
	}
}

func flush_encoder(fmtCtx *libavformat.AVFormatContext, codecCtx *libavcodec.AVCodecContext, vStreamIndex int) int32 {
	ret := int32(0)
	enc_pkt := libavcodec.AvPacketAlloc()
	enc_pkt.Data = nil
	enc_pkt.Size = 0

	if (codecCtx.Codec.Capabilities & libavcodec.AV_CODEC_CAP_DELAY) == 0 {
		return 0
	}

	fmt.Printf("Flushing stream #%d encoder\n", vStreamIndex)
	if codecCtx.AvcodecSendFrame(nil) >= 0 {
		for codecCtx.AvcodecReceivePacket(enc_pkt) >= 0 {
			fmt.Printf("success encoder 1 frame.\n")

			// parpare packet for muxing
			enc_pkt.StreamIndex = uint32(vStreamIndex)
			enc_pkt.AvPacketRescaleTs(codecCtx.TimeBase,
				fmtCtx.GetStream(uint32(vStreamIndex)).TimeBase)
			ret = fmtCtx.AvInterleavedWriteFrame(enc_pkt)
			if ret < 0 {
				break
			}
		}
	}

	enc_pkt.AvPacketUnref()

	return ret
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/950041
推荐阅读
相关标签
  

闽ICP备14008679号