diff --git a/frame.go b/frame.go index 8260345..2081ded 100644 --- a/frame.go +++ b/frame.go @@ -140,6 +140,14 @@ func (f *Frame) SetSampleRate(r int) { f.c.sample_rate = C.int(r) } +func (f *Frame) NewSideData(t FrameSideDataType, size int) *FrameSideData { + return newFrameSideDataFromC(C.av_frame_new_side_data(f.c, (C.enum_AVFrameSideDataType)(t), C.int(size))) +} + +func (f *Frame) SideData(t FrameSideDataType) *FrameSideData { + return newFrameSideDataFromC(C.av_frame_get_side_data(f.c, (C.enum_AVFrameSideDataType)(t))) +} + func (f *Frame) Width() int { return int(f.c.width) } diff --git a/frame_side_data.go b/frame_side_data.go new file mode 100644 index 0000000..f45d278 --- /dev/null +++ b/frame_side_data.go @@ -0,0 +1,36 @@ +package astiav + +//#cgo pkg-config: libavutil +//#include +import "C" +import ( + "math" + "unsafe" +) + +// https://github.com/FFmpeg/FFmpeg/blob/n5.0/libavutil/frame.h#L223 +type FrameSideData struct { + c *C.struct_AVFrameSideData +} + +func newFrameSideDataFromC(c *C.struct_AVFrameSideData) *FrameSideData { + if c == nil { + return nil + } + return &FrameSideData{c: c} +} + +func (d *FrameSideData) Data() []byte { + return bytesFromC(func(size *C.int) *C.uint8_t { + *size = d.c.size + return d.c.data + }) +} + +func (d *FrameSideData) SetData(b []byte) { + C.memcpy(unsafe.Pointer(d.c.data), unsafe.Pointer(&b[0]), C.size_t(math.Min(float64(len(b)), float64(d.c.size)))) +} + +func (d *FrameSideData) Type() FrameSideDataType { + return FrameSideDataType(d.c._type) +} diff --git a/frame_side_data_type.go b/frame_side_data_type.go new file mode 100644 index 0000000..fa18995 --- /dev/null +++ b/frame_side_data_type.go @@ -0,0 +1,33 @@ +package astiav + +//#cgo pkg-config: libavutil +//#include +import "C" + +// https://github.com/FFmpeg/FFmpeg/blob/n5.0/libavutil/frame.h#L48 +type FrameSideDataType C.enum_AVFrameSideDataType + +const ( + FrameSideDataTypePanscan = FrameSideDataType(C.AV_FRAME_DATA_PANSCAN) + FrameSideDataTypeA53Cc = FrameSideDataType(C.AV_FRAME_DATA_A53_CC) + FrameSideDataTypeStereo3D = FrameSideDataType(C.AV_FRAME_DATA_STEREO3D) + FrameSideDataTypeMatrixencoding = FrameSideDataType(C.AV_FRAME_DATA_MATRIXENCODING) + FrameSideDataTypeDownmixInfo = FrameSideDataType(C.AV_FRAME_DATA_DOWNMIX_INFO) + FrameSideDataTypeReplaygain = FrameSideDataType(C.AV_FRAME_DATA_REPLAYGAIN) + FrameSideDataTypeDisplaymatrix = FrameSideDataType(C.AV_FRAME_DATA_DISPLAYMATRIX) + FrameSideDataTypeAfd = FrameSideDataType(C.AV_FRAME_DATA_AFD) + FrameSideDataTypeMotionVectors = FrameSideDataType(C.AV_FRAME_DATA_MOTION_VECTORS) + FrameSideDataTypeSkipSamples = FrameSideDataType(C.AV_FRAME_DATA_SKIP_SAMPLES) + FrameSideDataTypeAudioServiceType = FrameSideDataType(C.AV_FRAME_DATA_AUDIO_SERVICE_TYPE) + FrameSideDataTypeMasteringDisplayMetadata = FrameSideDataType(C.AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) + FrameSideDataTypeGopTimecode = FrameSideDataType(C.AV_FRAME_DATA_GOP_TIMECODE) + FrameSideDataTypeSpherical = FrameSideDataType(C.AV_FRAME_DATA_SPHERICAL) + FrameSideDataTypeContentLightLevel = FrameSideDataType(C.AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) + FrameSideDataTypeIccProfile = FrameSideDataType(C.AV_FRAME_DATA_ICC_PROFILE) + FrameSideDataTypeS12MTimecode = FrameSideDataType(C.AV_FRAME_DATA_S12M_TIMECODE) + FrameSideDataTypeDynamicHdrPlus = FrameSideDataType(C.AV_FRAME_DATA_DYNAMIC_HDR_PLUS) + FrameSideDataTypeRegionsOfInterest = FrameSideDataType(C.AV_FRAME_DATA_REGIONS_OF_INTEREST) + FrameSideDataTypeVideoEncParams = FrameSideDataType(C.AV_FRAME_DATA_VIDEO_ENC_PARAMS) + FrameSideDataTypeSeiUnregistered = FrameSideDataType(C.AV_FRAME_DATA_SEI_UNREGISTERED) + FrameSideDataTypeFilmGrainParams = FrameSideDataType(C.AV_FRAME_DATA_FILM_GRAIN_PARAMS) +) diff --git a/frame_test.go b/frame_test.go index 067635e..61e72a4 100644 --- a/frame_test.go +++ b/frame_test.go @@ -187,4 +187,19 @@ func TestFrame(t *testing.T) { require.NoError(t, err) err = f4.AllocSamples(0) require.NoError(t, err) + + f5 := astiav.AllocFrame() + require.NotNil(t, f5) + defer f5.Free() + sd := f5.NewSideData(astiav.FrameSideDataTypeAudioServiceType, 4) + require.NotNil(t, sd) + sd.SetData([]byte{1, 2, 3}) + sd = f5.SideData(astiav.FrameSideDataTypeAudioServiceType) + require.NotNil(t, sd) + require.Equal(t, astiav.FrameSideDataTypeAudioServiceType, sd.Type()) + require.Equal(t, []byte{1, 2, 3, 0}, sd.Data()) + sd.SetData([]byte{1, 2, 3, 4, 5}) + sd = f5.SideData(astiav.FrameSideDataTypeAudioServiceType) + require.NotNil(t, sd) + require.Equal(t, []byte{1, 2, 3, 4}, sd.Data()) } diff --git a/packet.go b/packet.go index 4b4c256..dc806d8 100644 --- a/packet.go +++ b/packet.go @@ -74,6 +74,18 @@ func (p *Packet) SetPts(v int64) { p.c.pts = C.int64_t(v) } +func (p *Packet) AddSideData(t PacketSideDataType, data []byte) error { + // Create buf + buf := (*C.uint8_t)(C.av_malloc(C.size_t(len(data)))) + if buf == nil { + return errors.New("astiav: allocating buffer failed") + } + C.memcpy(unsafe.Pointer(buf), unsafe.Pointer(&data[0]), C.size_t(len(data))) + + // Add + return newError(C.av_packet_add_side_data(p.c, (C.enum_AVPacketSideDataType)(t), buf, C.size_t(len(data)))) +} + func (p *Packet) SideData(t PacketSideDataType) []byte { return bytesFromC(func(size *C.int) *C.uint8_t { return C.av_packet_get_side_data(p.c, (C.enum_AVPacketSideDataType)(t), size) diff --git a/packet_test.go b/packet_test.go index 2b96d1a..cc50220 100644 --- a/packet_test.go +++ b/packet_test.go @@ -101,5 +101,10 @@ func TestPacket(t *testing.T) { require.NoError(t, pkt4.FromData(b)) require.Equal(t, b, pkt4.Data()) - // TODO Test SideData + pkt5 := astiav.AllocPacket() + require.NotNil(t, pkt5) + defer pkt5.Free() + b = []byte{1, 2, 3, 4} + require.NoError(t, pkt5.AddSideData(astiav.PacketSideDataTypeAudioServiceType, b)) + require.Equal(t, b, pkt5.SideData(astiav.PacketSideDataTypeAudioServiceType)) }