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

代码命令如下:

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

参考了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
}

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

  1. Unity3D中调用外接摄像头,并保存为图片文件

    http://bbs.9ria.com/thread-170539-1-1.html 项目要求调用摄像头,并且把图像保存下来,上传到服务器. 这里有几个难点,调用摄像头是很简单的,unity已经提供好 ...

  2. 使用HTML5+调用手机摄像头和相册

    前言:前端时间使用HTML5做了一个WEB端APP,其中用到了H5页面调用手机摄像头的功能,当时也是花了不少时间去研究.最终是采用了HTML5plus(HTML5+)的方式完成了该功能,现将具体方法简 ...

  3. 2019.03.03 - Linux搭建go语言交叉环境

    编译GO 1.6版本以上的需要依赖GO 1.4版本的二进制,并且需要把GOROOT_BOOTSTRAP的路径设置为1.4版本GO的根目录,这样它的bin目录就可以直接使用到1.4版本的GO 搭建go语 ...

  4. Golang通过Thrift框架完美实现跨语言调用

    每种语言都有自己最擅长的领域,Golang 最适合的领域就是服务器端程序. 做为服务器端程序,需要考虑性能同时也要考虑与各种语言之间方便的通讯.采用http协议简单,但性能不高.采用TCP通讯,则需要 ...

  5. Atitit java c# php c++ js跨语言调用matlab实现边缘检测等功能attilax总结

    Atitit java c# php c++ js跨语言调用matlab实现边缘检测等功能attilax总结 1.1. 边缘检测的基本方法Canny最常用了1 1.2. 编写matlab边缘检测代码, ...

  6. Golang、Php、Python、Java基于Thrift0.9.1实现跨语言调用

    目录: 一.什么是Thrift? 1) Thrift内部框架一瞥 2) 支持的数据传输格式.数据传输方式和服务模型 3) Thrift IDL 二.Thrift的官方网站在哪里? 三.在哪里下载?需要 ...

  7. Java跨语言调用,使用JNA访问Java外部接口

    1. JNA简单介绍 先说JNI(Java Native Interface)吧,有过不同语言间通信经历的一般都知道,它允许Java代码和其他语言(尤其C/C++)写的代码进行交互,只要遵守调用约定即 ...

  8. 在VS2015中用C++编写可被其它语言调用的动态库DLL

    转自:http://blog.csdn.net/songyi160/article/details/50754705 VS2015用C++创建动态库DLL步骤如下: (1)启动VS2015>文件 ...

  9. C语言调用Intel处理器CPUID指令的实例

    C语言调用Intel处理器CPUID指令的实例 来源 https://blog.csdn.net/subfate/article/details/50789905 在Linux环境下,使用C语言内嵌汇 ...

  10. C/C++编程笔记:C语言入门知识点(三),请收藏C语言最全笔记!

    今天我们继续来学习C语言的入门知识点,第一课:C/C++编程笔记:C语言入门知识点(二),请收藏C语言最全笔记! 21. 输入 & 输出 当我们提到输入时,这意味着要向程序填充一些数据.输入可 ...

随机推荐

  1. 声网王浩宇:RTE 场景下的 Serverless 架构挑战【RTE 2022】

    前言 在「RTE2022 实时互联网大会」中,声网云原生边缘计算团队的负责人 @王浩宇 Dylan 以<RTE 场景下的 Serverless 架构挑战 -- 声网如何兼顾后端服务的可靠.高效和 ...

  2. Mathematica制作和使用程序包

    步骤 这里拿你制作并且使用一个程序包lost为例子 新建一个空白.wl文档,输入代码如下 BeginPackage[ "MyPkg`"] MainFunction::usage = ...

  3. UI/UE设计学习路线图(超详细)

    很多小伙伴认为ui设计很简单,就是用相关的软件设计制作图片.界面等.其实不然,UI设计融合了很多学科内容.要从一个完全没有基础的人成长为一个ui设计者,该如何学习呢?主要分为基础阶段和专业课程阶段,其 ...

  4. Apinto Dashboad V2.0 发布:可视化控制台让配置更轻松!

    大家好, Eolink 旗下开源网关 Apinto 本次带来了 Apinto Dashboad V2.0 的版本发布. Dashboad 需要与 Apinto 主版本一起使用,目前 Dashboad ...

  5. Java面试——架构设计与分布式

    更多内容,移步 IT-BLOG 一.用 Java 自己实现一个 LRU LRU(Least Recently Used:最近最少使用):简单的说,就是保证基本的 Cache容量,如果超过容量则必须丢掉 ...

  6. Lua基础语法学习笔记

    Lua是一门语言,我们可以使用一个库,可以在运行时去编译执行Lua中的代码,从而实现自己的内存中的数据和逻辑: 准备学习环境: 新建一个Lua项目目录,用来写我们的Lua代码: 进入目录,右键使用vs ...

  7. vue中新的状态管理器-pinia

    背景 对于pinia的使用,可参考官方文档在这不做过多赘述.这边主要来讲讲pinia中 少用且好用的方法,为什么我们选择pinia而不用vuex ps: 以下写法全部基于组合式API 使用方式: 先下 ...

  8. IOC创建对象方式

    IOC创建对象方式 User 类  public class User {  private String name;          public User(String name) {      ...

  9. GET 和 POST 到底有什么区别?

    HTTP最早被用来做浏览器与服务器之间交互HTML和表单的通讯协议:后来又被被广泛的扩充到接口格式的定义上.所以在讨论GET和POST区别的时候,需要现确定下到底是浏览器使用的GET/POST还是用H ...

  10. vue之条件渲染v-if

    目录 说明 语法 示例 说明 "vue条件渲染指令包括v-if.v-else.v-else-if.v-show. 语法 v-if="条件1&&条件2" # ...