Files
go-gst/gst/audio/gst_audio_buffer.go
2023-08-11 13:50:02 +02:00

133 lines
4.9 KiB
Go

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/go-gst/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) }