Skip to content

Instantly share code, notes, and snippets.

@tfriedel6
Created October 20, 2018 10:47
Show Gist options
  • Save tfriedel6/be453334bd025ded790b5d11ea584ca2 to your computer and use it in GitHub Desktop.
Save tfriedel6/be453334bd025ded790b5d11ea584ca2 to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"image"
"log"
"os"
"github.com/3d0c/gmf"
"github.com/tfriedel6/canvas"
"github.com/tfriedel6/canvas/sdlcanvas"
)
func main() {
if len(os.Args) <= 1 {
fmt.Println("Need video file name as command line parameter")
return
}
wnd, cv, err := sdlcanvas.CreateWindow(1280, 720, "Canvas Test")
if err != nil {
log.Println(err)
return
}
defer wnd.Destroy()
inputCtx, err := gmf.NewInputCtx(os.Args[1])
if err != nil {
panic(err)
}
defer inputCtx.CloseInputAndRelease()
srcVideoStream, err := inputCtx.GetBestStream(gmf.AVMEDIA_TYPE_VIDEO)
if err != nil {
panic(fmt.Sprint("No video stream found in", os.Args[1]))
}
codec, err := gmf.FindEncoder(gmf.AV_CODEC_ID_RAWVIDEO)
if err != nil {
panic(err)
}
cc := gmf.NewCodecCtx(codec)
defer gmf.Release(cc)
cc.SetTimeBase(gmf.AVR{Num: 1, Den: 1})
// This should really be AV_PIX_FMT_RGB32, but then red and blue channels are switched
cc.SetPixFmt(gmf.AV_PIX_FMT_BGR32).SetWidth(srcVideoStream.CodecCtx().Width()).SetHeight(srcVideoStream.CodecCtx().Height())
if codec.IsExperimental() {
cc.SetStrictCompliance(gmf.FF_COMPLIANCE_EXPERIMENTAL)
}
if err := cc.Open(nil); err != nil {
panic(err)
}
swsCtx := gmf.NewSwsCtx(srcVideoStream.CodecCtx(), cc, gmf.SWS_BICUBIC)
defer gmf.Release(swsCtx)
dstFrame := gmf.NewFrame().
SetWidth(srcVideoStream.CodecCtx().Width()).
SetHeight(srcVideoStream.CodecCtx().Height()).
SetFormat(gmf.AV_PIX_FMT_BGR32) // see above
defer gmf.Release(dstFrame)
if err := dstFrame.ImgAlloc(); err != nil {
panic(err)
}
ist, err := inputCtx.GetStream(srcVideoStream.Index())
if err != nil {
panic(err)
}
defer gmf.Release(ist)
codecCtx := ist.CodecCtx()
defer gmf.Release(codecCtx)
nextFrame := true
wnd.KeyDown = func(scancode int, rn rune, name string) {
nextFrame = true
}
vidImg, _ := canvas.LoadImage(nil)
wnd.MainLoop(func() {
cv.ClearRect(0, 0, 1280, 720)
if nextFrame {
// nextFrame = false
for packet := range inputCtx.GetNewPackets() {
if packet.StreamIndex() != srcVideoStream.Index() {
// skip non video streams
continue
}
frame, err := packet.Frames(codecCtx)
if err != nil {
fmt.Println(err)
break
}
swsCtx.Scale(frame, dstFrame)
p, err := dstFrame.Encode(cc)
if err != nil {
fmt.Println(err)
break
}
width, height := frame.Width(), frame.Height()
img := new(image.RGBA)
img.Pix = p.Data()
img.Stride = 4 * width // 4 bytes per pixel (RGBA), width times per row
img.Rect = image.Rect(0, 0, width, height)
vidImg.Replace(img)
gmf.Release(p)
gmf.Release(frame)
gmf.Release(packet)
break
}
}
cv.DrawImage(vidImg, 0, 0)
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment