mirror of
https://github.com/go-gst/go-gst.git
synced 2026-04-22 23:57:18 +08:00
add GstBaseSink and filesink example
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/tinyzimmer/go-glib/glib"
|
||||
"github.com/tinyzimmer/go-gst/gst"
|
||||
"github.com/tinyzimmer/go-gst/gst/base"
|
||||
)
|
||||
|
||||
// CAT is the log category for the gofilesink. It is safe to define GStreamer objects as globals
|
||||
// without calling gst.Init, since in the context of a loaded plugin all initialization has
|
||||
// already been taken care of by the loading application.
|
||||
var CAT = gst.NewDebugCategory(
|
||||
"gofilesink",
|
||||
gst.DebugColorNone,
|
||||
"GoFileSink Element",
|
||||
)
|
||||
|
||||
// Here we define a list of ParamSpecs that will make up the properties for our element.
|
||||
// This element only has a single property, the location of the file to write to.
|
||||
// When getting and setting properties later on, you will reference them by their index in
|
||||
// this list.
|
||||
var properties = []*gst.ParameterSpec{
|
||||
gst.NewStringParameter(
|
||||
"location", // The name of the parameter
|
||||
"File Location", // The long name for the parameter
|
||||
"Location to write the file to", // A blurb about the parameter
|
||||
nil, // A default value for the parameter
|
||||
gst.ParameterReadWrite, // Flags for the parameter
|
||||
),
|
||||
}
|
||||
|
||||
// Here we declare a private struct to hold our internal state.
|
||||
type state struct {
|
||||
// Whether the element is started or not
|
||||
started bool
|
||||
// The file the element is writing to
|
||||
file *os.File
|
||||
// The current position in the file
|
||||
position uint64
|
||||
}
|
||||
|
||||
// This is another private struct where we hold the parameter values set on our
|
||||
// element.
|
||||
type settings struct {
|
||||
location string
|
||||
}
|
||||
|
||||
// Finally a structure is defined that implements (at a minimum) the gst.GoElement interface.
|
||||
// It is possible to signal to the bindings to inherit from other classes or implement other
|
||||
// interfaces via the registration and TypeInit processes.
|
||||
type fileSink struct {
|
||||
// The settings for the element
|
||||
settings *settings
|
||||
// The current state of the element
|
||||
state *state
|
||||
}
|
||||
|
||||
// setLocation is a simple method to check the validity of a provided file path and set the
|
||||
// local value with it.
|
||||
func (f *fileSink) setLocation(path string) error {
|
||||
if f.state.started {
|
||||
return errors.New("Changing the `location` property on a started `GoFileSink` is not supported")
|
||||
}
|
||||
f.settings.location = strings.TrimPrefix(path, "file://") // should obviously use url.URL and do actual parsing
|
||||
return nil
|
||||
}
|
||||
|
||||
// The ObjectSubclass implementations below are for registering the various aspects of our
|
||||
// element and its capabilities with the type system. These are the minimum methods that
|
||||
// should be implemented by an element.
|
||||
|
||||
// Every element needs to provide its own constructor that returns an initialized
|
||||
// gst.GoElement implementation. Here we simply create a new fileSink with zeroed settings
|
||||
// and state objects.
|
||||
func (f *fileSink) New() gst.GoElement {
|
||||
CAT.Log(gst.LevelLog, "Initializing new fileSink object")
|
||||
return &fileSink{
|
||||
settings: &settings{},
|
||||
state: &state{},
|
||||
}
|
||||
}
|
||||
|
||||
// The TypeInit method should register any additional interfaces provided by the element.
|
||||
// In this example we signal to the type system that we also implement the GstURIHandler interface.
|
||||
func (f *fileSink) TypeInit(instance *gst.TypeInstance) {
|
||||
CAT.Log(gst.LevelLog, "Adding URIHandler interface to type")
|
||||
instance.AddInterface(gst.InterfaceURIHandler)
|
||||
}
|
||||
|
||||
// The ClassInit method should specify the metadata for this element and add any pad templates
|
||||
// and properties.
|
||||
func (f *fileSink) ClassInit(klass *gst.ElementClass) {
|
||||
CAT.Log(gst.LevelLog, "Initializing gofilesink class")
|
||||
klass.SetMetadata(
|
||||
"File Sink",
|
||||
"Sink/File",
|
||||
"Write stream to a file",
|
||||
"Avi Zimmerman <avi.zimmerman@gmail.com>",
|
||||
)
|
||||
CAT.Log(gst.LevelLog, "Adding sink pad template and properties to class")
|
||||
klass.AddPadTemplate(gst.NewPadTemplate(
|
||||
"sink",
|
||||
gst.PadDirectionSink,
|
||||
gst.PadPresenceAlways,
|
||||
gst.NewAnyCaps(),
|
||||
))
|
||||
klass.InstallProperties(properties)
|
||||
}
|
||||
|
||||
// Object implementations are used during the initialization of an element. The
|
||||
// methods are called once the object is constructed and its properties are read
|
||||
// and written to. These and the rest of the methods described below are documented
|
||||
// in interfaces in the bindings, however only individual methods needs from those
|
||||
// interfaces need to be implemented. When left unimplemented, the behavior of the parent
|
||||
// class is inherited.
|
||||
|
||||
// SetProperty is called when a `value` is set to the property at index `id` in the
|
||||
// properties slice that we installed during ClassInit. It should attempt to register
|
||||
// the value locally or signal any errors that occur in the process.
|
||||
func (f *fileSink) SetProperty(self *gst.Object, id uint, value *glib.Value) {
|
||||
param := properties[id]
|
||||
switch param.Name() {
|
||||
case "location":
|
||||
var val string
|
||||
if value == nil {
|
||||
val = ""
|
||||
} else {
|
||||
val, _ = value.GetString()
|
||||
}
|
||||
if err := f.setLocation(val); err != nil {
|
||||
gst.ToElement(self).ErrorMessage(gst.DomainLibrary, gst.LibraryErrorSettings,
|
||||
fmt.Sprintf("Could not set location on object: %s", err.Error()),
|
||||
"",
|
||||
)
|
||||
return
|
||||
}
|
||||
self.Log(CAT, gst.LevelInfo, fmt.Sprintf("Set `location` to %s", f.settings.location))
|
||||
}
|
||||
}
|
||||
|
||||
// GetProperty is called to retrieve the value of the property at index `id` in the properties
|
||||
// slice provided at ClassInit.
|
||||
func (f *fileSink) GetProperty(self *gst.Object, id uint) *glib.Value {
|
||||
param := properties[id]
|
||||
switch param.Name() {
|
||||
case "location":
|
||||
if f.settings.location == "" {
|
||||
return nil
|
||||
}
|
||||
val, err := glib.GValue(f.settings.location)
|
||||
if err == nil {
|
||||
return val
|
||||
}
|
||||
gst.ToElement(self).ErrorMessage(gst.DomainLibrary, gst.LibraryErrorFailed,
|
||||
fmt.Sprintf("Could not convert %s to GValue", f.settings.location),
|
||||
err.Error(),
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GstBaseSink implementations are optional methods to implement from the base.GstBaseSinkImpl interface.
|
||||
// If the method is not overridden by the implementing struct, it will be inherited from the parent class.
|
||||
|
||||
// Start is called to start the filesink. Open the file for writing and set the internal state.
|
||||
func (f *fileSink) Start(self *base.GstBaseSink) bool {
|
||||
if f.state.started {
|
||||
self.ErrorMessage(gst.DomainResource, gst.ResourceErrorSettings, "GoFileSink is already started", "")
|
||||
return false
|
||||
}
|
||||
|
||||
if f.settings.location == "" {
|
||||
self.ErrorMessage(gst.DomainResource, gst.ResourceErrorSettings, "No location configured on the filesink", "")
|
||||
return false
|
||||
}
|
||||
|
||||
destFile := f.settings.location
|
||||
|
||||
var err error
|
||||
f.state.file, err = os.Create(destFile)
|
||||
if err != nil {
|
||||
self.ErrorMessage(gst.DomainResource, gst.ResourceErrorOpenWrite,
|
||||
fmt.Sprintf("Could not open %s for writing", destFile), err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
self.Log(CAT, gst.LevelDebug, fmt.Sprintf("Opened file %s for writing", destFile))
|
||||
|
||||
f.state.started = true
|
||||
self.Log(CAT, gst.LevelInfo, "GoFileSink has started")
|
||||
return true
|
||||
}
|
||||
|
||||
// Stop is called to stop the element. Set the internal state and close the file.
|
||||
func (f *fileSink) Stop(self *base.GstBaseSink) bool {
|
||||
if !f.state.started {
|
||||
self.ErrorMessage(gst.DomainResource, gst.ResourceErrorSettings, "GoFileSink is not started", "")
|
||||
return false
|
||||
}
|
||||
|
||||
if err := f.state.file.Close(); err != nil {
|
||||
self.ErrorMessage(gst.DomainResource, gst.ResourceErrorWrite, "Failed to close the destination file", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
self.Log(CAT, gst.LevelInfo, "GoFileSink has stopped")
|
||||
return true
|
||||
}
|
||||
|
||||
// Render is called when a buffer is ready to be written to the file.
|
||||
func (f *fileSink) Render(self *base.GstBaseSink, buffer *gst.Buffer) gst.FlowReturn {
|
||||
if !f.state.started {
|
||||
self.ErrorMessage(gst.DomainResource, gst.ResourceErrorSettings, "GoFileSink is not started", "")
|
||||
return gst.FlowError
|
||||
}
|
||||
|
||||
self.Log(CAT, gst.LevelTrace, fmt.Sprintf("Rendering buffer at %v", buffer.Instance()))
|
||||
newPos, err := io.Copy(f.state.file, buffer.Reader())
|
||||
if err != nil {
|
||||
self.ErrorMessage(gst.DomainResource, gst.ResourceErrorWrite, "Error copying buffer to file", err.Error())
|
||||
return gst.FlowError
|
||||
}
|
||||
|
||||
f.state.position += uint64(newPos)
|
||||
self.Log(CAT, gst.LevelTrace, fmt.Sprintf("New position in file: %v", f.state.position))
|
||||
|
||||
return gst.FlowOK
|
||||
}
|
||||
|
||||
// URIHandler implementations are the methods required by the GstURIHandler interface.
|
||||
|
||||
// GetURI returns the currently configured URI
|
||||
func (f *fileSink) GetURI() string { return fmt.Sprintf("file://%s", f.settings.location) }
|
||||
|
||||
// GetURIType returns the types of URI this element supports.
|
||||
func (f *fileSink) GetURIType() gst.URIType { return gst.URISource }
|
||||
|
||||
// GetProtocols returns the protcols this element supports.
|
||||
func (f *fileSink) GetProtocols() []string { return []string{"file"} }
|
||||
|
||||
// SetURI should set the URI that this element is working on.
|
||||
func (f *fileSink) SetURI(uri string) (bool, error) {
|
||||
if uri == "file://" {
|
||||
return true, nil
|
||||
}
|
||||
err := f.setLocation(uri)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
CAT.Log(gst.LevelInfo, fmt.Sprintf("Set `location` to %s via URIHandler", f.settings.location))
|
||||
return true, nil
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// The contents of this file could be generated from markers placed in filesink.go
|
||||
package main
|
||||
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/tinyzimmer/go-gst/gst"
|
||||
"github.com/tinyzimmer/go-gst/gst/base"
|
||||
)
|
||||
|
||||
// The metadata for this plugin
|
||||
var pluginMeta = &gst.PluginMetadata{
|
||||
MajorVersion: gst.VersionMajor,
|
||||
MinorVersion: gst.VersionMinor,
|
||||
Name: "go-filesink-plugin",
|
||||
Description: "File plugins written in Go",
|
||||
Version: "v0.0.1",
|
||||
License: gst.LicenseLGPL,
|
||||
Source: "go-gst",
|
||||
Package: "examples",
|
||||
Origin: "https://github.com/tinyzimmer/go-gst",
|
||||
ReleaseDate: "2021-01-04",
|
||||
// The init function is called to register elements provided
|
||||
// by the plugin.
|
||||
Init: func(plugin *gst.Plugin) bool {
|
||||
return gst.RegisterElement(
|
||||
plugin,
|
||||
"gofilesink", // The name of the element
|
||||
gst.RankNone, // The rank of the element
|
||||
&fileSink{}, // The GoElement implementation for the element
|
||||
base.ExtendsBaseSink, // The base subclass this element extends
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
// A single method must be exported from the compiled library that provides for GStreamer
|
||||
// to fetch the description and init function for this plugin. The name of the method
|
||||
// must match the format gst_plugin_NAME_get_desc, where hyphens are replaced with underscores.
|
||||
|
||||
//export gst_plugin_gofilesink_get_desc
|
||||
func gst_plugin_gofilesink_get_desc() unsafe.Pointer { return pluginMeta.Export() }
|
||||
|
||||
// main is left unimplemented since these files are compiled to c-shared.
|
||||
func main() {}
|
||||
@@ -78,11 +78,6 @@ type fileSrc struct {
|
||||
state *state
|
||||
}
|
||||
|
||||
func (f *fileSrc) PostMessage(self *gst.Element, msg *gst.Message) bool {
|
||||
fmt.Println("Received message on the pipeline", msg)
|
||||
return self.ParentPostMessage(msg)
|
||||
}
|
||||
|
||||
// Private methods only used internally by the plugin
|
||||
|
||||
// setLocation is a simple method to check the validity of a provided file path and set the
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
var pluginMeta = &gst.PluginMetadata{
|
||||
MajorVersion: gst.VersionMajor,
|
||||
MinorVersion: gst.VersionMinor,
|
||||
Name: "go-file-plugins",
|
||||
Name: "go-filesrc-plugin",
|
||||
Description: "File plugins written in Go",
|
||||
Version: "v0.0.1",
|
||||
License: gst.LicenseLGPL,
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
|
||||
github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
|
||||
github.com/tinyzimmer/go-glib v0.0.1 h1:pfsr7EbP23/cZPGlEpsmwtQXjdzYj0S+WhUgOALdsQI=
|
||||
github.com/tinyzimmer/go-glib v0.0.1/go.mod h1:D5rd0CvYn1p7TBhwlwnBXHSr4d8lwEY9JImPQ66S+Bs=
|
||||
github.com/tinyzimmer/go-glib v0.0.2 h1:hdvjwrhcS6WrMMeqfxsf3e7/lOhV8gbVyJ9/sN3LfyY=
|
||||
github.com/tinyzimmer/go-glib v0.0.2/go.mod h1:D5rd0CvYn1p7TBhwlwnBXHSr4d8lwEY9JImPQ66S+Bs=
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
// Package base contains bindings for extendable GStreamer base objects.
|
||||
//
|
||||
// The objects and methods provided by this package are mostly for use in building
|
||||
// plugins using the go-gst bindings.
|
||||
package base
|
||||
|
||||
+6
-2
@@ -2,8 +2,12 @@
|
||||
#define __GST_BASE_GO_H__
|
||||
|
||||
#include <gst/base/gstbasesrc.h>
|
||||
#include <gst/base/gstbasesink.h>
|
||||
|
||||
inline GstBaseSrc * toGstBaseSrc (void *p) { return GST_BASE_SRC_CAST(p); };
|
||||
inline GstBaseSrcClass * toGstBaseSrcClass (void *p) { return (GstBaseSrcClass *)p; };
|
||||
inline GstBaseSink * toGstBaseSink (void *p) { return GST_BASE_SINK_CAST(p); }
|
||||
inline GstBaseSrc * toGstBaseSrc (void *p) { return GST_BASE_SRC_CAST(p); }
|
||||
|
||||
inline GstBaseSinkClass * toGstBaseSinkClass (void *p) { return (GstBaseSinkClass *)p; }
|
||||
inline GstBaseSrcClass * toGstBaseSrcClass (void *p) { return (GstBaseSrcClass *)p; }
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,306 @@
|
||||
package base
|
||||
|
||||
/*
|
||||
#include "gst.go.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/tinyzimmer/go-gst/gst"
|
||||
)
|
||||
|
||||
// GstBaseSink represents a GstBaseSink.
|
||||
type GstBaseSink struct{ *gst.Element }
|
||||
|
||||
// ToGstBaseSink returns a GstBaseSink object for the given object.
|
||||
func ToGstBaseSink(obj *gst.Object) *GstBaseSink {
|
||||
return &GstBaseSink{&gst.Element{Object: obj}}
|
||||
}
|
||||
|
||||
// wrapGstBaseSink wraps the given unsafe.Pointer in a GstBaseSink instance.
|
||||
func wrapGstBaseSink(obj *C.GstBaseSink) *GstBaseSink {
|
||||
return &GstBaseSink{gst.FromGstElementUnsafe(unsafe.Pointer(obj))}
|
||||
}
|
||||
|
||||
// Instance returns the underlying C GstBaseSrc instance
|
||||
func (g *GstBaseSink) Instance() *C.GstBaseSink {
|
||||
return C.toGstBaseSink(g.Unsafe())
|
||||
}
|
||||
|
||||
// DoPreroll is for if the sink spawns its own thread for pulling buffers from upstream.
|
||||
// It should call this method after it has pulled a buffer. If the element needed to preroll,
|
||||
// this function will perform the preroll and will then block until the element state is changed.
|
||||
//
|
||||
// This function should be called with the PREROLL_LOCK held and the object that caused the preroll.
|
||||
//
|
||||
// Since the object will always be a gst.MiniObject (which is not implemented properly), this method will check
|
||||
// against the provided types for structs known to be used in this context. The currently known options
|
||||
// are events, messages, queries, structures, and buffers. If you come across a need to use this function with
|
||||
// an unsupported type, feel free to raise an Issue or open a PR.
|
||||
func (g *GstBaseSink) DoPreroll(obj interface{}) gst.FlowReturn {
|
||||
miniobj := getPrerollObj(obj)
|
||||
if miniobj == nil {
|
||||
return gst.FlowError
|
||||
}
|
||||
return gst.FlowReturn(C.gst_base_sink_do_preroll(g.Instance(), miniobj))
|
||||
}
|
||||
|
||||
func getPrerollObj(obj interface{}) *C.GstMiniObject {
|
||||
switch obj.(type) {
|
||||
case *gst.Event:
|
||||
return (*C.GstMiniObject)(unsafe.Pointer(obj.(*gst.Event).Instance()))
|
||||
case *gst.Buffer:
|
||||
return (*C.GstMiniObject)(unsafe.Pointer(obj.(*gst.Buffer).Instance()))
|
||||
case *gst.Message:
|
||||
return (*C.GstMiniObject)(unsafe.Pointer(obj.(*gst.Message).Instance()))
|
||||
case *gst.Query:
|
||||
return (*C.GstMiniObject)(unsafe.Pointer(obj.(*gst.Query).Instance()))
|
||||
case *gst.Structure:
|
||||
return (*C.GstMiniObject)(unsafe.Pointer(obj.(*gst.Structure).Instance()))
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetBlocksize gets the number of bytes that the sink will pull when it is operating in pull mode.
|
||||
func (g *GstBaseSink) GetBlocksize() uint { return uint(C.gst_base_sink_get_blocksize(g.Instance())) }
|
||||
|
||||
// GetDropOutOfSegment checks if sink is currently configured to drop buffers which are outside the current segment
|
||||
func (g *GstBaseSink) GetDropOutOfSegment() bool {
|
||||
return gobool(C.gst_base_sink_get_drop_out_of_segment(g.Instance()))
|
||||
}
|
||||
|
||||
// GetLastSample gets the last sample that arrived in the sink and was used for preroll or for rendering.
|
||||
// This property can be used to generate thumbnails.
|
||||
//
|
||||
// The GstCaps on the sample can be used to determine the type of the buffer. Unref after usage. Sample will
|
||||
// be nil if no buffer has arrived yet.
|
||||
func (g *GstBaseSink) GetLastSample() *gst.Sample {
|
||||
sample := C.gst_base_sink_get_last_sample(g.Instance())
|
||||
if sample == nil {
|
||||
return nil
|
||||
}
|
||||
return gst.FromGstSampleUnsafe(unsafe.Pointer(sample))
|
||||
}
|
||||
|
||||
// GetLatency gets the currently configured latency.
|
||||
func (g *GstBaseSink) GetLatency() time.Duration {
|
||||
return time.Duration(C.gst_base_sink_get_latency(g.Instance()))
|
||||
}
|
||||
|
||||
// GetMaxBitrate gets the maximum amount of bits per second the sink will render.
|
||||
func (g *GstBaseSink) GetMaxBitrate() uint64 {
|
||||
return uint64(C.gst_base_sink_get_max_bitrate(g.Instance()))
|
||||
}
|
||||
|
||||
// GetMaxLateness gets the max lateness value.
|
||||
func (g *GstBaseSink) GetMaxLateness() int64 {
|
||||
return int64(C.gst_base_sink_get_max_lateness(g.Instance()))
|
||||
}
|
||||
|
||||
// GetProcessingDeadline gets the processing deadline of the sink.
|
||||
func (g *GstBaseSink) GetProcessingDeadline() time.Duration {
|
||||
return time.Duration(C.gst_base_sink_get_processing_deadline(g.Instance()))
|
||||
}
|
||||
|
||||
// GetRenderDelay gets the render delay for the sink.
|
||||
func (g *GstBaseSink) GetRenderDelay() time.Duration {
|
||||
return time.Duration(C.gst_base_sink_get_render_delay(g.Instance()))
|
||||
}
|
||||
|
||||
// SinkStats represents the current statistics on a GstBaseSink.
|
||||
type SinkStats struct {
|
||||
AverageRate float64
|
||||
Dropped uint64
|
||||
Rendered uint64
|
||||
}
|
||||
|
||||
// GetSinkStats returns various GstBaseSink statistics.
|
||||
func (g *GstBaseSink) GetSinkStats() *SinkStats {
|
||||
st := gst.FromGstStructureUnsafe(unsafe.Pointer(C.gst_base_sink_get_stats(g.Instance())))
|
||||
stats := &SinkStats{}
|
||||
if avgRate, err := st.GetValue("average-rate"); err == nil {
|
||||
stats.AverageRate = avgRate.(float64)
|
||||
}
|
||||
if dropped, err := st.GetValue("dropped"); err == nil {
|
||||
stats.Dropped = dropped.(uint64)
|
||||
}
|
||||
if rendered, err := st.GetValue("rendered"); err == nil {
|
||||
stats.Rendered = rendered.(uint64)
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
// GetSync checks if the sink is currently configured to synchronize on the clock.
|
||||
func (g *GstBaseSink) GetSync() bool { return gobool(C.gst_base_sink_get_sync(g.Instance())) }
|
||||
|
||||
// GetThrottleTime gets the time that will be inserted between frames to control maximum buffers
|
||||
// per second.
|
||||
func (g *GstBaseSink) GetThrottleTime() uint64 {
|
||||
return uint64(C.gst_base_sink_get_throttle_time(g.Instance()))
|
||||
}
|
||||
|
||||
// GetTsOffset gets the synchronization offset of sink.
|
||||
func (g *GstBaseSink) GetTsOffset() time.Duration {
|
||||
return time.Duration(C.gst_base_sink_get_ts_offset(g.Instance()))
|
||||
}
|
||||
|
||||
// IsAsyncEnabled checks if the sink is currently configured to perform asynchronous state changes to PAUSED.
|
||||
func (g *GstBaseSink) IsAsyncEnabled() bool {
|
||||
return gobool(C.gst_base_sink_is_async_enabled(g.Instance()))
|
||||
}
|
||||
|
||||
// IsLastSampleEnabled checks if the sink is currently configured to store the last received sample.
|
||||
func (g *GstBaseSink) IsLastSampleEnabled() bool {
|
||||
return gobool(C.gst_base_sink_is_last_sample_enabled(g.Instance()))
|
||||
}
|
||||
|
||||
// IsQoSEnabled checks if sink is currently configured to send QoS events upstream.
|
||||
func (g *GstBaseSink) IsQoSEnabled() bool {
|
||||
return gobool(C.gst_base_sink_is_qos_enabled(g.Instance()))
|
||||
}
|
||||
|
||||
// QueryLatency queries the sink for the latency parameters. The latency will be queried from the
|
||||
// upstream elements. live will be TRUE if sink is configured to synchronize against the clock.
|
||||
// upstreamLive will be TRUE if an upstream element is live.
|
||||
//
|
||||
// If both live and upstreamLive are TRUE, the sink will want to compensate for the latency introduced
|
||||
// by the upstream elements by setting the minLatency to a strictly positive value.
|
||||
//
|
||||
// This function is mostly used by subclasses.
|
||||
func (g *GstBaseSink) QueryLatency() (ok, live, upstreamLive bool, minLatency, maxLatency time.Duration) {
|
||||
var glive, gupLive C.gboolean
|
||||
var gmin, gmax C.GstClockTime
|
||||
ret := C.gst_base_sink_query_latency(g.Instance(), &glive, &gupLive, &gmin, &gmax)
|
||||
return gobool(ret), gobool(glive), gobool(gupLive), time.Duration(gmin), time.Duration(gmax)
|
||||
}
|
||||
|
||||
// SetAsyncEnabled configures sink to perform all state changes asynchronously. When async is disabled,
|
||||
// the sink will immediately go to PAUSED instead of waiting for a preroll buffer. This feature is useful
|
||||
// if the sink does not synchronize against the clock or when it is dealing with sparse streams.
|
||||
func (g *GstBaseSink) SetAsyncEnabled(enabled bool) {
|
||||
C.gst_base_sink_set_async_enabled(g.Instance(), gboolean(enabled))
|
||||
}
|
||||
|
||||
// SetBlocksize sets the number of bytes this sink will pull when operating in pull mode.
|
||||
func (g *GstBaseSink) SetBlocksize(blocksize uint) {
|
||||
C.gst_base_sink_set_blocksize(g.Instance(), C.guint(blocksize))
|
||||
}
|
||||
|
||||
// SetDropOutOfSegment configures sink to drop buffers which are outside the current segment.
|
||||
func (g *GstBaseSink) SetDropOutOfSegment(drop bool) {
|
||||
C.gst_base_sink_set_drop_out_of_segment(g.Instance(), gboolean(drop))
|
||||
}
|
||||
|
||||
// SetLastSampleEnabled configures the sink to store the last received sample.
|
||||
func (g *GstBaseSink) SetLastSampleEnabled(enabled bool) {
|
||||
C.gst_base_sink_set_last_sample_enabled(g.Instance(), gboolean(enabled))
|
||||
}
|
||||
|
||||
// SetMaxBitrate sets the maximum amount of bits per second the sink will render.
|
||||
func (g *GstBaseSink) SetMaxBitrate(bitrate uint64) {
|
||||
C.gst_base_sink_set_max_bitrate(g.Instance(), C.guint64(bitrate))
|
||||
}
|
||||
|
||||
// SetMaxLateness sets the new max lateness value to max_lateness. This value is used to decide if
|
||||
// a buffer should be dropped or not based on the buffer timestamp and the current clock time. A
|
||||
// value of -1 means an unlimited time.
|
||||
func (g *GstBaseSink) SetMaxLateness(maxLateness int64) {
|
||||
C.gst_base_sink_set_max_lateness(g.Instance(), C.gint64(maxLateness))
|
||||
}
|
||||
|
||||
// SetProcessingDeadline sets the maximum amount of time (in nanoseconds) that the pipeline can take
|
||||
// for processing the buffer. This is added to the latency of live pipelines.
|
||||
//
|
||||
// This function is usually called by subclasses.
|
||||
func (g *GstBaseSink) SetProcessingDeadline(deadline time.Duration) {
|
||||
C.gst_base_sink_set_processing_deadline(g.Instance(), C.GstClockTime(deadline.Nanoseconds()))
|
||||
}
|
||||
|
||||
// SetQoSEnabled configures sink to send Quality-of-Service events upstream.
|
||||
func (g *GstBaseSink) SetQoSEnabled(enabled bool) {
|
||||
C.gst_base_sink_set_qos_enabled(g.Instance(), gboolean(enabled))
|
||||
}
|
||||
|
||||
// SetRenderDelay sets the render delay in sink to delay. The render delay is the time between actual
|
||||
// rendering of a buffer and its synchronisation time. Some devices might delay media rendering which
|
||||
// can be compensated for with this function.
|
||||
//
|
||||
// After calling this function, this sink will report additional latency and other sinks will adjust
|
||||
// their latency to delay the rendering of their media.
|
||||
//
|
||||
// This function is usually called by subclasses.
|
||||
func (g *GstBaseSink) SetRenderDelay(delay time.Duration) {
|
||||
C.gst_base_sink_set_render_delay(g.Instance(), C.GstClockTime(delay.Nanoseconds()))
|
||||
}
|
||||
|
||||
// SetSync configures sink to synchronize on the clock or not. When sync is FALSE, incoming samples will
|
||||
// be played as fast as possible. If sync is TRUE, the timestamps of the incoming buffers will be used to
|
||||
// schedule the exact render time of its contents.
|
||||
func (g *GstBaseSink) SetSync(sync bool) { C.gst_base_sink_set_sync(g.Instance(), gboolean(sync)) }
|
||||
|
||||
// SetThrottleTime sets the time that will be inserted between rendered buffers. This can be used to control
|
||||
// the maximum buffers per second that the sink will render.
|
||||
func (g *GstBaseSink) SetThrottleTime(throttle uint64) {
|
||||
C.gst_base_sink_set_throttle_time(g.Instance(), C.guint64(throttle))
|
||||
}
|
||||
|
||||
// SetTsOffset adjusts the synchronization of sink with offset. A negative value will render buffers earlier
|
||||
// than their timestamp. A positive value will delay rendering. This function can be used to fix playback of
|
||||
// badly timestamped buffers.
|
||||
func (g *GstBaseSink) SetTsOffset(offset time.Duration) {
|
||||
C.gst_base_sink_set_ts_offset(g.Instance(), C.GstClockTimeDiff(offset.Nanoseconds()))
|
||||
}
|
||||
|
||||
// Wait will wait for preroll to complete and will then block until timeout is reached. It is usually called by
|
||||
// subclasses that use their own internal synchronization but want to let some synchronization (like EOS) be
|
||||
// handled by the base class.
|
||||
//
|
||||
// This function should only be called with the PREROLL_LOCK held (like when receiving an EOS event in the
|
||||
// ::event vmethod or when handling buffers in ::render).
|
||||
//
|
||||
// The timeout argument should be the running_time of when the timeout should happen and will be adjusted with any
|
||||
// latency and offset configured in the sink.
|
||||
func (g *GstBaseSink) Wait(timeout time.Duration) (ret gst.FlowReturn, jitter time.Duration) {
|
||||
var jit C.GstClockTimeDiff
|
||||
gret := C.gst_base_sink_wait(g.Instance(), C.GstClockTime(timeout.Nanoseconds()), &jit)
|
||||
return gst.FlowReturn(gret), time.Duration(jit)
|
||||
}
|
||||
|
||||
// WaitClock will block until timeout is reached. It is usually called by subclasses that use their own
|
||||
// internal synchronization.
|
||||
//
|
||||
// If time is not valid, no synchronisation is done and GST_CLOCK_BADTIME is returned. Likewise, if synchronization
|
||||
// is disabled in the element or there is no clock, no synchronization is done and GST_CLOCK_BADTIME is returned.
|
||||
//
|
||||
// This function should only be called with the PREROLL_LOCK held, like when receiving an EOS event in the event()
|
||||
// vmethod or when receiving a buffer in the render() vmethod.
|
||||
//
|
||||
// The timeout argument should be the running_time of when this method should return and is not adjusted with any
|
||||
// latency or offset configured in the sink.
|
||||
func (g *GstBaseSink) WaitClock(timeout time.Duration) (ret gst.ClockReturn, jitter time.Duration) {
|
||||
var jit C.GstClockTimeDiff
|
||||
gret := C.gst_base_sink_wait_clock(g.Instance(), C.GstClockTime(timeout.Nanoseconds()), &jit)
|
||||
return gst.ClockReturn(gret), time.Duration(jit)
|
||||
}
|
||||
|
||||
// WaitPreroll will block until the preroll is complete.
|
||||
//
|
||||
// If the render() method performs its own synchronisation against the clock it must unblock when going from
|
||||
// PLAYING to the PAUSED state and call this method before continuing to render the remaining data.
|
||||
//
|
||||
// If the render() method can block on something else than the clock, it must also be ready to unblock immediately
|
||||
// on the unlock() method and cause the render() method to immediately call this function. In this case, the
|
||||
// subclass must be prepared to continue rendering where it left off if this function returns GST_FLOW_OK.
|
||||
//
|
||||
// This function will block until a state change to PLAYING happens (in which case this function returns
|
||||
// GST_FLOW_OK) or the processing must be stopped due to a state change to READY or a FLUSH event (in which case
|
||||
// this function returns GST_FLOW_FLUSHING).
|
||||
//
|
||||
// This function should only be called with the PREROLL_LOCK held, like in the render function.
|
||||
func (g *GstBaseSink) WaitPreroll() gst.FlowReturn {
|
||||
return gst.FlowReturn(C.gst_base_sink_wait_preroll(g.Instance()))
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package base
|
||||
|
||||
/*
|
||||
#include "gst.go.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/tinyzimmer/go-gst/gst"
|
||||
)
|
||||
|
||||
//export goGstBaseSinkActivatePull
|
||||
func goGstBaseSinkActivatePull(sink *C.GstBaseSink, active C.gboolean) C.gboolean {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
ActivatePull(self *GstBaseSink, active bool) bool
|
||||
})
|
||||
return gboolean(iface.ActivatePull(wrapGstBaseSink(sink), gobool(active)))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkEvent
|
||||
func goGstBaseSinkEvent(sink *C.GstBaseSink, event *C.GstEvent) C.gboolean {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
Event(self *GstBaseSink, event *gst.Event) bool
|
||||
})
|
||||
return gboolean(iface.Event(wrapGstBaseSink(sink), gst.FromGstEventUnsafe(unsafe.Pointer(event))))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkFixate
|
||||
func goGstBaseSinkFixate(sink *C.GstBaseSink, caps *C.GstCaps) *C.GstCaps {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
Fixate(self *GstBaseSink, caps *gst.Caps) *gst.Caps
|
||||
})
|
||||
fixated := iface.Fixate(wrapGstBaseSink(sink), gst.FromGstCapsUnsafe(unsafe.Pointer(caps)))
|
||||
if fixated == nil {
|
||||
return nil
|
||||
}
|
||||
return (*C.GstCaps)(unsafe.Pointer(fixated.Instance()))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkGetCaps
|
||||
func goGstBaseSinkGetCaps(sink *C.GstBaseSink, filter *C.GstCaps) *C.GstCaps {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
GetCaps(self *GstBaseSink, filter *gst.Caps) *gst.Caps
|
||||
})
|
||||
filtered := iface.GetCaps(wrapGstBaseSink(sink), gst.FromGstCapsUnsafe(unsafe.Pointer(filter)))
|
||||
if filtered == nil {
|
||||
return nil
|
||||
}
|
||||
return (*C.GstCaps)(unsafe.Pointer(filtered.Instance()))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkGetTimes
|
||||
func goGstBaseSinkGetTimes(sink *C.GstBaseSink, buf *C.GstBuffer, start, end *C.GstClockTime) {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
GetTimes(self *GstBaseSink, buffer *gst.Buffer) (start, end time.Duration)
|
||||
})
|
||||
retStart, retEnd := iface.GetTimes(wrapGstBaseSink(sink), gst.FromGstBufferUnsafe(unsafe.Pointer(buf)))
|
||||
*start = C.GstClockTime(retStart.Nanoseconds())
|
||||
*end = C.GstClockTime(retEnd.Nanoseconds())
|
||||
}
|
||||
|
||||
//export goGstBaseSinkPrepare
|
||||
func goGstBaseSinkPrepare(sink *C.GstBaseSink, buf *C.GstBuffer) C.GstFlowReturn {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
Prepare(self *GstBaseSink, buffer *gst.Buffer) gst.FlowReturn
|
||||
})
|
||||
return C.GstFlowReturn(iface.Prepare(wrapGstBaseSink(sink), gst.FromGstBufferUnsafe(unsafe.Pointer(buf))))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkPrepareList
|
||||
func goGstBaseSinkPrepareList(sink *C.GstBaseSink, list *C.GstBufferList) C.GstFlowReturn {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
PrepareList(self *GstBaseSink, bufferList *gst.BufferList) gst.FlowReturn
|
||||
})
|
||||
return C.GstFlowReturn(iface.PrepareList(wrapGstBaseSink(sink), gst.FromGstBufferListUnsafe(unsafe.Pointer(list))))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkPreroll
|
||||
func goGstBaseSinkPreroll(sink *C.GstBaseSink, buf *C.GstBuffer) C.GstFlowReturn {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
Preroll(self *GstBaseSink, buffer *gst.Buffer) gst.FlowReturn
|
||||
})
|
||||
return C.GstFlowReturn(iface.Preroll(wrapGstBaseSink(sink), gst.FromGstBufferUnsafe(unsafe.Pointer(buf))))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkProposeAllocation
|
||||
func goGstBaseSinkProposeAllocation(sink *C.GstBaseSink, query *C.GstQuery) C.gboolean {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
ProposeAllocation(self *GstBaseSink, query *gst.Query) bool
|
||||
})
|
||||
return gboolean(iface.ProposeAllocation(wrapGstBaseSink(sink), gst.FromGstQueryUnsafe(unsafe.Pointer(query))))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkQuery
|
||||
func goGstBaseSinkQuery(sink *C.GstBaseSink, query *C.GstQuery) C.gboolean {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
Query(self *GstBaseSink, query *gst.Query) bool
|
||||
})
|
||||
return gboolean(iface.Query(wrapGstBaseSink(sink), gst.FromGstQueryUnsafe(unsafe.Pointer(query))))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkRender
|
||||
func goGstBaseSinkRender(sink *C.GstBaseSink, buf *C.GstBuffer) C.GstFlowReturn {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
Render(self *GstBaseSink, buffer *gst.Buffer) gst.FlowReturn
|
||||
})
|
||||
return C.GstFlowReturn(iface.Render(wrapGstBaseSink(sink), gst.FromGstBufferUnsafe(unsafe.Pointer(buf))))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkRenderList
|
||||
func goGstBaseSinkRenderList(sink *C.GstBaseSink, buf *C.GstBufferList) C.GstFlowReturn {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
RenderList(self *GstBaseSink, bufferList *gst.BufferList) gst.FlowReturn
|
||||
})
|
||||
return C.GstFlowReturn(iface.RenderList(wrapGstBaseSink(sink), gst.FromGstBufferListUnsafe(unsafe.Pointer(buf))))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkSetCaps
|
||||
func goGstBaseSinkSetCaps(sink *C.GstBaseSink, caps *C.GstCaps) C.gboolean {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
SetCaps(self *GstBaseSink, caps *gst.Caps) bool
|
||||
})
|
||||
return gboolean(iface.SetCaps(wrapGstBaseSink(sink), gst.FromGstCapsUnsafe(unsafe.Pointer(caps))))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkStart
|
||||
func goGstBaseSinkStart(sink *C.GstBaseSink) C.gboolean {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
Start(self *GstBaseSink) bool
|
||||
})
|
||||
return gboolean(iface.Start(wrapGstBaseSink(sink)))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkStop
|
||||
func goGstBaseSinkStop(sink *C.GstBaseSink) C.gboolean {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
Stop(self *GstBaseSink) bool
|
||||
})
|
||||
return gboolean(iface.Stop(wrapGstBaseSink(sink)))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkUnlock
|
||||
func goGstBaseSinkUnlock(sink *C.GstBaseSink) C.gboolean {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
Unlock(self *GstBaseSink) bool
|
||||
})
|
||||
return gboolean(iface.Unlock(wrapGstBaseSink(sink)))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkUnlockStop
|
||||
func goGstBaseSinkUnlockStop(sink *C.GstBaseSink) C.gboolean {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
UnlockStop(self *GstBaseSink) bool
|
||||
})
|
||||
return gboolean(iface.UnlockStop(wrapGstBaseSink(sink)))
|
||||
}
|
||||
|
||||
//export goGstBaseSinkWaitEvent
|
||||
func goGstBaseSinkWaitEvent(sink *C.GstBaseSink, event *C.GstEvent) C.GstFlowReturn {
|
||||
iface := gst.FromObjectUnsafePrivate(unsafe.Pointer(sink)).(interface {
|
||||
WaitEvent(self *GstBaseSink, event *gst.Event) gst.FlowReturn
|
||||
})
|
||||
return C.GstFlowReturn(iface.WaitEvent(wrapGstBaseSink(sink), gst.FromGstEventUnsafe(unsafe.Pointer(event))))
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
package base
|
||||
|
||||
/*
|
||||
#include "gst.go.h"
|
||||
|
||||
extern gboolean goGstBaseSinkActivatePull (GstBaseSink * sink, gboolean active);
|
||||
extern gboolean goGstBaseSinkEvent (GstBaseSink * sink, GstEvent * event);
|
||||
extern GstCaps * goGstBaseSinkFixate (GstBaseSink * sink, GstCaps * caps);
|
||||
extern GstCaps * goGstBaseSinkGetCaps (GstBaseSink * sink, GstCaps * filter);
|
||||
extern void goGstBaseSinkGetTimes (GstBaseSink * sink, GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
|
||||
extern GstFlowReturn goGstBaseSinkPrepare (GstBaseSink * sink, GstBuffer * buffer);
|
||||
extern GstFlowReturn goGstBaseSinkPrepareList (GstBaseSink * sink, GstBufferList * buffer_list);
|
||||
extern GstFlowReturn goGstBaseSinkPreroll (GstBaseSink * sink, GstBuffer * buffer);
|
||||
extern gboolean goGstBaseSinkProposeAllocation (GstBaseSink * sink, GstQuery * query);
|
||||
extern gboolean goGstBaseSinkQuery (GstBaseSink * sink, GstQuery * query);
|
||||
extern GstFlowReturn goGstBaseSinkRender (GstBaseSink * sink, GstBuffer * buffer);
|
||||
extern GstFlowReturn goGstBaseSinkRenderList (GstBaseSink * sink, GstBufferList * buffer_list);
|
||||
extern gboolean goGstBaseSinkSetCaps (GstBaseSink * sink, GstCaps * caps);
|
||||
extern gboolean goGstBaseSinkStart (GstBaseSink * sink);
|
||||
extern gboolean goGstBaseSinkStop (GstBaseSink * sink);
|
||||
extern gboolean goGstBaseSinkUnlock (GstBaseSink * sink);
|
||||
extern gboolean goGstBaseSinkUnlockStop (GstBaseSink * sink);
|
||||
extern GstFlowReturn goGstBaseSinkWaitEvent (GstBaseSink * sink, GstEvent * event);
|
||||
|
||||
GstFlowReturn do_wait_event (GstBaseSink * sink, GstEvent * event)
|
||||
{
|
||||
GObjectClass * this_class = G_OBJECT_GET_CLASS(G_OBJECT(sink));
|
||||
GstBaseSinkClass * parent = toGstBaseSinkClass(g_type_class_peek_parent(this_class));
|
||||
GstFlowReturn ret = parent->wait_event(sink, event);
|
||||
if (ret == GST_FLOW_ERROR)
|
||||
return ret;
|
||||
return goGstBaseSinkWaitEvent(sink, event);
|
||||
}
|
||||
|
||||
void setGstBaseSinkActivatePull (GstBaseSinkClass * klass) { klass->activate_pull = goGstBaseSinkActivatePull; }
|
||||
void setGstBaseSinkEvent (GstBaseSinkClass * klass) { klass->event = goGstBaseSinkEvent; }
|
||||
void setGstBaseSinkFixate (GstBaseSinkClass * klass) { klass->fixate = goGstBaseSinkFixate; }
|
||||
void setGstBaseSinkGetCaps (GstBaseSinkClass * klass) { klass->get_caps = goGstBaseSinkGetCaps; }
|
||||
void setGstBaseSinkGetTimes (GstBaseSinkClass * klass) { klass->get_times = goGstBaseSinkGetTimes; }
|
||||
void setGstBaseSinkPrepare (GstBaseSinkClass * klass) { klass->prepare = goGstBaseSinkPrepare; }
|
||||
void setGstBaseSinkPrepareList (GstBaseSinkClass * klass) { klass->prepare_list = goGstBaseSinkPrepareList; }
|
||||
void setGstBaseSinkPreroll (GstBaseSinkClass * klass) { klass->preroll = goGstBaseSinkPreroll; }
|
||||
void setGstBaseSinkProposeAllocation (GstBaseSinkClass * klass) { klass->propose_allocation = goGstBaseSinkProposeAllocation; }
|
||||
void setGstBaseSinkQuery (GstBaseSinkClass * klass) { klass->query = goGstBaseSinkQuery; }
|
||||
void setGstBaseSinkRender (GstBaseSinkClass * klass) { klass->render = goGstBaseSinkRender; }
|
||||
void setGstBaseSinkRenderList (GstBaseSinkClass * klass) { klass->render_list = goGstBaseSinkRenderList; }
|
||||
void setGstBaseSinkSetCaps (GstBaseSinkClass * klass) { klass->set_caps = goGstBaseSinkSetCaps; }
|
||||
void setGstBaseSinkStart (GstBaseSinkClass * klass) { klass->start = goGstBaseSinkStart; }
|
||||
void setGstBaseSinkStop (GstBaseSinkClass * klass) { klass->stop = goGstBaseSinkStop; }
|
||||
void setGstBaseSinkUnlock (GstBaseSinkClass * klass) { klass->unlock = goGstBaseSinkUnlock; }
|
||||
void setGstBaseSinkUnlockStop (GstBaseSinkClass * klass) { klass->unlock_stop = goGstBaseSinkUnlockStop; }
|
||||
void setGstBaseSinkWaitEvent (GstBaseSinkClass * klass) { klass->wait_event = do_wait_event; }
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/tinyzimmer/go-glib/glib"
|
||||
"github.com/tinyzimmer/go-gst/gst"
|
||||
)
|
||||
|
||||
var (
|
||||
// ExtendsBaseSink is an Extendable for extending a GstBaseSink
|
||||
ExtendsBaseSink gst.Extendable = &extendsBaseSink{parent: gst.ExtendsElement}
|
||||
)
|
||||
|
||||
// GstBaseSinkImpl is the documented interface for extending a GstBaseSink. It does not have to
|
||||
// be implemented in it's entirety. Each of the methods it declares will be checked for their presence
|
||||
// in the initializing object, and if the object declares an override it will replace the default
|
||||
// implementation in the virtual methods.
|
||||
type GstBaseSinkImpl interface {
|
||||
// Subclasses should override this when they can provide an alternate method of spawning a thread to
|
||||
// drive the pipeline in pull mode. Should start or stop the pulling thread, depending on the value
|
||||
// of the "active" argument. Called after actually activating the sink pad in pull mode. The default
|
||||
// implementation starts a task on the sink pad.
|
||||
ActivatePull(self *GstBaseSink, active bool) bool
|
||||
// Override this to handle events arriving on the sink pad
|
||||
Event(self *GstBaseSink, event *gst.Event) bool
|
||||
// Only useful in pull mode. Implement if you have ideas about what should be the default values for
|
||||
// the caps you support.
|
||||
Fixate(self *GstBaseSink, caps *gst.Caps) *gst.Caps
|
||||
// Called to get sink pad caps from the subclass
|
||||
GetCaps(self *GstBaseSink, filter *gst.Caps) *gst.Caps
|
||||
// Called to get the start and end times for synchronising the passed buffer to the clock
|
||||
GetTimes(self *GstBaseSink, buffer *gst.Buffer) (start, end time.Duration)
|
||||
// Called to prepare the buffer for render and preroll. This function is called before synchronization
|
||||
// is performed.
|
||||
Prepare(self *GstBaseSink, buffer *gst.Buffer) gst.FlowReturn
|
||||
// Called to prepare the buffer list for render_list. This function is called before synchronization is
|
||||
// performed.
|
||||
PrepareList(self *GstBaseSink, bufferList *gst.BufferList) gst.FlowReturn
|
||||
// Called to present the preroll buffer if desired.
|
||||
Preroll(self *GstBaseSink, buffer *gst.Buffer) gst.FlowReturn
|
||||
// Used to configure the allocation query
|
||||
ProposeAllocation(self *GstBaseSink, query *gst.Query) bool
|
||||
// Handle queries on the element
|
||||
Query(self *GstBaseSink, query *gst.Query) bool
|
||||
// Called when a buffer should be presented or output, at the correct moment if the GstBaseSink has been
|
||||
// set to sync to the clock.
|
||||
Render(self *GstBaseSink, buffer *gst.Buffer) gst.FlowReturn
|
||||
// Same as render but used with buffer lists instead of buffers.
|
||||
RenderList(self *GstBaseSink, bufferList *gst.BufferList) gst.FlowReturn
|
||||
// Notify subclass of changed caps
|
||||
SetCaps(self *GstBaseSink, caps *gst.Caps) bool
|
||||
// Start processing. Ideal for opening resources in the subclass
|
||||
Start(self *GstBaseSink) bool
|
||||
// Stop processing. Subclasses should use this to close resources.
|
||||
Stop(self *GstBaseSink) bool
|
||||
// Unlock any pending access to the resource. Subclasses should unblock any blocked function ASAP and call
|
||||
// WaitPreroll
|
||||
Unlock(self *GstBaseSink) bool
|
||||
// Clear the previous unlock request. Subclasses should clear any state they set during Unlock(), and be ready
|
||||
// to continue where they left off after WaitPreroll, Wait or WaitClock return or Render() is called again.
|
||||
UnlockStop(self *GstBaseSink) bool
|
||||
// Override this to implement custom logic to wait for the event time (for events like EOS and GAP). The bindings
|
||||
// take care of first chaining up to the parent class.
|
||||
WaitEvent(self *GstBaseSink, event *gst.Event) gst.FlowReturn
|
||||
}
|
||||
|
||||
type extendsBaseSink struct{ parent gst.Extendable }
|
||||
|
||||
func (e *extendsBaseSink) Type() glib.Type { return glib.Type(C.gst_base_sink_get_type()) }
|
||||
func (e *extendsBaseSink) ClassSize() int64 { return int64(C.sizeof_GstBaseSinkClass) }
|
||||
func (e *extendsBaseSink) InstanceSize() int64 { return int64(C.sizeof_GstBaseSink) }
|
||||
|
||||
func (e *extendsBaseSink) InitClass(klass unsafe.Pointer, elem gst.GoElement) {
|
||||
e.parent.InitClass(klass, elem)
|
||||
|
||||
sinkClass := C.toGstBaseSinkClass(klass)
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
ActivatePull(self *GstBaseSink, active bool) bool
|
||||
}); ok {
|
||||
C.setGstBaseSinkActivatePull(sinkClass)
|
||||
}
|
||||
if _, ok := elem.(interface {
|
||||
Event(self *GstBaseSink, event *gst.Event) bool
|
||||
}); ok {
|
||||
C.setGstBaseSinkEvent(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
Fixate(self *GstBaseSink, caps *gst.Caps) *gst.Caps
|
||||
}); ok {
|
||||
C.setGstBaseSinkFixate(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
GetCaps(self *GstBaseSink, filter *gst.Caps) *gst.Caps
|
||||
}); ok {
|
||||
C.setGstBaseSinkGetCaps(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
GetTimes(self *GstBaseSink, buffer *gst.Buffer) (start, end time.Duration)
|
||||
}); ok {
|
||||
C.setGstBaseSinkGetTimes(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
Prepare(self *GstBaseSink, buffer *gst.Buffer) gst.FlowReturn
|
||||
}); ok {
|
||||
C.setGstBaseSinkPrepare(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
PrepareList(self *GstBaseSink, bufferList *gst.BufferList) gst.FlowReturn
|
||||
}); ok {
|
||||
C.setGstBaseSinkPrepareList(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
Preroll(self *GstBaseSink, buffer *gst.Buffer) gst.FlowReturn
|
||||
}); ok {
|
||||
C.setGstBaseSinkPreroll(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
ProposeAllocation(self *GstBaseSink, query *gst.Query) bool
|
||||
}); ok {
|
||||
C.setGstBaseSinkProposeAllocation(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
Query(self *GstBaseSink, query *gst.Query) bool
|
||||
}); ok {
|
||||
C.setGstBaseSinkQuery(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
Render(self *GstBaseSink, buffer *gst.Buffer) gst.FlowReturn
|
||||
}); ok {
|
||||
C.setGstBaseSinkRender(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
RenderList(self *GstBaseSink, bufferList *gst.BufferList) gst.FlowReturn
|
||||
}); ok {
|
||||
C.setGstBaseSinkRenderList(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
SetCaps(self *GstBaseSink, caps *gst.Caps) bool
|
||||
}); ok {
|
||||
C.setGstBaseSinkSetCaps(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
Start(self *GstBaseSink) bool
|
||||
}); ok {
|
||||
C.setGstBaseSinkStart(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
Stop(self *GstBaseSink) bool
|
||||
}); ok {
|
||||
C.setGstBaseSinkStop(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
Unlock(self *GstBaseSink) bool
|
||||
}); ok {
|
||||
C.setGstBaseSinkUnlock(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
UnlockStop(self *GstBaseSink) bool
|
||||
}); ok {
|
||||
C.setGstBaseSinkUnlockStop(sinkClass)
|
||||
}
|
||||
|
||||
if _, ok := elem.(interface {
|
||||
WaitEvent(self *GstBaseSink, event *gst.Event) gst.FlowReturn
|
||||
}); ok {
|
||||
C.setGstBaseSinkWaitEvent(sinkClass)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ package base
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/tinyzimmer/go-gst/gst"
|
||||
@@ -28,6 +29,106 @@ func (g *GstBaseSrc) Instance() *C.GstBaseSrc {
|
||||
return C.toGstBaseSrc(g.Unsafe())
|
||||
}
|
||||
|
||||
// GetAllocator retrieves the memory allocator used by this base src. Unref after usage.
|
||||
func (g *GstBaseSrc) GetAllocator() (*gst.Allocator, *gst.AllocationParams) {
|
||||
var allocParams C.GstAllocationParams
|
||||
var allocator *C.GstAllocator
|
||||
C.gst_base_src_get_allocator(g.Instance(), &allocator, &allocParams)
|
||||
return gst.FromGstAllocatorUnsafe(unsafe.Pointer(allocator)), gst.FromGstAllocationParamsUnsafe(unsafe.Pointer(&allocParams))
|
||||
}
|
||||
|
||||
// GetBlocksize returns the number of bytes that the source will push out with each buffer.
|
||||
func (g *GstBaseSrc) GetBlocksize() uint { return uint(C.gst_base_src_get_blocksize(g.Instance())) }
|
||||
|
||||
// GetBufferPool returns the BufferPool used by this source. Unref after usage.
|
||||
func (g *GstBaseSrc) GetBufferPool() *gst.BufferPool {
|
||||
return gst.FromGstBufferPoolUnsafe(unsafe.Pointer(C.gst_base_src_get_buffer_pool(g.Instance())))
|
||||
}
|
||||
|
||||
// DoTimestamp will query if the timestamps outgoing on this source's buffers are based on the current
|
||||
// running time.
|
||||
func (g *GstBaseSrc) DoTimestamp() bool {
|
||||
return gobool(C.gst_base_src_get_do_timestamp(g.Instance()))
|
||||
}
|
||||
|
||||
// IsAsync retrieves the current async behavior of the source.
|
||||
func (g *GstBaseSrc) IsAsync() bool { return gobool(C.gst_base_src_is_async(g.Instance())) }
|
||||
|
||||
// IsLive checks if this source is in live mode.
|
||||
func (g *GstBaseSrc) IsLive() bool { return gobool(C.gst_base_src_is_live(g.Instance())) }
|
||||
|
||||
// Negotiate negotiates this source's pad caps with downstream elements. Do not call this in the Fill()
|
||||
// vmethod. Call this in Create() or in Alloc(), before any buffer is allocated.
|
||||
func (g *GstBaseSrc) Negotiate() bool { return gobool(C.gst_base_src_negotiate(g.Instance())) }
|
||||
|
||||
// NewSegment prepares a new segment for emission downstream. This function must only be called by derived
|
||||
// sub-classes, and only from the create function, as the stream-lock needs to be held.
|
||||
//
|
||||
// The format for the segment must be identical with the current format of the source, as configured with
|
||||
// SetFormat.
|
||||
//
|
||||
// The format of src must not be gst.FormatUndefined and the format should be configured via SetFormat before
|
||||
// calling this method.
|
||||
func (g *GstBaseSrc) NewSegment(segment *gst.Segment) bool {
|
||||
return gobool(C.gst_base_src_new_segment(g.Instance(), (*C.GstSegment)(unsafe.Pointer(segment.Instance()))))
|
||||
}
|
||||
|
||||
// QueryLatency queries the source for the latency parameters. live will be TRUE when src is configured as a
|
||||
// live source. minLatency and maxLatency will be set to the difference between the running time and the timestamp
|
||||
// of the first buffer.
|
||||
//
|
||||
// This function is mostly used by subclasses.
|
||||
func (g *GstBaseSrc) QueryLatency() (ok, live bool, minLatency, maxLatency time.Duration) {
|
||||
var glive C.gboolean
|
||||
var gmin C.GstClockTime
|
||||
var gmax C.GstClockTime
|
||||
gok := C.gst_base_src_query_latency(g.Instance(), &glive, &gmin, &gmax)
|
||||
return gobool(gok), gobool(glive), time.Duration(gmin), time.Duration(gmax)
|
||||
}
|
||||
|
||||
// SetAsync configures async behaviour in src, no state change will block. The open, close, start, stop, play and
|
||||
// pause virtual methods will be executed in a different thread and are thus allowed to perform blocking operations.
|
||||
// Any blocking operation should be unblocked with the unlock vmethod.
|
||||
func (g *GstBaseSrc) SetAsync(async bool) { C.gst_base_src_set_async(g.Instance(), gboolean(async)) }
|
||||
|
||||
// SetAutomaticEOS sets whether EOS should be automatically emmitted.
|
||||
//
|
||||
// If automaticEOS is TRUE, src will automatically go EOS if a buffer after the total size is returned. By default
|
||||
// this is TRUE but sources that can't return an authoritative size and only know that they're EOS when trying to
|
||||
// read more should set this to FALSE.
|
||||
//
|
||||
// When src operates in gst.FormatTime, GstBaseSrc will send an EOS when a buffer outside of the currently configured
|
||||
// segment is pushed if automaticEOS is TRUE. Since 1.16, if automatic_eos is FALSE an EOS will be pushed only when
|
||||
// the Create() implementation returns gst.FlowEOS.
|
||||
func (g *GstBaseSrc) SetAutomaticEOS(automaticEOS bool) {
|
||||
C.gst_base_src_set_automatic_eos(g.Instance(), gboolean(automaticEOS))
|
||||
}
|
||||
|
||||
// SetBlocksize sets the number of bytes that src will push out with each buffer. When blocksize is set to -1, a
|
||||
// default length will be used.
|
||||
func (g *GstBaseSrc) SetBlocksize(size uint) {
|
||||
C.gst_base_src_set_blocksize(g.Instance(), C.guint(size))
|
||||
}
|
||||
|
||||
// SetCaps sets new caps on the source pad.
|
||||
func (g *GstBaseSrc) SetCaps(caps *gst.Caps) bool {
|
||||
return gobool(C.gst_base_src_set_caps(g.Instance(), (*C.GstCaps)(unsafe.Pointer(caps.Instance()))))
|
||||
}
|
||||
|
||||
// SetDoTimestamp configures src to automatically timestamp outgoing buffers based on the current running_time of the pipeline.
|
||||
// This property is mostly useful for live sources.
|
||||
func (g *GstBaseSrc) SetDoTimestamp(doTimestamp bool) {
|
||||
C.gst_base_src_set_do_timestamp(g.Instance(), gboolean(doTimestamp))
|
||||
}
|
||||
|
||||
// SetDynamicSize sets if the size is dynamic for this source.
|
||||
//
|
||||
// If not dynamic, size is only updated when needed, such as when trying to read past current tracked size. Otherwise, size is
|
||||
// checked for upon each read.
|
||||
func (g *GstBaseSrc) SetDynamicSize(dynamic bool) {
|
||||
C.gst_base_src_set_dynamic_size(g.Instance(), gboolean(dynamic))
|
||||
}
|
||||
|
||||
// SetFormat sets the default format of the source. This will be the format used for sending
|
||||
// SEGMENT events and for performing seeks.
|
||||
//
|
||||
@@ -39,9 +140,50 @@ func (g *GstBaseSrc) SetFormat(format gst.Format) {
|
||||
C.gst_base_src_set_format(g.Instance(), C.GstFormat(format))
|
||||
}
|
||||
|
||||
// SetLive sets if the element listens to a live source.
|
||||
//
|
||||
// A live source will not produce data in the PAUSED state and will therefore not be able to participate in the
|
||||
// PREROLL phase of a pipeline. To signal this fact to the application and the pipeline, the state change return
|
||||
// value of the live source will be gst.StateChangeNoPreroll.
|
||||
func (g *GstBaseSrc) SetLive(live bool) { C.gst_base_src_set_live(g.Instance(), gboolean(live)) }
|
||||
|
||||
// StartComplete completes an asynchronous start operation. When the subclass overrides the start method,
|
||||
// it should call StartComplete when the start operation completes either from the same thread or from an
|
||||
// asynchronous helper thread.
|
||||
func (g *GstBaseSrc) StartComplete(ret gst.FlowReturn) {
|
||||
C.gst_base_src_start_complete(g.Instance(), C.GstFlowReturn(ret))
|
||||
}
|
||||
|
||||
// StartWait waits until the start operation is complete.
|
||||
func (g *GstBaseSrc) StartWait() gst.FlowReturn {
|
||||
return gst.FlowReturn(C.gst_base_src_start_wait(g.Instance()))
|
||||
}
|
||||
|
||||
// SubmitBufferList submits a list of buffers to the source.
|
||||
//
|
||||
// Subclasses can call this from their create virtual method implementation to submit a buffer list to be pushed out
|
||||
// later. This is useful in cases where the create function wants to produce multiple buffers to be pushed out in one
|
||||
// go in form of a GstBufferList, which can reduce overhead drastically, especially for packetised inputs (for data
|
||||
// streams where the packetisation/chunking is not important it is usually more efficient to return larger buffers instead).
|
||||
//
|
||||
// Subclasses that use this function from their create function must return GST_FLOW_OK and no buffer from their create
|
||||
// virtual method implementation. If a buffer is returned after a buffer list has also been submitted via this function the
|
||||
// behaviour is undefined.
|
||||
//
|
||||
// Subclasses must only call this function once per create function call and subclasses must only call this function when
|
||||
// the source operates in push mode.
|
||||
func (g *GstBaseSrc) SubmitBufferList(bufferList *gst.BufferList) {
|
||||
C.gst_base_src_submit_buffer_list(g.Instance(), (*C.GstBufferList)(unsafe.Pointer(bufferList.Instance())))
|
||||
}
|
||||
|
||||
// WaitPlaying will block until a state change to PLAYING happens (in which case this function returns gst.FlowOK) or the
|
||||
// processing must be stopped due to a state change to READY or a FLUSH event (in which case this function returns GST_FLOW_FLUSHING).
|
||||
//
|
||||
// If the Create() method performs its own synchronisation against the clock it must unblock when going from PLAYING to the PAUSED
|
||||
// state and call this method before continuing to produce the remaining data.
|
||||
//
|
||||
// gst.FlowOK will be returned if the source is PLAYING and processing can continue. Any other return value should be
|
||||
// returned from the Create() vmethod.
|
||||
func (g *GstBaseSrc) WaitPlaying() gst.FlowReturn {
|
||||
return gst.FlowReturn(C.gst_base_src_wait_playing(g.Instance()))
|
||||
}
|
||||
|
||||
@@ -10,3 +10,8 @@ func gboolean(b bool) C.gboolean {
|
||||
}
|
||||
return C.gboolean(0)
|
||||
}
|
||||
|
||||
// gobool provides an easy type conversion between C.gboolean and a go bool.
|
||||
func gobool(b C.gboolean) bool {
|
||||
return int(b) > 0
|
||||
}
|
||||
|
||||
@@ -14,6 +14,11 @@ type AllocationParams struct {
|
||||
ptr *C.GstAllocationParams
|
||||
}
|
||||
|
||||
// FromGstAllocationParamsUnsafe wraps the given unsafe.Pointer in an AllocationParams instance.
|
||||
func FromGstAllocationParamsUnsafe(alloc unsafe.Pointer) *AllocationParams {
|
||||
return &AllocationParams{ptr: (*C.GstAllocationParams)(alloc)}
|
||||
}
|
||||
|
||||
// NewAllocationParams initializes a set of allocation params with the default
|
||||
// values.
|
||||
func NewAllocationParams() *AllocationParams {
|
||||
@@ -65,6 +70,11 @@ func (a *AllocationParams) SetPadding(padding int64) { a.ptr.padding = C.gsize(p
|
||||
// Allocator is a go representation of a GstAllocator
|
||||
type Allocator struct{ *Object }
|
||||
|
||||
// FromGstAllocatorUnsafe wraps the given unsafe.Pointer in an Allocator instance.
|
||||
func FromGstAllocatorUnsafe(alloc unsafe.Pointer) *Allocator {
|
||||
return wrapAllocator(toGObject(alloc))
|
||||
}
|
||||
|
||||
// DefaultAllocator returns the default GstAllocator.
|
||||
func DefaultAllocator() *Allocator {
|
||||
return wrapAllocator(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(C.gst_allocator_find(nil)))})
|
||||
|
||||
+17
-3
@@ -22,9 +22,17 @@ type BufferList struct {
|
||||
ptr *C.GstBufferList
|
||||
}
|
||||
|
||||
// NewBufferList returns a new empty BufferList.
|
||||
func NewBufferList() *BufferList {
|
||||
return wrapBufferList(C.gst_buffer_list_new())
|
||||
// NewBufferList returns a new BufferList. The given slice can be nil and the returned
|
||||
// buffer list will be empty.
|
||||
func NewBufferList(buffers []*Buffer) *BufferList {
|
||||
bufList := wrapBufferList(C.gst_buffer_list_new())
|
||||
if buffers == nil {
|
||||
return bufList
|
||||
}
|
||||
for idx, buf := range buffers {
|
||||
bufList.Insert(idx, buf)
|
||||
}
|
||||
return bufList
|
||||
}
|
||||
|
||||
// NewBufferListSized creates a new BufferList with the given size.
|
||||
@@ -32,6 +40,12 @@ func NewBufferListSized(size uint) *BufferList {
|
||||
return wrapBufferList(C.gst_buffer_list_new_sized(C.guint(size)))
|
||||
}
|
||||
|
||||
// FromGstBufferListUnsafe wraps the given unsafe.Pointer in a BufferList instance. It is meant for internal usage
|
||||
// and exported for visibility to other packages.
|
||||
func FromGstBufferListUnsafe(ptr unsafe.Pointer) *BufferList {
|
||||
return wrapBufferList((*C.GstBufferList)(ptr))
|
||||
}
|
||||
|
||||
// Instance returns the underlying GstBufferList.
|
||||
func (b *BufferList) Instance() *C.GstBufferList { return C.toGstBufferList(unsafe.Pointer(b.ptr)) }
|
||||
|
||||
|
||||
@@ -22,6 +22,11 @@ func NewBufferPool() *BufferPool {
|
||||
return wrapBufferPool(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(pool))})
|
||||
}
|
||||
|
||||
// FromGstBufferPoolUnsafe wraps the given unsafe.Pointer in a BufferPool instance.
|
||||
func FromGstBufferPoolUnsafe(bufferPool unsafe.Pointer) *BufferPool {
|
||||
return wrapBufferPool(toGObject(bufferPool))
|
||||
}
|
||||
|
||||
// Instance returns the underlying GstBufferPool instance.
|
||||
func (b *BufferPool) Instance() *C.GstBufferPool { return C.toGstBufferPool(b.Unsafe()) }
|
||||
|
||||
|
||||
+1
-2
@@ -21,7 +21,6 @@ import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
@@ -327,7 +326,7 @@ func (b *Bus) PostError(src interface{}, msg string, err error) bool {
|
||||
if err != nil {
|
||||
st = NewStructure("go-error")
|
||||
if addErr := st.SetValue("error", err.Error()); addErr != nil {
|
||||
fmt.Println("go-gst-warning: failed to set error message to structure")
|
||||
b.Log(CAT, LevelWarning, "failed to set error message to structure")
|
||||
}
|
||||
}
|
||||
gstMsg := NewErrorMessage(src, gerr, string(debug.Stack()), st)
|
||||
|
||||
+47
-2
@@ -17,10 +17,55 @@ func FromGstSampleUnsafe(sample unsafe.Pointer) *Sample { return wrapSample(C.to
|
||||
// Instance returns the underlying *GstSample instance.
|
||||
func (s *Sample) Instance() *C.GstSample { return C.toGstSample(unsafe.Pointer(s.sample)) }
|
||||
|
||||
// Unref calls gst_sample_unref on the sample.
|
||||
func (s *Sample) Unref() { C.gst_sample_unref((*C.GstSample)(s.Instance())) }
|
||||
// Ref increases the ref count on the sample.
|
||||
func (s *Sample) Ref() *Sample {
|
||||
return wrapSample(C.gst_sample_ref(s.Instance()))
|
||||
}
|
||||
|
||||
// Copy creates a copy of the given sample. This will also make a newly allocated copy of the data
|
||||
// the source sample contains.
|
||||
func (s *Sample) Copy() *Sample { return wrapSample(C.gst_sample_copy(s.Instance())) }
|
||||
|
||||
// GetBuffer returns the buffer inside this sample.
|
||||
func (s *Sample) GetBuffer() *Buffer {
|
||||
return wrapBuffer(C.gst_sample_get_buffer((*C.GstSample)(s.Instance())))
|
||||
}
|
||||
|
||||
// GetBufferList gets the buffer list associated with this sample.
|
||||
func (s *Sample) GetBufferList() *BufferList {
|
||||
return wrapBufferList(C.gst_sample_get_buffer_list(s.Instance()))
|
||||
}
|
||||
|
||||
// GetCaps returns the caps associated with this sample. Take a ref if you need to hold on to them
|
||||
// longer then the life of the sample.
|
||||
func (s *Sample) GetCaps() *Caps { return wrapCaps(C.gst_sample_get_caps(s.Instance())) }
|
||||
|
||||
// GetInfo gets extra information about this sample. The structure remains valid as long as sample is valid.
|
||||
func (s *Sample) GetInfo() *Structure { return wrapStructure(C.gst_sample_get_info(s.Instance())) }
|
||||
|
||||
// GetSegment gets the segment associated with the sample. The segmenr remains valid as long as sample is valid.
|
||||
func (s *Sample) GetSegment() *Segment { return wrapSegment(C.gst_sample_get_segment(s.Instance())) }
|
||||
|
||||
// SetBuffer sets the buffer inside this sample. The sample must be writable.
|
||||
func (s *Sample) SetBuffer(buf *Buffer) { C.gst_sample_set_buffer(s.Instance(), buf.Instance()) }
|
||||
|
||||
// SetBufferList sets the buffer list for this sample. The sample must be writable.
|
||||
func (s *Sample) SetBufferList(buf *BufferList) {
|
||||
C.gst_sample_set_buffer_list(s.Instance(), buf.Instance())
|
||||
}
|
||||
|
||||
// SetCaps sets the caps on this sample. The sample must be writable.
|
||||
func (s *Sample) SetCaps(caps *Caps) { C.gst_sample_set_caps(s.Instance(), caps.Instance()) }
|
||||
|
||||
// SetInfo sets the info on this sample. The sample must be writable.
|
||||
func (s *Sample) SetInfo(st *Structure) bool {
|
||||
return gobool(C.gst_sample_set_info(s.Instance(), st.Instance()))
|
||||
}
|
||||
|
||||
// SetSegment sets the segment on this sample. The sample must be writable.
|
||||
func (s *Sample) SetSegment(segment *Segment) {
|
||||
C.gst_sample_set_segment(s.Instance(), segment.Instance())
|
||||
}
|
||||
|
||||
// Unref calls gst_sample_unref on the sample.
|
||||
func (s *Sample) Unref() { C.gst_sample_unref((*C.GstSample)(s.Instance())) }
|
||||
|
||||
@@ -75,6 +75,12 @@ func MarshalStructure(data interface{}) *Structure {
|
||||
return st
|
||||
}
|
||||
|
||||
// FromGstStructureUnsafe wraps the given unsafe.Pointer in a Structure. This is meant for internal usage
|
||||
// and is exported for visibility to other packages.
|
||||
func FromGstStructureUnsafe(st unsafe.Pointer) *Structure {
|
||||
return wrapStructure((*C.GstStructure)(st))
|
||||
}
|
||||
|
||||
// UnmarshalInto will unmarshal this structure into the given pointer. The object
|
||||
// reflected by the pointer must be non-nil.
|
||||
func (s *Structure) UnmarshalInto(data interface{}) error {
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
package gstauto
|
||||
|
||||
import "fmt"
|
||||
import "github.com/tinyzimmer/go-gst/gst"
|
||||
|
||||
func runOrPrintErr(f func() error) {
|
||||
if err := f(); err != nil {
|
||||
fmt.Println("[go-gst/gst/gstauto] Internal Error:", err.Error())
|
||||
gst.CAT.Log(gst.LevelError, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user