在现代社交媒体的时代,视频已经成为了人们分享生活、记录瞬间的重要方式之一。而对于制作视频来说,添加文字和图片元素可以起到丰富内容、增强表达能力的作用。那么,如何使用Go语言和FFmpeg来实现视频中添...
在现代社交媒体的时代,视频已经成为了人们分享生活、记录瞬间的重要方式之一。而对于制作视频来说,添加文字和图片元素可以起到丰富内容、增强表达能力的作用。那么,如何使用Go语言和FFmpeg来实现视频中添加文字和图片呢?
首先,我们需要了解一下Go语言和FFmpeg。Go语言作为一种开源编程语言,以其简洁高效的特点被广泛应用于各个领域。FFmpeg是一个强大的多媒体处理工具,它支持各种格式的音视频处理,包括视频剪辑、合并、转码等功能。
要在视频中添加文字,我们可以使用Go语言的FFmpeg绑定库来实现。首先,我们需要安装Go语言的FFmpeg绑定库,可以通过在终端中运行以下命令来安装:
go get -u github.com/giorgisio/goav/avcodec
go get -u github.com/giorgisio/goav/avutil
安装完成后,我们就可以使用Go语言来调用FFmpeg提供的各种功能了。接下来,我们需要加载视频文件,并创建一个用于渲染文字的函数。在这个函数中,我们可以使用FFmpeg提供的字幕过滤器来向视频中添加文字。具体的代码如下:
go
package main
import (
"github.com/giorgisio/goav/avcodec"
"github.com/giorgisio/goav/avformat"
"github.com/giorgisio/goav/avutil"
"github.com/giorgisio/goav/swscale"
)
func main() {
inputFileName := "input.mp4"
outputFileName := "output.mp4"
avformat.AvRegisterAll()
ctx := avformat.AvformatAllocContext()
if avformat.AvformatOpenInput(&ctx, inputFileName, nil, nil) < 0
return
if ctx.AvformatFindStreamInfo(nil) < 0
return
videoStream := -1
for i := 0; i < len(ctx.Streams()); i++ {
if ctx.Streams()[i].CodecParameters().CodecType() == avcodec.AVMEDIA_TYPE_VIDEO
videoStream = i
break
}
if videoStream == -1
return
decoder := ctx.Streams()[videoStream].Codec().AvcodecFindDecoder()
if decoder == nil
return
ctx.Streams()[videoStream].Codec().AvcodecOpen2(decoder, nil)
frame := avutil.AvFrameAlloc()
videoWidth := int(ctx.Streams()[videoStream].CodecParameters().Width())
videoHeight := int(ctx.Streams()[videoStream].CodecParameters().Height())
frameBuffer := avutil.AvMalloc(videoWidth * videoHeight * 3 / 2)
avformat.AvImageFillArrays(frame.Data(),
frame.Linesize(),
frameBuffer,
avcodec.AV_PIX_FMT_YUV420P,
videoWidth,
videoHeight,
1)
frameRgb := avutil.AvFrameAlloc()
rgbWidth := 1280
rgbHeight := 720
frameBufferRgb := avutil.AvMalloc(rgbWidth * rgbHeight * 3)
avutil.AvFrameSetData(frameRgb,
&frameBufferRgb,
[4]int32{int32(rgbWidth * 3), 0, 0, 0})
swsCtx := swscale.SwsGetcontext(
videoWidth,
videoHeight,
decoder.PixFmt(),
rgbWidth,
rgbHeight,
avcodec.AV_PIX_FMT_RGB24,
swscale.SWS_BICUBIC,
nil,
nil,
nil)
for {
pkt := avformat.AvPacketAlloc()
if ctx.AvReadFrame(pkt) < 0
break
if pkt.StreamIndex() == videoStream {
frameFinished := 0
ctx.Streams()[videoStream].Codec().AvcodecDecodeVideo2(frame, &frameFinished, pkt)
if frameFinished > 0 {
swsctx.Scale(frame.Data(),
frame.Linesize(),
0,
videoHeight,
rgbWidth,
rgbHeight,
frameRgb.Data(),
frameRgb.Linesize())
// 在这里添加文字,可以使用FFmpeg提供的字幕过滤器来实现
// 具体的代码可以根据需求来进行修改和扩展
// 将处理后的数据写入输出文件
// avcodec.AvFrameGetPts(frameRgb)
fmt.Println("frame pts:", framePts, avcodec.AvFrameGetPts(pkt))
}
}
pkt.AvPacketUnref()
}
avformat.AvformatCloseInput(&ctx)
fmt.Println("Done!")
}
当然,如果我们还希望在视频中添加图片元素,我们可以借助Go语言的图像处理库,github.com/disintegration/imaging
。我们可以先将图片按照需要的尺寸进行缩放,然后再将其与视频帧进行合并。具体的代码如下:
go
package main
import (
"fmt"
"image"
"image/draw"
"os"
"github.com/disintegration/imaging"
"github.com/giorgisio/goav/avcodec"
"github.com/giorgisio/goav/avfilter"
"github.com/giorgisio/goav/avformat"
"github.com/giorgisio/goav/avutil"
)
func main() {
inputFileName := "input.mp4"
outputFileName := "output.mp4"
overlayImageFileName := "logo.png"
decoder, err := avcodec.FindDecoder(avcodec.CodecID(avcodec.VideoCodecID(avformat.AV_CODEC_ID_H264)))
if err != nil {
panic(err)
}
ctx := avformat.AvformatAllocContext()
if avformat.OpenInput(&ctx, inputFileName, nil, nil) != 0 {
panic("Error: Couldn't open file.")
}
if avformat.FindStreamInfo(ctx) < 0 {
panic("Error: Couldn't find stream information.")
}
videoStream := -1
for i := 0; i < len(ctx.Streams()); i++ {
if ctx.Streams()[i].CodecType() == avcodec.AVMEDIA_TYPE_VIDEO
videoStream = i
break
}
if videoStream == -1 {
panic("Error: Couldn't find video stream.")
}
decoderCtx := ctx.Streams()[videoStream].Codec()
if decoderCtx == nil {
panic("Error: Couldn't find codec.")
}
if decoderCtx.AvcodecOpen2(decoder, nil) < 0 {
panic("Error: Couldn't open codec.")
}
frame := avutil.AvFrameAlloc()
frameRgb := avutil.AvFrameAlloc()
width := decoderCtx.Width()
height := decoderCtx.Height()
size := width * height * 3
buffer := avutil.AvMalloc(int(size))
avutil.AvFrameSetData(frameRgb,
&buffer,
[4]int32{int32(width * 3), 0, 0, 0})
swsCtx := swscale.SwsGetcontext(width,
height,
avutil.PixelFormat(decoderCtx.PixFmt()),
width,
height,
avutil.AV_PIX_FMT_RGB24,
swscale.SWS_BICUBIC,
nil,
nil,
nil)
for {
ret, frameFinished, pkt := avformat.AvReadFrame(ctx)
if ret < 0
break
if pkt.StreamIndex() == videoStream {
decoderCtx.AvcodecDecodeVideo2(frame, &frameFinished, pkt)
if frameFinished > 0 {
swscale.SwsScale(swsCtx,
frame.Data(),
frame.Linesize(),
0,
height,
frameRgb.Data(),
frameRgb.Linesize())
// 打开图片文件
imageFile, err := os.Open(overlayImageFileName)
if err != nil {
panic(err)
}
defer imageFile.Close()
// 解码图片文件
imageData, _, err := image.Decode(imageFile)
if err != nil {
panic(err)
}
// 将图片缩放到指定大小
overlayImage := imaging.Resize(imageData, width/4, height/4, imaging.Lanczos)
// 创建一个新的RGBA图像
rgba := image.NewRGBA(overlayImage.Bounds())
// 将图片绘制到新图像上
draw.Draw(rgba, overlayImage.Bounds(), overlayImage, image.Pt(0, 0), draw.Src)
// 创建一个新的AVFrame,作为视频帧与图片合成的结果
resultFrame := avutil.AvFrameAlloc()
avutil.AvFrameCopy(resultFrame, frame)
// 将图片绘制到视频帧上
for y := 0; y < rgba.Bounds().Max.Y; y++ {
for x := 0; x < rgba.Bounds().Max.X; x++ {
r, g, b, a := rgba.At(x, y).RGBA()
avutil.AvFrameSetRGB(resultFrame, x, y, uint8(r>>8), uint8(g>>8), uint8(b>>8))
avutil.AvFrameSetAlpha(resultFrame, x, y, uint8(a>>8))
}
}
// 根据合成的结果创建一个新的AVPacket,并将其写入输出文件
resultPacket := new(avcodec.Packet)
avcodec.AvPacketFromData(resultPacket, frameRgb.Data(), frameRgb.Linesize())
// 将目标文件路径转为存储路径用的字符串
resultPacketDataString := fmt.Sprintf("%s", outputFileName)
// 将文件的字符串写入文件
resultPacketDataByte := []byte(resultPacketDataString)
err = ioutil.WriteFile(resultPacket.Data(), []byte(resultPacketDataByte), 0644)
if err != nil {
panic(err)
}
// 关闭目标文件
f.Close()
// 判断是否写入成功
if err != nil {
panic(err)
}
fmt.Println("frame pts:", frame.Pts(), pkt.Pts())
}
}
avutil.AvFreePacket(pkt)
}
avformat.AvformatCloseInput(ctx)
avutil.AvFrameFree(frame)22
avutil.AvFrameFree(frameRgb)
}
使用Go语言和FFmpeg,我们可以轻松地实现视频中添加文字和图片的功能。无论是为了更好地传达信息,还是为了增加视频的趣味性,这样的功能都能帮助我们达到目标。随着技术的进步和应用的拓展,我们相信,视频编辑的方式还会越来越丰富多样,为人们带来更多的乐趣和创造力的发挥空间。