mirror of
https://github.com/go-gst/go-gst.git
synced 2025-10-05 16:06:55 +08:00
finish gif encoding example use it to demonstrate queries
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
@@ -12,6 +13,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/tinyzimmer/go-gst/examples"
|
"github.com/tinyzimmer/go-gst/examples"
|
||||||
"github.com/tinyzimmer/go-gst/gst"
|
"github.com/tinyzimmer/go-gst/gst"
|
||||||
@@ -90,6 +92,22 @@ func encodeGif(mainLoop *gst.MainLoop) error {
|
|||||||
pipeline.Add(appSink.Element)
|
pipeline.Add(appSink.Element)
|
||||||
jpegenc.Link(appSink.Element)
|
jpegenc.Link(appSink.Element)
|
||||||
|
|
||||||
|
// Wee can query the decodebin for the duration of the video it received. We can then
|
||||||
|
// use this value to calculate the total number of frames we expect to produce.
|
||||||
|
query := gst.NewDurationQuery(gst.FormatTime)
|
||||||
|
if ok := self.Query(query); !ok {
|
||||||
|
err := gst.NewGError(3, errors.New("Failed to query video duration from decodebin"))
|
||||||
|
pipeline.GetPipelineBus().
|
||||||
|
Post(gst.NewErrorMessage(self, err, "", nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the result from the query.
|
||||||
|
_, val := query.ParseDuration()
|
||||||
|
|
||||||
|
// This value is in nanoseconds. Since we told theee videorate element to produce 5 frames
|
||||||
|
// per second, we can use this value to calculate the total number of frames to expect.
|
||||||
|
totalFrames := int((time.Duration(val) * time.Nanosecond).Seconds()) * 5
|
||||||
|
|
||||||
// Getting data out of the sink is done by setting callbacks. Each new sample
|
// Getting data out of the sink is done by setting callbacks. Each new sample
|
||||||
// will be a new jpeg image from the pipeline.
|
// will be a new jpeg image from the pipeline.
|
||||||
var frameNum int
|
var frameNum int
|
||||||
@@ -99,16 +117,24 @@ func encodeGif(mainLoop *gst.MainLoop) error {
|
|||||||
// sink.
|
// sink.
|
||||||
imgReader := sink.PullSample().GetBuffer().Reader()
|
imgReader := sink.PullSample().GetBuffer().Reader()
|
||||||
|
|
||||||
|
// Increment the frame number counter
|
||||||
|
frameNum++
|
||||||
|
|
||||||
|
if frameNum > totalFrames {
|
||||||
|
// If we've reached the total number of frames we are expecting. We can
|
||||||
|
// signal the main loop to quit.
|
||||||
|
mainLoop.Quit()
|
||||||
|
return gst.FlowEOS
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("\033[2K\rProcessing image frame %d/%d", frameNum, totalFrames)
|
||||||
|
|
||||||
img, err := jpeg.Decode(imgReader)
|
img, err := jpeg.Decode(imgReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error decoding jpeg frame:", err)
|
fmt.Println("Error decoding jpeg frame:", err)
|
||||||
return gst.FlowError
|
return gst.FlowError
|
||||||
}
|
}
|
||||||
|
|
||||||
frameNum++
|
|
||||||
fmt.Printf("\033[2K\rProcessing image frame %d", frameNum)
|
|
||||||
// fmt.Printf("Processing image frame %d\n", frameNum)
|
|
||||||
|
|
||||||
// Create a new paletted image with the same bounds as the pulled one
|
// Create a new paletted image with the same bounds as the pulled one
|
||||||
frame := image.NewPaletted(img.Bounds(), palette.Plan9)
|
frame := image.NewPaletted(img.Bounds(), palette.Plan9)
|
||||||
|
|
||||||
@@ -130,17 +156,14 @@ func encodeGif(mainLoop *gst.MainLoop) error {
|
|||||||
srcPad.Link(queue.GetStaticPad("sink"))
|
srcPad.Link(queue.GetStaticPad("sink"))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add a watch on the bus on the pipeline and wait for any errors
|
// Now that the pipeline is all set up we can start it.
|
||||||
// or the end of the stream.
|
pipeline.SetState(gst.StatePlaying)
|
||||||
|
|
||||||
|
// Add a watch on the bus on the pipeline and catch any errors
|
||||||
|
// that happen.
|
||||||
var isError bool
|
var isError bool
|
||||||
pipeline.GetPipelineBus().AddWatch(func(msg *gst.Message) bool {
|
pipeline.GetPipelineBus().AddWatch(func(msg *gst.Message) bool {
|
||||||
switch msg.Type() {
|
switch msg.Type() {
|
||||||
// Uncomment this for very debuggy output
|
|
||||||
// default:
|
|
||||||
// fmt.Println(msg)
|
|
||||||
case gst.MessageEOS:
|
|
||||||
mainLoop.Quit()
|
|
||||||
return false
|
|
||||||
case gst.MessageError:
|
case gst.MessageError:
|
||||||
err := msg.ParseError()
|
err := msg.ParseError()
|
||||||
fmt.Println("ERROR:", err.Error())
|
fmt.Println("ERROR:", err.Error())
|
||||||
@@ -157,12 +180,11 @@ func encodeGif(mainLoop *gst.MainLoop) error {
|
|||||||
|
|
||||||
fmt.Println("Encoding video to gif")
|
fmt.Println("Encoding video to gif")
|
||||||
|
|
||||||
// Now that the pipeline is all set up we can start it.
|
|
||||||
pipeline.SetState(gst.StatePlaying)
|
|
||||||
|
|
||||||
// Iterate on the main loop until the pipeline is finished.
|
// Iterate on the main loop until the pipeline is finished.
|
||||||
mainLoop.Run()
|
mainLoop.Run()
|
||||||
|
|
||||||
|
// Print an extra line since we were doing fancy carriage return stuff
|
||||||
|
// from th app sink
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
// If no error happened on the pipeline. Write the results of the gif
|
// If no error happened on the pipeline. Write the results of the gif
|
||||||
@@ -179,7 +201,7 @@ func encodeGif(mainLoop *gst.MainLoop) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return pipeline.Destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -206,6 +228,7 @@ func main() {
|
|||||||
} else {
|
} else {
|
||||||
outFile = strings.Join(spl[:len(spl)-2], ".")
|
outFile = strings.Join(spl[:len(spl)-2], ".")
|
||||||
}
|
}
|
||||||
|
outFile = outFile + ".gif"
|
||||||
}
|
}
|
||||||
|
|
||||||
examples.RunLoop(func(mainLoop *gst.MainLoop) error {
|
examples.RunLoop(func(mainLoop *gst.MainLoop) error {
|
||||||
|
Reference in New Issue
Block a user