start building out audio and rtp libraries

This commit is contained in:
Avi Zimmerman
2021-01-25 19:49:57 +02:00
parent 177507cf0c
commit 099460e179
18 changed files with 888 additions and 35 deletions

2
go.sum
View File

@@ -2,3 +2,5 @@ github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o
github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
github.com/tinyzimmer/go-glib v0.0.18 h1:zSlJK5NDcquHK4FFQ2cF6tRavo2Y+6jc3Qowj1sN+oQ= github.com/tinyzimmer/go-glib v0.0.18 h1:zSlJK5NDcquHK4FFQ2cF6tRavo2Y+6jc3Qowj1sN+oQ=
github.com/tinyzimmer/go-glib v0.0.18/go.mod h1:zy2cs6eXSTtqqYrv9/UgYMDfr4pWKuYPSzwX87cBGX4= github.com/tinyzimmer/go-glib v0.0.18/go.mod h1:zy2cs6eXSTtqqYrv9/UgYMDfr4pWKuYPSzwX87cBGX4=
github.com/tinyzimmer/go-glib v0.0.19 h1:3DCrMb+tNHKXzpH6k/KXs9Gt3Wghz/nUbD6UT+HaCo4=
github.com/tinyzimmer/go-glib v0.0.19/go.mod h1:zy2cs6eXSTtqqYrv9/UgYMDfr4pWKuYPSzwX87cBGX4=

38
gst/audio/c_util.go Normal file
View File

@@ -0,0 +1,38 @@
package audio
/*
#include "gst.go.h"
GstClockTime
framesToClockTime (gint frames, gint rate) { return GST_FRAMES_TO_CLOCK_TIME(frames, rate); }
gint
clockTimeToFrames(GstClockTime ct, gint rate) { return GST_CLOCK_TIME_TO_FRAMES(ct, rate); }
*/
import "C"
import "time"
// FramesToDuration calculates the Clocktime (which is usually referred to as a time.Duration in the bindings)
// from the given frames and rate.
func FramesToDuration(frames, rate int) time.Duration {
ct := C.framesToClockTime(C.gint(frames), C.gint(rate))
return time.Duration(ct)
}
// DurationToFrames calculates the number of frames from the given duration and sample rate.
func DurationToFrames(dur time.Duration, rate int) int {
return int(C.clockTimeToFrames(C.GstClockTime(dur.Nanoseconds()), C.gint(rate)))
}
// gboolean converts a go bool to a C.gboolean.
func gboolean(b bool) C.gboolean {
if b {
return C.gboolean(1)
}
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
}

2
gst/audio/doc.go Normal file
View File

@@ -0,0 +1,2 @@
// Package audio contains bindings for the gstaudio C API.
package audio

6
gst/audio/gst.go.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef __GST_AUDIO_GO_H__
#define __GST_AUDIO_GO_H__
#include <gst/audio/audio.h>
#endif

View File

@@ -0,0 +1,132 @@
package audio
/*
#include "gst.go.h"
gpointer audioBufferPlaneData(GstAudioBuffer * buffer, gint plane)
{
return GST_AUDIO_BUFFER_PLANE_DATA(buffer, plane);
}
gint audioBufferPlaneSize(GstAudioBuffer * buffer)
{
return GST_AUDIO_BUFFER_PLANE_SIZE(buffer);
}
*/
import "C"
import (
"unsafe"
"github.com/tinyzimmer/go-gst/gst"
)
// ClipBuffer will return a new buffer clipped to the given segment. The given buffer is no longer valid.
// The returned buffer may be nil if it is completely outside the configured segment.
func ClipBuffer(buffer *gst.Buffer, segment *gst.Segment, rate, bytesPerFrame int) *gst.Buffer {
buf := C.gst_audio_buffer_clip(
(*C.GstBuffer)(unsafe.Pointer(buffer.Ref().Instance())),
(*C.GstSegment)(unsafe.Pointer(segment.Instance())),
C.gint(rate),
C.gint(bytesPerFrame),
)
if buf == nil {
return nil
}
return gst.FromGstBufferUnsafeFull(unsafe.Pointer(buf))
}
// ReorderChannels reorders the buffer against the given positions. The number of channels in each slice
// must be identical.
func ReorderChannels(buffer *gst.Buffer, format Format, from []ChannelPosition, to []ChannelPosition) bool {
return gobool(C.gst_audio_buffer_reorder_channels(
(*C.GstBuffer)(unsafe.Pointer(buffer.Instance())),
C.GstAudioFormat(format),
C.gint(len(from)),
(*C.GstAudioChannelPosition)(unsafe.Pointer(&from[0])),
(*C.GstAudioChannelPosition)(unsafe.Pointer(&to[0])),
))
}
// TruncateBuffer truncates the buffer to finally have the given number of samples, removing the necessary
// amount of samples from the end and trim number of samples from the beginning. The original buffer is no
// longer valid. The returned buffer may be nil if the arguments were invalid.
func TruncateBuffer(buffer *gst.Buffer, bytesPerFrame int, trim, samples int64) *gst.Buffer {
buf := C.gst_audio_buffer_truncate(
(*C.GstBuffer)(unsafe.Pointer(buffer.Ref().Instance())),
C.gint(bytesPerFrame),
C.gsize(trim),
C.gsize(samples),
)
if buf == nil {
return nil
}
return gst.FromGstBufferUnsafeFull(unsafe.Pointer(buf))
}
// MapBuffer maps an audio gst.Buffer so that it can be read or written.
//
// This is especially useful when the gstbuffer is in non-interleaved (planar) layout, in which case this
// function will use the information in the gstbuffer's attached GstAudioMeta in order to map each channel
// in a separate "plane" in GstAudioBuffer. If a GstAudioMeta is not attached on the gstbuffer, then it must
// be in interleaved layout.
//
// If a GstAudioMeta is attached, then the GstAudioInfo on the meta is checked against info. Normally, they
// should be equal, but in case they are not, a g_critical will be printed and the GstAudioInfo from the meta
// will be used.
//
// In non-interleaved buffers, it is possible to have each channel on a separate GstMemory. In this case, each
// memory will be mapped separately to avoid copying their contents in a larger memory area. Do note though
// that it is not supported to have a single channel spanning over two or more different GstMemory objects.
// Although the map operation will likely succeed in this case, it will be highly sub-optimal and it is
// recommended to merge all the memories in the buffer before calling this function.
func MapBuffer(info *Info, buffer *gst.Buffer, flags gst.MapFlags) (*Buffer, bool) {
var audioBuffer C.GstAudioBuffer
ret := gobool(C.gst_audio_buffer_map(
&audioBuffer,
info.ptr,
(*C.GstBuffer)(unsafe.Pointer(buffer.Instance())),
C.GstMapFlags(flags)),
)
if !ret {
return nil, ret
}
return &Buffer{ptr: &audioBuffer}, ret
}
// Buffer is a structure containing the result of a MapBuffer operation. For non-interleaved (planar) buffers,
// the beginning of each channel in the buffer has its own pointer in the planes array. For interleaved
// buffers, the Planes slice only contains one item, which is the pointer to the beginning of the buffer,
// and NumPlanes equals 1.
//
// The different channels in planes are always in the GStreamer channel order.
type Buffer struct {
ptr *C.GstAudioBuffer
}
// NumSamples returns the size of the buffer in samples.
func (b *Buffer) NumSamples() int64 { return int64(b.ptr.n_samples) }
// NumPlanes returns the number of available planes.
func (b *Buffer) NumPlanes() int { return int(b.ptr.n_planes) }
// Planes returns the planes inside the mapped buffer.
func (b *Buffer) Planes() [][]byte {
out := make([][]byte, b.NumPlanes())
for i := 0; i < b.NumPlanes(); i++ {
out[i] = C.GoBytes(
unsafe.Pointer(C.audioBufferPlaneData(b.ptr, C.gint(i))),
C.audioBufferPlaneSize(b.ptr),
)
}
return out
}
// WritePlane writes data to the plane at the given index.
func (b *Buffer) WritePlane(idx int, data []byte) {
bufdata := C.audioBufferPlaneData(b.ptr, C.gint(idx))
C.memcpy(unsafe.Pointer(bufdata), unsafe.Pointer(&data[0]), C.gsize(len(data)))
}
// Unmap will unmap the mapped buffer. Use this after calling MapBuffer.
func (b *Buffer) Unmap() { C.gst_audio_buffer_unmap(b.ptr) }

View File

@@ -0,0 +1,55 @@
package audio
// /*
// #include "gst.go.h"
// */
// import "C"
// import (
// "runtime"
// "unsafe"
// )
// // ChannelMixer is a structure for mixing audio channels.
// type ChannelMixer struct {
// ptr *C.GstAudioChannelMixer
// }
// // NewChannelMixer creates a new channel mixer with the given parameters.
// // It returns nil if the format is not supported.
// func NewChannelMixer(flags ChannelMixerFlags, format Format, inPositions, outPositions []ChannelPosition) *ChannelMixer {
// mixer := C.gst_audio_channel_mixer_new(
// C.GstAudioChannelMixerFlags(flags),
// C.GstAudioFormat(format),
// C.gint(len(inPositions)),
// (*C.GstAudioChannelPosition)(unsafe.Pointer(&inPositions[0])),
// C.gint(len(outPositions)),
// (*C.GstAudioChannelPosition)(unsafe.Pointer(&outPositions[0])),
// )
// if mixer == nil {
// return nil
// }
// wrapped := &ChannelMixer{mixer}
// runtime.SetFinalizer(wrapped, (*ChannelMixer).Free)
// return wrapped
// }
// // MixSamples will mix the given samples.
// //
// // In case the samples are interleaved, in must be a slice with a single element of interleaved samples.
// //
// // If non-interleaved samples are used, in must be a slice of data with an element for each channel
// // Free frees the channel mixer. The bindings will usually take care of this for you.
// func (c *ChannelMixer) Free() { C.gst_audio_channel_mixer_free(c.ptr) }
// // ChannelMixerFlags are flags used to configure a ChannelMixer
// type ChannelMixerFlags int
// // Castings for ChannelMixerFlags
// const (
// ChannelMixerFlagsNone ChannelMixerFlags = C.GST_AUDIO_CHANNEL_MIXER_FLAGS_NONE // (0) no flag
// ChannelMixerFlagsNonInterleavedIn ChannelMixerFlags = C.GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN // (1) input channels are not interleaved
// ChannelMixerFlagsNonInterleavedOut ChannelMixerFlags = C.GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT // (2) output channels are not interleaved
// ChannelMixerFlagsUnpositionedIn ChannelMixerFlags = C.GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_IN // (4) input channels are explicitly unpositioned
// ChannelMixerFlagsUnpositionedOut ChannelMixerFlags = C.GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_OUT // (8) output channels are explicitly unpositioned
// )

View File

@@ -0,0 +1,140 @@
package audio
/*
#include "gst.go.h"
*/
import "C"
import (
"strings"
"unsafe"
)
// GetFallbackChannelMask gets the fallback channel-mask for the given number of channels.
func GetFallbackChannelMask(channels int) uint64 {
return uint64(C.gst_audio_channel_get_fallback_mask(C.gint(channels)))
}
// ChannelPositionsFromMask converts the channels present in mask to a position array (which
// should have at least channels entries ensured by caller). If mask is set to 0, it is considered
// as 'not present' for purpose of conversion. A partially valid mask with less bits set than the
// number of channels is considered valid. This function returns nil if the arguments are invalid.
func ChannelPositionsFromMask(channels int, mask uint64) []ChannelPosition {
var out C.GstAudioChannelPosition
ret := C.gst_audio_channel_positions_from_mask(C.gint(channels), C.guint64(mask), &out)
if !gobool(ret) {
return nil
}
outsl := make([]ChannelPosition, channels)
tmp := (*[1 << 30]C.GstAudioChannelPosition)(unsafe.Pointer(&out))[:channels:channels]
for i, s := range tmp {
outsl[i] = ChannelPosition(s)
}
return outsl
}
// ChannelPositionsToMask converts the given channel positions to a bitmask. If forceOrder is true
// it additionally checks the channels in the order required by GStreamer.
func ChannelPositionsToMask(positions []ChannelPosition, forceOrder bool) (mask uint64, ok bool) {
var out C.guint64
ok = gobool(C.gst_audio_channel_positions_to_mask(
(*C.GstAudioChannelPosition)(unsafe.Pointer(&positions[0])),
C.gint(len(positions)),
gboolean(forceOrder),
&out,
))
if ok {
mask = uint64(out)
}
return
}
// ChannelPositionsToString converts the given positions into a human-readable string.
func ChannelPositionsToString(positions []ChannelPosition) string {
ret := C.gst_audio_channel_positions_to_string(
(*C.GstAudioChannelPosition)(unsafe.Pointer(&positions[0])),
C.gint(len(positions)),
)
defer C.g_free((C.gpointer)(unsafe.Pointer(ret)))
return C.GoString(ret)
}
// ChannelPositionsToValidOrder reorders the given positions from any order to the GStreamer order.
func ChannelPositionsToValidOrder(positions []ChannelPosition) (ok bool) {
ok = gobool(C.gst_audio_channel_positions_to_valid_order(
(*C.GstAudioChannelPosition)(unsafe.Pointer(&positions[0])),
C.gint(len(positions)),
))
return
}
// AreValidChannelPositions checks if the positions are all valid. If forceOrder is true, it also checks
// if they are in the order required by GStreamer.
func AreValidChannelPositions(positions []ChannelPosition, forceOrder bool) bool {
return gobool(C.gst_audio_check_valid_channel_positions(
(*C.GstAudioChannelPosition)(unsafe.Pointer(&positions[0])),
C.gint(len(positions)),
gboolean(forceOrder),
))
}
// ChannelPosition represents audio channel positions.
//
// These are the channels defined in SMPTE 2036-2-2008 Table 1 for 22.2 audio systems with the
// Surround and Wide channels from DTS Coherent Acoustics (v.1.3.1) and 10.2 and 7.1 layouts.
// In the caps the actual channel layout is expressed with a channel count and a channel mask,
// which describes the existing channels. The positions in the bit mask correspond to the enum
// values. For negotiation it is allowed to have more bits set in the channel mask than the
// number of channels to specify the allowed channel positions but this is not allowed in negotiated
// caps. It is not allowed in any situation other than the one mentioned below to have less
// bits set in the channel mask than the number of channels.
//
// ChannelPositionMono can only be used with a single mono channel that has no direction information
// and would be mixed into all directional channels. This is expressed in caps by having a single
// channel and no channel mask.
//
// ChannelPositionNone can only be used if all channels have this position. This is expressed in caps
// by having a channel mask with no bits set.
//
// As another special case it is allowed to have two channels without a channel mask. This implicitly
// means that this is a stereo stream with a front left and front right channel.
type ChannelPosition int
// ChannelPosition castings
const (
ChannelPositionNone ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_NONE // (-3) used for position-less channels, e.g. from a sound card that records 1024 channels; mutually exclusive with any other channel position
ChannelPositionMono ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_MONO // (-2) Mono without direction; can only be used with 1 channel
ChannelPositionInvalid ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_INVALID // (-1) invalid position
ChannelPositionFrontLeft ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT // (0) Front left
ChannelPositionFrontRight ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT // (1) Front right
ChannelPositionFrontCenter ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER // (2) Front center
ChannelPositionLFE1 ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_LFE1 // (3) Low-frequency effects 1 (subwoofer)
ChannelPositionRearLeft ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_REAR_LEFT // (4) Rear left
ChannelPositionRearRight ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT // (5) Rear right
ChannelPositionFrontLeftOfCenter ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER // (6) Front left of center
ChannelPositionFrontRightOfCenter ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER // (7) Front right of center
ChannelPositionRearCenter ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_REAR_CENTER // (8) Rear center
ChannelPositionLFE2 ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_LFE2 // (9) Low-frequency effects 2 (subwoofer)
ChannelPositionSideLeft ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT // (10) Side left
ChannelPositionSideRight ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT // (11) Side right
ChannelPositionTopFrontLeft ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT // (12) Top front left
ChannelPositionTopFrontRight ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT // (13) Top front right
ChannelPositionTopFrontCenter ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER // (14) Top front center
ChannelPositionTopCenter ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_TOP_CENTER // (15) Top center
ChannelPositionTopRearLeft ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT // (16) Top rear left
ChannelPositionTopRearRight ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT // (17) Top rear right
ChannelPositionTopSideLeft ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_LEFT // (18) Top side right
ChannelPositionTopSideRight ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_RIGHT // (19) Top rear right
ChannelPositionTopRearCenter ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER // (20) Top rear center
ChannelPositionBottomFrontCenter ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_CENTER // (21) Bottom front center
ChannelPositionBottomFrontLeft ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_LEFT // (22) Bottom front left
ChannelPositionBottomFrontRight ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_RIGHT // (23) Bottom front right
ChannelPositionWideLeft ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_WIDE_LEFT // (24) Wide left (between front left and side left)
ChannelPositionWideRight ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_WIDE_RIGHT // (25) Wide right (between front right and side right)
ChannelPositionSurroundLeft ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_SURROUND_LEFT // (26) Surround left (between rear left and side left)
ChannelPositionSurroundRight ChannelPosition = C.GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT // (27) Surround right (between rear right and side right)
)
func (c ChannelPosition) String() string {
// ugly hack
return strings.TrimSuffix(strings.TrimPrefix(ChannelPositionsToString([]ChannelPosition{c}), "[ "), " ]")
}

View File

@@ -0,0 +1,197 @@
package audio
/*
#include "gst.go.h"
*/
import "C"
import (
"unsafe"
"github.com/tinyzimmer/go-gst/gst"
)
// FormatInfo is a structure containing information about an audio format.
type FormatInfo struct {
ptr *C.GstAudioFormatInfo
}
// Format returns the format for this info.
func (f *FormatInfo) Format() Format { return Format(f.ptr.format) }
// Name returns the name for this info.
func (f *FormatInfo) Name() string { return C.GoString(f.ptr.name) }
// Description returns a user readable description for this info.
func (f *FormatInfo) Description() string { return C.GoString(f.ptr.description) }
// Flags returns the flags on this info.
func (f *FormatInfo) Flags() FormatFlags { return FormatFlags(f.ptr.flags) }
// Endianness returns the endianness for this info.
func (f *FormatInfo) Endianness() int { return int(f.ptr.endianness) }
// Width returns the amount of bits used for one sample.
func (f *FormatInfo) Width() int { return int(f.ptr.width) }
// Depth returns the amount of valid bits in width.
func (f *FormatInfo) Depth() int { return int(f.ptr.depth) }
// Silence returns the data for a single silent sample.
func (f *FormatInfo) Silence() []byte {
return C.GoBytes(unsafe.Pointer(&f.ptr.silence), C.gint(f.Width()/8))
}
// UnpackFormat is the format of unpacked samples.
func (f *FormatInfo) UnpackFormat() Format { return Format(f.ptr.unpack_format) }
// Layout represents the layout of audio samples for different channels.
type Layout int
// Castings for Layouts
const (
LayoutInterleaved Layout = C.GST_AUDIO_LAYOUT_INTERLEAVED // (0) interleaved audio
LayoutNonInterleaved Layout = C.GST_AUDIO_LAYOUT_NON_INTERLEAVED // (1) non-interleaved audio
)
// FormatFlags are the different audio flags that a format can have.
type FormatFlags int
// Castings for FormatFlags
const (
FormatFlagInteger FormatFlags = C.GST_AUDIO_FORMAT_FLAG_INTEGER // (1) integer samples
FormatFlagFloat FormatFlags = C.GST_AUDIO_FORMAT_FLAG_FLOAT // (2) float samples
FormatFlagSigned FormatFlags = C.GST_AUDIO_FORMAT_FLAG_SIGNED // (4) signed samples
FormatFlagComplex FormatFlags = C.GST_AUDIO_FORMAT_FLAG_COMPLEX // (16) complex layout
FormatFlagUnpack FormatFlags = C.GST_AUDIO_FORMAT_FLAG_UNPACK // (32) the format can be used in GstAudioFormatUnpack and GstAudioFormatPack functions
)
// PackFlags are the different flags that can be used when packing and unpacking.
type PackFlags int
// Castings for PackFlags
const (
PackFlagNone PackFlags = C.GST_AUDIO_PACK_FLAG_NONE // (0) No flag
PackFlagTruncateRange PackFlags = C.GST_AUDIO_PACK_FLAG_TRUNCATE_RANGE // (1) When the source has a smaller depth than the target format, set the least significant bits of the target to 0. This is likely slightly faster but less accurate. When this flag is not specified, the most significant bits of the source are duplicated in the least significant bits of the destination.
)
// Format is an enum describing the most common audio formats
type Format int
func (f Format) String() string {
return C.GoString(C.gst_audio_format_to_string(C.GstAudioFormat(f)))
}
// Info returns the info for this Format.
func (f Format) Info() *FormatInfo {
return &FormatInfo{
ptr: C.gst_audio_format_get_info(C.GstAudioFormat(f)),
}
}
// FormatFromString returns the format for the given string representation.
func FormatFromString(format string) Format {
f := C.CString(format)
defer C.free(unsafe.Pointer(f))
return Format(C.gst_audio_format_from_string((*C.gchar)(unsafe.Pointer(f))))
}
// LittleEndian represents little-endian format
const LittleEndian int = C.G_LITTLE_ENDIAN
// BigEndian represents big-endian format
const BigEndian int = C.G_BIG_ENDIAN
// FormatFromInteger returns a Format with the given parameters. Signed is whether signed or unsigned format.
// Endianness can be either LittleEndian or BigEndian. Width is the amount of bits used per sample, and depth
// is the amount of used bits in width.
func FormatFromInteger(signed bool, endianness, width, depth int) Format {
return Format(C.gst_audio_format_build_integer(
gboolean(signed),
C.gint(endianness),
C.gint(width),
C.gint(depth),
))
}
// RawFormats returns all the raw formats supported by GStreamer.
func RawFormats() []Format {
var l C.guint
formats := C.gst_audio_formats_raw(&l)
out := make([]Format, int(l))
tmpslice := (*[1 << 30]C.GstAudioFormat)(unsafe.Pointer(formats))[:l:l]
for i, s := range tmpslice {
out[i] = Format(s)
}
return out
}
// MakeRawCaps returns a generic raw audio caps for the formats defined. If formats is nil, all supported
// formats are used.
func MakeRawCaps(formats []Format, layout Layout) *gst.Caps {
var caps *C.GstCaps
if formats == nil {
caps = C.gst_audio_make_raw_caps(nil, C.guint(0), C.GstAudioLayout(layout))
} else {
caps = C.gst_audio_make_raw_caps((*C.GstAudioFormat)(unsafe.Pointer(&formats[0])), C.guint(len(formats)), C.GstAudioLayout(layout))
}
if caps == nil {
return nil
}
return gst.FromGstCapsUnsafeFull(unsafe.Pointer(caps))
}
// DefaultRate is the default sampling rate used in consumer audio
const DefaultRate = 44100
// Castings for Formats
const (
// DefaultFormat is the default format used in consumer audio
DefaultFormat Format = FormatS16LE
FormatUnknown Format = C.GST_AUDIO_FORMAT_UNKNOWN // (0) unknown or unset audio format
FormatEncoded Format = C.GST_AUDIO_FORMAT_ENCODED // (1) encoded audio format
FormatS8 Format = C.GST_AUDIO_FORMAT_S8 // (2) 8 bits in 8 bits, signed
FormatU8 Format = C.GST_AUDIO_FORMAT_U8 // (3) 8 bits in 8 bits, unsigned
FormatS16LE Format = C.GST_AUDIO_FORMAT_S16LE // (4) 16 bits in 16 bits, signed, little endian
FormatS16BE Format = C.GST_AUDIO_FORMAT_S16BE // (5) 16 bits in 16 bits, signed, big endian
FormatU16LE Format = C.GST_AUDIO_FORMAT_U16LE // (6) 16 bits in 16 bits, unsigned, little endian
FormatU16BE Format = C.GST_AUDIO_FORMAT_U16BE // (7) 16 bits in 16 bits, unsigned, big endian
FormatS2432LE Format = C.GST_AUDIO_FORMAT_S24_32LE // (8) 24 bits in 32 bits, signed, little endian
FormatS2332BE Format = C.GST_AUDIO_FORMAT_S24_32BE // (9) 24 bits in 32 bits, signed, big endian
FormatU2432LE Format = C.GST_AUDIO_FORMAT_U24_32LE // (10) 24 bits in 32 bits, unsigned, little endian
FormatU2432BE Format = C.GST_AUDIO_FORMAT_U24_32BE // (11) 24 bits in 32 bits, unsigned, big endian
FormatS32LE Format = C.GST_AUDIO_FORMAT_S32LE // (12) 32 bits in 32 bits, signed, little endian
FormatS32BE Format = C.GST_AUDIO_FORMAT_S32BE // (13) 32 bits in 32 bits, signed, big endian
FormatU32LE Format = C.GST_AUDIO_FORMAT_U32LE // (14) 32 bits in 32 bits, unsigned, little endian
FormatU32BE Format = C.GST_AUDIO_FORMAT_U32BE // (15) 32 bits in 32 bits, unsigned, big endian
FormatS24LE Format = C.GST_AUDIO_FORMAT_S24LE // (16) 24 bits in 24 bits, signed, little endian
FormatS24BE Format = C.GST_AUDIO_FORMAT_S24BE // (17) 24 bits in 24 bits, signed, big endian
FormatU24LE Format = C.GST_AUDIO_FORMAT_U24LE // (18) 24 bits in 24 bits, unsigned, little endian
FormatU24BE Format = C.GST_AUDIO_FORMAT_U24BE // (19) 24 bits in 24 bits, unsigned, big endian
FormatS20LE Format = C.GST_AUDIO_FORMAT_S20LE // (20) 20 bits in 24 bits, signed, little endian
FormatS20BE Format = C.GST_AUDIO_FORMAT_S20BE // (21) 20 bits in 24 bits, signed, big endian
FormatU20LE Format = C.GST_AUDIO_FORMAT_U20LE // (22) 20 bits in 24 bits, unsigned, little endian
FormatU20BE Format = C.GST_AUDIO_FORMAT_U20BE // (23) 20 bits in 24 bits, unsigned, big endian
FormatS18LE Format = C.GST_AUDIO_FORMAT_S18LE // (24) 18 bits in 24 bits, signed, little endian
FormatS18BE Format = C.GST_AUDIO_FORMAT_S18BE // (25) 18 bits in 24 bits, signed, big endian
FormatU18LE Format = C.GST_AUDIO_FORMAT_U18LE // (26) 18 bits in 24 bits, unsigned, little endian
FormatU18BE Format = C.GST_AUDIO_FORMAT_U18BE // (27) 18 bits in 24 bits, unsigned, big endian
FormatF32LE Format = C.GST_AUDIO_FORMAT_F32LE // (28) 32-bit floating point samples, little endian
FormatF32BE Format = C.GST_AUDIO_FORMAT_F32BE // (29) 32-bit floating point samples, big endian
FormatF64LE Format = C.GST_AUDIO_FORMAT_F64LE // (30) 64-bit floating point samples, little endian
FormatF64BE Format = C.GST_AUDIO_FORMAT_F64BE // (31) 64-bit floating point samples, big endian
FormatS16 Format = C.GST_AUDIO_FORMAT_S16 // (4) 16 bits in 16 bits, signed, native endianness
FormatU16 Format = C.GST_AUDIO_FORMAT_U16 // (6) 16 bits in 16 bits, unsigned, native endianness
FormatS2432 Format = C.GST_AUDIO_FORMAT_S24_32 // (8) 24 bits in 32 bits, signed, native endianness
FormatU2432 Format = C.GST_AUDIO_FORMAT_U24_32 // (10) 24 bits in 32 bits, unsigned, native endianness
FormatS32 Format = C.GST_AUDIO_FORMAT_S32 // (12) 32 bits in 32 bits, signed, native endianness
FormatU32 Format = C.GST_AUDIO_FORMAT_U32 // (14) 32 bits in 32 bits, unsigned, native endianness
FormatS24 Format = C.GST_AUDIO_FORMAT_S24 // (16) 24 bits in 24 bits, signed, native endianness
FormatU24 Format = C.GST_AUDIO_FORMAT_U24 // (18) 24 bits in 24 bits, unsigned, native endianness
FormatS20 Format = C.GST_AUDIO_FORMAT_S20 // (20) 20 bits in 24 bits, signed, native endianness
FormatU20 Format = C.GST_AUDIO_FORMAT_U20 // (22) 20 bits in 24 bits, unsigned, native endianness
FormatS18 Format = C.GST_AUDIO_FORMAT_S18 // (24) 18 bits in 24 bits, signed, native endianness
FormatU18 Format = C.GST_AUDIO_FORMAT_U18 // (26) 18 bits in 24 bits, unsigned, native endianness
FormatF32 Format = C.GST_AUDIO_FORMAT_F32 // (28) 32-bit floating point samples, native endianness
FormatF64 Format = C.GST_AUDIO_FORMAT_F64 // (30) 64-bit floating point samples, native endianness
)

124
gst/audio/gst_audio_info.go Normal file
View File

@@ -0,0 +1,124 @@
package audio
/*
#include "gst.go.h"
gint channels(GstAudioInfo * info)
{
return GST_AUDIO_INFO_CHANNELS(info);
}
*/
import "C"
import (
"runtime"
"unsafe"
"github.com/tinyzimmer/go-gst/gst"
)
// Flags contains extra audio flags
type Flags int
// Flags castings
const (
FlagNone Flags = C.GST_AUDIO_FLAG_NONE // (0) - no valid flag
FlagUnpositioned Flags = C.GST_AUDIO_FLAG_UNPOSITIONED // (1) the position array explicitly contains unpositioned channels.
)
func wrapInfoFull(ptr *C.GstAudioInfo) *Info {
info := &Info{ptr}
runtime.SetFinalizer(info, (*Info).Free)
return info
}
// Info is a structure used for describing audio properties. This can be filled in from caps
// or coverted back to caps.
type Info struct {
ptr *C.GstAudioInfo
}
// NewInfo returns a new Info that is also initialized.
func NewInfo() *Info { return wrapInfoFull(C.gst_audio_info_new()) }
// InfoFromCaps parses the provided caps and creates an info. It returns true if the caps could be parsed.
func InfoFromCaps(caps *gst.Caps) (*Info, bool) {
info := NewInfo()
return info, gobool(C.gst_audio_info_from_caps(info.ptr, (*C.GstCaps)(unsafe.Pointer(caps.Instance()))))
}
// FormatInfo returns the format info for the audio.
func (i *Info) FormatInfo() *FormatInfo { return &FormatInfo{i.ptr.finfo} }
// Flags returns additional flags for the audio.
func (i *Info) Flags() Flags { return Flags(i.ptr.flags) }
// Layout returns the audio layout.
func (i *Info) Layout() Layout { return Layout(i.ptr.layout) }
// Rate returns the audio sample rate.
func (i *Info) Rate() int { return int(i.ptr.rate) }
// Channels returns the number of channels.
func (i *Info) Channels() int { return int(C.channels(i.ptr)) }
// BPF returns the number of bytes for one frame. This is the size of one sample * Channels.
func (i *Info) BPF() int { return int(i.ptr.bpf) }
// Positions returns the positions for each channel.
func (i *Info) Positions() []ChannelPosition {
l := i.Channels()
out := make([]ChannelPosition, int(l))
tmpslice := (*[1 << 30]C.GstAudioChannelPosition)(unsafe.Pointer(&i.ptr.position))[:l:l]
for i, s := range tmpslice {
out[i] = ChannelPosition(s)
}
return out
}
// Init initializes the info with the default values.
func (i *Info) Init() { C.gst_audio_info_init(i.ptr) }
// Free frees the AudioInfo structure. This is usually handled for you by the bindings.
func (i *Info) Free() { C.gst_audio_info_free(i.ptr) }
// Convert converts among various gst.Format types. This function handles gst.FormatBytes, gst.FormatTime,
// and gst.FormatDefault. For raw audio, gst.FormatDefault corresponds to audio frames. This function can
// be used to handle pad queries of the type gst.QueryConvert. To provide a value from a time.Duration, use the
// Nanoseconds() method.
func (i *Info) Convert(srcFmt gst.Format, srcVal int64, destFmt gst.Format) (int64, bool) {
var out C.gint64
ret := C.gst_audio_info_convert(
i.ptr,
C.GstFormat(srcFmt),
C.gint64(srcVal),
C.GstFormat(destFmt),
&out,
)
return int64(out), gobool(ret)
}
// Copy creates a copy of this Info.
func (i *Info) Copy() *Info {
return wrapInfoFull(C.gst_audio_info_copy(i.ptr))
}
// IsEqual checks if the two infos are equal.
func (i *Info) IsEqual(info *Info) bool {
return gobool(C.gst_audio_info_is_equal(i.ptr, info.ptr))
}
// SetFormat sets the format for this info. This initializes info first and no values are preserved.
func (i *Info) SetFormat(format Format, rate int, positions []ChannelPosition) {
C.gst_audio_info_set_format(
i.ptr,
C.GstAudioFormat(format),
C.gint(rate),
C.gint(len(positions)),
(*C.GstAudioChannelPosition)(unsafe.Pointer(&positions[0])),
)
}
// ToCaps returns the caps representation of this info.
func (i *Info) ToCaps() *gst.Caps {
return gst.FromGstCapsUnsafeFull(unsafe.Pointer(C.gst_audio_info_to_caps(i.ptr)))
}

8
gst/audio/pkg_config.go Normal file
View File

@@ -0,0 +1,8 @@
package audio
/*
#cgo pkg-config: gstreamer-plugins-base-1.0
#cgo CFLAGS: -Wno-deprecated-declarations
#cgo LDFLAGS: -lgstaudio-1.0
*/
import "C"

View File

@@ -20,72 +20,86 @@ func cbWrapElement(elem *C.GstElement) *Element {
//export goGstBinAddElement //export goGstBinAddElement
func goGstBinAddElement(bin *C.GstBin, element *C.GstElement) C.gboolean { func goGstBinAddElement(bin *C.GstBin, element *C.GstElement) C.gboolean {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin)) var ret bool
caller := elem.(interface { glib.WithPointerTransferOriginal(unsafe.Pointer(bin), func(gobj *glib.Object, obj glib.GoObjectSubclass) {
caller := obj.(interface {
AddElement(self *Bin, element *Element) bool AddElement(self *Bin, element *Element) bool
}) })
return gboolean(caller.AddElement(cbWrapBin(bin), cbWrapElement(element))) ret = caller.AddElement(wrapBin(gobj), cbWrapElement(element))
})
return gboolean(ret)
} }
//export goGstBinDeepElementAdded //export goGstBinDeepElementAdded
func goGstBinDeepElementAdded(bin *C.GstBin, subbin *C.GstBin, child *C.GstElement) { func goGstBinDeepElementAdded(bin *C.GstBin, subbin *C.GstBin, child *C.GstElement) {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin)) glib.WithPointerTransferOriginal(unsafe.Pointer(bin), func(gobj *glib.Object, obj glib.GoObjectSubclass) {
caller := elem.(interface { caller := obj.(interface {
DeepElementAdded(self *Bin, subbin *Bin, child *Element) DeepElementAdded(self *Bin, subbin *Bin, child *Element)
}) })
caller.DeepElementAdded(cbWrapBin(bin), cbWrapBin(subbin), cbWrapElement(child)) caller.DeepElementAdded(wrapBin(gobj), cbWrapBin(subbin), cbWrapElement(child))
})
} }
//export goGstBinDeepElementRemoved //export goGstBinDeepElementRemoved
func goGstBinDeepElementRemoved(bin *C.GstBin, subbin *C.GstBin, child *C.GstElement) { func goGstBinDeepElementRemoved(bin *C.GstBin, subbin *C.GstBin, child *C.GstElement) {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin)) glib.WithPointerTransferOriginal(unsafe.Pointer(bin), func(gobj *glib.Object, obj glib.GoObjectSubclass) {
caller := elem.(interface { caller := obj.(interface {
DeepElementRemoved(self *Bin, subbin *Bin, child *Element) DeepElementRemoved(self *Bin, subbin *Bin, child *Element)
}) })
caller.DeepElementRemoved(cbWrapBin(bin), cbWrapBin(subbin), cbWrapElement(child)) caller.DeepElementRemoved(wrapBin(gobj), cbWrapBin(subbin), cbWrapElement(child))
})
} }
//export goGstBinDoLatency //export goGstBinDoLatency
func goGstBinDoLatency(bin *C.GstBin) C.gboolean { func goGstBinDoLatency(bin *C.GstBin) C.gboolean {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin)) var ret bool
caller := elem.(interface { glib.WithPointerTransferOriginal(unsafe.Pointer(bin), func(gobj *glib.Object, obj glib.GoObjectSubclass) {
caller := obj.(interface {
DoLatency(self *Bin) bool DoLatency(self *Bin) bool
}) })
return gboolean(caller.DoLatency(cbWrapBin(bin))) ret = caller.DoLatency(wrapBin(gobj))
})
return gboolean(ret)
} }
//export goGstBinElementAdded //export goGstBinElementAdded
func goGstBinElementAdded(bin *C.GstBin, child *C.GstElement) { func goGstBinElementAdded(bin *C.GstBin, child *C.GstElement) {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin)) glib.WithPointerTransferOriginal(unsafe.Pointer(bin), func(gobj *glib.Object, obj glib.GoObjectSubclass) {
caller := elem.(interface { caller := obj.(interface {
ElementAdded(self *Bin, child *Element) ElementAdded(self *Bin, child *Element)
}) })
caller.ElementAdded(cbWrapBin(bin), cbWrapElement(child)) caller.ElementAdded(wrapBin(gobj), cbWrapElement(child))
})
} }
//export goGstBinElementRemoved //export goGstBinElementRemoved
func goGstBinElementRemoved(bin *C.GstBin, child *C.GstElement) { func goGstBinElementRemoved(bin *C.GstBin, child *C.GstElement) {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin)) glib.WithPointerTransferOriginal(unsafe.Pointer(bin), func(gobj *glib.Object, obj glib.GoObjectSubclass) {
caller := elem.(interface { caller := obj.(interface {
ElementRemoved(self *Bin, child *Element) ElementRemoved(self *Bin, child *Element)
}) })
caller.ElementRemoved(cbWrapBin(bin), cbWrapElement(child)) caller.ElementRemoved(wrapBin(gobj), cbWrapElement(child))
})
} }
//export goGstBinHandleMessage //export goGstBinHandleMessage
func goGstBinHandleMessage(bin *C.GstBin, message *C.GstMessage) { func goGstBinHandleMessage(bin *C.GstBin, message *C.GstMessage) {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin)) glib.WithPointerTransferOriginal(unsafe.Pointer(bin), func(gobj *glib.Object, obj glib.GoObjectSubclass) {
caller := elem.(interface { caller := obj.(interface {
HandleMessage(self *Bin, msg *Message) HandleMessage(self *Bin, msg *Message)
}) })
caller.HandleMessage(cbWrapBin(bin), wrapMessage(message)) caller.HandleMessage(wrapBin(gobj), wrapMessage(message))
})
} }
//export goGstBinRemoveElement //export goGstBinRemoveElement
func goGstBinRemoveElement(bin *C.GstBin, element *C.GstElement) C.gboolean { func goGstBinRemoveElement(bin *C.GstBin, element *C.GstElement) C.gboolean {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin)) var ret bool
caller := elem.(interface { glib.WithPointerTransferOriginal(unsafe.Pointer(bin), func(gobj *glib.Object, obj glib.GoObjectSubclass) {
RemoveElement(self *Bin, element *Element) bool caller := obj.(interface {
RemoveElement(self *Bin, child *Element) bool
}) })
return gboolean(caller.RemoveElement(cbWrapBin(bin), cbWrapElement(element))) ret = caller.RemoveElement(wrapBin(gobj), cbWrapElement(element))
})
return gboolean(ret)
} }

View File

@@ -59,6 +59,14 @@ type MetaInfo struct {
ptr *C.GstMetaInfo ptr *C.GstMetaInfo
} }
// FromGstMetaInfoUnsafe wraps the given unsafe pointer in a MetaInfo instance.
func FromGstMetaInfoUnsafe(ptr unsafe.Pointer) *MetaInfo {
if ptr == nil {
return nil
}
return &MetaInfo{ptr: (*C.GstMetaInfo)(ptr)}
}
// RegisterAPIType registers and returns a GType for the given api name and associates it with tags. // RegisterAPIType registers and returns a GType for the given api name and associates it with tags.
func RegisterAPIType(name string, tags []string) glib.Type { func RegisterAPIType(name string, tags []string) glib.Type {
cTags := gcharStrings(tags) cTags := gcharStrings(tags)

19
gst/rtp/c_util.go Normal file
View File

@@ -0,0 +1,19 @@
package rtp
/*
#include "gst.go.h"
*/
import "C"
// gboolean converts a go bool to a C.gboolean.
func gboolean(b bool) C.gboolean {
if b {
return C.gboolean(1)
}
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
}

2
gst/rtp/doc.go Normal file
View File

@@ -0,0 +1,2 @@
// Package rtp contains bindings for the GStreamer RTP library.
package rtp

6
gst/rtp/gst.go.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef __GST_RTP_GO_H__
#define __GST_RTP_GO_H__
#include <gst/rtp/rtp.h>
#endif

95
gst/rtp/gst_rtp_meta.go Normal file
View File

@@ -0,0 +1,95 @@
package rtp
/*
#include "gst.go.h"
*/
import "C"
import (
"unsafe"
"github.com/tinyzimmer/go-glib/glib"
"github.com/tinyzimmer/go-gst/gst"
)
// MaxCSRCCount is the maximum number of elements that can be added to a CSRC.
const MaxCSRCCount uint = C.GST_RTP_SOURCE_META_MAX_CSRC_COUNT // 15
// SourceMeta is a wrapper around GstRTPSourceMeta.
type SourceMeta struct {
ptr *C.GstRTPSourceMeta
}
// SourceMetaAPIType returns the GType for GstRTPSourceMeta.
func SourceMetaAPIType() glib.Type {
return glib.Type(C.gst_rtp_source_meta_api_get_type())
}
// SourceMetaInfo returns the MetaInfo for GstRTPSourceMeta.
func SourceMetaInfo() *gst.MetaInfo {
return gst.FromGstMetaInfoUnsafe(unsafe.Pointer(C.gst_rtp_source_meta_get_info()))
}
// AppendCSRC appends the given CSRC to the list of contributing sources in meta.
func (s *SourceMeta) AppendCSRC(csrc []uint32) bool {
return gobool(C.gst_rtp_source_meta_append_csrc(
s.ptr,
(*C.guint32)(unsafe.Pointer(&csrc[0])),
C.guint(len(csrc)),
))
}
// GetSourceMeta retrieves the SourceMeta from the given buffer.
func GetSourceMeta(buffer *gst.Buffer) *SourceMeta {
meta := C.gst_buffer_get_rtp_source_meta((*C.GstBuffer)(unsafe.Pointer(buffer.Instance())))
if meta == nil {
return nil
}
return &SourceMeta{ptr: meta}
}
// AddSourceMeta attaches the given RTP source information to the buffer.
func AddSourceMeta(buffer *gst.Buffer, ssrc *uint32, csrc []uint32) *SourceMeta {
var meta *C.GstRTPSourceMeta
if ssrc == nil && csrc == nil {
meta = C.gst_buffer_add_rtp_source_meta(
(*C.GstBuffer)(unsafe.Pointer(buffer.Instance())),
nil, nil, 0,
)
} else if ssrc == nil {
meta = C.gst_buffer_add_rtp_source_meta(
(*C.GstBuffer)(unsafe.Pointer(buffer.Instance())),
nil,
(*C.guint32)(unsafe.Pointer(&csrc[0])), C.guint(len(csrc)),
)
} else if csrc == nil {
meta = C.gst_buffer_add_rtp_source_meta(
(*C.GstBuffer)(unsafe.Pointer(buffer.Instance())),
(*C.guint32)(unsafe.Pointer(ssrc)),
nil, 0,
)
} else {
meta = C.gst_buffer_add_rtp_source_meta(
(*C.GstBuffer)(unsafe.Pointer(buffer.Instance())),
(*C.guint32)(unsafe.Pointer(ssrc)),
(*C.guint32)(unsafe.Pointer(&csrc[0])), C.guint(len(csrc)),
)
}
if meta == nil {
return nil
}
return &SourceMeta{ptr: meta}
}
// GetSourceCount returns the total number of RTP sources found in this meta, both SSRC and CSRC.
func (s *SourceMeta) GetSourceCount() uint {
return uint(C.gst_rtp_source_meta_get_source_count(s.ptr))
}
// SetSSRC sets the SSRC on meta. If ssrc is nil, the SSRC of meta will be unset.
func (s *SourceMeta) SetSSRC(ssrc *uint32) bool {
if ssrc == nil {
return gobool(C.gst_rtp_source_meta_set_ssrc(s.ptr, nil))
}
return gobool(C.gst_rtp_source_meta_set_ssrc(s.ptr, (*C.guint32)(unsafe.Pointer(ssrc))))
}

8
gst/rtp/pkg_config.go Normal file
View File

@@ -0,0 +1,8 @@
package rtp
/*
#cgo pkg-config: gstreamer-plugins-base-1.0
#cgo LDFLAGS: -lgstrtp-1.0
#cgo CFLAGS: -Wno-deprecated-declarations -g -Wall
*/
import "C"

View File

@@ -1,5 +1,2 @@
// Package video contains bindings for the gstvideo C API. // Package video contains bindings for the gstvideo C API.
//
// This library should be linked to by getting cflags and libs from gstreamer-plugins-base-1.0.pc
// and adding -lgstvideo-1.0 to the library flags.
package video package video