mirror of
https://github.com/go-gst/go-gst.git
synced 2025-10-05 16:06:55 +08:00
add appsink example back and add more mapinfo data access funcs
This commit is contained in:
129
examples/appsink/main.go
Normal file
129
examples/appsink/main.go
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
// This example shows how to use the appsink element.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
|
||||||
|
"github.com/go-gst/go-gst/pkg/gst"
|
||||||
|
"github.com/go-gst/go-gst/pkg/gstapp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createPipeline() (gst.Pipeline, error) {
|
||||||
|
gst.Init()
|
||||||
|
|
||||||
|
pipeline := gst.NewPipeline("").(gst.Pipeline)
|
||||||
|
|
||||||
|
src := gst.ElementFactoryMake("audiotestsrc", "")
|
||||||
|
sink := gst.ElementFactoryMake("appsink", "").(gstapp.AppSink)
|
||||||
|
|
||||||
|
pipeline.AddMany(src, sink)
|
||||||
|
src.Link(sink)
|
||||||
|
|
||||||
|
// Tell the appsink what format we want. It will then be the audiotestsrc's job to
|
||||||
|
// provide the format we request.
|
||||||
|
// This can be set after linking the two objects, because format negotiation between
|
||||||
|
// both elements will happen during pre-rolling of the pipeline.
|
||||||
|
sink.SetCaps(gst.CapsFromString(
|
||||||
|
"audio/x-raw, format=S16LE, layout=interleaved, channels=1",
|
||||||
|
))
|
||||||
|
|
||||||
|
sink.ConnectNewSample(func(sink gstapp.AppSink) gst.FlowReturn {
|
||||||
|
// Pull the sample that triggered this callback
|
||||||
|
sample := sink.PullSample()
|
||||||
|
if sample == nil {
|
||||||
|
return gst.FlowEos
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the buffer from the sample
|
||||||
|
buffer := sample.GetBuffer()
|
||||||
|
if buffer == nil {
|
||||||
|
return gst.FlowError
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, buffer is only a reference to an existing memory region somewhere.
|
||||||
|
// When we want to access its content, we have to map it while requesting the required
|
||||||
|
// mode of access (read, read/write).
|
||||||
|
//
|
||||||
|
// We also know what format to expect because we set it with the caps. So we convert
|
||||||
|
// the map directly to signed 16-bit little-endian integers.
|
||||||
|
mapInfo, ok := buffer.Map(gst.MapRead)
|
||||||
|
if !ok {
|
||||||
|
return gst.FlowError
|
||||||
|
}
|
||||||
|
defer mapInfo.Unmap()
|
||||||
|
|
||||||
|
// Calculate the root mean square for the buffer
|
||||||
|
// (https://en.wikipedia.org/wiki/Root_mean_square)
|
||||||
|
|
||||||
|
samples := mapInfo.Int16Data(binary.LittleEndian)
|
||||||
|
var square float64
|
||||||
|
for _, i := range samples {
|
||||||
|
square += float64(i * i)
|
||||||
|
}
|
||||||
|
rms := math.Sqrt(square / float64(len(samples)))
|
||||||
|
fmt.Println("rms:", rms)
|
||||||
|
|
||||||
|
return gst.FlowOK
|
||||||
|
})
|
||||||
|
|
||||||
|
return pipeline, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMessage(msg *gst.Message) error {
|
||||||
|
switch msg.Type() {
|
||||||
|
case gst.MessageEos:
|
||||||
|
return fmt.Errorf("end of stream")
|
||||||
|
case gst.MessageError:
|
||||||
|
debug, gerr := msg.ParseError()
|
||||||
|
if debug != "" {
|
||||||
|
fmt.Println(debug)
|
||||||
|
}
|
||||||
|
return gerr
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runPipeline(pipeline gst.Pipeline) error {
|
||||||
|
|
||||||
|
// Start the pipeline
|
||||||
|
pipeline.SetState(gst.StatePlaying)
|
||||||
|
|
||||||
|
// Retrieve the bus from the pipeline
|
||||||
|
bus := pipeline.GetBus()
|
||||||
|
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(c, os.Interrupt)
|
||||||
|
go func() {
|
||||||
|
<-c
|
||||||
|
pipeline.SendEvent(gst.NewEventEos())
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Loop over messsages from the pipeline
|
||||||
|
for {
|
||||||
|
msg := bus.TimedPop(gst.ClockTimeNone)
|
||||||
|
if msg == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err := handleMessage(msg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
pipeline, err := createPipeline()
|
||||||
|
if err != nil {
|
||||||
|
println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = runPipeline(pipeline)
|
||||||
|
|
||||||
|
println(err)
|
||||||
|
}
|
@@ -1,8 +1,10 @@
|
|||||||
package gst
|
package gst
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"runtime"
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@@ -206,12 +208,152 @@ func (info *MapInfo) Length() int {
|
|||||||
return int(info.mapInfo.native.size)
|
return int(info.mapInfo.native.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Length returns the length of the mapped memory.
|
|
||||||
func (info *MapInfo) Data() []byte {
|
|
||||||
return unsafe.Slice((*byte)(info.mapInfo.native.data), info.mapInfo.native.size)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flags returns the flags of the mapped memory.
|
// Flags returns the flags of the mapped memory.
|
||||||
func (info *MapInfo) Flags() MapFlags {
|
func (info *MapInfo) Flags() MapFlags {
|
||||||
return MapFlags(info.mapInfo.native.flags)
|
return MapFlags(info.mapInfo.native.flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Data returns the mapped memory as a byte slice.
|
||||||
|
func (info *MapInfo) Data() []byte {
|
||||||
|
if info.mapInfo == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !info.Flags().Has(MapRead) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return unsafe.Slice((*byte)(info.mapInfo.native.data), info.mapInfo.native.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32Data returns a copy of the data as a slice of float32 with the given byte order (endianess).
|
||||||
|
func (info *MapInfo) Float32Data(byteOrder binary.ByteOrder) []float32 {
|
||||||
|
|
||||||
|
floats := make([]float32, info.Length()/4)
|
||||||
|
|
||||||
|
for i := range floats {
|
||||||
|
bits := byteOrder.Uint32(info.Data()[i*4 : (i+1)*4])
|
||||||
|
floats[i] = math.Float32frombits(bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
return floats
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Data returns a copy of the data as a slice of float64 with the given byte order (endianess).
|
||||||
|
func (info *MapInfo) Float64Data(byteOrder binary.ByteOrder) []float64 {
|
||||||
|
|
||||||
|
floats := make([]float64, info.Length()/8)
|
||||||
|
|
||||||
|
for i := range floats {
|
||||||
|
bits := byteOrder.Uint64(info.Data()[i*8 : (i+1)*8])
|
||||||
|
floats[i] = math.Float64frombits(bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
return floats
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsafeData is used to save on a cast to unsafe.Pointer in the ...Data() functions
|
||||||
|
func (info *MapInfo) unsafeData() unsafe.Pointer {
|
||||||
|
return unsafe.Pointer(info.mapInfo.native.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int8Data returns the mapped data as a slice of int8.
|
||||||
|
func (info *MapInfo) Int8Data() []int8 {
|
||||||
|
if info.mapInfo == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !info.Flags().Has(MapRead) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return unsafe.Slice((*int8)(info.unsafeData()), info.mapInfo.native.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint8Data returns the mapped data as a slice of uint8.
|
||||||
|
func (info *MapInfo) Uint8Data() []uint8 {
|
||||||
|
if info.mapInfo == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !info.Flags().Has(MapRead) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return unsafe.Slice((*uint8)(info.unsafeData()), info.mapInfo.native.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint16Data returns a copy of the data as a slice of uint16 with the given byte order (endianess).
|
||||||
|
func (info *MapInfo) Uint16Data(byteOrder binary.ByteOrder) []uint16 {
|
||||||
|
data := info.Data()
|
||||||
|
ints := make([]uint16, len(data)/2)
|
||||||
|
|
||||||
|
for i := range ints {
|
||||||
|
bits := byteOrder.Uint16(data[i*2 : (i+1)*2])
|
||||||
|
ints[i] = bits
|
||||||
|
}
|
||||||
|
|
||||||
|
return ints
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16Data returns a copy of the data as a slice of int16 with the given byte order (endianess).
|
||||||
|
func (info *MapInfo) Int16Data(byteOrder binary.ByteOrder) []int16 {
|
||||||
|
data := info.Data()
|
||||||
|
ints := make([]int16, len(data)/2)
|
||||||
|
|
||||||
|
for i := range ints {
|
||||||
|
bits := byteOrder.Uint16(data[i*2 : (i+1)*2])
|
||||||
|
ints[i] = int16(bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ints
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint32Data returns a copy of the data as a slice of uint32 with the given byte order (endianess).
|
||||||
|
func (info *MapInfo) Uint32Data(byteOrder binary.ByteOrder) []uint32 {
|
||||||
|
data := info.Data()
|
||||||
|
ints := make([]uint32, len(data)/4)
|
||||||
|
|
||||||
|
for i := range ints {
|
||||||
|
bits := byteOrder.Uint32(data[i*4 : (i+1)*4])
|
||||||
|
ints[i] = bits
|
||||||
|
}
|
||||||
|
|
||||||
|
return ints
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32Data returns a copy of the data as a slice of int32 with the given byte order (endianess).
|
||||||
|
func (info *MapInfo) Int32Data(byteOrder binary.ByteOrder) []int32 {
|
||||||
|
data := info.Data()
|
||||||
|
ints := make([]int32, len(data)/4)
|
||||||
|
|
||||||
|
for i := range ints {
|
||||||
|
bits := byteOrder.Uint32(data[i*4 : (i+1)*4])
|
||||||
|
ints[i] = int32(bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ints
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64Data returns a copy of the data as a slice of uint64 with the given byte order (endianess).
|
||||||
|
func (info *MapInfo) Uint64Data(byteOrder binary.ByteOrder) []uint64 {
|
||||||
|
data := info.Data()
|
||||||
|
ints := make([]uint64, len(data)/8)
|
||||||
|
|
||||||
|
for i := range ints {
|
||||||
|
bits := byteOrder.Uint64(data[i*8 : (i+1)*8])
|
||||||
|
ints[i] = bits
|
||||||
|
}
|
||||||
|
|
||||||
|
return ints
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64Data returns a copy of the data as a slice of int64 with the given byte order (endianess).
|
||||||
|
func (info *MapInfo) Int64Data(byteOrder binary.ByteOrder) []int64 {
|
||||||
|
data := info.Data()
|
||||||
|
ints := make([]int64, len(data)/8)
|
||||||
|
|
||||||
|
for i := range ints {
|
||||||
|
bits := byteOrder.Uint64(data[i*8 : (i+1)*8])
|
||||||
|
ints[i] = int64(bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ints
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user