mirror of
https://github.com/go-gst/go-gst.git
synced 2025-09-27 04:15:56 +08:00
231 lines
9.6 KiB
Go
231 lines
9.6 KiB
Go
package app
|
|
|
|
/*
|
|
#include "gst.go.h"
|
|
|
|
extern void goAppGDestroyNotifyFunc (gpointer user_data);
|
|
|
|
extern void goSinkEOSCb (GstAppSink * sink, gpointer user_data);
|
|
extern GstFlowReturn goSinkNewPrerollCb (GstAppSink * sink, gpointer user_data);
|
|
extern GstFlowReturn goSinkNewSampleCb (GstAppSink * sink, gpointer user_data);
|
|
|
|
void cgoSinkGDestroyNotifyFunc (gpointer user_data) { goAppGDestroyNotifyFunc(user_data); }
|
|
void cgoSinkEOSCb (GstAppSink * sink, gpointer user_data) { return goSinkEOSCb(sink, user_data); }
|
|
GstFlowReturn cgoSinkNewPrerollCb (GstAppSink * sink, gpointer user_data) { return goSinkNewPrerollCb(sink, user_data); }
|
|
GstFlowReturn cgoSinkNewSampleCb (GstAppSink * sink, gpointer user_data) { return goSinkNewSampleCb(sink, user_data); }
|
|
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"errors"
|
|
"unsafe"
|
|
|
|
gopointer "github.com/mattn/go-pointer"
|
|
|
|
"github.com/go-gst/go-gst/gst"
|
|
"github.com/go-gst/go-gst/gst/base"
|
|
)
|
|
|
|
// SinkCallbacks represents callbacks that can be installed on an app sink when data is available.
|
|
type SinkCallbacks struct {
|
|
EOSFunc func(appSink *Sink)
|
|
NewPrerollFunc func(appSink *Sink) gst.FlowReturn
|
|
NewSampleFunc func(appSink *Sink) gst.FlowReturn
|
|
}
|
|
|
|
// ErrEOS represents that the stream has ended.
|
|
var ErrEOS = errors.New("pipeline has reached end-of-stream")
|
|
|
|
// Sink wraps an Element made with the appsink plugin with additional methods for pulling samples.
|
|
type Sink struct{ *base.GstBaseSink }
|
|
|
|
// NewAppSink returns a new appsink element. Unref after usage.
|
|
func NewAppSink() (*Sink, error) {
|
|
elem, err := gst.NewElement("appsink")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return wrapAppSink(elem), nil
|
|
}
|
|
|
|
// SinkFromElement checks if the given element is an appsink and if so returns
|
|
// a Sink interface.
|
|
func SinkFromElement(elem *gst.Element) *Sink {
|
|
if appSink := C.toGstAppSink(elem.Unsafe()); appSink != nil {
|
|
return wrapAppSink(elem)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Instance returns the native GstAppSink instance.
|
|
func (a *Sink) Instance() *C.GstAppSink { return C.toGstAppSink(a.Unsafe()) }
|
|
|
|
// GetBufferListSupport checks if appsink supports buffer lists.
|
|
func (a *Sink) GetBufferListSupport() bool {
|
|
return gobool(C.gst_app_sink_get_buffer_list_support(a.Instance()))
|
|
}
|
|
|
|
// GetCaps gets the configured caps on appsink.
|
|
func (a *Sink) GetCaps() *gst.Caps {
|
|
caps := C.gst_app_sink_get_caps(a.Instance())
|
|
if caps == nil {
|
|
return nil
|
|
}
|
|
return gst.FromGstCapsUnsafeFull(unsafe.Pointer(caps))
|
|
}
|
|
|
|
// GetDrop checks if appsink will drop old buffers when the maximum amount of queued buffers is reached.
|
|
func (a *Sink) GetDrop() bool {
|
|
return gobool(C.gst_app_sink_get_drop(a.Instance()))
|
|
}
|
|
|
|
// GetEmitSignals checks if appsink will emit the "new-preroll" and "new-sample" signals.
|
|
func (a *Sink) GetEmitSignals() bool {
|
|
return gobool(C.gst_app_sink_get_emit_signals(a.Instance()))
|
|
}
|
|
|
|
// GetMaxBuffers gets the maximum amount of buffers that can be queued in appsink.
|
|
func (a *Sink) GetMaxBuffers() uint {
|
|
return uint(C.gst_app_sink_get_max_buffers(a.Instance()))
|
|
}
|
|
|
|
// GetWaitOnEOS checks if appsink will wait for all buffers to be consumed when an EOS is received.
|
|
func (a *Sink) GetWaitOnEOS() bool {
|
|
return gobool(C.gst_app_sink_get_wait_on_eos(a.Instance()))
|
|
}
|
|
|
|
// IsEOS returns true if this AppSink has reached the end-of-stream.
|
|
func (a *Sink) IsEOS() bool {
|
|
return gobool(C.gst_app_sink_is_eos((*C.GstAppSink)(a.Instance())))
|
|
}
|
|
|
|
// PullPreroll gets the last preroll sample in appsink. This was the sample that caused the appsink to preroll in the PAUSED state.
|
|
//
|
|
// This function is typically used when dealing with a pipeline in the PAUSED state. Calling this function after doing a seek will
|
|
// give the sample right after the seek position.
|
|
//
|
|
// Calling this function will clear the internal reference to the preroll buffer.
|
|
//
|
|
// Note that the preroll sample will also be returned as the first sample when calling gst_app_sink_pull_sample.
|
|
//
|
|
// If an EOS event was received before any buffers, this function returns NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
|
|
//
|
|
// This function blocks until a preroll sample or EOS is received or the appsink element is set to the READY/NULL state.
|
|
func (a *Sink) PullPreroll() *gst.Sample {
|
|
smpl := C.gst_app_sink_pull_preroll(a.Instance())
|
|
if smpl == nil {
|
|
return nil
|
|
}
|
|
return gst.FromGstSampleUnsafeFull(unsafe.Pointer(smpl))
|
|
}
|
|
|
|
// PullSample blocks until a sample or EOS becomes available or the appsink element is set to the READY/NULL state.
|
|
//
|
|
// This function will only return samples when the appsink is in the PLAYING state. All rendered buffers will be put in a queue
|
|
// so that the application can pull samples at its own rate. Note that when the application does not pull samples fast enough, the queued
|
|
// buffers could consume a lot of memory, especially when dealing with raw video frames.
|
|
//
|
|
// If an EOS event was received before any buffers, this function returns NULL. Use IsEOS() to check for the EOS condition.
|
|
func (a *Sink) PullSample() *gst.Sample {
|
|
smpl := C.gst_app_sink_pull_sample(a.Instance())
|
|
if smpl == nil {
|
|
return nil
|
|
}
|
|
return gst.FromGstSampleUnsafeFull(unsafe.Pointer(smpl))
|
|
}
|
|
|
|
// SetBufferListSupport instructs appsink to enable or disable buffer list support.
|
|
//
|
|
// For backwards-compatibility reasons applications need to opt in to indicate that they will be able to handle buffer lists.
|
|
func (a *Sink) SetBufferListSupport(enabled bool) {
|
|
C.gst_app_sink_set_buffer_list_support(a.Instance(), gboolean(enabled))
|
|
}
|
|
|
|
// SetCallbacks sets callbacks which will be executed for each new preroll, new sample and eos. This is an alternative to using the signals,
|
|
// it has lower overhead and is thus less expensive, but also less flexible.
|
|
//
|
|
// If callbacks are installed, no signals will be emitted for performance reasons.
|
|
//
|
|
// Before 1.16.3 it was not possible to change the callbacks in a thread-safe way.
|
|
func (a *Sink) SetCallbacks(cbs *SinkCallbacks) {
|
|
ptr := gopointer.Save(cbs)
|
|
appSinkCallbacks := &C.GstAppSinkCallbacks{
|
|
eos: (*[0]byte)(unsafe.Pointer(C.cgoSinkEOSCb)),
|
|
new_preroll: (*[0]byte)(unsafe.Pointer(C.cgoSinkNewPrerollCb)),
|
|
new_sample: (*[0]byte)(unsafe.Pointer(C.cgoSinkNewSampleCb)),
|
|
}
|
|
C.gst_app_sink_set_callbacks(
|
|
a.Instance(),
|
|
appSinkCallbacks,
|
|
(C.gpointer)(unsafe.Pointer(ptr)),
|
|
C.GDestroyNotify(C.cgoSinkGDestroyNotifyFunc),
|
|
)
|
|
}
|
|
|
|
// SetCaps sets the capabilities on the appsink element. This function takes a copy of the caps structure. After calling this method,
|
|
// the sink will only accept caps that match caps. If caps is non-fixed, or incomplete, you must check the caps on the samples to get
|
|
// the actual used caps.
|
|
func (a *Sink) SetCaps(caps *gst.Caps) {
|
|
C.gst_app_sink_set_caps(a.Instance(), (*C.GstCaps)(unsafe.Pointer(caps.Instance())))
|
|
}
|
|
|
|
// SetDrop instructs appsink to drop old buffers when the maximum amount of queued buffers is reached.
|
|
func (a *Sink) SetDrop(drop bool) {
|
|
C.gst_app_sink_set_drop(a.Instance(), gboolean(drop))
|
|
}
|
|
|
|
// SetEmitSignals makes appsink emit the "new-preroll" and "new-sample" signals. This option is by default disabled because signal emission
|
|
// is expensive and unneeded when the application prefers to operate in pull mode.
|
|
func (a *Sink) SetEmitSignals(emit bool) {
|
|
C.gst_app_sink_set_emit_signals(a.Instance(), gboolean(emit))
|
|
}
|
|
|
|
// SetMaxBuffers sets the maximum amount of buffers that can be queued in appsink. After this amount of buffers are queued in appsink,
|
|
// any more buffers will block upstream elements until a sample is pulled from appsink.
|
|
func (a *Sink) SetMaxBuffers(max uint) {
|
|
C.gst_app_sink_set_max_buffers(a.Instance(), C.guint(max))
|
|
}
|
|
|
|
// SetWaitOnEOS instructs appsink to wait for all buffers to be consumed when an EOS is received.
|
|
func (a *Sink) SetWaitOnEOS(wait bool) {
|
|
C.gst_app_sink_set_wait_on_eos(a.Instance(), gboolean(wait))
|
|
}
|
|
|
|
// TryPullPreroll gets the last preroll sample in appsink. This was the sample that caused the appsink to preroll in the PAUSED state.
|
|
//
|
|
// This function is typically used when dealing with a pipeline in the PAUSED state. Calling this function after doing a seek will give
|
|
// the sample right after the seek position.
|
|
//
|
|
// Calling this function will clear the internal reference to the preroll buffer.
|
|
//
|
|
// Note that the preroll sample will also be returned as the first sample when calling PullSample.
|
|
//
|
|
// If an EOS event was received before any buffers or the timeout expires, this function returns NULL. Use IsEOS () to check for the EOS condition.
|
|
//
|
|
// This function blocks until a preroll sample or EOS is received, the appsink element is set to the READY/NULL state, or the timeout expires.
|
|
func (a *Sink) TryPullPreroll(timeout gst.ClockTime) *gst.Sample {
|
|
tm := C.GstClockTime(timeout)
|
|
smpl := C.gst_app_sink_try_pull_preroll(a.Instance(), tm)
|
|
if smpl == nil {
|
|
return nil
|
|
}
|
|
return gst.FromGstSampleUnsafeFull(unsafe.Pointer(smpl))
|
|
}
|
|
|
|
// TryPullSample blocks until a sample or EOS becomes available or the appsink element is set to the READY/NULL state or the timeout expires.
|
|
//
|
|
// This function will only return samples when the appsink is in the PLAYING state. All rendered buffers will be put in a queue so that the
|
|
// application can pull samples at its own rate. Note that when the application does not pull samples fast enough, the queued buffers could
|
|
// consume a lot of memory, especially when dealing with raw video frames.
|
|
//
|
|
// If an EOS event was received before any buffers or the timeout expires, this function returns NULL. Use IsEOS () to check for the EOS condition.
|
|
func (a *Sink) TryPullSample(timeout gst.ClockTime) *gst.Sample {
|
|
tm := C.GstClockTime(timeout)
|
|
smpl := C.gst_app_sink_try_pull_sample(a.Instance(), tm)
|
|
if smpl == nil {
|
|
return nil
|
|
}
|
|
return gst.FromGstSampleUnsafeFull(unsafe.Pointer(smpl))
|
|
}
|