mirror of
https://github.com/qrtc/ffmpeg-dev-go.git
synced 2025-10-01 22:22:06 +08:00
116 lines
3.3 KiB
Go
116 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"syscall"
|
|
"unsafe"
|
|
|
|
ffmpeg "github.com/qrtc/ffmpeg-dev-go"
|
|
)
|
|
|
|
func fillYuvImage(data [4]*uint8, linesize [4]int32, width, height, frameIndex int32) {
|
|
// Y
|
|
data0 := unsafe.Slice(data[0], height*linesize[0]+width)
|
|
for y := int32(0); y < height; y++ {
|
|
for x := int32(0); x < width; x++ {
|
|
data0[y*linesize[0]+x] = (uint8)(x + y + frameIndex*3)
|
|
}
|
|
}
|
|
|
|
// Cb and Cr
|
|
data1 := unsafe.Slice(data[1], height*width/4)
|
|
data2 := unsafe.Slice(data[2], height*width/4)
|
|
for y := int32(0); y < height/2; y++ {
|
|
for x := int32(0); x < width/2; x++ {
|
|
data1[y*linesize[1]+x] = (uint8)(128 + y + frameIndex*2)
|
|
data2[y*linesize[2]+x] = (uint8)(64 + x + frameIndex*5)
|
|
}
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
var ret int32
|
|
var dstBufsize int32
|
|
var srcW int32 = 320
|
|
var srcH int32 = 240
|
|
var dstW, dstH int32
|
|
var srcData, dstData [4]*uint8
|
|
var srcLinesize, dstLinesize [4]int32
|
|
var srcPixFmt = ffmpeg.AV_PIX_FMT_YUV420P
|
|
var dstPixFmt = ffmpeg.AV_PIX_FMT_RGB24
|
|
|
|
if len(os.Args) != 3 {
|
|
fmt.Fprintf(os.Stderr, "Usage: %s output_file output_size\n"+
|
|
"API example program to show how to scale an image with libswscale.\n"+
|
|
"This program generates a series of pictures, rescales them to the given "+
|
|
"output_size and saves them to an output file named output_file\n."+
|
|
"\n", os.Args[0])
|
|
os.Exit(1)
|
|
}
|
|
dstFilename := os.Args[1]
|
|
dstSize := os.Args[2]
|
|
|
|
if ret = ffmpeg.AvParseVideoSize(&dstW, &dstH, dstSize); ret < 0 {
|
|
fmt.Fprintf(os.Stderr,
|
|
"Invalid size '%s', must be in the form WxH or a valid size abbreviation\n", dstSize)
|
|
os.Exit(1)
|
|
}
|
|
|
|
dstFile, err := os.OpenFile(dstFilename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Could not open %s\n", dstFilename)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// create scaling context
|
|
swsCtx := ffmpeg.SwsGetContext(srcW, srcH, srcPixFmt,
|
|
dstW, dstH, dstPixFmt,
|
|
ffmpeg.SWS_BILINEAR, nil, nil, nil)
|
|
if swsCtx == nil {
|
|
fmt.Fprintf(os.Stderr, "Impossible to create scale context for the conversion "+
|
|
"fmt:%s s:%dx%d -> fmt:%s s:%dx%d\n",
|
|
ffmpeg.AvGetPixFmtName(srcPixFmt), srcW, srcH,
|
|
ffmpeg.AvGetPixFmtName(dstPixFmt), dstW, dstH)
|
|
ret = ffmpeg.AVERROR(syscall.EINVAL)
|
|
goto end
|
|
}
|
|
|
|
// allocate source and destination image buffers
|
|
if ret = ffmpeg.AvImageAlloc(srcData[:], srcLinesize[:], srcW, srcH, srcPixFmt, 16); ret < 0 {
|
|
fmt.Fprintf(os.Stderr, "Could not allocate source image\n")
|
|
goto end
|
|
}
|
|
|
|
// buffer is going to be written to rawvideo file, no alignment
|
|
if ret = ffmpeg.AvImageAlloc(dstData[:], dstLinesize[:], dstW, dstH, dstPixFmt, 1); ret < 0 {
|
|
fmt.Fprintf(os.Stderr, "Could not allocate destination image\n")
|
|
goto end
|
|
}
|
|
dstBufsize = ret
|
|
|
|
for i := int32(0); i < 100; i++ {
|
|
// generate synthetic video
|
|
fillYuvImage(srcData, srcLinesize, srcW, srcH, i)
|
|
|
|
// convert to destination format
|
|
ffmpeg.SwsScale(swsCtx, srcData[:], srcLinesize[:], 0, srcH, dstData[:], dstLinesize[:])
|
|
|
|
// write scaled image to file
|
|
dstFile.Write(unsafe.Slice(dstData[0], dstBufsize))
|
|
}
|
|
|
|
fmt.Fprintf(os.Stderr, "Scaling succeeded. Play the output file with the command:\n"+
|
|
"ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",
|
|
ffmpeg.AvGetPixFmtName(dstPixFmt), dstW, dstH, dstFilename)
|
|
|
|
end:
|
|
dstFile.Close()
|
|
ffmpeg.AvFreep(&srcData[0])
|
|
ffmpeg.AvFreep(&dstData[0])
|
|
ffmpeg.SwsFreeContext(swsCtx)
|
|
if ret < 0 {
|
|
os.Exit(1)
|
|
}
|
|
}
|